aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gcc.gnu.org>2018-10-28 19:51:47 +0000
committerIain Buclaw <ibuclaw@gcc.gnu.org>2018-10-28 19:51:47 +0000
commitb4c522fabd0df7be08882d2207df8b2765026110 (patch)
treeb5ffc312b0a441c1ba24323152aec463fdbe5e9f /gcc/d
parent01ce9e31a02c8039d88e90f983735104417bf034 (diff)
downloadgcc-b4c522fabd0df7be08882d2207df8b2765026110.zip
gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.gz
gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.bz2
Add D front-end, libphobos library, and D2 testsuite.
ChangeLog: * Makefile.def (target_modules): Add libphobos. (flags_to_pass): Add GDC, GDCFLAGS, GDC_FOR_TARGET and GDCFLAGS_FOR_TARGET. (dependencies): Make libphobos depend on libatomic, libbacktrace configure, and zlib configure. (language): Add language d. * Makefile.in: Rebuild. * Makefile.tpl (BUILD_EXPORTS): Add GDC and GDCFLAGS. (HOST_EXPORTS): Add GDC. (POSTSTAGE1_HOST_EXPORTS): Add GDC and GDC_FOR_BUILD. (BASE_TARGET_EXPORTS): Add GDC. (GDC_FOR_BUILD, GDC, GDCFLAGS): New variables. (GDC_FOR_TARGET, GDC_FLAGS_FOR_TARGET): New variables. (EXTRA_HOST_FLAGS): Add GDC. (STAGE1_FLAGS_TO_PASS): Add GDC. (EXTRA_TARGET_FLAGS): Add GDC and GDCFLAGS. * config-ml.in: Treat GDC and GDCFLAGS like other compiler/flag environment variables. * configure: Rebuild. * configure.ac: Add target-libphobos to target_libraries. Set and substitute GDC_FOR_BUILD and GDC_FOR_TARGET. config/ChangeLog: * multi.m4: Set GDC. gcc/ChangeLog: * Makefile.in (tm_d_file_list, tm_d_include_list): New variables. (TM_D_H, D_TARGET_DEF, D_TARGET_H, D_TARGET_OBJS): New variables. (tm_d.h, cs-tm_d.h, default-d.o): New rules. (d/d-target-hooks-def.h, s-d-target-hooks-def-h): New rules. (s-tm-texi): Also check timestamp on d-target.def. (generated_files): Add TM_D_H and d-target-hooks-def.h. (build/genhooks.o): Also depend on D_TARGET_DEF. * config.gcc (tm_d_file, d_target_objs, target_has_targetdm): New variables. * config/aarch64/aarch64-d.c: New file. * config/aarch64/aarch64-linux.h (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/aarch64/aarch64-protos.h (aarch64_d_target_versions): New prototype. * config/aarch64/aarch64.h (TARGET_D_CPU_VERSIONS): Define. * config/aarch64/t-aarch64 (aarch64-d.o): New rule. * config/arm/arm-d.c: New file. * config/arm/arm-protos.h (arm_d_target_versions): New prototype. * config/arm/arm.h (TARGET_D_CPU_VERSIONS): Define. * config/arm/linux-eabi.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/arm/t-arm (arm-d.o): New rule. * config/default-d.c: New file. * config/glibc-d.c: New file. * config/gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/i386/i386-d.c: New file. * config/i386/i386-protos.h (ix86_d_target_versions): New prototype. * config/i386/i386.h (TARGET_D_CPU_VERSIONS): Define. * config/i386/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/i386/t-i386 (i386-d.o): New rule. * config/kfreebsd-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/kopensolaris-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/linux-android.h (ANDROID_TARGET_D_OS_VERSIONS): Define. * config/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/mips/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/mips/mips-d.c: New file. * config/mips/mips-protos.h (mips_d_target_versions): New prototype. * config/mips/mips.h (TARGET_D_CPU_VERSIONS): Define. * config/mips/t-mips (mips-d.o): New rule. * config/powerpcspe/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/powerpcspe-d.c: New file. * config/powerpcspe/powerpcspe-protos.h (rs6000_d_target_versions): New prototype. * config/powerpcspe/powerpcspe.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/powerpcspe/powerpcspe.h (TARGET_D_CPU_VERSIONS): Define. * config/powerpcspe/t-powerpcspe (powerpcspe-d.o): New rule. * config/riscv/riscv-d.c: New file. * config/riscv/riscv-protos.h (riscv_d_target_versions): New prototype. * config/riscv/riscv.h (TARGET_D_CPU_VERSIONS): Define. * config/riscv/t-riscv (riscv-d.o): New rule. * config/rs6000/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/rs6000-d.c: New file. * config/rs6000/rs6000-protos.h (rs6000_d_target_versions): New prototype. * config/rs6000/rs6000.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/rs6000/rs6000.h (TARGET_D_CPU_VERSIONS): Define. * config/rs6000/t-rs6000 (rs6000-d.o): New rule. * config/s390/s390-d.c: New file. * config/s390/s390-protos.h (s390_d_target_versions): New prototype. * config/s390/s390.h (TARGET_D_CPU_VERSIONS): Define. * config/s390/t-s390 (s390-d.o): New rule. * config/sparc/sparc-d.c: New file. * config/sparc/sparc-protos.h (sparc_d_target_versions): New prototype. * config/sparc/sparc.h (TARGET_D_CPU_VERSIONS): Define. * config/sparc/t-sparc (sparc-d.o): New rule. * config/t-glibc (glibc-d.o): New rule. * configure: Regenerated. * configure.ac (tm_d_file): New variable. (tm_d_file_list, tm_d_include_list, d_target_objs): Add substitutes. * doc/contrib.texi (Contributors): Add self for the D frontend. * doc/frontends.texi (G++ and GCC): Mention D as a supported language. * doc/install.texi (Configuration): Mention libphobos as an option for --enable-shared. Mention d as an option for --enable-languages. (Testing): Mention check-d as a target. * doc/invoke.texi (Overall Options): Mention .d, .dd, and .di as file name suffixes. Mention d as a -x option. * doc/sourcebuild.texi (Top Level): Mention libphobos. * doc/standards.texi (Standards): Add section on D language. * doc/tm.texi: Regenerated. * doc/tm.texi.in: Add @node for D language and ABI, and @hook for TARGET_CPU_VERSIONS, TARGET_D_OS_VERSIONS, and TARGET_D_CRITSEC_SIZE. * dwarf2out.c (is_dlang): New function. (gen_compile_unit_die): Use DW_LANG_D for D. (declare_in_namespace): Return module die for D, instead of adding extra declarations into the namespace. (gen_namespace_die): Generate DW_TAG_module for D. (gen_decl_die): Handle CONST_DECLSs for D. (dwarf2out_decl): Likewise. (prune_unused_types_walk_local_classes): Handle DW_tag_interface_type. (prune_unused_types_walk): Handle DW_tag_interface_type same as other kinds of aggregates. * gcc.c (default_compilers): Add entries for .d, .dd and .di. * genhooks.c: Include d/d-target.def. gcc/po/ChangeLog: * EXCLUDES: Add sources from d/dmd. gcc/testsuite/ChangeLog: * gcc.misc-tests/help.exp: Add D to option descriptions check. * gdc.dg/asan/asan.exp: New file. * gdc.dg/asan/gdc272.d: New test. * gdc.dg/compilable.d: New test. * gdc.dg/dg.exp: New file. * gdc.dg/gdc254.d: New test. * gdc.dg/gdc260.d: New test. * gdc.dg/gdc270a.d: New test. * gdc.dg/gdc270b.d: New test. * gdc.dg/gdc282.d: New test. * gdc.dg/gdc283.d: New test. * gdc.dg/imports/gdc170.d: New test. * gdc.dg/imports/gdc231.d: New test. * gdc.dg/imports/gdc239.d: New test. * gdc.dg/imports/gdc241a.d: New test. * gdc.dg/imports/gdc241b.d: New test. * gdc.dg/imports/gdc251a.d: New test. * gdc.dg/imports/gdc251b.d: New test. * gdc.dg/imports/gdc253.d: New test. * gdc.dg/imports/gdc254a.d: New test. * gdc.dg/imports/gdc256.d: New test. * gdc.dg/imports/gdc27.d: New test. * gdc.dg/imports/gdcpkg256/package.d: New test. * gdc.dg/imports/runnable.d: New test. * gdc.dg/link.d: New test. * gdc.dg/lto/lto.exp: New file. * gdc.dg/lto/ltotests_0.d: New test. * gdc.dg/lto/ltotests_1.d: New test. * gdc.dg/runnable.d: New test. * gdc.dg/simd.d: New test. * gdc.test/gdc-test.exp: New file. * lib/gdc-dg.exp: New file. * lib/gdc.exp: New file. libphobos/ChangeLog: * Makefile.am: New file. * Makefile.in: New file. * acinclude.m4: New file. * aclocal.m4: New file. * config.h.in: New file. * configure: New file. * configure.ac: New file. * d_rules.am: New file. * libdruntime/Makefile.am: New file. * libdruntime/Makefile.in: New file. * libdruntime/__entrypoint.di: New file. * libdruntime/__main.di: New file. * libdruntime/gcc/attribute.d: New file. * libdruntime/gcc/backtrace.d: New file. * libdruntime/gcc/builtins.d: New file. * libdruntime/gcc/config.d.in: New file. * libdruntime/gcc/deh.d: New file. * libdruntime/gcc/libbacktrace.d.in: New file. * libdruntime/gcc/unwind/arm.d: New file. * libdruntime/gcc/unwind/arm_common.d: New file. * libdruntime/gcc/unwind/c6x.d: New file. * libdruntime/gcc/unwind/generic.d: New file. * libdruntime/gcc/unwind/package.d: New file. * libdruntime/gcc/unwind/pe.d: New file. * m4/autoconf.m4: New file. * m4/druntime.m4: New file. * m4/druntime/cpu.m4: New file. * m4/druntime/libraries.m4: New file. * m4/druntime/os.m4: New file. * m4/gcc_support.m4: New file. * m4/gdc.m4: New file. * m4/libtool.m4: New file. * src/Makefile.am: New file. * src/Makefile.in: New file. * src/libgphobos.spec.in: New file. * testsuite/Makefile.am: New file. * testsuite/Makefile.in: New file. * testsuite/config/default.exp: New file. * testsuite/lib/libphobos-dg.exp: New file. * testsuite/lib/libphobos.exp: New file. * testsuite/testsuite_flags.in: New file. From-SVN: r265573
Diffstat (limited to 'gcc/d')
-rw-r--r--gcc/d/ChangeLog617
-rw-r--r--gcc/d/ChangeLog-2006954
-rw-r--r--gcc/d/ChangeLog-20071340
-rw-r--r--gcc/d/ChangeLog-2008331
-rw-r--r--gcc/d/ChangeLog-2009185
-rw-r--r--gcc/d/ChangeLog-20101484
-rw-r--r--gcc/d/ChangeLog-20111248
-rw-r--r--gcc/d/ChangeLog-2012857
-rw-r--r--gcc/d/ChangeLog-20131221
-rw-r--r--gcc/d/ChangeLog-2014660
-rw-r--r--gcc/d/ChangeLog-2015771
-rw-r--r--gcc/d/ChangeLog-20161262
-rw-r--r--gcc/d/ChangeLog-20171175
-rw-r--r--gcc/d/Make-lang.in337
-rw-r--r--gcc/d/config-lang.in33
-rw-r--r--gcc/d/d-attribs.cc835
-rw-r--r--gcc/d/d-builtins.cc1169
-rw-r--r--gcc/d/d-codegen.cc2660
-rw-r--r--gcc/d/d-convert.cc805
-rw-r--r--gcc/d/d-diagnostic.cc358
-rw-r--r--gcc/d/d-frontend.cc628
-rw-r--r--gcc/d/d-incpath.cc195
-rw-r--r--gcc/d/d-lang.cc1797
-rw-r--r--gcc/d/d-longdouble.cc204
-rw-r--r--gcc/d/d-spec.cc503
-rw-r--r--gcc/d/d-target-def.h20
-rw-r--r--gcc/d/d-target.cc394
-rw-r--r--gcc/d/d-target.def60
-rw-r--r--gcc/d/d-target.h34
-rw-r--r--gcc/d/d-tree.def29
-rw-r--r--gcc/d/d-tree.h675
-rw-r--r--gcc/d/decl.cc2312
-rw-r--r--gcc/d/dmd/access.c572
-rw-r--r--gcc/d/dmd/aggregate.h336
-rw-r--r--gcc/d/dmd/aliasthis.c169
-rw-r--r--gcc/d/dmd/aliasthis.h30
-rw-r--r--gcc/d/dmd/apply.c150
-rw-r--r--gcc/d/dmd/argtypes.c486
-rw-r--r--gcc/d/dmd/arrayop.c638
-rw-r--r--gcc/d/dmd/arraytypes.h62
-rw-r--r--gcc/d/dmd/attrib.c1602
-rw-r--r--gcc/d/dmd/attrib.h275
-rw-r--r--gcc/d/dmd/blockexit.c502
-rw-r--r--gcc/d/dmd/boostlicense.txt23
-rw-r--r--gcc/d/dmd/canthrow.c317
-rw-r--r--gcc/d/dmd/checkedint.c238
-rw-r--r--gcc/d/dmd/checkedint.h35
-rw-r--r--gcc/d/dmd/clone.c1198
-rw-r--r--gcc/d/dmd/compiler.h29
-rw-r--r--gcc/d/dmd/complex_t.h71
-rw-r--r--gcc/d/dmd/cond.c369
-rw-r--r--gcc/d/dmd/cond.h107
-rw-r--r--gcc/d/dmd/constfold.c1918
-rw-r--r--gcc/d/dmd/cppmangle.c1103
-rw-r--r--gcc/d/dmd/ctfe.h267
-rw-r--r--gcc/d/dmd/ctfeexpr.c2108
-rw-r--r--gcc/d/dmd/dcast.c3732
-rw-r--r--gcc/d/dmd/dclass.c1947
-rw-r--r--gcc/d/dmd/declaration.c2534
-rw-r--r--gcc/d/dmd/declaration.h899
-rw-r--r--gcc/d/dmd/delegatize.c210
-rw-r--r--gcc/d/dmd/denum.c748
-rw-r--r--gcc/d/dmd/dimport.c480
-rw-r--r--gcc/d/dmd/dinterpret.c6801
-rw-r--r--gcc/d/dmd/dmacro.c463
-rw-r--r--gcc/d/dmd/dmangle.c865
-rw-r--r--gcc/d/dmd/dmodule.c1436
-rw-r--r--gcc/d/dmd/doc.c2741
-rw-r--r--gcc/d/dmd/doc.h14
-rw-r--r--gcc/d/dmd/dscope.c702
-rw-r--r--gcc/d/dmd/dstruct.c1463
-rw-r--r--gcc/d/dmd/dsymbol.c1781
-rw-r--r--gcc/d/dmd/dsymbol.h406
-rw-r--r--gcc/d/dmd/dtemplate.c8602
-rw-r--r--gcc/d/dmd/dversion.c202
-rw-r--r--gcc/d/dmd/entity.c2392
-rw-r--r--gcc/d/dmd/enum.h95
-rw-r--r--gcc/d/dmd/errors.h50
-rw-r--r--gcc/d/dmd/escape.c1234
-rw-r--r--gcc/d/dmd/expression.c6945
-rw-r--r--gcc/d/dmd/expression.h1559
-rw-r--r--gcc/d/dmd/expressionsem.c8740
-rw-r--r--gcc/d/dmd/func.c5626
-rw-r--r--gcc/d/dmd/globals.h317
-rw-r--r--gcc/d/dmd/hdrgen.c3414
-rw-r--r--gcc/d/dmd/hdrgen.h54
-rw-r--r--gcc/d/dmd/iasm.c44
-rw-r--r--gcc/d/dmd/iasmgcc.c356
-rw-r--r--gcc/d/dmd/identifier.c190
-rw-r--r--gcc/d/dmd/identifier.h49
-rw-r--r--gcc/d/dmd/idgen.c503
-rw-r--r--gcc/d/dmd/impcnvgen.c599
-rw-r--r--gcc/d/dmd/imphint.c56
-rw-r--r--gcc/d/dmd/import.h60
-rw-r--r--gcc/d/dmd/init.c286
-rw-r--r--gcc/d/dmd/init.h119
-rw-r--r--gcc/d/dmd/initsem.c920
-rw-r--r--gcc/d/dmd/intrange.c460
-rw-r--r--gcc/d/dmd/intrange.h149
-rw-r--r--gcc/d/dmd/json.c890
-rw-r--r--gcc/d/dmd/json.h17
-rw-r--r--gcc/d/dmd/lexer.c2401
-rw-r--r--gcc/d/dmd/lexer.h75
-rw-r--r--gcc/d/dmd/macro.h42
-rw-r--r--gcc/d/dmd/mangle.h33
-rw-r--r--gcc/d/dmd/mars.h95
-rw-r--r--gcc/d/dmd/module.h179
-rw-r--r--gcc/d/dmd/mtype.c9410
-rw-r--r--gcc/d/dmd/mtype.h934
-rw-r--r--gcc/d/dmd/nogc.c241
-rw-r--r--gcc/d/dmd/nspace.c234
-rw-r--r--gcc/d/dmd/nspace.h38
-rw-r--r--gcc/d/dmd/objc.c84
-rw-r--r--gcc/d/dmd/objc.h53
-rw-r--r--gcc/d/dmd/opover.c1966
-rw-r--r--gcc/d/dmd/optimize.c1268
-rw-r--r--gcc/d/dmd/parse.c7992
-rw-r--r--gcc/d/dmd/parse.h188
-rw-r--r--gcc/d/dmd/readme.txt13
-rw-r--r--gcc/d/dmd/root/aav.c175
-rw-r--r--gcc/d/dmd/root/aav.h20
-rw-r--r--gcc/d/dmd/root/array.h232
-rw-r--r--gcc/d/dmd/root/ctfloat.h47
-rw-r--r--gcc/d/dmd/root/dcompat.h18
-rw-r--r--gcc/d/dmd/root/file.c265
-rw-r--r--gcc/d/dmd/root/file.h54
-rw-r--r--gcc/d/dmd/root/filename.c673
-rw-r--r--gcc/d/dmd/root/filename.h51
-rw-r--r--gcc/d/dmd/root/hash.h77
-rw-r--r--gcc/d/dmd/root/object.h60
-rw-r--r--gcc/d/dmd/root/outbuffer.c401
-rw-r--r--gcc/d/dmd/root/outbuffer.h77
-rw-r--r--gcc/d/dmd/root/port.h43
-rw-r--r--gcc/d/dmd/root/rmem.c162
-rw-r--r--gcc/d/dmd/root/rmem.h35
-rw-r--r--gcc/d/dmd/root/root.h19
-rw-r--r--gcc/d/dmd/root/rootobject.c49
-rw-r--r--gcc/d/dmd/root/speller.c240
-rw-r--r--gcc/d/dmd/root/speller.h16
-rw-r--r--gcc/d/dmd/root/stringtable.c200
-rw-r--r--gcc/d/dmd/root/stringtable.h57
-rw-r--r--gcc/d/dmd/safe.c168
-rw-r--r--gcc/d/dmd/sapply.c156
-rw-r--r--gcc/d/dmd/scope.h158
-rw-r--r--gcc/d/dmd/sideeffect.c439
-rw-r--r--gcc/d/dmd/statement.c1661
-rw-r--r--gcc/d/dmd/statement.h783
-rw-r--r--gcc/d/dmd/statementsem.c3574
-rw-r--r--gcc/d/dmd/staticassert.c104
-rw-r--r--gcc/d/dmd/staticassert.h32
-rw-r--r--gcc/d/dmd/staticcond.c100
-rw-r--r--gcc/d/dmd/target.h74
-rw-r--r--gcc/d/dmd/template.h397
-rw-r--r--gcc/d/dmd/tokens.c476
-rw-r--r--gcc/d/dmd/tokens.h233
-rw-r--r--gcc/d/dmd/traits.c1451
-rw-r--r--gcc/d/dmd/typesem.c123
-rw-r--r--gcc/d/dmd/unittests.c26
-rw-r--r--gcc/d/dmd/utf.c307
-rw-r--r--gcc/d/dmd/utf.h117
-rw-r--r--gcc/d/dmd/utils.c122
-rw-r--r--gcc/d/dmd/version.h45
-rw-r--r--gcc/d/dmd/visitor.h599
-rw-r--r--gcc/d/expr.cc3138
-rw-r--r--gcc/d/gdc.texi718
-rw-r--r--gcc/d/imports.cc208
-rw-r--r--gcc/d/intrinsics.cc846
-rw-r--r--gcc/d/intrinsics.def154
-rw-r--r--gcc/d/lang-specs.h29
-rw-r--r--gcc/d/lang.opt346
-rw-r--r--gcc/d/longdouble.h136
-rw-r--r--gcc/d/modules.cc853
-rw-r--r--gcc/d/runtime.cc315
-rw-r--r--gcc/d/runtime.def224
-rw-r--r--gcc/d/toir.cc1447
-rw-r--r--gcc/d/typeinfo.cc1676
-rw-r--r--gcc/d/types.cc986
-rw-r--r--gcc/d/verstr.h1
178 files changed, 159347 insertions, 0 deletions
diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog
new file mode 100644
index 0000000..b90ba71
--- /dev/null
+++ b/gcc/d/ChangeLog
@@ -0,0 +1,617 @@
+2018-10-26 Eugene Wissner <belka@caraus.de>
+
+ * Make-lang.in (selftest-d): New.
+ * d-diagnostic.cc (vwarning): Fix warning emitting.
+
+2018-10-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.cc (lang_specific_driver): Always link against phobos if any
+ input file is given.
+
+2018-10-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_get_alias_set): Always return zero.
+
+2018-10-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (maybe_set_intrinsic): Don't set built-in flag on
+ unsupported pow() overloads.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::binop_assignment): Call stabilize_reference on
+ LHS construct if it has side effects.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (clear_intrinsic_flag): Remove function.
+ (maybe_expand_intrinsic): Remove clear_intrinsic_flag call.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (expand_intrinsic_copysign): Use mathfn_built_in to
+ determine correct built-in to call.
+ (expand_intrinsic_pow): Likewise.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (expand_intrinsic_sqrt): Remove implicit int to double
+ conversion.
+ (expand_intrinsic_pow): Likewise.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_frame_for_symbol): Use error_at.
+ (build_frame_type): Likewise.
+ (get_framedecl): Likewise.
+ * d-lang.cc (d_parse_file): Likewise.
+ * decl.cc (DeclVisitor::visit(StructDeclaration)): Likewise.
+ (DeclVisitor::finish_vtable): Likewise.
+ (DeclVisitor::visit(ClassDeclaration)): Likewise.
+ (DeclVisitor::visit(InterfaceDeclaration)): Likewise.
+ (DeclVisitor::visit(EnumDeclaration)): Likewise.
+ (DeclVisitor::visit(VarDeclaration)): Likewise.
+ * toir.cc (IRVisitor::check_goto): Likewise.
+ (IRVisitor::check_previous_goto): Likewise.
+ (IRVisitor::visit(ThrowStatement)): Likewise.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_array_length): Use quoted format flag in message.
+ (d_build_call): Likewise.
+ * d-lang.cc (d_handle_option): Likewise.
+ * decl.cc (DeclVisitor::finish_vtable): Likewise.
+ * expr.cc (ExprVisitor::visit(ArrayLengthExp)): Likewise.
+ (ExprVisitor::visit(DeleteExp)): Likewise.
+ (ExprVisitor::visit(RemoveExp)): Likewise.
+ (ExprVisitor::visit(RemoveExp)): Likewise.
+ (ExprVisitor::visit(CallExp)): Likewise.
+ (ExprVisitor::visit(DotVarExp)): Likewise.
+ (ExprVisitor::visit(VarExp)): Likewise.
+ (ExprVisitor::visit(ScopeExp)): Likewise.
+ (ExprVisitor::visit(TypeExp)): Likewise.
+ (build_expr): Likewise.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-diagnostic.cc (d_diagnostic_report_diagnostic): Skip translation
+ by instead calling diagnostic_set_info_translated.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (bool_type_node): Rename to d_bool_type.
+ (byte_type_node): Rename to d_byte_type.
+ (ubyte_type_node): Rename to d_ubyte_type.
+ (short_type_node): Rename to d_short_type.
+ (ushort_type_node): Rename to d_ushort_type.
+ (int_type_node): Rename to d_int_type.
+ (uint_type_node): Rename to d_uint_type.
+ (long_type_node): Rename to d_long_type.
+ (ulong_type_node): Rename to d_ulong_type.
+ (cent_type_node): Rename to d_cent_type.
+ (ucent_type_node): Rename to d_ucent_type.
+
+2018-10-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(PowExp)): Remove function.
+
+2018-10-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c: Rename to d-attribs.cc.
+ * d-spec.c: Rename to d-spec.cc.
+
+2018-10-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_gimplify_expr): Don't handle TREE_THIS_VOLATILE.
+
+2018-10-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-diagnostic.cc (vwarning): Update to use Diagnostic enum.
+ (vdeprecation): Likewise.
+ (vdeprecationSupplemental): Likewise.
+ * d-lang.cc (d_init_options): Explicitly set warnings and deprecations
+ as DIAGNOSTICoff.
+ (d_handle_option): Update to use Diagnostic enum.
+ (d_post_options): Likewise.
+
+2018-10-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-diagnostic.cc (expand_format): Rename to expand_d_format.
+ Updated all callers.
+
+2018-10-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_linemap): Rename function to make_location_t.
+ Updated all callers.
+ * d-tree.h (get_linemap): Rename declaration to make_location_t.
+
+2018-10-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::binary_op): Use POINTER_DIFF_EXPR.
+
+2018-10-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (expand_intrinsic_bsf): Assert that built-in function
+ code is not END_BUILTINS.
+ (expand_intrinsic_bsr): Likewise.
+ (expand_intrinsic_bswap): Likewise.
+ (expand_intrinsic_popcnt): Likewise.
+
+2018-10-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * config-lang.in (gtfiles): Add modules.cc.
+ * modules.cc: Include gt-d-modules.h.
+ (module_info): Mark with GTY.
+ (static_ctor_list): Likewise.
+ (static_dtor_list): Likewise.
+
+2018-10-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.c (lang_specific_driver): Use strrchr and strcmp to check
+ input file suffix.
+
+2018-10-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.c (phobos_action): New enum.
+ (library): Rename to phobos_library.
+ (lang_specific_driver): Update to use phobos_library.
+ (lang_specific_pre_link): Likewise.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc (Port::writelongLE): Remove function.
+ (Port::writelongBE): Remove function.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-convert.cc (convert): Remove goto maybe_fold.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (warn_for_null_address): New function.
+ (build_boolop): Warn about comparing address of decl to null.
+ * d-convert.cc (decl_with_nonnull_addr_p): New function.
+ (d_truthvalue_conversion): Warn about evaluating address as boolean.
+ * d-tree.h (decl_with_nonnull_addr_p): Add declaration.
+ * lang.opt (Waddress): New option.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_array_length): Assert that argument type is a
+ dynamic array.
+ (d_array_ptr): Likewise.
+ (d_array_value): Likewise.
+ (delegate_method): Assert that argument type is a delegate.
+ (delegate_object): Likewise.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c (handle_malloc_attribute): Use gcc_assert instead of
+ gcc_unreachable.
+ (handle_pure_attribute): Likewise.
+ (handle_nothrow_attribute): Likewise.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in: Rename compiler proper to d21.
+ * config-lang.in (compilers): Rename compiler to d21.
+ * d-spec.c (lang_specific_driver): Update comments.
+ * lang-specs.h: Rename compiler to d21.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang.opt: Add missing periods to the ends of sentences.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Remove handling of -fdeps.
+ (d_parse_file): Don't generate module dependencies.
+ * lang.opt (fdeps, fdeps=): Remove options.
+ (fintfc, fintfc-dir=, fintfc-file=): Remove options.
+ (ftransition=safe): Remove option.
+
+2018-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init_ts): Remove handling of IASM_EXPR.
+ (d_gimplify_expr): Likewise.
+ * d-tree.def (IASM_EXPR): Remove tree code.
+
+2018-10-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attrib.c (attr_noreturn_exclusions): Attribute not mutually
+ exclusive with self.
+ * typeinfo.cc (TypeInfoVisitor::layout_interfaces): Assert that
+ base class vtable is found in interface.
+
+2018-10-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (DeclVisitor): Add using Visitor::visit.
+ * expr.cc (ExprVisitor): Likewise.
+ * imports.cc (ImportVisitor): Likewise.
+ * toir.cc (IRVisitor): Likewise.
+ * typeinfo.cc (TypeInfoVisitor): Likewise.
+ (TypeInfoDeclVisitor): Likewise.
+ (SpeculativeTypeVisitor): Likewise.
+ * types.cc (TypeVisitor): Likewise.
+
+2018-10-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc: Include compiler.h, errors.h, expression.h.
+ (genCmain): Rename function to Compiler::genCmain.
+ (Compiler::paintAsType): New function.
+ (Compiler::loadModule): New function.
+ (getTypeInfoType): Call error function directly.
+ * d-lang.cc (deps_write): Use hash_set for dependency tracking.
+ (d_parse_file): Call Compiler::loadModule.
+ * d-target.cc: Remove include identifier.h, module.h.
+ (Target::paintAsType): Remove function.
+ (Target::loadModule): Remove function.
+ (Target::getTargetInfo): New function.
+
+2018-10-01 Eugene Wissner <belka@caraus.de>
+
+ * decl.cc (finish_thunk): Adjust call to cgraph_node::create_thunk.
+
+2018-09-25 Eugene Wissner <belka@caraus.de>
+
+ * d-codegen.cc (d_assert_call): Don't make STRING_CSTs larger than they
+ are.
+ * expr.cc (ExprVisitor::visit(StringExp)): Likewise.
+ * typeinfo.cc (TypeInfoVisitor::layout_string): Likewise.
+
+2018-09-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc: Include expression.h, identifier.h.
+ * d-codegen.cc: Include identifier.h.
+ * d-convert.cc: Include declaration.h.
+ * d-frontend.cc: Include identifier.h.
+ * d-lang.cc: Include declaration.h, expression.h, identifier.h.
+ (d_parse_file): Call moduleToBuffer to get string dump of contents.
+ * d-target.cc: Include declaration.h, expression.h, identifier.h.
+ * expr.cc: Include identifier.h.
+ * imports.cc: Include identifier.h.
+ * intrinsics.cc: Include identifier.h.
+ * modules.cc: Include identifier.h.
+ * toir.cc: Include expression.h, identifier.h.
+ * typeinfo.cc: Include expression.h, identifier.h.
+ * types.cc: Include expression.h, identifier.h.
+
+2018-09-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_INCLUDES): Rename dfrontend to dmd.
+ (d/%.o): Likewise.
+ (d/%.dmdgen.o): Likewise.
+ * verstr.h: Update to 2.076.1
+
+2018-09-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (maybe_expand_intrinsic): Handle INTRINSIC_EXP.
+ * intrinsics.def (EXP): Add CTFE intrinsic.
+
+2018-09-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc: Include errors.h, mars.h.
+ * decl.cc: Include errors.h.
+ * typeinfo.cc: Include globals.h, errors.h.
+
+2018-09-05 Eugene Wissner <belka@caraus.de>
+
+ * d-frontend.cc (eval_builtin): Replace DECL_BUILT_IN with
+ fndecl_built_in_p.
+
+2018-08-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc (Target::prefixName): Remove function.
+ (Target::cppParameterType): New function.
+
+2018-08-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Add iasm.o, iasmgcc.o
+ * lang.opt (fproperty): Remove option.
+ * d-lang.cc (d_handle_option): Remove case for OPT_fproperty.
+ * toir.cc (IRVisitor::visit(ExtAsmStatement)): Rename override to
+ GccAsmStatement.
+
+2018-07-23 Eugene Wissner <belka@caraus.de>
+
+ * d-lang.cc (d_handle_option): Change function argument to HOST_WIDE_INT.
+ * lang.opt (Walloca-larger-than=, Wno-alloca-larger-than): New options.
+ * opt.texi (Walloca-larger-than=, Wno-alloca-larger-than): Likewise.
+
+2018-07-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (get_symbol_decl): Set all generated static symbols as
+ DECL_EXTERNAL. Move logic for determining TREE_STATIC ...
+ (start_function): ... here.
+ (d_finish_decl): Update TLS model after finishing variable linkage.
+
+2018-07-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (d.tags): Rename dfrontend to dmd.
+ * d-attribs.c: Rename dfrontend includes to dmd.
+ * d-builtins.cc: Likewise.
+ * d-codegen.cc: Likewise.
+ * d-convert.cc: Likewise.
+ * d-diagnostic.cc: Likewise.
+ * d-frontend.cc: Likewise.
+ * d-incpath.cc: Likewise.
+ * d-lang.cc: Likewise.
+ * d-longdouble.cc: Likewise.
+ * d-target.cc: Likewise.
+ * decl.cc: Likewise.
+ * expr.cc: Likewise.
+ * imports.cc: Likewise.
+ * intrinsics.cc: Likewise.
+ * modules.cc: Likewise.
+ * runtime.cc: Likewise.
+ * toir.cc: Likewise.
+ * typeinfo.cc: Likewise.
+ * types.cc: Likewise.
+
+2018-07-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc (same_type_p): Check type codes match before checking
+ equivalence.
+
+2018-07-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Makefile.in (d/verstr.h): Remove recipe.
+ (d.mostlyclean): Remove cleanup of verstr.h.
+ * verstr.h: New file.
+
+2018-07-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (lower_struct_comparison): Evaluate side effects of
+ empty struct.
+ (build_struct_comparison): Likewise.
+
+2018-07-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * typeinfo.cc (TypeInfoVisitor::layout_interfaces): Only generate an
+ interface vtable for classes.
+ (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Likewise.
+
+2018-07-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (deps_write): Ignore __main module.
+ (d_handle_option): Handle -fmain option.
+ (d_parse_file): Generate D main function if requested.
+ * lang.opt (fmain): New option.
+
+2018-07-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (d_build_builtins_module): Export __builtin_clonglong
+ and __builtin_culonglong to gcc builtins module.
+
+2018-07-04 Eugene Wissner <belka@caraus.de>
+
+ * d-spec.c: Include opt-suggestions.h containing option_proposer used by
+ gcc.h.
+
+2018-07-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (get_symbol_decl): Implicitly convert return type of 'void'
+ main to 'int' for both C and D entry functions.
+ * toir.cc (IRVisitor::visit(ReturnStatement)): Likewise.
+
+2018-06-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(FuncExp)): Don't error about nested
+ delegate literals.
+
+2018-06-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc (eval_builtin): Allow both gcc and frontend builtins.
+ * intrinsics.cc (call_builtin_fn): Use convert.
+ (expand_intrinsic_sqrt): Use fold_convert.
+ (expand_intrinsic_copysign): New function.
+ (expand_intrinsic_pow): New function.
+ (maybe_expand_intrinsic): Handle many math intrinsics.
+ * intrinsics.def (EXPM1, EXP2, LOG, LOG2, LOG10, ROUND, FLOORF),
+ (FLOOR, FLOORL, CEILF, CEIL, CEILL, TRUNC, FMIN, FMAX, COPYSIGN),
+ (POW, FMA): Add math intrinsics.
+
+2018-06-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (find_aggregate_field): Move to decl.cc
+ (build_class_instance): Move to decl.cc, make static.
+ * d-tree.h (build_class_instance): Remove declaration.
+ * decl.cc (DeclVisitor::finish_vtable): New function.
+
+2018-06-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc (TypeVisitor::visit(TypeClass)): Handle get_symbol_decl
+ returning an error_mark_node.
+
+2018-06-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (DeclVisitor::visit(FuncDeclaration)): Move function
+ unnesting to...
+ (get_symbol_decl): ... here.
+
+2018-06-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_post_options): Set global showColumns parameter.
+
+2018-06-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-diagnostic.cc (expand_format): Handle whitespace format specifier.
+ (d_diagnostic_report_diagnostic): Change signature, updated all
+ callers. Handle writing messages verbatim.
+ (vmessage): New function.
+ * d-lang.cc (d_parse_file): Use message to emit verbose diagnostics.
+ * decl.cc (DeclVisitor::visit(FuncDeclaration)): Likewise.
+ (get_symbol_decl): Likewise.
+
+2018-06-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_frontend_type): Use Type::merge2 to merge
+ generated front-end types.
+ * d-codegen.cc (declaration_type): Likewise.
+ (type_passed_as): Likewise.
+ * d-convert.cc (convert_expr): Use ClassDeclaration::isCPPclass.
+ * d-lang.cc (d_build_eh_runtime_type): Likewise.
+ * toir.cc (IRVisitor::visit): Use ClassDecalration::isCPPclass.
+ * typeinfo.cc (TypeInfoVisitor::visit): Use Type::merge2 to merge
+ generated front-end types.
+ * types.cc (layout_aggregate_type): Use ClassDeclaration::isCPPclass.
+
+2018-05-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(StringExp)): Copy string literal from
+ the frontend to a null terminated string.
+
+2018-05-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::binary_op): Don't do complex conversions if
+ already handling excess precision.
+
+2018-04-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (doing_semantic_analysis_p): New variable.
+ (d_parse_file): Set when in semantic pass.
+ * d-tree.h (doing_semantic_analysis_p): Add declaration.
+ * intrinsics.cc (maybe_expand_intrinsic): Test for
+ doing_semantic_analysis_p.
+
+2018-03-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (stabilize_expr): Move modify expression rewrite...
+ * expr.cc (ExprVisitor::binop_assignment): ... here.
+
+2018-03-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(StringExp)): Include null terminator
+ in length when calling build_String. Generate static array string
+ literals as array constructors.
+
+2018-03-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Rename OPT_fintfc cases to OPT_H.
+ * gdc.texi (Code Generation): Rename -fintfc options to -H.
+ * lang-specs.h: Add H, Hd, and Hf options.
+ * lang.opt (H, Hd, Hf): New options.
+ (fintfc, fintfc-dir=, fintfc-file=): Deprecate and alias new options.
+
+2018-03-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang.opt (fdeps, fdeps=): Deprecate options.
+ * gdc.texi (Code Generation): Remove deprecated fdeps options.
+
+2018-02-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Remove inline.o and inlinecost.o.
+
+2018-02-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc (CTFloat::fabs): Assign result to real_t directly.
+ (CTFloat::ldexp): Likewise.
+ * d-longdouble.cc (longdouble::from_int): Remove function.
+ (longdouble::from_uint): Likewise.
+ (longdouble::to_int): Update Signature.
+ (longdouble::to_uint): Likewise.
+ (longdouble::operator): Likewise.
+ (longdouble::add): New function, move operator overload headers.
+ (longdouble::sub, longdouble::mul, longdouble::div): Likewise.
+ (longdouble::mod, longdouble::neg): Likewise.
+ (longdouble::cmp, longdouble::equals): Likewise.
+ * d-target.cc (Target::_init): Construct assignment into real_t
+ directly.
+
+2018-02-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (DMD_WARN_CXXFLAGS): Only filter out
+ -Wmissing-format-attribute from WARN_CXXFLAGS.
+
+2018-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_frontend_type): Set alignment of structs in
+ frontend.
+
+2018-02-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-incpath.cc (add_environment_paths): Remove function.
+ * gdc.texi (Environment Variables): Remove section.
+
+2018-02-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::AssertExp): Use builtin expect to mark assert
+ condition as being likely true.
+
+2018-02-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang.opt (fd-vgc, fd-verbose, fd-vtls): Remove options.
+ (femit-moduleinfo, femit-templates): Likewise.
+ (fmake-deps, fmake-mdeps): Likewise.
+ (fin, fout, fXf): Likewise.
+
+2018-01-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * gdc.texi (Runtime Options): Remove deprecated -fproperty option.
+
+2018-01-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_gimplify_expr): Gimplify all CALL_EXPR_ARGS_ORDERED
+ call arguments, not just non-constant.
+
+2018-01-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (DeclVisitor::visit(VarDeclaration)): Don't reuse existing
+ temporary for TARGET_EXPR.
+ (declare_local_var): Push all variables to current binding level.
+
+2018-01-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * toir.cc (build_function_body): Set input_location.
+
+2018-01-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_frame_type): Don't add chain field for
+ functions without context pointer.
+ (build_closure): Don't set chain field for functions without context
+ pointer.
+
+2018-01-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (DeclVisitor::visit(StructDeclaration)): Mark compiler
+ generated symbols as DECL_ONE_ONLY instead of DECL_COMDAT.
+ (DeclVisitor::visit(ClassDeclaration)): Likewise.
+ (DeclVisitor::visit(InterfaceDeclaration)): Likewise.
+ (DeclVisitor::visit(EnumDeclaration)): Likewise.
+ (get_symbol_decl): Mark template instantiations as DECL_ONE_ONLY
+ instead of DECL_COMDAT. Don't call mark_needed.
+ (declare_extern_var): Don't call mark_needed.
+ (d_finish_decl): Remove zero initializer for common symbols.
+ (finish_thunk): Don't call d_comdat_linkage on generic thunk.
+ (d_comdat_linkage): Don't set DECL_DECLARED_INLINE on functions.
+ * typeinfo.cc (TypeInfoDeclVisitor::visit(TypeInfoDeclaration)): Mark
+ built-in typeinfo symbols as DECL_ONE_ONLY instead of DECL_COMDAT.
+
+2018-01-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init): Disable flag_weak if not supported.
+ * decl.cc (d_comdat_linkage): Use flag_weak to guard setting
+ DECL_ONE_ONLY on decls.
+ (d_linkonce_linkage): New function.
+ * gdc.texi (Runtime Options): Document -fweak.
+ * lang.opt (fweak): Declare.
+
+2018-01-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decls.cc (get_symbol_decl): Use attribute to mark naked functions.
+
+2018-01-08 Eugene Wissner <belka@caraus.de>
+
+ * d-builtins.cc (d_eval_constant_expression): Handle polynomial
+ VECTOR_CST_NELTS.
+ (build_frontend_type): Handle polynomial TYPE_VECTOR_SUBPARTS.
+
+2018-01-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ Update copyright years.
+
+Copyright (C) 2018 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2006 b/gcc/d/ChangeLog-2006
new file mode 100644
index 0000000..4160b0f
--- /dev/null
+++ b/gcc/d/ChangeLog-2006
@@ -0,0 +1,954 @@
+2006-12-27 DF <dvdfrdmn@users.sf.net>
+
+ * phobos/internal/fpmath.d: Support x86_64
+
+ * phobos/configure.in: x86_64 can use fpmath.d
+ * phobos/configure: update
+
+ * target-ver-syms.sh: Add some CPU architectures
+
+2006-12-26 DF <dvdfrdmn@users.sf.net>
+
+ * phobos/configure.in: actually use value of
+ --enable-phobos-config-dir
+
+2006-12-26 David Friedman <dvdfrdmn@users.sf.net>
+
+ Rest of 0.178 changes:
+
+ * phobos/std/bitarray.d: revert previous changes
+
+ * d-decls.cc (toSymbolX): update
+
+ * d-glue.cc (TypeFunction::retStyle): implement
+
+ * phobos/std/format.d: update for Mangle.Tenum
+
+ -------------
+
+ Initial merge of 0.178:
+
+ * dmd/class.c, dmd/declaration.c, dmd/declaration.h, dmd/doc.c,
+ dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/init.c,
+ dmd/lexer.c, dmd/mangle.c, dmd/mars.c, dmd/mars.h, dmd/mtype.c,
+ dmd/optimize.c, dmd/parse.c, dmd/statement.c, dmd/statement.h,
+ dmd/template.c, dmd/tocsym.c, dmd/toobj.c: Merge 0.178
+
+ * phobos/internal/gc/win32.d, phobos/internal/object.d,
+ phobos/std/c/linux/linux.d, phobos/std/date.d,
+ phobos/std/dateparse.d, phobos/std/format.d, phobos/std/gc.d,
+ phobos/std/regexp.d, phobos/std/socket.d, phobos/std.ddoc: Merge
+ 0.178
+
+ ---------------
+
+ * dmd/constfold.c (CastExp::constFold): Fix Bugzilla 738.
+
+ * dmd/todt.c (StructDeclaration::toDt): Fix Bugzilla 736.
+
+ * d-decls.cc (VarDeclaration::toSymbol): Fix Bugzilla 737.
+
+ * d-glue.cc (make_assign_math_op): Fix Bugzilla 739.
+
+ * d-codegen.cc, d-decls.cc, d-glue.cc, symbol.cc, symbol.h:
+ Use toParent2. Handle nested template instance functions.
+ (Bugzilla 742, 743)
+
+2006-12-25 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/mtype.c: Don't use '@' in mangled names
+
+ * d-glue.cc (TypeFunction::toCtype): Handle recursive type
+ reference (Bugzilla 745)
+
+ * d-codegen.cc, d-codegen.h, d-glue.cc, d-objfile.cc, d-objfile.h,
+ dmd/aggregate.h, dmd/attrib.c, dmd/class.c, dmd/declaration.c,
+ dmd/declaration.h, dmd/enum.c, dmd/enum.h, dmd/func.c,
+ dmd/idgen.c, dmd/scope.c, dmd/scope.h, dmd/struct.c: Implement
+ GCC attributes.
+
+ * dmd/mtype.c (TypeDelegate::dotExp): Fix regression caused by
+ last fix.
+
+2006-12-24 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/parse.h, dmd/parse.c(parseStatement, parseExtAsm),
+ dmd/statement.h, asmstmt.cc: Implement GCC extended assembler.
+
+2006-12-20 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/mars.h: format issues are due to newlib, not Cygwin
+
+ * setup-gcc.sh: Fix sed patterns and options.
+
+ * dmd/mtype.c (TypeDelegate::dotExp): Handle .ptr so that
+ it can be an lvalue. (Bugzilla 696)
+
+ * d-irstate.cc (getLoopForLabel): Handle labels pointing to
+ ScopeStatements. (Bugzilla 695)
+
+2006-12-16 David Friedman <dvdfrdmn@users.sf.net>
+
+ Release GDC 0.20
+
+ * setup-gcc.sh: account for modified version strings
+
+ * dmd/mtype.c (TypeTuple::toDecoBuffer): workaround newlib bug
+
+ * dmd/mars.h: fix printf formats for Cygwin
+
+ * d-builtins.c (d_init_builtins): Handle va_list type when it is
+ an array.
+
+ * gcc-mars.cc, gdc-version: update
+
+ * d-decls.cc: warnings cleanup
+
+ * dmd/expression.c (realToMangleBuffer): filter out 'x'
+
+2006-12-13 David Friedman <dvdfrdmn@users.sf.net>
+
+ * package/simple.sh: use MAKE environment variable
+
+2006-12-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ * patch-build_gcc-4.0: don't disable Objective C
+
+2006-12-09 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/bitarray.d (unittest): workaround 0.177 breakage
+
+ * phobos/std/format.d,
+ * phobos/std/string.d,
+ * phobos/std/loader.d: update
+
+ * phobos/std/file.d: fix merge. update.
+
+ * dmd/root.[ch] (writestring): make arg const
+
+ * dmd/expression.c (toMangleBuffer): update
+
+ Initial 0.177 merges
+
+ * dmd/constfold.c, dmd/declaration.c, dmd/expression.[ch],
+ dmd/func.c, dmd/idgen.c, dmd/manlge.c, dmd/mars.c, dmd/mtype.[ch],
+ dmd/opover.c, dmd/tocsym.c, dmd/toobj.c, dmd/typinf.c: Merge 0.177
+
+ * etc/c/zlib.d, phobos/internal/aaA.d, phobos/internal/adi.d,
+ phobos/internal/arraycat.d, phobos/internal/gc/gc.d,
+ phobos/internal/gc/testgc.d, phobos/internal/object.d,
+ phobos/internal/qsort.d, phobos/internal/switch.d,
+ phobos/internal/trace.d, phobos/object.d, phobos/std/array.d,
+ phobos/std/boxer.d, phobos/std/conv.d, phobos/std/cover.d,
+ phobos/std/cpuid.d, phobos/std/date.d, phobos/std/file.d,
+ phobos/std/format.d, phobos/std/loader.d, phobos/std/math2.d,
+ phobos/std/md5.d, phobos/std/mmfile.d, phobos/std/outbuffer.d,
+ phobos/std/path.d, phobos/std/regexp.d, phobos/std/socket.d,
+ phobos/std/stream.d, phobos/std/string.d, phobos/std/switcherr.d,
+ phobos/std/syserror.d, phobos/std/typeinfo/ti_Acdouble.d,
+ phobos/std/typeinfo/ti_Acfloat.d, phobos/std/typeinfo/ti_Acreal.d,
+ phobos/std/typeinfo/ti_Adchar.d, phobos/std/typeinfo/ti_Adouble.d,
+ phobos/std/typeinfo/ti_Afloat.d, phobos/std/typeinfo/ti_Ag.d,
+ phobos/std/typeinfo/ti_Aint.d, phobos/std/typeinfo/ti_Along.d,
+ phobos/std/typeinfo/ti_Areal.d, phobos/std/typeinfo/ti_Ashort.d,
+ phobos/std/typeinfo/ti_Aubyte.d, phobos/std/typeinfo/ti_Auint.d,
+ phobos/std/typeinfo/ti_Aulong.d, phobos/std/typeinfo/ti_Aushort.d,
+ phobos/std/typeinfo/ti_Awchar.d, phobos/std/uri.d,
+ phobos/std/utf.d, phobos/std/windows/charset.d,
+ phobos/std/windows/registry.d, phobos/std/zlib.d: Merge 0.177
+
+ --------------
+
+ * patch-apple-gcc-4.0.x, patch-build_gcc-4.0: Support
+ building the Apple way on PowerPC machines.
+
+2006-12-06 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (call): Fix for calling delegate literal.
+
+ * setup-gcc.sh: fail if patching build_gcc fails
+
+ * d-glue.cc (NewExp::toElem): expand stack vars
+ for GCC 3.x
+
+ * phobos/std/cpuid.d: fix for cpuid kludge
+
+2006-12-05 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/mars.h: Handle msvcrt C99 printf incompatibility.
+
+ * dmd/template.c, dmd/declaration.c, dmd/expression.c, dmd/func.c,
+ dmd/init.c, dmd/lexer.c, dmd/mangle.c, dmd/mtype.c,
+ dmd/optimize.c, dmd/root.c: ditto
+
+ * phobos/config/unix-mid: fix compile error
+
+2006-12-04 David Friedman <dvdfrdmn@users.sf.net>
+
+ More 0.176 merges
+
+ * phobos/config/unix-mid: add reentrant funcs
+
+ * d-glue.cc (DeleteExp::toElem): handle on-stack vars
+
+ * d-glue.cc (FuncDeclaration::toObjFile): emit _arguments
+
+ * dmd/declaration.h, dmd/func.c: save _arguments local var for
+ backend
+
+2006-12-03 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc: New _arguments ABI.
+
+ * gcc-mars.cc: Update for verror.
+
+ * d-decls.cc, d-objfile.cc,
+ * d-glue.cc (Module::genobjfile, d_gcc_aggregate_dtors): Update
+ for new toSymbolX.
+
+ * d-glue.cc (TypeAArray::toCtype): Implement new AA ABI.
+
+ * d-codegen.cc (convertTo): Don't allow conversion of dynamic
+ array to associated array and vice versa.
+
+ * d-codegen.cc (getLibCallDecl, rawArray, convertForCondition),
+ d-glue.cc (NullExp::toElem): change AA type
+
+ * gcc-mars.cc : printf corrections
+
+ * phobos/Makefile.in (MAIN_OBJS): add bind.o
+
+ Initial merge of DMD 0.176
+
+ * attrib.c, dmd/cast.c, dmd/class.c, dmd/cond.c, dmd/constfold.c,
+ dmd/declaration.c, dmd/doc.c, dmd/dsymbol.h, dmd/dump.c,
+ dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/idgen.c,
+ dmd/init.c, dmd/init.h, dmd/lexer.c, dmd/link.c, dmd/mangle.c,
+ dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/mtype.c, dmd/optimize.c,
+ dmd/parse.c, dmd/root.c, dmd/statement.c, dmd/template.c,
+ dmd/tocsym.c, dmd/todt.c, dmd/toobj.c: Merge 0.176
+
+ * internal/aaA.d, phobos/internal/cmath2.d, phobos/internal/deh.c,
+ phobos/internal/object.d, phobos/linux.mak,
+ phobos/std/c/linux/linux.d, phobos/std/c/linux/socket.d,
+ phobos/std/compiler.d, phobos/std/math.d, phobos/std/socket.d,
+ phobos/std/string.d, phobos/std/traits.d,
+ phobos/std/typeinfo/ti_Aubyte.d, phobos/std/typeinfo/ti_ubyte.d,
+ phobos/std.ddoc, phobos/win32.mak: Merge 0.176
+
+ * phobos/std/bind.d: New file in 0.176
+
+ * dmd/toir.[ch]: New files (from DMD 0.175)
+
+ * phobos/phobos.d: New file (from DMD 0.160)
+
+ --------------
+
+ * phobos/std/boxer.d (unbox(T : void*).unbox): fix
+
+ * d-glue.cc (NewExp::toElem): Support allocation on stack
+
+ Initial merge of DMD 0.175
+
+ * cast.c, dmd/class.c, dmd/dchar.c, dmd/dchar.h,
+ dmd/declaration.c, dmd/declaration.h, dmd/delegatize.c,
+ dmd/dsymbol.c, dmd/dump.c, dmd/enum.c, dmd/expression.c,
+ dmd/expression.h, dmd/func.c, dmd/identifier.c, dmd/identifier.h,
+ dmd/inifile.c, dmd/init.c, dmd/lexer.c, dmd/lstring.h,
+ dmd/mangle.c, dmd/mars.c, dmd/mtype.c, dmd/mtype.h,
+ dmd/optimize.c, dmd/parse.c, dmd/root.c, dmd/root.h, dmd/scope.c,
+ dmd/scope.h, dmd/statement.c, dmd/statement.h, dmd/stringtable.c,
+ dmd/todt.c, dmd/typinf.c: Merge 0.175
+
+ dmd/html.c: not merged
+
+ * phobos/internal/object.d, phobos/std/demangle.d,
+ phobos/std/format.d, phobos/std/socket.d, phobos/std/stdio.d,
+ phobos/std/traits.d, phobos/std/uni.d, phobos/std.ddoc:
+ Merge 0.175
+
+ ------------
+
+ * config/darwin8, config/mingw: update config fragments
+
+2006-11-26 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc, d-glue.cc: Fix missing continue label
+ expansion for GCC < 4.0
+
+ * d-glue.cc (make_math_op): Convert non-complex to complex
+ in all version of GCC. (Buzilla 575)
+
+ * d-codegen.cc: for tree code class for GCC < 4.0
+
+ * phobos/Makefile.in: make test programs dependendent on
+ libgphobos.a as gdc will still try to find it
+
+ * phobos/configure.in: conditionally build std/boxer.o
+
+ * phobos/Makefile.in (MAIN_OBJS): remove std/boxer.o
+
+ * phobos/internal/arraycat.d (_d_array_literal): disable
+
+ * phobos/std/format.d: fix for PowerPC Linux
+
+2006-11-25 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-gcc-real.h: cleanup for warnings
+
+2006-11-24 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (DotVarExp::toElem): Handle const members.
+
+ * d-codegen.cc (needs_temp): Return false for constants.
+ (isFreeOfSideEffects): New function.
+
+ * d-glue.cc (do_array_set): Evaluate the rvalue only once
+ (Bugzilla 578).
+
+2006-11-18 David Friedman <dvdfrdmn@users.sf.net>
+
+ Rest of DMD 0.174 merge:
+
+ * dmd/mtype.c (TypeDelegate::dotExp): Use cast-to-pointer
+ for .ptr property
+
+ * d-decls.cc (VarDeclaration::toSymbol): Build CONST_DECLs
+ * d-codegen.cc (IRState::emitLocalVar): Do nothing if CONST_DECL
+
+ * d-codegen.cc (ArrayScope::setArrayExp): Handle tuple/constant
+ lengths.
+
+ * dmd/toobj.c (Dsymbol::toObjFile): emit local variables for
+ tuples
+
+ * svn: move traits.d and typetuple.d to the correct directory
+
+ * gcc-mars.cc (error): add va_list form
+
+ * dmd/mars.h (error): use va_list for 'error'
+
+ * dmd/expression.c, dmd/lexer.c: fix compile errors
+
+ * phobos/Makefile.in (MAIN_OBJS): add traits.o and typetuple.o
+
+ * dmd-script: add -v1 option
+
+ * dmd/root.c (FileName::ensurePathExists): fix conditions
+ for non-win32, non-linux.
+
+ * dmd-script (printUsage): add missing options documentation
+
+ * d-codegen.{h, cc}: use size_t
+
+ * phobos/internal/dgccmain2.d: update
+
+ Initial merge of DMD 0.174:
+
+ * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/declaration.c,
+ dmd/declaration.h, dmd/doc.c, dmd/dsymbol.c, dmd/dsymbol.h,
+ dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/hdrgen.c,
+ dmd/idgen.c, dmd/inline.c, dmd/lexer.c, dmd/mangle.c, dmd/mars.c,
+ dmd/mars.h, dmd/module.c, dmd/mtype.c, dmd/mtype.h, dmd/parse.c,
+ dmd/statement.c, dmd/template.c, dmd/template.h, dmd/tocsym.c,
+ dmd/todt.c, dmd/toobj.c, dmd/typinf.c, dmd/utf.c, dmd/utf.h: Merge
+ 0.174
+
+ * phobos/internal/aApplyR.d, phobos/internal/dmain2.d,
+ phobos/internal/object.d, phobos/linux.mak, phobos/object.d,
+ phobos/std/date.d, phobos/std/openrj.d, phobos/std/signals.d,
+ phobos/win32.mak: Merge 0.174
+
+ * phobos/std/traits.d, phobos/std/typetuple.d: New files in 0.174
+
+
+2006-11-17 David Friedman <dvdfrdmn@users.sf.net>
+
+ * package/simple.sh: enhancements
+
+ * dmd/attrib.c: fix message
+
+2006-11-16 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (continueHere): fix error
+ * d-glue.cc (d_gcc_aggregate_dtors): "
+
+2006-11-14 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-builtins2.cc, d-codegen.{cc, h}, d-decls.cc, d-glue.cc,
+ d-lang.h: remove D_TYPE_IS_NESTED. Do not pull original
+ TypeFunction from FUNCTION_TYPE.
+
+ * d-codegen.cc: cleanup
+
+ * d-codegen.cc, gdc-alloca.h, phobos/config/gen_unix.c: fixes for
+ older MacOS X builds
+
+2006-11-13 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/cpuid.d: fixes for PIC
+
+ * d-asm-i386.h: Fix for referencing funcs (Bugzilla 307).
+ Correct clobbers for cpuid, but left out EBX as a kludge for
+ std.cpuid.
+
+ * phobos/std/c/linux/linux.d: make imports public (Bugzilla 403)
+
+ * d-decls.cc (uniqueName): Fixed logic error (Bugzilla 375). Then
+ just removed most of the code and comments because the workaround
+ is no longer needed.
+
+2006-11-12 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/root.c (Object::hashCode): cast to pointer acceptable int type
+
+ Rest of DMD 0.173 merge:
+
+ * d-glue.cc (UnrolledLoopStatement::toIR): implement
+
+ * d-codegen.h (setContinueLabel): add interface for multiple continues
+
+ * d-irstate.h (Flow), d-irstate.cc: add overrideContinueLabel for
+ GCC < 4.0
+
+ * d-builtins2.cc, d-glue.cc, d-codegen.cc: update for
+ TypeFunction::arguments -> parameters and tuples
+
+ * dmd/func.c: update
+
+ * d-gcc-complex_t.h: update
+
+ * phobos/Makefile.in (MAIN_OBJS): add signals.o and cpuid.o
+
+ Initial merge of DMD 0.173:
+
+ * dmd/arraytypes.h, dmd/cast.c, dmd/class.c, dmd/complex_t.h,
+ dmd/constfold.c, dmd/declaration.c, declaration.h,
+ dmd/delegatize.c, dmd/doc.c, dmd/dsymbol.c, dmd/dsymbol.h,
+ expression.c, dmd/expression.h, dmd/func.c, dmd/html.c,
+ dmd/html.h, dmd/inline.c, lexer.c, dmd/lexer.h, dmd/mars.c,
+ dmd/mars.h, dmd/mem.h, dmd/mtype.c, dmd/mtype.h, opover.c,
+ dmd/optimize.c, dmd/parse.c, dmd/parse.h, dmd/statement.c,
+ dmd/statement.h, struct.c, dmd/template.c, dmd/template.h,
+ dmd/tocsym.c, dmd/toobj.c, dmd/typinf.c: Merge 0.173
+
+ * phobos/internal/object.d, phobos/linux.mak, phobos/std/stream.d,
+ phobos/std/string.d, phobos/std/system.d, phobos/std.ddoc,
+ phobos/unittest.d, phobos/win32.mak: Merge 0.173
+
+ * phobos/std/c/locale.d, phobos/std/cpuid.d, phobos/std/signals.d:
+ New files in 0.173
+
+ ----
+
+ * dmd/class.c, dmd/mars.c, dmd/opover.c, dmd/statement.c:
+ Merge DMD 0.172
+
+ Merge DMD 0.171:
+
+ * dmd/func.c, dmd/optimize.c: Update comments
+
+ * dmd/aggregate.h, dmd/class.c, dmd/func.c, dmd/mars.c:
+ Merge 0.171
+
+ * phobos/internal/aApplyR.d, phobos/internal/gc/gc/.d: Merge 0.171
+
+ ----
+
+ Rest of DMD 0.170 merge:
+
+ * d-glue.cc (ArrayLiteralExp::toElem): Handle the case in which
+ the type of the expression is a pointer.
+
+ * dmd/optimize.c (PtrExp::optimize): Don't change type
+ of expression without cast
+
+ * phobos/internal/aApplyR.d: turn off debug(apply)
+
+2006-11-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (ForeachStatement::toIR): support foreach_reverse
+
+ * dmd/lexer.c: size_t -> unsigned
+
+ * d-lang.cc (d_handle_option): update
+
+ * phobos/Makefile.in: add aApplyR.o
+
+ * phobos/internal/monitor.c: merged
+
+ Initial merge of DMD 0.170:
+
+ * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/delegatize.c,
+ dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/func.c,
+ dmd/identifier.c, dmd/idgen.c, dmd/import.c, dmd/lexer.c,
+ dmd/lexer.h, dmd/mangle.c, dmd/mars.c, dmd/module.c, dmd/mtype.c,
+ dmd/mtype.h, dmd/opover.c, dmd/parse.c, dmd/statement.c,
+ dmd/statement.h, dmd/template.h, dmd/utf.h: Merge 0.170
+
+ * phobos/internal/aApply, phobos/internal/cast.d,
+ phobos/internal/gc/gc.d, phobos/internal/mars.h,
+ phobos/internal/object.d, phobos/linux.mak, phobos/object.d,
+ phobos/std/gc.d, phobos/std/math.d, phobos/std/outofmemory.d,
+ phobos/std/path.d, phobos/std/zlib.d, phobos/std.ddoc,
+ phobos/unittest.d, phobos/win32.mak: Merge 0.170
+
+ * internal/monitor.c: not changed; merge deferred for now
+
+ * phobos/internal/aApplyR.d: new file in 0.170
+
+ ----
+
+ Rest of 0.169 merge:
+
+ * phobos/internal/object.d: fix merge error
+
+ * d-asm-i386.h: update for DMD changes
+
+ * dmd/mtype.c, phobos/internal/adi.d (_adSortChar, _adSortWchar):
+ fix for calling conventions
+
+ * d-gcc-complex_t.h: updated
+
+ Initial merge of DMD 0.169:
+
+ * dmd/aggregate.h, dmd/arraytypes.h, dmd/attrib.h, dmd/class.c,
+ dmd/complex_t.h, dmd/cond.h, dmd/declaration.h, dmd/declaration.c,
+ dmd/doc.h, dmd/dsymbol.c, dmd/dsymbol.h, dmd/enum.h,
+ dmd/expression.c, dmd/expression.h, dmd/hdrgen.h, dmd/html.h,
+ dmd/identifier.h, dmd/idgen.c, dmd/import.c, dmd/import.h,
+ dmd/init.c, dmd/init.h, dmd/lexer.h, dmd/macro.h, dmd/macro.c,
+ dmd/mars.c, dmd/mars.h, dmd/module.c, dmd/module.h, dmd/mtype.c,
+ dmd/mtype.h, dmd/opover.c, dmd/optimize.c, dmd/parse.h,
+ dmd/root.c, dmd/scope.c, dmd/scope.h, dmd/statement.c,
+ dmd/statement.h, dmd/staticassert.h, dmd/struct.c, dmd/template.c,
+ dmd/template.h, dmd/total.h, dmd/typinf.c, dmd/utf.h,
+ dmd/version.h: Merge 0.169
+
+ * phobos/internal/adi.d, phbobos/internal/critical.c,
+ phbobos/internal/mars.h, phbobos/internal/monitor.c,
+ phbobos/internal/object.d, phbobos/object.d, phbobos/std/regexp.d:
+ Merge 0.169
+
+ ----
+
+ * dmd-script: Create directories for output files
+
+ Rest of 0.168 changes:
+
+ * d-dmd-gcc.h, d-glue.cc (d_gcc_aggregate_dtors): new function
+ * dmd/toobj.c (ClassDeclaration::toObjFile): use d_gcc_aggregate_dtors
+
+ * d-codegen.cc (convertTo): handle delegate .ptr property
+
+ * lang-specs.h, dmd-script: handle .xhtml extension
+
+ Initial merge of DMD 0.168
+
+ * dmd/aggregate.h, dmd/arraytypes.h, dmd/cast.c, dmd/class.c,
+ dmd/declaration.c, dmd/expression.h, dmd/func.c, dmd/html.[ch],
+ dmd/idgen.c, dmd/init.c, dmd/lexer.c, dmd/lexer.h, dmd/link.c,
+ dmd/mangle.c, dmd/mars.c, dmd/module.c, dmd/mtype.[ch],
+ dmd/statement.c, dmd/toobj.c, dmd/typeinf.c: Merge 0.168
+
+ * phobos/etc/gamma.d, phobos/internal/object.d,
+ phobos/std/c/linux/linux.d.orig-dmd, phobos/std/date.d,
+ phobos/std/math.d, phobos/std/socket.d, phobos/std/socketstream.d,
+ phobos/std/stream.d, phobos/std/uni.d, phobos/win32.mak: Merge 0.168
+
+2006-11-10 David Friedman <dvdfrdmn@users.sf.net>
+
+ * Make-lang.in (d.install-common): cross install fix for gdmd
+
+ * d-glue.cc (NewExp::toElem): uint -> unsigned
+
+ * package/simple.sh: Don't depend on rsync
+
+ * patch-toplev-3.4.x, patch-toplev-4.0.x: Modify top-level
+ Makefile.in, configure.in, and configure to work with
+ a Canadian cross build.
+
+ * d-glue.cc (SynchronizedStatement::toIR): Remove uneeded
+ startBindings call. Add missing _d_criticalenter call.
+
+2006-10-12 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/config/unix-mid: add sysconf
+
+2006-10-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/format.d (doFormat): support Mangle.Tstruct for p_args
+
+ * phobos/config/unix-head: import tm from gcc.config
+
+ * phobos/config/gen_unix.c (c_time): Moved out struct tm.
+
+ * phobos/config/gen_config1.c: Support clock_t. Move struct tm here.
+
+ * d-glue.cc (AssignExp::toElem): use _d_arraysetlength3p
+ (FuncDeclaration::toObjFile): Fixed assert of class member if
+ synchronized.
+
+ * d-codegen.{h, cc}: replace libcall _d_arraysetlength2p with
+ _d_arraysetlength3p
+
+ * phobos/internal/gc/gc.d (_d_arraysetlength3p): pointer version
+ of _d_arraysetlength3. GCC asm jump fix.
+
+2006-10-09 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.{h, cc}: new libcalls: _dnewmp, _d_newarraymip
+
+ * phobos/internal/gc/gc.d (_dnewmp, _d_newarraymip): pointer version
+ of _dnewm, _d_newarraymi
+
+ * phobos/config/unix-mid: add utime
+
+ * phobos/std/file.d: changes for GDC
+
+ * phobos/config/gen_unix.c: support utimbuf
+
+2006-09-23 David Friedman <dvdfrdmn@users.sf.net>
+
+ Initial merge of 0.167:
+
+ * dmd/array.c, dmd/cast.c, dmd/declaration.c, dmd/delegatize.c,
+ dmd/expression.[ch], dmd/func.c, dmd/idgen.c, dmd/import.c,
+ dmd/init.c, dmd/inline.c, dmd/lexer.[ch], dmd/mars.c,
+ dmd/mtype.[ch], dmd/optimize.c, dmd/parse.c, dmd/statement.c,
+ dmd/template.c, dmd/typinf.c: Merge 0.167
+
+ * phobos/internal/arraycat.d, phobos/internal/gc/gc.d,
+ phobos/internal/gc/testgc.d, phobos/internal/object.d,
+ phobos/linux.mak, phobos/object.d, phobos/std/asserterror.d,
+ phobos/std/c/linux/linux.d.orig-dmd, phobos/std/c/time.d,
+ phobos/std/file.d, phobos/std/format.d, phobos/std/math.d,
+ phobos/std/string.d, phobos/std/thread.d, phobos/unittest.d,
+ phobos/win32.mak: Merge 0.167
+
+ * phobos/std/c/windows/stat.d: New 0.167
+
+2006-09-06 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (FuncDelaration::toObjFile):
+ Assert isMember for synchronized functions.
+ (NewExp::toElem): Correct some cases for nested classes
+
+2006-09-04 David Friedman <dvdfrdmn@users.sf.net>
+
+ * gdc-version, gcc-mars.cc: update
+
+ * d-codegen.cc (trueDeclarationType): support lazy arguments
+ (trueArgumentType): ditto
+
+ * d-codegen.{h, cc}: comment out convertForInitialization
+
+ * Make-lang.in (D_DMD_OBJS): add delegatize
+
+ * dmd/delegatize.c: new, DMD 0.166
+
+ * dmd/cast.c, dmd/declaration.[ch], dmd/expression.[ch],
+ dmd/func.c, dmd/inline.c, dmd/lexer.c, dmd/lexer.h, dmd/mars.c,
+ dmd/mtype.c, dmd/mtype.h, dmd/opover.c, dmd/parse.c,
+ dmd/statement.c, dmd/struct.c, dmd/template.c, dmd/tocsym.c,
+ dmd/typinf.c: Merge DMD 0.166
+
+ * phobos/etc/c/zlib/...: Merge 0.166
+
+ * phobos/internal/aApply.d, phobos/internal/gc/linux.mak,
+ phobos/linux.mak, phobos/std/cover.d, phobos/std/utf.d,
+ phobos/win32.mak: Merge 0.166
+
+ * phobos/etc/zlib/infblock.[ch], phobos/etc/zlib/infcodes.[ch],
+ phobos/etc/zlib/infutil.[ch], phobos/etc/zlib/maketree.c,
+ phobos/etc/zlib/zlib.html: remove, DMD 0.166
+
+ * gdc-version: update
+
+ * d-glue.cc (FuncDeclaration::toObjFile): update
+
+ * dmd/cast.c, dmd/declaration.[ch], dmd/enum.c,
+ dmd/expression.[ch], dmd/func.c, dmd/init.c, dmd/inline.c,
+ dmd/mars.c, dmd/mtype.c, dmd/statement.c, dmd/template.c,
+ dmd/typeinf.c: Merge DMD 0.165
+
+ * phobos/internal/gc/gcx.d, phobos/std.ddoc: Merge DMD 0.165
+
+ * gdc-version: updated
+
+ * dmd/aggregate.h, dmd/declaration.[ch], dmd/doc.c, dmd/dsymbol.c,
+ dmd/expression.c, dmd/import.c, dmd/inifile.c, dmd/mars.c,
+ dmd/module.[ch], dmd/mtype.c, dmd/parse.c, dmd/statement.c,
+ dmd/template.c: Merge DMD 0.164
+
+ * phobos/std/socket.d: Merge DMD 0.164
+ * phobos/std/thread.d: no change
+
+2006-07-22 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/internal/gc/testgc.d: add import
+
+ * phobos/std/thread.d (Thread.thread_init, Thread.getESP): make
+ public
+
+ * phobos/std/c/unix/unix.d: use public import
+
+ * dmd/access.c, dmd/aggregate.h, dmd/attrib.c, dmd/class.c,
+ dmd/declaration.[ch], dmd/enum.c, dmd/expression.c, dmd/func.c,
+ dmd/import.[ch], dmd/mars.c, dmd/module.c, dmd/mtype.[ch],
+ dmd/parse.[ch], dmd/scope.[ch], dmd/struct.c, dmd/template.[ch],
+ dmd/todt.c: Merge DMD 0.163
+
+ * phobos/internal/object.d, phobos/std/c/linux/linux.d.orig-dmd,
+ phobos/std/regexp.d, phobos/std/stdio.d, phobos/std/stream.d:
+ Merge DMD 0.163
+
+2006-07-12 David Friedman <dvdfrdmn@users.sf.net>
+
+ Release GDC 0.19
+
+ * dmd/template.c: don't use ehfilter
+ * gdc-version: update
+
+2006-07-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ Support for Apple GCC and other fixes
+
+ * setup-gcc.sh: patch build_gcc
+ * patch-build_gcc-4.0: new
+
+ * dmd-script: Support -arch option and apple driver naming.
+ Use absolute path to execute program with -run.
+
+2006-07-10 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/config/darwin8/{frag-gen,frag-math,frag-unix}: new
+ * phobos/configure.in: support Darwin cross compiling
+ * phobos/configure.in: updated
+
+ * phobos/config/gen_unix.c (c_fcntl): added *_OK enums
+ * phobos/config/skyos/frag-unix: updated
+
+2006-07-03 David Friedman <dvdfrdmn@users.sf.net>
+
+ * ../../gcc/tree.h, ../../gcc/tree-dump.c: machine readable dump
+
+ Merge DMD 0.162
+
+ * d-glue.cc (AssignExp::toElem): use _d_arraysetlength2p
+
+ * phobos/internal/gc/gc.d: chanage _d_arraysetlength2 to
+ _d_arraysetlength2p
+
+2006-07-02 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.{h, cc}: support _d_arraysetlength2
+
+ * dmd/cast.c, dmd/declaration.c, dmd/doc.c, dmd/expression.c,
+ dmd/func.c, dmd/mars.c, dmd/mtype.c, dmd/parse.c, dmd/struct.c,
+ dmd/template.[ch], dmd/toobj.c: merged
+
+ * phobos/internal/gc/gc.d, phobos/object.d,
+ phobos/std/asserterror.d, phobos/std/moduleinit.d: merged
+
+ ---
+
+ * phobos/std/regexp.d (RegExp.Range.setbitmax): fix for
+ big endian
+
+2006-06-28 DF <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (TypeStruct::toCtype, TypeEnum::toCtype): Move
+ initTypeDecl call to after size calculation.
+
+2006-06-24 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/Makefile.in: fix and clean up config.d dependencies
+
+ * d-gcc-real.cc (real_t): fix assumptions about HOST_WIDE_INT
+
+2006-06-23 David Friedman <dvdfrdmn@users.sf.net>
+
+ * Make-lang.in, asmstmt.cc, d-convert.cc, d-gcc-includes.h,
+ d-lang.cc, setup-gcc.sh: update to support building with Apple
+ GCC
+ * d-apple-gcc.cc, patch-apple-gcc-4.0.x: new
+
+ Misc fixes
+
+ * Make-lang.in: Add dependencies for DMD header files.
+
+ * phobos/config/gen_unix.c (c_time): fix array bounds bug
+
+2006-06-22 David Friedman <dvdfrdmn@users.sf.net>
+
+ * Make-lang.in: use BUILD_LDFLAGS for generator progs
+
+2006-06-21 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-asm-i386.h: implement offset/offsetof
+
+2006-06-20 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 0.161
+
+ * gcc-mars.cc, gdc-version: updated
+
+ * dmd/cast.c, dmd/class.c, dmd/declaration.[ch], dmd/dsymbol.c,
+ dmd/expression.[ch], dmd/func.c, dmd/idegen.c, dmd/import.h,
+ dmd/inline.c, dmd/lexer.[ch], dmd/mars.[ch], dmd/module.c,
+ dmd/mtype.c, dmd/opover.c, dmd/parse.c, dmd/root.[ch],
+ dmd/statement.c, dmd/struct.c, dmd/template.[ch], dmd/toobj.c:
+ Merge DMD 0.161
+
+ * phobos/internal/adi.d, phobos/internal/cast.d,
+ phobos/internal/trace.d, phobos/linux.mak,
+ phobos/std/asserterror.d, phobos/std/base64.d,
+ phobos/std/bitarray.d, phobos/std/boxer.d,
+ phobos/std/c/linux/socket.d, phobos/std/c/windows/windows.d,
+ phobos/std/c/windows/winsock.d, phobos/std/conv.d,
+ phobos/std/cstream.d, phobos/std/date.d, phobos/std/dateparse.d,
+ phobos/std/demangle.d, phobos/std/file.d, phobos/std/format.d,
+ phobos/std/math.d, phobos/std/math2.d, phobos/std/mmfile.d,
+ phobos/std/random.d, phobos/std/regexp.d, phobos/std/socket.d,
+ phobos/std/socketstream.d, phobos/std/stream.d,
+ phobos/std/string.d, phobos/std/stream.d, phobos/std/thread.d,
+ phobos/std/typeinfo/ti_Along.d, phobos/std/typeinfo/ti_Aulong.d,
+ phobos/std/tyeinfo/ti_void.d, phobos/std/uni.d, phobos/std/uri.d,
+ phobos/std/utf.d, phobos/std/windows/registry.d, phobos/std/zip.d,
+ phobos/std/zlib.d, phobos/std.ddoc, phobos/unittest.d,
+ phobos/win32.mak: Merge DMD 0.161
+
+ * Make-lang.in, d-lang.cc: Possible workaround for MingGW path
+ issues. Create d-confdefs.h to contain the values of D_PHOBOS_DIR
+ and D_PHOBOS_TARGET_DIR.
+
+2006-06-10 David Friedman <dvdfrdmn@users.sf.net>
+
+ * History: new file
+ * package/install.sif: ditto
+ * package/simple.sh:
+
+ * phobos/std/zip.d (putUshort): fix for BigEndian case
+
+ * phobos/internal/gc/gcgccextern.d: update for version(freebsd)
+
+ * target-ver-syms.sh: Use "freebsd" for FreeBSD.
+
+ * phobos/configure.in: Enable std.loader for FreeBSD.
+ * phobos/std/loader.d: ditto
+ * phobos/configure: updated
+
+ * Make-lang.in: Support package building. Cleanup.
+
+2006-06-08 David Friedman <dvdfrdmn@users.sf.net>
+
+ * patch-gcc-4.0.x: updated with...
+ * .../gcc/tree-nested.c: check if static chain is a PARM_DECL
+ (Bugzilla 175)
+
+2006-06-07 David Friedman <dvdfrdmn@users.sf.net>
+
+ * Make-lang.in: use CXX_FOR_BUILD
+
+ * phobos/std/format.d (unittest): Some C libraries do not support
+ the %A format.
+
+2006-06-06 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/config/skyos/frag-unix: update for SkyOS beta 10
+
+2006-06-05 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 0.160
+
+ * d-codegen.cc (arrayType): handle zero-length arrays for local
+ variables.
+
+ * gdc-version, gcc-mars.cc: update
+
+ * d-glue.cc (NewExp::toElem): support 'exp. new ...'
+
+ * d-codegen.{h, cc}: support _d_assert_msg
+
+ * dmd/attrib.c, dmd/enum.c, dmd/expression.[ch], dmd/idgen.c,
+ dmd/inifile.c, dmd/inline.c, dmd/mars.c, dmd/module.c,
+ dmd/mtype.c, dmd/opover.c, dmd/parse.[ch], dmd/statement.[ch],
+ dmd/staticassert.[ch], dmd/struct.c: Merge DMD 0.160
+
+ * phobos/std/asserterror.d, phobos/std/regexp.d,
+ phobos/std/zlib.d, phobos/std.ddoc, phobos/win32.mak: Merge DMD
+ 0.160
+
+2006-06-04 David Friedman <dvdfrdmn@users.sf.net>
+
+ Various fixes
+
+ * d-codegen.cc (twoFieldType): cleanup
+
+ * phobos/internal/gc/gc_dyld.c: correct callback signature
+
+ * phobos/std/format.d (unittest): Undo test change.
+ (putreal): Handle the case where real is equivalent to double.
+
+ * d-glue.cc (TypeClass::toCtype): use prepareTypeDecl instead of
+ setting an initial TYPE_NAME (Bugzilla 174)
+ (TypeStruct::toCtype): ditto
+ (TypeEnum::toCtype): ditto
+
+ * d-objfile.{h, cc} (prepareTypeDecl): New: Create type
+ declarations, but do not declare them to back end.
+
+ Merge DMD 0.159 and more
+
+ * d-asm-i386.h (parsePrimaryExp): handle floating point const
+ decls specially (Bugzilla 141)
+
+2006-06-03 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (AssertExp::toElem): handle interfaces
+
+ * phobos/std/math.d (poly): fix for darwin x86
+
+ * phobos/std/format.d (unittest): handle some variation in %a
+ formats
+
+ * gdc-version: updated
+
+ * gcc-mars.cc: updated
+
+ * dmd/attrib.c, dmd/attrib.h, dmd/class.c, dmd/declaration.c,
+ dmd/doc.c, dmd/expression.c, dmd/expression.h, dmd/func.c,
+ dmd/link.c, dmd/mars.c, dmd/module.c, dmd/module.h, dmd/parse.c,
+ dmd/parse.h, dmd/statement.c, dmd/staticassert.c, dmd/struct.c,
+ dmd/template.c, dmd/toobj.c: Merge DMD 0.159
+
+ * phobos/std/c/linux/linux.d.orig-dmd,
+ phobos/std/c/linux/linuxextern.d, phobos/std/c/windows/windows.d,
+ phobos/std/regexp.d, phobos/std/string.d, phobos/std/uni.d,
+ phobos/std.ddoc: Merge DMD 0.159
+
+ * dmd-script: use -O3 for GCC if -O is passed
+
+ Fix bugs 157, 162, 164, 171
+
+ * d-asm-i386.h: 'invlpg' instruction takes an operand (Bug 171)
+
+ * patch-gcc-4.0.x: updated with...
+ * .../gcc/tree-nested.c: use a VAR_DECL for custom static chain
+ (Bug 162, Bug 164)
+
+ * gdc-version: updated
+
+ * d-glue.cc (FuncExp::toElem): Handle Tpointer case. (Bug 157)
+
+2006-06-01 David Friedman <dvdfrdmn@users.sf.net>
+
+ * Start of SourceForge repository
+
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2007 b/gcc/d/ChangeLog-2007
new file mode 100644
index 0000000..a2e5043
--- /dev/null
+++ b/gcc/d/ChangeLog-2007
@@ -0,0 +1,1340 @@
+2007-12-15 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos*/Makefile.{am,in}, phobos*/aclocal.m4: Automake changes
+
+ * setup-gcc.sh: Support Apple GCC build 5465
+
+ * patch-apple-gcc-5465, patch-build_gcc-5465, patch-toplev-5465:
+ new files
+
+2007-12-01 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/config/unix.x3, phobos/config/x3.c, phobos/config/x3.h
+ phobos/config/x3, phobos/config/x3main.c: better diagnostics
+ and behavior
+
+2007-11-24 David Friedman <dvdfrdmn@users.sf.net>
+
+ * setup-gcc.sh: Ignore .svn directories when making symlink trees.
+
+ * d-bi-attrs-34.h, d-bi-attrs-341.h, d-bi-attrs-40,h,
+ d-bi-attrs-41.h: Support attributes on declarations in
+ other modules.
+
+ * d-codegen.cc (IRState::attributes): Support constant declarations
+ as string arguments.
+
+2007-11-08 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-cppmngl.cc: Use base-36 in substitutions. Other fixes.
+
+2007-10-17 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-cppmngl.cc: More C++ mangling fixes and cleanups.
+
+2007-10-16 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (EqualExp::toElem): Convert result to libcall
+ to expression type. (Bugzilla 1573)
+
+2007-10-15 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-cppmngl.cc: Improve C++ mangling.
+
+2007-10-14 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.022, 2.005
+
+ * dmd/..., dmd2/..., phobos/..., phobos2/...: Merge.
+
+ * Make-lang.in: Add builtin.dmd.o and d-cppmngl.o for V2.
+
+ * d-cppmngl.cc: New file
+
+ * phobos/std/c/dirent.d, phobos/std/c/linux/linux.d: Update
+ * phobs2/...: same
+
+ * symbol.h, d-decls.cc: Remove references to Classym
+
+ ----
+
+ * d-glue.cc (CatExp::toElem): Null check. (Bugzilla 1581)
+
+ Remove carriage returns from files
+
+2007-10-13 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (CatExp::toElem): Flatten multiple CatExps into a
+ single library call. (Bugzilla 1556)
+
+ * phobos/std/boxer.d (box, boxArray), phobos2/...: Fix for
+ promoted types. (Bugzilla 1543)
+
+ * d-codegen.cc (call): Catch a case in which a member function can
+ be called without 'this'. (Bugzilla 1568)
+
+ * dmd/mtype.c (TypeArray::dotExp): Correct return type of
+ sort and reverse functions. (SF 1809220 / Bugzilla 1554)
+
+ * dmd2/mtype.c: Ditto.
+
+ * patch-gcc-4.1.x: Add patch for ARM exception handling int nested
+ functions.
+
+ * d-objfile.cc: Make DT data TREE_CONSTANT
+
+ * dmd2/optimize.c: Fix for infinite recursion on initializer
+ when an error has already occurred.
+
+ -----
+
+ Add support for ARM EABI. Fix some missing items from
+ cross-compilation changes.
+
+ * d-lang.cc: Add "Arm" and "Thumb" version identifiers
+
+ * phobos/unwind.d: Move pointer encoding to deh_pe.d. Move generic
+ unwinder interface to unwind_generic.d. Import either generic or
+ ARM interfaces based on config value.
+
+ * phobos/unwind_generic.d, phobos/unwind_pe.d: New file; old code.
+
+ * phobos/unwind_arm.d: New file.
+
+ * phobos/deh.d: Support ARM exception handling ABI.
+
+ * phobos/configure.in, frag-ac.in: Add config for ARM unwinder
+
+ * phobos/configure.in, phobos/internal.c, phobos/monitor.c: Support
+ "no system" targets.
+
+ * phobos/cbridge_math.c: Correct identifier names for earlier
+ changes.
+
+ * phobos/Makefile.am, phobos/Makefile.in, phobos/config.h.in,
+ phobos/configure : Update.
+
+ * phobos2/...: Duplicate phobos/ changes
+
+2007-10-07 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge cross-compilation changes to phobos2
+
+ * phobos2/....: Merge
+
+ ---
+
+ Enhance cross-compilation support:
+
+ * phobos/Makefile.am, phobos/Makefile.in, phobos/acinclude.m4,
+ phobos/aclocal.m4, phobos/configure.in, phobos/configure,
+ phobos/config.h.in: Replace "fragment generation" with "X3"
+ system. Remove obsolete tests.
+
+ * phobos/config/{config-head, config-mid, config-tail}: Removed
+ * phobos/config/{makestruct.h, unix-head, unix-mid}: Removed
+ * phobos/{darwin8, mingw, skyos}: Removed
+
+ * phobos/config/{errno.x3, fpcls.x3, libc.x3, unix.x3},
+ phobos/config{x3, x3.c, x3.h, x3main.c}: New files
+
+ * phobos/frag-ac.in: Now only contains boolean constants.
+ * phobos/frag-math.in: New file. Contains old configured math
+ functions.
+
+ * phobos/gcc/configext.d: Removed
+ * phobos/gcc/support.d: Move fallback strtold definition here.
+
+ * phobos/Makefile.am: Do not compile std/c/stdio.o
+ * phobos/std/c/stdio.c: Change function definitions to external
+ declarations.
+
+ * phobos/gcc/deh.d, phobos/gcc/fpcls.d, phobos/gcc/fpmath.d,
+ phobos/gcc/support.d, phobos/gcc/threadsem.d,
+ phobos/internal/dgccmain2.d, phobos/internal/fpmath.d,
+ phobos/internal/gc/gcgcc.d, phobos/phobos-ver-syms.in,
+ phobos/std/c/dirent.d, phobos/std/c/math.d, phobos/std/c/stddef.d,
+ phobos/std/c/stdio.d, phobos/std/c/stdlib.d, phobos/std/c/time.d,
+ phobos/std/c/unix/unix.d, phobos/std/date.d, phobos/std/math.d,
+ phobos/std/math2.d, phobos/std/mmfile.d, phobos/std/random.d,
+ phobos/std/stdio.d, phobos/std/stream.d, phobos/std/system.d,
+ phobos/std/thread.d: Update. Add some support for targets
+ withouth an operation system.
+
+2007-09-24 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc (IndeExp::toElem), d-codegen.cc (arrayElemRef):
+ Put the BIND_EXPR "inside the brackets". (Bugzilla 1155)
+
+ (StructLiteralExp::toElem): Handle NULL elements (for anonymous
+ unions.)
+
+2007-09-23 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.{h,cc}, d-glue.cc: Add type to error_mark_node
+ for code that assumes the type of certain expressions.
+ (Bugzilla 1051)
+
+ * d-glue.cc (FuncDeclaration::toObjFile): Set DECL_IGNORED_P
+ on the frame paramter. (Bugzilla 1033)
+
+ * d-glue.cc, d-codegen.cc, d-objfile.cc: Set DECL_IGNORED_P
+ in most cases where DECL_ARTIFICIAL is set.
+
+ * d-builtins2.cc (d_gcc_magic_builtins_module): Handle type
+ declarations after converting functions.
+
+ * d-glue.cc (make_assign_math_op): Special case for division
+ when lhs is imaginary. (Bugzilla 739)
+
+ * dmd-script: Apply Ander's patch for implicit -H and -D
+ behavior. (Bugzilla 1502)
+
+ Use of -of argument does not depend on header generation.
+ (Bugzilla 1501)
+
+ * d-builtins2.cc, dmd*/module.c: If the target va_list is a
+ struct, add the struct declaration to the object module.
+ (Bugzilla 1507)
+
+ * dmd2/parse.c: fix line endings
+
+ ----
+
+ Update for D 2.0:
+
+ * Make-lang.in: Support both DMD front end version 1 and 2.
+ Replace gcc-mars.cc with d/mars.c.
+
+ * gcc-mars.cc: Remove file.
+
+ * d-codegen.h, d-codegen.cc: Update for DMD 2.x.
+ Add _d_hidden_func libcall.
+
+ * d-decls.cc, d-glue.cc: Update for DMD 2.x.
+
+ * d-dmd-gcc.h: Add rtlsym, etc.
+
+ * d-lange.cc: Include mars.h. Implement rtlsym.
+
+ * d-objfile.cc (ObjectFile::hasModule): Add checks to allow
+ this function to be called earlier.
+
+ * dmd*/mars.c: Make changes for GDC.
+
+ * dmd*/attrib.c: Use WANTinterpret for pragma(GNU_asm)
+
+ * dmd2/parse.c (parseDeclarator): Fix aliasing bug.
+
+ * rdmd.d: Update for D 2.0
+
+ * gdc-version: now only contains the GDC version
+
+ * setup-gcc.sh: Support building D version 1 or 2. Take DMD
+ version from dmd*/mars.c.
+
+ * dmd2/, phobos2/: New directories
+
+ * phobos2/Makefile.am (MAIN_OBJS): add std.c.stdio module
+ for std{in,out,err} vars
+
+ * phobos*/std/c/stdio.d: Make functions with definitions
+ extern(D).
+
+ * phobos2/std/loader.d: Update for D 2.0.
+
+ * phobos2/std/hiddenfunc.d: Use C calling conventions for GDC.
+
+2007-09-14 David Friedman <dvdfrdmn@users.sf.net>
+
+
+ * d-codegen.cc (convertTo, call): Prevent multiple re-evaluation
+ of delgate. (Bugzilla 1492)
+
+2007-09-13 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc, d-codegen.h, d-codegen.cc: Make it an error
+ to reference a nested function without a body. (SF 1793594)
+
+2007-09-12 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/config/ldfuncs-ppclinux: Declare sqrt.
+
+ * target-ver-syms.sh, phobos/acinclude.m4, phobos/configure.in:
+ Support kfreebsd.
+
+ * d-codegen.{h, cc}, d-glue.cc: Change rawArray to toDArray. Do
+ not cast result to void[]. (Bugzilla 1490)
+
+2007-09-07 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/c/stdio.d: Define fpos_t correctly for Drawin
+ (Bugzilla 1469)
+
+2007-09-05 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.021
+
+ * dmd-script, d-spec.c (lang_specific_driver): Support
+ -debuglib= and -defaultlib= options.
+
+ * dmd/cast.c, dmd/constfold.c, dmd/declaration.c, dmd/dsymbol.c,
+ dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/identifier.c,
+ dmd/idgen.c, dmd/init.c, dmd/init.h, dmd/interpret.c, dmd/lexer.c,
+ dmd/lexer.h, dmd/link.c, dmd/mars.c, dmd/mars.h, dmd/parse.c,
+ dmd/statement.c, dmd/staticassert.c, dmd/template.c: Merge
+
+ * internal/object.d, phobos/internal/trace.d, phobos/object.d,
+ phobos/std/c/windows/windows.d, phobos/std/date.d,
+ phobos/std/regexp.d, phobos/std/windows/registry.d: Merge
+
+ ---
+
+ * phobos/std/stdio.d (readln): Use the result of getdelim
+ correctly. (SF 1788195)
+
+ * d-glue.cc (FuncDeclaration::toObjFile): Do not gimplify if
+ there were errors (Bugzilla 1415)
+
+2007-08-31 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-objfile.cc (outdata): Do not set TREE_CONSTANT on initializers
+ (Bugzilla 1453)
+
+2007-08-29 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-decls.cc (uniqueName): Allow multiple static declaration with
+ the same name if in a function. (SF 1783085)
+
+2007-08-28 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (call): Use CommaExp correctly. (Bugzilla 1443)
+
+ * dmd/todt.c (createTsarrayDt): Don't take quadratic time to build
+ the initializer. (Bugzilla 1440)
+
+2007-08-22 David Friedman <dvdfrdmn@users.sf.net>
+
+ Release GDC 0.24
+
+ ---
+
+ * rdmd.d: Fix for Windows
+
+2007-08-21 David Friedman <dvdfrdmn@users.sf.net>
+
+ * GDC.html, History, README, gcc-mars.cc, gdc-version:
+ Update for 0.24
+
+ * rdmd.d, rdmd.1: New files. (Bugzilla 1152)
+
+ * patch-build_gcc-4.0: Build universal rdmd. (Bugzilla 1152)
+
+ * package/simple.sh: Install rdmd. (Bugzilla 1152)
+ Install man pages for MacOS build.
+
+ * dmd-script: Apply Ander's patch to make -op apply
+ to interface files. (Bugzilla 1137)
+
+ * d-lang.cc (d_parse_file): In -fall-sources mode,
+ only generate an interface file for the -fonly module.
+
+ * phobos/internal/adi.d (_adReverseChar, _adReverseWchar):
+ Make sure stride difference is signed.
+
+2007-08-20 David Friedman <dvdfrdmn@users.sf.net>
+
+ * patch-gcc-4.1.x, patch-gcc-4.0.x: Fix botched patches.
+
+2007-08-05 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (convertForArgument): Recognize
+ pointer arithmetic expression as reference.
+ (Bugzilla 1400)
+
+ * d-glue.cc (DotVarExp::toElem): Do not NOP_EXPR
+ the result. (Bugzilla 1398)
+
+2007-07-27 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/stdio: Fix breakage from last commit.
+ (SF 1761989)
+
+2007-07-26 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/c/stdio.d: Change import for gcc.config
+
+ * d-lang.cc: add flag_iso for target macros
+
+ * patch-gcc-4.0.x: (gcc/tree-sra.c): Do not use SRA
+ on structs with aliased fields created for anonymous
+ unions. (Followup to Bugzilla 1034)
+
+2007-07-25 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-lang.cc: implement d_gcc_is_target_win32
+
+ * dmd/parse.c (parseLinkage): use d_gcc_is_target_win32
+
+ * d-dmd-gcc.h (d_gcc_is_target_win32): added
+
+2007-07-24 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.019 - 1.020
+
+ * dmd/attrib.c, dmd/cast.c, dmd/constfold.c, dmd/declaration.h,
+ dmd/expression.c, dmd/expression.h, dmd/func.c, dmd/idgen.c,
+ dmd/inline.c, dmd/interpret.c, dmd/mars.c, dmd/mars.h,
+ dmd/mtype.c, dmd/mtype.h, dmd/opover.c, dmd/parse.c,
+ dmd/template.c, dmd/template.h, dmd/tocsym.c, dmd/toir.c: Merge
+
+ * phobos/internal/gc/gc.d, phobos/linux.mak,
+ phobos/std/demangle.d, phobos/std/format.d, phobos/std/loader.d,
+ phobos/std/socket.d, phobos/std/uni.d: Merge
+
+2007-07-22 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.015 - 1.018:
+
+ * dmd/lexer.c (escapeSequence): Change vendor string.
+
+ * dmd-script: Update documentation link
+
+ * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/declaration.c,
+ dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/func.c,
+ dmd/hdrgen.h, dmd/idgen.c, dmd/init.c, dmd/init.h, dmd/inline.c,
+ dmd/interpret.c, dmd/lexer.c, dmd/mars.c, dmd/mars.h,
+ dmd/module.c, dmd/mtype.c, dmd/mtype.h, dmd/optimize.c,
+ dmd/parse.c, dmd/scope.c, dmd/scope.h, dmd/statement.c,
+ dmd/statement.h, dmd/staticassert.c, dmd/template.c: Merge
+
+ * phobos/internal/dmain2.d, phobos/internal/gc/gcx.d,
+ phobos/internal/object.d, phobos/object.d, phobos/std/bind.d,
+ phobos/std/compiler.d, phobos/std/date.d, phobos/std/dateparse.d,
+ phobos/std/format.d, phobos/std/intrinsic.d, phobos/std/loader.d,
+ phobos/std/math2.d, phobos/std/metastrings.d, phobos/std/mmfile.d,
+ phobos/std/outbuffer.d, phobos/std/string.d,
+ phobos/std/windows/registry.d, phobos/win32.mak: Merge
+
+ ----
+
+ * gdc_alloca.h: Support OpenBSD. (Bugzilla 1065)
+
+ * patch-gcc-4.1.x (gcc/tree-sra.c): Do not use SRA
+ on structs with aliased fields created for anonymous
+ unions. (Bugzilla 1034)
+
+2007-07-19 David Friedman <dvdfrdmn@users.sf.net>
+
+ * patch-gcc-4.1.x (gcc/predict.c): Add null-pointer check.
+ (Bugzilla 1035)
+
+ ---
+
+ * phobos/std/format.d (doFormatPtr): Fix accidental
+ reversion from DMD merge.
+
+ * d-codegen.cc (maybeSetUpBuiltin): Add some missing
+ instrinsics.
+
+ * phobos/Makefile.am (MAIN_OBJS): Add gcc.builtins
+ module to get built-instruct initializers.
+
+ * phobos/Makefile.in: Regenerated
+
+ * d-lang.cc (d_parse_file): Call d_gcc_magic_module
+ for each module on the command line.
+
+ * d-builtins2.cc (d_gcc_magic_builtins_module): output
+ declaration other than funcs
+
+2007-07-16 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/todt.c (StructLiteralExp::toDt): Use target_size_t
+ as in StructInitializer::toDt.
+
+ Bugzilla 1032:
+
+ * dmd/todt.c: Use DT_container for arrays, array elements,
+ and structs
+
+ * dt.h, d-objfile.cc: Add DT_container / dtcontainer
+
+2007-07-14 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (ArrayScope::setArrayExp, finish): Handle
+ constant lengths. (Bugzilla 1031)
+
+2007-07-13 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (toElemLvalue): Use toElemLvalue recursively.
+ (Bugzilla 1191)
+
+ * d-codegen.cc (twoFieldCtor): Only set TREE_READONLY if
+ TREE_CONSTANT
+
+ * d-glue.cc (array_set_expr, AssocArrayLiteralExp::toElem,
+ (StructLiteralExp::toElem, NullExp::toElem):
+ Do not set TREE_READONLY.
+
+ * d-glue.cc (NewExp::toElem): Do not set TREE_READONLY on
+ new array dimensions.
+
+ * d-codegen.cc (darrayVal): Do not set TREE_READONLY.
+ (Bugzilla 1329)
+
+ (delegateVal): ditto
+
+ * d-codegen.cc (FieldVisitor::visit): Handle classes that
+ are forward references. (Bugzilla 1325)
+
+ * dmd-script: Pass -J option correctly. (SF 1721435)
+
+ * d-glue.cc (DeleteExp::toElem): Handle interfaces.
+ (SF 1721496)
+
+ * d-decls.cc (VarDeclaration::toSymbol): Handle void initializer.
+ (SF 1749622)
+
+ * d-glue.cc (AndAndExp, OrOrExp): Handle void second expression.
+ (SF 1689634)
+
+ * phobos/gcc/cbridge_time.c (_d_gnu_cbridge_tza): Remove
+ daylight saving time offset from tm_gmtoff (Bugzilla 1208)
+
+ * phobos/std/format.d (doFormat): Use original signature. Actual
+ work is done by new doFormatPtr. (Bugzilla 1109)
+
+ * phobos/std/boxer.d: Use doFormatPtr
+
+2007-07-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-convert.cc (default_conversion): make public
+ (SF 1711324 and 1709602)
+
+ * d-apple-gcc.c (build_function_call): re-enable some code
+
+2007-05-08 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-apple-gcc.c: Remove a variable that is now defined in d-lang.c
+
+ * d-lang.cc: Fix for other GCC versions.
+
+ * d-c-stubs.c: New file.
+
+ * Make-lang.in (D_BORROWED_C_OBJS): Always use C_TARGET_OBJS. Add
+ stubs for C compiler to allow linking target-specific preprocessor
+ defines.
+
+2007-05-05 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (hwi2toli, getTargetSizeConst): Fix 2x wide int to
+ long int conversion.
+
+ * dmd/cast.c (implicitConvTo): Use GCC floating point
+ routines instead of native.
+
+ * d-gcc-real.cc (toInt): Correctly convert to long integer
+
+ * Make-lang.in (D_DMD_H): Add d-gcc-real.h
+
+ * phobos/internal/dgccmain2.d: Print newline after error message
+
+2007-04-29 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.014:
+
+ * dmd/aggregate.h, dmd/constfold.c, dmd/delegatize.c, dmd/enum.c,
+ dmd/enum.h, dmd/expression.c, dmd/expression.h, dmd/idgen.c,
+ dmd/inline.c, dmd/interpret.c, dmd/lexer.c, dmd/lexer.h,
+ dmd/mars.c, dmd/mtype.c, dmd/optimize.c, dmd/struct.c,
+ dmd/template.c, dmd/tocsym.c, dmd/todt.c, dmd/toobj.c,
+ dmd/typinf.c: Merge.
+
+ * phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d,
+ phobos/std/format.d, phobos/std.ddoc: Merge.
+
+ * d-glue.d (StructLiteralExp::toElem): implement
+ * d-decls.d (EnumDeclaration::toInitializer): copy from tocsym.c
+
+ ------------
+
+ Merge DMD 1.013:
+
+ * dmd/cast.c, dmd/constfold.c, dmd/declaration.c,
+ dmd/expression.c, dmd/expression.h, dmd/interpret.c, dmd/link.c,
+ dmd/mars.c, dmd/mtype.c, dmd/opover.c, dmd/optimize.c,
+ dmd/parse.c, dmd/port.h, dmd/statement.c: Merge.
+
+ * phobos/internal/aaA.d, phobos/internal/switch.d,
+ phobos/std/date.d, phobos/std/file.d, phobos/std/format: Merge.
+
+ * d-codegen.h, d-codegen.cc: add _d_assocarrayliteralTp
+ * d-glue.cc (AssocArrayLiteralExp::toElem): Implement.
+
+ * phobos/internal/aaA.d (_d_assocarrayliteralT): modified
+ to use pointers to keys, values.
+
+ --------------
+
+ Merge DMD 1.012:
+
+ * arraytypes.h, dmd/declaration.c, dmd/delegatize.c,
+ dmd/expression.c, dmd/expression.h, dmd/init.c, dmd/init.h,
+ dmd/inline.c, dmd/interpret.c, dmd/lexer.c, dmd/lexer.h,
+ dmd/mangle.c, dmd/mars.c, dmd/optimize.c, dmd/template.c,
+ dmd/template.h: Merge
+
+ * phobos/internal/object.d: Merge
+
+ * dmd/template.c (TemplateInstance::mangle): printf portability
+
+ * d-glue.cc (AssocArrayLiteralExp::toElem): non-working implementation
+
+2007-04-28 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.011:
+
+ * dmd/access.c, dmd/aggregate.h, dmd/arraytypes.h, dmd/attrib.c,
+ dmd/attrib.h, dmd/bit.c, dmd/cast.c, dmd/class.c, dmd/complex_t.h,
+ dmd/cond.c, dmd/cond.h, dmd/constfold.c, 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/hdrgen.c, dmd/hdrgen.h, dmd/html.c, dmd/html.h,
+ dmd/identifier.c, dmd/identifier.h, dmd/idgen.c, dmd/impcnvgen.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/macro.c, dmd/macro.h, dmd/mangle.c, dmd/mars.c,
+ dmd/mars.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/scope.c, dmd/scope.h, dmd/statement.c, dmd/statement.h,
+ dmd/staticassert.c, dmd/staticassert.h, dmd/struct.c,
+ dmd/template.c, dmd/template.h, dmd/tocsym.c, dmd/todt.c,
+ dmd/toir.c, dmd/toir.h, dmd/toobj.c, dmd/total.h, dmd/typinf.c,
+ dmd/unialpha.c, dmd/utf.c, dmd/utf.h, dmd/version.c, dmd/version.h:
+ Merge
+
+ * phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d,
+ phobos/internal/object.d, phobos/std/c/locale.d,
+ phobos/std/stdio.d, phobos/std/windows/registry.d: Merge
+
+ * dmd/expression.c: Comment out some logging code.
+ * d-builtins2.cc: Update and fix handling of built-in structs.
+ * d-codegen.cc, d-glue.cc: Update
+
+ ----------------
+
+ Merge DMD 1.010:
+
+ * dmd/aggregate.h, dmd/class.c, dmd/declaration.c, dmd/doc.c,
+ dmd/dsymbol.c, dmd/expression.c, dmd/expression.h, dmd/func.c,
+ dmd/interpret.c, dmd/mars.c, dmd/scope.c, dmd/statement.c,
+ dmd/template.c, dmd/template.h, dmd/todt.c: Merge.
+
+ * phobos/internal/dmain2.d, phobos/internal/gc/gc.d,
+ phobos/internal/gc/gcx.d, phobos/internal/gc/testgc.d,
+ phobos/internal/object.d, phobos/object.d,
+ phobos/std/c/linux/linux.d, phobos/std/c/stdio.d,
+ phobos/std/file.d, phobos/std/gc.d, phobos/std/moduleinit.d,
+ phobos/std/regexp.d, phobos/std/stdio.d, phobos/std/string.d,
+ phobos/std.ddoc, phobos/win32.mak: Merge
+
+ * dmd/mtype.c, phobos/internal/dgccmain2.d: Update.
+ * d-glue.cc (gcc_d_backend_init): Update.
+
+ * phobos/config/unix-mid, phobos/std/c/unix/unix.d: Moved dirent
+ and stdio definitions out of configunix to std.c.unix.unix because
+ of compilation problems.
+
+ * phobos/internal/gc/gcx.d (GC.realloc, GC.extend, GC.free): Clear
+ gcx.p_cache
+
+ * phobos/std/stdio.d, phobos/frag-ac.in, phobos/configure.in:
+ Account for various configurations.
+
+ * phobos/phobos-ver-syms.in: Remove GNU_Have_fwide
+ * phobos/configure: Regenerate
+
+2007-04-22 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-gcc-includes.h, d-lang.cc: Add target-specific preprocessor
+ symbols to the list of D version symbols.
+
+ * d-glue.cc (NewExp::toElem): Use NewExp::newtype (Bugzilla 1038)
+
+2007-04-16 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.009 (from 1.007):
+
+ * d-decls.c: Merge changes from dmd/tocsym.c
+
+ * dmd/constfold.c, dmd/declaration.c, dmd/declaration.h,
+ dmd/expression.c, dmd/expression.h, dmd/init.c, dmd/interpret.c,
+ dmd/mangle.c, dmd/mars.c, dmd/mars.h, dmd/mtype.c,
+ dmd/optimize.c, dmd/statement.c, dmd/staticassert.c,
+ dmd/tocsym.c, dmd/todt.c: Merge changes.
+
+ * phobos/std/path.d, phobos/std/string.d: Merge changes.
+
+ ----
+
+ * d-builtins.c, d-builtins2.cc, d-lang.h: Reworked code to only
+ convert built-in functions when the gcc.builtins module is
+ imported. RECORD_TYPE is now converted to a TypeStruct. Fixed
+ problem that caused some functions to not be available. Support
+ targets builtins.
+
+2007-03-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-decls.cc (ClassDeclaration::toSymbol): Do not set TREE_READONLY.
+ (Bugzilla 1037)
+
+2007-03-10 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (call): Handle CommaExp form of a delegate call
+ (Bugzilla 1043)
+
+ * d-decls.cc (VarDeclaration::toSymbol): Partial fix for Bugzilla 1044
+
+ * dt.h, d-objfile.cc, dmd/typeinf.c: Only pad 32-bit words in RTTI if
+ needed. (Bugzilla 1045, 1046)
+ * dmd/toobj.c: update
+
+ * d-glue.cc, d-objfile.cc: Additional GCC 3.3.x cleanup
+
+ ----
+
+ * ChangeLog, History, Make-lang.in, asmstmt.cc, d-builtins.c,
+ d-codegen.cc, d-convert.cc, d-decls.cc, d-gcc-includes.h,
+ d-gcc-real.cc, d-glue.cc, d-gt.c, d-irstate.cc, d-lang.cc,
+ d-lang.h, d-misc.c, d-objfile.cc, d-spec.c, phobos/configure.in,
+ setup-gcc.sh: Remove support for GCC 3.3.x
+
+ * phobos/configure: Regenerated
+
+ * gcc-3.3.5-framework-headers.patch,
+ gcc-3.3.5-framework-linker.patch, patch-gcc-3.3.x,
+ patch-gcc-darwin-eh-3.3.x, patch-toplev-3.3.x,
+ phobos/config/ldfuncs33, phobos/config/noldfuncs33,
+ d-bi-attrs-33.h: Removed.
+
+2007-03-05 David Friedman <dvdfrdmn@users.sf.net>
+
+ Release GDC 0.23
+
+ * phobos/Makefile.am: Add all-local target to build libgphobos.a
+ * phobos/Makefile.in: Regenrated
+
+ PowerPC 64 fixes:
+
+ * d-glue.cc (TypeStruct:toCtype): Add words at the end of a struct.
+
+ * phobos/config/darwin8/frag-unix: More accurate struct definitions.
+ * phobos/internal/gc/gc_dyld.c: Support Mach-O 64.
+ * phobos/internal/gc/gcgcc.d: Correct stack for 64-bit Darwin.
+ * phobos/std/thread.d (getESP): Align result.
+
+2007-03-04 David Friedman <dvdfrdmn@users.sf.net>
+
+ Rest of DMD 1.007 Merge:
+
+ * package/simple.sh: Install GDC.html
+
+ * Make-lang.in (D_DMD_OBJS): add interpret.dmd.o
+
+ * gdc-version: update
+
+ * GDC.html, d-lang.cc, dmd-script, lang-specs.h, lang.opt,
+ patch-gcc-4.0.x, patch-gcc-4.1.x, patch-apple-gcc-4.0.x,
+ patch-gcc-3.4.x, patch-gcc-3.3.x: Add -J option.
+
+ * dmd/constfold.d, dmd/declaration.h, dmd/func.c: update
+
+ * d-glue.c: update
+
+ Initial merge of DMD 1.007 (from DMD 1.005):
+
+ * dmd/arraytypes.h, dmd/attrib.c, dmd/cond.c, dmd/constfold.c,
+ dmd/declaration.c, dmd/declaration.h, dmd/expression.c,
+ dmd/expression.h, dmd/func.c, dmd/idgen.c, dmd/init.c,
+ dmd/lexer.c, dmd/lexer.h, dmd/mars.c, dmd/mars.h, dmd/module.c,
+ dmd/mtype.c, dmd/opover.c, dmd/optimize.c, dmd/parse.c,
+ dmd/parse.h, dmd/statement.c, dmd/statement.h, dmd/template.c,
+ dmd/typinf.c: Merge
+
+ * phobos/internal/aApply.d, phobos/internal/aApplyR.d,
+ phobos/internal/adi.d, phobos/internal/dmain2.d,
+ phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d,
+ phobos/internal/gc/win32.d, phobos/internal/object.d,
+ phobos/std/base64.d, phobos/std/c/string.d, phobos/std/c/time.d,
+ phobos/std/c/windows/com.d, phobos/std/c/windows/windows.d,
+ phobos/std/dateparse.d, phobos/std/demangle.d, phobos/std/file.d,
+ phobos/std/format.d, phobos/std/regexp.d, phobos/std/stdio.d,
+ phobos/std/stream.d, phobos/std/string.d, phobos/std/thread.d,
+ phobos/std/utf.d: Merge
+
+ * dmd/interpret.c: New file
+
+2007-03-03 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/c/darwin/darwin.d: Remove. (Bugzilla 984)
+
+ * phobos/std/date.d: Cleanup
+
+ * d-lang.cc: Evaluate BYTES_BIG_ENDIAN at runtime.
+
+ * d-codegen.cc: Cleanup.
+
+ * d-glue.cc: Initialize foreach key with zero, not default init.
+
+ * patch-gcc-4.0.x, patch-gcc-4.1.x, patch-apple-gcc-4.0.x:
+ Prevent emission of prologue and epilogue code for naked functions.
+ (Bugzilla 1013)
+
+2007-03-02 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-lang.cc: Test BYTES_BIG_ENDIAN at runtime.
+
+ * d-glue.cc (ForeachStatement::toIR): Initialize key to zero, not
+ defaultInit.
+
+ * patch-build_gcc-4.0, phobos/acinclude.m4, phobos/configure.in,
+ phobos/Makefile.am: Remove references to libgphobos.spec
+
+ * phobos/Makefile.in, phobos/configure: Regenerate
+
+ * patch-gcc-3.4.x, patch-gcc-3.3.x, patch-gcc-4.0.x,
+ patch-gcc-4.1.x, patch-apple-gcc-4.0.x: Support enabling
+ -pthread option by default without 'unrecognized option'
+ error message.
+
+ * d-spec.c (lang_specific_driver): Enable -pthread option
+
+ * phobos/libgphobos.spec.in: Remove
+
+2007-02-28 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/loader.d: Fix error
+
+2007-02-27 David Friedman <dvdfrdmn@users.sf.net>
+
+ * setup-gcc.sh: Create directory of links instead of a single
+ link. No longer need to copy support files.
+
+ * target-ver-syms.sh: Support targets with both 32-bit and
+ 64-bit modes. Output preprocessor definitions instead of
+ command line otions.
+
+ * Make-lang.in: Put target-ver-syms.sh output in d-confdefs.h.
+
+ * package/simple.sh: Handle multilib.
+
+ * phobos/configure.in: Use Automake, multilib.
+ * phobos/Makefile.am: New file.
+ * phobos/acinclude.m4: Fix quoting.
+
+ * phobos/Makefile.in, phobos/configure: regenerated
+
+ * patch-gcc-3.3.x, patch-gcc-3.4.x, patch-gcc-4.0.x,
+ patch-gcc-4.1.x, lang-specs.h: Add %N spec code.
+
+ * patch-build_gcc-4.0: Grab 64-bit libgphobos.a
+
+ * dt.h, d-objfile.cc
+ (dt_size): Change return type to target_size_t. Use target_size_t.
+ (dtnzeros, dtdword, dtxoff): Change count to target_size_t
+ (dtabytes, dtnbytes, dtawords, dtnwords, dtnbits): Change count to size_t
+ (dti32): added
+
+ * d-todt.cc: Cleanup.
+
+ * d-objfile.cc:
+ (dt2node): use Type::tsize_t for DT_word and DT_xoff
+
+ * d-glue.cc:
+ (PtrExp::toElem): Use target_size_t for offset
+ (gcc_d_backend_init): Set CLASSINFO_SIZE and Tindex.
+ (AssignExp::toElem): Use tsize_t for _d_arraycopy arg
+ (CaseStatement::toIR): (not really a 64-bit change) Use int32 for
+ case value to match libcall
+ (CatAssignExp::toElem): cleanup (not 64-bit)
+ (ForeachStatement::toIR): fix bug in key increment expression
+
+ * d-codegen.{cc,h}
+ (AggLayout::addField): use target_size_t for offset
+
+ * d-codegen.cc:
+ (...): LIBCALL_ARRAYCAST: Use size_t args (libcall already uses size_t)
+ LIBCALL_ARRAYCOPY: ditto
+ (convertTo): Use Type::tsize_t for _d_arraycat arguments
+
+ * d-decls.cc
+ (ClassDeclaration::toVtblSymbol): Use Type::tindex for array size.
+ (FuncDeclaration::toThunkSymbol): Use target_ptrdiff_t
+
+ * lang.opt: add -fmultilib-dir
+
+ * d-lang.cc: Use -fmultilib-dir
+
+ (d_init): Set global.params.isX86_64 if TARGET_64BIT.
+ Set CPU version symbol according to TARGET_64BIT.
+ Remove BitsPerPointer and BitsPerWord version symbols.
+
+ * d-builtins2.cc
+ (d_gcc_magic_builtins_module): Change "abi" integer types
+ to "C". Add "pointer" integer types.
+ (gcc_type_to_d_type): Use Type::tindex for array types. Use whole
+ back-end size.
+
+ * symbol.h
+ (Thunk): Use target_ptrdiff_t for offset.
+
+ * dmd/mars.h: Define target_size_t and target_ptrdiff_t to allow use of
+ 32-bit size-tracking variables when generating 32-bit code.
+
+ * dmd/aggregate.h:
+ (CLASSINFO_SIZE) change to 'extern int' %%....
+ * dmd/cast.d: Use target_ptrdiff_t with isBaseOf.
+
+ * dmd/class.c:
+ (ClassDeclaration::semantic): use PTRSIZE
+ (InterfaceDeclaration::semantic): Use sc->offset = PTRSIZE * 2 instead of
+ 8 -- not sure what this is for...
+
+ * dmd/dsymbol.[ch]
+ (Dsymbol::size): Change to target_size_t
+
+ * dmd/init.h: ArrayInitializer::dim <- chg to target_size_t
+
+ * dmd/aggregate.h: Use target_ptrdiff_t and target_size_t
+
+ * dmd/typinf.c (TypeInfoStructDeclaration::toDt): Use dti32 for flags.
+ * dmd/toobj.c (Module::genmoduleinfo, ClassDeclaration::toObjFile,
+ InterfaceDeclaration::toObjFile): ditto
+
+ * dmd/func.c: Use target_ptrdiff_t with isBaseOf.
+ (NewDeclaration::semantic): Allow Type::tuns64 if 64-bit.
+
+ * dmd/mtype.c
+ (Type::init): set CLASSINFO_SIZE
+ (Type::dotExp): use Type::tsize_t for .offsetof property
+ (TypeArray::dotExp): use Type::tsize_t for _adReverse args
+ (TypeAArray::dotExp): use PTRSIZE to align keysize
+ (TypeStruct::dotExp): use Type::tsize_t for offset
+ (TypeStruct::alignsize): use target_size_t
+
+ * dmd/mtype.h: Add Tindex global variable.
+ (Type): Change tindex to baseic[Tindex].
+ (Type::isBaseOf): use target_ptrdiff_t
+
+ * dmd/expression.[ch]:
+ (SymOffExp): offset changed to target_size_t
+ (NewExp::semantic): use size_t as argument
+ (ArrayLiteralExp::toMangleBuffer, SymOffExp::toCBuffer): fix printf
+
+ * dmd/declaration.c
+ (VarDeclaration::semantic): use sinteger_t for dim
+
+ * dmd/declaration.h:
+ (Declaration::size): Use target_size_t
+ (VarDeclaration): Use target_size_t for offset
+
+ * dmd/schope.h:
+ (Scope::offset) Use target_size_t.
+
+ * dmd/statement.c:
+ (ForeachStatement::semantic): Change return value of _a*Apply* to
+ Type::tint32. Fix logic for allowed index variable types.
+ Use PTRSIZE to align keysize.
+
+ * dmd/struct.c
+ (AggregateDeclaration::addField): use target_size_t
+
+ * dmd/todt.c
+ (StructInitializer::toDt): Use target_size_t for offsets
+ (ClassDeclaration::toDt2): Use PTRSIZE
+
+ * phobos/object.d, phobos/internal/object.d:
+ (Interface): Use ptrdiff_t for offset.
+ (*.toHash): cast pointer to size_t
+
+ * phobos/internal/object.d: Use integer type definitions from
+ phobos/object.d. Split %.*s args.
+
+ * phobos/internal/adi.d:
+ (_adReverse): Use size_t for szelem.
+ * phobos/configure.in: fix multilib dir
+ * phobos/configure: updated
+
+ * phobos/config/cb_unix.c: Removed.
+
+ * phobos/config/gen_config1.c: Add ssize_t.
+
+ * phobos/config/config-head: Use __builtin_Clong and __builtin_Culong.
+ * phobos/config/config-mid: Support X86_64 and other 64-bit CPUs.
+ * phobos/config/unix-mid: Some size_t and ssize_t arg/return type fixes.
+
+ * phobos/config/darwin8/frag-gen, phobos/config/darwin8/frag-unix:
+ Support 32- and 64-bit.
+ * phobos/config/mingw/frag-unix, phobos/config/skyos/frag-unix:
+ Add ssize_t.
+
+ * phobos/gcc/builtins.d: Update documentation
+
+ * phobos/gcc/unwind.d: Use different builtin integer types.
+
+ * phobos/internal/arraycat.d (_d_arraycopy): use size_t arg
+
+ * phobos/std/c/fenv.d: Add field for 64-bit Linux.
+
+ * phobos/std/c/linuxextern.d: Use C long for timezone.
+
+ * phobos/std/c/stdio.d,
+ phobos/std/c/stdlib.d, phobos/std/c/math.d,
+ phobos/std/c/time.d: use C long types
+
+ * phobos/std/stdint.d: Add C long types.
+ Use ptrdiff_t and size_t for *intptr_t types.
+
+ * phobos/std/format.d: Formatting structs on X86_64 looses
+
+ * phobos/internal/cast.d (_d_isbaseof2): change offset to size_t
+
+ * phobos/internal/fpmath.d: Support 64-bit CPUs.
+
+ * phobos/std/file.d: Type of stat.st_size may vary; use auto.
+ (Unix read): Make sure file's size is within range.
+
+ * phobos/crc32.d, phobos/gcstats.d,
+ phobos/internal/qsortg.d:
+ phobos/internal/gc/gc.d (_d_arraycatnT),
+ phobos/internal/gc/gcold.d (_d_arraycatn),
+ phobos/internal/gc/gcx.d,
+ phobos/internal/mars.h,
+ phobos/std/base64.d, phobos/std/bitarray.d, phobos/std/math.d,
+ phobos/std/math2.d, phobos/std/md5sum.d, phobos/std/outbuffer.d,
+ phobos/std/path.d, phobos/std/string.d, phobos/std/uri.d
+ phobos/std/typeinfo/ti_AC.d,
+ use size_t, ptrdiff_t/ssize_t
+
+ * phobos/std/loader.d: Add definitions for 64-bit Mach-O objects.
+
+ * phobos/std/openrj.d, phobos/std/loader.d, phobos/std/moduleinit.d,
+ phobos/std/socket.d, phobos/std/regexp.d, phobos/std/uri.
+ d, phobos/std/zip.d: split '%.*s' args
+
+ * phobos/std/typeinfo/ti_A*.d, phobos/std/typeinfo/ti_ptr.d:
+ fix compare methods
+
+ * phobos/internal/gc/gc_dyld.c: use uintptr_t
+
+ * phobos/std/c/stdio.d, phobos/internal/gc/gcgcc.d:
+ Don't use old version symbols.
+
+ * phobos/std/c/mach/mach.d (natural_t): always a uint
+
+ * phobos/etc/c/zlib.d: use Culog_t
+
+2007-02-13 David Friedman <dvdfrdmn@users.sf.net>
+
+ * setup-gcc.sh: Copy the removed files from the top-level
+ directory.
+
+2007-02-10 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/config.guess, phobos/config.sub, phobos/install-sh:
+ Remove files.
+
+ * phobos/std/format.d (putAArray): account for
+ alignment of the value
+
+ * phobos/Makefile.in: fix metastrings.o
+
+2007-02-09 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/std/format.d (doFormat): use aligntsize
+
+ Rest of DMD 1.005 merge:
+
+ * phobos/Makefile.in (MAIN_OBJS): add metastrings.o
+
+2007-02-08 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-lang.cc, lang.opt: support -v1 option
+
+ * lang.opt (d_init_options): set global.params.Dversion
+
+ * dmd-script: -v1 -> -fd-version=1
+
+ * phobos/std/format.d (doFormat): Fix for var args differences
+
+ Initial merge of DMD 1.005:
+
+ dmd/attrib.c, dmd/attrib.h, dmd/cast.c, dmd/cond.c,
+ dmd/constfold.c, dmd/dsymbol.c, dmd/dsymbol.h, dmd/expression.c,
+ dmd/expression.h, dmd/func.c, dmd/idgen.c, dmd/inline.c,
+ dmd/lexer.c, dmd/lexer.h, dmd/mars.c, dmd/module.c, dmd/mtype.c,
+ dmd/mtype.h, dmd/optimize.c, dmd/parse.c, dmd/parse.h,
+ dmd/scope.c, dmd/statement.c, dmd/statement.h, dmd/template.c,
+ dmd/template.h, dmd/toobj.c, dmd/typinf.c: Merge.
+
+ phobos/internal/aaA.d, phobos/internal/gc/gc.d,
+ phobos/internal/object.d, phobos/linux.mak, phobos/std/c/stdlib.d,
+ phobos/std/conv.d, phobos/std/ctype.d, phobos/std/format.d,
+ phobos/std/regexp.d, phobos/std/zlib.d, phobos/std.ddoc,
+ phobos/win32.mak: Merge.
+
+ phobos/std/metastrings.d: New file
+
+2007-02-05 David Friedman <dvdfrdmn@users.sf.net>
+
+ Release GDC 0.22
+
+ * d-codegen.cc (twoFieldType): Fix back end -> front end type
+ mapping.
+
+ * Make-lang.in: Enable ELFOBJ to put some RTTI in the read-only
+ data section.
+
+ * GDC.html: Update
+
+2007-02-04 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/gcc/cbridge_time.c (_d_gnu_cbridge_tza),
+ phobos/std/date.d: Fix timezone adjust sign
+
+2007-02-03 David Friedman <dvdfrdmn@users.sf.net>
+
+ * phobos/config/unix-mid: Correctly initialize sockaddr*
+ (Bugzilla 818)
+
+ * dmd-script: Fix -H* options (Bugzilla 896).
+ Support -framework. Fix error message.
+
+ * d-lang.cc (d_write_global_declarations), patch-gcc-4.1.x:
+ Fixes for dwarf2out ICEs
+
+ * d-objfile.cc (check_static_sym): Fix setting TREE_CONSTANT.
+
+ Rest of DMD 1.004 merge:
+
+ * gcc-mars.cc, gdc-version: Update
+
+ * phobos/std/regexp.d: update
+
+ * phobos/internal/gc/gcold.d (_d_newarrayip):
+
+ * phobos/internal/gc/gc.d: Fix argument and result types.
+
+ * phobos/config/unix-head, phobos/config/unix-mid: Update
+
+ * phobos/Makefile.in: Update for files removed in DMD 1.004
+
+ * d-decls.cc (TypedefDeclaration::toInitializer): Copy
+ from dmd/tocsym.c. Create the Sdt here.
+
+ * dmd/toobj.c (TypedefDeclaration::toObjFile): Update
+ for toInitializer change
+
+ * dmd/mtype.c (TypeArray::dotExp): Fix library call decls
+
+ * d-lang.cc: Update
+
+ * d-codegen.[ch], d-glue.cc: Update memory allocation library
+ calls.
+
+ * d-lang.cc (d_write_global_declarations): call
+ emit_debug_global_declarations only for GCC 4.0
+
+ * dmd/mtype.c (TypeArray::dotExp): update
+
+ * phobos/config/unix-head, phobos/config/unix-mid: update
+
+ * phobos/internal/gc/gcold.d: Use old GDC modifications.
+
+2007-02-02 David Friedman <dvdfrdmn@users.sf.net>
+
+ Initial merge DMD 1.004:
+
+ * dmd/aggregate.h, dmd/attrib.c, dmd/attrib.h, dmd/declaration.c,
+ dmd/declaration.h, dmd/dsymbol.c, dmd/dsymbol.h, dmd/expression.c,
+ dmd/import.c, dmd/import.h, dmd/inline.c, dmd/mars.c, dmd/mars.h,
+ dmd/module.c, dmd/module.h, dmd/mtype.c, dmd/mtype.h,
+ dmd/struct.c, dmd/template.c, dmd/template.h, dmd/tocsym.c,
+ dmd/todt.c, dmd/toobj.c, dmd/typinf.c: Merge DMD 1.004
+
+ * phobos/internal/aaA.d, phobos/internal/adi.d,
+ phobos/internal/arraycast.d, phobos/internal/arraycat.d,
+ phobos/internal/gc/gc.d, phobos/internal/gc/gcx.d,
+ phobos/internal/gc/linux.mak, phobos/internal/gc/win32.mak,
+ phobos/internal/object.d, phobos/linux.mak, phobos/object.d,
+ phobos/std/c/linux/linux.d, phobos/std/compiler.d,
+ phobos/std/file.d, phobos/std/gc.d, phobos/std/outbuffer.d,
+ phobos/std/random.d, phobos/std/regexp.d,
+ phobos/std/typeinfo/ti_AC.d, phobos/std/typeinfo/ti_Acdouble.d,
+ phobos/std/typeinfo/ti_Acfloat.d, phobos/std/typeinfo/ti_Acreal.d,
+ phobos/std/typeinfo/ti_Adouble.d, phobos/std/typeinfo/ti_Afloat.d,
+ phobos/std/typeinfo/ti_Ag.d, phobos/std/typeinfo/ti_Aint.d,
+ phobos/std/typeinfo/ti_Along.d, phobos/std/typeinfo/ti_Areal.d,
+ phobos/std/typeinfo/ti_Ashort.d, phobos/std/typeinfo/ti_C.d,
+ phobos/std/typeinfo/ti_cdouble.d, phobos/std/typeinfo/ti_cfloat.d,
+ phobos/std/typeinfo/ti_char.d, phobos/std/typeinfo/ti_creal.d,
+ phobos/std/typeinfo/ti_dchar.d, phobos/std/typeinfo/ti_delegate.d,
+ phobos/std/typeinfo/ti_double.d, phobos/std/typeinfo/ti_float.d,
+ phobos/std/typeinfo/ti_ptr.d, phobos/std/typeinfo/ti_real.d,
+ phobos/std/typeinfo/ti_void.d, phobos/std/typeinfo/ti_wchar.d,
+ phobos/win32.mak: Merge DMD 1.004
+
+ * phobos/std/typeinfo/ti_Aa.d, phobos/std/typeinfo/ti_Adchar.d,
+ phobos/std/typeinfo/ti_Aubyte.d, phobos/std/typeinfo/ti_Auint.d,
+ phobos/std/typeinfo/ti_Aulong.d, phobos/std/typeinfo/ti_Aushort.d,
+ phobos/std/typeinfo/ti_Awchar.d: Removed in DMD 1.004
+
+ * phobos/internal/gc/gcold.d: New in DMD 1.004
+
+2007-02-01 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-lang.cc (d_write_global_declarations): Emit debug info.
+
+ * d-codegen.cc (twoFieldType): Fix debugging information.
+ * d-objfile.cc (initTypeDecl): Ditto.
+
+ * d-glue.cc (PtrExp::toElem): Don't wrap the result in
+ a NOP_EXPR.
+
+ * Make-lang.in: Add d-tree.def to dependencies
+
+2007-01-30 David Friedman <dvdfrdmn@users.sf.net>
+
+ GCC 4.1.x changes:
+
+ * GDC.html, INSTALL, INSTALL.html, README: update
+
+ * dmd/idgen.c, dmd/impcnvgen.c, dmd/mtype.h: Change to allow
+ compilation as C.
+
+ * patch-gcc-4.1.x, patch-toplev-4.1.x: New files
+
+ * Make-lang.in: Use $(version) instead of $(gcc_version).
+ Add d-bi-attrs-41.h. Use C for generator programs instead of C++.
+
+ * d-bi-attrs-41.h: New file.
+
+ * d-builtins.c: update
+
+ * d-builtins2.cc: Do not associate d_gcc_builtin_va_list_d_type with
+ va_list_type_node. Do this for GCC 4.0 and 4.1.
+
+ * d-codegen.cc: Use CtorEltMaker.
+ (maybeExpandSpecialCall): Cast d_gcc_builtin_va_list_d_type to
+ va_list_type_node.
+ (hostToTargetString): Update.
+
+ * d-codegen.h: Add CtorEltMaker class for before/after 4.1.x
+ compatibility.
+
+ * d-convert.cc: Add special case for pointer/int comparison
+
+ * d-decls.cc: Do not use SET_DECL_ASSEMBLER_NAME for CONST_DECLs
+
+ * d-gcc-includes.h: Include vec.h
+
+ * d-glue.cc: Use CtorEltMaker.
+ (gcc_d_backend_init): Call default_init_unwind_resume_libfunc
+
+ * d-lang.cc: Add d_types_compatible_p hook for va_list conversion
+
+ * d-lang.h: Update
+
+ * d-objfile.cc: CtorEltMaker.
+
+ * phobos/std/conv.d: Do not assume signed integer wraparound.
+
+2007-01-28 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-asm-i386.h, d-codegen.cc, d-gcc-real.cc,
+ d-decls.cc, d-glue.cc, d-lanc.cc: various fixes
+
+ * d-codegen.cc, d-codegen.h, d-glue.cc, d-lang.h:
+ Remove bit array code
+
+2007-01-27 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-asm-i386.h: fix fistp, lmsw, lldt, mov[sz]x, setCC, smsw, and
+ sldt instructions (Bugzilla 836, 837, 838, 839, 841, 843, 844).
+ Also r[co][lr].
+
+ * d-glue.cc (StringExp::toElem): Correct termination of wchar
+ and dchar (Bugzilla 889)
+
+2007-01-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ * INSTALL.html: fix corruption
+
+2007-01-03 David Friedman <dvdfrdmn@users.sf.net>
+
+ Release GDC 0.21
+
+ * GDC.html: New file.
+
+ * README: Update, refer to GDC.html
+
+ Rest of DMD 1.00 merge:
+
+ * d-codegen.cc: Patch from Anders Bjšrklund for GCC 3.3
+
+ * d-glue.cc (FuncDeclaration::toObjFile): Fix shouldDefer/outputStage
+ logic.
+
+ * dmd/attrib.c (PragmaDeclaration::semantic): uint -> unsigned
+
+ * dmd/module.c (load): output to stdmsg
+
+ * dmd/mtype.c: revert '@' mangling changes
+
+ * gdc-version, gcc-mars.cc: update
+
+ * phobos/config/unix-mid: Support more functions
+
+ * phobos/acinclude.m4, phobos/config/gen_unix.c (c_pthread):
+ Support more types
+
+ * phobos/configure, phobos/config.h.in: update
+
+ * phobos/config/darwin8/frag-unix: update
+
+ Initial merge of DMD 1.00:
+
+ * dmd/cond.c, dmd/constfold.c, dmd/delegatize.c, dmd/dsymbol.c,
+ dmd/enum.c, dmd/expression.c, dmd/expression.h, dmd/init.c,
+ dmd/inline.c, dmd/mars.c, dmd/module.c, dmd/module.h, dmd/mtype.c,
+ dmd/parse.c, dmd/statement.c, dmd/struct.c, dmd/template.c,
+ dmd/todt.c: Merge 1.00
+
+ * internal/gc/gc.d, phobos/linux.mak,
+ phobos/std/c/linux/linux.d.orig-dmd, phobos/std/c/stdlib.d,
+ phobos/std/conv.d, phobos/win32.mak: Merge 1.00
+
+ * phobos/std/c/linux/pthread.d.orig-dmd: New file (originally
+ pthread.d DMD)
+
+ ------------------------
+
+ * dmd/init.c (ArrayInitializer::semantic),
+ * dmd/root.c (OutBuffer::write4): 64-bit host cleanup
+
+ * d-asm-i386.h: cleanup, saftey
+
+2007-01-02 DF <dvdfrdmn@users.sf.net>
+
+ * d-codegen.cc (convertTo): Use 64-bit for Tarray, Tsarray conversion.
+
+ * d-codegen.{h, cc} (darrayVal): use uinteger_t arg
+
+
+Copyright (C) 2007 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2008 b/gcc/d/ChangeLog-2008
new file mode 100644
index 0000000..23dc712
--- /dev/null
+++ b/gcc/d/ChangeLog-2008
@@ -0,0 +1,331 @@
+2008-12-12 Arthur Loiret <arthur.loiret@u-psud.fr>
+
+ Bugzilla 929:
+
+ * dmd/mtype.c: Provide isZeroInit() overload in TypeAArray that
+ returns TRUE.
+ * dmd/mtype.h: Add prototype for TypeAArray::isZeroInit().
+
+ * dmd2/mtype.c, dmd2/mtype.h: Ditto.
+
+2008-07-21 David Friedman <David Friedman>
+
+ * dmd/root.c, dmd2/root.c: Fix earlier patching error.
+
+ * phobos/config/x3.c, phobos2/config/x3.c: Fix problem when
+ building under MSYS.
+
+ * config-lang.in: Remove lang_requires.
+
+2008-07-20 David Friedman <David Friedman>
+
+ * dmd/expression.c, dmd2/expression.c: Make integer conversion
+ fix work for other hosts/targets.
+
+2008-07-20 Arthur Loiret <arthur.loiret@u-psud.fr>
+
+ * dmd/expression.c: Fix integer conversion routines on x86_64.
+ Patch from downs <default_357-line@yahoo.de>, thanks!
+ * dmd2/expression.c: Likewise.
+
+ * config-lang.in: Add lang_requires="c c++".
+
+2008-07-19 David Friedman <David Friedman>
+
+ * patches/patch-gcc-4.0.x, patches/patch-gcc-4.1.x: Fix infinite
+ loop bug in patch.
+ * patches/patch-apple-gcc-4.0.x: Ditto.
+
+ * d-lang.cc: Do not assume D_OS_VERSYM is defined.
+ Handle TARGET_xxx_CPP_BUILTINS macros for more targets.
+
+2008-07-17 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd-script: Append an exe suffix to executables when the
+ target is Windows.
+
+ * phobos/gcc/deh.d, phobos2/gcc/deh.d: Fix for sjlj exceptions.
+
+2008-06-16 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-decls.cc: Correct logic for output constanting vars for V1.
+
+2008-06-01 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD.1.30 and 2.014
+
+ * dmd-script: Implement -man, -lib and single-object features.
+
+ * phobos2/Makefile.am: add bigint
+
+ * phobos2/config/{ldfuncs,ldfuncs-darwin,ldfuncs-ppclinux,noldfuncs},
+ Merge nanl change from std/c/math.d
+
+ * phobos2/gcc/support.d: Merge std/c/math.d changes.
+
+ * d-objfile.cc (obj_append): Implement.
+ * phobos2/std/c/unix/unix.d: Merge linux.d and socket.d changes
+
+ * d-glue.cc, d-irstate.cc, d-lang.cc: Update
+
+ * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge
+
+2008-05-26 David Friedman <dvdfrdmn@users.sf.net>
+
+ * asmstmt.cc, d-decls.cc, d-glue.cc, d-misc.c, d-objfile.{cc, h}:
+ Fix for -combine compilation. Remove fileContext global and clean
+ up generation of unique symbol names.
+
+ * phobos/internal/object.d: Correct merge error
+
+ ----
+
+ * dmd-script, lang.opt, d-lang.cc, : support -ignore
+
+ Merge DMD 1.029 and 2.013
+
+ * phobos2/std/perf.d: use std.c.unix.unix
+
+2008-05-22 Arthur Loiret <arthur.loiret@u-psud.fr>
+
+ * target-ver-syms.sh: Add missing CPUs and fix
+ d_cpu_versym/d_cpu_versym64 for each.
+
+ * d-lang.cc: Fix build on non biarched 64-bit archs (alpha, ia64, ...)
+ and fix 64-bit cpu detection.
+
+ * Move patch-* to patches/
+ * setup-gcc.sh: Update.
+
+2008-05-10 David Friedman <dvdfrdmn@users.sf.net>
+
+ * lang-specs.h: Support a "cc1d" spec. (Bugzilla 2068)
+
+ Merge DMD 1.028 and 2.012
+
+ * d-codegen.{h,cc}: Add postblitting array libcalls.
+
+ * phobos2/internal/arrayassign.d
+ (_d_arraysetassign, _d_arraysetctor): Use size_t.
+
+ * d-glue.cc (AssignExp::toElem): Postblit-aware code
+
+ * phobos2/Makefile.am: Add arrayssign.d. Remove math2.d.
+
+ * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge
+
+2008-05-03 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-dmd-gcc.h, d-glue.cc, dmd*/toobj.c: Cleanup: Remove unused
+ d_gcc_aggregate_dtors.
+
+2008-05-02 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.027 and 2.011
+
+ * termios.d: Point to std.c.unix.unix. Leave original
+ termios.d as termios.d.orig-dmd
+
+ * asmstsmt.cc: Implement blockExit
+
+ * phobos2/config/unix.x3: Add termios stuff
+
+ * phobos2/std/c/unix/unix.d: Merge new funcs from std.c.linux.d
+
+ * d-objfile.cc: Implement stub obj_startaddress
+
+ * d-glue.cc (ForStatement::toIR): condition may be NULL
+ (DeleteExp::toIR): Use libcalls for interfaces
+
+ * dmd*/clone.c, dmd*/e2ir.c: New files.
+
+ * Make-lang.in: Add new clone.c
+
+ * d-codegen.{h, cc}, d-glue.cc: Use _d_callinterfacefinalizer.
+ Also use _d_delinterface instead of casting.
+
+ * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge
+
+2008-04-27 David Friedman <dvdfrdmn@users.sf.net>
+
+ Merge DMD 1.026 and 2.010
+
+ * dmd/..., dmd2/..., phbobos/..., phobos2/...: Merge
+
+ ---
+
+ * d-lang.cc (d_write_global_declarations): Make earlier change
+ regarding cgraph_optimize only apply to 4.0.x.
+
+ ---
+
+ * d-decls.cc (VarDeclartion::toSymbol): Change for
+ V2 STCmanifest. Make more constant vars have
+ static storage (instead of making CONST_DECLs) in
+ both V1 and V2.
+
+ * dmd2/constfold.c (Cmp): Compare wchar and dchar
+ strings portably.
+
+ * asmstmt.cc (ExtAsmStatement::semantic): Heuristic
+ for evaluating operands: If an input operand, evaluate.
+
+ * d-asm-i386.h: Make previous change apply to V1.
+
+ * d-glue.cc (TypeEnum::toCtype): Update.
+
+ Phobos changes (applies to V2 Phobos as well):
+
+ * phobos/Makefile.am, phobos/configure.in:
+ Deal with strerror_r portability.
+
+ * phobos/Makefile.in, phobos/configure, phobos/config.h.in:
+ Updated.
+
+ * phobos/gcc/cbridge_strerror.c: New file.
+
+ * phobos/std/c/string.d: Replace non-portable strerror_r with
+ _d_gnu_cbridge_strerror.
+
+ * phobos/std/file.d, phobos/std/loader.d, phobos/std/process.d,
+ phobos/std/socket.d, phobos/std/stdio.d: Use
+ _d_gnu_cbridge_strerror.
+
+ Merge DMD 2.009:
+
+ * dmd2/..., phobos2/...: Merge.
+
+ Merge DMD 1.025:
+
+ * dmd/..., phobos/...: Merge.
+
+2008-04-25 David Friedman <dvdfrdmn@users.sf.net>
+
+ * asmstmt.cc, d-asm-i386.h: Handle some other cases
+ for constant floating point operands.
+
+2008-04-19 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/toobj.c, dmd2/toobj.c (EnumDeclaration::toObjFile):
+ Output initializer correctly.
+
+ * d-decls.cc (EnumDeclaration::toInitializer): Correctly
+ set up initializer symbol. (Bugzilla 1746)
+
+2008-04-17 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd/toobj.c (InterfaceDeclaration::toObjFile): Fix error.
+ (Bugzilla 1844)
+
+2008-04-16 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-codegen.{h, cc}: Clean up nested function / nested class /
+ closure code.
+
+ * phobos/std/c/stdlib.d, phobos2/...: Remove comment that hides
+ atof. (Bugzilla 1888)
+
+2008-03-11 David Friedman <dvdfrdmn@users.sf.net>
+
+ * d-glue.cc: cleanup
+
+ * dmd/expression.c (DotVarExp::semantic): Apply fix from dmd2/
+
+ * dmd2/expression.c (DotVarExp::semantic): Move fix to
+ better location.
+
+2008-03-09 David Friedman <dvdfrdmn@users.sf.net>
+
+ * dmd2/func.c (FuncDeclaration::needsClosure): Closures fix:
+ Change test from isVirtual to isThis.
+
+ * dmd2/expression.c (DotVarExp::semantic): Note change from DMD.
+
+ ----
+
+ * patch-build_gcc-5465: Correctly build driver-driver
+
+ * phobos*/Makefile.am (MAIN_OBJS): Add std/cover.o
+
+ * phobos2/std/file.d: use 'mkdir -p' in unittest
+
+ * d-builtins2.cc: Fixes for pointer-to-function types (for V2)
+
+ * d-codegen.cc: Add _d_allocmemory libcall.
+ (emitLocalVar): Rework.
+ (var): New function to handle static-frame/closure variables
+ (convertTo): Use typesSame instead of typesCompatible
+ (assignValue): New function to handle Exp(v=value) vs. Exp(value)
+ (getFrameForFunction, getFrameForNestedClass): New interface
+ to get frames for nested functions.
+ (functionNeedsChain): Return false for nested functions that
+ take closures.
+
+ * d-decls.cc: Changes for const/invariant/STCinit
+
+ * d-glue.cc: Use new interface for nested functions. Use
+ IRState::var instead of v->toSymbol()->Stree. Create
+ closures.
+
+ * d-lang.cc: Implement CONVERT_PARM_FOR_INLINING hook
+
+ * d-objfile.cc: Add case for closure-using function when
+ setting the link-once attribute.
+
+ * package/simple.sh: install .../include/d2
+
+ * patch-build_gcc-4.0, patch-build_gcc-5465: Support D 2.0
+ includes and libraries.
+
+ * phobos2/std/bitmanip.d: Apply previous bitarray.d changes.
+
+ * phobos*/std/typeinfo/ti_ptr.d (getHash): Cast to hash_t.
+
+ * d-decls.cc (VarDeclaration::toSymbol): For D 2.0, use
+ isInvariant() and STCinit as criteria for making CONST_DECLs and
+ setting TREE_READONLY.
+
+ * phobos2/std/c/linux/linux.d: Do not import std.c.dirent.
+
+ * phobos2/std/c/dirent.d: Deprecated std.c.dirent.
+
+ * phobos2/std/c/unix/unix.d: Move dirent/DIR routines here.
+
+ * phobos*/std/c/darwin/ldblcompat.d: declare constants as 'string'
+
+ Merge DMD 2.008:
+
+ * dmd2/..., phobos2/...: Merge.
+
+ Merge DMD 1.024:
+
+ * phobos*/config/unix.x3: ensure MSG_NOSIGNAL is defined
+
+ * dmd/..., phobos/...: Merge.
+
+ ------
+
+ * patch-apple-gcc-4.0.x, patch-apple-gcc-5465: Include patch
+ for SRA pass like the other 4.x patches.
+
+ * d-codegen.cc (convertTo): Ensure pointers are cast to an
+ unsigned type.
+
+ * d-objfile.cc (dt2tree_list_of_elems): Always generate a
+ CONSTRUCTOR for struct data.
+ (ObjectFile::ObjectFile): Use NULL_TREE for file context instead
+ of TRANSLATION_UNIT_DECL.
+
+ * d-lang.cc (d_write_global_declarations): Call
+ debug_hooks->global_decl before cgraph_optimize so that nested
+ class functions do not get passed to dwarf2out before the
+ outer class functions.
+
+ * Rename patch-build_gcc-4.0 to patch-build_gcc-4.0.x
+
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2009 b/gcc/d/ChangeLog-2009
new file mode 100644
index 0000000..90a204d
--- /dev/null
+++ b/gcc/d/ChangeLog-2009
@@ -0,0 +1,185 @@
+2009-12-28 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.043
+
+ * phobos/configure.in: Changed part of phobos configure.
+
+ * samples/README, samples/samples.sh: Uploading the start of the some
+ small tests to help in the testing of GDC/D components.
+
+ * Make-lang.in, d-lang.cc, dmd/machobj.c, phobos/config/unix.x3,
+ phobos/std/file.d, phobos/std/moduleinit.d, phobos/std/socket.d: Fixed
+ problem when building on Mac OS X.
+
+2009-12-05 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.042
+
+ * Make-lang.in: Added async.dmd.o
+
+ * d-asm-i386.h, d-codegen.h: Merge changes from dmd/constfold.c.
+
+ * d-codegen.h, phobos2/aclocal.m4, phobos2/configure.in: Fixed
+ problems with D2.
+
+2009-11-22 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.041
+
+ * Make-lang.in: Update for files added in DMD 1.041.
+
+ * d-backendfunctions.c: Added stubs for functions in the backend that
+ cannot be included in the front end source.
+
+ * dmd-script: Added Bitbucket page to display for gdmd wrapper script.
+
+2009-11-07 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ Changes to GCC-4.4.x branch:
+
+ * tools/makewebstatistics.d: Added d tool to generate webstats about
+ dstress in D2.
+
+2009-10-25 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.040
+
+ * dmd/..., phobos/...: Now working for D1 (Not on GCC 4.3.4?)
+
+ * asmstmt.cc: Merge from dmd/statement.c
+
+ * phobos/acinclude.m4, phobos/configure.in, phobos/phobos-ver-syms.in:
+ Posix is now defined.
+
+2009-10-24 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * dmd/attrib.c, dmd/cast.c, dmd/class.c, dmd/constfold.c,
+ dmd/declaration.c, dmd/dsymbol.c, dmd/expression.c, dmd/toobj.c: Fixes
+ some errors in the DMD v1 frontend. Trying to fix DMD 1.039, but still
+ no fix. The problem may be in phobos then.
+
+ Changes to GCC-4.4.x branch:
+
+ * d-lang.cc, d-lang.h setup-gcc.sh, patches/patch-gcc-4.4.x,
+ patches/patch-toplev-4.4.x: Applied Eldar patches for gcc 4.4.0
+
+2009-10-07 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * dmd2/attrib.c, dmd2/class.c, dmd2/declaration.c, dmd2/doc.c,
+ dmd2/dsymbol.h, dmd2/func.c, dmd2/parse.c, dmd2/statement.c,
+ dmd2/template.c, dmd2/toir.c: 2.015 WORKING ;)
+
+ * dmd2/parse.c: Fixed problem with static if.
+
+ * dmd2/template.c: Fixed problem with tuples.
+
+ * Makefile-lang.in: Update for files added in DMD 2.015.
+
+2009-10-01 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ Changes to 2.032 branch:
+
+ * dmd2/..., phobos2/...: Force merge with 2.032 - NOT WORKING AT ALL.
+ - Adding new files.
+
+2009-10-04 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.039
+
+ * d-decls.cc: Merge changes from dmd/mtype.h.
+
+ * phobos/internal/aaA.d, phobos/std/stdio.d: Small Phobos fix.
+
+2009-09-30 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * phobos2/internal/aaA.d, phobos2/linux.mak, phobos2/std/algorithm.d,
+ phobos2/std/functional.d, phobos2/std/math.d, phobos2/std/thread.d:
+ DMD 2.015 Phobos changes.
+
+ * Make-lang.in: Fixed a problem introduced by Michael modifying a
+ common file between D1 and D2.
+
+
+2009-09-29 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.036
+
+2009-09-28 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ Merge with DMD 2.015
+
+ * dmd2/mtype.h, dmd2/parse.c: Fixed parser in D2.
+
+ * dmd2/template.c, dmd2/toobj.c: Other fixes.
+
+2009-09-28 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.035
+
+ * d-objfile.cc: Merge changes from dmd/attrib.c.
+
+ * phobos/Makefile.in, phobos/internal/arraydouble.d,
+ phobos/internal/arrayfloat.d: Included arraydouble, arrayfloat, and
+ arrayreal in libphobos Makefile.
+
+ * asmstmt.cc, dmd/statement.c, dmd/statement.h, phobos/std/math.d: Fixed
+ Phobos std.math bug.
+
+2009-09-25 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.033
+
+2009-09-17 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * dmd2.032/...: Initial import of version 2.032.
+
+ * setup-gcc.sh, dmd/.svn/...: Removed .svn directory.
+
+2009-09-13 michaelp <baseball.mjp@gmail.com>
+
+ * phobos/std/boxer.d phobos/std/dateparse.d: Fixed phobos build and
+ possible implicit conversion errors in boxer.d.
+
+ * d-objfile.cc: Removed assert(0) line 926.
+
+2009-09-13 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * History gdc-version: Changed version.
+
+ * phobos2/config/x3, setup-gcc.sh: Added support for DMD 2.
+
+ * phobos2/std/c/string.d, phobos2/std/contracts.d: Fixed a std.string
+ bug following these guidelines:
+ http://www.digitalmars.com/d/archives/D/gnu/strerror_r_3403.html
+
+ * phobos2/std/contracts.d, phobos2/std/date.d, phobos2/std/dateparse.d,
+ phobos2/std/file.d, phobos2/std/md5.d, phobos2/std/path.d,
+ phobos2/std/random.d, phobos2/std/stdio.d: Fix DMD 2 for GCC-4.3.4
+
+2009-09-11 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ Switching to Mercurial branch system.
+
+ * d/...: Setting up default branch with GCC-4.3.x support.
+
+ * branches/gcc-4.1/...: Starting gcc-4.1.x stable branch.
+
+ * setup-gcc.sh, target-ver-syms.sh: Fixed permission problems in
+ bash scripts.
+
+2009-09-10 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * trunk/...: Import of gdc 0.24 stable into bitbucket.
+
+2009-01-31 Arthur Loiret <arthur.loiret@u-psud.fr>
+
+ * d-glue.cc, d-objfile.cc, d-codegen.cc, d-lang.h, d-builtins2.cc,
+ d-convert.cc, d-codegen.h: Replace calls to build macro by appropriate
+ buildN function (build is removed in GCC > 4.1).
+
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2010 b/gcc/d/ChangeLog-2010
new file mode 100644
index 0000000..40c8fa4
--- /dev/null
+++ b/gcc/d/ChangeLog-2010
@@ -0,0 +1,1484 @@
+2010-12-28 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-lang.cc, d/patches/patch-apple-gcc-5465,
+ d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.0.x,
+ d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x: New function added to langhooks:
+ d_dump_tree
+ [8a2198026630]
+
+ * d/d-lang.cc, d/patches/patch-apple-gcc-5465,
+ d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.0.x,
+ d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x, d/phobos2/Makefile.am,
+ d/phobos2/Makefile.in: New function added to langhooks:
+ d_gimplify_expr
+ [0d43883dcc75]
+
+ * d/d-builtins2.cc, d/druntime/core/stdc/complex.d,
+ d/druntime/rt/complex.c, d/phobos2/Makefile.am, d/phobos2/Makefile.in:
+ D2 - Use GCC builtins in core.stdc.complex
+ [d13bd5912295]
+
+ * d/d-codegen.cc, d/d-glue.cc: Issue #109 - segfault in memcpy()
+ [80c61a61f254]
+
+2010-12-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/asmstmt.cc, d/d-bi-attrs-45.h, d/d-c-stubs.c,
+ d/d-cppmngl.cc, d/d-gcc-includes.h, d/d-glue.cc, d/d-lang-45.h,
+ d/d-lang.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated to 2.051.
+ [9d12fbe44d3]
+
+ * d/phobos2/Makefile.am, d/phobos2/Makefile.in: D2 - Move generated
+ headers out of the way so as they don't interfere with build process.
+ [c52428bb97b]
+
+ * /druntime/rt/aaA.d, d/druntime/rt/adi.d, d/druntime/rt/lifetime.d,
+ d/druntime/rt/memory.d, d/druntime/rt/qsort.d,
+ d/druntime/rt/switch_.d, d/druntime/rt/util/string.d: Merge
+ differences between GDC and DMD Druntime. Should fix Issue #129
+ [1d6e8e716ae3]
+
+ * d/d-glue.cc, d/d-lang.cc, d/druntime/rt/dmain2.d,
+ d/phobos2/Makefile.am, d/phobos2/Makefile.in,
+ d/phobos2/gcc/bitmanip.d: Fix codegen in ArrayLiteralExp; Split cmain
+ from dmain2 in druntime; Update gcc.bitmanip for 2.051.
+ [b1393d6cc45a]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-lang.cc,
+ d/d-objfile.cc, d/dt.cc: Use build_constructor to make constructor
+ nodes.
+ [bd721e198eff]
+
+2010-12-17 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.h, d/d-glue.cc, d/dmd/expression.c, d/dmd2/expression.c:
+ Fix handling of _argptr after commit 398.
+ [95992bb703de]
+
+ * d/d-lang.cc, d/patches/patch-gcc-4.4.x: Issue #104 revisited -
+ easier to instead fix in GCC.
+ [dedbc5dc14a9]
+
+ * d/d-lang.cc: Issue #104 - ICE on inlining nested struct member
+ functions
+ [eb09c05188ea]
+
+ * d/d-decls.cc: Issue #85 - template functions not inlined.
+ [c9db2183900a]
+
+2010-12-12 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins2.cc, d/d-lang.cc, d/dmd2/toobj.c: D2 - tighten up
+ purity set on builtins.
+ [677ff59c566]
+
+ * d/GDC.html, d/dmd/attrib.c, d/dmd/idgen.c, d/dmd2/attrib.c,
+ d/dmd2/idgen.c, d/phobos/gcc/unwind_arm.d, d/phobos2/gcc/unwind_arm.d:
+ GNU_attribute and GNU_set_attribute deprecated for promoting attribute
+ and set_attribute.
+ [99b197365502]
+
+ * d/d-glue.cc, d/d-objfile.cc, d/dmd2/expression.c, d/dmd2/todt.c:
+ cleanup todt; testsuite fixes.
+ [3ee0b55b9fcc]
+
+2010-12-10 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins2.cc, d/d-dmd-gcc.h, d/dmd2/builtin.c,
+ d/dmd2/declaration.h, d/dmd2/expression.c, d/dmd2/interpret.c: Power
+ operators ^^ now working in CTFE.
+ [d804e40bb245]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #121 - ICE in
+ gimple_rhs_has_side_effects.
+ [63a29e175dba]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-gcc-real.h, d/d-irstate.h,
+ d/d-lang.h, d/d-objfile.h, d/dt.h: Glue Header code cleanups.
+ [42d36e6321f5]
+
+ * d/phobos2/std/math.d: Issue #113 - std.math: cos/sin forward
+ declaration issue.
+ [089fa0826192]
+
+ * d/d-asm-i386.h, d/phobos2/std/math.d: Add special case for fdiv/fsub
+ opcodes.
+ [69b717b206e1]
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc: Glue code cleanups.
+ [03e46b45acfc]
+
+ * d/d-asm-i386.h, d/dmd2/expression.c, d/phobos2/std/math.d:
+ off-by-one Inline asm fix.
+ [9f3bb8c3e1e4]
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/dmd2/builtin.c,
+ d/dmd2/declaration.h, d/dmd2/interpret.c, d/phobos2/Makefile.in,
+ d/phobos2/configure: D2 - GCC builtins now CTFE'd.
+ [46b8a2bb22f5]
+
+2010-12-04 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-lang.cc, d/druntime/gc/gcgccextern.d, d/phobos2/Makefile.am,
+ d/phobos2/Makefile.in, d/phobos2/std/math.d, d/setup-gcc.sh,
+ d/target-ver-syms.sh: Updated FreeBSD and Solaris version identifiers.
+ [a52396ea0fa4]
+
+2010-12-03 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-asm-i386.h, d/d-spec.c, d/dmd2/root.c, d/dmd2/speller.c,
+ d/druntime/core/sys/posix/setjmp.d, d/phobos2/configure,
+ d/phobos2/configure.in, d/phobos2/std/math.d: Applied patches from
+ Issue #100, some work on Phobos/Druntime ARM port.
+ [8dbea571bd08]
+
+ * d/d-asm-i386.h, d/d-builtins.c, d/d-lang.cc: Issue #118 - Segfault
+ on string compare.
+ [e2092db74028]
+
+2010-11-26 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-decls.cc: Issue #110 - Pure Nothrow Functions Not Called.
+ [46680c366e68]
+
+ * d/dmd/entity.c, d/dmd2/entity.c: Fixes to html entities.
+ [954a116bc175]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-irstate.h: D2 -
+ support 'case var:' in switch statements.
+ [af08a1a054c8]
+
+ * d/d-glue.cc, d/d-objfile.cc, d/dmd/expression.c,
+ d/dmd2/expression.c: Check lwr <= upr in pointer array slices, fixed
+ AA bug using const types.
+ [0a0c8ff325da]
+
+ * d/druntime/core/sys/osx/mach/kern_return.d,
+ d/druntime/core/sys/osx/mach/port.d,
+ d/druntime/core/sys/osx/mach/semaphore.d,
+ d/druntime/core/sys/osx/mach/thread_act.d: Add version(OSX) at top of
+ source files.
+ [106a741599c6]
+
+ * d/d-glue.cc: Fix ICE compiling empty with{} or volatile{}
+ statements.
+ [e83350ff851b]
+
+ * d/druntime/rt/aaA.d, d/phobos2/std/format.d, d/phobos2/std/string.d:
+ Fix bug in aaA.d, remove workaround in std.format.
+ [6549ec58cf1c]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc,
+ d/druntime/rt/lifetime.d: Issue #108 - crash when compiling
+ declaration of a big array.
+ [38209ac30752]
+
+ * d/d-builtins2.cc, d/d-glue.cc, d/dmd2/expression.c,
+ d/dmd2/expression.h, d/dmd2/optimize.c, d/druntime/core/atomic.d,
+ d/dt.cc, d/dt.h: Refs #108 - Prevent crash when compiling declaration
+ of a big array.
+ [bece6cdf81f8]
+
+2010-11-21 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-convert.cc, d/d-cppmngl.cc,
+ d/d-gcc-real.cc, d/d-glue.cc, d/druntime/core/stdc/stdarg.d,
+ d/druntime/rt/lifetime.d, d/dt.cc, d/symbol.cc: Add _d_arrayliteralT
+ as libcall.
+ [1d3d564d0bfc]
+
+ * d/d-glue.cc, d/dmd2/expression.c, d/druntime/core/stdc/stdarg.d,
+ d/phobos2/std/algorithm.d: Issue #107 - compilation failed on
+ associated array.clear()
+ [75733609b163]
+
+ * d/d-decls.cc, d/d-lang.cc, d/gdc.1, d/lang.opt,
+ d/phobos2/Makefile.am, d/phobos2/Makefile.in: Issue #106 - compilation
+ failed on files importing std.xml.
+ [3205e04db834]
+
+ * d/d-objfile.cc, d/druntime/object.di, d/phobos2/Makefile.am,
+ d/phobos2/Makefile.in: Makefile now properly creates D interface files
+ for installing.
+
+2010-11-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc,
+ d/d-lang.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend
+ to 2.050.
+ [93726e7f3043]
+
+ * d/d-glue.cc, d/dmd2/*, d/phobos2/*: Issue #95 - 'Hello World' for
+ 64bit not working.
+ [f58b9a4c4827]
+
+ * d/Make-lang.in, d/d-codegen.cc, d/d-decls.cc, d/d-irstate.cc,
+ d/druntime/gc/gcgccextern.d, d/dt.h, d/phobos2/Makefile.am: No more
+ segfaults from calling the moduleTlsDtor of a spawned thread.
+ [7afee485d3ec]
+
+ * d/druntime/core/atomic.d, d/druntime/rt/dmain2.d,
+ d/phobos2/Makefile.am, d/phobos2/Makefile.in: Fix makefile to generate
+ & install .di headers for druntime.
+ [8d8f3f8e346f]
+
+ * d/d-codegen.cc, d/d-glue.cc, d/druntime/rt/memory.d: Passes the
+ compilable/fail_compilation testsuite. Fix off-by-one static assert in
+ rt.memory.
+ [a05310b5bd39]
+
+ * d/d-codegen.cc, d/druntime/core/atomic.d, d/druntime/rt/monitor.c:
+ Don't make a libcall for _d_arraycast when converting void[] to
+ array[]. Fix a hang in the generic atomicOps.
+ [d9555265c627]
+
+ * d/Make-lang.in, d/d-apple-gcc.c, d/d-codegen.cc, d/d-glue.cc: Remove
+ redundant tree checking. Fold in apple-gcc patches.
+ [a62de16def16]
+
+ * d/patches/patch-apple-gcc-5664, d/patches/patch-build_gcc-5664: New
+ patches for apple-gcc.
+ [80db7b3f1bbc]
+
+ * d/dmd/entity.c, d/dmd2/entity.c: Merge Walter's and Thomas' named
+ entity lists.
+ [8949157fe7b0]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #98 - cannot
+ perform floating-point modulo division on creal.
+ [53c34b538c56]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #102 - Fixed error
+ using overloaded <>= operator.
+ [61db8ca7622c]
+
+ * d/d-glue.c: Issue #89 - Error initialising struct with static array.
+ [24f69762e9c3]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Issue #103 - destructor
+ not called on array of structs. Postblit on struct now called when
+ returned from a function.
+ [cb7faae1f7b9]
+
+ * d/druntime/object_.d: Merge workaround from Phobos1 library.
+ [336c20f065e4]
+
+ * d/phobos/std/math.d, d/phobos2/std/math.d: Add aliases for missing
+ rndtol and rndtonl functions.
+ [86eb7cecbe6a]
+
+ * d/d-codegen.cc, d/d-glue.cc: Properly handle return (void)value. In
+ slice expression [lwr .. upr], ensure lwr gets evaluated first. Tree
+ checking fixes in NewExp and floatMod.
+ [967482328f44]
+
+2010-11-13 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-c-stubs.c, d/d-codegen.cc, d/d-glue.cc, d/d-objfile.cc,
+ d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.049.
+ [6c13728646ec]
+
+ * d/druntime/core/sys/posix/sys/select.d: Issue #90 - select.d fails
+ to compile on 64 bits Linux.
+ [9cd6979d9a7d]
+
+ * d/druntime/core/sys/posix/sys/select.d, d/druntime/rt/lifetime.d,
+ d/phobos2/gcc/bitmanip.d, d/phobos2/std/bitmanip.d,
+ d/phobos2/std/regexp.d: Issue #91, #92, #93 - various issues building
+ on 64bit Linux.
+ [c3ef6baccc9d]
+
+2010-11-12 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-convert.cc,
+ d/d-cppmngl.cc, d/d-glue.cc, d/d-lang.cc, d/d-spec.c, d/dmd2/*,
+ d/druntime/*, d/phobos2/*: Updated D2 frontend to 2.048.
+ [0d91f8245403]
+
+ * d/druntime/core/sys/posix/sys/select.d: Fix some 64bit compat issues
+ with druntime module.
+ [05bb4c2b1f7d]
+
+2010-11-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/d-glue.cc, d/d-lang.cc,
+ d/dmd-script, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend
+ to 2.047.
+ [4bd4615c8a7e]
+
+2010-11-07 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc,
+ d/dmd-script, d/dmd-script.1, d/gdc.1, d/dmd2/*, d/druntime/*,
+ d/phobos2/*: Updated D2 frontend to 2.046. Removed tabs, trailing
+ spaces.
+ [5be9e0023b23]
+
+2010-11-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc, d/d-irstate.cc, d/d-lang.cc, d/d-objfile.cc,
+ d/d-objfile.h, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2
+ frontend to 2.040.
+ [5beb7019c5e6]
+
+
+2010-11-03 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos/etc/c/zlib.d,
+ d/phobos/std/zlib.d, d/phobos2/Makefile.am, d/phobos2/Makefile.in,
+ d/phobos2/etc/c/zlib.d, d/phobos2/std/zlib.d, d/zlib/*: Upgrade zlib
+ support to zlib 1.2.5.
+ [ea7e83019088]
+
+ * d/d-gcc-real.cc: Issue #79 - Wrong decimal value in error message.
+ [71d8713b0604]
+
+ * d/phobos2/std/json.d, d/setup-gcc.sh: Added --update option for
+ setup-gcc.sh to rebuild directory of libphobos links.
+
+ * d/dmd/typinf.c, d/dmd2/typinf.c: Issue #83 - wrong TypeInfo_Struct
+ name outputted.
+ [f9ddff9d5ed9]
+
+ * d/d-lang.cc: Bugzilla 1911 - Link error when creating array of
+ typedefs with default initializer.
+ [8667626321e7]
+
+2010-11-01 michaelp <baseball.mjp@gmail.com>
+
+ * d/d-codegen.cc: Issue #76 - odd error message when casting between
+ non-convertable types.
+ [0c78536565d6]
+
+2010-11-01 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h,
+ d/d-cppmngl.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/dmd-script,
+ d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.037.
+ [e37f9fae0867]
+
+ * d/druntime/compiler/gdc/object_.d, d/druntime/compiler/gdc/rt/aaA.d,
+ d/druntime/import/object.di: Issue #82 - undefined references in
+ object.d
+ [0aff60753810]
+
+2010-10-31 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/dmd2/*, d/druntime/*,
+ d/phobos2/*: Updated D2 frontend to 2.036.
+ [6bf237fb6ba6]
+
+ * d/d-decls.cc, d/d-glue.cc: Issue #80 - Bad codegen for structs
+ containing invariants.
+ [2fe867d16c45]
+
+ * d/d-codegen.cc, d/d-glue.cc: Issue #81 - Bad codegen and ICEs using
+ enums.
+ [3d028b2d1d30]
+
+ * d/d-lang.cc: Issue #76 - Hide 'In file included from <builtin>'
+ message in errors.
+ [d590dd56696b]
+
+ * d/phobos2/std/string.d, d/phobos2/std/zlib.d: Fix return result of
+ cmp().
+ [582cd1b0bff4]
+
+ * d/d-builtins2.cc, d/druntime/import/core/stdc/math.d: All GCC
+ builtins now marked pure and optionally nothrow. core.stdc.math
+ functions made builtin.
+ [dc2b50a4c0f6]
+
+2010-10-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-glue.cc, d/d-lang.cc, d/dmd2/*, d/druntime/*,
+ d/phobos2/*: Update D2 frontend to 2.035.
+ [ef0d5e8ec06d]
+
+ * d/d-glue.cc: Adjust Classinfo size for D2.
+ [b8673983b46b]
+
+ * d/patches/*, d/set-gcc.sh: Updated patches and setup-gcc.sh for
+ Apple GCC.
+ [b25313940945]
+
+ * d/d-asm-i386.h, d/phobos/std/cpuid.d, d/phobos2/std/cpuid.d: Tell
+ backend cpuid clobbers EBX; remove workaround in std.cpuid.
+ [3cbf9b8108a2]
+
+2010-10-24 michaelp <baseball.mjp@gmail.com>
+
+ * d/d-glue.cc, d/druntime/*, d/phobos2/*: Issue #77 - porting D2
+ Phobos to x86_64.
+ [cf5f02e03fda]
+
+2010-10-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/phobos2/*: Issue #74 - New D2 Phobos source rebased from DMD.
+ [98120f156997]
+
+ * d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos/config.h.in
+ d/phobos/configure, d/phobos2/Makefile.am, d/phobos2/Makefile.in:
+ Fix building with --enable-multilib
+ [67365c9f7b52]
+
+2010-10-21 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-asm-i386.h, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc,
+ d/dmd-script, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 frontend
+ to 2.032.
+ [861e16b38529]
+
+ * d/d-builtins2.cc, d/druntime/import/core/stdc/stdarg.d: D2 - Add
+ core.stdc.stdarg as an stdarg module. Patched core.stdc.stdarg to work
+ with GDC compiler.
+ [8b0a0deb8e7d]
+
+ * d/d-codegen.cc: Issue #72 - 'this' in nested structs cannot access
+ frame of outer function.
+ [3422c59c130a]
+
+ * d/phobos/std/intrinsic.d: D1 - Fix bt function on 64bit archs.
+ [7445723aaedd]
+
+ * d/d-codegen.cc, d/d-glue.cc: Issue #73 - ICE declaring string enums.
+ [0865e6286775]
+
+ * d/druntime/compiler/gdc/aaA.d: D2 - Fixed segfault getting AA
+ keys/values.
+ [d049574ccd3f]
+
+ * d/dmd/mars.h, d/dmd/mtype.c, d/phobos/acinclude.m4,
+ d/phobos/configure, d/phobos/configure.in, d/phobos2/acinclude.m4,
+ d/phobos2/configure, d/phobos2/configure.in, d/target-ver-syms.sh:
+ Some updated to target OS detection.
+ [7fecb2ef6432]
+
+2010-10-12 opticron <nyphbl8d@gmail.com>
+
+ * d/phobos/Makefile.am, d/phobos/Makefile.in, d/phobos2/Makefile.am
+ d/phobos2/Makefile.in: D1/D2: Fix type sizes in gcc/config/* when
+ building with multilib.
+ [b9f7dd4e80a2]
+
+2010-10-11 michaelp <baseball.mjp@gmail.com>
+
+ * d/patches/patch-gcc-4.4.x, d/patches/patch-toplev-4.4.x: Updated
+ 4.4.x patches for 4.4.5
+ [dd2f05ac4246]
+
+2010-10-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc, d/dmd2/*, d/druntime/*: Updated D2 frontend to 2.029.
+ [082c04bad0c3]
+
+2010-10-07 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-asm-i386.h, d/d-codegen.h, d/d-decls.cc
+ d/d-gcc-real.cc, d/d-gcc-real.h, d/d-glue.cc, d/dmd2/*, d/druntime/*,
+ d/phobos2/*: Update D2 frontend to 2.028.
+ [141118223a79]
+
+ * d/dmd/cast.c d/dmd/constfold.c d/dmd/identifier.c d/dmd/lexer.c
+ d/dmd/mars.h d/dmd/mtype.c d/dmd/opover.c d/dmd/optimize.c
+ d/dmd/template.h d/dmd/todt.c d/dmd/toobj.c: Cleaned up D1 folder
+ after D2 updates.
+ [5c293d142e2d]
+
+ * d/asmstmt.cc, d/d-asm-i386.h: Issue #70 - Inline Asm errors junk
+ `(%ebp)+4' after expression.
+ [21764cc50c3f]
+
+2010-10-06 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, dmd2/*, phobos2/*: Updated D2 frontend to 2.026.
+ [7a1dfe79af05]
+
+ * d/d-glue.cc: Issue #69 - ICE on typedef'd array
+ concatenation.
+ [fe66fbb9e08e]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: D2 - Fixed 'this.this'
+ being null in a nested class.
+ [d1dfd83df144]
+
+ * d/d-decls.cc: Let backend know about functions marked as 'nothrow'
+ and 'immutable'.
+ [77df72e87dd0]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc: D2 -
+ Implemented nested structs.
+ [8c901ab67b00]
+
+ * d/d-codegen.cc d/d-codegen.h d/d-glue.cc: Move block of code
+ initialising structs from emitLocalVar to AssignExp.
+ [32165d66c011]
+
+ * d/Make-lang.in, d/d-lang.cc, d/dmd2/array.c, d/dmd2/async.c
+ d/dmd2/async.h, d/dmd2/root.c: D2 - Added AsyncRead sources.
+ [3407bc0a9896]
+
+2010-10-03 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/phobos/std/regexp.d: Fix D1 phobos for 64bit systems.
+ [2cc2741e0031]
+
+ * d/d-decls.cc, d/d-lang.h: D2 - Let backend know about functions
+ marked as 'pure'.
+ [e9eb758ba073]
+
+ * d/druntime/compiler/gdc/lifetime.d: Issue #69 - arraycatnT not
+ working on 64bit.
+ [1fb27285a969]
+
+2010-09-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d/d-codegen.cc, d/d-glue.cc, dmd2/*, druntime/*
+ phobos2/*: Updated D2 frontend to 2.025.
+ [4b8327c25e06]
+
+2010-09-29 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2
+ frontend to 2.022
+ [747409fe2b40]
+
+ * d/d-codegen.cc, d/d-glue.cc, d/phobos2/Makefile.in: Fix building with
+ --enable-checking.
+ [364d892342c5]
+
+ * d/d-codegen.cc, d/druntime/gc/basic/gcx.d: Issue #68 - Cannot cast to
+ structs of same type size.
+ [8fd7216c74a7]
+
+ * d/d-lang.cc, d/dmd-script, d/lang.opt: Added -safe switch.
+ [a06f5919bd1c]
+
+ * d/d-spec.c: Update D2 driver.
+ [9e1b27a03458]
+
+2010-09-28 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * zlib/*: Moved zlib to it's own maintained directory.
+ * d/phobos/etc/c/zlib, d/phobos2/etc/c/zlib: Removed.
+ [46deecb698ea]
+
+ * dmd/*, phobos/*: Updated D1 frontend to 1.064.
+ [77f4acd15b72]
+
+ * dmd2/*, druntime/*, phobos2/*: Updated D2 frontend to 2.021.
+ [ed6460a378bc]
+
+ * d/druntime/compiler/gdc/adi.d, d/druntime/compiler/gdc/alloca.d,
+ d/druntime/compiler/gdc/cover.d, d/druntime/compiler/gdc/memset.d,
+ d/druntime/compiler/gdc/qsort.d, d/druntime/compiler/gdc/qsort2.d,
+ d/phobos2/Makefile.am, d/phobos2/Makefile.in: D2 runtime segfault fixes.
+ [7c9615da20cb]
+
+ * d/d-builtins2.cc d/d-codegen.cc d/d-decls.cc d/d-glue.cc
+ d/dmd2/mars.h d/druntime/compiler/gdc/util/console.d
+ d/phobos2/std/bigint.d d/phobos2/std/bitmanip.d d/phobos2/std/boxer.d
+ d/phobos2/std/date.d d/phobos2/std/dateparse.d d/phobos2/std/md5.d: D2
+ 'this' parameter to struct member functions is now a reference type.
+ [91fd4a667dc9]
+
+2010-09-25 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc: D2 - rework return by ref.
+ [ecd406de9575]
+
+ * d-codegen.cc, d-glue.cc: Move check for ref function to better place.
+ [9dc1edb1c332]
+
+ * d-glue.cc: Issue #66 - Array setting causes OutOfMemoryException.
+ [65f4cc943169]
+
+2010-09-20 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins.c, d-codegen.cc, d-glue.cc:
+ D2 updates - Return by reference now implemented (instead of ignored).
+ [6e2ba321e290]
+
+ * d-codegen.cc, d-convert.cc, d-decls.cc, d-glue.cc:
+ Gain back some compiler speed in release builds.
+ [c8bdb254e8fc]
+
+2010-09-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * phobos2/config.h.in, phobos2/configure:
+ Regenerate D2 configure scripts.
+ [eed0b915018b]
+
+ * druntime/compiler/gdc/dmain2.d:
+ Fix _d_hidden_func to work with GDC compiler
+ [8c2f5a4e8805]
+
+ * d-codegen.cc, d-convert.cc, d-glue.cc, d-lang.h:
+ Issue #64 - enable-checking in configure fails on 4.4.x
+ [7bfec5c437bb]
+
+ * d-lang.h: Issue #28 - enable-checking in configure fails
+ [3de9afb31bb7]
+
+ * druntime/compiler/gdc/trace.d, phobos2/Makefile.am,
+ phobos2/Makefile.in, phobos2/config.log:
+ Remove trace.d from D2
+ [253e781b9254]
+
+2010-09-15 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc d-glue.cc: Fix obscure memory bug in D2.
+ [af9fbe154ba6]
+
+ * d-codegen.cc, d-codegen.h, d-glue.cc, d-irstate.cc, d-irstate.h,
+ dmd/statement.c, dmd2/statement.c:
+ Issue #56 - goto into a try block doesn't produce an error.
+ [960b54da053d]
+
+ * dmd2/inifile.c, druntime/compiler/gdc/cmath2.d,
+ druntime/compiler/gdc/gccmemory.d, druntime/compiler/gdc/memory.d,
+ phobos2/Makefile.am, phobos2/Makefile.in:
+ Split off rt.memory, remove useless sources.
+ [08fac74f4074]
+
+ * druntime/common/core/thread.d, druntime/compiler/gdc/util/cpuid.d:
+ Merge getESP code from D2 phobos to druntime.
+ [5e6ee66625e4]
+
+ * druntime/compiler/gdc/llmath.d: Remove llmath.d
+ [6b7397510e33]
+
+2010-09-09 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc:
+ Revert part of commit 210, and fix integer representations on gdc-4.4.
+ [844b25646834]
+
+ * d-bi-attrs-34.h, d-bi-attrs-341.h, d-builtins.c, d-c-stubs.c,
+ Make-lang.in: Merge d-bi-attrs-341 with d-bi-attrs-34.h.
+ [c2f92387a049]
+
+
+2010-09-07 michaelp <baseball.mjp@gmail.com>
+
+ * gcc-mars.cc:
+ Removed gcc-mars.cc from top level d/ folder.
+ [e4b1e3753bf5]
+
+ * Make-lang.in:
+ Updated Make-lang.in for removal of gcc-mars.cc.
+ [db7d6aae8ceb]
+
+ * GDC.html, History, INSTALL, INSTALL.html, README, dmd-script,
+ dmd-script.1, gdc.1:
+ Documentation updates.
+ [e651ed00a16e]
+
+2010-09-03 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc, d-glue.cc, d-objfile.cc:
+ Issue #59 and #60: ICE when goto undefined label and ICE in foreach over
+ member member array in static func
+ [955dc7d43780]
+
+ * d-codegen.cc, d-glue.cc, d-irstate.cc, d-lang.h, dmd/func.c,
+ dmd/statement.c, dmd/statement.h:
+ Issue #54: 1.063 changes in phobos versioning + dmd backend.
+ [4c10fa4a539a]
+
+2010-09-01 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * dmd/cast.c, dmd/impcnvgen.c, dmd2/impcnvgen.c:
+ Bugzilla 1822 - String slicing in 64-bit gdc causes spurious
+ warnings
+ [5efc9014eef8]
+
+ * patches/patch-gcc-4.0.x, patches/patch-gcc-4.1.x, d/patches
+ /patch-gcc-4.2.x, patches/patch-gcc-4.3.x, patches/patch-
+ gcc-4.4.x:
+ Issue #50 - thanks venix1: SjLj expections fail when thrown from catch
+ block
+ [d655a072bbb8]
+
+ * d-builtins2.cc, d-lang.cc, d-spec.c:
+ Removed va_list hack, small change to D2 lang driver.
+ [7a67e4973ace]
+
+2010-08-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc:
+ Issue #14: STATIC_CHAIN_EXPR not caught in estimate_num_insns_1()
+ [63c14701ccde]
+
+2010-08-29 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-c-stubs.c, d-glue.cc, d-lang.cc:
+ Add stubs for C_TARGET_OBJS on non-x86 archs.
+ [b530fcd9baab]
+
+ * d-glue.cc:
+ Bugzilla 1669 - this.outer in nested classes gives a bogus pointer
+ [ebce488abf89]
+
+ * d-lang.cc, phobos2/Makefile.am, phobos2/acinclude.m4:
+ Add D_Version2 version predicate.
+ [9808b8987cce]
+
+2010-08-28 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-c-stubs.c, d-decls.cc, d-lang.cc,
+ druntime/compiler/gdc/aaA.d, druntime/compiler/gdc/util/cpuid.d,
+ druntime/gc/basic/gc_c.h, druntime/gc/basic/gc_dyld.c,
+ druntime/gc/basic/gc_freebsd.c, druntime/gc/basic/gcgccextern.d,
+ phobos/internal/gc/gcgccextern.d, phobos/std/loader.d,
+ phobos2/Makefile.am, phobos2/acinclude.m4,
+ phobos2/std/cpuid.d:
+ D2 updates.
+ [ebe4ca2bd83a]
+
+2010-08-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d-spec.c, phobos2/Makefile.am:
+ Add druntime to the GDC driver.
+ [3dbc1c4cd214]
+
+ * druntime/Makefile, druntime/compiler/gdc/dgccmain2.d,
+ druntime/compiler/gdc/lifetime.d, phobos2/gcc/deh.d,
+ phobos2/gcc/unwind_generic.d, phobos2/gcc/unwind_pe.d,
+ phobos2/std/stream.d:
+ Remove Makefile and fix module dependencies in Druntime
+ [6fea2af61a0c]
+
+ * phobos2/Makefile.am, phobos2/acinclude.m4, phobos2/aclocal.m4,
+ phobos2/configure.in, d/setup-gcc.sh:
+ Reorganise D2 Makefile for Druntime
+ [f888b572d19a]
+
+ * d/Make-lang.in:
+ Use BACKENDLIBS rather than GMPLIBS for gdc-4.4
+ [bda0f5d37728]
+
+ * d-glue.cc:
+ Fix ICE in D2 ForeachRange statements
+ [7d35bcb69e7e]
+
+2010-08-26 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * patches/patch-gcc-4.4.x:
+ Regenerate gcc-4.4.x patch
+ [4dfe5494460a]
+
+2010-08-25 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.h:
+ Fix codegen for addressOf array types, resolves broken va_lists on
+ gdc-4.4.
+ [9463381e1daa]
+
+ * druntime/compiler/gdc/fpmath.d, druntime/compiler/gdc/gcc/*,
+ druntime/druntimelicense.txt, druntime/druntimereadme.txt,
+ druntime/hello.d, druntime/license.txt, druntime/readme.txt:
+ Re-add fpmath.d - previously from removed internal directory.
+ [bf3e292d1a4c]
+
+ * d-builtins2.cc:
+ Slight alteration to va_list type generation on gdc-4.4
+ [e005caeafced]
+
+ * d-codegen.cc, d-glue.cc, d-irstate.cc, d-lang.h:
+ Use own language flag for labels marked 'used'.
+ [d7963235235c]
+
+ * d-lang.cc:
+ Rework of previous commit for Issue #58.
+ [025031c2e274]
+
+2010-08-24 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-lang.cc:
+ Issue #58 - Fixed stack overflow in gdc-4.4
+ [c02f5ac787a8]
+
+2010-08-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc:
+ Bugzilla 1813 - ICE on static function parametrized with alias.
+ [2e06ca97b873]
+
+2010-08-22 michaelp <baseball.mjp@gmail.com>
+
+ * patches/patch-gcc-3.4.x, patches/patch-gcc-4.0.x, d/patches
+ /patch-gcc-4.1.x, patches/patch-gcc-4.2.x, patches/patch-
+ gcc-4.3.x, patches/patch-toplev-3.4.x, patches/patch-
+ toplev-4.0.x, patches/patch-toplev-4.1.x, patches/patch-
+ toplev-4.2.x, patches/patch-toplev-4.3.x:
+ Updated patches for D2/druntime
+ [dc882e7537c0]
+
+2010-08-22 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d-bi-attrs-44.h, d-builtins.c, d-builtins2.cc,
+ d-codegen.cc, d-decls.cc, d-gcc-includes.h, d-lang.cc,
+ d-objfile.cc, patches/patch-gcc-4.4.x, patches/patch-
+ toplev-4.4.x, d/setup-gcc.sh:
+ Building on GCC-4.4 now supported.
+ [0616ebb4255b]
+
+ * d-lang.cc:
+ Issue #51: 1.062 outstanding issues
+ [9663a271233b]
+
+2010-08-20 michaelp <baseball.mjp@gmail.com>
+
+ * phobos2/*:
+ Updated phobos2 to 2.020 (not working)
+ [08d9a5b24ff4]
+
+2010-08-20 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc:
+ Fix ICE on shorthand if statements.
+ [ef2959fa8184]
+
+2010-08-20 michaelp <baseball.mjp@gmail.com>
+
+ * d-glue.cc:
+ Fixed problem with continue statements in D2
+ [511f3176ec0d]
+
+2010-08-20 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-lang.cc, druntime/compiler/gdc/arraybyte.d,
+ druntime/compiler/gdc/arraydouble.d,
+ druntime/compiler/gdc/arrayfloat.d,
+ druntime/compiler/gdc/arrayint.d,
+ druntime/compiler/gdc/arrayshort.d, phobos/internal/arraybyte.d,
+ phobos/internal/arraydouble.d, phobos/internal/arrayfloat.d,
+ phobos/internal/arrayint.d, phobos/internal/arrayshort.d,
+ phobos2/internal/arraybyte.d, phobos2/internal/arraydouble.d,
+ phobos2/internal/arrayfloat.d, phobos2/internal/arrayint.d,
+ phobos2/internal/arrayshort.d:
+ Issue #30: D_InlineAsm updates
+ [ce1833f9106a]
+
+2010-08-19 michaelp <baseball.mjp@gmail.com>
+
+ * d-lang.cc:
+ Fixed JSON option for D2
+ [2118f4d1de83]
+
+ * d/setup-gcc.sh:
+ Updated setup-gcc.sh for libdruntime building
+ [6e7640bc2b3c]
+
+ * patches/patch-toplev-4.1.x, patches/patch-toplev-4.2.x,
+ patches/patch-toplev-4.3.x:
+ Updated toplevel 4.1, 4.2, and 4.3 patches for libdruntime
+ [1df5716f2b88]
+
+ * patches/patch-toplev-3.4.x, patches/patch-toplev-4.0.x:
+ Updated 3.4 + 4.0 toplevel patches to include libdruntime
+ [a74ceca3c239]
+
+ * dmd/func.c:
+ Issue #57: C-style variadic functions broken
+ [ae817bd07dbf]
+
+2010-08-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * phobos/*:
+ Updated Phobos to 1.063 - expanded tabs.
+ [bbe96bfd09dd]
+
+2010-08-17 michaelp <baseball.mjp@gmail.com>
+
+ * d-glue.cc:
+ One of Issue #56. Cannot goto into finally block
+ [22792e6a6253]
+
+2010-08-17 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc, d-glue.cc, d-irstate.cc, d-irstate.h:
+ Bugzilla 1041 - incorrect code gen for scope(exit) inside switch
+ [d472abadf847]
+
+2010-08-16 michaelp <baseball.mjp@gmail.com>
+
+ * d-glue.cc, dmd/func.c, dmd/statement.c, dmd/statement.h:
+ Temporarily reverted 1.063 change
+ [d89d1a46125d]
+
+2010-08-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d-apple-gcc.c, d-asm-i386.h, d-builtins.c,
+ d-builtins2.cc, d-c-stubs.c, d-codegen.cc, d-codegen.h,
+ d-convert.cc, d-cppmngl.cc, d-decls.cc, d-gcc-includes.h,
+ d-gcc-real.h, d-glue.cc, d-irstate.cc, d-lang.cc,
+ d-lang.h, d-objfile.cc, d-spec.c, d/dt.cc, d/dt.h,
+ d/gdc_alloca.h, d/symbol.cc:
+ Added GPL onto files missing it, attributed modifications.
+ [4d41771eba7c]
+
+2010-08-15 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc:
+ Some more type conversion updates in glue.
+ [4567e417c0b3]
+
+2010-08-14 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-apple-gcc.c, d-codegen.cc, d-convert.cc, d-glue.cc,
+ d-lang.cc:
+ Remove default_conversion, tighten up signed/unsigned conversions.
+ [c1ae96f4e1a6]
+
+ * d-builtins2.cc, d-codegen.cc, d-glue.cc, d-lang.cc,
+ d-lang.h:
+ Removed references to TREE_UNSIGNED.
+ [4a59c1bbc04c]
+
+ * d-gcc-includes.h:
+ Fixed previous glue commit.
+ [9cac96f771a1]
+
+2010-08-14 michaelp <baseball.mjp@gmail.com>
+
+ * phobos/std/thread.d:
+ Updated thread_attach bug in Windows
+ [de30c34ef79d]
+
+2010-08-14 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d-builtins2.cc, d-codegen.cc, d-gcc-includes.h,
+ d-glue.cc, d-lang.cc, d-objfile.cc:
+ Glue touch-ups, now uses D_USE_MAPPED_LOCATION
+ [6122f6d23a71]
+
+2010-08-13 michaelp <baseball.mjp@gmail.com>
+
+ * d-cppmngl.cc:
+ Uploaded missing fix from 1.063 merge
+ [fc7de0a268ab]
+
+ * dmd/template.c:
+ Fixed implicit conversion of template parameters
+ [888e3cc8a31d]
+
+ * d-glue.cc, dmd/async.c, dmd/declaration.c,
+ dmd/declaration.h, dmd/dsymbol.c, dmd/dsymbol.h, dmd/enum.c,
+ dmd/enum.h, dmd/expression.c, dmd/func.c, dmd/init.c,
+ dmd/interpret.c, dmd/mars.c, dmd/mars.h, dmd/module.c,
+ dmd/module.h, dmd/mtype.c, dmd/parse.c, dmd/parse.h,
+ dmd/root.c, dmd/statement.c, dmd/statement.h, dmd/todt.c,
+ phobos/internal/deh2.d, phobos/internal/object.d,
+ phobos/std/math.d:
+ Updated to 1.063
+ [f1e726cbcc98]
+
+2010-08-11 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d-bi-attrs-34.h, d-bi-attrs-341.h, d-bi-
+ attrs-40.h, d-bi-attrs-41.h, d-bi-attrs-42.h, d-bi-attrs-43.h,
+ d-builtins.c:
+ Cleanup d-bi-attrs. Make includes slightly smarter.
+ [349f85192e52]
+
+ * d-codegen.cc:
+ Remove useless trial/error comments in function.
+ [89b4363653f8]
+
+2010-08-10 michaelp <baseball.mjp@gmail.com>
+
+ * d-codegen.cc:
+ Issue 33 - Sefault with nested array allocation
+ [be805cb4fb58]
+
+2010-08-09 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, patches/patch-gcc-4.2.x, patches/patch-
+ toplev-4.2.x, d/setup-gcc.sh:
+ Building on GCC-4.2 now supported.
+ [c1b55292cd94]
+
+ * d-codegen.cc, d-glue.cc, d-irstate.cc:
+ Apply adaptation of feep's autovec patch (one big thanks!)
+ [fbce9c0580d3]
+
+ * d/asmstmt.cc, d-asm-i386.h:
+ Replace tabs for space in ASM outbuffer.
+ [659f6f38f6f4]
+
+2010-08-09 michaelp <baseball.mjp@gmail.com>
+
+ * d/dmd-script:
+ Whitespace fix to previous commit.
+ [0fee937d84d4]
+
+ * d-lang.cc, d/dmd-script, d/lang.opt:
+ Added JSON support - Issue 52 + gdmd usage change
+ [35f04cb2339c]
+
+ * d/dmd-script:
+ Added -defaultlib= and -debuglib= into gdmd usage
+ [e34a68f9c427]
+
+ * d/dmd-script:
+ Updated -defaultlib and -debuglib switches for gdmd - Issue 46
+ [181e89b3d8d6]
+
+2010-08-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins.c, d-c-stubs.c, d-codegen.cc, d-glue.cc,
+ d-lang.h:
+ Build with GCC-3.4 working again.
+ [58e9b23e110c]
+
+ * d/Make-lang.in, dmd2/array.c, dmd2/mars.c, dmd2/root.c,
+ dmd2/total.h:
+ Updates of previous commit
+ [41657ecdc3fe]
+
+ * d/Make-lang.in, d-decls.cc, dmd/expression.c, dmd2/arrayop.c,
+ dmd2/bit.c, dmd2/complex_t.h, dmd2/e2ir.c, dmd2/lib.h,
+ dmd2/libelf.c, dmd2/link.c, dmd2/man.c, dmd2/port.h,
+ dmd2/template.c, dmd2/tocsym.c, dmd2/toir.c, dmd2/toir.h,
+ dmd2/toobj.c, d/symbol.cc, d/symbol.h:
+ Issue 29 - Remove unused D2 files
+ [fdef7864146b]
+
+ * d-decls.cc:
+ Bugzilla 1296 - ICE when object.d is missing things
+ [e9bfccc01834]
+
+2010-08-06 michaelp <baseball.mjp@gmail.com>
+
+ * d/dmd-script:
+ More updates to gdmd
+ [d77ee89f6174]
+
+2010-08-05 michaelp <baseball.mjp@gmail.com>
+
+ * d/dmd-script:
+ Small changes to gdmd; some fixes for Issue 46
+ [9269acda0b86]
+
+2010-08-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-decls.cc, d-glue.cc:
+ Fix logic on array ops. Fixup comments for previous commits.
+ [5792cfbf3ae7]
+
+ * d-glue.cc:
+ Issue 43: >>> and >>>= generate wrong code
+ [56caae262c41]
+
+2010-08-02 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-lang.cc:
+ Regression in D1 when building with --enable-checking
+ [6f2adfcabae6]
+
+ * d-spec.c:
+ Check missing argument for -defaultlib
+ [8d59f275476b]
+
+ * d-decls.cc:
+ Issue 47: GDC improperly handles extern(System) and extern(Windows) on
+ Windows
+ [e5b50cb17c57]
+
+2010-07-31 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc, dmd/todt.c:
+ Issue 51: 1.062 outstanding issues
+ [f41ce1e8e5b2]
+
+ * dmd/aav.c, dmd/aav.h, dmd/arrayop.c, dmd/attrib.c,
+ dmd/cast.c, dmd/constfold.c, dmd/dsymbol.c,
+ dmd/expression.c, dmd/imphint.c, dmd/interpret.c,
+ dmd/lexer.c, dmd/mtype.c, dmd/parse.c, dmd/speller.h,
+ dmd/statement.c, dmd/toobj.c, dmd/unittests.c, dmd/utf.c:
+ Line endings, cleanups, and a missing ')'
+ [84378e5ef655]
+
+ * d-codegen.cc, d-glue.cc:
+ Glue updates for previous merge.
+ [a48e13277e67]
+
+2010-07-31 michaelp <baseball.mjp@gmail.com>
+
+ * d-glue.cc, dmd/*, phobos/std/date.d:
+ Updated to 1.062
+ [9f7927e5f551]
+
+2010-07-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-spec.c:
+ Added -defaultlib and -debuglib to allow building with another
+ library other than libphobos.
+ [f7a52f778a09]
+
+ * druntime/*:
+ Initial import of druntime into project.
+ [2f052aaedd25]
+
+ * d-glue.cc:
+ Fix generation of D array concatenation calls.
+ [d70321dcd604]
+
+ * phobos2/acinclude.m4, phobos2/configure, phobos2/configure.in,
+ phobos2/internal/arrayassign.d, phobos2/phobos-ver-syms.in:
+ D2 now defines Posix.
+ [575ed6d347e0]
+
+ * dmd/parse.c, dmd/speller.c:
+ Include header needed for MinGW to build.
+ [5260cab6c448]
+
+2010-07-29 michaelp <baseball.mjp@gmail.com>
+
+ * phobos2/std/c/stdio.d:
+ Fixed accidentally reapplied Windows patch
+ [d4356fb371ee]
+
+ * d/Make-lang.in, dmd/aav.c, dmd/aav.h, dmd/class.c,
+ dmd/declaration.c, dmd/dsymbol.c, dmd/dsymbol.h,
+ dmd/expression.c, dmd/func.c, dmd/imphint.c, dmd/mars.c,
+ dmd/mars.h, dmd/optimize.c, dmd/scope.c, dmd/speller.c,
+ dmd/struct.c, dmd/template.c, phobos2/std/c/stdio.d:
+ Updated to 1.061
+ [9038432ea1ff]
+
+ * phobos/std/c/stdio.d, phobos2/std/c/stdio.d:
+ Remove stdio.d patches from Issue 21 patch
+ [a53c51fad1bd]
+
+ * d-decls.cc, phobos/std/c/stdio.d, phobos2/std/c/stdio.d:
+ Issue 21 - _iob undefined reference under Windows
+ [ea913c7eec42]
+
+ * d-glue.cc:
+ Fixed array ops bugs from 1.059
+ [92c39c74433f]
+
+ * d/Make-lang.in, dmd/cast.c, dmd/class.c, dmd/declaration.c,
+ dmd/declaration.h, dmd/dsymbol.c, dmd/expression.c,
+ dmd/expression.h, dmd/idgen.c, dmd/init.c, dmd/inline.c,
+ dmd/interpret.c, dmd/json.c, dmd/mars.c, dmd/mtype.c,
+ dmd/parse.c, dmd/speller.c, dmd/speller.h, dmd/statement.h,
+ dmd/unittests.c:
+ Updated to 1.060
+ [1c1cc97db718]
+
+2010-07-28 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/dmd-script, d/lang-specs.h:
+ Issue 48: gdc/gdmd should be able to compile .di files
+ [976a611f59f3]
+
+ * d-lang.cc, dmd/*, phobos/*:
+ Updated to 1.058
+ [9ac6a02138c2]
+
+ * d/Make-lang.in, dmd/machobj.c:
+ Remove machobj.c from D1
+ [67d109f8fe79]
+
+ * d-lang.cc, d/dmd-script, d/symbol.cc:
+ Issue 42: -Wall should not error out compiler
+ [7593822be7c0]
+
+2010-07-27 michaelp <baseball.mjp@gmail.com>
+
+ * d/Make-lang.in, d-lang.cc, d/dmd-script, dmd/dsymbol.c,
+ dmd/dsymbol.h, dmd/expression.c, dmd/func.c, dmd/init.c,
+ dmd/inline.c, dmd/interpret.c, dmd/machobj.c, dmd/mars.c,
+ dmd/mars.h, dmd/module.c, dmd/module.h, dmd/mtype.c,
+ dmd/root.c, dmd/root.h, dmd/scope.c, dmd/scope.h,
+ dmd/speller.c, dmd/speller.h, dmd/statement.c,
+ dmd/template.c, d/lang.opt, phobos/internal/aaA.d:
+ Updated to 1.057
+ [b4fb93e94c29]
+
+2010-07-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, dmd/array.c, dmd/bit.c, dmd/complex_t.h,
+ dmd/constfold.c, dmd/e2ir.c, dmd/elfobj.c, dmd/expression.c,
+ dmd/irstate.c, dmd/irstate.h, dmd/lib.h, dmd/libelf.c,
+ dmd/libmach.c, dmd/link.c, dmd/man.c, dmd/mars.c,
+ dmd/mem.c, dmd/mem.h, dmd/mtype.c, dmd/port.c, dmd/port.h,
+ dmd/root.c, dmd/tocsym.c, dmd/toir.c, dmd/toir.h:
+ Issue 29 - Remove unused D1 files
+ [d74291c4230b]
+
+ * dmd/template.c, dmd2/template.c:
+ Issue 36: duplicate symbols created for negatively initialized template
+ arugments
+ [1bd9793d8fc6]
+
+ * d-builtins.c:
+ Partial fix for Issue 28
+ [7fb5519947d4]
+
+ * d-lang.cc:
+ Issue 44: strange code in d-asm-1386.h
+ [73c379cc9714]
+
+2010-07-26 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc, d-glue.cc:
+ D2 postblit on struct literals finished!
+ [9ee37bd66bca]
+
+2010-07-25 michaelp <baseball.mjp@gmail.com>
+
+ * d-lang.cc, d/dmd-script, dmd/*,
+ phobos/internal/arrayfloat.d:
+ Updated to 1.056
+ [4ff162deda23]
+
+2010-07-24 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc:
+ D2 postblit updates.
+ [d53a8be7c0ed]
+
+2010-07-23 michaelp <baseball.mjp@gmail.com>
+
+ * dmd/class.c, dmd/enum.c, dmd/enum.h, dmd/mars.c,
+ dmd/struct.c:
+ Updated to 1.055
+ [9c62fb9d0abf]
+
+ * dmd/expression.c:
+ Fixed spot with wrong patch in it
+ [172855a888e9]
+
+ * dmd/*, phobos/internal/gc/gcx.d:
+ Updated to 1.054
+ [64df5a74b2c4]
+
+2010-07-21 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-lang.cc:
+ Fixed warnings in d-lang.cc (thanks Trass3r)
+ [7a3c1ae0b625]
+
+ * d-asm-i386.h:
+ Fix cast warnings in d-asm-i386.h
+ [fa9b66399a13]
+
+ * dmd/lexer.c, dmd2/lexer.c:
+ Fix buffer overflow in certain error messages
+ [b91574453f5e]
+
+ * d-asm-i386.h:
+ Correctly check align value in asm.
+ [d5a0f3619810]
+
+2010-07-20 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc, dmd/root.c, dmd/statement.c, dmd/template.c,
+ dmd/template.h, phobos/std/c/stddef.d:
+ Quick updates to D1 and postblit code.
+ [214fbfbf5f3f]
+
+ * d-builtins2.cc, d-codegen.cc, d-codegen.h, d-glue.cc,
+ dmd/expression.c, dmd/func.c, dmd/machobj.c, dmd/mtype.c,
+ dmd/parse.c, dmd/statement.c, dmd/statement.h, dmd/toobj.c,
+ phobos/internal/gc/gc.d:
+ Some whitespace corrections.
+ [c9c54a275526]
+
+2010-07-20 michaelp <baseball.mjp@gmail.com>
+
+ * d-builtins2.cc, d-codegen.cc, d-codegen.h, d-glue.cc,
+ dmd/*, phobos/*:
+ Updated to 1.053
+ [f02a96cfc1de]
+
+2010-07-20 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc:
+ Quick revision updates
+ [c79811b4f1fc]
+
+2010-07-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc, dmd2/attrib.c, dmd2/cast.c, dmd2/cond.c,
+ dmd2/constfold.c, dmd2/declaration.c, dmd2/declaration.h,
+ dmd2/e2ir.c, dmd2/expression.c, dmd2/func.c,
+ dmd2/impcnvgen.c, dmd2/lexer.c, dmd2/lexer.h, dmd2/link.c,
+ dmd2/mars.c, dmd2/mtype.c, dmd2/mtype.h, dmd2/parse.c,
+ dmd2/parse.h, dmd2/statement.c, dmd2/toir.c:
+ Updated to 2.020 - Frontend Only
+ [676f0aa79458]
+
+2010-07-17 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * phobos2/Makefile.in:
+ libgphobos2 Makefile fixes.
+ [c4acdacfddd2]
+
+2010-07-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ Merge with DMD 2.019
+
+ * d-decls.cc: Merge changes from dmd2/tocsym.c
+
+ * phobos/Makefile.am, phobos/Makefile.in, phobos2/Makefile.am,
+ phobos2/Makefile.in: Fix build for check-target-libphobos tests.
+
+ * d-decls.cc, d-objfile: Fixed ICE in gdc-4.3 [39825b8156a3]
+
+2010-07-14 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ Merge with DMD 2.018
+
+ * d-lang.cc: Added support for AsyncRead in D1.
+
+ * dmd/constfold.c, dmd2/constfold.c: Fixed lost precision when casting
+ from large floats to integral types.
+
+ * dmd/todt.c, dmd2/todt.c: Fixed initialiased pointer array values
+ being reset to null during compilation.
+
+ * Make-lang.in, d-backendfunctions.c, dmd/template.c: Removed
+ backendfunctions.c from Makefile.
+
+2010-07-11 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-asm-i386.h: AMD Opcodes Supported.
+
+ * Make-lang.in, dmd/mtype.c, dmd/struct.c, target-ver-syms.sh:
+ struct ABI fixes.
+
+ * phobos/std/math.d, phobos2/std/math.d: Fix wrong return value in
+ expi() function.
+
+2010-07-07 michaelp <baseball.mjp@gmail.com>
+
+ * dmd/arrayop.c: Fix problem with float array operations.
+ - Added linear search for the array op library functions.
+
+2010-07-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * dmd2/..., phobos2/...: Resolved issues for DMD 2.017.
+
+ * phobos2/configure, phobos2/configure.in: Re-add GNU_Need_execvpe for
+ D2 libphobos.
+
+ * dmd/mtype.h, phobos2/internal/object.d, phobos2/std/cpuid.d:
+ Quick updates to previous revisions.
+
+2010-07-05 michaelp <baseball.mjp@gmail.com>
+
+ Merge DMD 2.017
+
+2010-07-04 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ Merge DMD 1.052
+
+ * d-glue.cc: Fix ICE when using type tuple as function argument.
+
+ * phobos/..., phobos2/...: libphobos cleanup and updates.
+
+ * d-codegen.cc, d-decls.cc: Fix problem when building with
+ --enable-checking.
+
+2010-06-28 michaelp <baseball.mjp@gmail.com>
+
+ * setup-gcc.sh: D1 is default in setup-gcc.sh now.
+
+2010-06-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ Merge with DMD 1.050
+
+ * Make-lang.in: Update for files added in DMD 1.050.
+
+ * phobos/etc/c/zlib.d, phobos/std/zlib.d, phobos2/etc/c/zlib.d:
+ Updated Zlib to 1.2.3.
+
+2010-06-22 michaelp <baseball.mjp@gmail.com>
+
+ * phobos/configure, phobos/configure.in, phobos/std/process.d,
+ phobos2/configure, phobos2/configure.in, phobos2/std/process.d:
+ Fix problem when building with a version of GNU C that has execvpe()
+ implemented (staring with glibc-2.11).
+
+ * phobos/configure, phobos/configure.in, phobos/std/c/freebsd/freebsd.d:
+ Fix problem when linking on FreeBSD targets.
+
+2010-06-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ Merge with DMD 1.049
+
+ * d-lang.cc: Merge changes from dmd/mars.c.
+
+ * d-codegen.cc, d-decls.cc: Fix ICEs in const array assignments.
+
+ * d-lang.cc, dmd-script, lang.opt: Added -fdeps option to gdc and
+ -deps to gdmd.
+
+ * dmd/mem.c, dmd/mem.h, dmd/port.c, dmd/rmem.h, dt.cc, dt.h,
+ phobos/internal/qsortg.d: Remove executable bit on source files.
+
+2010-06-12 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ Merge with DMD 1.047
+
+ * d-codegen.cc: Look for reference initializations in foreach
+ statement assignments.
+
+ * dmd/..., dmd2/..., phobos/..., phobos2/...: Converted CR, CRLF line
+ endings to LF (thanks to venix1).
+
+2010-06-04 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * d-asm-i386.h: Apply patch to compile tango (thanks to venix1).
+
+2010-04-05 michaelp <baseball.mjp@gmail.com>
+
+ Merge with DMD 1.046
+
+ * d-decls.cc: Fix problem with struct declarations in GCC-4.3.x.
+
+ * dmd-script: Added -pipe option to gdmd
+
+ * d-lang.cc, phobos/...: Fix FreeBSD and Windows version issues.
+
+ * dmd/root.c: Fix Windows template instantiating error.
+
+ * dmd/func.c: Fix segfault on wrong arg type.
+
+2010-02-17 Vincenzo Ampolo <vincenzo.ampolo@gmail.com>
+
+ * d-glue.cc: Make d1 classinfo like d2 ones.
+
+ * dmd/expression.c, phobos/std/process.d: Apply feep (downs) patch.
+
+2010-02-07 michaelp <baseball.mjp@gmail.com>
+
+ Merge with 1.045
+
+ * phobos/linux.mak, phobos/win32.mak: Removed Phobos .mak files for
+ D 1.045 update.
+
+ * samples/hello.d, samples/samples.sh: Added 1 file to samples
+ directory.
+
+2010-01-15 opticron <nyphbl8d@gmail.com>
+
+ * phobos/std/string.d: Fix a set of bugs in std.string.split which
+ made delemiters of length > 1 segfault.
+
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2011 b/gcc/d/ChangeLog-2011
new file mode 100644
index 0000000..a5c1558
--- /dev/null
+++ b/gcc/d/ChangeLog-2011
@@ -0,0 +1,1248 @@
+2011-12-31 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc: Revert some prior code
+ additions.
+ [a61a03e817c3]
+
+ * d/d-decls.cc, d/d-glue.cc: Issue #301 - ref return funcs returning
+ wrong reference
+ [2350d3a27ac8]
+
+2011-12-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-irstate.cc, d/d-lang.cc: Implicitly convert all statements to
+ void, warn if statement has no side effects.
+ [d73ff02f1131]
+
+ * d/d-decls.cc, d/d-glue.cc: mark RESULT_DECL as artificial.
+ [a2de4187caa4]
+
+ * d/d-codegen.cc, d/d-glue.cc: Remove check for isref out of ::call
+ and into CallExp::toElem
+ [1b827c7df15c]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: Use INIT_EXPR instead of
+ MODIFY_EXPR where applicable, added vinit.
+ [27c401e61169]
+
+ * d/d-codegen.cc, d/d-codegen.h: Move functions written in d-codegen
+ header to source file.
+ [605c79094f14]
+
+ * d/d-codegen.cc: Issue #302 - lazy arg causing ICE in
+ gimple_expand_cfg, at cfgexpand.c:4063
+ [786acc44a0ff]
+
+2011-12-28 Daniel Green <venix1@gmail.com>
+
+ * d/phobos2/Makefile.am, d/phobos2/Makefile.in: Add
+ std/internal/windows/advapi32.o to WINDOWS_OBJS.
+ [e7639c523add]
+
+2011-12-28 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-gcc-includes.h, d/d-glue.cc: Emit pretty debug tree information
+ on -fdump-tree-original
+ [7631e902659e]
+
+ * d/d-asm-i386.h, d/d-codegen.h, d/d-glue.cc, d/d-lang.cc,
+ d/d-objfile.cc: Remove some dead code.
+ [e8ae51578e54]
+
+ * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang-45.h,
+ d/d-lang.cc, d/d-lang.h, d/d-objfile.cc: Issue #258 - cannot access
+ frame with contract inheritance
+ [0b470bc59251]
+
+ * d/d-lang.cc, d/gdc.1, d/lang.opt: Add switches to control in(),
+ out() and invariant() code generation.
+ [e9904da308eb]
+
+ * d/asmstmt.cc, d/d-builtins2.cc, d/d-decls.cc, d/d-glue.cc,
+ d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x,
+ d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x,
+ d/patches/patch-gcc-4.6.x: Remove gdc patch to cgraph.c - fix codegen.
+ [fc5e3bddbf94]
+
+ * d/d-decls.cc: Issue #298 - Array Range Functions Don't Get Inlined
+ [f9217ce815ea]
+
+2011-12-25 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc, d/dmd2/expression.c, d/dmd2/expression.h,
+ d/dmd2/optimize.c, d/phobos/configure, d/phobos2/configure: Fixup
+ arrayliteral assignments.
+ [d71656e55ad8]
+
+ * d/phobos/configure, d/phobos2/configure: Rebuild configure for D1
+ [bedf43669633]
+
+ * d/d-glue.cc: Issue #297 - GDC Acquires Locks Twice in Synchronized
+ Member Methods.
+ [7470a20b2900]
+
+ * d/d-objfile.cc, d/d-objfile.h: First attack at fixing issue #246
+ [bd1f89846e93]
+
+2011-12-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc: Issue #287 - Casting between array types is broken.
+ [63647d6f2b87]
+
+ * d/phobos2/Makefile.in, d/phobos2/configure: Rebuild Makefile.in,
+ configure for D2.
+ [b3200b086277]
+
+ * d/d-lang.cc: Issue #296 - -fproperty implies -frelease
+ [4dfa4c11ccd7]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-lang.cc: Remove unused
+ warnSignCompare.
+ [60ea5d6b4173]
+
+ * d/d-codegen.cc: Issue #289 - ICE: in extract_range_from_binary_expr,
+ at tree-vrp.c:229
+ [9076a0f27fd9]
+
+ * d/dmd-script, d/dmd-script.1, d/gdc.1: Update manpages for new
+ GDC/GDMD options.
+ [9caec4bea289]
+
+ * d/d-objfile.cc: Issue #279 - ICE: in gimple_expand_cfg
+ [6778c7a1f79e]
+
+ * d/d-builtins2.cc: Add CTFE support for builtins atan2, rndtol,
+ expm1, exp2.
+ [afe30f1b9435]
+
+2011-12-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc: D2 - Handle nulltype to D array conversions.
+ [d7fe9fa5bb6c]
+
+ * d/d-glue.cc, d/d-lang.cc: Match GCC logic for emitting D_LP64
+ version identifier.
+ [7475431fe1bd]
+
+ * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc: Better implementation of
+ bt, btc, bts, btr functions, allowing constant folding.
+ [caf2c8d4f036]
+
+ * d/d-builtins2.cc: Implement CTFE for bswap, bsr, bsf.
+ [730c51fcdd3e]
+
+ * d/druntime/core/thread.d: Issue #290 - errno conflict in std.file
+ [ecd60be7f89c]
+
+ * d/d-lang.cc: Define D_LP64 if is64bit.
+ [633ea9c9e5bf]
+
+ * d/dmd-script: Issue #282 - gdmd multithreaded -lib implementation.
+ [f1bd82f9bb5b]
+
+ * d/dmd-script: Issue #283 - gdmd: libraries not put into -od dir.
+ [75a7b584473a]
+
+ * d/d-objfile.cc, d/dmd/attrib.c, d/dmd2/attrib.c, d/lang.opt: Issue
+ #286 - -fignore-unknown-pragmas doesn't seem to work
+ [f342fde254e2]
+
+2011-12-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc,
+ d/d-irstate.cc, d/d-irstate.h, d/d-lang.cc, d/dmd2/*, d/druntime/*,
+ d/phobos2/*: Updated D2 Frontend to 2.057
+ [36c28efc6c88]
+
+2011-12-11 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/dmd/*: Updated D1 Frontend to 1.072
+ [e83cac3b4109]
+
+ * d/dmd/expression.c, d/dmd2/expression.c: Issue #279 - ICE: in
+ gimple_expand_cfg
+ [c501487a685a]
+
+2011-12-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc,
+ d/d-codegen.cc, d/d-cppmngl.cc, d/d-decls.cc, d/d-dmd-gcc.h,
+ d/d-glue.cc, d/d-irstate.cc, d/d-lang-45.h, d/d-lang-type-45.h,
+ d/d-lang-type.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc,
+ d/dmd-script, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2 Fronted
+ to 2.056
+ [fbe890ef4c1f]
+
+ * d/d-codegen.cc, d/d-glue.cc: Relax conversion checking. Move getImpl
+ to CastExp.
+ [b0407ff2e57c]
+
+ * d/dmd/optimize.c, d/dmd2/optimize.c: Remove old frontend ifdef'd
+ code.
+ [8e0291212f46]
+
+2011-12-02 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-lang.cc, d/lang-specs.h, d/lang.opt: remove preprocessor options
+ from spec and use own switches.
+ [5f71b69d1494]
+
+ * d/d-objfile.cc: Issue #275 - ICE with wrong interface implementation
+ [e32c8fbe7343]
+
+ * d/d-lang.cc, d/dmd/mars.h, d/dmd2/mars.h, d/lang-specs.h,
+ d/lang.opt: Issue #236 - -M, -MM, -MF options to generate dependencies
+ like gcc
+ [3763796b9cbf]
+
+ * d/d-lang.cc, d/lang.opt: ASCII collate lang switches.
+ [951ff44f1035]
+
+2011-12-02 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-objfile.cc: Issue #268 - ICE with -flto and -g
+ [3da453291dc3]
+
+2011-11-24 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in: Issue #266 - make install-strip fails to install
+ gdmd.
+ [d1005cb77a06]
+
+ * d/d-glue.cc, d/d-lang.cc, d/dt.cc: Remove checks for
+ type_structural_equality for now.
+ [5265f1318114]
+
+ * d/d-glue.cc: Issue #261 - ICE: tree check: expected record_type or
+ union_type, have array_type in delegateVal
+ [61ab289788a3]
+
+ * d/d-glue.cc: Issue #264 - ICE: can't convert between bool and enum :
+ bool
+ [fcb2523b8ccd]
+
+ * d/d-codegen.cc, d/d-glue.cc: Issue #263 - forward reference error
+ with algorithm.find
+ [75b7e1bca4d7]
+
+2011-11-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc, d/d-decls.cc,
+ d/d-glue.cc, d/d-irstate.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h,
+ d/d-objfile.cc: Add d_free, rename dkeep to d_keep.
+ [a0e0fcfd913c]
+
+2011-11-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/d-lang-45.h, d/d-lang.cc,
+ d/d-lang.h: Issue #262 - ICE: weird segfault when -o option is used
+ [51d11a9bddf2]
+
+ * d/d-lang.cc: Issue #255 - ICE: invalid conversion in gimple call
+ [36ae9c015e86]
+
+ * d/d-decls.cc: Issue #259 - ICE: constant not recomputed when
+ ADDR_EXPR changed
+ [72c16f7ab674]
+
+ * d/d-builtins2.cc, d/d-dmd-gcc.h, d/dmd/attrib.c,
+ d/dmd/declaration.c, d/dmd/declaration.h, d/dmd/mtype.c,
+ d/dmd/struct.c, d/dmd2/attrib.c, d/dmd2/declaration.c,
+ d/dmd2/declaration.h, d/dmd2/mtype.c, d/dmd2/struct.c: Issue #215 -
+ Alignment of struct members wrong on ARM
+ [2df7ca5fa4b6]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc,
+ d/d-lang.cc: Issue #242 - Another lambda segfault
+ [467d7fa518fc]
+
+2011-10-31 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-lang.cc: Arm -> ARM and darwin -> Darwin in d-lang.cc.
+ [51e67c38af0c]
+
+2011-10-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/target-ver-syms.sh: Make some system and CPU version identifiers
+ consistent in casing.
+ [5d11c2ded7b7]
+
+ * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc: Use isMember2 when
+ checking member functions.
+ [d89c3b7d495a]
+
+ * d/d-codegen.cc, d/d-decls.cc, d/d-lang-45.h, d/d-lang.h,
+ d/d-objfile.cc: Issue #78 D1/D2 - in/out contract inheritance
+ [736ae4b92f2]
+
+2011-10-26 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-glue.cc, d/d-irstate.cc: Issue
+ #252 - Error: suffix or operands invalid for `jc'
+ [0d65aed46422]
+
+ * d/lang-specs.h, d/patches/patch-apple-gcc-5465,
+ d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x, d/patches/patch-gcc-4.6.x: Issue #251 -
+ Remove all references to fmultilib-dir usage in gdc spec and patches.
+ [c72727fc3f13]
+
+2011-10-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/druntime/core/stdc/stdio.d, d/druntime/core/stdc/stdlib.d,
+ d/druntime/rt/critical_.d, d/druntime/rt/dmain2.d,
+ d/druntime/rt/monitor_.d, d/phobos/config/libc.x3,
+ d/phobos2/config/libc.x3, d/target-ver-syms.sh: Start on implementing
+ platform agnostic druntime for GDC D2.
+ [c46d1009bd78]
+
+ * d/d-lang.cc, d/target-ver-syms.sh: Add VENDOR_VERSYM to D version
+ identifiers if defined.
+ [f7abc9009d0d]
+
+ * d/d-lang.cc, d/d-objfile.cc: Issue #224 - Link time optimization
+ [bf9d0ac53e9d]
+
+ * d/d-decls.cc, d/d-glue.cc, d/d-irstate.cc, d/d-irstate.h,
+ d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/lang.opt: Merge changes
+ from gcc-4.7 branch.
+ [5992dd0f2f7e]
+
+ * d/d-codegen.cc: Use gcc atomics for bt, btc, btr, bts intrinsics.
+ [2cc2e8c5a778]
+
+ * d/d-glue.cc: build_assign_math_op: Stabilize LHS expression.
+ [031b711ce09]
+
+2011-10-21 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc, d/d-glue.cc,
+ d/d-irstate.cc, d/d-lang-45.h, d/d-lang.h, d/dmd/mtype.c,
+ d/dmd2/mtype.c: Issue #247 - undefined reference to `.LDASM1'
+ [19de20aec625]
+
+ * d/asmstmt.cc, d/d-asm-i386.h: Fallback to 32bit instruct suffix when
+ 64bit not available, add special case for fild.
+ [8789c97f84ac]
+
+ * d/asmstmt.cc, d/d-asm-i386.h: Issue #248 - Inline assembler
+ generates wrong argument size for FILD instruction.
+ [8bd2a4ca84c0]
+
+2011-09-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/dmd-script: Issue #241 - dmd.conf DFLAGS doesn't work with
+ DMD-style args.
+ [4bf307759462]
+
+ * d/d-codegen.cc, d/d-glue.cc: Issue #239 - Filter + Closure =
+ Segfault.
+ [23b24ffe94f2]
+
+ * d/dmd-script: Properly handle -X and -map switches in gdmd.
+ [f7c13cf55264]
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-irstate.cc, d/d-irstate.h: Fixup
+ some build warnings.
+ [891f65500765]
+
+ * d/dmd-script: Issue #234 - add DFLAGS to the build command in gdmd.
+ [3acdb17df213]
+
+2011-09-25 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/dmd-script: Issue #234 - dmd.conf equivalent
+ [db9070d078a8]
+
+ * d/druntime/core/thread.d, d/phobos2/std/path.d: Re-add fixes that
+ got removed in last D library merge.
+ [a998cdff6e0f]
+
+ * d/dmd/todt.c, d/dmd2/todt.c, d/dt.cc: size_t'ify toDt.
+ [c1306d366f94]
+
+ * d/d-glue.cc: CallExp - only call convert on basic return types.
+ [bc7ad8e2569]
+
+ * d/d-gcc-real.cc: real_t::convert - check base type
+ [71eb59683499]
+
+ * d/dmd/attrib.c, d/dmd2/attrib.c: Optimise attribute pragma
+ arguments.
+ [dca4ddf21110]
+
+2011-09-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc: Issue #235 - ICE in feep's tools library
+ [17da3d28ba17]
+
+2011-09-15 Daniel Green <venix1@gmail.com>
+
+ * d/d-glue.cc: Make PowAssignExp::toElem only compile with D2.
+ [fa6a47ddbd9c]
+
+ * d/dt.h: Issue #231. Use size_t for dt_size declaration in dt.h.
+ [f9fee0fd57a2]
+
+2011-09-14 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins2.cc, d/d-gcc-real.cc, d/d-gcc-real.h, d/d-glue.cc,
+ d/dmd2/constfold.c, d/dmd2/declaration.h, d/dmd2/expression.c,
+ d/dmd2/expression.h, d/dmd2/interpret.c, d/dmd2/optimize.c: Implement
+ constant folding of ^^ expressions.
+ [06f5e7c038fa]
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc,
+ d/d-cppmngl.cc, d/d-decls.cc, d/d-glue.cc, d/d-incpath.cc,
+ d/d-lang.cc, d/d-objfile.cc, d/dt.cc: Change unsigned for size_t in
+ for loops.
+ [814fc99ff732]
+
+ * d/d-lang.cc, d/dmd/mars.c, d/dmd2/mars.c: Re-enforce -Werror flag in
+ gdc.
+ [eced11f7d5b5]
+
+ * d/d-glue.cc: Issue #232 - sqrt(3) == 2.15118e-4930
+ [8994cef9271f]
+
+2011-09-12 Daniel Green <venix1@gmail.com>
+
+ * d/d-lang.cc: Convert Array to Strings required by DMD 1.070/2.055
+ [fc0033715683]
+
+2011-09-12 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/druntime/rt/dmain2.d, d/druntime/rt/lifetime.d: Issue #214 -
+ Segfault Allocating from Shared Static C'tor
+ [41218d9f5f59]
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc,
+ d/d-codegen.h, d/d-cppmngl.cc, d/d-decls.cc, d/d-dmd-gcc.h,
+ d/d-glue.cc, d/d-incpath.cc, d/d-irstate.cc, d/d-irstate.h,
+ d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/dmd2/*, d/druntime/*,
+ d/phobos2/*: Updated D2 Frontend to 2.055.
+ [0ada920f6394]
+
+ * d/dmd/*, d/phobos/*: Updated D1 Frontend to 1.070.
+ [fad5f4cad72b]
+
+2011-09-10 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-spec.c: Issue #230 - Error building Cross Compiler under MinGW
+ [b0a9ef534877]
+
+ * d/d-lang.cc, d/druntime/core/thread.d: Issue #226 - GC from spawned
+ threads segfaults on 64-bit
+ [3ea496446c7e]
+
+2011-09-03 Daniel Green <venix1@gmail.com>
+
+ * d/asmstmt.cc: Use of V1 is more correct.
+ [748ce286f58f]
+
+ * d/dmd/root.c d/dmd2/root.c: Enables MinGW32 to use ANSI STDIO.
+ [e69b142048f0]
+
+ * d/asmstmt.cc: Allow inline assembly to set return values. Matches
+ DMD functionality.
+ [857c5645429c]
+
+2011-08-29 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc,
+ d/d-objfile.cc, d/symbol.cc: Emit pretty identifier to the debugger.
+ [ac87eb9db360]
+
+2011-08-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-glue.cc, d/d-objfile.cc: Don't warn about unused
+ compiler generated vars.
+ [0a71a122ca29]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-irstate.cc,
+ d/d-irstate.h, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h: New functions
+ build_d_decl_lang_specific, d_mark_exp_read. Added support for
+ -Wunused-variable, WIP -Wunused-but-set-variable.
+ [d23bab68266c]
+
+2011-08-19 Daniel Green <venix1@gmail.com>
+
+ * d/druntime/core/sys/windows/stacktrace.d: Issue #227. build error
+ libphobos/core/sys/windows/stacktrace.d.
+ [b1c34b7e7764]
+
+2011-08-15 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-decls.cc: Issue #225 - Array ops should be COMDAT.
+ [dda1c10c8c7b]
+
+2011-08-12 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc, d/d-irstate.cc: Re-add codegen which caused issue #205
+ in correct place.
+ [e26b2b67bffa]
+
+ * d/d-codegen.cc, d/d-gcc-includes.h: Issue #191 - SEGV(gimple.c:2624)
+ getting array ref of incomplete type.
+ [d0edf91c3fcf]
+
+2011-08-07 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-glue.cc: Issue #205 - ICE using phobos sort.
+ [b3a5c764de90]
+
+ * d/d-asm-i386.h, d/d-tree.def: Define tree code IASM_EXPR.
+ [c7e7dc1c089b]
+
+ * d/d-asm-i386.h: Handle zero and one operand forms of fcomi, fcomip.
+ Fixed db, ds, di, dl to output constants and strings properly.
+ [e394c90a88fa]
+
+ * d/d-decls.cc, d/d-glue.cc, d/d-lang-type-45.h, d/d-lang-type.h,
+ d/d-lang.cc, d/d-lang.h: Create TYPE_LANG_SPECIFIC type for arrays,
+ functions, delegates.
+ [1c25bfb71c05]
+
+ * d/d-glue.cc, d/dt.cc: Use TYPE_STRUCTURAL_EQUALITY for conversions
+ of records, should fix Issue #217.
+ [04b8a399ddeb]
+
+ * d/asmstmt.cc, d/d-asm-i386.h: Fix error using offsetoff for
+ SymOffExp's in IASM.
+ [933d2ca08770]
+
+ * d/d-asm-i386.h: Added SSE4.1, SSE4.2 instructions
+ [6a643f59ac86]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc, d/d-lang-45.h,
+ d/d-lang.cc, d/d-lang.h, d/d-objfile.cc, d/dt.cc: More 4.6.x gimple
+ checking issues.
+ [148a5a16d432]
+
+2011-07-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-glue.cc, d/d-lang-45.h, d/d-lang.h,
+ d/d-objfile.cc, d/dt.cc: Fix gimplication checking issues in 4.6.x
+ [d3cc96b0546f]
+
+ * d/d-codegen.cc: Issue #220 - Segfault on nested mixin functions.
+ [c3720dd1e4f6]
+
+ * d/patches/patch-gcc-4.6.x: Issue #218 - segmentation fault when
+ compiling Hello World.
+ [07bb061b2e4b]
+
+2011-07-28 Daniel Green <venix1@gmail.com>
+
+ * d/d-glue.cc: Backout untested solution to issue #217.
+ [fd532d8a5181]
+
+ * d/d-glue.cc, d/setup-gcc.sh: Fixes issue #219
+ [949ab1610a42]
+
+ * d/setup-gcc.sh: Updated -hg to reflect working directory revision
+ and handle compiling outside a mercurial repository.
+ [b3b60fdac583]
+
+2011-07-24 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/GDC.html, d/README, d/gdc-version: GDC version 0.30
+ [a4f3d0470b7a]
+
+ * d/Make-lang.in, d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc,
+ d/d-lang.cc, d/patches/patch-gcc-4.2.x, d/patches/patch-gcc-4.3.x,
+ d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x,
+ d/patches/patch-gcc-4.6.x, d/symbol.cc d/symbol.h: Re-implemented D
+ custom static chains into frontend - removed all belated backend
+ patches.
+ [488e8c0f482f]
+
+ * d/Make-lang.in, d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc,
+ d/d-codegen.h, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc,
+ d/d-objfile.h, d/dmd2/*, d/druntime/*, d/phobos2/*: Updated D2
+ Frontend to 2.054
+ [ca958eccbde0]
+
+ * d/Make-lang.in, d/asmstmt.cc, d/d-builtins.c, d/d-builtins2.cc,
+ d/d-codegen.cc, d/d-codegen.h, d/d-convert.cc, d/d-decls.cc,
+ d/d-glue.cc, d/d-irstate.cc, d/dmd/*, d/phobos/*: Updated D1 Frontend
+ to 1.069
+ [c77c7af3dda0]
+
+2011-07-11 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-glue.cc, d/d-lang.h: Debug fixes: Give AAs a
+ TYPE_NAME. Make closure vars visible to the debugger.
+ [7cb42bd4eb94]
+
+2011-07-09 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-asm-i386.h: Issue #213 - ASM: Invalid absolute jmp/call address
+ [e01697578501]
+
+ * d/d-asm-i386.h, d/d-glue.cc, d/d-lang.cc: Asm 32/64bit generation
+ fixes.
+ [0a2261bde3e1]
+
+ * d/d-codegen.h, d/d-decls.cc, d/d-lang.h, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x, d/patches/patch-gcc-4.6.x: Use
+ TREE_NO_TRAMPOLINE macro - remove redundant patches.
+ [b79169244c60]
+
+2011-07-04 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in: Fixes executable relocation issues with MinGW.
+ [c272d49246c9]
+
+ * d/d-decls.cc: Always mark struct/class members for inlining.
+ [61c81c98d80c]
+
+2011-06-30 Daniel Green <venix1@gmail.com>
+
+ * d/d-asm-i386.h: Fixes issue #213.
+ [71737ec293cb]
+
+2011-06-20 Daniel Green <venix1@gmail.com>
+
+ * d/phobos/internal/gc/win32.d, d/phobos/std/stream.d: Win64 support
+ for Phobos/D1.
+ [b2b0dae5dec2]
+
+ * d/Make-lang.in, d/dmd/root.c: Enables ANSI implemention of MinGW
+ stdio.
+ [fd0f112bfca8]
+
+ * d/dmd-script: Added the ability to specify the name of output map
+ file. Undocumented DMD feature.
+ [d36a8b0e175]
+
+2011-06-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-glue.cc, d/d-objfile.cc, d/dmd2/arrayop.c,
+ d/druntime/core/stdc/math.d, d/phobos2/gcc/deh.d: Issue #212 - ICE
+ With Map, dotProduct
+ [f333a7e70d3d]
+
+2011-06-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h,
+ d/d-decls.cc, d/d-glue.cc, d/dmd2/*, d/druntime/*, d/phobos2/*:
+ Updated D2 Frontend to 2.053
+ [89eccdc0155e]
+
+ * d/d-decls.cc, d/d-lang-45.h, d/d-lang.h, d/d-objfile.cc: gcc-4.6.x -
+ Fix imported static const optimizer bug (D2 now passes testsuite).
+ [9ccc077422a8]
+
+2011-06-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-codegen.cc, d/dmd-script: gcc-4.6.x - -combine
+ removed, re-add d-gcc.o object, fix compilation on ARM.
+ [dd43ade64753]
+
+ * d/d-decls.cc, d/d-objfile.cc, d/patches/patch-gcc-4.6.x: gcc-4.6.x -
+ Fix undefined references to thunks.
+ [6b13c1f980f4]
+
+ * d/d-bi-attrs-40.h, d/d-bi-attrs-41.h: Remove d-bi-attrs.h for 4.0
+ and 4.1
+ [86169933de9c]
+
+2011-06-02 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-bi-attrs-45.h, d/d-lang.cc, d/d-spec.c,
+ d/lang.opt, d/patches/patch-gcc-4.6.x, d/setup-gcc.sh: Fix missing
+ gcc-4.6 driver options, add to setup scripts.
+ [937e3e68e003]
+
+2011-05-31 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/config-lang.in, d/d-builtins.c, d/d-builtins2.cc,
+ d/d-codegen.h, d/d-gcc-real.cc, d/d-glue.cc, d/d-incpath.cc,
+ d/d-lang-45.h, d/d-lang.cc, d/d-spec.c, d/lang.opt,
+ d/patches/patch-gcc-4.6.x, d/patches/patch-toplev-4.6.x: Add gcc-4.6.x
+ support
+ [94fdbcd3ae33]
+
+ * d/Make-lang.in, d/d-bi-attrs-45.h, d/d-builtins.c, d/d-codegen.cc,
+ d/d-codegen.h, d/d-gcc-includes.h, d/d-lang.cc, d/d-lang.h,
+ d/d-objfile.cc, d/druntime/core/stdc/stdarg.d,
+ d/druntime/core/vararg.d, d/patches/patch-gcc-4.0.x,
+ d/patches/patch-gcc-4.1.x, d/patches/patch-toplev-4.0.x,
+ d/patches/patch-toplev-4.1.x, d/phobos/std/c/stdarg.d,
+ d/phobos/std/stdarg.d, d/symbol.h: Drop support for gcc-4.0.x;
+ gcc-4.1.x
+ [75f0bbfbdd5e]
+
+ * d/d-asm-i386.h: Rename cmpxch8b to cmpxchg8b
+ [21128c37d917]
+
+2011-04-29 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc: Issue #203 - ArrayLiteralExp::toElem incorrectly sets
+ TREE_STATIC
+ [584a5f3a7dce]
+
+ * d/druntime/core/stdc/wchar_.d: Use alias to make vswprintf and
+ swprintf match ANSI signature.
+ [344229e36805]
+
+ * d/d-glue.cc: Issue #200 - Optimization breaks condition variables
+ [b805b62dcdc8]
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/d-glue.cc, d/dt.cc: Be less
+ trusting with GCC builtins.
+ [194016d49ca]
+
+2011-04-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-asm-i386.h: Make SSE3 iasm opcodes available for 32bit.
+ [7861f5acdf6b]
+
+ * d/dmd/todt.c, d/dmd2/todt.c: speed up emission of large static array
+ initialisers.
+ [9a840a37e508]
+
+ * d-decls.cc, d/d-glue.cc, d/phobos/configure, d/phobos/configure.in,
+ d/phobos2/Makefile.am, d/phobos2/configure: D1 regression with static
+ array equality testing.
+ [af07c3a2f08c]
+
+2011-04-18 Daniel Green <venix1@gmail.com>
+
+ * d/phobos2/Makefile.in: Added std/c/wcharh.d to list of compiled
+ Windows objects. Required by MinGW's stdio patch
+ [3cf208768d86]
+
+2011-04-17 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-decls.cc, d/druntime/core/thread.d,
+ d/phobos/configure, d/phobos/configure.in, d/phobos2/Makefile.am,
+ d/phobos2/Makefile.in, d/phobos2/configure, d/phobos2/configure.in:
+ Edit configure scripts so cross compilers install imports in gcc
+ version specific runtime directory
+ [8fe76a59ba1e]
+
+ * d/d-builtins2.cc: Issue #192 - ARM Compilation Fails When Including
+ gcc.intrinsics
+ [bf186179001b]
+
+ * d/druntime/core/stdc/stdio.d: Change ctor in cstdio to 'shared
+ static' - should fix Mingw IO in std.stdio
+ [efb1b1ed90d8]
+
+ * d/d-objfile.cc, d/druntime/core/stdc/stdio.d, d/phobos2/Makefile.am,
+ d/phobos2/Makefile.in, d/phobos2/std/stdio.d: Merge Daniel's MinGW
+ work, put special case static ctor in core.stdio
+ [71f10f204790]
+
+2011-04-15 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/dmd/func.c, d/dmd2/func.c: Remove __va_argsave definition from
+ 64bit GDC
+ [997a9ec407fe]
+
+ * testsuite/*: Upload D2 testsuite for GDC.
+ [6e40c9c42f6e]
+
+ * d/d-asm-i386.h, d/d-irstate.cc, d/d-objfile.cc,
+ d/druntime/core/thread.d: 64bit IASM fix, move tls definitions to
+ d-objfile, add _tls_index stub for MinGW.
+ [ff35bec78100]
+
+ * d/d-objfile.cc: Issue #187 - Multiple definition of TypeInfo with
+ MinGW.
+ [d52ae1bf8343]
+
+ * d/d-lang.cc, d/dmd-script, d/druntime/rt/monitor_.d: Uncomment
+ implementations in rt.monitor_ (for MinGW), code cleanups.
+ [1cf36f68d061]
+
+ * d/d-codegen.cc: Issue #189 - sqrt(integer) causes ICE in
+ maybeExpandSpecialCall
+ [d46da356ca46]
+
+ * d/d-incpath.cc: Issue #188 - -J option ignored.
+ [875395c71f37]
+
+ * d/Make-lang.in, d/d-asm-i386.h, d/d-builtins2.cc, d/d-codegen.cc,
+ d/d-glue.cc, d/d-irstate.cc, d/dt.cc: 64bit testsuite fixes - passes
+ all tests 32bit linux passes.
+ [62c8038af25a]
+
+ * d/Make-lang.in, d/d-builtins.c, d/d-decls.cc, d/d-lang-45.h,
+ d/d-lang.cc, d/d-lang.h, d/d-misc.c, d/d-objfile.cc,
+ d/phobos/configure, d/phobos/configure.in, d/phobos2/configure,
+ d/phobos2/configure.in: Remove d-misc.c, fixed code that depended on
+ it.
+ [066ecfe85f1]
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h: Issue #185 -
+ Intrinsics cause ICE on MinGW
+ [c17a1cdfb868]
+
+2011-04-11 Daniel Green <venix1@gmail.com>
+
+ * d/Make-lang.in, d/d-incpath.cc, d/d-lang-45.h, d/d-lang.cc,
+ d/d-lang.h: Added d-incpath.c for handling import paths.
+ [5a55df337408]
+
+ * d/setup-gcc.sh: Added option '-hg' for replacing 'gdc-version' with
+ repository revision.
+ [32ed0cf6d419]
+
+2011-04-09 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-codegen.h: Implement math intrinsics into the
+ compiler.
+ [431f375abaf1]
+
+ * d/d-asm-i386.h, d/druntime/core/atomic.d: More 64bit IASM fixes,
+ favour ASM implementations in core.atomic.
+ [8f5627ca0ba5]
+
+ * d/phobos2/gcc/bitmanip.d: Really remove gcc.bitmanip.
+ [c61617158bd8]
+
+ * d/druntime/core/atomic.d, d/phobos/configure, d/phobos/configure.in,
+ d/phobos2/Makefile.am, d/phobos2/Makefile.in, d/phobos2/configure,
+ d/phobos2/configure.in, d/phobos2/gcc/atomics.d: First stab at
+ gcc.atomics; Remove unused gcc.bitmanip; Add -inline as DFLAG for
+ Phobos
+ [1a74f184e2d8]
+
+2011-04-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-asm-i386.h, d/d-codegen.cc, d/d-glue.cc, d/d-lang.cc,
+ d/d-spec.c: Issue #164 - ICE:fold-const.c:2792.
+ [c42297cf76c3]
+
+ * d/d-asm-i386.h, d/druntime/core/thread.d: 64bit IASM fixes.
+ [406daaa254ad]
+
+ * d/d-builtins2.cc, d/d-glue.cc: Issue #164 - (ICE:fold-const.c:2792)
+ using std.range.zip
+ [437b1cc2f607]
+
+ * d/d-lang.cc, d/phobos/Makefile.am, d/phobos/Makefile.in,
+ d/phobos2/Makefile.am, d/phobos2/Makefile.in: Phobos: Issue #179 -
+ explicitly include zlib directory when building.
+ [37ba91ed454c]
+
+ * d/d-convert.cc: Issue 143: non-determistic FPE in runtime code.
+ [4ea171da4900]
+
+ * d/d-codegen.cc: Issue #178 - ICE in hwi2toli.
+ [9133d6873087]
+
+ * d/Make-lang.in, d/d-codegen.cc: Tidy up Make-lang.in, remove old
+ bits.
+ [1d8b36b4bfb7]
+
+ * d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc, d/d-objfile.cc: Remove
+ old-old workarounds for GCC < 4.0.x
+ [b2ffdbb41245]
+
+ * d/d-gcc-real.cc, d/d-gcc-real.h, d/dmd/cast.c, d/dmd2/cast.c,
+ d/dmd2/expression.c: D2: Fix precision bug in PowExp.
+ [ab7782c68bb5]
+
+ * d/d-codegen.cc, d/d-gcc-real.cc: Don't error when casting from
+ static array -> struct of same type size.
+ [90b0b0208d3f]
+
+2011-03-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-gcc-real.cc, d/d-gcc-real.h: Fix strict-aliasing
+ warning.
+ [79ed94287f94]
+
+2011-03-30 Daniel Green <venix1@gmail.com>
+
+ * d/asmstmt.cc: An unitialized array was forcing GDC to mark all
+ registers as clobbered.
+ [007de89f7694]
+
+2011-03-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-lang.cc: Move cgraph finalize into d_write_global_decls.
+ [b7da3f7426ac]
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.h, d/d-dmd-gcc.h,
+ d/d-gcc-real.h, d/d-irstate.cc, d/d-irstate.h, d/d-objfile.cc,
+ d/d-objfile.h, d/druntime/core/thread.d, d/patches/patch-gcc-4.5.x,
+ d/symbol.h: _tlsstart/_tlsend compiler generated symbols.
+ [d2dfed983fff]
+
+ * d/Make-lang.in, d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.cc,
+ d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h: New
+ d_global_trees array for gcc trees of commonly used D types/decls.
+ [d553b62db8e6]
+
+2011-03-24 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-decls.cc, d/d-glue.cc, d/d-objfile.cc,
+ d/d-objfile.h, d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x: More WIP DMD calling convention - evaluate
+ arguments left to right, pass in reverse order
+ [6949b05e21e4]
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-codegen.cc, d/d-codegen.h,
+ d/d-irstate.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/lang.opt:
+ More WIP - 64bit IASM.
+ [a85a80c8732a]
+
+ * d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x, d/patches/patch-toplev-4.1.x,
+ d/patches/patch-toplev-4.2.x, d/patches/patch-toplev-4.3.x,
+ d/patches/patch-toplev-4.4.x, d/patches/patch-toplev-4.5.x: Switch
+ patches to unified diff.
+ [1738b301128b]
+
+ * d/d-builtins2.cc, d/d-decls.cc, d/d-glue.cc, d/d-objfile.cc,
+ d/d-tree.def, d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x: More WIP DMD calling convention - Add
+ 'optlink' function attribute.
+ [521dce459f71]
+
+2011-03-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc: WIP: Merge
+ make_bool_binop, make_math_op, make_assign_math_op into toElemBin.
+ [886b0a5af18a]
+
+ * d/asmstmt.cc, d/d-asm-i386.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h,
+ d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-convert.cc,
+ d/d-cppmngl.cc, d/d-decls.cc, d/d-glue.cc, d/d-irstate.h,
+ d/d-lang-45.h, d/d-objfile.cc, d/d-spec.c: Use gcc_unreachable instead
+ of abort, cleanup line endings.
+ [3d6a01bd6e93]
+
+2011-03-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-lang.cc, d/d-objfile.cc, d/d-objfile.h, d/symbol.cc, d/symbol.h:
+ Issue #167 - Assembler error: Already defined.
+ [36a609d5155b]
+
+ * d/d-glue.cc: IndexExp: call aaGetp if AA is modifiable.
+ [d69227218b07]
+
+ * d/d-codegen.cc, d/d-objfile.cc: Issue #165: Link failure with
+ templates.
+ [2221d9fb1dd9]
+
+ * d/Make-lang.in, d/d-builtins2.cc, d/d-codegen.cc: Add experimental
+ void* _argptr implementation switch in Makefile.
+ [9a8cbe47da29]
+
+ * d/Make-lang.in, d/d-builtins2.cc, d/d-codegen.cc, d/d-convert.cc,
+ d/d-gcc-real.cc, d/d-glue.cc, d/d-spec.c: Replace calls to
+ fold(build()) with fold_build()
+ [8eab661a9626]
+
+ * d/d-convert.cc: Harden d_truthvalue_conversion, catches scalars
+ passed for conversion by buggy frontend.
+ [ff5142f57beb]
+
+ * d/Make-lang.in, d/d-decls.cc, d/d-glue.cc, d/d-lang.cc: Add
+ experimental DMD calling convention switch in Makefile
+ [c5153f67119a]
+
+ * d/d-bi-attrs-44.h: Update d-bi-attrs-44.h for current 4.4.5 release.
+ [e44747eee585]
+
+ * d/d-glue.cc: Mark used parameters to prevent false warnings from
+ -Wunused-parameter.
+ [f0a6db429617]
+
+2011-03-12 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc: Fix codegen bug in CatAssignExp.
+ [15f72843d336]
+
+ * d/d-builtins2.cc, d/d-codegen.cc, d/d-codegen.h, d/d-glue.cc,
+ d/d-lang.cc, d/d-objfile.cc: IRState::addTypeModifiers - Add D2 type
+ modifiers (const/shared) onto GCC types (const/volatile).
+ [ef3c725214ec]
+
+2011-03-06 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-lang.cc, d/d-spec.c, d/gdc.1, d/lang-specs.h,
+ d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x: Remove lang_specific_spec_functions code.
+ [da7dc4ae6277]
+
+ * d/dmd-script: Issue #161 - noboundscheck doesn't work with GDMD.
+ [9ad16376258f]
+
+2011-02-28 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-decls.cc, d/d-glue.cc, d/d-objfile.cc, d/d-objfile.h,
+ d/dmd/template.c, d/dmd2/template.c, d/symbol.h: Moved GCC code to
+ prevent templates being emitted more than once to the backend.
+ [585920b19963]
+
+ * d/Make-lang.in, d/d-decls.cc, d/d-glue.cc, d/d-lang.h,
+ d/d-objfile.cc: Cleaned up ObjFile::makeDeclOneOnly implementation.
+ [cbad6b2b6b42]
+
+2011-02-25 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-apple-gcc.c, d/d-builtins2.cc, d/d-c-stubs.c, d/d-codegen.cc,
+ d/d-gcc-includes.h, d/d-glue.cc, d/d-lang.cc, d/d-objfile.cc: Remove
+ dependencies on CPP objects.
+ [33967b4ff6e9]
+
+ * d/d-gcc-includes.h, d/patches/patch-apple-gcc-5465,
+ d/patches/patch-apple-gcc-5664, d/patches/patch-gcc-4.0.x,
+ d/patches/patch-gcc-4.1.x, d/patches/patch-gcc-4.2.x,
+ d/patches/patch-gcc-4.3.x, d/patches/patch-gcc-4.4.x,
+ d/patches/patch-gcc-4.5.x: Remove old redundant code.
+ [7b72e8118c29]
+
+ * d/d-spec.c: Handle -pthread option in d-spec.c
+ [b6062a158fdd]
+
+ * d/d-glue.cc, d/phobos2/std/stdio.d, d/target-ver-syms.sh: Issue #151
+ - MinGW-w64: recent GDC does not build w/ recent GCC
+ [978bb5bc82cf]
+
+ * d/druntime/core/sys/posix/sys/un.d, d/phobos2/Makefile.am,
+ d/phobos2/Makefile.in: Remove posix.sys.un from druntime.
+ [bb92ab765845]
+
+2011-02-20 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-builtins2.cc, d/d-lang.cc, d/d-spec.c, d/dmd2/*,
+ d/druntime/*, d/phobos2/*: Updated D2 Frontend to 2.052.
+ [c4980ba67971]
+
+ * d/dmd/*, d/phobos/*: Updated D1 Frontend to 1.067.
+ [343f35cc00c8]
+
+ * d/d-objfile.cc: Put compiler-generated arrayops on comdat.
+ [4d14649603c2]
+
+ * d/d-gcc-includes.h, d/d-glue.cc: use totym to apply D type modifiers
+ on GCC types.
+ [d3b9d3188b68]
+
+ * d/d-decls.cc: Issue #155 - ICE when using byte
+ [7846c6471861]
+
+ * d/d-bi-attrs-43.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h: Remove
+ 'artificial' attribute from GDC.
+ [4b8f90d1f6aa]
+
+ * d/d-codegen.cc, d/d-glue.cc, d/d-irstate.cc, d/d-lang.cc: Conversion
+ fixes for types with GCC attributes applied.
+ [5e733844f91f]
+
+ * d/d-codegen.cc, d/d-codegen.h, d/d-decls.cc, d/d-glue.cc,
+ d/d-objfile.cc, d/druntime/object.di, d/druntime/object_.d,
+ d/druntime/rt/aaA.d, d/phobos/Makefile.am, d/phobos/Makefile.in,
+ d/phobos/gcc/support.d, d/phobos/internal/aaA.d,
+ d/phobos/internal/gc/gc.d, d/phobos2/gcc/support.d: ABI update: New
+ signatures for _d_assocarrayliteralTp, _d_arrayliteralTp and
+ _d_arrayappendcTp
+ [b66226b53e71]
+
+ * d/d-glue.cc: Update make_assign_math_op implementation
+ [8390d07b450e]
+
+ * d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.cc,
+ d/d-gcc-includes.h, d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc,
+ d/d-lang.h, d/d-objfile.cc: Fix cast-qual and unused parameter
+ warnings in glue.
+ [377c4f5505be]
+
+ * d/Make-lang.in, d/d-c-stubs.c, d/d-lang.cc: Drop support for CPP
+ Builtins.
+ [6dc9468f6789]
+
+2011-02-10 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-builtins.c, d/d-builtins2.cc, d/d-lang-45.h, d/d-lang.cc,
+ d/d-lang.h: New function added to langhooks: d_register_builtin_type.
+ [9674e391725f]
+
+ * d/d-bi-attrs-40.h, d/d-bi-attrs-41.h, d/d-bi-attrs-42.h,
+ d/d-bi-attrs-43.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h: Only accept
+ string argument in mode attribute handler.
+ [99764267b71b]
+
+ * d/asmstmt.cc, d/d-builtins2.cc, d/d-codegen.cc, d/d-cppmngl.cc,
+ d/d-decls.cc, d/d-dmd-gcc.h, d/d-glue.cc, d/d-irstate.cc,
+ d/d-objfile.cc, d/d-todt.cc: Remove all references to total.h in glue.
+ [30c8afda4902]
+
+ * d/asmstmt.cc, d/d-apple-gcc.c, d/d-asm-i386.h, d/d-builtins2.cc,
+ d/d-codegen.cc, d/d-cppmngl.cc, d/d-decls.cc, d/d-gcc-real.cc,
+ d/d-glue.cc, d/d-irstate.cc, d/d-lang.cc, d/d-objfile.cc, d/dt.cc:
+ Remove all references to assert.h in glue.
+ [1d176d15d1e8]
+
+2011-02-02 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-bi-attrs-40.h, d/d-bi-attrs-41.h, d/d-bi-attrs-42.h,
+ d/d-bi-attrs-43.h, d/d-bi-attrs-44.h, d/d-bi-attrs-45.h,
+ d/dmd/attrib.c, d/dmd2/attrib.c: Fix mode attribute handler to accept
+ string argument.
+ [4ab9f7b5de07]
+
+2011-01-29 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/druntime/core/stdc/config.d: D2 - import gcc.builtins in
+ core.stdc.config
+ [1e41fd67396c]
+
+ * d/d-codegen.cc, d/d-glue.cc, d/druntime/core/stdc/config.d,
+ d/druntime/core/stdc/stdint.d, d/druntime/core/thread.d,
+ d/druntime/gc/gc.d, d/druntime/gc/gcbits.d, d/druntime/gc/gcx.d,
+ d/druntime/gcstub/gc.d, d/druntime/rt/lifetime.d,
+ d/phobos2/std/intrinsic.d: 64bit TLS/GC fixes. Closes #109, #115.
+ [0c10de583cd3]
+
+2011-01-28 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/Make-lang.in, d/d-codegen.cc, d/dmd/*, d/phobos/*: Updated D1
+ Frontend to 1.066
+ [06b390b6f86b]
+
+ * d/d-codegen.cc, d/d-glue.cc, d/druntime/rt/mars.h,
+ d/phobos/std/c/stdarg.d: Remove redundant checks for Tbit in D1, add
+ __va_argsave_t alias in phobos.
+ [5a4481f10bce]
+
+ * d/Make-lang.in: use new variable (ALL_CXXFLAGS)
+ [a3ec7496100e]
+
+ * d/d-c-stubs.c, d/d-codegen.cc, d/d-codegen.h, d/dmd/root.h,
+ d/dmd2/root.h: Implement frontend std.intrinsics into GDC.
+ [330bd9e6077b]
+
+2011-01-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/asmstmt.cc, d/d-codegen.cc, d/dmd/statement.h, d/dmd2/statement.h:
+ Implemented ExtAsmstatement::toCBuffer.
+ [4163067c9831]
+
+ * d/dmd/arrayop.c, d/dmd/root.c, d/dmd2/arrayop.c, d/dmd2/root.c: Add
+ binary implementation, use it in arrayops.
+ [78358cd41c04]
+
+ * d/dmd2/func.c, d/phobos/std/math.d, d/phobos2/std/intrinsic.d,
+ d/phobos2/std/math.d, d/phobos2/std/string.d: Fix log2 implementation
+ for systems requiring supplement.
+ [961f4dd29944]
+
+2011-01-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc: Pass static chain by reference for functions nested in
+ classes.
+ [e37f417ab86f]
+
+ * d/d-lang-45.h, d/dmd/todt.c, d/dmd2/todt.c: rework todt for GCC.
+ [a15a367a189a]
+
+ * d/druntime/core/sys/posix/config.d,
+ d/druntime/core/sys/posix/sys/stat.d,
+ d/druntime/core/sys/posix/sys/types.d, d/druntime/gc/gcx.d: rework
+ sys.stat struct implementation.
+ [dc8e70a01ccf]
+
+2011-01-13 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-glue.cc, d/d-lang.cc, d/d-lang.h: Improve type names of
+ shared/const/immutable types in debugging.
+ [95990b0754e6]
+
+ * d/d-codegen.cc: Issue #147 - static arrays passed as parameter
+ should be value type.
+ [59c59a459398]
+
+ * d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x: Second fix for
+ Issue #104.
+ [1e4da57f4be4]
+
+2011-01-09 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/dmd/mtype.c, d/dmd2/mtype.c: Issue #134 - Fix 64bit double align.
+ [ab3473b8ee56]
+
+ * d/dmd-script, d/patches/patch-gcc-4.4.x, d/patches/patch-gcc-4.5.x:
+ Remove -fomit-frame-pointer from gdmd, fixes Issue #141
+ [191fd75f1716]
+
+2011-01-06 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-codegen.h, d/d-glue.cc, d/d-objfile.cc, d/lang-specs.h: Compiler
+ segfault when not Object class not defined.
+ [44b6978e5f6c]
+
+ * d/d-builtins2.ca,c d/d-codegen.h, d/d-decls.cc, d/d-glue.cc,
+ d/d-lang.cc, d/dmd/dchar.h, d/dmd/mars.c, d/dmd2/dchar.h: Fix some
+ warnings in d-lang, ICE when object.d is empty.
+ [48827ef72351]
+
+ * d/d-asm-i386.h, d/d-codegen.h: Refs Issue #135 - turn ICE into a
+ temp error.
+ [8f4b7ddb676e]
+
+ * d/d-glue.cc: Call rest_of_type_compilation in toDebug for
+ Record/Union/Enums.
+ [ca79068bcb60]
+
+ * d/druntime/object.di, d/druntime/object_.d: Issue #133 - Segfault On
+ AA Foreach
+ [aba6c8857d64]
+
+ * d/druntime/core/thread.d, d/druntime/gc/gcx.d: Refs #115 - addRoot
+ for each call for malloc in the GC.
+ [3721c1dc5aad]
+
+ * d/phobos2/Makefile.am, d/phobos2/Makefile.in: D2 - emit templates
+ only for building phobos.
+ [c2b8a3f7c35b]
+
+ * d/d-decls.cc, d/d-objfile.cc: Issue #132 - unresolved symbol with
+ typedef initializers.
+ [69ebdbbcd8c2]
+
+ * d/druntime/core/sys/posix/config.d,
+ d/druntime/core/sys/posix/signal.d,
+ d/druntime/core/sys/posix/sys/stat.d, d/phobos2/std/file.d: Fix struct
+ stat_t implementation for linux.
+ [29c51189bf66]
+
+2011-01-02 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d/d-spec.c: Fix warning messages in d-spec.c.
+ [da4c33277396]
+
+ * d/d-codegen.cc, d/d-glue.cc: Issue #105 - assertion failure
+ comparing structs for equality.
+ [9a212ed12cec]
+
+ * d/d-codegen.cc: Fix some diagnostic messages.
+ [1447423e541a]
+
+ * d/d-convert.cc: Update d_convert_basic for gcc-4.5
+ [28166c71baad]
+
+ * d/d-builtins.c, d/d-builtins2.cc, d/d-codegen.cc, d/d-decls.cc,
+ d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc:
+ Declare d_build_decl as extern "C". Add function d_build_decl_loc.
+ [29253025adb2]
+
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2012 b/gcc/d/ChangeLog-2012
new file mode 100644
index 0000000..741747b
--- /dev/null
+++ b/gcc/d/ChangeLog-2012
@@ -0,0 +1,857 @@
+2013-02-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (GDC_EXTENDED_ASM_SYNTAX): Remove macro.
+
+2013-02-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.h (D_DECL_IS_CONTRACT): Remove macro.
+ * d-decls.cc (FuncDeclaration::toSymbol): Likewise.
+
+2013-02-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_gcc_is_target_win32): Remove.
+ (d_add_builtin_version): New function to handle define_builtin
+ callback from backend.
+ * d-codegen.cc (IRState::maybeExpandSpecialCall): Remove intrinsic bt.
+
+ * d-builtins.c: Merge with d-builtins2.cc.
+ * d-builtins2.cc: Remove.
+
+2013-02-07 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_init): Use gcc's config system for predefined OS versions.
+ * setup-gcc.sh: Likewise.
+ * target-ver-syms.sh: Likewise.
+
+2013-02-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins2.cc (gcc_type_to_d_type): Remove STRUCTTHISREF condition.
+ * d-decls.cc (FuncDeclaration::toSymbol): Likewise.
+ * d-elem.cc (ThisExp::toElem): Likewise.
+ * d-ctype.cc (TypeSArray::toCtype): Remove SARRAYVALUE condition.
+ * d-codegen.cc (IRState::isDeclarationReferenceType): Likewise.
+ (IRState::isArgumentReferenceType): Likewise.
+
+2013-02-01 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_init): Use gcc's config system for predefined CPU versions.
+ (d_init): Fix definition of D_LP64 version.
+ * setup-gcc.sh: Likewise.
+ * target-ver-syms.sh: Likewise.
+
+2012-12-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Don't optimise PUREconst
+ calls.
+
+2012-10-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::buildAssignOp): Handle case where LHS type is
+ not compatible with expression type.
+
+2012-10-26 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-decls.cc (ClassDeclaration::toSymbol): Use empty RECORD_TYPE to
+ build internal symbol.
+ (Module::toSymbol): Likewise.
+ * d-objfile.cc (outdata): Set type size from constructor if not
+ COMPLETE_TYPE_P. Assert that DECL_INITIAL is never bigger than
+ TYPE_SIZE.
+
+2012-10-25 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::getFrameInfo): Use vthis to determine whether
+ function is nested.
+
+2012-10-21 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins2.cc (gcc_type_to_d_type): Remove special case for
+ double/long double types.
+ (d_gcc_magic_builtins_module): Cleanup generation of builtin types.
+ Add __builtin_unwind_int and __builtin_unwind_uint.
+
+2012-10-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-objfile.cc (ObjectFile::outputThunk): Mark thunk as DECL_WEAK
+ rather than using weakref attribute.
+
+2012-10-14 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-bi-attrs.h: Remove file.
+ * d-builtins.c (d_attribute_table): Define table of machine independant
+ attributes for gcc builtins.
+ (d_format_attribute_table): Define table of format attributes for gcc
+ builtins.
+ (handle_noreturn_attribute, handle_leaf_attribute,
+ handle_const_attribute, handle_malloc_attribute,
+ handle_returns_twice_attribute, handle_pure_attribute,
+ handle_novops_attribute, get_nonnull_operand,
+ handle_nonnull_attribute, handle_nothrow_attribute,
+ handle_sentinel_attribute, handle_type_generic_attribute,
+ handle_fnspec_attribute, handle_transaction_pure_attribute,
+ ignore_attribute): Moved common attribute handlers from d-bi-attrs.h.
+ * d-lang.cc (LANG_HOOKS_ATTRIBUTE_TABLE): Use instead of
+ LANG_HOOKS_COMMON_ATTRIBUTE_TABLE.
+ (d_attribute_table): Renamed from d_common_attribute_table.
+ (d_format_attribute_table): Renamed from
+ d_common_format_attribute_table.
+ (d_init_ts): Renamed from d_common_init_ts.
+
+ * d-builtins2.cc (d_bi_init): Determine D frontend type for size_t.
+ * d-objfile.cc (ObjectFile::hasModule): Remove old compatibility
+ macros.
+
+2012-10-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc (VectorExp::toElem): Handle non-constant array literals as
+ vector expressions.
+
+2012-10-04 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc (VectorExp::toElem): Handle both array literal as well as
+ single element constructors for vector expressions.
+
+2012-09-27 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-convert.cc (convert): Remove assert.
+
+2012-09-22 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::maybeCompound): Use IRState::compound.
+ (IRState::maybeVoidCompound): Use IRState::voidCompound.
+ (IRState::call): Check TREE_SIDE_EFFECTS to determine order of
+ evaluation in function calls. Evaluate callee before arguments if has
+ side effects.
+ * d-decls.cc (FuncDeclaration::toSymbol): Don't set any pure/nothrow
+ attributes if asserts are generated in code.
+ * d-incpath (add_fileimp_path): Fix ICE using -J option.
+ * d-objfile.cc (Obj::moduleinfo): Clean-up.
+
+2012-09-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-lang.cc (d_initialize_diagnostics): New function, disable unneeded
+ diagnostic options.
+ (d_handle_option): Remove OPT_fdebug_c.
+ * d-spec.c (lang_specific_driver): Remove OPT_fod_, OPT_fop.
+ * lang.opt: Remove -fdebug-c, -fod, and -fop compiler options.
+
+2012-09-17 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.h (CtorEltMaker::cons): Adjust call to VEC_safe_push.
+ * d-objfile.cc (ObjectFile::stripVarDecl): Clean-up.
+
+2012-09-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::isCallByAlias): New function.
+ (IRState::call): Use IRState::isCallByAlias.
+ * d-objfile.cc (ObjectFile::setupSymbolStorage): Mark
+ force_static_public symbols as public.
+
+ * d-spec.c (lang_specific_driver): Update for GCC-4.8.
+ * lang.opt: Fix spelling of option -static-libphobos
+
+ * d-codegen.cc (IRState::maybeExpandSpecialCall): Do not handle inp*
+ and outp* port intrinsic functions.
+ (IRState::maybeSetUpBuiltin): Likewise.
+ (IRState::expandPortIntrinsic): Remove.
+
+2012-09-10 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (AggLayout::doFields): Propagate volatile out of type.
+ (AggLayout::addField): Likewise.
+ * d-decls.cc (VarDeclaration::toSymbol): Likewise.
+
+2012-09-06 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.h (IRState::vconvert): Don't use VIEW_CONVERT_EXPR.
+ * d-glue.cc (TypeEnum::toCtype): Mark TYPE_PACKED if flag_short_enums.
+ (TypeClass::toCtype): Mark TREE_ADDRESSABLE to ensure class is always
+ passed in memory.
+
+ * d-tree.def (UNSIGNED_RSHIFT_EXPR): Define new tree expression.
+ (FLOAT_MOD_EXPR): Define new tree expression.
+ * d-lang.cc (d_common_init_ts): New function.
+ (d_write_global_declarations): Call check_global_declarations after
+ finalize_compilation_unit.
+ (d_gimplify_expr): Handle UNSIGNED_RSHIFT_EXPR, IASM_EXPR.
+ * d-codegen.cc (IRState::arrayOpNotImplemented): New function.
+ (IRState::buildOp): New function.
+ (IRState::buildAssignOp): New function.
+ * d-glue.cc (build_bool_binop): Remove function, mostly move to
+ CmpExp::toElem.
+ (build_math_op): Remove function, mostly move to IRState::buildOp.
+ (build_assign_math_op): Remove function, mostly move to
+ IRState::buildAssignOp.
+ (BinExp::toElemBin): Remove function.
+ (IdentityExp::toElem, EqualExp::toElem, CmpExp::toElem)
+ (AndAndExp::toElem, OrOrExp::toElem): Clean-up, use IRState::boolOp.
+ (XorExp::toElem, OrExp::toElem, AndExp::toElem, UshrExp::toElem)
+ (ShrExp::toElem, ShlExp::toElem, ModExp::toElem, DivExp::toElem)
+ (MulExp::toElem, MinExp::toElem, AddExp::toElem):Use
+ IRState::arrayOpNotImplemented, IRState::buildOp.
+ (XorAssignExp::toElem, OrAssignExp::toElem, AndAssignExp::toElem)
+ (UshrAssignExp::toElem, ShrAssignExp::toElem, ShlAssignExp::toElem)
+ (ModAssignExp::toElem, DivAssignExp::toElem, MulAssignExp::toElem)
+ (MinAssignExp::toElem, AddAssignExp::toElem): Use
+ IRState::arrayOpNotImplemented, IRState::buildAssignOp.
+
+ * d-codegen.cc (libcall_ids): Remove _adCmpChar.
+ (IRState::getLibCallDecl): Remove LIBCALL_ADCMPCHAR.
+ * d-glue.cc (CmpExp::toElem): Don't call LIBCALL_ADCMPCHAR.
+
+ * lang.opt: Define Wcast-result.
+ * d-codegen.cc (IRState::convertTo): Warn about null result, but only
+ if -Wcast-result.
+ (IRState::hwi2toli): Move to header.
+ (IRState::realPart): Likewise.
+ (IRState::imagPart): Likewise.
+ (IRState::toElemLvalue): Clean-up tree args array.
+ (IRState::doArraySet): New function.
+ (IRState::arraySetExpr): New function.
+ * d-glue.cc (EqualExp::toElem): Clean-up tree args array.
+ (CatAssignExp::toElem): Likewise.
+ (AssignExp::toElem): Likewise.
+ (DeleteExp::toElem): Likewise.
+ (NewExp::toElem): Use IRState::modify.
+ (ArrayLiteralExp::toElem): Don't call ARRAYLITERALTX library function
+ if assigning to static array.
+ (StructLiteralExp::toElem): Use IRState::arraySetExpr.
+ (do_array_set): Move to IRState::doArraySet.
+ (array_set_expr): Move to IRState::arraySetExpr.
+
+ * d-lang.h (D_TYPE_IMAGINARY_FLOAT): Define.
+ (d_convert_basic): Remove.
+ * d-builtins.c (d_init_builtins): Mark imaginary types as
+ D_TYPE_IMAGINARY_FLOAT.
+ * d-builtins2.cc (gcc_type_to_d_type): Use convert.
+ * d-codegen.cc (IRState::emitLocalVar): Call pushdecl earlier so
+ catches CONST_DECLs.
+ (IRState::convertTo): Remove handling of conversions between
+ imaginary/real, imaginary/complex, complex/imaginary types, use
+ convert.
+ (IRState::convertForArgument): Use convert.
+ (IRState::arrayElemRef): Likewise.
+ (IRState::call): Likewise.
+ (IRState::libCall): Likewise.
+ (IRState::maybeExpandSpecialCall): Likewise.
+ * d-convert.cc (d_convert_basic): Mark static.
+ (convert): Handle correct conversions between imaginary/real,
+ imaginary/complex, complex/imaginary types.
+ * d-glue.cc (InExp::toElem): Use convert.
+ (BoolExp::toElem): Likewise.
+ (FuncDeclaration::buildClosure): Likewise.
+
+ * d-builtins.c (def_fn_type): Use build_varargs_function_type_array and
+ build_function_type_array to create built-in functions.
+ (d_init_builtins): Use lang_hooks.types.type_for_size.
+ * d-builtins2.cc (d_gcc_magic_builtins_module): Use
+ lang_hooks.types.type_for_mode.
+ * d-codegen.cc (IRState::pointerIntSum): Use
+ lang_hooks.types.type_for_size.
+ (IRState::call): Use lang_hooks.types.type_promotes_to.
+ (IRState::maybeExpandSpecialCall): Likewise.
+ * d-glue.cc (build_math_op): Use lang_hooks.types.type_for_mode.
+ * d-lang.cc (d_type_for_mode): Mark static.
+ (d_type_for_size): Likewise.
+ (d_type_promotes_to): Likewise.
+
+2012-08-31 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc (FuncDeclaration::toObjFile): Flatten nested levels and
+ loops in function, delay printing function name in verbose mode until
+ we know the function is being compiled.
+
+ * d-codegen.cc (IRState::buildFrameForFunction): New function.
+ (IRState::buildChain): Use IRState::buildFrameForFunction to get the
+ frame record type.
+ (IRState::getFrameInfo): Likewise.
+ * d-glue.cc (FuncDeclaration::buildClosure): Likewise.
+
+2012-08-30 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * asmstmt.cc (ExtAsmStatement::toCBuffer): Mark unused parameter as
+ ATTRIBUTE_UNUSED.
+ * d-codegen.cc (WrappedExp::toCBuffer): Likewise.
+ * d-objfile.cc (ObjectFile::setupSymbolStorage): Revert to previous
+ behaviour of setting symbol storage.
+
+ * d-codegen.cc (IRState::expandDecl): Use IRState::vinit.
+ (IRState::binding): Likewise.
+ (IRState::var): Handle all declarations, not just vars.
+ * d-glue.cc (PtrExp::toElem): Simplify use of IRState::var.
+ (SymbolExp::toElem ): Likewise.
+ (ThisExp::toElem): Likewise.
+
+ * d-lang.cc (d_init): Remove 'Thumb' identifier for ARM as 16bit
+ platforms aren't supported.
+ (GNU_LongDouble128): Remove identifier as long double size is
+ determined from type information.
+
+ * d-decls.cc (TypeInfoDeclaration::toSymbol): Mark all typeinfo decls
+ as 'used'.
+ * d-glue.cc (one_elem_array): Remove.
+ (CatExp::toElem): Inline use of one_elem_array, clean-up.
+ * d-objfile.cc (ObjectFile::setupSymbolStorage): Update to better
+ handle use of declarations marked with comdat, extern or static.
+ (ObjectFile::doSimpleFunction): Mark function as 'used'.
+ * dt.cc (dt2node): Clean-up indentation.
+
+ * Make-lang.in: Fix issue with cross-compiler configuration.
+
+2012-08-29 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * lang-specs.h: Remove special case for handled D source files.
+ * Make-lang.in: Remove special case for building gcc.o, use
+ GCC_EXTRA_LIBS to link against, rather than specific gcc object files.
+ (D_DRIVER_NAME): Remove use of variable.
+ (D_DRIVER_OBJS): Likewise.
+ (D_COMPILER_NAME): Likewise.
+
+2012-08-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins2.cc (eval_builtin): Use builtin_decl_explicit.
+ * d-codegen.cc (IRState::emitLocalVar): Use warning.
+ (IRState::convertTo): Likewise.
+ (IRState::addressOf): Use IRState::markAddressable.
+ (IRState::markAddressable): New function.
+ (IRState::markUsed): New function.
+ (IRState::markRead): New function.
+ (IRState::maybeExpandSpecialCall): Use builtin_decl_explicit.
+ (IRState::floatMod): Likewise.
+ (IRState::exceptionObject): Likewise.
+ * d-glue.cc (IdentityExp::toElem): Likewise.
+ (EqualExp::toElem): Likewise.
+ (PowExp::toElem): Likewise.
+ (AssignExp::toElem): Likewise.
+ (HaltExp::toElem): Likewise.
+ (ArrayLiteralExp::toElem): Likewise.
+ (FuncDeclaration::toObjFile): Likewise.
+ * d-lang.cc (d_mark_addressable): Remove function.
+ (d_mark_exp_read): Remove function.
+ * d-lang.h (d_warning): Remove macro.
+ (d_built_in_decls): Remove macro.
+ * d-objfile.cc (Obj::includelib): Use warning.
+ (Obj::startaddress): Likewise.
+
+2012-08-22 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-lang.cc (binary): Moved function from frontend.
+ * d-codegen.cc (IRState::extractMethodCallExpr): Update for new C++ VEC
+ template in GCC.
+ * d-bi-attrs.h (parse_optimize_options): Likewise.
+ * d-dmd-gcc.h: Remove ifdef __cplusplus, use GCC_SAFE_DMD.
+ * d-gcc-includes.h: Remove ifdef __cplusplus.
+ * d-lang.h: Likewise.
+ * Make-lang.in: Remove CC and CFLAGS from Makefile, add build rule for
+ new texi man pages.
+ * gdc.texi: New documentation for GDC.
+
+2012-08-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::convertTo): Fix to allow conversion between
+ void* and associative arrays.
+ (IRState::convertForArgument): Use d_convert_basic.
+ (IRState::call): Don't use d_convert_basic, now handled by
+ convertForArgument.
+ * d-gcc-real.cc (real_t::real_t): Increase real type mode to be greater
+ than integer type size to prevent overflow in conversions.
+ * d-glue.cc (CastExp::toElem): Don't get implicit AA type.
+
+2012-08-17 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * dfrontend: Update to D frontend version 2.060
+
+ * d-codegen.cc (libcall_ids): New library functions.
+ (IRState::getLibCallDecl): Implement new library function signatures.
+ * d-codegen.h (LibCall::LIBCALL_NEWITEMT): New enum value.
+ (LibCall::LIBCALL_NEWITEMIT): Likewise.
+ * d-decls.cc (FuncDeclaration::toSymbol): Small readability cleanup.
+ * d-glue.cc (NewExp::toElem): Use new library functions.
+ (StructLiteralExp::toElem): Update for new frontend.
+ (ReturnStatement::toIR): Likewise.
+ * d-incpath.cc (add_import_path): New signature.
+ (add_fileimp_path): Likewise.
+ (add_import_paths): Pass split Strings to helper functions.
+ * d-lang.cc (d_parse_file): Use Obj::init and Obj::term.
+ * d-objfile.cc (objmod): New variable.
+ (Obj::init): New function.
+ (Obj::term): Likewise.
+ (Obj::includelib): Likewise.
+ (Obj::startaddress): Likewise.
+ (Obj::allowZeroSize): Likewise.
+ (Obj::moduleinfo): Likewise.
+ (Obj::export_symbol): Likewise.
+ * symbol.h (Obj): New struct to allow object oriented interface to glue
+ code from frontend.
+
+ * d-builtins2.cc (d_gcc_magic_stdarg_check): Add new va_arg magic
+ function that stores the next value through a passed parameter.
+ Remove workaround for inout signature as va_list is always passed by
+ reference to intrinsic templates.
+ (d_gcc_magic_module): Assign module directly to global IRState.
+ * d-codegen.cc (IRState::builtinsModule): Remove static declaration.
+ (IRState::intrinsicModule): Likewise.
+ (IRState::intrinsicCoreModule): Likewise.
+ (IRState::mathModule): Likewise.
+ (IRState::mathCoreModule): Likewise.
+ (IRState::cstdargTemplateDecl): Likewise.
+ (IRState::cstdargStartTemplateDecl): Likewise.
+ (IRState::varsInScope): Likewise.
+ (IRState::call): Use flag_split_darrays.
+ (IRState::maybeExpandSpecialCall): Clean-up va_start and va_arg
+ implementations.
+ (IRState::maybeSetUpBuiltin): Handle new va_arg function.
+ * d-codegen.h (Intrinsic::INTRINSIC_VA_ARG): New enum definition.
+ (IRState::setBuiltinsModule): Remove.
+ (IRState::setIntrinsicModule): Likewise.
+ (IRState::setMathModule): Likewise.
+ (IRState::setCStdArg): Likewise.
+ * d-glue.cc (CatExp::toElem): Use flag_split_darrays.
+ * d-irstate.cc (IRBase::startFunction): Set varsInScope.
+ * d-lang.cc (d_init_options): Set modules that require special
+ handling.
+ (d_handle_option): Don't handle OPT_fsplit_dynamic_arrays.
+ * lang.opt: fsplit-dynamic-arrays mapped to variable
+ flag_split_darrays.
+
+2012-08-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc (IdentityExp::toElem): Re-order precendence of type
+ checking. Treat static arrays as D arrays in identity comparisons.
+ (EqualExp::toElem): Use adEq2 over built-in memcmp for equality
+ comparisons for static and dynamic arrays.
+ (TypeStruct::toCtype): Remove old platform specific workaround.
+
+ * d-builtins2.cc (bi_lib_list): New decl to hold list of GCC library
+ built-ins.
+ (d_bi_init): Add decls to bi_list_list if recognising built-ins.
+ (d_gcc_magic_builtins_module): Rename built-in type C long to
+ __builtin_clong, built-in type C ulong to __builtin_culong.
+ (d_gcc_magic_libbuiltins_check): New function to assign internal
+ symbol for built-in library functions.
+ (d_gcc_magic_libbuiltins_module): New function to scan modules that
+ contain GCC library built-ins.
+ (d_gcc_magic_module): Search all core.stdc modules for possible GCC
+ library built-ins.
+ * d-codegen.h (IRState::useBuiltins): Remove.
+ * d-lang.cc (d_init_options): Don't set IRState::useBuiltins.
+ (d_handle_option): Likewise.
+ * lang.opt: Re-order D frontend compiler options.
+
+ * d-codegen.cc (IRState::buildChain): Override chainLink and chainFunc
+ for function if static chain is passed via hidden 'this' and no frame
+ is created.
+ (IRState::getFrameInfo): Pass static chain around nested functions in
+ the same way as closures for better performance.
+
+ * d-codegen.cc (libcall_ids): Re-order list in ascii collating order,
+ add new library routines to lookup, rename all non-vararg functions to
+ match DMD ABI implementation.
+ (LibCall): Re-order enum and rename values to match libcall_ids.
+ (IRState::toElemLvalue): Use new LibCall name.
+ (IRState::getLibCallDecl): Update to match current library signatures,
+ add implementation of new library routines.
+ (IRState::maybeSetLibCallDecl): New function to set internal symbol
+ for special D RT library functions.
+ * d-decls.cc (FuncDeclaration::toSymbol): Use
+ IRState::maybeSetLibCallDecl.
+ * d-glue.cc (InExp::toElem): Use new LibCall name.
+ (CatAssignExp::toElem): Likewise.
+ (IndexExp::toElem): Likewise.
+ (DeleteExp::toElem): Likewise.
+ (RemoveExp::toElem): Likewise.
+ (NewExp::toElem): Likewise.
+ (ArrayLiteralExp::toElem): Likewise.
+ (AssocArrayLiteralExp::toElem): Likewise.
+ (NullExp::toElem): Use IRState::convertTo.
+
+ * d-codegen.cc (needs_temp): Remove.
+ (IRState::makeTemp): New function.
+ (IRState::maybeMakeTemp): Re-implement to use isFreeOfSideEffects.
+ (IRState::isFreeOfSideEffects): Re-implement to allow better CSE.
+ (IRState::call): Use IRState::makeTemp.
+
+ * d-builtins2.cc (gcc_type_to_d_type): Use d_convert_basic.
+ * d-codegen.cc (IRState::emitLocalVar): Use IRState::vinit.
+ (IRState::convertTo): New function for tree conversions.
+ (IRState::convertTo): Use IRState::convertTo.
+ (IRState::convertForCondition): Likewise.
+ (IRState::darrayVal): Likewise.
+ (IRState::pointerIntSum): Likewise.
+ (IRState::pointerOffsetOp): Likewise.
+ (IRState::pvoidOkay): Likewise.
+ (IRState::boundsCond): Likewise.
+ * d-convert.cc (convert): New function to be called from C.
+ (d_build_truthvalue_op): Use d_convert_basic.
+ * d-glue.cc (convert): Remove.
+ (build_bool_binop): Use IRState::convertTo.
+ (build_math_op): Likewise.
+ (CmpExp::toElem): Likewise.
+ (PowExp::toElem): Likewise.
+ (do_array_set): Likewise.
+ (AssignExp::toElem): Likewise.
+ (VectorExp::toElem): Likewise.
+ (NotExp::toElem): Likewise.
+ (CallExp::toElem): Likewise.
+ (SymbolExp::toElem): Likewise.
+ * dt.cc (dt2tree_list_of_elems): Use d_convert_basic.
+
+2012-07-26 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-gcc-real.cc (real_t::real_t): Use d_float64 for constructor.
+ (real_t::isConst0): Remove.
+ (real_t::isConst1): Likewise.
+ (real_t::isConst2): Likewise.
+ (real_t::isConstMinus1): Likewise.
+ (real_t::isConstHalf): Likewise.
+ * d-gcc-real.h (longdouble): New typedef for real_t.
+ (ldouble): New template for ldouble conversions.
+ (ld_sprint): New function for ldouble to string formatting.
+ * d-codegen.cc (IRState::hwi2toli): Handle maximum 64bit value case.
+
+2012-07-18 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::delegateVal): Remove ENABLE_CHECKING code.
+ (IRState::objectInstanceMethod): Remove special case to avoid calling
+ DotTypeExp::toElem.
+ * d-glue.cc (CommaExp::toElem): Likewise.
+ (DotTypeExp::toElem): Implement function.
+ (StructLiteralExp::toElem): Assert instead that basetype is a struct.
+ * d-gcc-reah.cc (real_t::real_t): New overload for 'double' type.
+ (real_t::format): Change function type to int, return size of buffer
+ from function.
+ (real_t::formatHex): Likewise.
+ * d-builtins2.cc (d_gcc_magic_stdarg_check): Update signature, remove
+ check for is_c_std_arg.
+ (d_gcc_magic_stdarg_module): Likewise.
+ (d_gcc_magic_module): Remove check for core.vararg.
+ * d-codegen.cc (INTRINSIC_STD_VA_ARG): Remove.
+ (IRState::maybeSetUpBuiltin): Don't handle INTRINSIC_STD_VA_ARG.
+
+2012-07-13 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-decls.cc (Dsymbol::toSymbolX): Remove use of PRIuSIZE format macro.
+ (FuncDeclaration::toThunkSymbol): Likewise.
+
+2012-07-12 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-lang.h (D_DECL_IS_CONTRACT): New macro.
+ * d-decls.cc (FuncDeclaration::toSymbol): Mark in and out contracts as
+ D_DECL_IS_CONTRACT.
+ (FuncDeclaration::toThunkSymbol): D thunks no longer private by
+ design. Alter mangling of thunk symbols to be unique across the entire
+ compilation unit.
+ * d-objfile.cc (ObjectFile::makeDeclOneOnly): Catch public contracts to
+ mark them as one-only.
+ (ObjectFile::outputThunk): Mark weakref thunks as private.
+
+2012-07-10 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * Make-lang.in: Remove unused borrowed objects.
+ * d-builtins2.cc (d_bi_builtin_func): Don't add builtin if
+ -fno-builtin was given.
+ * d-codegen.cc (IRState::emitTemplates): Remove static declaration.
+ (IRState::splitDynArrayVarArgs): Likewise.
+ (IRState::useInlineAsm): Likewise.
+ (IRState::useBuiltins): Likewise.
+ (d_gcc_force_templates): Update to use global gen.
+ * d-codegen.h (emitTemplates): Remove static attribute.
+ (splitDynArrayVarArgs): Likewise.
+ (useBuiltins): Likewise.
+ (useInlineAsm): Remove member.
+ (stdInc): Define new member.
+ * d-incpath.cc (std_inc): Remove global.
+ (add_import_paths): Update function signature.
+ * d-lang.cc (d_init_options): Default splitDynArrayVarArgs to false.
+ (d_init): Update call to add_import_paths.
+ (d_handle_option): Remove OPT_fd_inline_asm, add
+ OPT_fsplit_dynamic_arrays.
+ * lang.opt: Likewise.
+
+2012-07-08 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins2.cc (d_gcc_type_align): Update function signature. Use
+ type align size to determine the known align size of a decl.
+ * d-dmd-gcc.h (d_gcc_type_align): Update function signature.
+ * symbol.h (Symbol): New member, Salignment.
+ * symbol.cc (Symbol::Symbol): Initialise Salignment.
+ * d-decls.cc (VarDeclaration::toSymbol): Set Salignment if there is an
+ alignment in effect on the decl.
+ (AggregateDeclaration::toInitializer): Likewise.
+ * d-objfile.cc (ObjectFile::outputStaticSymbol): Set DECL_ALIGN if
+ Salignment was given for static decl.
+
+2012-07-07 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins2.cc (d_gcc_magic_builtins_module): Add check for
+ DECL_ASSEMBLER_NAME_SET_P when testing for builtins that can be
+ markable as pure in the D frontend.
+
+ * d-codegen.cc (IRState::integerConstant): Hide use of
+ HOST_BITS_PER_WIDE_INT macros.
+ (IRState::hwi2toli): Likewise.
+ (IRState::getTargetSizeConst): Likewise.
+
+ * d-builtins.c (d_global_trees): Move declaration here.
+ (lookup_C_type_name): Rename to lookup_ctype_name.
+ (d_init_builtins): Move set-up of d_global_trees here.
+ (gcc_d_backend_init): Move function from d-glue.cc and refactored.
+ (gcc_d_backend_term): Likewise.
+ * d-builtins2.cc (d_bi_init): Set-up D frontend sizes here.
+ * d-glue.cc (gcc_d_backend_init): Removed.
+ (gcc_d_backend_term): Likewise.
+
+ * d-incpath.cc (add_phobos_versyms): New function to scan
+ phobos-vers-syms file.
+ (register_import_chains): Renamed to add_import_paths.
+ * d-lang.cc (d_init): Call add_phobos_versyms and add_import_paths.
+ (d_parse_int): Don't use strtol to get number from argument string.
+
+ * d-incpath.cc (maybe_fixup_phobos_target): Remove.
+ (register_import_chains): Remove use of maybe_fixup_phobos_target.
+ * d-lang.cc (maybe_fixup_os_versym): Remove
+ (d_init): Remove use of maybe_fixup_os_versym.
+
+ * d-lang.cc (saved_reg_names): Remove.
+ (d_init): Remove use of saved_reg_names.
+ (d_post_options): Likewise.
+
+2012-07-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-glue.cc (StructLiteralExp::toElem): Stop after first assignment for
+ constructors built for union types.
+
+2012-07-01 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * symbol.h (deferredNestedFuncs): Renamed from otherNestedFuncs, use as
+ value type rather than pointer.
+ (thunks): Use as value type rather than pointer.
+ * d-decls.cc (FuncDeclaration::toSymbol): Remove check for
+ deferredNestedFuncs being NULL.
+ (FuncDeclaration::toThunkSymbol): Remove check for thunks being NULL.
+ * d-glue.cc (DelegateExp::toElem): Remove check for deferredNestedFuncs
+ being NULL.
+ (FuncDeclaration::toObjFile): Likewise.
+ * d-objfile.cc (ObjectFile::shouldEmit): Add nested functions to
+ deferredNestedFuncs of their parent function incase parent is actually
+ emitted later in during compilation.
+ * d-builtins2.cc (d_gcc_type_align): Explicit alignment of variables
+ takes precedence over default alignment.
+ * d-gcc-includes.h: Re-order list of includes.
+
+2012-06-26 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::twoFieldType): Use rest_of_decl_compilation.
+ * d-gcc-includes.h: Remove last of poisoned backend headers.
+ * d-glue.cc (FuncDeclaration::toObjFile): Use fprintf for diagnostic
+ message. Use rest_of_decl_compilation directly.
+ (SynchronizedStatement::toIR): Likewise.
+ (TypeFunction::toCtype): Remove old version1 macro.
+ * d-lang.cc (d_parse_file): Remove dependency on backend header. Use
+ fprintf for diagnostic messages.
+ (nametype): Use rest_of_decl_compilation directly.
+ (d_handle_option): Remove version 1 option.
+ * dmd-script: Likewise.
+ * lang.opt: Likewise.
+ * d-objfile.cc (ObjectFile::outputStaticSymbol): Use
+ rest_of_decl_compilation directly.
+ (ObjectFile::declareType): Likewise.
+ (obj_moduleinfo): Likewise.
+ (obj_tlssections): Likewise.
+ (ObjectFile::outputThunk): Implement new method of thunk generation
+ for external symbols using weakref.
+ * d-objfile.h (rodc): Remove.
+
+2012-06-25 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins.c (d_init_builtins): Use build_tree_list to initialise
+ void_list_node.
+ * d-glue.cc (ArrayLiteralExp::toElem): Always generate code for
+ arrayliteralTp.
+ (TypeFunction::toCtype): Chain on void_list_node to the end of the
+ function type parameters. Fixes function signatures in debugging.
+
+2012-06-23 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * Make-lang.in (d_OBJS): Add so IN_GCC_FRONTEND is defined when
+ building gdc sources.
+ * d-builtins.c: Remove poisoned headers.
+ * d-codegen.cc: Likewise.
+ * d-gcc-includes.h: GCC system headers included first, removed
+ internally defined macros and poisoned headers.
+ * d-gcc-tree.h: Use GCC system headers instead of defining tree_node.
+ * d-lang.cc: GCC system headers included first.
+ (pushdecl_top_level): Removed.
+ * d-objfile.cc: Remove poisoned headers.
+ * gdc_alloca.h: Use liberty.h instead of handling include of alloca.
+
+ * d-decls.cc (Dsymbol::toSymbolX): Use snprintf rather than sprintf.
+ (FuncDeclaration::toSymbol): Likewise.
+ * d-gcc-real.cc (real_t::init): Likewise.
+ * symbol.cc (Symbol::Symbol): Use NULL_TREE to initialise tree.
+ (symbol_calloc): Use xstrdup to copy string.
+
+ * Make-lang.in: Remove D language version 1 from build
+ (_GNU_SOURCE): Removed macro from build.
+ (ELFOBJ): Likewise.
+ (D_VA_LIST_TYPE_VOIDPTR): Likewise.
+ * asmstmt.cc (ExtAsmStatement::semantic): Removed use of V2 macro.
+ * d-builtins2.cc (d_gcc_builtin_va_list_d_type): Removed use of
+ D_VA_LIST_TYPE_VOIDPTR macro.
+ (gcc_type_to_d_type): Likewise.
+ (d_gcc_magic_stdarg_check): Likewise.
+ (d_gcc_magic_builtins_module): Removed use of V2 macro, and V1
+ encapsulated code.
+ * d-codegen.cc (IRState::convertTo): Likewise.
+ (IRState::toDArray): Likewise.
+ (IRState::typesCompatible): Likewise.
+ (IRState::arrayBoundsCheck): Likewise.
+ (IRState::assertCall): Likewise.
+ (libcall_ids): Likewise.
+ (IRState::getLibCallDecl): Likewise.
+ (IRState::getFrameForSymbol): Likewise.
+ (IRState::isFuncNestedIn): Likewise.
+ (IRState::buildChain): Likewise.
+ (IRState::getFrameInfo): Likewise.
+ (IRState::getFrameRef): Likewise.
+ (IRState::functionNeedsChain): Likewise.
+ (IRState::startCond): Likewise.
+ (IRState::exitIfFalse): Likewise.
+ (IRState::startCase): Likewise.
+ (IRState::doCase): Likewise.
+ (IRState::endCase): Likewise.
+ * d-decls.cc (VarDeclaration::toSymbol): Likewise
+ (FuncDeclaration::toSymbol): Likewise.
+ * d-glue.cc (CondExp::toElem): Likewise.
+ (build_bool_binop): Likewise.
+ (EqualExp::toElem): Likewise.
+ (CmpExp::toElem): Likewise.
+ (AndAndExp::toElem): Likewise.
+ (OrOrExp::toElem): Likewise.
+ (AssignExp::toElem): Likewise.
+ (CastExp::toElem): Likewise.
+ (CallExp::toElem): Likewise.
+ (AssertExp::toElem): Likewise.
+ (AssocArrayLiteralExp::toElem): Likewise.
+ (StructLiteralExp::toElem): Likewise.
+ (FuncDeclaration::toObjFile): Likewise.
+ (Module::genobjfile): Likewise.
+ (TypeFunction::toCtype): Likewise.
+ (ThrowStatement::toIR): Likewise.
+ (TryCatchStatement::toIR): Likewise.
+ (ReturnStatement::toIR): Likewise.
+ (SwitchStatement::toIR): Likewise.
+ (IfStatement::toIR): Likewise.
+ (ForStatement::toIR): Likewise.
+ (ExpStatement::toIR): Likewise.
+ * d-irstate.cc (IRBase::startFunction): Likewise.
+ * d-lang.cc (d_init_options_struct): Likewise.
+ (d_handle_option): Likewise.
+ (d_parse_file): Likewise.
+
+2012-06-21 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * Make-lang.in: Remove d-asm-i386.h
+ * asmstmt.cc (d_build_asm_stmt): Update signature, use build5.
+ (getFrameRelativeValue): Remove.
+ (d_format_priv_asm_label): Likewise.
+ (d_have_inline_asm): Likewise.
+ (AsmProcessor): Likewise.
+ (AsmStatement::toIR): Update sorry message.
+ * d-codegen.cc (IRState::expandPortIntrinsic): Update call to
+ d_build_asm_stmt.
+ (IRState::doAsm): Likewise.
+ * d-decls.cc (FuncDeclaration::toSymbol): Remove check for inline asm.
+ * d-glue.cc (FuncDeclaration::toObjFile): Likewise.
+ (LabelStatement::toIR): Likewise.
+ * d-lang.cc (VersionCondition::addPredefinedGlobalIdent): Remove D
+ Inline Asm version identifiers.
+ * d-lang.h (d_build_asm_stmt): Update signature.
+
+2012-06-19 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Mark in/out contracts as
+ TREE_PUBLIC to allow calling cross-module.
+ * d-lang.cc (d_parse_file): Update for 2.059.
+
+2012-06-16 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * dfrontend: Merged with DMD 2.059.
+ * d-builtins2.cc (gcc_type_to_d_type): Use new frontend value.
+ * d-codegen.cc (IRState::getLibCallDecl): Fix return type of _aaDelp.
+ (IRState::getVThis): Use frontend provided member to determine if
+ function has nested references.
+ * d-decl.cc (FuncDeclaration::toSymbol): Weakly pure functions don't
+ guarantee no vops.
+ * d-gcc-real.cc (max_float_mode): Remove.
+ (real_t::convert): Catch imaginary types in conversion.
+ * d-glue.cc (EqualExp::toElem): Use memcmp for struct comparisons.
+ (CatAssignExp::toElem): Rework order of logic to allow appending
+ delegates to an array.
+ (DelegateExp::toElem): Implement handling of lambda functions.
+ (FuncExp::toElem): Ditto.
+ (AssocArrayLiteralExp::toElem): Implement handling of AssociativeArray
+ types sent to backend.
+ * d-objfile.cc (lmtab): Remove.
+ (cvtLocToloc_t): Update implementation.
+ (outdata): Now assert that we don't receive error nodes.
+
+2012-06-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Make better use of 'pure' and
+ 'pure const' functions in GCC codegen.
+ * d-bi-attrs.h: Added TM_ATTR* masks.
+ (handle_tm_wrap_attribute, handle_tm_attribute, tm_attr_to_mask,
+ find_tm_attribute): New.
+ (struct d_common_attribute_table): Added transaction* attributes.
+
+2012-06-04 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-objfile.cc (ObjectFile::outputThunk): Output thunks moved back to
+ the frontend, as backend does not emit them for DECL_EXTERNAL functions.
+
+2012-05-29 Daniel Green <venix1@gmail.com>
+
+ * setup-gcc.sh: Add GCC 4.8 to list of supported GCC versions. Patch
+ courtesy of Calrama
+ https://bitbucket.org/goshawk/gdc/issue/345
+
+2012-05-29 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-codegen.cc (IRState::endCase): Remove parameter from function. Use
+ condition type as the SWITCH_EXPR type, rather than use of void.
+ * d-codegen.h (IRState::endCase): Update signature.
+ * d-glue.cc (SwitchStatement::toIR): Update call to endCase.
+
+2012-05-28 Daniel Green <venix1@gmail.com>
+
+ * d-builtins.c (DEF_ATTR_STRING): Define and undefine along with other
+ macros.
+ * d-lang.cc (d_write_global_declartions): Use
+ finalize_compilation_unit. GCC 2012-04-30
+ * d-objfile.cc (ObjectFile::outputThunk): Use
+ symtab_add_to_same_comdat_group. GCC 2012-04-30
+ * lang.opt: Match help strings for duplicated options.
+
+2012-02-01 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * setup-gcc.sh: Remove -hg option.
+ * dfrontend/func.c (FuncDeclaration::semantic): Remove code adding
+ method to flat list.
+ (FuncDeclaration::semantic3): Re-add here.
+
+2012-01-01 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins2.cc (IRState::buildChain): Don't do nrvo if the
+ variable is put in a closure.
+ * d-glue.cc (FuncDeclaration::buildClosure): Ditto.
+ (ReturnStatement::toIR): Don't call postblit on nrvo returns.
+ (DtorExpStatement::toIR): Don't call destructor if var is returned as
+ the nrvo variable.
+
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2013 b/gcc/d/ChangeLog-2013
new file mode 100644
index 0000000..eeb12c9
--- /dev/null
+++ b/gcc/d/ChangeLog-2013
@@ -0,0 +1,1221 @@
+2013-12-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_two_field_type): Declare builtin types as
+ toplevel declarations.
+ * d-ctype.cc (EnumDeclaration::toDebug): Build type decl in debug code.
+ * d-lang.cc (nametype): Rename to d_nametype.
+
+2013-12-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (EnumDeclaration::toDebug): Don't send array types to
+ rest_of_type_compilation.
+
+2013-12-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.cc (lang_specific_driver): Require linking in library for all
+ files except D interface files.
+ * d-lang.cc (d_write_global_declarations): Call d_finish_compilation.
+ * d-objfile.cc (mark_needed): Mark static.
+ (d_finish_symbol): Don't call mark_needed.
+ (d_finish_function): Likewise.
+ (d_finish_compilation): New function to wrapup all global
+ declarations, mark templates/comdats as needed if required, and start
+ the final compilation.
+
+2013-12-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-ctype.cc (TypeVector::toCtype): Treat void vectors as ubyte.
+ * d-objfile.cc (VarDeclaration::toObjFile): Gag all errors compiling
+ manifest constants.
+ * d-todt.cc (TypeVector::toDt): New function to generate correct static
+ data for vector initialisers.
+
+2013-12-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init_options_struct): Don't define strict aliasing.
+ (d_get_alias_set): New function to return language-specific alias set.
+ * d-convert.cc (d_convert_basic): Always zero extend pointer to integer
+ conversions.
+
+2013-12-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (maybe_set_builtin_frontend): Assert that all runtime
+ library functions have been set-up correctly.
+ (libcall_ids): Remove unhandled library functions.
+ (get_libcall): Likewise.
+ * d-codegen.h (LibCall): Likewise.
+ * d-objfile.cc (output_symbol_p): Remove.
+
+2013-12-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init_options): Update for frontend changes.
+ (d_handle_option): Set frontend allInst option if -femit-templates.
+ * d-objfile.cc (output_template_p): Want to emit all instantiated
+ templates if -femit-templates or -fdebug was passed to the compiler.
+ * d-objfile.h (TemplateEmission): Define TEallinst.
+ * d-todt.cc (StructDeclaration::toDt): Update for frontend changes.
+ * d-spec.cc (THREAD_LIBRARY): Define default thread library to link if
+ one is not already specified in the configuration process.
+ (TIME_LIBRARY): Define default real time library to link if one is not
+ already specified in the configuration process.
+ (LIBSTDCXX): Define C++ library to link if compiling C++ and D sources.
+ (lang_specific_driver): Update implementation to use new macros.
+
+2013-12-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (CatAssignExp::toElem): Don't call postblit after element
+ append to array.
+ (NewExp::toElem): Handle calling 'new' on opaque types.
+ (ArrayLiteralExp::toElem): Ensure array literal elements have no side
+ effects by making temporaries as necessary.
+ * d-todt.cc (StructLiteralExp::toDt): Update for frontend changes.
+ * d-codegen.cc (build_frame_type): Check for scoped variables if
+ building a closure.
+ * d-objfile.cc (d_finish_symbol): Relax toDt checking rule.
+
+2013-12-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-asmstmt.cc (ExtAsmStatement::ExtAsmStatement): Remove labels
+ member from class.
+ * d-codegen.cc (d_gcc_force_templates): Remove.
+ (convert_expr): Update for frontend changes.
+ (convert_for_assignment): Likewise.
+ (maybe_set_builtin_frontend): Update for changes to libdruntime
+ core.bitops signatures.
+ * d-ctype.cc (TypeFunction::toCtype): Update for frontend changes.
+ * d-decls.cc (Dsymbol::toSymbolX): Likewise.
+ (VarDeclaration::toSymbol): Likewise.
+ (FuncDeclaration::toSymbol): Don't defer nested functions here.
+ * d-elem.cc (PowAssignExp::toElem): Update for frontend changes.
+ (DeleteExp::toElem): Likewise.
+ (AssertExp::toElem): Don't call invariant on an extern C++ class.
+ * d-glue.cc (Global::init): Initialise new stdmsg member.
+ * d-lang.cc (d_handle_option): Handle -fdeps switch. Remove TEprivate
+ for -femit-templates switch.
+ (genCmain): Update for frontend changes.
+ (d_parse_file): Likewise.
+ * d-longdouble.cc (longdouble::dump): Likewise.
+ * d-objfile.cc (ClassDeclaration::toObjFile): Update for frontend
+ changes.
+ (InterfaceDeclaration::toObjFile): Likewise.
+ (EnumDeclaration::toObjFile): Likewise.
+ (Symbol::Symbol): Remove outputSymbol member.
+ (output_symbol_p): Mark static.
+ (output_declaration_p): Determine symbol codegen status from
+ semanticRun.
+ (output_template_p): New function to determine whether an instantiated
+ template is to be written to object file.
+ (FuncDeclaration::toObjFile): Use semanticRun to update codegen status
+ of function.
+ (FuncDeclaration::buildClosure): Error if putting a scoped variable in
+ a closure.
+ (Module::genobjfile): Update for frontend changes.
+ (d_comdat_linkage): Don't determine linkage from TE setting. Mark all
+ comdat symbols as DECL_COMDAT.
+ (setup_symbol_storage): Use output_template_p to determine whether the
+ symbol is being written to object file.
+ (mark_needed): New function to mark decls that must be emitted.
+ (d_finish_symbol): Mark finished symbols as needed.
+ (d_finish_function): Mark finished functions as needed.
+ (build_simple_function): Set semanticRun for glue changes.
+ * d-objfile.h (OutputStage): Remove enum.
+ * d-todt.cc (build_vptr_monitor): Update for frontend changes.
+ (StructInitializer::toDt): Likewise.
+ (StructDeclaration::toDt): Likewise.
+ (TypeInfoEnumDeclaration::toDt): Likewise.
+ (TypeInfoStructDeclaration::toDt): Likewise.
+ (Type::getTypeInfo): Likewise.
+
+2013-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (genCmain): Implement code generation of __entrypoint
+ module to provide the target C main function.
+ (deps_write): Ignore the module __entrypoint when writing make deps.
+ (d_parse_file): Handle writing __entrypoint module to object file.
+ * d-objfile.cc (d_finish_symbol): Remove special handling of _tlsstart
+ symbol, but ensure _tlsend gets written to the thread common section.
+ (d_finish_function): Remove call to build_tlssections.
+ (build_tlssections): Remove.
+
+2013-11-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (ClassDeclaration::toVtblSymbol): Use TypeSArray::makeType
+ to generate frontend static array type.
+ * d-glue.cc (Dsymbol::ungagSpeculative): Define.
+ * d-lang.cc (genCmain): Define as empty.
+ (d_parse_file): Update for frontend changes.
+ * d-objfile.cc (StructDeclaration::toObjFile): Likewise.
+ * d-typinf.cc (TypeBasic::builtinTypeInfo): Likewise.
+ * d-longdouble.cc (longdouble::isIdenticalTo): Remove.
+ * d-port.cc (Port::fequal): Define.
+
+2013-11-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (gcc_type_to_d_type): Use TypeSArray::makeType to
+ generate frontend static array types.
+ * d-codegen.cc (build_attributes): Use optimize as don't want the
+ ctfeInterpret of TypeExp expressions.
+ (get_object_method): Update for frontend changes.
+ (get_libcall): Update to use Type::dtypeinfo.
+ * d-elem.cc (IndexExp::toElem): Don't generate bounds checking codegen
+ if frontend explictly requests it.
+ (ArrayLiteralExp::toElem): Use TypeSArray::makeType to generate
+ frontend static array type.
+ (StructLiteralExp::toElem): Update for frontend changes.
+ * d-glue.cc (Global::increaseErrorCount): Define.
+ * d-objfile.cc (Module::genmoduleinfo): Remove moduleinfo 'New'
+ implementation for libdruntime changes.
+ * d-todt.cc (StructLiteralExp::toDt): Literal initialisers override
+ default initialisers.
+ (TypeInfoDeclaration::toDt): Update to use Type::dtypeinfo.
+ (TypeInfoStructDeclaration::toDt): Update for frontend changes.
+ * d-typinf.c (Type::getInternalTypeInfo): Update to use
+ Type::dtypeinfo.
+
+2013-11-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-asmstmt.cc (ExtAsmStatement::comeFromImpl): Define for frontend
+ implementation changes.
+ * d-codegen.cc (get_libcall): Update to use Type::typeinfoclass.
+ * d-codegen.cc (WrappedExp): Define as class.
+ * d-convert.cc (d_convert_basic): Fix format warnings.
+ * d-decls.cc (ModuleInfoDeclaration::toSymbol): Remove.
+ (FuncDeclaration::toSymbol): Use mangleExact to get decl mangle.
+ * d-elem.cc (ClassReferenceExp::toElem): Return reference to class.
+ * d-glue.cc (verror): Fix format warnings.
+ (verrorSupplemental): Likewise.
+ (vwarning): Likewise.
+ (vdeprecation): Likewise.
+ (escapePath): Define for frontend implementation changes.
+ * d-irstate.cc (IRState::getLoopForLabel): Implement breaking on named
+ scope labels in for/while loops.
+ * d-lang.cc (d_handle_option): Add handler for new -fdeps and
+ -fmake-deps options.
+ (d_parse_file): Handle new -fdeps and fmake-deps options.
+ * d-objfile.cc (Dsymbol::toObjFile): Update to use RootObject.
+ (Type::typeinfoclass): Update to use Type::typeinfoclass.
+ (InterfaceDeclaration::toObjFile): Likewise.
+ * d-objfile.h (Symbol): Remove inheritance from Object.
+ * d-todt.cc (TypeInfoStructDeclaration::toDt): Update to use
+ Type::immutableOf.
+
+2013-11-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (gcc_type_to_d_type): Use TREE_INT_CST_LOW macro instead
+ of tree_low_cst.
+ (eval_builtin): Likewise.
+ (gcc_cst_to_d_expr): Use tree_cst_hwi.
+ * d-codegen.cc (tree_to_hwi): Remove call to deleted host_integerp.
+ (maybe_expand_builtin): Use TREE_INT_CST_LOW macro.
+ * d-lang.cc (d_parse_file): Update debug_hooks call for middle-end
+ changes.
+ * d-system.h: Update includes for middle-end changes.
+
+2013-11-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (finish_thunk): Update for conversion of symtab types to
+ a true class hierarchy.
+
+ * d-ctype.cc (TypeClass::toCtype): Fix ABI to emit correct vtable and
+ monitor field names.
+
+ * d-ctype.cc (TypeClass:toCtype): Set TYPE_LANG_SPECIFIC on record as
+ well as reference type.
+ * d-lang.cc (d_classify_record): New langhook to return appropriate
+ class/interface/struct type to the debugger.
+
+2013-10-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (ArrayLiteralExp::toElem): Build empty constructor for zero
+ sized arrays.
+
+2013-10-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (AssignExp::toElem): Optimise assigning array literal to a
+ static array.
+ (ArrayLiteralExp::toElem): Do not allocate static or const array
+ literals on the heap using the GC.
+
+2013-10-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (DEF_FUNCTION_TYPE_8): Define.
+
+2013-10-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (gcc_cst_to_d_expr): Add support for VECTOR_CST to
+ Expression conversion.
+ (d_gcc_paint_type): Add support for painting to/from array literals.
+
+2013-10-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (cvtLocToloc_t): Rename to get_linemap.
+ * d-glue.cc: New source to provide interface for defined globals and
+ error handling called from the front-end.
+
+2013-09-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::call): Rename to d_build_call.
+ (IRState::emitLocalVar): Rename to build_local_var.
+ (IRState::buildAssignOp): Move to BinExp::toElemBin.
+ (IRState::IRState): Remove IRState class.
+ * d-irstate.cc (IRBase::IRBase): Rename to IRState, remove inheritance
+ from Object class.
+ * d-decls.cc (VarDeclaration::toSymbol): Remove redundant CONST_DECL
+ code as VarDeclaration::toObjFile does not emit manifest constants.
+ * d-ctype.cc (TypeEnum::toCtype): Generate CONST_DECLs for enumeration
+ members for correct debugging.
+ * d-objfile.cc (build_type_decl): Use fully qualified type name in
+ debugging code.
+ (VarDeclaration::toObjFile): Emit manifest constant values in debug
+ code generation.
+
+2013-09-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (SliceExp::toElem): Don't build D array for slices that
+ return a static array.
+
+2013-09-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::buildOp): Rename to build_binary_op.
+
+2013-09-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (binfo_for): Rename to build_class_binfo.
+ (intfc_binfo_for): Rename to build_interface_binfo.
+ (ClassDeclaration::toDebug): Move binfo generation into toCtype.
+ * d-lang.cc (pushlevel): Rename to push_binding_level.
+ (poplevel): Rename to pop_binding_level.
+ (global_bindings_p): Rename to d_global_bindings_p, add langhook.
+ (pushdecl): Rename to d_pushdecl, add langhook.
+ (getdecls): Rename to d_getdecls, add langhook.
+ (set_block): Remove function.
+ (insert_block): Remove function.
+ * d-irstate.cc (IRBase::startBindings): Inline set_block here.
+ (IRBase::endBindings): Inline insert_block here.
+
+2013-08-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.c (lang_specific_spec_functions): Remove.
+
+2013-08-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::doArraySet): Rename to IRBase::doArraySet.
+ (IRState::arraySetExpr): Remove function.
+ (IRState::expandDecl): Rename to expand_decl.
+ (IRState::typeinfoReference): Rename to build_typeinfo.
+ (IRState::buildChain): Merge into FuncDeclaration::buildClosure.
+ (IRState::getVThis): Rename to build_vthis.
+ (IRState::maybeExpandSpecialCall): Rename to maybe_expand_builtin.
+ (IRState::toDArray): Rename to d_array_convert.
+
+2013-08-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (convert_expr): Check that the class type the codegen is
+ casting from is a base class of the class type the codegen is casting
+ to, not the other way round.
+
+2013-08-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (ArrayLiteralExp::toElem): Return null for zero length
+ array literals.
+
+2013-08-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (finish_thunk): Don't emit thunks to external symbols as
+ weakref declarations.
+ * d-codegen.cc (IRState::maybeExpandSpecialCall): Remove intrinsic yl2x
+ and yl2xp1 builtins.
+ (maybe_set_builtin_frontend): Likewise.
+
+2013-07-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (d_gcc_magic_builtins_module): Set builtins solely
+ provided by the compiler as @safe, pure and nothrow.
+ * d-codegen.cc (IRState::getVThis): Don't set outer 'this' of structs
+ to be parent function chain if no frame has been created.
+
+2013-07-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (Expression::toElemDtor): Wrap temp variables destructor
+ calls in a try/finally expression.
+
+2013-07-05 Johannes Pfau <johannespfau@gmail.com>
+
+ * patch-versym-os-4.8.x: Set versions on powerpc and alpha.
+ Remove SysV4 support and therefore fix macro redefinition warnings.
+ * patch-versym-os-4.9.x: Likewise.
+
+2013-07-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-longdouble.cc (longdouble::set): Intepret set values at higher
+ precision for min/max properties.
+ * d-codegen.cc (maybe_set_builtin_frontend): Add yl2x and yl2xp1
+ math intrinsics.
+ (IRState::maybeExpandSpecialCall): Likewise.
+
+2013-07-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (Module::genobjfile): Don't free current_module_info.
+ * d-codegen.cc (IRState::buildAssignOp): Don't create a SAVE_EXPR
+ around comma expressions used as lvalues.
+ * d-todt.cc (TypeSArray::toDtElem): Get underlying vector basetype when
+ layouting out data in a static array.
+
+2013-06-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * complex_t.h: Move into dfrontend.
+ * d-builtins.c (gcc_cst_to_d_expr): Explicitly create longdouble.
+ * d-longdouble.cc (longdouble::parse): Remove function.
+ (longdouble::longdouble): Remove constructors from longdouble.
+ Replaced with operator= template and longdouble::set.
+ (longdouble::rv): Update for new class layout.
+ (longdouble::from_shwi): New function to create a longdouble value
+ from a HOST_WIDE_INT.
+ (longdouble::from_uhwi): Likewise, but from an unsigned HOST_WIDE_INT.
+ (longdouble::to_shwi): New function to return a HOST_WIDE_INT value
+ from a longdouble.
+ (longdouble::to_uhwi): Likewise, but from an unsigedn HOST_WIDE_INT.
+ (longdouble::set): New function to explicitly set longdouble value.
+ (longdouble::toInt): Remove function.
+ (longdouble::isZero): Remove function.
+ (longdouble::isNegative): Remove function.
+ * d-port.cc (Port::nan): Rename to Port::ldbl_nan.
+ (Port::infinity): Rename to Port::ldbl_infinity.
+ (Port::ldbl_max): New static field.
+ (Port::init): Set ldbl_max to be maximimum value for long double type.
+ (Port::strtof): New function to convert string to longdouble.
+ (Port::strtod): Likewise.
+ (Port::strtold): Likewise.
+
+2013-06-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (make_alias_for_thunk): Do not set
+ TREE_SYMBOL_REFERENCED.
+
+2013-06-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_struct_memcmp): New function.
+ * d-elem.cc (IdentityExp::toElem): Use build_struct_memcmp for field
+ comparisons of small structs.
+
+2013-06-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (make_temp): New function.
+ * d-decls.cc (StructLiteralExp::toSymbol): Implement correctly to
+ generate an anonymous symbol to reference to in the codegen.
+ (ClassReferenceExp::toSymbol): Likewise, but also use an anonymous
+ type as size is not determined until the data has been layed out.
+ * d-elem.cc (EqualExp::toElem): Optimise comparisons of arrays of basic
+ types, also ensure left-to-right evaluation.
+ (SliceExp::toElem): Handle returing slice as a static array type.
+ (AddrExp::toElem): Handle taking the address of StructLiteralExp and
+ ClassReferenceExp symbols.
+ (FuncExp::toElem): Relax type checking to allow returning function
+ addresses as generic pointer types.
+ (ArrayLiteralExp::toElem): Implicitly convert static arrays of void to
+ static arrays of ubyte.
+ (StructLiteralExp::toElem): Remove code generation of postblit calls,
+ now taken care of in the front end.
+ * d-objfile.cc (Module::genmoduleinfo): Emit module name as a null
+ terminated static array.
+ * d-ctype.cc (TypeAArray::toCtype): Pass AA types around like pointers.
+
+2013-06-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dfrontend: Update to D front-end version 2.063.
+
+ * d-builtins.c (gcc_type_to_d_type): Use Loc for unknown locations.
+ (d_gcc_magic_builtins_module): Likewise.
+ (gcc_cst_to_d_expr): Likewise.
+ * d-codegen.cc (get_libcall): Use FuncDeclaration::genCfunc to build
+ D runtime library functions.
+ * d-decl.cc (SymbolDeclaration::SymbolDeclaration): Remove function.
+ (StructLiteralExp::toSymbol): New function.
+ (ClassReferenceExp::toSymbol): New function.
+ * d-elem.cc (AssertExp::toElem): Call struct/class invariants only if
+ compiler is generating invariant code.
+ (TupleExp::toElem): Update for new front-end.
+ (ClassReferenceExp::toElem): New function.
+ * d-lang.cc (d_init_options): Set compiler.vendor front-end parameter.
+ (d_init): Call Expression::init.
+ * d-objfile.cc (InterfaceDeclaration::toObjFile): Correctly set the
+ xgetRTInfo field in the record layout.
+ * d-todt.cc (CastExp::toDt): New function.
+ (AddrExp::toDt): New function.
+ (ClassReferenceExp::toDt): New function.
+ (ClassReferenceExp::toDtI): New function.
+ (ClassReferenceExp::toInstanceDt): New function.
+ (ClassReferenceExp::toDt2): New function.
+
+2013-06-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (FuncDeclaration::toObjFile): Set 'this' parameter as
+ implicitly read-only.
+ * d-codegen.cc (declaration_type): Set 'this' declaration type as
+ implicitly const.
+ (build_frame_type): Set frame or closure type as implicitly const.
+
+2013-06-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (d_init_builtins): Make d_unknown_type_node a
+ RECORD_TYPE.
+ * d-lang.cc (d_build_eh_type_type): Cast the returned typeinfo decl to
+ void pointer type.
+
+2013-06-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::var): Rename to get_decl_tree.
+ (IRState::convertForArgument): Rename to convert_for_argument.
+ (IRState::floatMod): Rename to build_float_modulus.
+ (IRState::findThis): Rename to find_this_tree.
+ (IRState::emitLocalVar): Update signature.
+ (IRState::arrayElemRef): Remove function.
+ * d-elem.cc (IndexExp::toElem): Move implementation of
+ IRState::arrayElemRef here.
+
+2013-06-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (cmodule): Rename to current_module_decl.
+ (object_file): Remove variable.
+ * d-objfile.cc (ObjectFile::moduleInfo): Rename to current_module_info.
+ (ObjectFile::modules): Rename to output_modules.
+ (ObjectFile::staticCtorList): Rename to static_ctor_list.
+ (ObjectFile::staticDtorList): Rename to static_dtor_list.
+ (ObjectFile::emitTemplates): Rename to flag_emit_templates.
+ (ObjectFile::beginModule): Remove function.
+ (ObjectFile::endModule): Remove function.
+ (ObjectFile::finish): Rename to d_finish_module.
+ (ObjectFile::doLineNote): Remove function.
+ (ObjectFile::setLoc): Rename to set_input_location.
+ (ObjectFile::setDeclLoc): Rename to set_decl_location.
+ (ObjectFile::setCfunEndLoc): Rename to set_function_end_locus.
+ (ObjectFile::giveDeclUniqueName): Rename to get_unique_name.
+ (ObjectFile::setupSymbolStorage): Rename to setup_symbol_storage.
+ (ObjectFile::setupStaticStorage): Remove function.
+ (ObjectFile::makeDeclOneOnly): Rename to d_comdat_linkage.
+ (ObjectFile::outputStaticSymbol): Rename to d_finish_symbol.
+ (ObjectFile::outputFunction): Rename to d_finish_function.
+ (ObjectFile::addAggMethod): Remove function.
+ (ObjectFile::initTypeDecl): Rename to build_type_decl.
+ (ObjectFile::declareType): Remove function.
+ (ObjectFile::shouldEmit): Rename to output_declaration_p.
+ (ObjectFile::shouldEmit): Rename variant to output_symbol_p.
+ (ObjectFile::doThunk): Rename to use_thunk.
+ (ObjectFile::stripVarDecl): Remove function.
+ (ObjectFile::doSimpleFunction): Rename to build_simple_function.
+ (ObjectFile::doFunctionToCallFunctions): Rename to
+ build_call_function.
+ (ObjectFile::doCtorFunction): Rename to build_ctor_function.
+ (ObjectFile::doDtorFunction): Rename to build_dtor_function.
+ (ObjectFile::doUnittestFunction): Rename to build_unittest_function.
+ (ObjectFile::hasModule): Rename to output_module_p.
+ (ObjectFile::outputThunk): Rename to finish_thunk.
+ (write_deferred_thunks): New function to emit deferred thunks.
+
+2013-06-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (VarDeclaration::toSymbol): Don't set default tls model.
+ * d-objfile.cc (ObjectFile::setupSymbolStorage): Set default tls
+ model for var decls before determining whether symbol is public.
+ (build_tlssections): Likewise for TLS symbols.
+
+2013-06-01 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-codegen.cc (maybe_set_builtin_frontend): Check parameter and
+ return types of intrinsics.
+
+2013-06-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::var): Handle variables used for NRVO.
+ * d-ir.cc (ReturnStatement::toIR): Return result decl directly if NRVO.
+ * d-objfile.cc (Symbol::SnamedResult): New member to hold the named
+ RESULT_DECL of the function.
+ (FuncDeclaration::toObjFile): Set-up function for NRVO.
+ (build_tlssections): Align _tlsstart and _tlsend symbols to target
+ address size.
+ * d-ctype.cc (TypeFunction::toSymbol): Mark functions returning non-POD
+ structs as TREE_ADDRESSABLE to force return in memory.
+ * d-decls.cc (FuncDeclaration::toSymbol): Propagate TREE_ADDRESSABLE
+ from the original function type.
+
+2013-05-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc: New source file to handle Target structure.
+
+ * d-builtins.c (d_bi_init): Remove function.
+ (d_gcc_type_align): Move to Target::alignsize.
+ (d_gcc_field_align): Move to Target::fieldalign.
+ (d_init_builtins): Build va_list type for D frontend.
+ * d-lang.cc (d_init): Use isLP64 to determine LP64 targets.
+ (d_add_builtin_version): Set is64bit if target is X86_64.
+ * d-codegen.cc (convert_for_assignment): Use memset to implement front
+ end code (struct = 0) here, rather than build an empty constructor.
+ * d-elem.cc (AssignExp::toElem): Remove handling of (struct = 0) and
+ call convert_for_assignment.
+
+2013-05-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-gcc-complex_t.h: Rename to complex_t.h.
+ * d-gcc-real.cc: Rename to d-longdouble.cc.
+ * d-gcc-real.h: Rename to longdouble.h
+ * d-port.cc: New source file to handle Port structure.
+ * gdc_alloca.h: Remove source.
+
+ * d-longdouble.cc (real_t): Rename to longdouble.
+ (longdouble::getnan): Move to Port::nan.
+ (longdouble::getsnan): Move to Port::snan.
+ (longdouble::getinfinity): Move to Port::infinity.
+ (longdouble::isInf): Move to Port::isInfinite.
+ (longdouble::isNan): Move to Port::isNan.
+ (longdouble::isSignallingNan): Move to Port::isSignallingNan.
+ * d-builtins.c (gcc_d_backend_init): Rename to d_backend_init.
+ (gcc_d_backend_term): Rename to d_backend_term.
+ (gcc_type_to_d_type): Don't map 128bit integers to D front end.
+
+ * d-elem.cc (AssignExp::toElem): Remove handling of fillHoles, use
+ memset to implement (struct = 0).
+ (StructLiteralExp::toElem): Handle fillHoles here, creating a
+ temporary var that is zero init'd with memset and returned.
+
+2013-05-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::localVar): Rename to build_local_var.
+ (IRState::exprVar): Rename to create_temporary_var.
+ (IRState::maybeExprvar): Rename to maybe_temporary_var.
+ (IRState::pointerIntSum): Rename to build_array_index.
+ * d-lang.cc (d_handle_target_attribute): New function to handle D
+ target attributes.
+
+2013-05-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-incpath.cc (prefixed_path): Add cpp_GCC_INCLUDE_DIR back in as
+ second method for relocation.
+ * d-elem.cc (IndexExp::toElem): Fix call to _aaGetX as from
+ IRState::toElemLvalue.
+ * d-codegen.cc (IRState::toElemLvalue): Remove function.
+ (IRState::convertForAssignment): Rename to convert_for_assignment.
+ (IRState::convertForCondition): Rename to convert_for_condition.
+ (IRState::checkedIndex): Rename to d_checked_index.
+ (IRState::boundsCond): Rename to d_bounds_condition.
+ (IRState::arrayBoundsCheck): Rename to array_bounds_check.
+ (IRState::assertCall): Rename to d_assert_call.
+ (IRState::doLineNote): Move to irstate.h.
+ * d-irstate.cc (IRBase::getLocalContext): Remove function.
+ * d-decls.cc (VarDeclaration::toSymbol): Build decl lang specific for
+ decl to point back to D front end type.
+ (FuncDeclaration::toSymbol): Likewise.
+
+2013-05-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (AggLayout::finish): Unset TYPE_SIZE before
+ re-calculating.
+ * d-ctype.cc (TypeStruct::toCtype): Don't call decl_attribute on the
+ type twice.
+
+2013-05-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_gcc_dump_source): Remove function.
+ (d_post_options): Set flag_excess_precision_cmd as standard.
+ * d-gcc-real.cc (real_t::convert): Remove function.
+ (real_t::floatCompare): Remove function.
+ (real_t::operator): Always perform floating point compilation at the
+ precision of the target real mode.
+ * d-todt.cc (dt_last): Remove function.
+ (dtlist_to_tree): Rename to dtvector_to_tree.
+ (dt_cons): Replace TREE_CHAIN implementation for use of CONSTRUCTOR.
+ (dt_chainon): Likewise.
+ (dt_container): Likewise.
+ (dt_container2): Likewise.
+ (StructInitializer::toDt): Likewise.
+ (StructLiteralExp::toDt): Likewise.
+
+2013-05-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::convertTo): Replace with d_convert and
+ convert_expr.
+ (IRState::declContext): Replace with d_decl_context.
+ (IRState::functionNeedsChain): Replace with needs_static_chain.
+ (IRState::label): Replace with d_build_label.
+ (IRState::emitTemplates): Move to ObjectFile.
+ (functionDegenerateClosure): Replace with is_degenerate_closure.
+ (get_object_method): Assert that function is a method.
+ (IRState::startCond): Move to IRBase.
+ (IRState::startElse): Likewise.
+ (IRState::endCond): Likewise.
+ (IRState::startLoop): Likewise.
+ (IRState::continueHere): Likewise.
+ (IRState::setContinueLabel): Likewise.
+ (IRState::exitIfFalse): Likewise.
+ (IRState::endLoop): Likewise.
+ (IRState::startCase): Likewise.
+ (IRState::doCase): Likewise.
+ (IRState::endCase): Likewise.
+ (IRState::continueLoop): Likewise.
+ (IRState::exitLoop): Likewise.
+ (IRState::startTry): Likewise.
+ (IRState::startCatches): Likewise.
+ (IRState::startCatch): Likewise.
+ (IRState::endCatch): Likewise.
+ (IRState::endCatches): Likewise.
+ (IRState::startFinally): Likewise.
+ (IRState::endFinally): Likewise.
+ (IRState::doReturn): Likewise.
+ (IRState::doJump): Likewise.
+ (IRState::pushLabel): Likewise.
+ (IRState::checkSwitchCase): Likewise.
+ (IRState::checkGoto): Likewise.
+ (IRState::checkPreviousGoto): Likewise.
+
+ * d-elem.cc (CatAssignExp::toElem): Call postblit on appending array of
+ structs if required.
+
+2013-05-16 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-incpath.cc (prefixed_path): use cpp_PREFIX instead of
+ cpp_GCC_INCLUDE_DIR for relocation.
+
+2013-05-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::convertForAssignment): Remove use of
+ CtorEltMaker wrapper for vec<constructor_elt, va_gc>.
+ (d_array_value): Likewise.
+ (build_delegate_cst): Likewise.
+ (extract_from_method_call): Likewise.
+ * d-elem.cc (NewExp::toElem): Likewise.
+ (ArrayLiteralExp::toElem): Likewise.
+ (AssocArrayLiteralExp::toElem): Likewise.
+ (StructLiteralExp::toElem): Likewise.
+ (NullExp::toElem): Likewise.
+ (VectorExp::toElem): Likewise.
+ * d-objfile.cc (build_moduleinfo): Likewise.
+ * d-todt.cc (dt_container): Likewise.
+ (dt_container2): Likewise.
+
+ * d-asmstmt.cc (ExtAsmStatement::toIR): Remove use of ListMaker
+ wrapper for tree chaining.
+ * d-builtins.c (d_bi_builtin_func): Likewise.
+ (d_bi_builtin_type): Likewise.
+ (d_gcc_magic_builtins_module): Likewise.
+ (d_gcc_magic_libbuiltins_module): Likewise.
+ * d-codegen.cc (build_attributes): Likewise.
+ (IRState::call): Likewise.
+ (IRState::buildFrameForFunction): Likewise.
+ (AggLayout::doFields): Likewise.
+ (AggLayout::addField): Likewise.
+ * d-ctype.cc (TypeEnum::toCtype): Likewise.
+ (TypeFunction::toCtype): Likewise.
+ * d-todt.cc (dt_container2): Likewise.
+
+ * d-codegen.cc (IRState::getFrameInfo): Replace with get_frameinfo.
+ (IRState::buildFrameForFunction): Replace with build_frame_type.
+ (IRState::isClassNestedInFunction): Replace with d_nested_class.
+ (IRState::isStructNestedInFunction): Replace with d_nested_struct.
+ (IRState::getFrameForFunction): Fold into IRState::getFrameForSymbol.
+ (IRState::getFrameForNestedClass): Likewise.
+ (IRState::getFrameForNestedStruct): Likewise.
+
+2013-05-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::buildFrameForFunction): Also copy the
+ parameters of functions with 'in' contracts to a local frame decl.
+ * d-lang.cc (d_handle_flatten_attribute): New function to handle D
+ flatten attributes.
+
+2013-05-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::chainLink): Remove function.
+ (IRState::chainFunc): Remove function.
+ (IRState::sthis): New member which holds the chain of function.
+ (IRState::buildChain): Update to use new static chain decl.
+ (IRState::getFrameInfo): Likewise.
+ * d-objfile.cc (FuncDeclaration::buildClosure): Likewise.
+ (FuncDeclaration::toObjFile): Default the function static chain decl
+ to null unless vthis is given for the function.
+
+2013-05-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_noinline_attribute): New function to handle D
+ noinline attributes.
+ (d_handle_forceinline_attribute): New function to handle D forceinline
+ attributes.
+ * d-elem.cc (StructLiteralExp::toElem): Return the struct initialiser
+ symbol directly if the tree has already been built.
+ * d-decls.cc (Dsymbol::toSymbolX): Constify the mangling name to use.
+
+2013-05-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-typinf.cc: New file containing type info routines originally in
+ the D Front End.
+
+ * d-todt.cc (dt_last): New helper function to retrieve last node in a
+ dt_t tree list.
+ (dt_cons): New helper function to append nodes to the end of a list.
+ (dt_chainon): New helper function to concatenate two lists together.
+ (dt_container): New helper function to build a ctor from a list.
+ (build_vptr_monitor): New helper function to generate the class
+ vtable, and put out __vptr and __monitor.
+ symbol default values in a class declaration.
+ (dtlist_to_tree): New helper function to convert a dt_t list into a
+ constructor tree.
+ (Type::toDt): Implement routines for new dt_t format.
+ (TypeInfoDeclaration::toDt): Likewise.
+ (Initializer::toDt): Likewise.
+ (Expression::toDt): Likewise.
+ (Declaration::toDt): Likewise.
+
+ * d-objfile.cc (Dsymbol::toObjFile): Update for new dt_t format.
+ (Module::genmoduleinfo): Likewise.
+ (Symbol::Symbol): Moved from symbol.cc
+ (Obj::objmod): Remove abstraction layer.
+ (Obj::moduleinfo): Renamed to build_moduleinfo.
+ (obj_tlssections): Renamed to build_tlssections.
+ (outdata): Renamed to d_finish_symbol.
+ (check_static_sym): Moved into d_finish_symbol.
+
+ * d-codegen.cc (d_gcc_emit_local_variable): Remove.
+
+ * d-decls.cc (Dsymbol::toSymbolX): Update to not call symbol_calloc.
+ (FuncDeclaration::toThunkSymbol): Likewise.
+ (ClassDeclaration::toSymbol): Build type as d_unknown_type_node.
+ (InterfaceDeclaration::toSymbol): Likewise.
+ (Module::toSymbol): Likewise.
+ (ClassDeclaration::toVtblSymbol): Update call to toSymbolX.
+ (AggregateDeclaration::toInitializer): Likewise.
+ (TypedefDeclaration::toInitializer): Likewise.
+ (EnumDeclaration::toInitializer): Likewise.
+
+ * d-ir.cc (CaseStatement::toIR): Don't call static_sym.
+
+ * d-lang.cc (rtlsym): Remove symbol.
+ (D_DECL_READONLY_STATIC): Remove macro.
+ (d_unknown_type_node): New LANG_TYPE node for marking TypeInfo_Class,
+ Interface, and ModuleInfo types that are of a variable size determined
+ at compile time.
+
+ * d-elem.cc (StringExp::toElem): Clean up for new dt_t format.
+
+ * symbol.cc: Remove file.
+
+2013-05-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::getFrameInfo): Don't create a frame/closure
+ for member functions, only required for nested.
+ * d-elem.cc (Expression::toElemDtor): Call dtors in the correct order.
+ (DeclarationExp::toElem): Don't call dtor on static, manifest, or
+ extern symbols upon declaration.
+ (AssignExp::toElem): Only call postblit on lvalues in assignment.
+ (ArrayLiteralExp::toElem): Always generate literals on heap.
+
+2013-05-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (StructLiteralExp::toElem): Return the default initialiser
+ symbol if one exists.
+ * d-builtins.c (d_gcc_magic_libbuiltins_check): Override the function
+ type with the correct built-in function type as defined in backend.
+
+2013-04-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (IdentityExp::toElem): Remove special handling of class,
+ reference and array types.
+
+2013-04-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (maybe_make_temp): Save call expressions so aren't
+ evaluated more than once.
+ (d_has_side_effects): Remove check for exceptional class types.
+
+2013-04-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Harden logic for marking
+ functions pure as in 'has no side effects'.
+
+2013-04-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Push deferred functions to
+ FuncDeclaration::deferred.
+ * d-elem.cc (DelegateExp::toElem): Likewise.
+ (FuncExp::toElem): Likewise.
+ * d-objfile.cc (ObjectFile::shouldEmit): Likewise.
+ (FuncDeclaration::toObjFile): Process all deferred functions in
+ FuncDeclaration::deferred.
+ * symbol.cc (Symbol::deferredNestedFuncs): Remove.
+
+2013-04-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (FuncExp::toElem): Defer function literals and lambdas
+ until parent function has finished processing.
+
+2013-04-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::buildChain): Use __frame decl directly when
+ setting up the function frame.
+ (maybe_set_builtin_frontend): Exit early if symbol has no parent.
+ * d-decls.cc (FuncDeclaration::toSymbol): Defer all nested functions,
+ not just templated instances.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Delay processed deferred
+ nested functions until function has finished being generated.
+ (ObjectFile::shouldEmit): Don't emit nested functions if the parent
+ function hasn't finished processing.
+
+2013-04-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (maybe_set_builtin_frontend): Merged from
+ maybe_set_builtin and maybe_set_libcall.
+ * d-decls.cc (FuncDeclaration::toSymbol): Use
+ maybe_set_builtin_frontend.
+
+2013-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init_options): Default module info emission to on.
+ (d_handle_option): New femit-moduleinfo switch.
+ * d-objfile.cc (Module::genobjfile): Don't emit module if disabled
+ explicitly.
+ * d-builtins.cc (is_intrinsic_module_p): New function to test whether
+ module is core.bitops.
+ (is_math_module_p): New function to test whether module is std.math or
+ core.stdc.math.
+ (is_builtin_va_arg_p): New function to test whether symbol is
+ specially handled va_arg template.
+ (is_builtin_va_start_p): New function to test whether symbol is
+ specially handled va_start template.
+ * d-codegen.cc (IRState::binding): Replace with bind_expr.
+ (IRState::mathModule): Replace with std_math_module.
+ (IRState::mathCoreModule): Replace with core_math_module.
+ (IRState::intrinsicModule): Replace with std_intrinsic_module.
+ (IRState::cstdargTemplateDecl): Replace with va_arg_template.
+ (IRState::stdargTemplateDecl): Replace with va_arg2_template.
+ (IRState::cstdargStartTemplateDecl): Replace with va_start_template.
+ (IRState::getLibCallDecl): Replace with get_libcall.
+ (IRState::maybeSetLibCallDecl): Replace with maybe_set_libcall.
+ (IRState::libCall): Replace with build_libcall.
+ (IRState::maybeSetUpBuiltin): Replace with maybe_set_builtin.
+ (IRState::Intrinsic): Move enum out of IRState.
+
+2013-03-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::darrayPtrRef): Replace with d_array_ptr.
+ (IRState::darrayLenRef): Replace with d_array_length.
+ (IRState::darrayVal): Replace with d_array_value.
+ (IRState::darrayString): Replace with d_array_string.
+ (IRState::arrayLength): Replace with get_array_length.
+ (get_object_method): Remove dependancy on irs parameter.
+ * d-lang.cc (d_init): Use static bool std_inc to determine whether to
+ include standard module paths.
+ (d_post_options): Canonicalize the input filename.
+ (d_parse_file): Correctly catch cases where input file is stdin.
+
+2013-03-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::getFrameInfo) Create a custom static chain for
+ all nested functions.
+ * d-gcc-includes.h: Rename to d-system.h
+
+2013-03-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (d_bi_init): Set REALPAD to be TYPE_PRECISION of
+ long_double_type_node.
+ * d-codegen.cc (IRState::twoFieldType): Replace with
+ build_two_field_type.
+ (IRState::arrayOpNotImplemented): Replace with unhandled_arrayop_p.
+ (IRState::delegateMethodRef): Replace with delegate_method.
+ (IRState::delegateObjectRef): Replace with delegate_object.
+ (IRState::delegateVal): Replace with build_delegate_cst.
+ (IRState::methodCallExpr): Replace with build_method_call.
+ (IRState::extractMethodCallExpr): Replace with
+ extract_from_method_call.
+ (IRState::objectInstanceMethod): Replace with get_object_method.
+ (IRState::twoFieldCtor): Remove.
+ (IRState::call): Assert that if calling a normal FUNCTION_TYPE,
+ 'object' is not set.
+ * d-ctype.cc (TypeDelegate::toCtype): Build a METHOD_TYPE for the .func
+ field type in delegates.
+ * d-lang.h (D_IS_METHOD_CALL_EXPR): Rename to D_METHOD_CALL_EXPR.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Remove assert for chain
+ function.
+
+2013-03-20 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-codegen.cc (IRState::objectInstanceMethod): Recursively check
+ for TOKsuper / TOKdottype. Do not ignore CastExp.
+ * d-elem.cc (IdentityExp::toElem): Ignore padding in bitwise floating
+ point comparisons.
+ * testsuite: Cleanup. Remove invalid tests, adjust tests, etc.
+
+2013-03-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::objectInstanceMethod): Get function pointer
+ off function TREE_TYPE.
+ (build_deref): Handle cases where expression to dereference is an
+ address expression.
+ (modify_expr): New function overload to set return type directly.
+ * d-elem.cc (CatAssignExp::toElem): Use new modify_expr.
+ (AssignExp::toElem): Likewise.
+ * d-decls.cc (FuncDeclaration::toSymbol): Don't build a method type for
+ nested functions / delegates. Just add on the hidden 'this' pointer
+ containing the custom static chain/closure object.
+
+ * d-codegen.cc (GlobalValues): Replace with current_module,
+ current_irs, object_file.
+ (IRState::getFuncType): Replace with get_function_type.
+ (IRState::isCallByAlias): Replace with call_by_alias_p.
+ (IRState::isFuncType): Replace with function_type_p.
+ (IRState::doExp): Remove.
+
+ * d-asmstmt.cc (ExtAsmStatement::syntaxCopy): Use arraySyntaxCopy to
+ copy front end expressions.
+
+ * d-codegen.cc (AssignExp::toElem): Call _d_arrayassign / _d_arrayctor
+ when assigning arrays of structs.
+
+2013-03-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::realPart): Replace with real_part.
+ (IRState::imagPart): Replace with imaginary_part.
+ (IRState::integerConstant): Replace with build_integer_cst.
+ (IRState::floatConstant): Replace with build_float_cst.
+ (IRState::hwi2toli): Replace with cst_to_hwi.
+ (IRState::addressOf): Replace with build_address.
+ (IRState::markAddressable): Replace with d_mark_addressable.
+ (IRState::markUsed): Replace with d_mark_used.
+ (IRState::markRead): Replace with d_mark_read.
+ (IRState::indirect): Replace with indirect_ref.
+ (IRState::pvoidOkay): Replace with void_okay_p.
+ (IRState::maybeCompound): Replace with maybe_compound_expr.
+ (IRState::maybeVoidCompound): Replace with maybe_vcompound_expr.
+ (IRState::isErrorMark): Replace with error_mark_p.
+ (IRState::getTargetSizeConst): Replace with tree_to_hwi.
+ (IRState::modify): Replace with modify_expr.
+ (IRState::vmodify): Replace with vmodify_expr.
+ (IRState::vinit): Replace with build_vinit.
+ (IRState::nop): Replace with build_nop.
+ (IRState::vconvert): Replace with build_vconvert.
+ (IRState::boolOp): Replace with build_boolop.
+ (IRState::compound): Replace with compound_expr.
+ (IRState::voidCompound): Replace with vcompound_expr.
+ (IRState::component): Replace with component_ref.
+ (IRState::errorMark): Replace with error_mark.
+ (IRState::typesSame): Replace with d_types_same.
+ (IRState::typesCompatible): Replace with d_types_compatible.
+ (IRState::getDType): Replace with build_dtype.
+ (IRState::getObjectType): Replace with build_object_type.
+ (IRState::isDeclarationReferenceType): Replace with decl_reference_p.
+ (IRState::trueDeclarationType): Replace with declaration_type.
+ (IRState::isArgumentReferenceType): Replace with arg_reference_p.
+ (IRState::trueArgumentType): Replace with type_passed_as.
+ (IRState::arrayType): Replace with d_array_type.
+ (IRState::addTypeAttribute): Replace with insert_type_attributes.
+ (IRState::addDeclAttribute): Replace with insert_decl_attributes.
+ (IRState::attributes): Replace with build_attributes.
+ (IRState::addTypeModifiers): Replace with insert_type_modifiers.
+ (IRState::maybeMakeTemp): Replace with maybe_make_temp.
+ (IRState::isFreeOfSideEffects): Replace with d_has_side_effects.
+ (IRState::pointerOffsetOp): Replace with build_offset_op.
+ (IRState::pointerOffset): Replace with build_offset.
+ (IRState::buildCall): Replace with d_build_call.
+ (IRState::exceptionObject): Replace with build_exception_object.
+
+2013-03-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-asmstmt.cc (d_build_asm_stmt): Remove.
+ (ExtAsmStatement::ExtAsmStatement): Update to match renamed members.
+ (ExtAsmStatement::syntaxCopy): Likewise.
+ (ExtAsmStatement::semantic): Likewise.
+ (ExtAsmStatement::toCBuffer): Likewise.
+ (ExtAsmStatement::comeFrom): New.
+ (ExtAsmStatement::blockExit): Don't error if must not throw.
+ (naturalString): Remove.
+ (ExtAsmStatement::toIR): Inline IRState::doAsm implementation.
+ * d-codegen.cc (IRState::doAsm): Remove.
+ * d-decls.cc (FuncDeclaration::toSymbol): Don't generate 'naked'
+ attribute.
+ (binfo_for): Move into d-decls.cc.
+ (intfc_binfo_for): Likewise.
+ (ClassDeclaration::toDebug): Likewise.
+ (EnumDeclaration::toDebug): Likewise.
+ (TypedefDeclaration::toDebug): Likewise.
+ (StructDeclaration::toDebug): Likewise.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Move into d-objfile.cc.
+ (FuncDeclaration::buildClosure): Likewise.
+ (Module::genobjfile): Likewise.
+ * d-glue.cc: Remove file.
+
+2013-03-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-ir.cc (SynchronizedStatement::toIR): Remove implementation as is
+ now handled by the frontend.
+
+2013-03-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (IRState::maybeExpandSpecialCall): Handle ref argptr
+ arguments.
+
+2013-03-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (handle_alias_attribute): New function to handle
+ internal 'alias' attribute.
+ (handle_weakref_attribute): New function to handle internal 'weakref'
+ attribute.
+ * d-objfile.cc (ObjectFile::outputThunk): Define thunks to external
+ symbols as weakref, alias
+
+2013-03-12 Johannes Pfau <johannespfau@gmail.com>
+
+ * patch-versym-os-4.8.x (mingw32.h): Fix typo
+ * patch-versym-cpu-4.8.x (mips.h): Fix typo
+ Update version symbols to latest dlang specification.
+
+2013-03-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Delay setting TREE_TYPE as
+ function type could be hidden in a nested function not yet built.
+ * d-codegen.cc (IRState::findThis): Don't get 'this' from outer
+ function if it's a closure type. This has already been handled by
+ IRState::getFrameForSymbol.
+ (IRState::buildChain): Give frame decl debug name '__frame'.
+ Always set '__chain' link field.
+ (IRState::getFrameInfo): Don't build a frame for all nested functions.
+ Search through nested aggregates for static chain in outer functions.
+ * d-codegen.h (IRState::useParentChain): Remove.
+ * d-glue.cc (FuncDeclaration::toObjFile): Don't call useParentChain.
+ Don't create a local var for the chain link for a function.
+ (FuncDeclaration::buildClosure): Always set '__chain' link field.
+
+2013-03-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_gcc_force_templates): Only check for emitting
+ templates as private.
+ * d-lang.cc (d_handle_option): Remove -femit-templates= option.
+ * d-objfile.cc (ObjectFile::makeDeclOneOnly): Fix code logic so
+ fallback method could be reached.
+ * d-objfile.h (TEall, TEauto): Remove.
+
+2013-03-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-ir.cc (ReturnStatement::toIR): Don't call postblit on return.
+ * d-codegen.cc (IRState::trueDeclarationType): Don't set
+ D_TYPE_ADDRESSABLE.
+ (IRState::makeTemp): Remove.
+ (IRState::maybeMakeTemp): Copy makeTemp into function.
+ * d-glue.cc (d_genericize): Remove D_TYPE_ADDRESSABLE handling.
+ * d-lang.h (D_TYPE_ADDRESSABLE): Remove macro.
+
+2013-03-04 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-ctype.cc (Type::toCtype): Always call gen.addTypeModifiers to
+ make sure TYPE_MAIN_VARIANT is set. Reuse tree from unqualified
+ variant for that. Also cache the resulting qualified tree.
+ (TypeTypedef::toCtype): Likewise.
+ (TypeEnum::toCtype): Likewise.
+ (TypeStruct::toCtype): Likewise.
+ (TypeFunction::toCtype): Likewise.
+ (TypeVector::toCtype): Likewise.
+ (TypeSArray::toCtype): Likewise.
+ (TypeDArray::toCtype): Likewise.
+ (TypeAArray::toCtype): Likewise.
+ (TypeDelegate::toCtype): Likewise.
+ (TypeClass::toCtype): Likewise.
+ * d-objfile.cc (ObjectFile::giveDeclUniqueName): Make sure DECL_NAME is set
+
+2013-03-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (VarDeclaration::toSymbol): Remove use of c_ident.
+ (FuncDeclaration::toSymbol): Likewise.
+ * d-builtins.c (handle_noreturn_attribute): Assert that this is only
+ used for internal purposes.
+ (handle_const_attribute): Likewise.
+ (handle_malloc_attribute): Likewise.
+ (handle_pure_attribute): Likewise.
+ (handle_nonnull_attribute): Likewise.
+ (handle_nothrow_attribute): Likewise.
+ (handle_sentinel_attribute): Likewise.
+ (handle_transaction_pure_attribute): Likewise.
+ (handle_returns_twice_attribute): Likewise.
+ * d-glue.cc (FuncDeclaration::toObjFile): Result variables have no
+ default initialiser.
+ * d-codegen.cc (IRState::emitLocalVar): Add in assert that the local
+ variable has no initialiser if called with no_init = true.
+ (IRState::getLibCallDecl): Mark exceptional library functions as
+ noreturn.
+ (IRState::attributes): Gracefully handle @attribute, and
+ @attribute(null).
+
+2013-02-28 Jernej Krempus <jkrempus@gmail.com>
+
+ * d-builtins.c (d_attribute_table): Renamed it to
+ d_builtins_attribute_table.
+ * d-lang.cc (d_attribute_table): Added an empty table
+ * d-lang.cc (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Defined it as
+ d_builtins_attribute_table.
+ * d-lang.h (d_builtins_attribute_table): Added a declaration.
+ * d-codegen.cc (IRState::attributes): Changed it so it goes through
+ in_attrs and looks for any @gcc.attribute.attribute("attr_name").
+ * d-objfile.cc (ObjectFile::setupSymbolStorage): Pass userAttributes
+ instead of attributes in all calls to IRState::attributes.
+ * d-ctype.cc (TypeTypedef::toCtype): Likewise.
+ (TypeEnum::toCtype): Likewise.
+ (TypeStruct::toCtype): Likewise.
+ (TypeClass::toCtype): Likewise.
+ * libphobos/libdruntime/gcc/attribute.d: New file.
+
+2013-02-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Remove OPT_fdeprecated and
+ OPT_Wsign_compare, add handling for OPT_Wdeprecated.
+ (d_post_options): Handle Wdeprecated and Werror switch combination.
+
+2013-02-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (ArrayScope::ArrayScope): Don't setup length var if its
+ value is known at compile time.
+ (ArrayScope::setArrayExp): Likewise.
+ * d-decls.cc (uniqueName): Remove function.
+ (VarDeclaration::toSymbol): Set decl assembler name directly.
+ (FuncDeclaration::toSymbol): Likewise.
+
+2013-02-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (GDC_EXTENDED_ASM_SYNTAX): Remove macro.
+
+2013-02-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.h (D_DECL_IS_CONTRACT): Remove macro.
+ * d-decls.cc (FuncDeclaration::toSymbol): Likewise.
+
+2013-02-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_gcc_is_target_win32): Remove.
+ (d_add_builtin_version): New function to handle define_builtin
+ callback from backend.
+ * d-codegen.cc (IRState::maybeExpandSpecialCall): Remove intrinsic bt.
+
+ * d-builtins.c: Merge with d-builtins2.cc.
+ * d-builtins2.cc: Remove.
+
+2013-02-07 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_init): Use gcc's config system for predefined OS versions.
+ * setup-gcc.sh: Likewise.
+ * target-ver-syms.sh: Likewise.
+
+2013-02-05 Iain Buclaw <ibuclaw@ubuntu.com>
+
+ * d-builtins2.cc (gcc_type_to_d_type): Remove STRUCTTHISREF condition.
+ * d-decls.cc (FuncDeclaration::toSymbol): Likewise.
+ * d-elem.cc (ThisExp::toElem): Likewise.
+ * d-ctype.cc (TypeSArray::toCtype): Remove SARRAYVALUE condition.
+ * d-codegen.cc (IRState::isDeclarationReferenceType): Likewise.
+ (IRState::isArgumentReferenceType): Likewise.
+
+2013-02-01 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_init): Use gcc's config system for predefined CPU versions.
+ (d_init): Fix definition of D_LP64 version.
+ * setup-gcc.sh: Likewise.
+ * target-ver-syms.sh: Likewise.
+
+
+Copyright (C) 2013 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2014 b/gcc/d/ChangeLog-2014
new file mode 100644
index 0000000..cf8c8ac
--- /dev/null
+++ b/gcc/d/ChangeLog-2014
@@ -0,0 +1,660 @@
+2014-12-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (check_gdc_parallelize): Update for testsuite changes.
+ * d-convert.cc (d_convert_basic): Avoid stack overflow when converting
+ from pointer to integer.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Emit correct frame
+ information for closures rather than generic void pointers.
+
+2014-11-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (CatExp::toElem): Split dynamic arrays when passing as
+ varargs to arraycatT and arraycatnT.
+
+2014-11-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_vthis): Handle getting static chain for nested
+ templated structs.
+
+2014-09-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (ArrayLiteralExp::toElem): Remove special handling for
+ immutable arrays.
+
+2014-08-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-longdouble.cc (longdouble::formatHex): Convert buffer to uppercase
+ for use in mangling templates.
+
+2014-07-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (NewExp::toElem): Check for opaque structs before
+ continuing to generate the new expression.
+
+ * d-lang.h.cc (d_vtbl_ptr_type_node): Renamed to vtbl_ptr_type_node.
+ (d_boolean_type_node): Renamed to bool_type_node.
+ (d_char_type_node): Renamed to char8_type_node.
+ (d_wchar_type_node): Renamed to char16_type_node.
+ (d_dchar_type_node): Renamed to char32_type_node.
+ (d_ifloat_type_node): Renamed to ifloat_type_node.
+ (d_idouble_type_node): Renamed to idouble_type_node.
+ (d_ireal_type_node): Renamed to ireal_type_node.
+ (byte_type_node, ubyte_type_node): New macros for fixed integral
+ types in D.
+ (short_type_node, ushort_type_node): Likewise.
+ (int_type_node, uint_type_node): Likewise.
+ (long_type_node, ulong_type_node): Likewise.
+ (cent_type_node, ucent_type_node): Likewise.
+ * d-builtins.c (d_init_builtins): Initialise all D specific type nodes.
+ * d-codegen.cc (d_bounds_condition): Use D-specific type macros instead
+ of backend C types.
+ (layout_aggregate_type): Likewise.
+ (build_integer_cst): Likewise.
+ (build_boolop): Likewise.
+ * d-convert.cc (d_build_truthvalue_op): Likewise.
+ (d_truthvalue_conversion): Likewise.
+ * d-ctype.cc (Type::toCtype): Likewise.
+ * d-decls.cc (FuncDeclaration::toSymbol): Likewise.
+ * d-elem.cc (CmpExp::toElem): Likewise.
+ (OrOrExp::toElem): Likewise.
+ (NotExp::toElem): Likewise.
+ * d-lang.cc (d_type_for_mode): Likewise.
+ (d_type_for_size): Likewise.
+ (d_signed_or_unsigned_type): Likewise.
+
+2014-07-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-ctype.cc (TypeFunction::toCtype): Only check for ref return for
+ functions returning non-void.
+
+2014-07-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (output_declaration_p): Don't emit any declarations from
+ the gcc.attribute module.
+ (StructDeclaration::toObjFile): Call output_declaration_p.
+ * d-glue.cc (verror): Only call vasprintf on the initial format string.
+
+2014-07-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init_options_struct): Set flag_wrapv as on by default.
+
+2014-07-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (NewExp::toElem): Don't initialise a new'd struct at the
+ caller. The callee ensures this is done.
+
+2014-07-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (d_finish_symbol): Always set TREE_STATIC for symbols
+ being sent to the backend here.
+
+2014-07-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (d_finish_symbol): Don't set DECL_INITIAL if the
+ initialiser is all zeros.
+
+2014-07-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (lookup_ctype_name): Remove function.
+ (string_type_node): Move to static declaration from d_global_trees.
+ (const_string_type_node): Likewise.
+ (wint_type_node): Likewise.
+ (intmax_type_node): Likewise.
+ (uintmax_type_node): Likewise.
+ (signed_size_type_node): Likewise.
+ (d_init_builtins): Update.
+ * d-lang.cc (d_type_for_mode): Return only fixed size types.
+ (d_type_for_size): Likewise.
+ (d_signed_or_unsigned_type): Likewise.
+ (d_unsigned_type): Remove duplicated code from
+ d_signed_or_unsigned_type.
+ (d_signed_type): Likewise.
+
+2014-07-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (finish_thunk): Use set_decl_section_name, copy the
+ implicit section flag.
+ (setup_symbol_storage): Use decl_default_tls_model.
+
+2014-06-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.h (d_types_compatible): Remove function.
+ (d_types_same): Use more conservative approach to type equality.
+ * d-codegen.cc (get_libcall): Allow backend to be able to optimise
+ closure memory allocations.
+ (convert_for_assignment): Use d_types_same.
+ * d-elem.cc (CatExp::toElem): Likewise.
+ (BinExp::toElemBin): Likewise.
+ (CatAssignExp::toElem): Likewise.
+ (StructLiteralExp::toElem): Likewise.
+
+2014-06-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (CondExp::toElem): Handle void type condition expressions.
+ (AssignExp::toElem): Use ismemset to test for initialising arrays with
+ a single value.
+ (StructLiteralExp::toElem): Build static initialiser if a symbol was
+ created by the front-end.
+ * d-codegen.h (d_types_compatible): First check equality of types, then
+ implicit compatibility.
+ * d-convert.cc (d_default_conversion): Remove function, fold
+ implementation into...
+ (d_truthvalue_conversion): ... here.
+
+2014-06-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-convert.cc (d_scalar_conversion): Remove function.
+ (d_build_truthvalue_op): Update.
+ (d_truthvalue_conversion): Update.
+
+ * d-codegen.cc (get_frame_for_symbol): Remove glue-specific error
+ messages and refactor.
+ (build_vthis): Likewise.
+ (get_framedecl): Likewise.
+ * d-elem.cc (AssignExp::toElem): Update call to build_vthis.
+ (NewExp::toElem): Likewise.
+ (StructLiteralExp::toElem): Likewise.
+ * d-objfile.cc (Dsymbol::toObjFile): Fix build warning.
+
+ * d-codegen.cc (d_decl_context): Always return parent context for
+ functions nested in functions.
+ (is_degenerate_closure): Remove function.
+ (needs_static_chain): Remove function.
+ * d-decls.cc (FuncDeclaration::toSymbol): Remove workaround for cgraph
+ nesting structure, saving the original context decl.
+ * d-lang.h (D_DECL_STATIC_CHAIN): Remove macro.
+ * d-objfile.cc (Symbol::Symbol): Remove ScontextDecl field.
+ (FuncDeclaration::toObjFile): Remove workaround for cgraph nesting
+ structure, restoring the original context decl. Delay building the
+ cgraph node until...
+ (d_finish_function): ... here, where the function is unnested.
+
+2014-06-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (d_finish_function): Update the callgraph to reflect
+ unnesting of the function, as unravelling has already been handled by
+ the frontend. Do not delay calling cgraph_finalize_function.
+
+2014-06-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (d_comdat_group): Return a decl.
+ * d-decl.cc (FuncDeclaration::toThunkSymbol): Don't set comdat group.
+ * d-elem.cc (EqualExp::toElem): Always store temporaries when comparing
+ two dynamic arrays.
+
+2014-06-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (TypeInfoDeclaration::toSymbol): Add assert that Error
+ types never reach the backend.
+ * d-typinf.cc (Type::getTypeInfo): Likewise.
+
+2014-06-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dfrontend: Update to D front-end version 2.065.
+
+ * d-codegen.cc (d_build_call): Evaluate side effects of the object
+ parameter for method or delegate calls before passing.
+ (libcall_ids): Rename _d_array_bounds to _d_arraybounds.
+ (get_libcall): Update parameter types for _d_arraycopy.
+ (finish_aggregate_type): Update for frontend UDA changes.
+ * d-ctype.cc (TypeTypedef::toCtype): Update for frontend UDA changes.
+ (TypeEnum::toCtype): Likewise.
+ (TypeStruct::toCtype): Likewise.
+ (TypeClass::toCtype): Likewise.
+ * d-elem.cc (BoolExp::toElem): New function.
+ * d-lang.cc (rootmodule): New declaration for frontend entrypoint
+ changes.
+ (genCmain): Update for frontend entrypoint changes.
+ (d_handle_option): Don't duplicate memory for argument values.
+ (d_parse_file): Don't duplicate memory for source filenames.
+ * d-objfile.cc (VarDeclaration::toObjFile): Don't emit instantiated
+ manifest constants to debug.
+ (TemplateInstance::toObjFile): Update for frontend changes.
+ (output_template_p): Remove function.
+ (output_declaration_p): Update for frontend changes.
+ (setup_symbol_storage): Update for frontend UDA changes.
+ * d-target.cc (Target::reverseCppOverloads): New declaration.
+ * d-typinf.cc (Type::getInternalTypeInfo): Update for frontend changes.
+ (Type::getTypeInfo, Type::getTypeInfoDeclaration): Likewise.
+ (TypeTypedef::getTypeInfoDeclaration): Likewise.
+ (TypePointer::getTypeInfoDeclaration): Likewise.
+ (TypeDArray::getTypeInfoDeclaration): Likewise.
+ (TypeSArray::getTypeInfoDeclaration): Likewise.
+ (TypeAArray::getTypeInfoDeclaration): Likewise.
+ (TypeStruct::getTypeInfoDeclaration): Likewise.
+ (TypeClass::getTypeInfoDeclaration): Likewise.
+ (TypeVector::getTypeInfoDeclaration): Likewise.
+ (TypeEnum::getTypeInfoDeclaration): Likewise.
+ (TypeFunction::getTypeInfoDeclaration): Likewise.
+ (TypeDelegate::getTypeInfoDeclaration): Likewise.
+ (TypeTuple::getTypeInfoDeclaration): Likewise.
+ (createTypeInfoArray): Likewise.
+
+ * d-intrinsics.def: New file for declaring D intrinsics.
+
+ * d-builtins.cc (std_intrinsic_module, std_math_module)
+ (core_math_module, va_arg_template, va_arg2_template)
+ (va_start_template): Remove declarations.
+ (is_intrinsic_module_p, is_math_module_p, is_builtin_va_arg_p)
+ (is_builtin_va_start_p, d_gcc_magic_stdarg_check)
+ (d_gcc_magic_stdarg_module): Remove functions.
+ (d_gcc_magic_builtins_module): Rename to d_build_builtins_module.
+ (d_gcc_magic_libbuiltins_module): Rename to maybe_set_builtin.
+ (d_gcc_magic_libbuiltins_check): Rename to maybe_set_builtin_1.
+ (gcc_type_to_d_type): Rename to build_dtype.
+ (gcc_cst_to_d_expr): Rename to build_expression.
+ (d_gcc_eval_builtin): Remove function.
+ (eval_builtin): Moved to...
+ * d-glue.cc (eval_builtin): New function, updated for glue changes.
+ (FuncDeclaration::isBuiltin): New function to determine whether a
+ given function symbol is a compiler intrinsic.
+ * d-codegen.cc (maybe_expand_builtin): Rename to expand_intrinsic.
+ (Intrinsic): Remove enum declaration, replaced with...
+ (intrinsic_code): New enum for compiler intrinsics.
+ (intrinsic_decls): New declaration for store intrinsic information.
+ (expand_intrinsic_bt): Update signature.
+ (maybe_set_intrinsic): New function to replace...
+ (maybe_set_builtin_frontend): Remove function.
+ * d-decls.cc (FuncDeclaration::toSymbol): Update for glue changes.
+
+ * d-builtins.c: Rename to d-builtins.cc
+ * d-gt.c: Rename to d-gt.cc
+ * d-spec.c: Rename to d-spec.cc
+
+ * d-toir.cc: Renamed to toir.cc
+ * toir.cc: New file, re-implement toIR methods as a visitor.
+
+ * d-codegen.cc (insert_type_modifiers): Handle MODwildconst modifiers.
+ (build_ir): New function.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Use build_ir to walk
+ front-end IR trees.
+ * d-decls.cc (VarDeclaration::toSymbol): Mark compiler temporaries as
+ DECL_ARTIFICIAL.
+ (ClassDeclaration::toVtblSymbol): Update for front-end changes.
+ * d-builtins.c (gcc_type_to_d_type): Likewise.
+ * d-elem.cc (CatAssignExp::toElem): Likewise.
+ (ArrayLiteralExp::toElem): Likewise.
+ (BoolExp::toElem): Remove function.
+ (ComExp::toElem): Assert that unhandled array operations no longer
+ leak from the front-end.
+ (NegExp::toElem): Likewise.
+ * d-glue.cc (Global::init): Initialise new member run_noext.
+ * d-incpath (add_import_path): Update for front-end changes.
+ * d-lang.cc (d_add_builtin_version): Likewise.
+ * d-todt.cc (StructDeclaration::toDt): Likewise.
+ * d-toir.cc (LabelStatement::toIR): Don't delete forward references.
+ (GotoStatement::toIR): Assert that undefined labels no longer leak
+ from the front-end.
+
+2014-05-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-todt.cc (dt_container): Properly handle zero length static arrays.
+ * d-codegen.h (build_dtype): Rename to lang_dtype.
+ (build_ddecl): Rename to lang_ddecl.
+
+2014-05-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (d_init_builtins): Use void_node instead of
+ d_void_zero_node.
+ * d-lang.h (d_void_zero_node): Remove.
+ * d-elem.cc (AndAndExp::toElem): Adjust.
+ (OrOrExp::toElem): Likewise.
+ (AssertExp::toElem): Likewise.
+ (TupleExp::toElem): Likewise.
+
+ * d-builtins.c (d_init_builtins): Use null_pointer_node instead of
+ d_null_pointer.
+ * d-lang.h (d_null_pointer): Remove.
+ * d-codegen.cc (convert_expr): Adjust.
+ (get_frame_for_symbol): Likewise.
+ (build_vthis): Likewise.
+ (get_framedecl): Likewise.
+ * d-elem.cc (DeleteExp::toElem): Likewise.
+ (CallExp::toElem): Likewise.
+ (AssertExp::toElem): Likewise.
+ (NewExp::toElem): Likewise.
+ (ArrayLiteralExp::toElem): Likewise.
+ (NullExp::toElem): Likewise.
+ * d-objfile.cc (ClassDeclaration::toObjFile): Likewise.
+ (InterfaceDeclaration::toObjFile): Likewise.
+ (FuncDeclaration::toObjFile): Likewise.
+ (build_moduleinfo): Likewise.
+ * d-todt.cc (TypeInfoTypedefDeclaration::toDt): Likewise.
+ (TypeInfoEnumDeclaration::toDt): Likewise.
+ (TypeInfoStructDeclaration::toDt): Likewise.
+
+2014-05-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-longdouble.cc (longdouble::from_shwi): Rename to from_int.
+ (longdouble::from_uhwi): Rename to from_uint.
+ (longdouble::to_shwi): Rename to to_int.
+ (longdouble::to_uhwi): Rename to to_uint.
+ (longdouble::set): Adjust.
+ (longdouble::operator): Likewise.
+
+ * d-lang.cc (alloc_binding_level): Adjust.
+ (build_d_type_lang_specific): Likewise.
+ (build_d_decl_lang_specific): Likewise.
+ * d-lang.h (lang_type): Don't use variable_size gty attribute.
+ * d-codegen.cc (cst_to_hwi): Remove function.
+ * d-codegen.cc (tree_to_hwi): Remove function.
+ * d-builtins.c (gcc_type_to_d_type): Adjust.
+ (gcc_cst_to_d_expr): Likewise.
+ * d-convert.cc (d_truthvalue_conversion): Use integer_zerop.
+ (get_nonnull_operand): Use tree_fits_uhwi_p.
+ * d-longdouble.cc (longdouble::from_int): Adjust.
+ (longdouble::from_uint): Likewise.
+ (longdouble::to_int): Likewise.
+
+2014-04-30 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_init): Define GNU_SEH_Exceptions and
+ GNU_DWARF2_Exceptions versions.
+
+2014-04-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init_options): Default deprecation warnings to off.
+ * d-ctype.cc (TypeDelegate::toCtype): Propogate TREE_ADDRESSABLE from
+ the base function to the delegatised copy.
+
+2014-04-15 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_handle_noclone_attribute): New function to handle
+ noclone attribute. noclone is required by the naked attribute.
+ * d-elem.cc (SymbolExp::toElem): Convert symbols to the expression
+ type.
+
+2014-04-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_frameinfo): Don't copy the node for frame record.
+ * d-irstate.cc (IRState::endCatches): Rebuild the STATEMENT_LIST of
+ catches in a TRY_CATCH_EXPR if it gets optimised away by
+ IRState::popStatement.
+ * d-codegen.cc (d_attribute_p): Provide access to target attributes.
+
+2014-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (error_mark_p): Removed function, replace uses with
+ error_operand_p.
+ (error_mark): Removed function, replace uses with error_mark_node.
+ * d-ctype.cc (Type::toCtype): Return d_unknown_type_node for frontend
+ error types.
+ * d-objfile.cc (VarDeclaration::toObjFile): Don't build CONST_DECLs for
+ non-scalar manifests.
+
+2014-03-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (Dsymbol::toImport): Prevent GC from collecting
+ IMPORTED_DECL nodes whilst front-end compilation in progress.
+
+2014-03-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (AggLayout::visit): Rename to layout_aggregate_type.
+ (AggLayout::doFields, AggLayout::doInterfaces): Remove function and
+ move implementation into layout_aggregate_type.
+ (AggLayout::addField): Rename to insert_aggregate_field.
+ (AggLayout::finish): Rename to finish_aggregate_type.
+ * d-codegen.h (AggLayout): Update definition.
+ * d-ctype.cc (TypeStruct::toCtype): Update for glue changes.
+ (TypeFunction::toCtype): Fix ICE on generic function types.
+ (TypeClass::toCtype): Move generation of vptr and monitor fields into
+ layout_aggregate_type. Moved generation of TYPE_METHODS from ...
+ * d-objfile.cc (FuncDeclaration::toObjFile): ... here into
+ TypeClass::toCtype. Don't build up TYPE_METHODS on a per-function
+ basis, generate the entire vtable.
+
+2014-03-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (Dsymbol::toSymbolX): Set the symbol prettyIdent.
+ (Dsymbol::toImport): Emit packages as their fully qualified names.
+ (ClassDeclaration::toSymbol): Distinguish between the classinfo
+ assembler and decl name.
+ (InterfaceDeclaration::toSymbol): Likewise for interface symbol.
+ (Module::toSymbol): Likewise for moduleinfo symbol.
+ (ClassDeclaration::toVtblSymbol): Likewise for class vtable symbol.
+ (AggregateDeclaration::toInitializer)
+ (TypedefDeclaration::toInitializer, EnumDeclaration::toInitializer):
+ Likewise for default initialisers.
+ * d-objfile.cc (Module::genobjfile): Don't set-up moduleinfo symbol
+ storage twice.
+
+2014-03-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_decl_context): Fix null pointer dereference.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Don't override the setting
+ of DECL_CONTEXT on the declaration here.
+ (d_finish_symbol): Likewise.
+ * d-objfile.cc (VarDeclaration::toObjFile): Move the generation of
+ manifest constants to ...
+ * d-decls.cc (VarDeclaration::toSymbol): ... here, and emit them as
+ CONST_DECLs. Set the DECL_CONTEXT for all variable symbols.
+
+ * d-builtins.cc (d_gcc_magic_builtins_module): Don't store compiler
+ generated builtins in Symbol::isym, use Symbol::csym instead.
+ (d_gcc_magic_libbuiltins_check): Likewise.
+ * d-codegen.cc (d_decl_context): Return the imported symbol tree of
+ modules where the NAMESPACE_DECL is now stored.
+ (d_build_module): Remove function. Move implementation to ...
+ * d-decls.cc (Dsymbol::toImport): ... here. Build an IMPORTED_DECL for
+ all imported declarations.
+ (FuncDeclaration::toSymbol): Remove special handling of Symbol::isym.
+ (Module::toSymbol): Remove call to d_build_module.
+ * d-objfile.cc (Dsymbol::toObjFile): Handle emission of IMPORTED_DECL
+ symbols to debug.
+
+2014-03-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_attributes): Ensure D-specific attributes have
+ their value interpreted through CTFE.
+
+2014-02-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_build_module): Update signature to accept a Loc
+ location to the module declaration.
+ * d-decls.cc (Module::toSymbol): Update call to d_build_module.
+ Set TREE_PUBLIC/DECL_EXTERNAL to distingush which modules are being
+ compiled.
+ * d-objfile.cc (Dsymbol::toObjFile): Handle Import symbols, and emit
+ debug information for imported modules.
+ (ImportStatement::toIR): Likewise.
+ (set_input_location): New function to implement the equivalent of
+ set_decl_location, but instead sets input_location.
+
+2014-02-19 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-objfile.cc (build_call_function): Call set_input_location
+ to set debug info correctly
+
+2014-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (VarDeclaration::toObjFile): Remove toplevel check.
+ DECL_CONTEXT is never set on manifest constants.
+ (d_finish_compilation): Remove fancy check on force outputting
+ symbols to object file.
+ (build_type_decl): Don't emit the qualified identifier in debug
+ information. The fully qualified name is now determined through the
+ NAMESPACE_DECL context chain.
+ * d-ctype.cc (TypeEnum::toCtype): Likewise for enum members.
+ (VarDeclaration::toSymbol): Likewise for static variables.
+ (FuncDeclaration::toSymbol): Likewise for functions.
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Don't emit the 'D main'
+ symbol to debug as plain 'main'.
+ * d-objfile.cc (VarDeclaration::toObjFile): Don't emit the qualified
+ identifier of manifest constants in debug information.
+
+2014-02-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_build_module): New function.
+ * d-decls.cc (Module::toSymbol): Use d_build_module to build up the
+ qualified module namespace.
+
+ * d-codegen.cc (expand_intrinsic_op, expand_intrinsic_op2): New
+ functions to build a call to a builtin code.
+ (expand_intrinsic_bsr, expand_intrinsic_bt): New functions to expand a
+ BUILTIN_FRONTEND call to core.bitop intrinsics.
+ (expand_intrinsic_vaarg, expand_intrinsic_vastart): New functions to
+ expand a BUILTIN_FRONTEND call to core.vararg intrinsics.
+ (maybe_expand_builtin): Update.
+
+2014-02-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (Module::toSymbol): Build a NAMESPACE_DECL to populate the
+ DECL_CONTEXT of toplevel functions.
+ * d-codegen.cc (d_decl_context): Return the enclosing module
+ NAMESPACE_DECL as the decl context only when the symbol is extern(D)
+ and not D main.
+
+2014-02-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (VarDeclaration::toSymbol): Don't call
+ setup_symbol_storage until after SET_DECL_ASSEMBLER_NAME has been set.
+
+ * d-decls.cc (VarDeclaration::toSymbol): Give prettyIdent precedence
+ for the DECL_NAME over the simple identifier.
+ (FuncDeclaration::toSymbol): Likewise.
+ * d-objfile.cc (d_finish_symbol): Remove setting DECL_NAME as
+ prettyIdent, this has already been done in Declaration::toSymbol.
+ (d_finish_function): Likewise.
+
+ * d-decls.cc (VarDeclaration::toSymbol): Call set_user_assembler_name
+ if pragma(mangle) was seen.
+ (FuncDeclaration::toSymbol): Likewise.
+
+2014-02-12 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Do not set TREE_NOTHROW on
+ nothrow functions.
+ * d-decls.cc (TypeInfoDeclaration::toSymbol): Call relayout_decl after
+ changing the type.
+
+2014-02-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+
+ * d-codegen.cc (d_build_call): Remove special handling of
+ flag_split_darrays switch.
+ (maybe_expand_builtin): Likewise.
+ * d-elem.cc (CatExp::toElem): Likewise.
+ * lang.opt (fsplit-dynamic-arrays): Remove.
+
+2014-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-glue.cc (readFile, writeFile, ensurePathToNameExists): Define.
+ * d-incpath.cc (add_import_path): Update for frontend changes.
+ (add_fileimp_path): Likewise.
+ * d-lang.cc (deps_write): Likewise.
+ (d_parse_file): Likewise.
+ * d-todt.cc (Dts): Update define for frontend changes.
+ * d-decls.cc (ClassDeclaration::toVtblSymbol): Don't mark __vtbl
+ symbols as virtual. They are global static symbols.
+
+2014-01-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (EnumDeclaration::toDebug): Build TYPE_DECL only for
+ enumeral types.
+
+2014-01-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-ctype.cc (TypeClass::toCtype): Don't add __monitor field for
+ extern(C++) classes.
+
+ * d-builtins.c (d_gcc_magic_module): Remove tdata.
+ * d-codegen.cc (build_interface_binfo): Likewise.
+ * d-ctype.cc (TypeEnum::toCtype): Likewise.
+ (TypeClass::toCtype): Likewise.
+ * d-lang.cc (deps_write): Likewise.
+
+2014-01-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-ctype.cc (TypeEnum::toCtype): Don't push CONST_DECLs into current
+ function.
+ * d-decls.cc (FuncDeclaration::toThunkSymbol): Don't mark symbol as
+ TREE_PRIVATE, just TREE_PUBLIC as false.
+ (StructLiteralExp::toSymbol): Likewise.
+ (ClassReferenceExp::toSymbol): Likewise.
+ * d-objfile.cc (d_comdat_linkage): Likewise.
+ (d_finish_symbol): Likewise.
+ (build_moduleinfo): Likewise.
+
+ * config-lang.in: Add d-lang.cc to gtfiles.
+ * d-irstate.h (IRState::varsInScope): Change from Array to vec<> type.
+ (IRState::statementList_): Likewise.
+ (IRState::scopes_): Likewise.
+ (IRState::loops_): Likewise.
+ (IRState::labels_): Likewise.
+ * d-lang.h (d_bi_builtin_func): Remove declaration.
+ (d_bi_builtin_type): Likewise.
+ (d_keep_list): Likewise.
+ * d-objfile.h (Symbol::thunks): Change from Array to vec<> type.
+ (ModuleInfo::classes): Likewise.
+ (ModuleInfo::ctors): Likewise.
+ (ModuleInfo::dtors): Likewise.
+ (ModuleInfo::ctorgates): Likewise.
+ (ModuleInfo::sharedctors): Likewise.
+ (ModuleInfo::shareddtors): Likewise.
+ (ModuleInfo::sharedctorgates): Likewise.
+ (ModuleInfo::unitTests): Likewise.
+ (build_simple_function): Remove declaration.
+ (build_call_function): Likewise.
+ (build_ctor_function): Likewise.
+ (build_dtor_function): Likewise.
+ (build_unittest_function): Likewise.
+ * d-builtins.c (bi_fn_list): Rename to gcc_builtins_functions.
+ (bi_lib_list): Rename to gcc_builtins_libfuncs.
+ (bi_type_list): Rename to gcc_builtins_types.
+ (builtin_converted_types): Remove.
+ (builtin_converted_decls): Change from Array to vec<> type.
+ (gcc_type_to_d_type): Update.
+ (d_bi_builtin_func): Remove and move to d_builtin_function.
+ (d_bi_builtin_type): Remove and move to d_register_builtin_type.
+ (d_gcc_magic_builtins_module): Update.
+ * d-ctype.cc (TypeClass::toCtype): Remove unused var.
+ * d-decls.cc (FuncDeclaration::toThunkSymbol): Update for change to
+ vec<> type.
+ * d-elem.cc (CatExp::toElem): Change stashed vars from Array to vec<>.
+ (Expression::toElemDtor): Update for change to vec<> type.
+ * d-irstate.cc (IRState::startFunction): Likewise.
+ (IRState::endFunction): Likewise.
+ (IRState::addExp): Likewise.
+ (IRState::pushStatementList): Likewise.
+ (IRState::popStatementList): Likewise.
+ (IRState::getLabelBlock): Likewise.
+ (IRState::getLoopForLabel): Likewise.
+ (IRState::beginFlow): Likewise.
+ (IRState::endFlow): Likewise.
+ (IRState::startScope): Likewise.
+ (IRState::pushLabel): Likewise.
+ (IRState::checkGoto): Likewise.
+ (IRState::checkPreviousGoto): Change from Array to Blocks type.
+ * d-lang.cc (global_declarations): Change from Array to vec<> type.
+ (d_add_global_declaration): Update for change to vec<> type.
+ (d_write_global_declarations): Likewise.
+ (d_keep_list): Make static to source file.
+ * d-objfile.cc (static_ctor_list): Change from Array to vec<> type.
+ (static_dtor_list): Likewise.
+ (Module::genobjfile): Update for change to vec<> type.
+ (d_finish_module): Likewise.
+ (d_finish_function): Likewise.
+ (deferred_thunks): Change from ArrayBase<> to vec<> type.
+ (write_deferred_thunks): Update for change to vec<> type.
+ (use_thunk): Likewise.
+ (build_simple_function): Make static to source file.
+ (build_call_function): Likewise.
+ (build_ctor_function): Likewise.
+ (build_dtor_function): Likewise.
+ (build_unittest_function): Likewise.
+
+2014-01-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (setup_symbol_storage): Use output_module_p on template
+ instantiating module to determine if symbol is externally compiled.
+ (d_finish_function): Set function local if function body was compiled.
+ * d-decls.cc (Dsymbol::toSymbolX): Use unsigned integer format for the
+ prefix string length.
+
+
+Copyright (C) 2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2015 b/gcc/d/ChangeLog-2015
new file mode 100644
index 0000000..918068b
--- /dev/null
+++ b/gcc/d/ChangeLog-2015
@@ -0,0 +1,771 @@
+2015-10-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (StructLiteralExp::toSymbol): Use letter prefix for
+ anonymous name. Don't set TREE_READONLY.
+ (ClassReferenceExp::toSymbol): Likewise.
+
+2015-10-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_struct_literal): New function.
+ (layout_aggregate_members): Handle variables that are really tuples.
+ * d-elem.cc (StructLiteralExp::toElem): Handle slicing void arrays.
+ Use build_struct_literal to handle anonymous records.
+ * d-lang.h (d_unknown_type_node): Rename to unknown_type_node, update
+ in all files.
+
+2015-10-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_two_field_type): Use DECL_FIELD_CONTEXT to access
+ field context decl.
+ (build_frame_type): Likewise.
+ (lookup_anon_field): New function.
+ (component_ref): Use it.
+ (fixup_anonymous_offset): New function.
+ (layout_aggregate_members): New function.
+ (layout_aggregate_type): Move generation of fields into
+ layout_aggregate_members.
+ (insert_aggregate_field): Update signature, update all callers.
+ (finish_aggregate_type): Likewise.
+ * d-todt.cc (dt_container2): Use DECL_FIELD_CONTEXT to access field
+ context decl.
+ * types.cc (TypeVisitor::visit (TypeStruct)): Likewise.
+ (TypeVisitor::visit (TypeClass)): Likewise.
+ * d-tree.h (ANON_AGGR_TYPE_P): New type macro.
+
+2015-08-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (maybe_set_builtin_1): Remove va_list handling.
+ (d_init_builtins): Don't represent static array va_list as reference.
+ * d-codegen.cc (convert_for_argument): Handle va_list as a static array.
+ (declaration_type): Likewise.
+ (type_passed_as): Likewise.
+ (decl_reference_p): Renamed to declaration_type_kind, update to return
+ how type is represented internally, updated all callers.
+ (arg_reference_p): Renamed to argument_type_kind, update to return how
+ type is represented internally, updated all callers.
+ * d-codegen.h (type_kind): Declare.
+
+2015-08-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * toir.cc (IRVisitor::visit (TryCatchStatement)): Always emit call to
+ LIBCALL_BEGIN_CATCH at the start of the catch.
+ * d-elem.cc (AssertExp::toElem): Stabilize reference to class object
+ before passing it to _d_invariant.
+
+2015-08-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * toir.cc (IRVisitor::visit): Set input location in all visitors that
+ either throw an ICE or sorry message.
+
+2015-08-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in: Replace uses of $(target_alias) with
+ $(target_noncanonical).
+
+2015-08-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc (TypeVisitor::visit (TypeEnum)): Set ENUM_IS_SCOPED on all
+ enumeral types.
+ * d-lang.cc (d_init_options_struct): Remove setting
+ flag_evaluation_order.
+
+2015-08-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (HaltExp::toElem): Use __builtin_trap to halt execution,
+ rather than the library abort() call.
+
+2015-08-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_closure): Update signature, update all callers.
+ (build_vthis): Likewise.
+ (get_frame_for_symbol): Likewise.
+ (build_local_var): Likewise.
+ (get_decl_tree): Likewise.
+ (start_function): Likewise.
+ * d-irstate.h (IRState): Move func, mod, sthis, deferred,
+ statementList, and varsInScope fields to...
+ * d-tree.h (language_function): Here, updated all uses.
+ * d-irstate.h: Remove file.
+ (IRState): Remove all uses everywhere.
+
+2015-08-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_GLUE_OBJS): Remove d-irstate.o.
+ * d-tree.h (d_label_use_entry): New structure.
+ (d_label_entry): New structure.
+ (binding_level): Add level_kind field.
+ (language_function): Add hash table field for labels.
+ (D_LABEL_VARIABLE_CASE): New macro.
+ * d-codegen.cc (pop_binding_label): New function.
+ (pop_label): New function.
+ (push_binding_level): Update signature.
+ (pop_binding_level): Update signature. Handle declared or used labels.
+ (build_array_set): Update for push/pop binding changes.
+ (check_goto): New function.
+ (check_previous_goto): New function.
+ (d_lookup_label): Remove function.
+ (lookup_label): New function.
+ (lookup_bc_label): New function.
+ (define_label): New function.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Update for push/pop binding
+ changes.
+ * toir.cc (IRVisitor): Add break and continue label fields.
+ (IRVisitor::IRVisitor): Initialize here.
+ (IRVisitor::start_scope): Update signature.
+ (IRVisitor::end_scope): Return the finished scope, updated all callers.
+ (IRVisitor::push_break_label): New function.
+ (IRVisitor::pop_break_label): New function.
+ (IRVisitor::push_continue_label): New function.
+ (IRVisitor::pop_continue_label): New function.
+ (IRVisitor::start_condition): Remove function.
+ (IRVisitor::start_else): Remove function.
+ (IRVisitor::end_condition): Remove function.
+ (IRVisitor::start_catches): Remove function.
+ (IRVisitor::start_catch): Remove function.
+ (IRVisitor::end_catch): Remove function.
+ (IRVisitor::end_catches): Remove function.
+ (IRVisitor::start_finally): Remove function.
+ (IRVisitor::end_finally): Remove function.
+ (IRVisitor::start_case): Remove function.
+ (IRVisitor::end_case): Remove function.
+ * d-irstate.cc: Remove.
+
+2015-08-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * config-lang.in (gtfiles): Replace d-lang.h for d-tree.h
+ * d-lang.h: Move all GTY structures to d-tree.h, updated all source
+ header dependencies.
+ * d-tree.h: New file.
+
+2015-08-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * toir.cc (IRVisitor::start_condition): Don't cache condition.
+ (IRVisitor::start_else): Return the then body, updated all callers.
+ (IRVisitor::end_condition): Update signature.
+ (IRVisitor::start_catches): Return the try body, updated all callers.
+ (IRVisitor::start_catch): Don't cache catch type.
+ (IRVisitor::end_catch): Update signature.
+ (IRVisitor::end_catches): Update signature.
+ (IRVisitor::start_finally): Return the try body, updated all callers.
+ (IRVisitor::end_finally): Update signature.
+ (IRVisitor::start_case): Don't cache the condition.
+ (IRVisitor::end_case): Update signature.
+ * d-codegen.cc (convert_for_assignment): Use size_type_node for index.
+ * d-irstate.cc (IRState::beginFlow): Remove call to push_stmt_list.
+
+2015-08-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (push_stmt_list): New function.
+ (pop_stmt_list): New function.
+ (add_stmt): New function.
+ (start_function): New function.
+ (end_function): New function.
+ (expand_decl): Update to use new interface.
+ (build_closure): Likewise.
+ (push_binding_level): Moved from d-lang.cc.
+ (pop_binding_level): Likewise.
+ * d-lang.cc (d_init): Inline call to init_global_binding_level.
+ (alloc_binding_level): Remove function.
+ (push_binding_level): Remove function.
+ (pop_binding_level): Remove function.
+ (init_global_binding_level): Remove function.
+ (set_decl_binding_chain): Remove function.
+ * d-elem.cc (DeclarationExp::toElem): Likewise.
+ * d-objfile.cc (VarDeclaration::toObjFile): Likewise.
+ (FuncDeclaration::toObjFile): Likewise.
+ * toir.cc (IRVisitor::start_scope): Moved from d-irstate.cc, updated
+ all callers in IRVisitor.
+ (IRVisitor::end_scope): Likewise.
+ (IRVisitor::is_return_label): Likewise.
+ (IRVisitor::do_label): Likewise.
+ (IRVisitor::do_jump): Likewise.
+ (IRVisitor::start_condition): Likewise.
+ (IRVisitor::start_else): Likewise.
+ (IRVisitor::end_condition): Likewise.
+ (IRVisitor::start_catches): Likewise.
+ (IRVisitor::start_catch): Likewise.
+ (IRVisitor::end_catch): Likewise.
+ (IRVisitor::end_catches): Likewise.
+ (IRVisitor::start_finally): Likewise.
+ (IRVisitor::end_finally): Likewise.
+ (IRVisitor::end_loop): Likewise.
+ (IRVisitor::start_case): Likewise.
+ (IRVisitor::end_case): Likewise.
+ (build_ir): Update signature.
+
+2015-08-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (DMD_COMPILE): Declare as COMPILE with WARN_CXXFLAGS
+ replaced with DMD_WARN_CXXFLAGS.
+ (DMDGEN_COMPILE): Declare as DMD_COMPILE but with COMPILER replaced
+ with COMPILER_FOR_BUILD.
+ (d/idgen): Use LINKER_FOR_BUILD.
+ (d/impcvgen): Likewise.
+ (d/%.o): Use DMD_COMPILE and POSTCOMPILE.
+ (d/%.dmdgen.o): Use DMDGEN_COMPILE and POSTCOMPILE.
+
+2015-07-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (current_irstate): Remove.
+ (d_build_call): Check cfun before dereferencing.
+ * d-codegen.h (current_irstate): Redefine as macro.
+ * d-irstate.cc (IRState::IRState): Remove.
+ (IRState::startFunction): Initialize language-specific cfun field.
+ (IRState::endFunction): Free language-specific cfun field.
+ * d-lang.cc (d_parse_file): Don't initialize current_irstate.
+ * d-lang.h (language_function): Add irs field.
+ * d-objfile.cc (Dsymbol::toObjFile): Check cfun.
+ (FuncDeclaration::toObjFile): Adjust start and end calls.
+
+2015-07-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-irstate.cc (IRState::doArraySet): Remove function.
+ * d-codegen.cc (build_array_set): New function.
+ * d-elem.cc (AssignExp::toElem): Use build_array_set.
+ (StructLiteralExp::toElem): Likewise.
+
+ * d-codegen.cc (build_array_set): Don't set this_block, update call to
+ pop_binding_level.
+ * d-irstate.cc (IRState::endFunction): Update assert.
+ (IRState::startScope): Move IRState::startBindings here, clean-up.
+ (IRState::endScope): Move IRState::endBindings here, clean-up.
+ (IRState::startBindings): Remove function.
+ (IRState::endBindings): Likewise.
+ (IRState::currentScope): Likewise.
+ (IRState::scopes_): Remove.
+ * d-lang.cc (pop_binding_level): Update signature, clean-up.
+ (d_pushdecl): Don't set names_end.
+ (binding_level::names_end): Remove.
+ (binding_level::this_block): Remove.
+ (FuncDeclaration::toObjFile): Clean-up.
+
+2015-07-24 Sebastien Alaiwan <sebastien.alaiwan@gmail.com>
+
+ * d-lang.cc (deps_write): Use StringTable instead of hash_set of string
+ pointers.
+
+2015-07-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.h: Adjust includes.
+ * d-builtins.cc: Likewise.
+ * d-codegen.cc: Likewise.
+ * d-convert.cc: Likewise.
+ * d-decls.cc: Likewise.
+ * d-elem.cc: Likewise.
+ * d-glue.cc: Likewise.
+ * d-incpath.cc: Likewise.
+ * d-irstate.cc: Likewise.
+ * d-lang.cc: Likewise.
+ * d-longdouble.cc: Likewise.
+ * d-objfile.cc: Likewise.
+ * d-port.cc: Likewise.
+ * d-target.cc: Likewise.
+ * d-todt.cc: Likewise.
+ * toir.cc: Likewise.
+ * types.cc: Likewise.
+
+2015-07-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (convert_expr): Warn about casts between imaginary
+ and non-imaginary types.
+ * d-convert (d_convert_basic): Rename to convert, handle conversions
+ between complex and imaginary types.
+ (convert): Remove.
+ (d_build_truthvalue_op): Update to call convert.
+ (d_truthvalue_conversion): Likewise.
+
+ * d-builtins.cc (d_init_builtins): Build imaginary types as distinct
+ floating point type nodes.
+ * d-codegen.cc (build_float_modulus): Update to handle imaginary types.
+ (d_array_type): Use the front-end equivalent of sizetype to represent
+ the index type of arrays.
+ (build_array_index): Likewise.
+ (build_offset_op): Likewise.
+ (expand_intrinsic): Only get the inner callee if it's an address.
+
+ * d-codegen.h (component_ref, modify_expr, vmodify_expr, build_vinit)
+ (build_nop, build_vconvert, build_boolop, compound_expr)
+ (vcompound_expr, real_part, imaginary_part): Move to d-codegen.cc,
+ use fold build functions for codegen.
+ * d-codeden.cc (build_address): Use build_fold_addr_expr_with_type,
+ remove special handling of taking an address of an indirect ref.
+ (return_expr): New function.
+ (complex_expr): New function.
+ (indirect_ref): Use fold build functions for codegen.
+ (build_deref): Likewise.
+ (build_array_index): Likewise.
+ (build_offset_op): Likewise.
+ (void_okay_p): Likewise.
+ (build_binary_op): Likewise.
+ (build_float_modulus): Likewise.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Likewise.
+ * d-elem.cc (MinExp::toElem): Likewise.
+ (AddExp::toElem): Likewise.
+ (NotExp::toElem): Likewise.
+ (ComExp::toElem): Likwise.
+ (NegExp::toElem): Likewise.
+ * d-irstate.cc (IRState::doLabel): Likewise.
+ (IRState::doReturn): Likewise.
+ (IRState::doJump): Likewise.
+
+ * d-attribs.c: Adjust includes for flags.h changes.
+ * d-builtins.cc: Likewise.
+ * d-codegen.cc: Likewise.
+ * d-convert.cc: Likewise.
+ * d-elem.cc: Likewise.
+ * d-decls.cc: Likewise.
+ * d-glue.cc: Likewise.
+ * d-incpath.cc: Likewise.
+ * d-irstate.cc: Likewise.
+ * d-lang.cc: Likewise.
+ * d-longdouble.cc: Likewise.
+ * d-objfile.cc: Likewise.
+ * d-port.cc: Likewise.
+ * d-target.cc: Likewise.
+ * d-todt.cc: Likewise.
+ * toir.cc: Likewise.
+ * types.cc: Likewise.
+
+2015-07-20 Sebastien Alaiwan <sebastien.alaiwan@gmail.com>
+
+ * d-lang.cc (is_system_module): Extract function.
+ (write_one_dep): Extract function.
+ (deps_write): Eliminate duplicated dependencies, include
+ indirect and private dependencies.
+
+2015-07-19 Sebastien Alaiwan <sebastien.alaiwan@gmail.com>
+
+ * d-lang.cc (d_parse_file): Set ref flag on the module and make deps
+ file handle.
+
+2015-07-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (convert_for_assignment): Remove handling of zero
+ initialising a structure using memset.
+ (d_build_call): Removing handling of setting of return slot
+ optimisation on in call expression.
+ * d-elem.cc (AssignExp::toElem): Emit a memset to zero initialise
+ structures here. Set return slot optimisation on construction of
+ static arrays and structs only.
+
+2015-07-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (expand_intrinsic_arith): Use build_deref to handle
+ ref parameters being used for the 'overflow' parameter.
+
+2015-07-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (StringExp::toElem): Zero-terminate all string literals
+ types, except for static arrays.
+ * d-objfile.cc (build_type_decl): Add TYPE_DECLs to global declarations,
+ don't call rest_of_decl_declaration.
+ (d_finish_compilation): Call rest_of_decl_declaration on TYPE_DECLs.
+ (Dsymbol::toObjFile): Don't try to handle tuples when emitting import
+ declarations to debug.
+ * d-builtins.cc (builtin_sym): Use StructDeclaration for decl field.
+ (build_dtype): Don't handle anonymous structs. Create a stub parent
+ module for the declaration symbol.
+ (d_build_builtins_module): Always override the parent module of
+ converted struct declarations.
+ (maybe_set_builtin_1): Convert all static array parameters to ref
+ parameters, not just va_list.
+
+2015-07-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c (d_handle_section_attribute): Use VAR_P throughout.
+ (d_handle_weak_attribute): Use VAR_OR_FUNCTION_DECL_P.
+ * d-codegen.cc (convert_for_assignment): Use VAR_P.
+ * d-lang.cc (pop_binding_level): Likewise.
+ (d_types_compatible_p): Likewise.
+ * d-objfile.cc (setup_symbol_storage): Likewise.
+ (mark_needed): Likewise.
+ (d_finish_compilation): Likewise.
+
+2015-06-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.def: Added ADDS, ADDSL, ADDU, ADDUL, SUBS, SUBSL, NEGS,
+ NEGSL, MULS, MULSL, MULU, and MULUL intrinsic definitions.
+ * d-codegen.cc (expand_intrinsic_arith): New function.
+ (expand_intrinsic): Add cases for core.checkedint functions adds, addu,
+ subs, subu, negs, muls, and mulu intrinsics.
+
+2015-06-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_DMD_H): Remove.
+ (D_TREE_H): Likewise.
+ (CFLAGS-d/d-spec.o): Declare extra CFLAGS for building driver.
+ (d-warn): Declare default warning flags for compiler.
+ (D_DMD_OBJS): Remove 'dmd' from the object file suffix.
+ (D_GLUE_OBJS): Remove 'cglue' and 'glue' from object file suffix.
+ (D_GENERATED_OBJS): Remove 'gen' from the object file suffix.
+ (D_BORROWED_C_OBJS): Remove.
+ (CFLAGS-d/id.o): Declare extra CFLAGS for building generated sources.
+ (CFLAGS-d/impcnvtab.o): Likewise.
+ * types.cc (TypeVisitor::visit (TypeClass)): Build a pointer type for
+ classes, not a reference type.
+ * types.cc (TypeVisitor::visit (TypeDelegate)): Don't build a
+ METHOD_TYPE for delegates, as that requires knowing the underlying
+ record type for the 'this' object parameter.
+ (TypeVisitor::visit (TypeEnum): Don't call rest_of_type_compilation.
+ (TypeVisitor::visit (TypeClass): Likewise.
+ (TypeVisitor::visit (TypeStruct): Likewise.
+ * d-decls.cc (TypeInfoDeclaration::toSymbol): Assert class is a pointer
+ type, not a reference type.
+ (FuncDeclaration::toSymbol): Don't convert nested functions into a
+ METHOD_TYPE to be strictly compatible with delegates.
+ * d-codegen.cc (convert_for_argument): Use correct accessors for array
+ .ptr and .length properties.
+ (expand_intrinsic_vaarg): Don't remove the va_list pointer reference,
+ as the backend now assumes this is what the front-end sets up.
+ (d_build_call): Remove assert as delegates and nested functions are no
+ longer represented as METHOD_TYPE.
+ (build_vthis_type): New function.
+ (d_decl_context): Don't set static/__gshared declaration context as
+ anything other than the enclosing module of the declaration.
+ * toir.cc (IRVisitor::visit (ExtAsmStatement)): Support named labels by
+ calling resolve_asm_operand_names.
+ * d-builtins.cc (d_backend_init): Remove.
+ (d_backend_term): Remove.
+ * d-lang.cc (d_write_global_declarations): Remove langhook.
+ (d_init): Move d_backend_init implementation here.
+ (d_parse_file): Move d_write_global_declarations implementation here.
+ (d_finish_compilation): Remove calls to finalize_compilation_unit,
+ check_global_declarations, and emit_debug_global_declarations.
+ (d-system.h): Remove file. Move all includes into local sources.
+
+2015-06-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_build_call): Only apply CALL_EXPR_RETURN_SLOT_OPT to
+ calls returning an aggregate.
+ (expand_intrinsic): Use CALL_EXPR_FN and CALL_EXPR_ARG directly.
+ (layout_aggregate_type): Update signature.
+ (insert_aggregate_field): Likewise.
+ (finish_aggregate_type): Likewise.
+ * d-codegen.h (AggLayout): Remove helper class.
+ (AddrOfExpr): Remove helper class.
+ (CallExpr): Remove helper class.
+ * d-elem.cc (InExp::toElem): Use build_address directly.
+ (CatAssignExp::toElem): Likewise.
+ (IndexExp::toElem): Likewise.
+ (RemoveExp::toElem): Likewise.
+ * types.cc (TypeVisitor::visit (TypeFunction)): Only apply
+ TREE_ADDRESSABLE to function types returning an aggregate.
+ (TypeVisitor::visit (TypeStruct)): Update for layout_aggregate_type and
+ finish_aggregate_type changes.
+ (TypeVisitor::visit (TypeClass)): Likewise.
+
+2015-06-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (setup_symbol_storage): Mark declarations as private or
+ protected for the benefit of debug code.
+ * d-elem.cc (ArrayLiteralExp::toElem): Only set a value at the given
+ index in the array constructor if it is non-zero.
+ (AssignExp::toElem): Use memset it assigning/initialising an array with
+ all zeroes.
+ (IndexExp::toElem): Simplify codegen to use a placeholder variable for
+ the dollar length.
+ (SliceExp::toElem): Likewise.
+ * d-codegen.cc (ArrayScope): Remove helper class.
+ * Make-lang.in (cc1d$(exeext)): Use link mutex.
+
+2015-05-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_GLUE_OBJS): Rename d-ctype.cc to types.cc.
+ (d-spec.o): Rename d-spec.cc to d-spec.c
+ * types.cc (build_ctype): New function.
+ (Type::toCtype): Convert toCtype methods to use Visitor interface.
+
+2015-04-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_GLUE_OBJS): Add d-attribs.o. Remove d-gt.o.
+ * d-attribs.c: New file.
+ * d-builtins.cc: Move attribute handler functions to d-attribs.c
+ * d-lang.cc: Likewise. Added include for gtype-d.h from d-gt.cc.
+ * d-gt.cc: Remove file.
+
+2015-04-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc, d-convert.cc, d-ctype.cc, d-decls.cc, d-elem.cc,
+ d-glue.cc, d-incpath.cc, d-irstate.cc, d-longdouble.cc, d-port.cc,
+ d-target.cc, d-typinf.cc, toir.cc: Re-order included headers.
+ * d-codegen.h, d-dmd-gcc.h, d-irstate.h, d-lang.h, d-objfile.cc,
+ d-system.h: Remove all includes from headers.
+ * d-codegen.cc: Re-order included headers.
+ (build_attributes): Use ctfeInterpret instead of optimize.
+ * d-lang.cc: Re-order included headers.
+ (d_init_options): Don't use tristate enum for flag_emit_templates.
+ (d_handle_option): Likewise.
+ * d-objfile.cc: Re-order included headers.
+ (output_declaration_p): Update check for flag_emit_templates.
+ (setup_symbol_storage): Likewise.
+ * d-todt.cc: Re-order included headers.
+ (ExpInitializer::toDt): Use ctfeInterpret instead of optimize.
+ (TypeInfoTupleDeclaration::toDt): Likewise.
+
+2015-04-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_exception_object): Remove.
+ * runtime.def (BEGIN_CATCH): Declare runtime function __gdc_begin_catch.
+ * toir.cc (IRVisitor::visit::TryCatchStatement): Use LIBCALL_BEGIN_CATCH
+ to get the correct exception object for handler.
+
+2015-04-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_build_call): Set CALL_EXPR_RETURN_SLOT_OPT on calls to
+ functions that return an aggregate or array that returns in memory.
+ (build_memref): New function.
+ (get_object_method): Use build_memref instead of building a
+ POINTER_PLUS_EXPR for vtable dereferences.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Support NRVO on
+ ARRAY_TYPE's that may not return in registers.
+ * d-ctype.cc (TypeFunction::toCtype): Don't mark TREE_ADDRESSABLE when
+ returning non-POD types by reference.
+
+2015-04-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (EnumDeclaration::toDebug): Remove.
+ (ClassDeclaration::toDebug): Remove.
+ (StructDeclaration::toDebug): Remove.
+ * d-ctype.cc (TypeEnum::toCtype): Call rest_of_type_compilation here.
+ (TypeClass::toCtype): Likewise.
+ (TypeStruct::toCtype): Likewise.
+
+2015-04-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (get_decl_tree): Check and generate correct code for when
+ a non-local 'this' is accessed through a closure pointer.
+ (FuncDeclaration::toObjFile): Remove check for _arguments.
+ * d-codegen.cc (build_local_var): Likewise.
+
+2015-04-11 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-objfile.cc (setup_symbol_storage): Mark functions without
+ body as DECL_EXTERNAL.
+
+2015-04-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_decl_tree): Get correct non-local 'this' decl by
+ constructing component reference through parent link of nested classes.
+ * d-builtins.cc (DEF_FUNCTION_TYPE_VAR_8): Remove.
+ (DEF_FUNCTION_TYPE_VAR_12): Likewise.
+ (DEF_FUNCTION_TYPE_VAR_7, DEF_FUNCTION_TYPE_VAR_11): New macros.
+
+2015-04-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (output_declaration_p): Remove check for semanticRun.
+ (FuncDeclaration::toObjFile): Name bool parameter force_p, allow it to
+ override the initial output_declaration_p check. Force run all
+ semantic passes for symbols that it routine is generating code for.
+ (d_finish_function): Don't mark TREE_STATIC on functions that are
+ really DECL_EXTERN.
+ (finish_thunk): Force thunks referencing external methods to be
+ expanded to gimple.
+ * d-decls.cc (FuncDeclaration::toThunkSymbol): Call toObjFile on all
+ thunk target functions.
+
+2015-04-05 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_handle_section_attribute): New function.
+ * d-builtins.cc (handle_alias_attribute): Move to d-lang.cc to
+ support attribute(alias) in user code.
+ * d-lang.cc (d_handle_alias_attribute): Ditto.
+ * d-lang.cc (d_handle_weak_attribute): New function.
+ * d-decls.cc (FuncDeclaration::toSymbol): Do not set
+ DECL_DECLARED_INLINE_P prematurely.
+
+2015-03-21 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_init): Add GNU_EMUTLS version.
+ * d-objfile.cc (build_emutls_function): New function.
+ * d-objfile.cc (VarDeclaration::toObjFile): Collect all TLS variables
+ in a module into tlsVars array.
+ * d-objfile.cc (genmoduleinfo): Add reference to __modtlsscan
+ function generated by build_emutls_function to moduleinfo.
+
+2015-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * config-lang.in: Remove lang_requires_boot_languages.
+ * d-incpath.cc (iprefix): Remove global variable.
+ (multilib_dir): Ditto.
+ (prefixed_path): Add iprefix parameter.
+ (add_import_paths): Add iprefix and imultilib parameter.
+ Use cpp_include_defaults to get list of import paths.
+ * d-lang.cc (iprefix_dir): New static variable to cache -iprefix switch.
+ (imultilib_dir): New static variable to cache -imultilib switch.
+ (d_init): Pass iprefix_dir and imultilib_dir to add_import_paths.
+ (d_handle_option): Use new static variables.
+
+2015-02-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc: Remove d-confdef.h header.
+ * d-incpath.cc: Ditto.
+ * d-spec.cc: Ditto.
+
+2015-01-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-incpath.cc (add_phobos_versyms): Remove function.
+ * d-lang.cc (d_init): Remove call to add_phobos_versyms.
+
+2015-01-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (DEF_FUNCTION_TYPE_VAR_8)
+ (DEF_FUNCTION_TYPE_VAR_12): New macros.
+
+2015-01-24 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-builtins.cc (d_build_builtins_module): Mark builtin functions
+ as @nogc.
+
+2015-01-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in: Update for D frontend changes.
+ * d-asmstmt.cc: Remove file.
+ * d-builtins.cc (build_dtype): No longer set struct handle.
+ (d_gcc_paint_type): Move to Target::paintAsType.
+ * d-codegen.cc (convert_expr): No longer call getImpl on associative
+ array conversions. Add case for converting void pointers to delegates.
+ (unhandled_arrayop_p): Remove.
+ (build_two_field_type): Use layout_type instead of building
+ TYPE_STUB_DECL and calling rest_of_decl_compilation.
+ (build_binop_assignment): New function.
+ (libcall_ids): Remove static variable.
+ (get_libcall): New function.
+ (maybe_set_intrinsic): Remove druntime library call handling.
+ (expand_intrinsic_vaarg): Dereference ref va_list parameters.
+ (build_closure): New function.
+ (WrappedExp::WrappedExp): Move to frontend sources.
+ (WrappedExp::toCBuffer): Ditto.
+ * d-codegen.h (LibCallFlag): New enum.
+ (LibCall): Use runtime.def macro to define members.
+ * d-ctype.cc (Type::toCParamtype): Remove function.
+ (TypeTypedef::toCParamtype): Ditto.
+ (TypeClass::toSymbol): Ditto.
+ (TypeFunction::retStyle): Move to retStyle.
+ (TypeSArray::toCParamtype): Ditto.
+ (Type::toSymbol): Ditto.
+ (Type::totym): Ditto.
+ (TypeFunction::totym): Ditto.
+ * d-decls.cc (Dsymbol::toSymbolX): Update for frontend changes.
+ (Dsymbol::toImport): Ditto.
+ (VarDeclaration::toSymbol): Ditto.
+ (FuncDeclaration::toSymbol): Ditto.
+ (InterfaceDeclaration::toSymbol): Use TREE_READONLY instead of
+ (EnumDeclaration::toDebug): Only call rest_of_type_compilation on
+ ENUMERAL_TYPE types.
+ TREE_CONSTANT to declare that the symbol cannot be modified.
+ (ClassDeclaration::toVtblSymbol): Ditto.
+ (AggregateDeclaration::toInitializer): Ditto.
+ (EnumDeclaration::toInitializer): Ditto.
+ (TypedefDeclaration::toInitializer): Remove function.
+ (TypedefDeclaration::toDebug): Ditto.
+ (Dsymbol::cvMember): Remove stub function.
+ (EnumDeclaration::cvMember): Ditto.
+ (FuncDeclaration::cvMember): Ditto.
+ (VarDeclaration::cvMember): Ditto.
+ (TypedefDeclaration::cvMember): Ditto.
+ * d-elem.cc (XorExp::toElem): Remove call to unhandled_arrayop_p.
+ (OrExp::toElem): Ditto.
+ (AndExp::toElem): Ditto.
+ (UshrExp::toElem): Ditto.
+ (ShrExp::toElem): Ditto.
+ (ShlExp::toElem): Ditto.
+ (ModExp::toElem): Ditto.
+ (DivExp::toElem): Ditto.
+ (MulExp::toElem): Ditto.
+ (MinExp::toElem): Ditto.
+ (AddExp::toElem): Ditto.
+ (XorAssignExp::toElem): Ditto.
+ (OrAssignExp::toElem): Ditto.
+ (AndAssignExp::toElem): Ditto.
+ (UshrAssignExp::toElem): Ditto.
+ (ShrAssignExp::toElem): Ditto.
+ (ShlAssignExp::toElem): Ditto.
+ (ModAssignExp::toElem): Ditto.
+ (DivAssignExp::toElem): Ditto.
+ (MulAssignExp::toElem): Ditto.
+ (PowAssignExp::toElem): Ditto.
+ (MinAssignExp::toElem): Ditto.
+ (AddAssignExp::toElem): Ditto.
+ (BinExp::toElemBin): Move to build_binop_assignment.
+ (AssignExp::toElem): Update for frontend changes.
+ (DelegatePtrExp::toElem): New function.
+ (DelegateFuncptrExp::toElem): New function.
+ (DelegateExp::toElem): Update for frontend changes.
+ (FuncExp::toElem): Ditto.
+ (NewExp::toElem): Ditto.
+ (StringExp::toElem): Don't set TREE_READONLY on string literals.
+ (AssocArrayLiteralExp::toElem): Remove codegen rewrite for new
+ associative array implementation.
+ * d-glue.cc (Global::isSpeculativeGagging): Remove function.
+ (Dsymbol::ungagSpeculative): Ditto.
+ (Ungag::~Ungag): Ditto.
+ (Loc::toChars): Update for new column diagnostic support.
+ (Loc::Loc): Ditto.
+ (Loc::equals): Ditto.
+ (error): Ditto.
+ (binary): Remove function.
+ (asmSemantic): New function.
+ (retStyle): New function.
+ (FuncDeclaration::isBuiltin): Rename to isBuiltin.
+ * d-intrinsics.def: Rename to intrinsics.def.
+ * d-irstate.cc (IRState::addExp): Remove old warning to catch statements
+ with no side effects. Now handled in frontend.
+ * d-lang.cc (d_init_options): Update for frontend changes.
+ (d_initialize_diagnostics): Remove function.
+ (d_add_builtin_version): Update for frontend changes.
+ (d_init): Ditto.
+ (d_handle_option): Ditto.
+ (d_post_options): Ditto.
+ (d_parse_file): Ditto.
+ * d-objfile.cc (Nspace::toObjFile): New function.
+ (StructDeclaration::toObjFile): Update for frontend changes.
+ (TypedefDeclaration::toObjFile): Remove function.
+ (TemplateInstance::toObjFile): Update for frontend changes.
+ (TemplateMixin::toObjFile): Ditto.
+ (unnest_function): New function.
+ (output_declaration_p): Update for frontend changes.
+ (FuncDeclaration::toObjFile): Ditto.
+ (FuncDeclaration::buildClosure): Move to buildClosure.
+ (get_linemap): Update for frontend changes.
+ (build_simple_function): Ditto.
+ (build_call_function): Ditto.
+ * d-target.cc (Target::va_listType): New function.
+ (Target::paintAsType): Ditto.
+ * d-todt.cc (dt_container2): Do not set TREE_READONLY on initialisers.
+ (dt_container): Ditto.
+ (ClassReferenceExp::toDt2): Update for C++ class support.
+ (ClassReferenceExp::toInstanceDt): Ditto.
+ (TypeTypedef::toDt): Remove function.
+ (TypeInfoTypedefDeclaration::toDt): Ditto.
+ (TypeInfoAssociativeArrayDeclaration::toDt): Update typeinfo size.
+ (TypeInfoAssociativeArrayDeclaration::toDt): Remove reference to impl
+ field in TypeInfo struct.
+ (TypeInfoStructDeclaration::toDt): Update for frontend changes.
+ * d-typinf.cc (Type::getTypeInfo): Update for frontend changes.
+ (TypeTypedef::getTypeInfoDeclaration): Remove function.
+ (createTypeInfoArray): Remove function.
+ * runtime.def: New file.
+ * toir.cc (IRVisitor::visit::DtorExpStatement): Remove function.
+ (IRVisitor::visit::ExtAsmStatement): Update for frontend changes.
+
+2015-01-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (UshrAssignExp::toElem): Remove integer promotion on left
+ hand side of unsigned right shift expression.
+
+2015-01-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-system.h: Include hash-set.h, machmode.h, vec.h, double-int.h,
+ input.h, alias.h, symtab.h and inchash.h due to flattening of tree.h.
+ * d-gt.cc: Ditto.
+
+2015-01-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.h (build_boolop): Don't eagerly fold comparison expressions.
+
+
+Copyright (C) 2015 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2016 b/gcc/d/ChangeLog-2016
new file mode 100644
index 0000000..dbd7573
--- /dev/null
+++ b/gcc/d/ChangeLog-2016
@@ -0,0 +1,1262 @@
+2016-12-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(VarExp)): Remove type forced conversion.
+
+2016-12-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Handle -ftransition=safe.
+ * lang.opt (ftransition=safe): Add compiler option.
+
+2016-12-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init_options): Initialize hdrStripPlainFunctions.
+ (d_post_options): Add post option handling of flag.
+
+2016-12-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (layout_aggregate_type): Adjust layout of D interfaces.
+ Only add a __vptr field if no base interfaces, don't add __monitor.
+
+2016-12-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_parse_file): Run runDeferredSemantic2 after semantic2.
+
+2016-12-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(ArrayLiteralExp)): Use getElement to
+ index elements array.
+ (ExprVisitor::visit(VectorExp)): Likewise.
+
+2016-12-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_DMD_OBJS): Add d/objc.o
+ * types.cc (TypeVisitor::visit(TypeFunction)): Handle ObjC linkage.
+
+2016-12-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (mangle_decl): New function.
+ (make_internal_name): Update.
+ (get_symbol_decl): Update.
+
+2016-12-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::needs_dtor): New function.
+ (ExprVisitor::lvalue_p): New function.
+ (ExprVisitor::visit(AssignExp)): Check both for postblit and dtors
+ when generating array assignments.
+
+2016-12-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (convert_expr): Allow upcasting C++ classes.
+ (build_class_instance): Generate initial values of vtable interfaces
+ before class fields.
+ (layout_aggregate_type): Layout vtable interfaces before class fields.
+ * d-decls.cc (get_symbol_decl): Build DECL_ARGUMENTS for functions
+ that have no body.
+
+2016-12-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc (Target::cppExceptions): New variable.
+ (Target::init): Initialize it.
+ (Target::prefixName): New function.
+
+2016-12-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (ClassDeclaration::toObjFile): Use layout_classinfo to
+ generate TypeInfo for classes.
+ (InterfaceDeclaration::toObjFile): Likewise.
+ * d-todt.cc (build_vptr_monitor): Remove function.
+ * typeinfo.cc (TypeInfoVisitor::set_field): New function.
+ (TypeInfoVisitor::layout_interfaces): New function.
+ (TypeInfoVisitor::layout_interface_vtables): New function.
+ (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Implement.
+ (layout_classinfo): New function.
+
+2016-12-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * typeinfo.cc (TypeInfoVisitor): Use build_typeinfo instead of
+ get_typeinfo_decl.
+ * d-objfile.cc (ClassDeclaration::toObjFile): Use build_constructor to
+ build the vtable, instead of using dt_cons.
+
+2016-12-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (layout_moduleinfo_fields): Use finish_aggregate_type
+ instead of layout_type.
+ (layout_classinfo_interfaces): Likewise.
+
+2016-12-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_dtype): Use static create method for allocating
+ frontend types.
+ * d-codegen.cc (declaration_type): Likewise.
+ (type_passed_as): Likewise.
+ (get_libcall): Likewise.
+ * d-lang.cc (d_parse_file): Likewise.
+ * d-objfile.cc (build_simple_function_decl): Likewise.
+ (build_emutls_function): Likewise.
+ * d-todt.cc (StructDeclaration::toDt): Likewise.
+ * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoInterfaceDeclaration)):
+ Likewise.
+
+2016-12-17 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-decls.cc (copy_struct): Also copy and update TYPE_METHODS.
+ * d-spec.c (lang_specific_driver): Do not link in math, thread and
+ time libraries. Use a spec file instead to do this.
+ (lang_specific_pre_link): Load libgphobos.spec to set up the link
+ dependencies for libgphobos.
+
+2016-12-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_dtype): Cache all allocated frontend types.
+ (builtin_sym): Update constructor.
+ (builtin_converted_decls): Rename to builtin_converted_syms.
+ (d_build_builtins_module): Check if decl set before assigning parent.
+
+2016-12-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_dtype): Set type modifiers on frontend type.
+
+2016-12-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_dtype): Don't set default parameter storage
+ class as const.
+
+2016-12-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (add_moduleinfo_field): New function.
+ (layout_moduleinfo_fields): New function.
+ (get_moduleinfo_decl): Use record type for moduleinfo decl.
+ * d-objfile.cc (build_moduleinfo_symbol): Delay calling
+ get_moduleinfo_decl until after ModuleInfo type is validated.
+ (d_finish_symbol): Remove check for unknown_type_node.
+
+2016-12-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (copy_struct): New function.
+ (layout_classinfo_interfaces): New function.
+ (get_classinfo_decl): Use record type for classinfo decl.
+ * d-codegen.cc (create_field_decl): New function.
+ Use it instead of build_decl when creating a new FIELD_DECL.
+
+2016-12-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_dtype): Don't build generic function types.
+ (d_build_builtins_module): Remove check.
+
+2016-12-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_vindex_ref): Move saving of object to callers.
+ * expr.cc (ExprVisitor::visit(CallExp)): Save object reference before
+ passing to build_vindex_ref.
+ (ExprVisitor::visit(DelegateExp)): Likewise.
+
+2016-12-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.c (lang_specific_driver): Remove error handling.
+ * d-lang.cc (d_parse_file): Don't error twice.
+
+2016-12-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.c (lang_specific_driver): Remove 'added' variable.
+
+2016-12-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (get_symbol_decl): Use needsCodegen to determine whether
+ template instance is extern or not.
+
+2016-12-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-glue.cc (escapePath): Move to dfrontend.
+ (readFile): Likewise.
+ (writeFile): Likewise.
+ (ensurePathToNameExists): Likewise.
+
+2016-12-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc: Include memmodel.h.
+ * d-attrib.c (d_handle_section_attribute): No longer set
+ user_defined_section_attribute.
+
+2016-11-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc (TypeVisitor::visit(Type)): Update.
+
+2016-11-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_struct_literal): Stop after first field
+ assignment in union constructor.
+ (build_class_instance): Skip void initialized fields.
+ * expr.cc (ExprVisitor::visit(StructLiteralExp)): Likewise.
+
+2016-11-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (get_symbol_decl): Don't set alignment if
+ STRUCTALIGN_DEFAULT.
+
+2016-11-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-todt.cc (ClassDeclaration::toDt): Update.
+ (ClassDeclaration::toDt2): Remove function.
+ (TypeSArray::toDtElem): Remove function.
+ (dt_chainon): Remove function.
+ (dt_zeropad): Remove function.
+ (dt_container): Remove function.
+ (dt_container2): Rename to dt_container. All callers updated.
+ * d-objfile.cc (VarDeclaration::toObjFile): Update.
+
+2016-11-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (copy_lang_decl): Rename to d_dup_lang_specific_decl.
+ (LANG_HOOKS_DUP_LANG_SPECIFIC_DECL): Redefine.
+ * d-decls.cc (make_alias_for_thunk): Call dup_lang_specific_decl.
+ (make_thunk): Likewise.
+
+2016-11-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.h (FuncFrameInfo): Remove type. All users updated to
+ interface with new frame macro accessors.
+ (build_frame_type): Mark as static.
+ (get_frameinfo): Update to return a tree type.
+ * d-lang.cc (LANG_HOOKS_TREE_SIZE): Redefine.
+ (LANG_HOOKS_PRINT_XNODE): Redefine.
+ (d_tree_size): New function.
+ (d_print_xnode): New function.
+ (d_tree_node_structure): New function.
+ * d-tree.def (FUNCFRAME_INFO): New tree_code.
+ * d-tree.h (tree_frame_info): New type.
+ (FRAMEINFO_CREATES_FRAME): New macro accessor.
+ (FRAMEINFO_STATIC_CHAIN): New macro accessor.
+ (FRAMEINFO_IS_CLOSURE): New macro accessor.
+ (FRAMEINFO_TYPE): New macro accessor.
+ (lang_decl): Replace frame_info field with a tree type.
+ (d_tree_node_structure_enum): New type.
+ (lang_tree_node): Update GTY tags.
+
+2016-11-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (setup_symbol_storage): Remove function.
+ (Dsymbol::toSymbol): Remove function and all overrides. All callers
+ updated to call ...
+ (get_symbol_decl): ... New function.
+
+2016-11-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (output_modules): Remove variable.
+ (output_module): Remove variable.
+ (d_gcc_get_output_module): Remove function. All callers updated to
+ use Module::rootModule.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Mark all functions being
+ constructed here as TREE_STATIC.
+ (output_module_p): Remove function. All callers updated to call
+ Module::isRoot.
+
+2016-11-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (get_template_storage_info): Remove function.
+ (setup_symbol_storage): Use Dsymbol::isInstantiated instead.
+
+2016-11-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_struct_literal): Handle anonymous fields.
+ (build_class_instance): New functions.
+ (find_aggregate_field): Update signature. All callers updated.
+ * d-todt.cc (dt_chainon): Mark as static.
+ (dt_zeropad): Likewise.
+ (dt_container): Likewise.
+ (ClassReferenceExp::toInstanceDt): Remove function.
+ (ClassReferenceExp::toDt2): Remove function.
+
+2016-11-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (lang_decl): Remove readonly field.
+ (DECL_LANG_READONLY): Remove macro. All callers updated.
+
+2016-10-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (ClassReferenceExp::toSymbol): Use class record type for
+ static symbol.
+ * d-lang.cc (global_context): New static variable.
+ (global_declarations): New static variable.
+ (d_nametype): Pass built-in types to debug_hooks::type_decl.
+ (d_add_global_declaration): Remove function, update all callers.
+ (get_global_context): New function.
+ (d_pushdecl): Push decls to global, or bindings list here.
+ (StructDeclaration::toObjFile): Send type decl to d_pushdecl.
+ (ClassDeclaration::toObjFile): Likewise.
+ (InterfaceDeclaration::toObjFile): Likewise.
+ (EnumDeclaration::toObjFile): Likewise.
+ (FuncDeclaration::toObjFile): Send finished decl to d_pushdecl.
+ (d_finish_symbol): Likewise.
+ (emit_modref_hooks): Likewise.
+ (d_comdat_linkage): Don't set DECL_COMDAT on non-public decls.
+ (setup_symbol_storage): Don't set DECL_ABSTRACT_P on templates.
+ (d_finish_compilation): Remove check for type decls.
+ (build_type_decl): Don't add to global decl list, just call
+ rest_of_decl_compilation.
+ * expr.cc (ExprVisitor::visit(ArrayLiteralExp)): Send finished decl to
+ d_pushdecl.
+ * toir.cc (IRVisitor::visit(SwitchStatement)): Likewise.
+ (IRVisitor::end_scope): Mark bind expr as having side effects.
+ * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoTupleDeclaration)): Send
+ finished decl to d_pushdecl.
+
+2016-10-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (layout_aggregate_type): Continue searching based on
+ aggregate members, not just fields.
+ * types.cc (TypeVisitor::visit(TypeEnum)): Use void for opaque enums.
+ (TypeVisitor::visit(TypeStruct)): Don't give opaque structs a size.
+
+2016-10-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(AssignExp)): Don't set TREE_ADDRESSABLE.
+ * d-codegen.cc (build_assign): Handle setting up INIT_EXPR from a
+ value returning via NRVO here instead.
+
+2016-10-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_build_call): Only convert CALL_EXPRs into a
+ TARGET_EXPR if return type is TREE_ADDRESSABLE.
+ (build_assign): Use TARGET_EXPR accessors.
+ (compound_expr): Likewise.
+
+2016-10-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.h (d_types_same): Return early if types are identical.
+
+2016-10-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (FuncDeclaration::toThunkSymbol): Rename to make_thunk.
+ All callers updated.
+ (finish_thunk): Update signature.
+
+2016-10-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.h (Thunk): Remove type, move offset field to ...
+ * d-tree.h (lang_decl): ... here. Replace Thunk field with a tree.
+ (THUNK_LANG_OFFSET): New macro accessor.
+ * d-lang.cc (copy_lang_decl): New function.
+ * d-decls.cc (FuncDeclaration::toThunkSymbol): Use new thunk macros.
+
+2016-10-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (finish_thunk): Add assert that current_function_decl is
+ never set when function is called.
+ (DeferredThunk): Remove type.
+ (deferred_thunks): Remove variable.
+ (write_deferred_thunks): Remove function. All callers updated.
+ (use_thunk): Remove function.
+ (FuncDeclaration::toThunkSymbol): Call finish_thunk when done.
+
+2016-10-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (deferred_thunks): Move to d-decls.cc.
+ (write_deferred_thunks): Likewise.
+ (use_thunk): Likewise. Mark as static.
+ (thunk_labelno): Likewise.
+ (make_alias_for_thunk): Likewise.
+ (finish_thunk): Likewise.
+
+2016-10-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (setup_symbol_storage): Remove unused parameters.
+
+2016-10-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (ClassReferenceExp::toSymbol): Rename to
+ build_new_class_expr. All callers updated.
+ (StructLiteralExp::toSymbol): Remove function. Inline into caller ...
+ * expr.cc (ExprVisitor::visit(AddrExpr)): ... here.
+
+2016-10-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (TypeInfoDeclaration::toSymbol): Rename to
+ get_typeinfo_decl. All callers updated.
+ (TypeInfoDeclVisitor): New visitor helper for get_typeinfo_decl.
+ * d-codegen.cc (get_decl_tree): Add check for building typeinfo decls.
+
+2016-10-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (AggregateDeclaration::toInitializer): Rename to
+ aggregate_initializer. All callers updated.
+ (EnumDeclaration::toInitializer): Rename to enum_initializer.
+ (Module::toSymbol): Rename to get_moduleinfo_decl.
+ (ClassDeclaration::toSymbol): Rename to get_classinfo_decl.
+ (InterfaceDeclaration::toSymbol): Merge into get_classinfo_decl.
+
+2016-10-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Remove saving of current
+ module decl before calling semantic.
+ (StructLiteralExp::toSymbol): Don't handle sinit.
+ (ClassReferenceExp::toSymbol): Likewise.
+ (AggregateDeclaration::toInitializer): Likewise.
+ (EnumDeclaration::toInitializer): Likewise.
+ * d-glue.cc (toInitializer): Remove function.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Remove saving of current
+ module decl before calling semantic.
+ * expr.cc (ExprVisitor::visit(CallExpr)): Replace accesses of sinit
+ field with useStaticInit.
+ (ExprVisitor::visit(StructLiteralExp)): Likewise.
+
+2016-10-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (ClassDeclaration::toVtblSymbol): Rename to
+ get_vtable_decl. All callers updated.
+
+2016-10-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (setup_symbol_storage): Move function to ...
+ * d-decls.cc (setup_symbol_storage): ... here. Mark as static.
+ (get_template_storage_info): Likewise.
+
+2016-10-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (call_by_alias_p): Check whether caller and callee are
+ nested in the same parent function.
+ * expr.cc (ExprVisitor::visit(CallExp)): Set TREE_PUBLIC directly
+ instead of calling setup_symbol_storage.
+
+2016-10-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (VarDeclaration::toObjFile): Always generate
+ DECL_INITIAL for all kinds of var decls.
+ * d-codegen.cc (build_address): Use the DECL_INITIAL directly if
+ taking the address of a CONST_DECL.
+
+2016-10-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (DECL_LANG_TREE): Remove macro. All callers updated.
+
+2016-10-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.h (Symbol): Remove struct. Update all functions to return
+ a tree instead. Remove all new allocations of Symbol.
+ * d-tree.h (DECL_LANG_READONLY): Update accessor.
+ (DECL_LANG_INITIAL): Likewise.
+ (DECL_LANG_TREE): Likewise.
+ (SET_DECL_LANG_FRAME_FIELD): Likewise.
+ (DECL_LANG_FRAME_FIELD): Likewise.
+ (SET_DECL_LANG_NRVO): Likewise.
+ (DECL_LANG_NRVO): Likewise.
+ (DECL_LANG_THUNKS): Likewise.
+ (DECL_LANG_FRAMEINFO): Likewise.
+
+2016-10-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.h (Symbol): Remove symbol identifier field.
+ * d-tree.h (DECL_LANG_IDENTIFIER): Remove macro. Update callers to
+ instead use DECL_ASSEMBLER_NAME.
+ (DECL_LANG_PRETTY_NAME): Remove macro.
+
+2016-09-26 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-objfile.cc (d_finish_function): Handle template mixins (issue 231).
+
+2016-09-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (Dsymbol::toSymbolX): Remove function, update all callers
+ to use ...
+ (make_internal_name): ... New function.
+ * d-objfile.h (Symbol): Replace char* fields with tree.
+ * d-tree.h (lang_identifier): Add pretty_ident field.
+ (IDENTIFIER_PRETTY_NAME): New macro accessor.
+ (DECL_LANG_PRETTY_NAME): Update to use IDENTIFIER_PRETTY_NAME.
+
+2016-09-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.h (Symbol): Move declaration-specific fields to ...
+ * d-tree.h (lang_decl): ... here.
+ (DECL_LANG_READONLY): Update to reference lang_decl field.
+ (DECL_LANG_INITIAL): Likewise.
+ (DECL_LANG_FRAME_FIELD): Likewise.
+ (DECL_LANG_NRVO): Likewise.
+ (DECL_LANG_THUNKS): Likewise.
+ (DECL_LANG_FRAMEINFO): Likewise.
+ (SET_DECL_LANG_FRAME_FIELD): New setter macro, update all callers.
+ (SET_DECL_LANG_NRVO): Likewise.
+
+2016-09-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (d_build_builtins_module): Set DECL_LANG_SPECIFIC
+ before using any DECL_LANG accessor macros.
+ (maybe_set_builtin_1): Likewise.
+ * d-codegen.cc (maybe_set_intrinsic): Likewise.
+ (layout_aggregate_members): Likewise.
+ d-decls.cc (VarDeclaration::toSymbol): Likewise.
+ (FuncDeclaration::toThunkSymbol): Likewise.
+ (ClassDeclaration::toSymbol): Likewise.
+ (InterfaceDeclaration::toSymbol): Likewise.
+ (Module::toSymbol): Likewise.
+ (StructLiteralExp::toSymbol): Likewise.
+ (ClassReferenceExp::toSymbol): Likewise.
+ (ClassDeclaration::toVtblSymbol): Likewise.
+ (AggregateDeclaration::toInitializer): Likewise.
+ (EnumDeclaration::toInitializer): Likewise.
+
+2016-09-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (DECL_LANG_IDENTIFIER): New macro accessor, use instead of
+ direct field accesses.
+ (DECL_LANG_PRETTY_NAME): Likewise.
+ (DECL_LANG_READONLY): Likewise.
+ (DECL_LANG_INITIAL): Likewise.
+ (DECL_LANG_TREE): Likewise.
+ (DECL_LANG_FRAME_FIELD): Likewise.
+ (DECL_LANG_NRVO): Likewise.
+ (DECL_LANG_THUNKS): Likewise.
+ (DECL_LANG_FRAMEINFO): Likewise.
+
+2016-09-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * imports.cc (ImportVisitor::visit(ScopeDsymbol)): New visit method.
+
+2016-09-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-todt.cc (ArrayInitializer::toDt): Update to use build_expr.
+ * d-codegen.cc (d_array_value): Don't override default const and
+ static bits for array constructors.
+
+2016-09-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (lower_struct_comparison): Don't compare vectors in the
+ same way as integers.
+
+2016-09-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-todt.cc (Type::toDt): Remove function, inline into callers.
+ (TypeVector::toDt): Likewise.
+ (TypeSArray::toDt): Likewise.
+ (TypeStruct::toDt): Likewise.
+
+2016-09-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (FuncDeclaration::toSymbol): Save current module decl
+ before calling function semantic.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Likewise.
+
+2016-09-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc: Document and reformat file.
+
+2016-09-10 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-objfile.cc (setup_symbol_storage): Setup TREE_PUBLIC before
+ calling decl_default_tls_model.
+ * d-typeinfo.cc (TypeInfoVisitor::find_field): Move method...
+ * d-codegen.cc (find_aggregate_field): here.
+ * d-objfile.cc (build_simple_function): Extract some code into new
+ function.
+ (build_simple_function_decl): Extracted from build_simple_function.
+ * d-objfile.cc (build_moduleinfo): Split into emit_moduleinfo_hooks
+ and emit_modref_hooks.
+ (build_dso_registry_var): New function.
+ (emit_dso_registry_cdtor): Likewise.
+ (emit_dso_registry_helpers): Likewise.
+ (emit_dso_registry_hooks): Likewise.
+ (emit_moduleinfo_hooks): Only emit hooks if required druntime functions
+ are available.
+ * d-objfile.cc (Module::genmoduleinfo): Rename to
+ build_moduleinfo_symbol.
+ (emit_moduleinfo_hooks): rename to Module::genmoduleinfo.
+ (Module::genmoduleinfo): only call build_moduleinfo_symbol when
+ emitting module info registry code.
+ * d-spec.c (lang_specific_driver): Add -shared-libphobos option,
+ default to static libphobos.
+ * d-lang.opt: Likewise.
+ * d-spec.c: Rename libgphobos2 to libgphobos.
+
+2016-07-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_frameinfo): Use hasNestedFrameRefs to determine
+ whether a frame should be created.
+
+2016-07-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (FuncDeclaration::toObjFile): Always convert the
+ DECL_RESULT of NRVO-capable functions into reference decls.
+
+2016-06-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c (handle_nonnull_attribute): Accept the nonnull
+ attribute in type-generic builtins.
+ * d-codegen.cc (d_build_call): Check AGGREGATE_TYPE_P before testing
+ for aggregate_value_p.
+
+2016-06-20 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-lang.cc (d_handle_option): Add new -ftransition=dip25 and
+ -fmax-error-messages switches.
+ * lang.opt: Likewise.
+
+2016-06-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_decl_tree): Remove assert for RESULT_DECL.
+ (convert_for_argument): Handle lazy arguments early.
+ (argument_reference_p): Handle types marked TREE_ADDRESSABLE.
+ (lvalue_p): Add case for TARGET_EXPR.
+ (d_mark_addressable): Likewise.
+ (build_assign): Likewise.
+ (compound_expr): Likewise.
+ (build_target_expr): New function.
+ (d_build_call): Always set CALL_EXPR_RETURN_SLOT_OPT for all calls
+ that return an aggregate in memory.
+ * d-decls.cc (VarDeclaration::toSymbol): Handle reference parameters.
+ * d-lang.cc (d_gimplify_expr): Handle taking address of constructor.
+ * d-objfile.cc (FuncDeclaration::toObjFile): Handle reference return.
+ * expr.cc (ExprVisitor::visit(AssignExp)): Mark LHS as addressable if
+ RHS assignment is a returned aggregate.
+ * types.cc (TypeVisitor::visit(TypeStruct)): Mark the RECORD_TYPE of
+ non-trivial structs as TREE_ADDRESSABLE.
+ (TypeVisitor::visit(TypeClass)): Mark all classes as TREE_ADDRESSABLE.
+ (TypeVisitor::visit(TypeFunction)): Don't set TREE_ADDRESSABLE.
+ (TypeVisitor::visit(TypeDelegate)): Likewise.
+
+2016-06-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (lvalue_p): Add more cases to look for.
+ (build_address): Mark expression as addressable after stabilizing.
+ (d_mark_addressable): Remove special cases.
+ (d_mark_used): Add cases for other kinds of DECLs.
+ (build_struct_comparison): Stabilize before saving.
+ (modify_expr): Remove overload. Updated all callers.
+ (build_vinit): Remove function. Updated all callers to use ...
+ (build_assign): ... New function.
+ (lvalue_p): Remove tests in default case.
+ * expr.cc (build_expr_dtor): Rewrite assignments to elide a temporary.
+
+2016-06-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (make_temp): Rename to d_save_expr.
+ (maybe_make_temp): Remove function.
+ Updated all callers to use d_save_expr().
+ (vcompound_expr): Remove function.
+ Updated all callers to use compound_expr().
+ (maybe_compound_expr): Likewise.
+ (maybe_vcompound_expr): Likewise.
+ (vmodify_expr): Remove function.
+ Updated all callers to use modify_expr().
+ (lvalue_p): New function.
+
+2016-06-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (add_stmt): Don't add statements without side effects.
+ Push each COMPOUND_EXPR as a separate statement.
+ (build_local_temp): Use input_location.
+ (create_temporary_var): Likewise.
+ (d_has_side_effects): Remove function.
+ Updated all callers to use TREE_SIDE_EFFECTS.
+ (stabilize_expr): New function.
+ Updated all routines that check for COMPOUND_EXPR to use it.
+ * expr.cc (ExprVisitor::visit(EqualExp)): Use maybe_make_temp to save
+ expressions. Use build_boolop for constructed conditions.
+ (ExprVisitor::visit(CatAssignExp)): Stabilize RHS before assignment.
+ (ExprVisitor::visit(NewExp)): Don't always create SAVE_EXPR.
+ (ExprVisitor::visit(AssocArrayLiteralExp)): Likewise.
+ (ExprVisitor::visit(ArrayLiteralExp)): Evaluate elements before
+ appending to constructor fields.
+ (ExprVisitor::visit(StructLiteralExp)): Likewise.
+
+2016-06-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-convert.cc (d_build_truthvalue_op): Fold truthvalue operation.
+ (d_truthvalue_conversion): Use zero constant of expression type.
+
+2016-06-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_address): Handle ERROR_MARK and COMPOUND_EXPR.
+ (build_nop): Likewise.
+ (indirect_ref): Likewise.
+ (build_deref): Likewise.
+ (d_build_call): Only create temporaries if more than one argument has
+ side effects.
+ * expr.cc (get_compound_value): Remove function.
+ (build_expr_dtor): Wrap cleanups in a TRY_FINALLY_EXPR only if the
+ expression has side effects.
+
+2016-06-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_GLUE_OBJS): Remove d-typinf.o, add typeinfo.o.
+ * d-codegen.cc (build_typeinfo): Move to ...
+ * typeinfo.cc: ... here. New file.
+ * d-objfile.cc (TypeInfoDeclaration::toObjFile): Use layout_typeinfo.
+ * d-todt.cc (verify_structsize): Remove function.
+ (TypeInfoDeclaration::toDt): Remove function and overrides.
+ * d-typinf.cc: Remove file. Contents moved to typeinfo.cc.
+ * expr.cc (ExprVisitor::visit(DeleteExp)): Use build_typeinfo.
+ (ExprVisitor::visit(NewExp)): Likewise.
+
+2016-06-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dfrontend: Update to D front-end version 2.068.
+ * d-codegen.cc (insert_type_modifiers): Don't build TYPE_QUAL_VOLATILE
+ types. Set TYPE_SHARED instead.
+ (insert_aggregate_field): Propagate TYPE_SHARED to TREE_ADDRESSABLE.
+ (array_bounds_check): Use BOUNDSCHECK interface.
+ * d-lang.cc (d_init_options): Likewise.
+ (d_init): Likewise.
+ (d_handle_option): Likewise.
+ (d_post_options): Likewise.
+ * d-decls.cc (VarDeclaration::toSymbol): Propagate TYPE_SHARED_to
+ TREE_ADDRESSABLE.
+ * d-objfile.cc (ClassDeclaration::toObjFile): Make overload shadowing
+ an error. Remove call to _d_hidden_func.
+ (TypeInfoDeclaration::toObjFile): Updated template emission rules.
+ (FuncDeclaration::toObjFile): Likewise.
+ * d-port.cc (Port::readwordLE): New function.
+ (Port::readwordBE): New function.
+ (Port::readlongLE): New function.
+ (Port::readlongBE): New function.
+ * d-todt.cc (dt_container2): Handle error_mark_node.
+ (dt_container): Likewise.
+ (TypeInfoStructDeclaration::toDt): Updated template emission rules.
+ * d-typinf.cc (genTypeInfo): Likewise.
+ (getTypeInfo): Remove function.
+ (getTypeInfoType): New function.
+ (isSpeculativeType): New function.
+ * d-tree.h (TYPE_SHARED): New macro.
+ * expr.cc (ExprVisitor::visit(CondExp)): Don't generate dtors in
+ condition expression.
+ (ExprVisitor::visit(AssignExp)): Update for frontend changes.
+ (ExprVisitor::visit(DeleteExp)): Likewise.
+ (ExprVisitor::visit(CallExp)): Likewise.
+ (ExprVisitor::visit(DelegateExp)): Likewise.
+ (ExprVisitor::visit(TypeidExp)): New function.
+ * lang.opt (bounds_check_set_manually): Remove variable.
+ (ftransition=complex): New option.
+ * runtime.def (HIDDEN_FUNC): Remove runtime function.
+
+2016-06-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_alignment_field): New function.
+ (build_struct_literal): Update signature, updated all callers.
+ Add anonymous fields to fill alignment holes in constructor.
+ (fill_alignment_field): Remove function.
+ (fill_alignment_holes): Remove function.
+ (finish_aggregate_type): Don't add anonymous fields.
+
+2016-06-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_build_call): Separate parameter to pass from it's
+ construction expression.
+ * expr.cc (build_dtor_list): New function.
+ (get_compound_value): New function.
+ (build_expr_dtor): Update to use helper functions.
+ (build_return_dtor): New function.
+ * toir.cc (IRVisitor::visit(ReturnStatement)): Use it.
+
+2016-06-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_deref): Handle ERROR_MARK nodes early.
+ (build_array_index): Likewise.
+
+2016-05-29 Johannes Pfau <johannespfau@gmail.com>
+
+ * toir.cc (IRVisitor::visit(SwitchStatement)): Set correct type for the
+ string table for switch(string) statements.
+
+2016-05-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (convert_expr): Return empty constructor for null to
+ associative array conversions.
+ * expr.cc (ExprVisitor::visit(NullExp)): Likewise.
+
+2016-05-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_struct_literal): Don't set TREE_STATIC.
+ (build_boolop): Remove side effects from aggregate types only.
+ * expr.cc (ExprVisitor::visit(ArrayLiteralExp)): Don't check
+ initializer_constant_valid_p until after constructor is built.
+ (ExprVisitor::visit(StructLiteralExp)): Likewise.
+
+2016-05-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(AssignExp)): Build the rhs constructor
+ before the lhs declaration.
+ (ExprVisitor::visit(DeclarationExp)): Compile the declaration and
+ initializer before pushing it to vars_in_scope.
+ (build_expr_dtor): Compound all dtors in reverse.
+
+2016-05-16 Johannes Pfau <johannespfau@gmail.com>
+
+ * expr.cc (ExprVisitor::visit(IdentityExp*)): Remove side-effects
+ before comparing two floating point types.
+ * d-codegen.cc (build_struct_comparison): Remove side-effects
+ before comparing two values.
+ (build_boolop): Likewise.
+
+2016-05-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-todt.cc (Expression::toDt): Remove function and all overrides.
+ Update all callers to use build_expr.
+ * expr.cc (ExprVisitor::visit(SymOffExp)): Move check for non-constant
+ expressions in static initializer data to ...
+ (build_expr): ... here.
+ * toir.cc (IRVisitor::visit(SwitchStatement)): Build array of indexes
+ directly using build_artificial_decl.
+
+2016-05-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(IdentityExp*)): Remove side-effects
+ before comparing two dynamic arrays.
+
+2016-05-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_decl_tree): First check if cfun is set.
+ * d-todt.cc (StructLiteralExp::toDt): Update call to build_expr.
+ (SymOffExp::toDt): Likewise.
+ (VarExp::toDt): Likewise.
+ (FuncExp::toDt): Likewise.
+ (VectorExp::toDt): Likewise.
+ * expr.cc (ExprVisitor::visit(SymbolExp)): Remove function.
+ (ExprVisitor::visit(SymOffExp)): New function.
+ (ExprVisitor::visit(VarExp)): New function.
+ (ExprVisitor::visit(StructLiteralExp)): Don't return static
+ initializer symbol if constant literal requested.
+
+2016-05-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_struct_literal): Maybe set TREE_CONSTANT or
+ TREE_STATIC on the returned constructor.
+ Allow building struct literals with initializer list out of order.
+ Add check and error when initializer overlaps previous field.
+ Don't explicitly set empty initializers for anonymous aggregates or
+ artificial fields.
+
+2016-05-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_array_from_val): New function.
+ * expr.cc (ExprVisitor::visit(StructLiteralExp)): Use it.
+
+2016-05-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (convert_expr): Use build_nop to cast between two
+ static arrays of the same size.
+ * d-todt.cc (IntegerExp::toDt): Update call to build_expr.
+ (RealExp::toDt): Likewise.
+ (ComplexExp::toDt): Likewise.
+ (StringExp::toDt): Likewise.
+ (NullExp::toDt): Use build_expr to generate initializer.
+ (ArrayLiteralExp::toDt): Likewise.
+ (CastExp::toDt): Likewise.
+ (ClassReferenceExp::toDt): Likewise.
+ (ClassReferenceExp::toDtI): Remove function.
+ * expr.cc (ExprVisitor::visit(CastExp)): Forward constp to the next
+ leaf expression in the tree.
+ (ExprVisitor::visit(AddrExp)): Likewise.
+ (ExprVisitor::visit(FuncExp)): Likewise.
+ (ExprVisitor::visit(ArrayLiteralExp)): Likewise.
+ (ExprVisitor::visit(StructLiteralExp)): Likewise.
+ (ExprVisitor::visit(VectorExp)): Likewise.
+ (ExprVisitor::visit(ClassReferenceExp)): Adjust reference for constp.
+
+2016-05-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (get_unique_name): Remove function.
+ (build_artificial_decl): New function.
+ (d_finish_symbol): Use build_artificial_decl.
+ (build_moduleinfo): Likewise.
+ * d-decls.cc (StructLiteralExp::toSymbol): Likewise.
+ (ClassReferenceExp::toSymbol): Likewise.
+
+2016-05-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(BinExp)): New function.
+ (ExprVisitor::visit(XorExp)): Remove function.
+ (ExprVisitor::visit(OrExp)): Likewise.
+ (ExprVisitor::visit(AndExp)): Likewise.
+ (ExprVisitor::visit(UshrExp)): Likewise.
+ (ExprVisitor::visit(ShrExp)): Likewise.
+ (ExprVisitor::visit(ShlExp)): Likewise.
+ (ExprVisitor::visit(ModExp)): Likewise.
+ (ExprVisitor::visit(DivExp)): Likewise.
+ (ExprVisitor::visit(MulExp)): Likewise.
+ (ExprVisitor::visit(MinExp)): Likewise.
+ (ExprVisitor::visit(AddExp)): Likewise.
+ (ExprVisitor::visit(BinAssignExp)): New function.
+ (ExprVisitor::visit(XorAssignExp)): Remove function.
+ (ExprVisitor::visit(OrAssignExp)): Likewise.
+ (ExprVisitor::visit(AndAssignExp)): Likewise.
+ (ExprVisitor::visit(ShrAssignExp)): Likewise.
+ (ExprVisitor::visit(ShlAssignExp)): Likewise.
+ (ExprVisitor::visit(ModAssignExp)): Likewise.
+ (ExprVisitor::visit(DivAssignExp)): Likewise.
+ (ExprVisitor::visit(MulAssignExp)): Likewise.
+ (ExprVisitor::visit(PowAssignExp)): Likewise.
+ (ExprVisitor::visit(MinAssignExp)): Likewise.
+ (ExprVisitor::visit(AddAssignExp)): Likewise.
+
+2016-05-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::ExprVisitor): Update signature.
+ (ExprVisitor::visit(AddrExp)): Handle constant expressions.
+ (ExprVisitor::visit(FuncExp)): Likewise.
+ (ExprVisitor::visit(ComplexExp)): Likewise.
+ (ExprVisitor::visit(StringExp)): Likewise.
+ (ExprVisitor::visit(ArrayLiteralExp)): Likewise.
+ (ExprVisitor::visit(StructLiteralExp)): Likewise.
+ (ExprVisitor::visit(NullExp)): Likewise.
+ (ExprVisitor::visit(ClassReferenceExp)): Likewise.
+ (build_expr): Update signature.
+
+2016-05-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_GLUE_OBJS): Add d/expr.o.
+ Remove d/d-elem.o
+ * d-codegen.cc (size_mult_expr): New function.
+ * d-tree.h (build_expr): New function, update all callers to toElem.
+ (build_expr_dtor): New function, update all callers to toElemDtor.
+ * expr.cc: New file.
+ * d-elem.cc: Remove file.
+
+2016-05-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc (Target::init): Target::realpad value should be size
+ minus precision.
+
+2016-04-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (finish_aggregate_type): Use SET_TYPE_ALIGN.
+ * types.cc (TypeVisitor::visit(TypeStruct)): Likewise.
+ * d-decls.cc (ClassDeclaration::toVtblSymbol): Use SET_DECL_ALIGN.
+ * d-objfile.cc (d_finish_symbol): Likewise.
+ * d-target.cc (Target::fieldalign): Likewise.
+
+2016-04-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-todt.cc (TypeSArray::toDtElem): Remove special handling for
+ arrays of vectors.
+
+2016-04-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_dtype): Make function static.
+ * d-lang.cc (d_init_exceptions): Remove function.
+ * d-codegen.h: Move visitor declarations to ...
+ * d-tree.h: ... here.
+ (lang_decl): Remove `d_` prefix from fields.
+ (lang_type): Likewise.
+ * d-lang.cc (build_d_type_lang_specific): Rename to build_lang_type.
+ (build_d_decl_lang_specific): Rename to build_lang_decl.
+ * imports.cc: Update includes.
+
+2016-03-29 Johannes Pfau <johannespfau@gmail.com>
+
+ * d-objfile.cc (d_comdat_linkage): Rewrite template duplicate
+ handling to generate only one backend tree for all duplicates.
+ (FuncDeclaration::toObjFile): Likewise.
+ (VarDeclaration::toObjFile): Likewise.
+ * d-decls.cc (FuncDeclaration::toSymbol): Likewise.
+ (VarDeclaration::toSymbol): Likewise.
+ * d-objfile.cc (get_template_storage_info): Extract function from
+ setup_symbol_storage.
+ (setup_symbol_storage): Likewise.
+ * d-tree.h (lang_identifier): Add field for Dsymbol.
+ (IDENTIFIER_LANG_SPECIFIC): New macro.
+ (IDENTIFIER_DSYMBOL): Likewise.
+
+2016-03-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (fill_alignment_field): Call layout_decl on field.
+ (finish_aggregate_type): Add assertion that TYPE_MODE is equal.
+
+2016-03-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (convert_expr): Replace call build_integer_cst with
+ size_int.
+ (convert_for_assignment): Likewise.
+ (build_struct_comparison): Likewise.
+ (d_assert_call): Likewise.
+ * d-elem.cc (IdentityExp::toElem): Likewise.
+ (AssignExp::toElem): Likewise.
+ (IndexExp::toElem): Likewise.
+ (SymbolExp::toElem): Likewise.
+ (NewExp::toElem): Likewise.
+ (ArrayLiteralExp::toElem): Likewise.
+ (AssocArrayLiteralExp::toElem): Likewise.
+
+2016-03-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (CLASS_TYPE_P): New macro.
+ * d-codegen.cc (build_struct_literal): Check RECORD_OR_UNION_TYPE_P
+ before testing ANON_AGGR_TYPE_P.
+ (fill_alignment_field): New function.
+ (fill_alignment_holes): New function.
+ (finish_aggregate_type): Call fill_alignment_holes before computing
+ backend type mode.
+
+2016-03-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (D_METHOD_CALL_EXPR): Removed `D_' prefix from macro,
+ updated all callers.
+ (D_TYPE_IMAGINARY_FLOAT): Likewise.
+ (D_LABEL_VARIABLE_CASE): Likewise.
+ * d-codegen.cc (build_delegate_cst): Always return valid constructor.
+ (get_object_method): Remove function.
+ (build_vindex_ref): New function.
+ * d-elem.cc (FuncExp::toElem): Use the real function pointer type when
+ converting to delegate.
+ (CallExp::toElem): Handle setting up virtual functions directly.
+ (DelegateExp::toElem): Likewise.
+ (DotVarExp::toElem): Remove handling of virtual functions.
+
+2016-03-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.h (lang_dtype): Remove function.
+ (lang_ddecl): Remove function.
+ * d-tree.h (TYPE_LANG_FRONTEND): New macro, replace all uses of
+ lang_dtype function.
+ (DECL_LANG_FRONTEND): New macro.
+ * d-attribs.c: Update includes.
+ * d-builtins.cc: Likewise.
+ * d-codegen.cc: Likewise.
+ * d-incpath.cc: Likewise.
+ * d-lang.cc: Likewise.
+ * d-objfile.cc: Likewise.
+
+2016-03-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.h (function_type_p): Remove function.
+ * d-codegen.cc (d_build_call): Use FUNC_OR_METHOD_P macro.
+ (build_bounds_condition): Update signature.
+ (d_assert_call): Likewise.
+ (insert_aggregate_field): Likewise.
+ * d-objfile.cc (get_linemap): Likewise.
+ * d-lang.h: Remove file, updated all includes. Moved forward
+ declarations of types and functions to ...
+ * d-tree.h: ... here.
+
+2016-03-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_checked_index): Remove function.
+ (d_bounds_condition): Remove function.
+ (build_bounds_condition): New function.
+ * d-elem.cc (IndexExp::toElem): Use build_bounds_condition.
+ (SliceExp::toElem): Likewise.
+ (EqualExp::toElem): Convert expressions to dynamic arrays when
+ inlining comparison. Don't pass zero length arrays to memcmp.
+
+2016-03-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_array_convert): New function overload.
+ * d-elem.cc (CatExp::toElem): Call new runtime function _d_arraycatnTX
+ when flattening multiple concatenations.
+ (NewExp::toElem): Update call construction for new signatures of
+ runtime functions _d_newarraymTX and _d_newarraymiTX.
+ * runtime.def (NEWARRAYMTX): Update signature.
+ (NEWARRAYMITX): Likewise,
+ (ARRAYCATNT): Remove runtime function.
+ (ARRAYCATNTX): New runtime function.
+
+2016-03-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * imports.cc (ImportVisitor::visit(Declaration)): Don't assume toSymbol
+ method will cache it's result.
+
+2016-03-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dfrontend: Update root library to 2.068.
+ * Make-lang.in (D_DMD_OBJS): Add newdelete.o
+ * d-target.cc (Target::classinfosize): New variable, replaces all uses
+ of global CLASSINFO_SIZE.
+ (Target::init): Initialize it.
+ * d-decls.cc (ClassInfoDeclaration::toSymbol): Remove function.
+
+2016-03-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dfrontend: Update to D front-end version 2.067.
+ * Make-lang.in (D_DMD_OBJS): Add new frontend sources.
+ * d-builtins.cc (d_build_builtins_module): Update signature.
+ (maybe_set_builtin): Rename to d_maybe_set_builtin, update signature.
+ (d_gcc_magic_module): Remove function.
+ * d-codegen.cc (expand_volatile_load): New function.
+ (expand_volatile_store): New function.
+ (expand_intrinsic): Handle volatileLoad and volatileStore intrinsics.
+ * d-decls.cc (Module::toModuleAssert): Remove function.
+ (Module::toModuleUnittest): Remove function.
+ (Module::toModuleArray): Remove function.
+ (TypeAArray::aaGetSymbol): Remove function.
+ * d-elem.cc (AssignExp::toElem): Call _d_arrayassign_{l,r} when
+ generating dynamic array assignment.
+ (IndexExp::toElem): Call _aaGetY when indexing an associative array.
+ (SliceExp::toElem): Use known CTFE result to check whether bounds
+ checks are necessary.
+ (DeleteExp::toElem): Call _d_delstruct when deleting a struct pointer.
+ (Expression::toElemDtor): Don't run cleanup of temporary if it's
+ constructor thrown an exception.
+ (NewExp::toElem): Handle special construction of new() arguments.
+ * d-glue.cc (Loc::Loc): Update signature.
+ (error): Likewise.
+ (toInitializer): New function.
+ * d-lang.cc (d_handle_option): Replace deprecated handlers.
+ (d_post_options): Set flag_max_errors.
+ (d_parse_file): Process any modules marked as builtin.
+ * d-objfile.cc (ClassDeclaration::toObjFile): Don't write out ctors
+ in the vtable marked @disable.
+ * d-target.cc (Target::loadModule): New function.
+ (Target::checkVectorType): New function.
+ * d-specs.c (lang_specific_driver): Handle -v option.
+ * lang-specs.h: Pass -v option to to frontend.
+
+2016-03-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * imports.cc: New file.
+ * d-decls.cc (Dsymbol::toImport): Remove function, update all callers
+ to use build_import_decl.
+
+2016-03-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (gcc_attribute_p): New function.
+ (output_declaration_p): Inline into FuncDeclaration::ObjFile.
+ (unnest_function): Likewise.
+ (FuncDeclaration::toObjFile): Remove named parameter, update all
+ callers to ignore it.
+ (d_comdat_group): Use DECL_ASSEMBLER_NAME for the comdat group.
+ (d_comdat_linkage): Catch duplicate instantiations of templates, put
+ them in the same comdat group.
+ (setup_symbol_storage): Mark templates not to be written as abstract.
+ (d_finish_function): Don't send DECL_ABSTRACT_P functions to backend.
+ (d_finish_compilation): Mark all symbols as needed.
+
+ * d-objfile.cc: Remove redundant bool parameter from all lowering
+ routines for symbols, update all callers.
+
+2016-02-22 Eugene Wissner <belka@caraus.de>
+
+ * d-lang.cc (d_init): Remove short_double parameter from
+ build_common_tree_nodes.
+
+2016-02-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.def: Split signature macros into three groups.
+ Attributes, types, and helper generators.
+ * d-elem.cc (needsPostblit): Change signature to return boolean,
+ updated all callers.
+ (AssignExp::toElem): Don't assign destination to a temporary in
+ arraycopy call.
+ * toir.cc (IRVisior::visit(ThrowStatement)): Use NOP_EXPR cast to
+ convert thrown exception to Object.
+ (IRVisitor::visit(TryCatchStatement)): Use NOP_EXPR cast to convert
+ caught Object to thrown exception.
+ * d-codegen.cc (void_okay_p): Lazily build the convert to type.
+ * d-lang.cc (parse_int): Remove function.
+ (d_handle_option): Use integral_argument to parse numbers.
+
+ * d-codegen.cc (lower_struct_comparison): Built custom type if
+ lang_hooks.types.type_for_mode returns nothing.
+ * d-lang.cc (d_type_for_mode): Always support cent/ucent modes.
+ (d_type_for_size): Add support for cent/ucent precision types.
+ (d_signed_or_unsigned_type): Always support cent/ucent precisions.
+
+ * d-codegen.cc (d_build_call): Remove type promotion handling for
+ variadic arguments.
+ (expand_intrinsic_vaarg): Likewise.
+ * d-lang.cc (d_type_promotes_to): Likewise.
+
+ * d-elem.cc (AddrExp::toElem): Take address of the static const symbol
+ for the struct literal, not the const constructor.
+ (CallExp::toElem): Don't pass generated static struct literal symbol
+ as the object parameter for DotVar call expressions.
+
+ * d-codegen.cc (type_va_array): New function.
+ (declaration_type_kind): Remove function.
+ (declaration_reference_p): New function, update all callers of
+ declaration_type_kind.
+ (argument_type_kind): Remove function.
+ (argument_reference_p): New function, update all callers of
+ argument_type_kind.
+ (build_address): Remove special handling of static array va_list.
+ * d-codegen.h (type_kind): Remove enum.
+
+2016-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_condition): New function. Update all callers
+ that generate a COND_EXPR that returns a value to use it.
+ (build_vcondition): New function. Update all callers that generate a
+ void COND_EXPR to use it.
+ * toir.cc (IRVisitor::visit(DoStatement)): Build a COND_EXPR instead
+ of an EXIT_EXPR to break from the loop.
+ (IRVisitor::visit(ForStatement)): Likewise.
+
+2016-02-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc: Remove redundant IRState parameter from all lowering
+ routines for expressions, update all callers.
+
+2016-02-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_array_set): Use POSTINCREMENT_EXPR to adjust
+ array pointer.
+ (identity_compare_p): New function.
+ (build_struct_memcmp): Refactor into ...
+ (lower_struct_comparison): ... New function.
+ (build_struct_comparison): New function.
+ (build_array_struct_comparison): New function.
+ * d-elem.cc (IdentityExp::toElem): Use build_struct_comparison for
+ RECORD_TYPE values.
+ (EqualExp::toElem): Likewise.
+ Use memcmp for array of structs that pass test for identity_compare_p,
+ or fallback to build_array_struct_comparison.
+ (NewExp::toElem): Remove setting of StructLiteralExp::fillHoles.
+ (StructLiteralExp::toElem): Ignore StructLiteralExp::fillHoles, unless
+ building a union literal.
+
+2016-02-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-elem.cc (AssignExp::toElem): Pass parameters for arraycopy and
+ arrayassign in the correct order.
+
+2016-01-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * longdouble.h (longdouble): Use one contiguous array for the
+ real_value data payload.
+
+2016-01-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * toir.cc (IRVisitor::visit (ExtAsmStatement): Do validation of input
+ and output constraints, marking operands as addressable if requested.
+
+2016-01-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (empty_aggregate_p): New function.
+ (d_build_call): Don't pass empty aggregates by value.
+ (build_struct_memcmp): Don't compare empty aggregates by value.
+ * d-elem.cc (IdentityExp::toElem): Likewise.
+ (EqualExp::toElem): Likewise.
+ * (StructLiteralExp::toElem): Don't create temporaries or initialize
+ holes for empty aggregates.
+ * d-lang.cc (empty_modify_p): New function.
+ (d_gimplify_expr): Remove assignments that involve empty aggregates.
+
+2016-01-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (d_builtin_type): Define DEF_FUNCTION_TYPE_9,
+ DEF_FUNCTION_TYPE_10, and DEF_FUNCTION_TYPE_11.
+ (d_init_builtins): Likewise.
+ * d-longdouble.cc (machineMode): Remove function.
+ (longdouble::init): Don't use initialize real format by reference.
+ (longdouble::operator+): Use real_arithmetic instead of
+ REAL_ARITHMETIC.
+ (longdouble::operator-): Likewise.
+ (longdouble::operator*): Likewise.
+ (longdouble::operator/): Likewise.
+ (longdouble::operator%): Likewise.
+ * d-port.cc (Port::isSignallingNan): Use REAL_VALUE_ISSIGNALING_NAN.
+ (Port::fequal): Use real_identical instead of REAL_VALUES_IDENTICAL.
+ * d-target.cc: Include stor-layout.h header.
+ * lang.opt: Remove documentation for switches defined elsewhere.
+
+2016-01-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_libcall): Use set_call_expr_flags to apply runtime
+ function attributes.
+ * d-codegen.h (LibCallFlag): Remove type.
+ * runtime.def: Replace LibCallFlag with ECF everywhere.
+
+
+Copyright (C) 2016 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/ChangeLog-2017 b/gcc/d/ChangeLog-2017
new file mode 100644
index 0000000..4f64c31
--- /dev/null
+++ b/gcc/d/ChangeLog-2017
@@ -0,0 +1,1175 @@
+2017-12-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.def (INTRINSIC_MULUI): Declare.
+
+2017-12-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_target_expr): Update signature.
+ (force_target_expr): New function.
+ (build_address): Use force_target_expr to store temporary.
+ (d_build_call): Likewise.
+ * d-lang.cc (d_gimplify_expr): Likewise.
+ * d-tree.h (language_function): Update type for vars_in_scope from
+ vec<VarDeclaration*> to vec<tree>.
+ (force_target_expr): Declare.
+ * decl.cc (DeclVisitor::visit(VarDeclaration)): Put vars with scope
+ destructors into a TARGET_EXPR, setting its cleanup.
+ (declare_local_var): Don't push vars with scope destructors into the
+ function binding level.
+ * expr.cc (ExprVisitor::visit(DeclarationExp)): Don't handle scope
+ destructors.
+ (ExprVisitor::visit(CallExp)): Handle calling constructors using
+ temporary objects.
+ (build_dtor_list): Remove function.
+ (build_expr_dtor): Put result into a CLEANUP_POINT_EXPR if any new
+ temporaries needing destruction were added to scope.
+ (build_return_dtor): Likewise.
+ * toir.cc (add_stmt): Set CLEANUP_POINT_EXPR type as void.
+
+2017-12-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c (attr_noreturn_exclusions): New array.
+ (attr_returns_twice_exclusions, attr_const_pure_exclusions): Likewise.
+ (attr_inline_exclusions, attr_noinline_exclusions): Likewise.
+ (d_langhook_common_attribute_table): Swap affects_identity and handler
+ fields. Initialize new member of struct attribute_spec.
+ (d_langhook_attribute_table): Likewise.
+ (handle_weakref_attribute): Remove function.
+
+2017-12-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (stabilize_expr): Handle assignment expressions.
+ (get_frame_for_symbol): Adjust the 'this' field of frames of
+ overridden interface functions.
+ * d-diagnostic.cc (expand_format): Rewrite '%X' format as '%x'.
+ * decl.cc (DeclVisitor::visit(ClassDeclaration)): Handle future
+ attribute.
+ * expr.cc (ExprVisitor::binop_assignment): Ensure RHS is evaluated
+ before LHS.
+ (ExprVisitor::visit(SliceExp)): Always save lower bounds if upper has
+ any side effects.
+ * typeinfo.cc (TypeInfoVisitor::TypeInfoClassDeclaration): Use
+ ClassDeclaration::isAbstract.
+ (TypeInfoVisitor::visit(TypeInfoTupleDeclaration)): Mark internal
+ reference as public and hidden.
+
+2017-12-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_alignment_field): Set DECL_PADDING_P and
+ DECL_FIELD_CONTEXT on generated fields.
+ (build_struct_literal): Use build_zero_cst to generate padding.
+ * decl.cc (build_type_decl): Set public and decl assembler name.
+
+2017-12-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc (TypeVisitor::visit(TypeClass)): Check for duplicate
+ declarations before adding method.
+
+2017-12-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(AddrExp)): Build internal struct literal
+ symbol before generating its initializer.
+
+2017-12-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_parse_file): Set first_global_object_name.
+
+2017-12-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang.opt (fmodule-filepath=): Rename to fmodule-file.
+ * d-lang.cc (d_handle_option): Update case for OPT_fmodule_file_.
+
+2017-12-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (CALL_EXPR_ARGS_ORDERED): Define.
+ * d-codegen.cc (d_build_call): Set CALL_EXPR_ARGS_ORDERED for
+ functions with D linkage.
+ * d-lang.cc (d_gimplify_expr): Handle CALL_EXPR_ARGS_ORDERED.
+
+2017-12-09 Eugene Wissner <belka@caraus.de>
+
+ * toir.cc (IRVisitor::visit(SwitchStatement)): Set SWITCH_ALL_CASES_P on
+ switch statements. Set SWITCH_BREAK_LABEL_P on the artificial label
+ created for break statements from a switch.
+
+2017-12-04 Eugene Wissner <belka@caraus.de>
+
+ * toir.cc (IRVisitor::visit(SwitchStatement)): Build SWITCH_EXPR using build2 instead
+ of build3.
+
+2017-11-14 Eugene Wissner <belka@caraus.de>
+
+ * decl.cc (finish_thunk): Drop frequency argument from
+ symbol_table::create_edge.
+ * d-lang.cc (d_post_options): Set default value of
+ -Wreturn-type to false.
+
+2017-11-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_float_cst): Remove float rounding check.
+ * d-longdouble.cc (longdouble::to_int): Don't round floats before int
+ conversion.
+ * expr.cc (ExprVisitor::binary_op): Handle excess precision.
+ (ExprVisitor::visit(NegExp)): Likwise.
+
+2017-10-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_address): Store CST nodes into a TARGET_EXPR
+ before taking its address.
+
+2017-10-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Remove newdelete.o.
+ * d-incpath.cc (add_globalpaths): Handle NULL target path.
+
+2017-10-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoClassDeclaration)):
+ Properly check base classes for pointers.
+
+2017-09-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(StringExp)): Add extra null terminator
+ onto string type, not the literal.
+
+2017-09-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc (make_array_type): Move checking of void static arrays
+ here.
+
+2017-09-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c: Add include for attribs.h.
+ * d-codegen.cc (copy_aggregate_type): Remove TYPE_METHODS.
+ (lower_struct_comparison): Use opt_scalar_int_mode.
+ * d-target.cc (Target::_init): Use TYPE_MAX_VALUE instead of
+ TYPE_MAXVAL.
+ (Target::isVectorTypeSupported): Update call to
+ scalar_mode_supported_p.
+ * decl.cc (DeclVisitor::visit(Import)): Pass false as new argument to
+ the imported_module_or_decl hook.
+ * types.cc (TypeVisitor::visit(TypeClass)): Remove TYPE_METHODS.
+
+2017-09-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Add blockexit.o, initsem.o,
+ inlinecost.o, safe.o, staticcond.o, and typesem.o.
+ * d-attribs.c (uda_attribute_p): Use get_identifier to compare
+ strings.
+ (build_attributes): Handle empty string expressions.
+ * d-builtins.cc (build_frontend_type): Use static create methods to
+ 'new' front-end types, expressions, and declarations.
+ (d_eval_constant_expression): Likewise.
+ (build_alias_declaration): Likewise.
+ (d_build_builtins_module): Likewise.
+ * d-codegen.cc (declaration_type): Likewise.
+ (type_passed_as): Likewise.
+ (get_frame_for_symbol): Remove dependency on id.h.
+ (get_frameinfo): Don't overwrite FRAMEINFO_CREATES_FRAME if function
+ has nested frame references.
+ * d-convert.cc (convert_for_assignment): Allow static arrays to be
+ initialized with a zero integer value.
+ * d-frontend.cc (genCmain): Remove dependency on id.h.
+ * d-frontend.h (initializerToExpression): Add declaration.
+ (gendocfile): Add declaration.
+ (initTraitsStringTable): Remove.
+ * d-lang.cc (deps_write): Remove dependency on id.h.
+ (deps_add_target): Don't call StringTables's destructor.
+ (d_init): Remove calls to deleted front-end initialize functions.
+ * decl.cc (DeclVisitor::visit(PragmaDeclaration)): Remove dependency
+ on id.h.
+ (DeclVisitor::visit(VarDeclaration)): Call initializerToExpression to
+ get the initializer of decl.
+ (build_decl_tree): Remove dependency on id.h.
+ (layout_class_initializer): Use static create method to 'new'
+ front-end expression.
+ * expr.cc (ExprVisitor::visit(AssignExp)): Handle static array
+ assignment where RHS is integer zero.
+ (ExprVisitor::visit(VarExp)): Remove dependency on id.h.
+ (ExprVisitor::visit(StringExp)): Handle empty string expressions.
+ * modules.cc (get_internal_fn): Use FuncDeclaration::genCfunc to
+ create function decl.
+ (build_module_tree): Remove dependency on id.h.
+ * toir.cc (IRVisitor::visit(ExtAsmStatement)): Handle empty string
+ expressions.
+ * typeinfo.cc (make_frontend_typeinfo): Use static create methods to
+ 'new' front-end declarations.
+ (create_tinfo_types): Remove dependency on id.h.
+ (get_cpp_typeinfo_decl): Likewise.
+ (create_typeinfo): Likewise.
+
+2017-08-23 Johannes Pfau <johannespfau@gmail.com>
+
+ * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoStructDeclaration)): Do
+ not send member functions to backend here.
+
+2017-08-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-convert.cc (convert_expr): Use build_zero_cst for casts from
+ typeof(null).
+
+2017-08-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc (Target::isVectorOpSupported): Disallow vectors in
+ conditional and logical operators.
+
+2017-08-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (maybe_expand_intrinsic): Handle isNaN(), isInfinity()
+ and isFinite() intrinsics.
+ * intrinsics.def: Add INTRINSIC_ISNAN, INTRINSIC_ISINFINITY, and
+ INTRINSIC_ISFINITE.
+
+2017-08-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * intrinsics.cc (expand_intrinsic_popcnt): New function.
+ (maybe_expand_intrinsic): Handle INTRINSIC_POPCNT.
+ * intrinsics.def (INTRINSIC_POPCNT): Declare.
+
+2017-08-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc (isBuiltin): Remove restriction on builtins.
+ (eval_builtin): Check DECL_INTRINSIC_CODE.
+ * d-tree.h (intrinsic_code): Add enum declaration.
+ (lang_decl): Add intrinsic field.
+ (DECL_INTRINSIC_CODE): New macro.
+ (DECL_BUILT_IN_CTFE): New macro.
+ * decls.cc (get_symbol_decl): Initialize DECL_INTRINSIC_CODE.
+ * intrinsics.cc (intrinsic_decl): Add ctfeonly field.
+ (maybe_set_intrinsic): Set frontend builtin flag only if the function
+ is CTFE-able. Set BUILT_IN_FRONTEND if function has no body.
+ (clear_intrinsic_flag): Clear DECL_INTRINSIC_CODE instead of frontend
+ builtin flag.
+ (maybe_expand_intrinsic): Handle INTRINSIC_TAN intrinsics.
+ Call clear_intrinsic_flag on CTFE built-ins if semantic has finished.
+ * intrinsics.def: Add INTRINSIC_TAN.
+ (DEF_D_BUILTIN): New macro.
+ (DEF_CTFE_BUILTIN): New macro.
+
+2017-08-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (DeclVisitor::visit): Don't set input_location.
+ (build_decl_tree): Handle set and restore of input_location.
+ (declare_local_var): Don't set input_location.
+ * expr.cc (build_expr): Handle set and restore of input_location.
+ * imports.cc (build_import_decl): Likewise.
+ * modules.cc (get_dso_registry_fn): Use UNKNOWN_LOCATION for
+ declaration of _d_dso_registry.
+ * runtime.cc (build_libcall_decl): Use UNKNOWN_LOCATION for
+ declaration of library functions.
+ * toir.cc (IRVisitor::visit): Don't set input_location.
+ (IRVisitor::build_stmt): New function.
+ (IRVisitor::do_jump): Update signature.
+ (build_function_body): Use IRVisitor::build_stmt.
+ * typeinfo.cc (layout_classinfo_interfaces): Don't set input_location.
+ * types.cc (layout_aggregate_members): Likewise.
+ (layout_aggregate_type): Likewise.
+
+2017-08-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_boolop): Handle VECTOR_TYPE comparisons.
+ * d-target.cc (Target::checkVectorType): Rename to
+ Target::isVectorTypeSupported.
+ (Target::isVectorOpSupported): New function.
+ * expr.cc (ExprVisitor::visit(IdentityExp)): Don't memcmp floating
+ point vectors.
+ (ExprVisitor::visit(CmpExp)): Handle always true or always false
+ vector comparisons.
+
+2017-08-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * typeinfo.cc (SpeculativeTypeVisitor::visit(TypeClass)): Don't emit
+ typeinfo for speculative class types.
+
+2017-07-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (build_lang_decl): Handle compiler generated typeinfo that
+ also appear in code.
+ * d-tree.h (lang_identifier): Add decl_tree.
+ (IDENTIFIER_DECL_TREE): New macro.
+ * decl.cc (declare_extern_var): Re-use already generated decl if
+ called with the same identifier twice.
+
+2017-07-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (d_finish_decl): Replace ENABLE_TREE_CHECKING macro with
+ flag_checking.
+
+2017-07-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (D_DECL_ONE_ONLY): Remove macro accessor.
+ * decl.cc (DeclVisitor::visit(StructDeclaration)): Move call to
+ d_comdat_linkage here.
+ (DeclVisitor::visit(ClassDeclaration)): Likewise.
+ (DeclVisitor::visit(InterfaceDeclaration)): Likewise.
+ (DeclVisitor::visit(EnumDeclaration)): Likewise.
+ (get_symbol_decl): Move call to mark_needed here.
+ (declare_extern_var): Mark compiler generated symbols as needed.
+ (make_thunk): Remove copy of D_DECL_ONE_ONLY.
+ (get_vtable_decl): Don't call d_comdat_linkage.
+ (aggregate_initializer_decl): Likewise.
+ (enum_initializer_decl): Likewise.
+ * modules.cc (d_finish_compilation): Don't call mark_needed.
+ * typeinfo.cc (get_classinfo_decl): Don't call d_comdat_linkage.
+
+2017-07-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.c (lang_specific_driver): Always add `-o' option when
+ compiling D sources.
+
+2017-07-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc (genCmain): Don't error if entrypoint not found.
+
+2017-07-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_types_compatible_p): Check that both types are
+ RECORD_TYPE before using record-specific flag comparison.
+
+2017-07-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (d_build_d_type_nodes): Set TYPE_DYNAMIC_ARRAY on
+ array_type_node.
+ * d-codegen.cc (build_delegate_cst): Set TYPE_DELEGATE on internal
+ delegate constant types.
+ * d-frontend.h (cppTypeInfoMangle): Remove declaration.
+ (toCppMangleItanium): Add declaration.
+ (cppTypeInfoMangleItanium): Add declaration.
+ * d-lang.cc (d_types_compatible_p): Use type flags to determine
+ compatibility. Return false instead of doing size comparison.
+ * d-target.cc (Target::toCppMangle): New function.
+ (Target::cppTypeInfoMangle): New function.
+ (Target::cppTypeMangle): New function.
+ (Target::systemLinkage): New function.
+ * d-tree.h (TYPE_DYNAMIC_ARRAY): New macro.
+ (TYPE_DELEGATE): New macro.
+ (TYPE_ASSOCIATIVE_ARRAY): New macro.
+ * typeinfo.cc (layout_cpp_typeinfo): Use Target::cppTypeInfoMangle.
+ * types.cc (TypeVisitor::visit(TypeDArray)): Set TYPE_DYNAMIC_ARRAY.
+ (TypeVisitor::visit(TypeAArray)): Set TYPE_ASSOCIATIVE_ARRAY.
+ (TypeVisitor::visit(TypeDelegate)): Set TYPE_DELEGATE.
+
+2017-07-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc (Target::loadModule): Check module identifier if a
+ declaration doesn't exist.
+ * typeinfo.cc (make_frontend_typeinfo): Use module location instead if
+ a declaration doesn't exist.
+
+2017-06-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc (CTFloat::hash): New function.
+
+2017-06-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_array_string): Remove function.
+ (d_assert_call): Inline implementation of d_array_string here.
+ * d-tree.h (d_array_string): Remove declaration.
+ * typeinfo.cc (TypeInfoVisitor::layout_string): New function.
+ (TypeInfoVisitor::visit): Update calls to d_array_string to use
+ layout_string instead.
+
+2017-06-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * toir.cc (IRVisitor::visit(ExtAsmStatement)): Set ASM_VOLATILE_P only
+ if statement is not marked with pure attribute.
+
+2017-06-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_parse_file): Print all predefined version identifiers
+ if verbose.
+
+2017-06-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-frontend.cc (Global::_init): Remove memset for global.params.
+
+2017-06-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_ALL_OBJS): Add D_TARGET_OBJS.
+ * d-builtins.cc (d_add_builtin_version): Move here from d-lang.cc.
+ (d_init_versions): New function.
+ * d-lang.cc (d_init): Call d_init_versions.
+ * d-target-def.h: New file.
+ * d-target.cc (Target::critsecsize): Replace with call to
+ targetdm.critsec_size.
+ * d-target.def: New file.
+ * d-target.h: New file.
+ * d-tree.h (d_init_versions): Add declaration.
+
+2017-06-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(BinAssignExp)): Strip promotions from
+ both signed and unsigned rshift assignments.
+
+2017-06-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-diagnostic.cc (expand_format): New function.
+ (d_diagnostic_report_diagnostic): New function.
+ (error, verror): Update format attributes. Use function
+ d_diagnostic_report_diagnostic instead of xvasprintf.
+ (errorSupplemental, verrorSupplemental): Likewise.
+ (warning, vwarning): Likewise.
+ (warningSupplemental, vwarningSupplemental): Likewise.
+ (deprecation, vdeprecation): Likewise.
+ (deprecationSupplemental, vdeprecationSupplemental): Likewise.
+
+2017-06-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(AssertExp)): Don't call invariant on
+ interface objects.
+
+2017-06-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(DelegateExp)): Convert object to right
+ type before using it.
+
+2017-06-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (get_decl_tree): Find the first parent member function
+ before constructing non-local `this' decl.
+
+2017-06-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (build_frontend_type): Allow all vector types to be
+ included in builtins module.
+
+2017-06-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * types.cc (TypeVisitor::visit(TypeStruct)): Let struct alignment
+ override the alignsize.
+
+2017-06-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_decl_context): Use origin template declaration as
+ context for instantiated type symbols.
+
+2017-06-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c (d_handle_weak_attribute): Use quoted string format.
+ * decls.cc (finish_thunk): Update call to create_edge for new API.
+
+2017-06-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(StringExp)): Create string type that is
+ same length as string value literal.
+
+2017-05-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Rename object.o to rootobject.o.
+
+2017-05-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc: Remove include for dumpfile.h.
+ (finish_function): Use dump_function to for dumping original ASTs.
+
+2017-05-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * config-lang.in (gtfiles): Add typeinfo.cc.
+ * d-codegen.cc (d_build_call_list): Remove function.
+ (d_build_call_nary): Remove function.
+ (build_binary_op): Remove function.
+ (build_binop_assignment): Remove function.
+ (build_vthis_type): Rename to build_vthis_function.
+ (create_field_decl): Move to decl.cc.
+ * d-lang.cc (genCmain): Moved to d-frontend.cc.
+ (builtin_modules): Declare static.
+ (d_add_builtin_module): New function.
+ (d_add_entrypoint_module): New function.
+ * expr.cc (ExprVisitor::binary_op): New function.
+ (ExprVisitor::binop_assignment): New function.
+ * intrinsic.cc (expand_intrinsic): Rename to maybe_expand_intrinsic.
+ * runtime.cc (build_libcall): Updated signature.
+ * types.cc (make_two_field_type): Remove function.
+ (make_struct_type): New function.
+
+2017-05-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_OBJS): Add intrinsics.o and runtime.o.
+ * d-codegen.h: Remove file.
+ * intrinsics.cc: New file.
+ * runtime.cc: New file.
+
+2017-05-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc: Remove include for d-dmd-gcc.h.
+ * d-dmd-gcc.h: Rename to d-frontend.h. Update all includes.
+ * d-frontend.cc (Global::_init): Remove unnecessary initialization.
+ * expr.cc: Remove include for d-dmd-gcc.h.
+
+2017-05-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c (handle_sentinel_attribute): Remove function.
+ (ignore_attribute): Remove function.
+ (d_langhook_common_attribute_table): Remove sentinel and tm regparm
+ from common attribute table.
+ (d_langhook_format_attribute_table): Remove variable.
+ * d-lang.cc (LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE): Remove macro.
+ (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Remove macro.
+ (d_post_options): Don't set flag_unit_at_a_time.
+ (d_nametype): Remove function.
+ * types.cc (TypeVisitor::visit(TypeBasic)): Set TYPE_NAME.
+ (TypeVisitor::visit(TypeVector)): Likewise.
+
+2017-05-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_OBJS): Remove d-objfile.o. Add modules.o.
+ * d-codegen.cc (get_linemap): Move function here.
+ * d-objfile.cc: Remove file.
+ * d-objfile.h: Remove header.
+ * d-tree.h (GDC_PREFIX): New macro.
+ * decl.cc (make_internal_name): Rename to mangle_internal_decl.
+ (DeclVisitor): Move class here.
+ (gcc_attribute_p): Move function here.
+ (build_decl_tree): Likewise.
+ (d_finish_decl): Likewise.
+ (start_function): Likewise.
+ (finish_function): Likewise.
+ (mark_needed): Likewise.
+ (base_vtable_offset): Likewise.
+ (build_artificial_decl): Likewise.
+ (build_type_decl): Likewise.
+ (d_comdat_group): Likewise.
+ (d_comdat_linkage): Likewise.
+ (add_moduleinfo_field): Move to modules.cc
+ (layout_moduleinfo_fields): Likewise.
+ (get_moduleinfo_decl): Likewise.
+ * modules.cc: New file.
+
+2017-05-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * imports.cc (ImportVisitor::visit(Import)): New function.
+
+2017-05-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (DeclVisitor::visit(Module)): Set input_location before
+ walking module members.
+ (get_linemap): Return input_location if no filename set.
+ (set_input_location): Remove function. Update all callers to set
+ input_location directly.
+ (set_decl_location): Remove function. Update all callers to pass
+ get_linemap to build_decl, or use input_location.
+ * types.cc (insert_aggregate_field): Update signature.
+
+2017-04-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (start_function): Update signature.
+ (finish_function): Update signature.
+ (DeclVisitor::visit(FuncDeclaration)): Move function construction to
+ start_function. Move function finalization to finish_function.
+ (set_function_end_locus): Remove function.
+ (d_finish_function): Remove function.
+ (build_simple_function_decl): Don't set frontend body.
+ (build_simple_function): Update signature. Use start/finish function
+ to compile the body.
+ (emit_dso_registry_cdtor): Likewise.
+ * expr.cc (ExprVisitor::visit(WrappedExp)): Remove function.
+
+2017-04-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-diagnostic.cc (verror): Use xvasprintf.
+ (verrorSupplemental): Likewise.
+ (vwarning): Likewise.
+ (vwarningSupplemental): Likewise.
+ (vdeprecation): Likewise.
+ (vdeprecationSupplemental): Likewise.
+
+2017-04-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (d_tree_index): Add DTI_VTABLE_ENTRY_TYPE,
+ DTI_VTBL_INTERFACE_TYPE, DTI_ARRAY_TYPE, and DTI_NULL_ARRAY.
+ (vtable_entry_type): New macro.
+ (vtbl_interface_type_node): New macro.
+ (array_type_node): New macro.
+ (null_array_node): New macro.
+ * d-builtins.cc (d_build_d_type_nodes): Initialize new trees.
+ * d-codegen.cc (build_struct_literal): Allow NULL index when
+ looking for next field to initialize.
+ (copy_aggregate_type): New function.
+ * d-target.cc (Target::loadModule): Look for object module,
+ call create_tinfo_types.
+ * decl.cc (TypeInfoDeclVisitor): Move to typeinfo.cc.
+ (get_typeinfo_decl): Likewise.
+ (copy_struct): Remove function. Updated callers to use
+ copy_aggregate_type.
+ (layout_classinfo_interfaces): Move to typeinfo.cc.
+ (get_classinfo_decl): Likewise.
+ (get_cpp_typeinfo_decl): Likewise.
+ * typeinfo.cc (tinfo_kind): New enum.
+ (tinfo_types): New static variable.
+ (get_typeinfo_kind): New function.
+ (make_internal_typeinfo): New function.
+ (make_frontend_typeinfo): New function.
+ (create_tinfo_types): New function.
+ (TypeInfoVisitor::set_field): Remove function.
+ Update all callers to use layout_field.
+ (TypeInfoVisitor::layout_vtable): Remove function.
+ Update all callers to use layout_base.
+ (TypeInfoVisitor::layout_field): New function.
+ (TypeInfoVisitor::layout_base): New function.
+ (builtin_typeinfo_p): New function.
+ (genTypeInfo): Rename to create_typeinfo.
+ (isSpeculativeType): Rename to speculative_type_p.
+
+2017-04-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-tree.h (d_function_chain): Declare macro. Update all uses of
+ `cfun->language' to use it.
+
+2017-04-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc: Rename to decl.cc.
+ (get_symbol_decl): Handle typeinfo declarations.
+ (declare_extern_var): New function.
+ (declare_local_var): New function.
+ (get_moduleinfo_decl): Call declare_extern_var.
+ (get_classinfo_decl): Likewise.
+ (get_vtable_decl): Likewise.
+ (get_cpp_typeinfo_decl): Likewise.
+ (aggregate_initializer_decl): Likewise.
+ (enum_initializer_decl): Likewise.
+ * Make-lang.in (D_OBJS): Update.
+ * d-codegen.cc (build_local_var): Remove function.
+ Updated all callers to use declare_local_var.
+ (build_local_temp): Move to decl.cc.
+ (get_decl_tree): Likewise.
+ (expand_decl): Remove function.
+ (build_closure): Inline expand_decl here.
+
+2017-04-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (pop_binding_label): Move to toir.cc.
+ (pop_label): Likewise.
+ (push_binding_level): Likewise
+ (pop_binding_level): Likewise.
+ (push_stmt_list): Likewise.
+ (add_stmt): Likewise.
+ (check_goto): Move to toir.cc, make it a member of IRVisitor.
+ (check_previous_goto): Likewise.
+ (lookup_label): Likewise.
+ (lookup_bc_label): Likewise.
+ (define_label): Likewise.
+ * toir.cc (build_ir): Rename to build_function_body.
+
+2017-04-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc: Update includes.
+
+2017-04-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang-specs.h: Remove capitalized D source suffixes.
+
+2017-04-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang-specs.h: Add rule for forwarding -iprefix and -imultilib to the
+ compiler proper.
+
+2017-04-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang-specs.h: Remove cc1d spec.
+
+2017-04-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang-specs.h: Remove +e handling.
+
+2017-04-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-diagnostic.cc: New file.
+ * d-frontend.cc: New file.
+ * d-glue.cc: Remove file.
+ * d-port.cc: Remove file.
+ * d-longdouble.h (template<typename T> operator): Remove operators.
+
+2017-04-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-incpath.cc (add_env_var_paths): Rename to add_environment_paths.
+ (make_absolute): Remove function.
+ (add_import_path): Rename to add_globalpaths.
+ (add_fileimp_path): Rename to add_filepaths.
+
+2017-04-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.h (d_types_same): Renamed to same_type_p.
+ Moved to types.cc.
+ (build_object_type): Renamed to get_object_type. Moved to types.cc.
+ * d-codegen.cc (type_va_array): Renamed to valist_array_p.
+ Moved to types.cc.
+ (d_array_type): Renamed to make_array_type. Moved to types.cc.
+ (insert_type_modifiers): Moved to types.cc.
+ (build_two_field_type): Likewise.
+ (empty_aggregate_p): Likewise.
+ (fixup_anonymous_offset): Likewise.
+ (layout_aggregate_members): Likewise.
+ (layout_aggregate_type): Likewise.
+ (insert_aggregate_field): Likewise.
+ (finish_aggregate_type): Likewise.
+
+2017-04-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Update to match new source names.
+
+2017-04-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * gdc.texi: Rewrite documentation for manpages.
+
+2017-04-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (DeclVisitor::visit(FuncDeclaration)): Remove logic
+ that parent needs to be compiled before nested.
+
+2017-04-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_post_options): Don't overwrite in_fnames.
+ (d_parse_file): Don't error about not being able to use stdin.
+ Implement support for reading source code from stdin.
+
+2017-04-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_parse_file): Remove invalid file name checks.
+
+2017-04-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-glue.cc (Global::_init): Set global.stdmsg to stderr.
+
+2017-04-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codgen.h (current_module_decl): Moved to d-objfile.cc.
+ * d-objfile.h (current_module_info): Likewise.
+ (ModuleInfoFlags): Likewise.
+ (ModuleInfo): Likewise.
+ * d-objfile.cc (start_function): Move updating ModuleInfo structure to
+ ...
+ (DeclVisitor::visit(FuncDeclaration)): ... here. Set it after
+ finishing off the function.
+
+2017-04-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (DeclVisitor::visit(FuncDeclaration)): Use
+ push_function_decl for storing current state when switching to nested
+ functions. Remove handling of deferred functions.
+ * d-tree.h (language_function): Remove deferred_fns.
+ * expr.cc (ExprVisitor::visit(DelegateExp)): Don't defer compiling
+ the delegate lambda.
+ (ExprVisitor::visit(FuncExp)): Likewise for function literals.
+ (ExprVisitor::visit(VarExp)): Likewise.
+
+2017-04-07 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (start_function): Move to d-objfile.cc, make it static.
+ (end_function): Likewise. Renamed to finish_function.
+
+2017-04-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (d_convert): Move to d-convert.cc.
+ (convert_expr): Likewise.
+ (convert_for_assignment): Likewise.
+ (convert_for_argument): Likewise.
+ (convert_for_condition): Likewise.
+ (d_array_convert): Likewise.
+
+2017-04-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.c (d_global_trees): Move to d-lang.cc.
+ (build_dtype): Rename to build_frontend_type.
+ Updated all callers.
+ (build_expression): Rename to d_eval_constant_expression.
+ Updated all callers.
+ (build_alias_declaration): New function.
+ (d_build_c_type_nodes): New function.
+ (d_build_d_type_nodes): New function.
+ (d_define_builtins): New function.
+
+2017-04-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-attribs.c (insert_type_attribute): Use
+ build_type_attribute_variant.
+ (insert_decl_attribute): Use build_decl_attribute_variant.
+ (uda_attribute_p): Remove string table, use Identifier comparison for
+ looking up table attributes.
+ (build_attributes): Make unknown attribute a warning, use quoted
+ strings in diagnostic messages.
+
+2017-04-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Handle -fdump-d-original.
+ (d_parse_file): Likewise.
+ * d-target.cc (Target::maxStaticDataSize): New variable.
+ (Target::_init): Initialize maxStaticDataSize.
+ * lang.opt (fdump-d-original): Declare.
+
+2017-04-01 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_GLUE_OBJS): Remove d-todt.cc.
+ * d-objfile.cc (build_moduleinfo_symbol): Build initializer for
+ ModuleInfo directly from inferred type fields.
+ (d_finish_symbol): Remove handling of DECL_LANG_INITIAL.
+ * d-todt.cc: Remove file.
+ * d-tree.h (lang_decl): Remove initial field.
+ (DECL_LANG_INITIAL): Remove macro.
+
+2017-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (DeclVisitor::visit(VarDeclaration)): Use build_expr to
+ generate the static initializer.
+ * d-todt.cc (Initializer::toDt): Remove function and all overrides.
+ * expr.cc (ExprVisitor::visit(VarExp)): Use build_expr to get the
+ constant initializer of a constant variable.
+
+2017-03-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (aggregate_initializer): Renamed to
+ aggregate_initializer_decl. Updated all callers.
+ (enum_initializer): Renamed to enum_initializer_decl.
+ Updated all callers.
+ (layout_class_initializer): New function.
+ (layout_struct_initializer): New function.
+ * d-todt.cc (ClassDeclaration::toDt): Remove function.
+ (StructDeclaration::toDt): Remove function.
+
+2017-03-27 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (DeclVisitor::visit(Module)): New function.
+ (Module::genobjfile): Remove function.
+ Updated all callers to use build_decl_tree.
+ (layout_moduleinfo): New function.
+ (Module::genmoduleinfo): Remove function.
+ Update all callers to use layout_moduleinfo.
+
+2017-03-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (base_vtable_offset): New function.
+ (ClassDeclaration::baseVtblOffset): Remove function.
+ Updated all callers to use base_vtable_offset.
+
+2017-03-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (DeclVisitor): New visitor interface to supercede the
+ toObjFile methods.
+ (build_decl_tree): New function.
+ (Dsymbol::toObjFile): Remove function and overrides.
+ Updated all callers to use build_decl_tree.
+
+2017-03-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (get_cpp_typeinfo_decl): New function.
+ * d-lang.cc (d_build_eh_type_type): Return classinfo for
+ __cpp_type_info_ptr when generating catch for C++ classes.
+ * runtime.def (CXA_BEGIN_CATCH): Define.
+ (CXA_END_CATCH): Define.
+ * toir.cc (IRVisitor::visit(TryCatchStatement)): Support catching
+ classes thrown from C++.
+ * typeinfo.cc (layout_cpp_typeinfo): New function.
+
+2017-03-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-builtins.cc (d_build_builtins_module): Always mark gcc builtins as
+ nothrow functions.
+
+2017-03-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-longdouble.cc (CTFloat::zero): New variable.
+ (CTFloat::one): New variable.
+ (CTFloat::minusone): New variable.
+ (CTFloat::half): New variable.
+ (longdouble::set): Remove float and double overloads.
+ (longdouble::operator float): Remove function.
+ (longdouble::operator double): Remove function.
+ * d-target.cc (Target::_init): Initialize floating point constants.
+
+2017-03-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init): Replace calls to init with _init.
+ * d-glue.cc (Global::init): Renamed to Global::_init.
+ * d-target.cc (Target::init): Renamed to Target::_init.
+
+2017-03-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-longdouble.cc (longdouble::format): Remove function.
+ (longdouble::formatHex): Remove function.
+ (longdouble::dump): Remove function.
+ (CTFloat::sprint): Inline implementation of format and formatHex here.
+
+2017-03-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_init): Remove calls to Port::init and longdouble::init.
+ * d-longdouble.cc (real_limits): Remove variable.
+ (longdouble::init): Remove function.
+ (CTFloat::parse): Update to use Target::RealProperties.
+ * d-port.cc (Port::ldbl_nan): Remove variable.
+ (Port::snan): Remove variable.
+ (Port::ldbl_infinity): Remove variable.
+ (Port::ldbl_max): Remove variable.
+ (Port::init): Remove function.
+ (Port::isFloat32LiteralOutOfRange): Update to use
+ Target::RealProperties.
+ (Port::isFloat64LiteralOutOfRange): Likewise.
+ * d-target.cc (Target::FPTypeProperties<T>::max): Define.
+ (Target::FPTypeProperties<T>::min_normal): Define.
+ (Target::FPTypeProperties<T>::nan): Define.
+ (Target::FPTypeProperties<T>::snan): Define.
+ (Target::FPTypeProperties<T>::infinity): Define.
+ (Target::FPTypeProperties<T>::epsilon): Define.
+ (Target::FPTypeProperties<T>::dig): Define.
+ (Target::FPTypeProperties<T>::mant_dig): Define.
+ (Target::FPTypeProperties<T>::max_exp): Define.
+ (Target::FPTypeProperties<T>::min_exp): Define.
+ (Target::FPTypeProperties<T>::max_10_exp): Define.
+ (Target::FPTypeProperties<T>::min_10_exp): Define.
+ (define_float_constants): New function.
+ (Target::init): Initialize compile-time floating point properties.
+ * longdouble.h (Mode): Remove type declaration.
+ (real_properties): Remove type declaration.
+
+2017-03-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-longdouble.cc (CTFloat::fabs): New function.
+ (CTFloat::isIdentical): New function.
+ (CTFloat::isNaN): New function.
+ (CTFloat::isSNaN): New function.
+ (CTFloat::isInfinity): New function.
+ (CTFloat::parse): New function.
+ (CTFloat::sprint): New function.
+ * d-port.cc (Port::isNan): Remove function.
+ (Port::isSignallingNan): Remove function.
+ (Port::isInfinity): Remove function.
+ (Port::fequal): Remove function.
+ (Port::strtof): Remove function.
+ (Port::strtod): Remove function.
+ (Port::strtold): Remove function.
+ (Port::isFloat32LiteralOutOfRange): New function.
+ (Port::isFloat64LiteralOutOfRange): New function.
+ * longdouble.h (ld_sprint): Remove function.
+
+2017-03-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-glue.cc (verror): Update to handle -Wspeculative.
+ (verrorSupplemental): Likewise.
+ * d-lang.cc (d_init_options): Initialize module alias array.
+ (d_init_options): Handle -fmodule-filepath= and -Wspeculative.
+ * d-port.cc (Port::stricmp): Remove function.
+ (Port::writelongLE): New function.
+ (Port::writelongBE): New function.
+ * lang.opt (Wspeculative): Declare.
+ (fmodule-filepath=): Declare.
+
+2017-03-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Handle -ftransition=dip1000
+ * lang.opt (ftransition=dip1000): Declare.
+ (ftransition=safe): Make alias for -ftransition=dip1000
+
+2017-03-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (get_decl_tree): Handle chaining over many levels of
+ nesting functions to get to the right parent for the 'this' field.
+
+2017-03-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (get_symbol_decl): Move generation of DECL_ARGUMENTS for
+ empty body declarations to ...
+ (make_thunk): ... here. Also set-up DECL_RESULT.
+ (finish_thunk): Mark DECL_UNINLINEABLE on external functions.
+
+2017-03-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (make_thunk): Don't build thunks for functions that
+ failed to compile.
+
+2017-03-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (emit_dso_registry_hooks): Set DECL_PRESERVE_P.
+
+2017-02-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_frame_type): Update condition for scope
+ destruction error.
+ * d-port.cc (Port::valcpy): New function.
+ * expr.cc (ExprVisitor::visit(CallExp)): Generate cast of 'this'
+ object to the right handle type before indexing.
+
+2017-02-24 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-glue.cc (warningSupplemental): New function.
+ (vwarningSupplemental): New function.
+ (deprecationSupplemental): New function.
+ (vdeprecationSupplemental): New function.
+
+2017-02-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * imports.cc (ImportVisitor::visit(OverDeclaration)): New function.
+ (ImportVisitor::visit(FuncAliasDeclaration)): New function.
+
+2017-02-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Handle -X and -Xf options.
+ (d_parse_file): Update.
+ * lang-specs.h: Add rules for -X style options.
+ * lang.opt (X): Declare.
+ (Xf): Declare.
+ (fXf=): Make alias for -Xf.
+
+2017-02-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang.opt (fd-vgc): Comment out help test.
+ (fd-verbose): Likewise.
+ (fd-vtls): Likewise.
+ (femit-modules): Likewise.
+
+2017-02-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc (Target::fieldalign): Adjust.
+
+2017-02-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_option_data): Add fields to support other -M options.
+ (d_init_options): Initialize them.
+ (deps_add_target): New function.
+ (deps_write): Support multiple targets and phony rules.
+ (d_handle_option): Handle gcc -M style options.
+ (d_parse_file): Likewise.
+ * lang-specs.h: Add rules for -M style options.
+ * lang.opt: Declare -M style options.
+
+2017-02-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (is_system_module): Remove.
+ (deps_write): Always ignore entrypoint module.
+
+2017-02-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (write_one_dep): Remove.
+ (deps_write): Update signature.
+
+2017-02-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (iprefix_dir): Remove.
+ (imultilib_dir): Remove.
+ (std_inc): Remove.
+ (d_option_data): New struct.
+ (d_option): Declare.
+ (d_init_options): Initialize d_option.
+ (d_init): Update to use d_option.
+ (d_handle_option): Likewise.
+ (d_parse_file): Likewise.
+ (deps_write): Update signature.
+
+2017-02-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Call D_handle_option_auto.
+ * lang.opt (Wunknown-pragmas): Turn on warning with -Wall.
+
+2017-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Replace -fin with -fpreconditions;
+ -fout with -fpostconditions. Handle -fswitch-errors.
+ (d_post_options): Move setting of release code flags here.
+ * lang.opt (fassert): Declare flag_assert.
+ (fin): Make alias for -fpreconditions.
+ (finvariants): Declare flag_invariants.
+ (fout): Make alias for -fpostconditions.
+ (fpostconditions): Declare.
+ (fpreconditions): Declare.
+ (fswitch-errors): Declare.
+
+2017-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (PragmaDeclaration::toObjFile): Warn about unknown
+ pragmas only if -Wunknown-pragmas.
+
+2017-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-glue.cc (Global::init): Initialize errorLimit to flag_max_errors.
+ (verror): Don't halt program after invocation limit.
+ * d-lang.cc (d_handle_option): Remove handling -fmax-error-messages.
+ * lang.opt (fmax-error-messages): Remove option.
+
+2017-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-decls.cc (get_symbol_decl): Handle -Wtemplates.
+ * d-lang.cc (d_init_options): Remove setting flag_emit_templates.
+ (d_handle_option): Replace handling -femit-templates with
+ -fall-instantiations.
+ (d_pushdecl): Remove checking for flag_emit_templates.
+ * d-tree.h (D_DECL_IS_TEMPLATE): Remove macro.
+ * lang.opt (flag_emit_templates): Remove variable.
+ (fall-instantiations): Declare.
+ (femit-templates): Make alias for -fall-instantiations.
+ (Wtemplates): Declare.
+
+2017-02-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * lang.opt (fassert): Update help text.
+ (fin): Likewise.
+ (finvariants): Likewise.
+ (fout): Likewise.
+
+2017-02-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (VarDeclaration::toObjFile): Error if a variable covers
+ more than half the address space.
+
+2017-02-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-objfile.cc (Module::genmoduleinfo): Ignore symbol visibility when
+ looking up module DSO symbols.
+
+2017-01-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Handle -ftransition=all.
+ * lang.opt (ftransition=all): Add compiler option.
+
+2017-01-29 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Handle -ftransition=checkimports.
+ * lang.opt (ftransition=checkimports): Add compiler option.
+
+2017-01-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-lang.cc (d_handle_option): Handle -ftransition=import.
+ * lang.opt (ftransition=import): Add compiler option.
+
+2017-01-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * imports.cc (ImportVisitor::visit(EnumDeclaration)): New function.
+ (ImportVisitor::visit(AggregateDeclaration)): New function.
+ (ImportVisitor::visit(ClassDeclaration)): New function.
+ (ImportVisitor::make_import): New function.
+ (ImportVisitor::visit(AliasDeclaration)): Get decl for type alias.
+
+2017-01-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * expr.cc (ExprVisitor::visit(EqualExp)): Don't use memcmp on arrays
+ of structs that define xopEquals.
+
+2017-01-15 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-spec.cc (lang_specific_driver): Add missing break.
+
+2017-01-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen.cc (build_class_instance): Don't check for void
+ initialized fields.
+ * expr.cc (ExprVisitor::visit(StructLiteralExp)): Likewise.
+
+2017-01-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * typeinfo.cc (layout_classinfo): Use placement new to initialize
+ typeinfo class declaration.
+
+2017-01-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-codegen,cc (get_frame_for_symbol): Use fully qualified name in
+ error message.
+ (build_frame_type): Always add parameters to closure vars if the
+ function has a contract function.
+ (get_frameinfo): Likewise, always create a frame.
+ * expr.cc (ExprVisitor::needs_dtor): New function.
+ (ExprVisitor::lvalue_p): New function.
+ (ExprVisitor::visit(AssignExp)): Check for dtor in array assignments.
+ (ExprVisitor::visit(TypeidExp)): Cast result to expression type.
+
+
+Copyright (C) 2017 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
new file mode 100644
index 0000000..79baf01
--- /dev/null
+++ b/gcc/d/Make-lang.in
@@ -0,0 +1,337 @@
+# Make-lang.in -- Top level -*- makefile -*- fragment for the D frontend.
+# Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file provides the language dependent support in the main Makefile.
+
+# Installation name.
+
+D_INSTALL_NAME = $(shell echo gdc|sed '$(program_transform_name)')
+D_TARGET_INSTALL_NAME = $(target_noncanonical)-$(shell echo gdc|sed '$(program_transform_name)')
+
+# Name of phobos library
+D_LIBPHOBOS = -DLIBPHOBOS=\"gphobos\"
+
+# The name for selecting d in LANGUAGES.
+d: d21$(exeext)
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: d
+
+# Create the compiler driver for D.
+CFLAGS-d/d-spec.o += $(DRIVER_DEFINES) $(D_LIBPHOBOS)
+
+GDC_OBJS = $(GCC_OBJS) d/d-spec.o
+gdc$(exeext): $(GDC_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS)
+ +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+ $(GDC_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \
+ $(EXTRA_GCC_LIBS) $(LIBS)
+
+# Create a version of the gdc driver which calls the cross-compiler.
+gdc-cross$(exeext): gdc$(exeext)
+ -rm -f gdc-cross$(exeext)
+ cp gdc$(exeext) gdc-cross$(exeext)
+
+# Filter out pedantic and virtual overload warnings.
+d-warn = $(filter-out -pedantic -Woverloaded-virtual, $(STRICT_WARN))
+
+# Also filter out warnings for missing format attributes in the D Frontend.
+DMD_WARN_CXXFLAGS = $(filter-out -Wmissing-format-attribute, $(WARN_CXXFLAGS))
+DMD_COMPILE = $(subst $(WARN_CXXFLAGS), $(DMD_WARN_CXXFLAGS), $(COMPILE))
+DMDGEN_COMPILE = $(subst $(COMPILER), $(COMPILER_FOR_BUILD), $(DMD_COMPILE))
+
+# D Frontend object files.
+D_FRONTEND_OBJS = \
+ d/aav.o \
+ d/access.o \
+ d/aliasthis.o \
+ d/apply.o \
+ d/argtypes.o \
+ d/arrayop.o \
+ d/attrib.o \
+ d/blockexit.o \
+ d/canthrow.o \
+ d/checkedint.o \
+ d/clone.o \
+ d/cond.o \
+ d/constfold.o \
+ d/cppmangle.o \
+ d/ctfeexpr.o \
+ d/dcast.o \
+ d/dclass.o \
+ d/declaration.o \
+ d/delegatize.o \
+ d/denum.o \
+ d/dimport.o \
+ d/dinterpret.o \
+ d/dmacro.o \
+ d/dmangle.o \
+ d/dmodule.o \
+ d/doc.o \
+ d/dscope.o \
+ d/dstruct.o \
+ d/dsymbol.o \
+ d/dtemplate.o \
+ d/dversion.o \
+ d/entity.o \
+ d/escape.o \
+ d/expression.o \
+ d/expressionsem.o \
+ d/file.o \
+ d/filename.o \
+ d/func.o \
+ d/hdrgen.o \
+ d/iasm.o \
+ d/iasmgcc.o \
+ d/identifier.o \
+ d/imphint.o \
+ d/init.o \
+ d/initsem.o \
+ d/intrange.o \
+ d/json.o \
+ d/lexer.o \
+ d/mtype.o \
+ d/nogc.o \
+ d/nspace.o \
+ d/objc.o \
+ d/opover.o \
+ d/optimize.o \
+ d/outbuffer.o \
+ d/parse.o \
+ d/rmem.o \
+ d/rootobject.o \
+ d/safe.o \
+ d/sapply.o \
+ d/sideeffect.o \
+ d/speller.o \
+ d/statement.o \
+ d/statementsem.o \
+ d/staticassert.o \
+ d/staticcond.o \
+ d/stringtable.o \
+ d/tokens.o \
+ d/traits.o \
+ d/typesem.o \
+ d/utf.o \
+ d/utils.o
+
+# D Frontend generated files.
+D_GENERATED_SRCS = d/id.c d/id.h d/impcnvtab.c
+D_GENERATED_OBJS = d/id.o d/impcnvtab.o
+
+# Language-specific object files for D.
+D_OBJS = \
+ d/d-attribs.o d/d-builtins.o d/d-codegen.o d/d-convert.o \
+ d/d-diagnostic.o d/d-frontend.o d/d-incpath.o d/d-lang.o \
+ d/d-longdouble.o d/d-target.o d/decl.o d/expr.o d/imports.o \
+ d/intrinsics.o d/modules.o d/runtime.o d/toir.o d/typeinfo.o d/types.o
+
+# All language-specific object files for D.
+D_ALL_OBJS = $(D_FRONTEND_OBJS) $(D_GENERATED_OBJS) $(D_OBJS) $(D_TARGET_OBJS)
+
+d_OBJS = $(D_ALL_OBJS) d/d-spec.o
+
+d21$(exeext): $(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
+ +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+ $(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
+
+# Documentation.
+
+D_TEXI_FILES = \
+ d/gdc.texi \
+ $(gcc_docdir)/include/fdl.texi \
+ $(gcc_docdir)/include/gpl_v3.texi \
+ $(gcc_docdir)/include/gcc-common.texi \
+ gcc-vers.texi
+
+doc/gdc.info: $(D_TEXI_FILES)
+ if test "x$(BUILD_INFO)" = xinfo; then \
+ rm -f doc/gdc.info*; \
+ $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
+ -I $(gcc_docdir)/include -o $@ $<; \
+ else true; fi
+
+doc/gdc.dvi: $(D_TEXI_FILES)
+ $(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+doc/gdc.pdf: $(D_TEXI_FILES)
+ $(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+$(build_htmldir)/d/index.html: $(D_TEXI_FILES)
+ $(mkinstalldirs) $(@D)
+ rm -f $(@D)/*
+ $(TEXI2HTML) -I $(gcc_docdir) -I $(gcc_docdir)/include \
+ -I $(srcdir)/d -o $(@D) $<
+
+.INTERMEDIATE: gdc.pod
+
+gdc.pod: d/gdc.texi
+ -$(TEXI2POD) -D gdc < $< > $@
+
+# Build hooks.
+
+d.all.cross: gdc-cross$(exeext)
+d.start.encap: gdc$(exeext)
+d.rest.encap:
+d.info: doc/gdc.info
+d.dvi: doc/gdc.dvi
+d.pdf: doc/gdc.pdf
+d.html: $(build_htmldir)/d/index.html
+d.srcinfo: doc/gdc.info
+ -cp -p $^ $(srcdir)/doc
+d.srcextra:
+
+d.tags: force
+ cd $(srcdir)/d; \
+ etags -o TAGS.sub *.c *.cc *.h dmd/*.c dmd/*.h dmd/root/*.h dmd/root/*.c; \
+ etags --include TAGS.sub --include ../TAGS.sub
+
+d.man: doc/gdc.1
+d.srcman: doc/gdc.1
+ -cp -p $^ $(srcdir)/doc
+
+# 'make check' in gcc/ looks for check-d, as do all toplevel D-related
+# check targets. However, our DejaGNU framework requires 'check-gdc' as its
+# entry point. We feed the former to the latter here.
+check-d: check-gdc
+lang_checks += check-gdc
+lang_checks_parallelized += check-gdc
+check_gdc_parallelize = 10
+
+# No D-specific selftests.
+selftest-d:
+
+# Install hooks.
+
+d.install-common: installdirs
+ -rm -f $(DESTDIR)$(bindir)/$(D_INSTALL_NAME)$(exeext)
+ $(INSTALL_PROGRAM) gdc$(exeext) $(DESTDIR)$(bindir)/$(D_INSTALL_NAME)$(exeext)
+ -if test -f d21$(exeext); then \
+ if test -f gdc-cross$(exeext); then \
+ :; \
+ else \
+ rm -f $(DESTDIR)$(bindir)/$(D_TARGET_INSTALL_NAME)$(exeext); \
+ ( cd $(DESTDIR)$(bindir) && \
+ $(LN) $(D_INSTALL_NAME)$(exeext) $(D_TARGET_INSTALL_NAME)$(exeext) ); \
+ fi; \
+ fi
+
+d.install-plugin:
+
+d.install-info: $(DESTDIR)$(infodir)/gdc.info
+
+d.install-pdf: doc/gdc.pdf
+ @$(NORMAL_INSTALL)
+ test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+ @for p in doc/gdc.pdf; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(pdf__strip_dir) \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+ done
+
+d.install-html: $(build_htmldir)/d
+ @$(NORMAL_INSTALL)
+ test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
+ @for p in $(build_htmldir)/d; do \
+ if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
+ f=$(html__strip_dir) \
+ if test -d "$$d$$p"; then \
+ echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+ echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
+ else \
+ echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
+ $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
+ fi; \
+ done
+
+d.install-man: $(DESTDIR)$(man1dir)/$(D_INSTALL_NAME)$(man1ext)
+
+$(DESTDIR)$(man1dir)/$(D_INSTALL_NAME)$(man1ext): doc/gdc.1 installdirs
+ -rm -f $@
+ -$(INSTALL_DATA) $< $@
+ -chmod a-x $@
+
+d.uninstall:
+ -rm -rf $(DESTDIR)$(bindir)/$(D_INSTALL_NAME)$(exeext)
+ -rm -rf $(DESTDIR)$(man1dir)/$(D_INSTALL_NAME)$(man1ext)
+ -rm -rf $(DESTDIR)$(bindir)/$(D_TARGET_INSTALL_NAME)$(exeext)
+ -rm -rf $(DESTDIR)$(infodir)/gdc.info*
+
+# Clean hooks.
+
+d.mostlyclean:
+ -rm -f d/*$(objext)
+ -rm -f d/*$(coverageexts)
+ -rm -f $(D_GENERATED_SRCS)
+ -rm -f d/gdc$(exeext) gdc-cross$(exeext) d/d21$(exeext)
+d.clean:
+d.distclean:
+d.maintainer-clean:
+ -rm -f $(docobjdir)/gdc.1
+
+# Stage hooks.
+
+d.stage1: stage1-start
+ -mv d/*$(objext) stage1/d
+d.stage2: stage2-start
+ -mv d/*$(objext) stage2/d
+d.stage3: stage3-start
+ -mv d/*$(objext) stage3/d
+d.stage4: stage4-start
+ -mv d/*$(objext) stage4/d
+d.stageprofile: stageprofile-start
+ -mv d/*$(objext) stageprofile/d
+d.stagefeedback: stagefeedback-start
+ -mv d/*$(objext) stagefeedback/d
+
+# Include the dfrontend and build directories for headers.
+D_INCLUDES = -I$(srcdir)/d -I$(srcdir)/d/dmd -Id
+
+CFLAGS-d/id.o += $(D_INCLUDES)
+CFLAGS-d/impcnvtab.o += $(D_INCLUDES)
+
+# Override build rules for D frontend.
+d/%.o: d/dmd/%.c $(D_GENERATED_SRCS)
+ $(DMD_COMPILE) $(D_INCLUDES) $<
+ $(POSTCOMPILE)
+
+d/%.o: d/dmd/root/%.c $(D_GENERATED_SRCS)
+ $(DMD_COMPILE) $(D_INCLUDES) $<
+ $(POSTCOMPILE)
+
+# Generated programs.
+d/idgen: d/idgen.dmdgen.o
+ +$(LINKER_FOR_BUILD) $(BUILD_LINKER_FLAGS) $(BUILD_LDFLAGS) -o $@ $^
+
+d/impcvgen: d/impcnvgen.dmdgen.o
+ +$(LINKER_FOR_BUILD) $(BUILD_LINKER_FLAGS) $(BUILD_LDFLAGS) -o $@ $^
+
+# Generated sources.
+d/id.c: d/idgen
+ cd d && ./idgen
+
+# idgen also generates id.h; just verify it exists.
+d/id.h: d/id.c
+
+d/impcnvtab.c: d/impcvgen
+ cd d && ./impcvgen
+
+d/%.dmdgen.o: $(srcdir)/d/dmd/%.c
+ $(DMDGEN_COMPILE) $(D_INCLUDES) $<
+ $(POSTCOMPILE)
diff --git a/gcc/d/config-lang.in b/gcc/d/config-lang.in
new file mode 100644
index 0000000..745ad7e
--- /dev/null
+++ b/gcc/d/config-lang.in
@@ -0,0 +1,33 @@
+# config-lang.in -- Top level configure fragment for gcc D frontend.
+# Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language - name of language as it would appear in $(LANGUAGES)
+# compilers - value to add to $(COMPILERS)
+
+language="d"
+
+compilers="d21\$(exeext)"
+
+target_libs="target-libphobos target-zlib target-libbacktrace"
+
+gtfiles="\$(srcdir)/d/d-tree.h \$(srcdir)/d/d-builtins.cc \$(srcdir)/d/d-lang.cc \$(srcdir)/d/modules.cc \$(srcdir)/d/typeinfo.cc"
+
+# Do not build by default.
+build_by_default="no"
diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
new file mode 100644
index 0000000..4f5d3e6
--- /dev/null
+++ b/gcc/d/d-attribs.cc
@@ -0,0 +1,835 @@
+/* d-attribs.c -- D attributes handling.
+ Copyright (C) 2015-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Implementation of attribute handlers for user defined attributes and
+ internal built-in functions. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/declaration.h"
+#include "dmd/mtype.h"
+
+#include "tree.h"
+#include "diagnostic.h"
+#include "tm.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "varasm.h"
+
+#include "d-tree.h"
+
+
+/* Internal attribute handlers for built-in functions. */
+static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
+static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_const_attribute (tree *, tree, tree, int, bool *);
+static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
+static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
+static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+
+/* D attribute handlers for user defined attributes. */
+static tree d_handle_noinline_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_forceinline_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_flatten_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_target_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_noclone_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_section_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_alias_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_weak_attribute (tree *, tree, tree, int, bool *) ;
+
+/* Helper to define attribute exclusions. */
+#define ATTR_EXCL(name, function, type, variable) \
+ { name, function, type, variable }
+
+/* Define attributes that are mutually exclusive with one another. */
+static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
+{
+ ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("malloc", true, true, true),
+ ATTR_EXCL ("pure", true, true, true),
+ ATTR_EXCL ("returns_twice", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
+{
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
+{
+ ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL ("pure", true, true, true),
+ ATTR_EXCL (NULL, false, false, false)
+};
+
+static const struct attribute_spec::exclusions attr_inline_exclusions[] =
+{
+ ATTR_EXCL ("noinline", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
+{
+ ATTR_EXCL ("forceinline", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+/* Helper to define an attribute. */
+#define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \
+ affects_type_identity, handler, exclude) \
+ { name, min_len, max_len, decl_req, type_req, fn_type_req, \
+ affects_type_identity, handler, exclude }
+
+/* Table of machine-independent attributes.
+ For internal use (marking of built-ins) only. */
+const attribute_spec d_langhook_common_attribute_table[] =
+{
+ ATTR_SPEC ("noreturn", 0, 0, true, false, false, false,
+ handle_noreturn_attribute, attr_noreturn_exclusions),
+ ATTR_SPEC ("leaf", 0, 0, true, false, false, false,
+ handle_leaf_attribute, NULL),
+ ATTR_SPEC ("const", 0, 0, true, false, false, false,
+ handle_const_attribute, attr_const_pure_exclusions),
+ ATTR_SPEC ("malloc", 0, 0, true, false, false, false,
+ handle_malloc_attribute, NULL),
+ ATTR_SPEC ("returns_twice", 0, 0, true, false, false, false,
+ handle_returns_twice_attribute, attr_returns_twice_exclusions),
+ ATTR_SPEC ("pure", 0, 0, true, false, false, false,
+ handle_pure_attribute, attr_const_pure_exclusions),
+ ATTR_SPEC ("nonnull", 0, -1, false, true, true, false,
+ handle_nonnull_attribute, NULL),
+ ATTR_SPEC ("nothrow", 0, 0, true, false, false, false,
+ handle_nothrow_attribute, NULL),
+ ATTR_SPEC ("transaction_pure", 0, 0, false, true, true, false,
+ handle_transaction_pure_attribute, NULL),
+ ATTR_SPEC ("no vops", 0, 0, true, false, false, false,
+ handle_novops_attribute, NULL),
+ ATTR_SPEC ("type generic", 0, 0, false, true, true, false,
+ handle_type_generic_attribute, NULL),
+ ATTR_SPEC ("fn spec", 1, 1, false, true, true, false,
+ handle_fnspec_attribute, NULL),
+ ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
+};
+
+/* Table of D language attributes exposed by `gcc.attribute' UDAs. */
+const attribute_spec d_langhook_attribute_table[] =
+{
+ ATTR_SPEC ("noinline", 0, 0, true, false, false, false,
+ d_handle_noinline_attribute, attr_noinline_exclusions),
+ ATTR_SPEC ("forceinline", 0, 0, true, false, false, false,
+ d_handle_forceinline_attribute, attr_inline_exclusions),
+ ATTR_SPEC ("flatten", 0, 0, true, false, false, false,
+ d_handle_flatten_attribute, NULL),
+ ATTR_SPEC ("target", 1, -1, true, false, false, false,
+ d_handle_target_attribute, NULL),
+ ATTR_SPEC ("noclone", 0, 0, true, false, false, false,
+ d_handle_noclone_attribute, NULL),
+ ATTR_SPEC ("section", 1, 1, true, false, false, false,
+ d_handle_section_attribute, NULL),
+ ATTR_SPEC ("alias", 1, 1, true, false, false, false,
+ d_handle_alias_attribute, NULL),
+ ATTR_SPEC ("weak", 0, 0, true, false, false, false,
+ d_handle_weak_attribute, NULL),
+ ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
+};
+
+
+/* Insert the type attribute ATTRNAME with value VALUE into TYPE.
+ Returns a new variant of the original type declaration. */
+
+tree
+insert_type_attribute (tree type, const char *attrname, tree value)
+{
+ tree ident = get_identifier (attrname);
+
+ if (value)
+ value = tree_cons (NULL_TREE, value, NULL_TREE);
+
+ tree attribs = merge_attributes (TYPE_ATTRIBUTES (type),
+ tree_cons (ident, value, NULL_TREE));
+
+ return build_type_attribute_variant (type, attribs);
+}
+
+/* Insert the decl attribute ATTRNAME with value VALUE into DECL. */
+
+tree
+insert_decl_attribute (tree decl, const char *attrname, tree value)
+{
+ tree ident = get_identifier (attrname);
+
+ if (value)
+ value = tree_cons (NULL_TREE, value, NULL_TREE);
+
+ tree attribs = merge_attributes (DECL_ATTRIBUTES (decl),
+ tree_cons (ident, value, NULL_TREE));
+
+ return build_decl_attribute_variant (decl, attribs);
+}
+
+/* Returns TRUE if NAME is an attribute recognized as being handled by
+ the `gcc.attribute' module. */
+
+static bool
+uda_attribute_p (const char *name)
+{
+ tree ident = get_identifier (name);
+
+ /* Search both our language, and target attribute tables.
+ Common and format attributes are kept internal. */
+ for (const attribute_spec *p = d_langhook_attribute_table; p->name; p++)
+ {
+ if (get_identifier (p->name) == ident)
+ return true;
+ }
+
+ for (const attribute_spec *p = targetm.attribute_table; p->name; p++)
+ {
+ if (get_identifier (p->name) == ident)
+ return true;
+ }
+
+ return false;
+}
+
+/* [attribute/uda]
+
+ User Defined Attributes (UDA) are compile time expressions that can be
+ attached to a declaration. These attributes can then be queried, extracted,
+ and manipulated at compile-time. There is no run-time component to them.
+
+ Expand and merge all UDAs found in the EATTRS list that are of type
+ `gcc.attribute.Attribute'. This symbol is internally recognized by the
+ compiler and maps them to their equivalent GCC attribute. */
+
+tree
+build_attributes (Expressions *eattrs)
+{
+ if (!eattrs)
+ return NULL_TREE;
+
+ expandTuples (eattrs);
+
+ tree attribs = NULL_TREE;
+
+ for (size_t i = 0; i < eattrs->dim; i++)
+ {
+ Expression *attr = (*eattrs)[i];
+ Dsymbol *sym = attr->type->toDsymbol (0);
+
+ if (!sym)
+ continue;
+
+ /* Attribute symbol must come from the `gcc.attribute' module. */
+ Dsymbol *mod = (Dsymbol*) sym->getModule ();
+ if (!(strcmp (mod->toChars (), "attribute") == 0
+ && mod->parent != NULL
+ && strcmp (mod->parent->toChars (), "gcc") == 0
+ && !mod->parent->parent))
+ continue;
+
+ /* Get the result of the attribute if it hasn't already been folded. */
+ if (attr->op == TOKcall)
+ attr = attr->ctfeInterpret ();
+
+ /* Should now have a struct `Attribute("attrib", "value", ...)'
+ initializer list. */
+ gcc_assert (attr->op == TOKstructliteral);
+ Expressions *elems = ((StructLiteralExp*) attr)->elements;
+ Expression *e0 = (*elems)[0];
+
+ if (e0->op != TOKstring)
+ {
+ error ("expected string attribute, not %qs", e0->toChars ());
+ return error_mark_node;
+ }
+
+ StringExp *se = (StringExp*) e0;
+ gcc_assert (se->sz == 1);
+
+ /* Empty string attribute, just ignore it. */
+ if (se->len == 0)
+ continue;
+
+ /* Check if the attribute is recognized and handled.
+ Done here to report the diagnostic at the right location. */
+ const char *name = (const char *)(se->len ? se->string : "");
+ if (!uda_attribute_p (name))
+ {
+ warning_at (make_location_t (e0->loc), OPT_Wattributes,
+ "unknown attribute %qs", name);
+ return error_mark_node;
+ }
+
+ /* Chain all attribute arguments together. */
+ tree args = NULL_TREE;
+
+ for (size_t j = 1; j < elems->dim; j++)
+ {
+ Expression *e = (*elems)[j];
+ tree t;
+ if (e->op == TOKstring && ((StringExp *) e)->sz == 1)
+ {
+ StringExp *s = (StringExp *) e;
+ const char *string = (const char *)(s->len ? s->string : "");
+ t = build_string (s->len, string);
+ }
+ else
+ t = build_expr (e);
+
+ args = chainon (args, build_tree_list (0, t));
+ }
+
+ tree list = build_tree_list (get_identifier (name), args);
+ attribs = chainon (attribs, list);
+ }
+
+ return attribs;
+}
+
+/* Built-in attribute handlers. */
+
+/* Handle a "noreturn" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ tree type = TREE_TYPE (*node);
+
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_THIS_VOLATILE (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node)
+ = build_pointer_type
+ (build_type_variant (TREE_TYPE (type),
+ TYPE_READONLY (TREE_TYPE (type)), 1));
+ else
+ gcc_unreachable ();
+
+ return NULL_TREE;
+}
+
+/* Handle a "leaf" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_leaf_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ if (!TREE_PUBLIC (*node))
+ {
+ warning (OPT_Wattributes, "%qE attribute has no effect", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "const" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_const_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ tree type = TREE_TYPE (*node);
+
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_READONLY (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node)
+ = build_pointer_type
+ (build_type_variant (TREE_TYPE (type), 1,
+ TREE_THIS_VOLATILE (TREE_TYPE (type))));
+ else
+ gcc_unreachable ();
+
+ return NULL_TREE;
+}
+
+/* Handle a "malloc" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_malloc_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))));
+ DECL_IS_MALLOC (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Handle a "pure" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_pure_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ DECL_PURE_P (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Handle a "no vops" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ DECL_IS_NOVOPS (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Helper for nonnull attribute handling; fetch the operand number
+ from the attribute argument list. */
+
+static bool
+get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
+{
+ /* Verify the arg number is a constant. */
+ if (!tree_fits_uhwi_p (arg_num_expr))
+ return false;
+
+ *valp = TREE_INT_CST_LOW (arg_num_expr);
+ return true;
+}
+
+/* Handle the "nonnull" attribute. */
+
+static tree
+handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
+ tree args, int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ tree type = *node;
+
+ /* If no arguments are specified, all pointer arguments should be
+ non-null. Verify a full prototype is given so that the arguments
+ will have the correct types when we actually check them later.
+ Avoid diagnosing type-generic built-ins since those have no
+ prototype. */
+ if (!args)
+ {
+ gcc_assert (prototype_p (type)
+ || !TYPE_ATTRIBUTES (type)
+ || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)));
+
+ return NULL_TREE;
+ }
+
+ /* Argument list specified. Verify that each argument number references
+ a pointer argument. */
+ for (; args; args = TREE_CHAIN (args))
+ {
+ tree argument;
+ unsigned HOST_WIDE_INT arg_num = 0, ck_num;
+
+ if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
+ gcc_unreachable ();
+
+ argument = TYPE_ARG_TYPES (type);
+ if (argument)
+ {
+ for (ck_num = 1; ; ck_num++)
+ {
+ if (!argument || ck_num == arg_num)
+ break;
+ argument = TREE_CHAIN (argument);
+ }
+
+ gcc_assert (argument
+ && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE);
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "nothrow" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ TREE_NOTHROW (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Handle a "type_generic" attribute. */
+
+static tree
+handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ /* Ensure we have a function type. */
+ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+ /* Ensure we have a variadic function. */
+ gcc_assert (!prototype_p (*node) || stdarg_p (*node));
+
+ return NULL_TREE;
+}
+
+/* Handle a "transaction_pure" attribute. */
+
+static tree
+handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ /* Ensure we have a function type. */
+ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+ return NULL_TREE;
+}
+
+/* Handle a "returns_twice" attribute. */
+
+static tree
+handle_returns_twice_attribute (tree *node, tree ARG_UNUSED (name),
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+
+ DECL_IS_RETURNS_TWICE (*node) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "fn spec" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
+ tree args, int ARG_UNUSED (flags),
+ bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+ gcc_assert (args
+ && TREE_CODE (TREE_VALUE (args)) == STRING_CST
+ && !TREE_CHAIN (args));
+ return NULL_TREE;
+}
+
+/* Language specific attribute handlers. */
+
+/* Handle a "noinline" attribute. */
+
+static tree
+d_handle_noinline_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+ if (t->ty == Tfunction)
+ DECL_UNINLINABLE (*node) = 1;
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "forceinline" attribute. */
+
+static tree
+d_handle_forceinline_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+ if (t->ty == Tfunction)
+ {
+ tree attributes = DECL_ATTRIBUTES (*node);
+
+ /* Push attribute always_inline. */
+ if (! lookup_attribute ("always_inline", attributes))
+ DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("always_inline"),
+ NULL_TREE, attributes);
+
+ DECL_DECLARED_INLINE_P (*node) = 1;
+ DECL_NO_INLINE_WARNING_P (*node) = 1;
+ DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "flatten" attribute. */
+
+static tree
+d_handle_flatten_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+ Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+ if (t->ty != Tfunction)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "target" attribute. */
+
+static tree
+d_handle_target_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+ /* Ensure we have a function type. */
+ if (t->ty != Tfunction)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if (! targetm.target_option.valid_attribute_p (*node, name, args, flags))
+ *no_add_attrs = true;
+
+ return NULL_TREE;
+}
+
+/* Handle a "noclone" attribute. */
+
+static tree
+d_handle_noclone_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool *no_add_attrs)
+{
+ Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+ if (t->ty == Tfunction)
+ {
+ tree attributes = DECL_ATTRIBUTES (*node);
+
+ /* Push attribute noclone. */
+ if (! lookup_attribute ("noclone", attributes))
+ DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("noclone"),
+ NULL_TREE, attributes);
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "section" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ tree decl = *node;
+
+ if (targetm_common.have_named_sections)
+ {
+ if (VAR_OR_FUNCTION_DECL_P (decl)
+ && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+ {
+ if (VAR_P (decl)
+ && current_function_decl != NULL_TREE
+ && !TREE_STATIC (decl))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "section attribute cannot be specified for "
+ "local variables");
+ *no_add_attrs = true;
+ }
+
+ /* The decl may have already been given a section attribute
+ from a previous declaration. Ensure they match. */
+ else if (DECL_SECTION_NAME (decl) != NULL
+ && strcmp (DECL_SECTION_NAME (decl),
+ TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+ {
+ error ("section of %q+D conflicts with previous declaration",
+ *node);
+ *no_add_attrs = true;
+ }
+ else if (VAR_P (decl)
+ && !targetm.have_tls && targetm.emutls.tmpl_section
+ && DECL_THREAD_LOCAL_P (decl))
+ {
+ error ("section of %q+D cannot be overridden", *node);
+ *no_add_attrs = true;
+ }
+ else
+ set_decl_section_name (decl,
+ TREE_STRING_POINTER (TREE_VALUE (args)));
+ }
+ else
+ {
+ error ("section attribute not allowed for %q+D", *node);
+ *no_add_attrs = true;
+ }
+ }
+ else
+ {
+ error_at (DECL_SOURCE_LOCATION (*node),
+ "section attributes are not supported for this target");
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle an "alias" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_alias_attribute (tree *node, tree ARG_UNUSED (name),
+ tree args, int ARG_UNUSED (flags),
+ bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+ tree decl = *node;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL
+ && TREE_CODE (decl) != VAR_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+ || (TREE_CODE (decl) != FUNCTION_DECL
+ && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
+ /* A static variable declaration is always a tentative definition,
+ but the alias is a non-tentative definition which overrides. */
+ || (TREE_CODE (decl) != FUNCTION_DECL
+ && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
+ {
+ error ("%q+D defined both normally and as %qE attribute", decl, name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ else if (decl_function_context (decl))
+ {
+ error ("%q+D alias functions must be global", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ else
+ {
+ tree id;
+
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("attribute %qE argument not a string", name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ id = get_identifier (TREE_STRING_POINTER (id));
+ /* This counts as a use of the object pointed to. */
+ TREE_USED (id) = 1;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ DECL_INITIAL (decl) = error_mark_node;
+ else
+ TREE_STATIC (decl) = 1;
+
+ return NULL_TREE;
+ }
+}
+
+/* Handle a "weak" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_weak_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * ARG_UNUSED (no_add_attrs))
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (*node))
+ {
+ warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
+ *no_add_attrs = true;
+ }
+ else if (VAR_OR_FUNCTION_DECL_P (*node))
+ {
+ struct symtab_node *n = symtab_node::get (*node);
+ if (n && n->refuse_visibility_changes)
+ error ("%q+D declared weak after being used", *node);
+ declare_weak (*node);
+ }
+ else
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+ return NULL_TREE;
+}
+
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
new file mode 100644
index 0000000..a4a31e6
--- /dev/null
+++ b/gcc/d/d-builtins.cc
@@ -0,0 +1,1169 @@
+/* d-builtins.cc -- GCC builtins support for D.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/attrib.h"
+#include "dmd/aggregate.h"
+#include "dmd/cond.h"
+#include "dmd/declaration.h"
+#include "dmd/expression.h"
+#include "dmd/identifier.h"
+#include "dmd/module.h"
+#include "dmd/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "d-target.h"
+
+
+static GTY(()) vec<tree, va_gc> *gcc_builtins_functions = NULL;
+static GTY(()) vec<tree, va_gc> *gcc_builtins_libfuncs = NULL;
+static GTY(()) vec<tree, va_gc> *gcc_builtins_types = NULL;
+
+/* Record built-in types and their associated decls for re-use when
+ generating the `gcc.builtins' module. */
+
+struct builtin_data
+{
+ Type *dtype;
+ tree ctype;
+ Dsymbol *dsym;
+
+ builtin_data (Type *t, tree c, Dsymbol *d = NULL)
+ : dtype(t), ctype(c), dsym(d)
+ { }
+};
+
+static vec<builtin_data> builtin_converted_decls;
+
+/* Build D frontend type from tree TYPE type given. This will set the
+ back-end type symbol directly for complex types to save build_ctype()
+ the work. For other types, it is not useful or will cause errors, such
+ as casting from `C char' to `D char', which also means that `char *`
+ needs to be specially handled. */
+
+static Type *
+build_frontend_type (tree type)
+{
+ Type *dtype;
+ MOD mod = 0;
+
+ if (TYPE_READONLY (type))
+ mod |= MODconst;
+ if (TYPE_VOLATILE (type))
+ mod |= MODshared;
+
+ /* If we've seen the type before, re-use the converted decl. */
+ for (size_t i = 0; i < builtin_converted_decls.length (); ++i)
+ {
+ tree t = builtin_converted_decls[i].ctype;
+ if (TYPE_MAIN_VARIANT (t) == TYPE_MAIN_VARIANT (type))
+ return builtin_converted_decls[i].dtype;
+ }
+
+ switch (TREE_CODE (type))
+ {
+ case POINTER_TYPE:
+ dtype = build_frontend_type (TREE_TYPE (type));
+ if (dtype)
+ {
+ /* Check for char * first. Needs to be done for chars/string. */
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
+ return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod);
+
+ if (dtype->ty == Tfunction)
+ return (TypePointer::create (dtype))->addMod (mod);
+
+ return dtype->pointerTo ()->addMod (mod);
+ }
+ break;
+
+ case REFERENCE_TYPE:
+ dtype = build_frontend_type (TREE_TYPE (type));
+ if (dtype)
+ {
+ /* Want to assign ctype directly so that the REFERENCE_TYPE code
+ can be turned into as an `inout' argument. Can't use pointerTo(),
+ because the returned Type is shared. */
+ dtype = (TypePointer::create (dtype))->addMod (mod);
+ dtype->ctype = type;
+ builtin_converted_decls.safe_push (builtin_data (dtype, type));
+ return dtype;
+ }
+ break;
+
+ case BOOLEAN_TYPE:
+ /* Should be no need for size checking. */
+ return Type::tbool->addMod (mod);
+
+ case INTEGER_TYPE:
+ {
+ unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+ bool unsignedp = TYPE_UNSIGNED (type);
+
+ /* For now, skip support for cent/ucent until the frontend
+ has better support for handling it. */
+ for (size_t i = Tint8; i <= Tuns64; i++)
+ {
+ dtype = Type::basic[i];
+
+ /* Search for type matching size and signedness. */
+ if (unsignedp != dtype->isunsigned ()
+ || size != dtype->size ())
+ continue;
+
+ return dtype->addMod (mod);
+ }
+ break;
+ }
+
+ case REAL_TYPE:
+ {
+ unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+
+ for (size_t i = Tfloat32; i <= Tfloat80; i++)
+ {
+ dtype = Type::basic[i];
+
+ /* Search for type matching size. */
+ if (dtype->size () != size)
+ continue;
+
+ return dtype->addMod (mod);
+ }
+ break;
+ }
+
+ case COMPLEX_TYPE:
+ {
+ unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+ for (size_t i = Tcomplex32; i <= Tcomplex80; i++)
+ {
+ dtype = Type::basic[i];
+
+ /* Search for type matching size. */
+ if (dtype->size () != size)
+ continue;
+
+ return dtype->addMod (mod);
+ }
+ break;
+ }
+
+ case VOID_TYPE:
+ return Type::tvoid->addMod (mod);
+
+ case ARRAY_TYPE:
+ dtype = build_frontend_type (TREE_TYPE (type));
+ if (dtype)
+ {
+ tree index = TYPE_DOMAIN (type);
+ tree ub = TYPE_MAX_VALUE (index);
+ tree lb = TYPE_MIN_VALUE (index);
+
+ tree length = fold_build2 (MINUS_EXPR, TREE_TYPE (lb), ub, lb);
+ length = size_binop (PLUS_EXPR, size_one_node,
+ convert (sizetype, length));
+
+ dtype = dtype->sarrayOf (TREE_INT_CST_LOW (length))->addMod (mod);
+ builtin_converted_decls.safe_push (builtin_data (dtype, type));
+ return dtype;
+ }
+ break;
+
+ case VECTOR_TYPE:
+ dtype = build_frontend_type (TREE_TYPE (type));
+ if (dtype)
+ {
+ poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (type);
+ dtype = dtype->sarrayOf (nunits.to_constant ())->addMod (mod);
+
+ if (dtype->nextOf ()->isTypeBasic () == NULL)
+ break;
+
+ dtype = (TypeVector::create (Loc (), dtype))->addMod (mod);
+ builtin_converted_decls.safe_push (builtin_data (dtype, type));
+ return dtype;
+ }
+ break;
+
+ case RECORD_TYPE:
+ if (TYPE_NAME (type))
+ {
+ tree structname = DECL_NAME (TYPE_NAME (type));
+ Identifier *ident
+ = Identifier::idPool (IDENTIFIER_POINTER (structname));
+
+ /* Neither the `object' and `gcc.builtins' modules will not exist when
+ this is called. Use a stub 'object' module parent in the meantime.
+ If `gcc.builtins' is later imported, the parent will be overridden
+ with the correct module symbol. */
+ static Identifier *object = Identifier::idPool ("object");
+ static Module *stubmod = Module::create ("object.d", object, 0, 0);
+
+ StructDeclaration *sdecl = StructDeclaration::create (Loc (), ident,
+ false);
+ sdecl->parent = stubmod;
+ sdecl->structsize = int_size_in_bytes (type);
+ sdecl->alignsize = TYPE_ALIGN_UNIT (type);
+ sdecl->alignment = STRUCTALIGN_DEFAULT;
+ sdecl->sizeok = SIZEOKdone;
+ sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
+ sdecl->type->ctype = type;
+ sdecl->type->merge2 ();
+
+ /* Does not seem necessary to convert fields, but the members field
+ must be non-null for the above size setting to stick. */
+ sdecl->members = new Dsymbols;
+ dtype = sdecl->type;
+ builtin_converted_decls.safe_push (builtin_data (dtype, type, sdecl));
+ return dtype;
+ }
+ break;
+
+ case FUNCTION_TYPE:
+ dtype = build_frontend_type (TREE_TYPE (type));
+ if (dtype)
+ {
+ tree parms = TYPE_ARG_TYPES (type);
+ int varargs_p = 1;
+
+ Parameters *args = new Parameters;
+ args->reserve (list_length (parms));
+
+ /* Attempt to convert all parameter types. */
+ for (tree parm = parms; parm != NULL_TREE; parm = TREE_CHAIN (parm))
+ {
+ tree argtype = TREE_VALUE (parm);
+ if (argtype == void_type_node)
+ {
+ varargs_p = 0;
+ break;
+ }
+
+ StorageClass sc = STCundefined;
+ if (TREE_CODE (argtype) == REFERENCE_TYPE)
+ {
+ argtype = TREE_TYPE (argtype);
+ sc |= STCref;
+ }
+
+ Type *targ = build_frontend_type (argtype);
+ if (!targ)
+ {
+ delete args;
+ return NULL;
+ }
+
+ args->push (Parameter::create (sc, targ, NULL, NULL));
+ }
+
+ /* GCC generic and placeholder built-ins are marked as variadic, yet
+ have no named parameters, and so can't be represented in D. */
+ if (args->dim != 0 || !varargs_p)
+ {
+ dtype = TypeFunction::create (args, dtype, varargs_p, LINKc);
+ return dtype->addMod (mod);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+/* Attempt to convert GCC evaluated CST to a D Frontend Expression.
+ This is used for getting the CTFE value out of a const-folded builtin,
+ returns NULL if it cannot convert CST. */
+
+Expression *
+d_eval_constant_expression (tree cst)
+{
+ STRIP_TYPE_NOPS (cst);
+ Type *type = build_frontend_type (TREE_TYPE (cst));
+
+ if (type)
+ {
+ /* Convert our GCC CST tree into a D Expression. This seems like we are
+ trying too hard, as these will only be converted back to a tree again
+ later in the codegen pass, but satisfies the need to have GCC built-ins
+ CTFE-able in the frontend. */
+ tree_code code = TREE_CODE (cst);
+ if (code == COMPLEX_CST)
+ {
+ real_value re = TREE_REAL_CST (TREE_REALPART (cst));
+ real_value im = TREE_REAL_CST (TREE_IMAGPART (cst));
+ complex_t value = complex_t (ldouble (re), ldouble (im));
+ return ComplexExp::create (Loc (), value, type);
+ }
+ else if (code == INTEGER_CST)
+ {
+ dinteger_t value = TREE_INT_CST_LOW (cst);
+ return IntegerExp::create (Loc (), value, type);
+ }
+ else if (code == REAL_CST)
+ {
+ real_value value = TREE_REAL_CST (cst);
+ return RealExp::create (Loc (), ldouble (value), type);
+ }
+ else if (code == STRING_CST)
+ {
+ const void *string = TREE_STRING_POINTER (cst);
+ size_t len = TREE_STRING_LENGTH (cst);
+ return StringExp::create (Loc (), CONST_CAST (void *, string), len);
+ }
+ else if (code == VECTOR_CST)
+ {
+ dinteger_t nunits = VECTOR_CST_NELTS (cst).to_constant ();
+ Expressions *elements = new Expressions;
+ elements->setDim (nunits);
+
+ for (size_t i = 0; i < nunits; i++)
+ {
+ Expression *elem
+ = d_eval_constant_expression (VECTOR_CST_ELT (cst, i));
+ if (elem == NULL)
+ return NULL;
+
+ (*elements)[i] = elem;
+ }
+
+ Expression *e = ArrayLiteralExp::create (Loc (), elements);
+ e->type = ((TypeVector *) type)->basetype;
+
+ return VectorExp::create (Loc (), e, type);
+ }
+ }
+
+ return NULL;
+}
+
+/* Callback for TARGET_D_CPU_VERSIONS and TARGET_D_OS_VERSIONS.
+ Adds IDENT to the list of predefined version identifiers. */
+
+void
+d_add_builtin_version (const char* ident)
+{
+ /* For now, we need to tell the D frontend what platform is being targeted.
+ This should be removed once the frontend has been fixed. */
+ if (strcmp (ident, "linux") == 0)
+ global.params.isLinux = true;
+ else if (strcmp (ident, "OSX") == 0)
+ global.params.isOSX = true;
+ else if (strcmp (ident, "Windows") == 0)
+ global.params.isWindows = true;
+ else if (strcmp (ident, "FreeBSD") == 0)
+ global.params.isFreeBSD = true;
+ else if (strcmp (ident, "OpenBSD") == 0)
+ global.params.isOpenBSD = true;
+ else if (strcmp (ident, "Solaris") == 0)
+ global.params.isSolaris = true;
+ /* The is64bit field only refers to x86_64 target. */
+ else if (strcmp (ident, "X86_64") == 0)
+ global.params.is64bit = true;
+ /* No other fields are required to be set for the frontend. */
+
+ VersionCondition::addPredefinedGlobalIdent (ident);
+}
+
+/* Initialize the list of all the predefined version identifiers. */
+
+void
+d_init_versions (void)
+{
+ VersionCondition::addPredefinedGlobalIdent ("GNU");
+ VersionCondition::addPredefinedGlobalIdent ("D_Version2");
+
+ if (BYTES_BIG_ENDIAN)
+ VersionCondition::addPredefinedGlobalIdent ("BigEndian");
+ else
+ VersionCondition::addPredefinedGlobalIdent ("LittleEndian");
+
+ if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+ VersionCondition::addPredefinedGlobalIdent ("GNU_SjLj_Exceptions");
+ else if (targetm_common.except_unwind_info (&global_options) == UI_SEH)
+ VersionCondition::addPredefinedGlobalIdent ("GNU_SEH_Exceptions");
+ else if (targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
+ VersionCondition::addPredefinedGlobalIdent ("GNU_DWARF2_Exceptions");
+
+ if (!targetm.have_tls)
+ VersionCondition::addPredefinedGlobalIdent ("GNU_EMUTLS");
+
+#ifdef STACK_GROWS_DOWNWARD
+ VersionCondition::addPredefinedGlobalIdent ("GNU_StackGrowsDown");
+#endif
+
+ /* Should define this anyway to set us apart from the competition. */
+ VersionCondition::addPredefinedGlobalIdent ("GNU_InlineAsm");
+
+ /* LP64 only means 64bit pointers in D. */
+ if (global.params.isLP64)
+ VersionCondition::addPredefinedGlobalIdent ("D_LP64");
+
+ /* Setting `global.params.cov' forces module info generation which is
+ not needed for the GCC coverage implementation. Instead, just
+ test flag_test_coverage while leaving `global.params.cov' unset. */
+ if (flag_test_coverage)
+ VersionCondition::addPredefinedGlobalIdent ("D_Coverage");
+ if (flag_pic)
+ VersionCondition::addPredefinedGlobalIdent ("D_PIC");
+
+ if (global.params.doDocComments)
+ VersionCondition::addPredefinedGlobalIdent ("D_Ddoc");
+
+ if (global.params.useUnitTests)
+ VersionCondition::addPredefinedGlobalIdent ("unittest");
+
+ if (global.params.useAssert)
+ VersionCondition::addPredefinedGlobalIdent ("assert");
+
+ if (global.params.useArrayBounds == BOUNDSCHECKoff)
+ VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks");
+
+ VersionCondition::addPredefinedGlobalIdent ("all");
+
+ /* Emit all target-specific version identifiers. */
+ targetdm.d_cpu_versions ();
+ targetdm.d_os_versions ();
+}
+
+/* A helper for d_build_builtins_module. Return a new ALIAS for TYPE.
+ Analogous to `alias ALIAS = TYPE' in D code. */
+
+static AliasDeclaration *
+build_alias_declaration (const char *alias, Type *type)
+{
+ return AliasDeclaration::create (Loc (), Identifier::idPool (alias), type);
+}
+
+/* A helper function for Target::loadModule. Generates all code for the
+ `gcc.builtins' module, whose frontend symbol should be M. */
+
+void
+d_build_builtins_module (Module *m)
+{
+ Dsymbols *members = new Dsymbols;
+ tree decl;
+
+ for (size_t i = 0; vec_safe_iterate (gcc_builtins_functions, i, &decl); ++i)
+ {
+ const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+ TypeFunction *tf
+ = (TypeFunction *) build_frontend_type (TREE_TYPE (decl));
+
+ /* Cannot create built-in function type for DECL. */
+ if (!tf)
+ continue;
+
+ /* A few notes on D2 attributes applied to builtin functions:
+ - It is assumed that built-ins solely provided by the compiler are
+ considered @safe and pure.
+ - Built-ins that correspond to `extern(C)' functions in the standard
+ library that have `__attribute__(nothrow)' are considered `@trusted'.
+ - The purity of a built-in can vary depending on compiler flags set
+ upon initialization, or by the `-foptions' passed, such as
+ flag_unsafe_math_optimizations.
+ - Built-ins never use the GC or raise a D exception, and so are always
+ marked as `nothrow' and `@nogc'. */
+ tf->purity = DECL_PURE_P (decl) ? PUREstrong
+ : TREE_READONLY (decl) ? PUREconst
+ : DECL_IS_NOVOPS (decl) ? PUREweak
+ : !DECL_ASSEMBLER_NAME_SET_P (decl) ? PUREweak
+ : PUREimpure;
+ tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUSTsafe
+ : TREE_NOTHROW (decl) ? TRUSTtrusted
+ : TRUSTsystem;
+ tf->isnothrow = true;
+ tf->isnogc = true;
+
+ FuncDeclaration *func
+ = FuncDeclaration::create (Loc (), Loc (),
+ Identifier::idPool (name),
+ STCextern, tf);
+ DECL_LANG_SPECIFIC (decl) = build_lang_decl (func);
+ func->csym = decl;
+ func->builtin = BUILTINyes;
+
+ members->push (func);
+ }
+
+ for (size_t i = 0; vec_safe_iterate (gcc_builtins_types, i, &decl); ++i)
+ {
+ const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+ Type *t = build_frontend_type (TREE_TYPE (decl));
+
+ /* Cannot create built-in type for DECL. */
+ if (!t)
+ continue;
+
+ members->push (build_alias_declaration (name, t));
+ }
+
+ /* Iterate through the target-specific builtin types for va_list. */
+ if (targetm.enum_va_list_p)
+ {
+ const char *name;
+ tree type;
+
+ for (int i = 0; targetm.enum_va_list_p (i, &name, &type); ++i)
+ {
+ Type *t = build_frontend_type (type);
+ /* Cannot create built-in type. */
+ if (!t)
+ continue;
+
+ members->push (build_alias_declaration (name, t));
+ }
+ }
+
+ /* Push out declarations for any RECORD_TYPE types encountered when building
+ all builtin functions and types. */
+ for (size_t i = 0; i < builtin_converted_decls.length (); ++i)
+ {
+ /* Currently, there is no need to run semantic, but we do want to output
+ initializers, typeinfo, and others on demand. */
+ Dsymbol *dsym = builtin_converted_decls[i].dsym;
+ if (dsym != NULL)
+ {
+ dsym->parent = m;
+ members->push (dsym);
+ }
+ }
+
+ /* va_list should already be built, so no need to convert to D type again. */
+ members->push (build_alias_declaration ("__builtin_va_list", Type::tvalist));
+
+ /* Expose target-specific integer types to the builtins module. */
+ {
+ Type *t = build_frontend_type (long_integer_type_node);
+ members->push (build_alias_declaration ("__builtin_clong", t));
+
+ t = build_frontend_type (long_unsigned_type_node);
+ members->push (build_alias_declaration ("__builtin_culong", t));
+
+ t = build_frontend_type (long_long_integer_type_node);
+ members->push (build_alias_declaration ("__builtin_clonglong", t));
+
+ t = build_frontend_type (long_long_unsigned_type_node);
+ members->push (build_alias_declaration ("__builtin_culonglong", t));
+
+ t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 0));
+ members->push (build_alias_declaration ("__builtin_machine_byte", t));
+
+ t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 1));
+ members->push (build_alias_declaration ("__builtin_machine_ubyte", t));
+
+ t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 0));
+ members->push (build_alias_declaration ("__builtin_machine_int", t));
+
+ t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 1));
+ members->push (build_alias_declaration ("__builtin_machine_uint", t));
+
+ t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 0));
+ members->push (build_alias_declaration ("__builtin_pointer_int", t));
+
+ t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 1));
+ members->push (build_alias_declaration ("__builtin_pointer_uint", t));
+
+ /* _Unwind_Word has its own target specific mode. */
+ machine_mode mode = targetm.unwind_word_mode ();
+ t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 0));
+ members->push (build_alias_declaration ("__builtin_unwind_int", t));
+
+ t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 1));
+ members->push (build_alias_declaration ("__builtin_unwind_uint", t));
+ }
+
+ m->members->push (LinkDeclaration::create (LINKc, members));
+}
+
+/* Search for any `extern(C)' functions that match any known GCC library builtin
+ function in D and override its internal back-end symbol. */
+
+static void
+maybe_set_builtin_1 (Dsymbol *d)
+{
+ AttribDeclaration *ad = d->isAttribDeclaration ();
+ FuncDeclaration *fd = d->isFuncDeclaration ();
+
+ if (ad != NULL)
+ {
+ /* Recursively search through attribute decls. */
+ Dsymbols *decls = ad->include (NULL, NULL);
+ if (decls && decls->dim)
+ {
+ for (size_t i = 0; i < decls->dim; i++)
+ {
+ Dsymbol *sym = (*decls)[i];
+ maybe_set_builtin_1 (sym);
+ }
+ }
+ }
+ else if (fd && !fd->fbody)
+ {
+ tree t;
+
+ for (size_t i = 0; vec_safe_iterate (gcc_builtins_libfuncs, i, &t); ++i)
+ {
+ gcc_assert (DECL_ASSEMBLER_NAME_SET_P (t));
+
+ const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t));
+ if (fd->ident != Identifier::idPool (name))
+ continue;
+
+ /* Found a match, tell the frontend this is a builtin. */
+ DECL_LANG_SPECIFIC (t) = build_lang_decl (fd);
+ fd->csym = t;
+ fd->builtin = BUILTINyes;
+ return;
+ }
+ }
+}
+
+/* A helper function for Target::loadModule. Traverse all members in module M
+ to search for any functions that can be mapped to any GCC builtin. */
+
+void
+d_maybe_set_builtin (Module *m)
+{
+ if (!m || !m->members)
+ return;
+
+ for (size_t i = 0; i < m->members->dim; i++)
+ {
+ Dsymbol *sym = (*m->members)[i];
+ maybe_set_builtin_1 (sym);
+ }
+}
+
+/* Used to help initialize the builtin-types.def table. When a type of
+ the correct size doesn't exist, use error_mark_node instead of NULL.
+ The latter results in segfaults even when a decl using the type doesn't
+ get invoked. */
+
+static tree
+builtin_type_for_size (int size, bool unsignedp)
+{
+ tree type = lang_hooks.types.type_for_size (size, unsignedp);
+ return type ? type : error_mark_node;
+}
+
+/* Support for DEF_BUILTIN. */
+
+static void
+do_build_builtin_fn (built_in_function fncode,
+ const char *name,
+ built_in_class fnclass,
+ tree fntype, bool both_p, bool fallback_p,
+ tree fnattrs, bool implicit_p)
+{
+ tree decl;
+ const char *libname;
+
+ if (fntype == error_mark_node)
+ return;
+
+ gcc_assert ((!both_p && !fallback_p)
+ || !strncmp (name, "__builtin_",
+ strlen ("__builtin_")));
+
+ libname = name + strlen ("__builtin_");
+
+ decl = add_builtin_function (name, fntype, fncode, fnclass,
+ fallback_p ? libname : NULL, fnattrs);
+
+ set_builtin_decl (fncode, decl, implicit_p);
+}
+
+/* Standard data types to be used in builtin argument declarations. */
+
+static GTY(()) tree string_type_node;
+static GTY(()) tree const_string_type_node;
+static GTY(()) tree wint_type_node;
+static GTY(()) tree intmax_type_node;
+static GTY(()) tree uintmax_type_node;
+static GTY(()) tree signed_size_type_node;
+
+
+/* Build nodes that would have been created by the C front-end; necessary
+ for including builtin-types.def and ultimately builtins.def. */
+
+static void
+d_build_c_type_nodes (void)
+{
+ void_list_node = build_tree_list (NULL_TREE, void_type_node);
+ string_type_node = build_pointer_type (char_type_node);
+ const_string_type_node
+ = build_pointer_type (build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST));
+
+ if (strcmp (SIZE_TYPE, "unsigned int") == 0)
+ {
+ intmax_type_node = integer_type_node;
+ uintmax_type_node = unsigned_type_node;
+ signed_size_type_node = integer_type_node;
+ }
+ else if (strcmp (SIZE_TYPE, "long unsigned int") == 0)
+ {
+ intmax_type_node = long_integer_type_node;
+ uintmax_type_node = long_unsigned_type_node;
+ signed_size_type_node = long_integer_type_node;
+ }
+ else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0)
+ {
+ intmax_type_node = long_long_integer_type_node;
+ uintmax_type_node = long_long_unsigned_type_node;
+ signed_size_type_node = long_long_integer_type_node;
+ }
+ else
+ gcc_unreachable ();
+
+ wint_type_node = unsigned_type_node;
+ pid_type_node = integer_type_node;
+}
+
+/* Build nodes that are used by the D front-end.
+ These are distinct from C types. */
+
+static void
+d_build_d_type_nodes (void)
+{
+ /* Integral types. */
+ d_byte_type = make_signed_type (8);
+ d_ubyte_type = make_unsigned_type (8);
+
+ d_short_type = make_signed_type (16);
+ d_ushort_type = make_unsigned_type (16);
+
+ d_int_type = make_signed_type (32);
+ d_uint_type = make_unsigned_type (32);
+
+ d_long_type = make_signed_type (64);
+ d_ulong_type = make_unsigned_type (64);
+
+ d_cent_type = make_signed_type (128);
+ d_ucent_type = make_unsigned_type (128);
+
+ {
+ /* Re-define size_t as a D type. */
+ machine_mode type_mode = TYPE_MODE (size_type_node);
+ size_type_node = lang_hooks.types.type_for_mode (type_mode, 1);
+ }
+
+ /* Bool and Character types. */
+ d_bool_type = make_unsigned_type (1);
+ TREE_SET_CODE (d_bool_type, BOOLEAN_TYPE);
+
+ char8_type_node = make_unsigned_type (8);
+ TYPE_STRING_FLAG (char8_type_node) = 1;
+
+ char16_type_node = make_unsigned_type (16);
+ TYPE_STRING_FLAG (char16_type_node) = 1;
+
+ char32_type_node = make_unsigned_type (32);
+ TYPE_STRING_FLAG (char32_type_node) = 1;
+
+ /* Imaginary types. */
+ ifloat_type_node = build_distinct_type_copy (float_type_node);
+ TYPE_IMAGINARY_FLOAT (ifloat_type_node) = 1;
+
+ idouble_type_node = build_distinct_type_copy (double_type_node);
+ TYPE_IMAGINARY_FLOAT (idouble_type_node) = 1;
+
+ ireal_type_node = build_distinct_type_copy (long_double_type_node);
+ TYPE_IMAGINARY_FLOAT (ireal_type_node) = 1;
+
+ /* Used for ModuleInfo, ClassInfo, and Interface decls. */
+ unknown_type_node = make_node (RECORD_TYPE);
+
+ /* Make sure we get a unique function type, so we can give
+ its pointer type a name. (This wins for gdb). */
+ {
+ tree vfunc_type = make_node (FUNCTION_TYPE);
+ TREE_TYPE (vfunc_type) = d_int_type;
+ TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
+ layout_type (vfunc_type);
+
+ vtable_entry_type = build_pointer_type (vfunc_type);
+ }
+
+ vtbl_ptr_type_node = build_pointer_type (vtable_entry_type);
+ layout_type (vtbl_ptr_type_node);
+
+ /* When an object is accessed via an interface, this type appears
+ as the first entry in its vtable. */
+ {
+ tree domain = build_index_type (size_int (3));
+ vtbl_interface_type_node = build_array_type (ptr_type_node, domain);
+ }
+
+ /* Use `void[]' as a generic dynamic array type. */
+ array_type_node = make_struct_type ("__builtin_void[]", 2,
+ get_identifier ("length"), size_type_node,
+ get_identifier ("ptr"), ptr_type_node);
+ TYPE_DYNAMIC_ARRAY (array_type_node) = 1;
+
+ null_array_node = d_array_value (array_type_node, size_zero_node,
+ null_pointer_node);
+}
+
+/* Handle default attributes. */
+
+enum built_in_attribute
+{
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_STRING
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+ ATTR_LAST
+};
+
+static GTY(()) tree built_in_attributes[(int) ATTR_LAST];
+
+/* Initialize the attribute table for all the supported builtins. */
+
+static void
+d_init_attributes (void)
+{
+ /* Fill in the built_in_attributes array. */
+#define DEF_ATTR_NULL_TREE(ENUM) \
+ built_in_attributes[(int) ENUM] = NULL_TREE;
+# define DEF_ATTR_INT(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
+#define DEF_ATTR_STRING(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE);
+#define DEF_ATTR_IDENT(ENUM, STRING) \
+ built_in_attributes[(int) ENUM] = get_identifier (STRING);
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
+ built_in_attributes[(int) ENUM] \
+ = tree_cons (built_in_attributes[(int) PURPOSE], \
+ built_in_attributes[(int) VALUE], \
+ built_in_attributes[(int) CHAIN]);
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_STRING
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+}
+
+/* Builtin types. */
+
+enum d_builtin_type
+{
+#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
+#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
+#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) NAME,
+#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8) NAME,
+#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9) NAME,
+#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10) NAME,
+#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
+#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+ NAME,
+#define DEF_FUNCTION_TYPE_VAR_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) NAME,
+#define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_VAR_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
+#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_9
+#undef DEF_FUNCTION_TYPE_10
+#undef DEF_FUNCTION_TYPE_11
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_FUNCTION_TYPE_VAR_6
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
+#undef DEF_POINTER_TYPE
+ BT_LAST
+};
+
+typedef enum d_builtin_type builtin_type;
+
+/* A temporary array used in communication with def_fn_type. */
+static GTY(()) tree builtin_types[(int) BT_LAST + 1];
+
+/* A helper function for d_init_builtins. Build function type for DEF with
+ return type RET and N arguments. If VAR is true, then the function should
+ be variadic after those N arguments.
+
+ Takes special care not to ICE if any of the types involved are
+ error_mark_node, which indicates that said type is not in fact available
+ (see builtin_type_for_size). In which case the function type as a whole
+ should be error_mark_node. */
+
+static void
+def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...)
+{
+ tree t;
+ tree *args = XALLOCAVEC (tree, n);
+ va_list list;
+ int i;
+
+ va_start (list, n);
+ for (i = 0; i < n; ++i)
+ {
+ builtin_type a = (builtin_type) va_arg (list, int);
+ t = builtin_types[a];
+ if (t == error_mark_node)
+ goto egress;
+ args[i] = t;
+ }
+
+ t = builtin_types[ret];
+ if (t == error_mark_node)
+ goto egress;
+ if (var)
+ t = build_varargs_function_type_array (t, n, args);
+ else
+ t = build_function_type_array (t, n, args);
+
+ egress:
+ builtin_types[def] = t;
+ va_end (list);
+}
+
+/* Create builtin types and functions. VA_LIST_REF_TYPE_NODE and
+ VA_LIST_ARG_TYPE_NODE are used in builtin-types.def. */
+
+static void
+d_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED,
+ tree va_list_arg_type_node ATTRIBUTE_UNUSED)
+{
+#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
+ builtin_types[(int) ENUM] = VALUE;
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
+ def_fn_type (ENUM, RETURN, 0, 0);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
+ def_fn_type (ENUM, RETURN, 0, 1, ARG1);
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
+ def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+ def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+ def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+ def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) \
+ def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) \
+ def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8) \
+ def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8);
+#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9) \
+ def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8, ARG9);
+#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10) \
+ def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8, ARG9, ARG10);
+#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \
+ def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8, ARG9, ARG10, ARG11);
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
+ def_fn_type (ENUM, RETURN, 1, 0);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
+ def_fn_type (ENUM, RETURN, 1, 1, ARG1);
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
+ def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+ def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+ def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+ def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6) \
+ def_fn_type (ENUM, RETURN, 1, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7) \
+ def_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+ ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \
+ def_fn_type (ENUM, RETURN, 1, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+ ARG7, ARG8, ARG9, ARG10, ARG11);
+#define DEF_POINTER_TYPE(ENUM, TYPE) \
+ builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
+
+#include "builtin-types.def"
+
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_9
+#undef DEF_FUNCTION_TYPE_10
+#undef DEF_FUNCTION_TYPE_11
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_FUNCTION_TYPE_VAR_6
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
+#undef DEF_POINTER_TYPE
+ builtin_types[(int) BT_LAST] = NULL_TREE;
+
+ d_init_attributes ();
+
+#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
+ NONANSI_P, ATTRS, IMPLICIT, COND) \
+ if (NAME && COND) \
+ do_build_builtin_fn (ENUM, NAME, CLASS, \
+ builtin_types[(int) TYPE], \
+ BOTH_P, FALLBACK_P, \
+ built_in_attributes[(int) ATTRS], IMPLICIT);
+#include "builtins.def"
+#undef DEF_BUILTIN
+}
+
+/* Build builtin functions and types for the D language frontend. */
+
+void
+d_init_builtins (void)
+{
+ /* Build the "standard" abi va_list. */
+ Type::tvalist = build_frontend_type (va_list_type_node);
+ if (!Type::tvalist)
+ {
+ error ("cannot represent built-in va_list type in D");
+ gcc_unreachable ();
+ }
+
+ /* Map the va_list type to the D frontend Type. This is to prevent both
+ errors in gimplification or an ICE in targetm.canonical_va_list_type. */
+ Type::tvalist->ctype = va_list_type_node;
+ TYPE_LANG_SPECIFIC (va_list_type_node) = build_lang_type (Type::tvalist);
+
+ d_build_c_type_nodes ();
+ d_build_d_type_nodes ();
+
+ if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+ {
+ /* It might seem natural to make the argument type a pointer, but there
+ is no implicit casting from arrays to pointers in D. */
+ d_define_builtins (va_list_type_node, va_list_type_node);
+ }
+ else
+ {
+ d_define_builtins (build_reference_type (va_list_type_node),
+ va_list_type_node);
+ }
+
+ targetm.init_builtins ();
+ build_common_builtin_nodes ();
+}
+
+/* Registration of machine- or os-specific builtin types.
+ Add to builtin types list for maybe processing later
+ if `gcc.builtins' was imported into the current module. */
+
+void
+d_register_builtin_type (tree type, const char *name)
+{
+ tree decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL,
+ get_identifier (name), type);
+ DECL_ARTIFICIAL (decl) = 1;
+
+ if (!TYPE_NAME (type))
+ TYPE_NAME (type) = decl;
+
+ vec_safe_push (gcc_builtins_types, decl);
+}
+
+/* Add DECL to builtin functions list for maybe processing later
+ if `gcc.builtins' was imported into the current module. */
+
+tree
+d_builtin_function (tree decl)
+{
+ if (!flag_no_builtin && DECL_ASSEMBLER_NAME_SET_P (decl))
+ vec_safe_push (gcc_builtins_libfuncs, decl);
+
+ vec_safe_push (gcc_builtins_functions, decl);
+ return decl;
+}
+
+
+#include "gt-d-d-builtins.h"
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
new file mode 100644
index 0000000..74edb36
--- /dev/null
+++ b/gcc/d/d-codegen.cc
@@ -0,0 +1,2660 @@
+/* d-codegen.cc -- Code generation and routines for manipulation of GCC trees.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/ctfe.h"
+#include "dmd/declaration.h"
+#include "dmd/identifier.h"
+#include "dmd/target.h"
+#include "dmd/template.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "stringpool.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "attribs.h"
+#include "function.h"
+
+#include "d-tree.h"
+
+
+/* Return the GCC location for the D frontend location LOC. */
+
+location_t
+make_location_t (const Loc& loc)
+{
+ location_t gcc_location = input_location;
+
+ if (loc.filename)
+ {
+ linemap_add (line_table, LC_ENTER, 0, loc.filename, loc.linnum);
+ linemap_line_start (line_table, loc.linnum, 0);
+ gcc_location = linemap_position_for_column (line_table, loc.charnum);
+ linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
+ }
+
+ return gcc_location;
+}
+
+/* Return the DECL_CONTEXT for symbol DSYM. */
+
+tree
+d_decl_context (Dsymbol *dsym)
+{
+ Dsymbol *parent = dsym;
+ Declaration *decl = dsym->isDeclaration ();
+
+ while ((parent = parent->toParent ()))
+ {
+ /* We've reached the top-level module namespace.
+ Set DECL_CONTEXT as the NAMESPACE_DECL of the enclosing module,
+ but only for extern(D) symbols. */
+ if (parent->isModule ())
+ {
+ if (decl != NULL && decl->linkage != LINKd)
+ return NULL_TREE;
+
+ return build_import_decl (parent);
+ }
+
+ /* Declarations marked as 'static' or '__gshared' are never
+ part of any context except at module level. */
+ if (decl != NULL && decl->isDataseg ())
+ continue;
+
+ /* Nested functions. */
+ FuncDeclaration *fd = parent->isFuncDeclaration ();
+ if (fd != NULL)
+ return get_symbol_decl (fd);
+
+ /* Methods of classes or structs. */
+ AggregateDeclaration *ad = parent->isAggregateDeclaration ();
+ if (ad != NULL)
+ {
+ tree context = build_ctype (ad->type);
+ /* Want the underlying RECORD_TYPE. */
+ if (ad->isClassDeclaration ())
+ context = TREE_TYPE (context);
+
+ return context;
+ }
+
+ /* Instantiated types are given the context of their template. */
+ TemplateInstance *ti = parent->isTemplateInstance ();
+ if (ti != NULL && decl == NULL)
+ parent = ti->tempdecl;
+ }
+
+ return NULL_TREE;
+}
+
+/* Return a copy of record TYPE but safe to modify in any way. */
+
+tree
+copy_aggregate_type (tree type)
+{
+ tree newtype = build_distinct_type_copy (type);
+ TYPE_FIELDS (newtype) = copy_list (TYPE_FIELDS (type));
+
+ for (tree f = TYPE_FIELDS (newtype); f; f = DECL_CHAIN (f))
+ DECL_FIELD_CONTEXT (f) = newtype;
+
+ return newtype;
+}
+
+/* Return TRUE if declaration DECL is a reference type. */
+
+bool
+declaration_reference_p (Declaration *decl)
+{
+ Type *tb = decl->type->toBasetype ();
+
+ /* Declaration is a reference type. */
+ if (tb->ty == Treference || decl->storage_class & (STCout | STCref))
+ return true;
+
+ return false;
+}
+
+/* Returns the real type for declaration DECL. */
+
+tree
+declaration_type (Declaration *decl)
+{
+ /* Lazy declarations are converted to delegates. */
+ if (decl->storage_class & STClazy)
+ {
+ TypeFunction *tf = TypeFunction::create (NULL, decl->type, false, LINKd);
+ TypeDelegate *t = TypeDelegate::create (tf);
+ return build_ctype (t->merge2 ());
+ }
+
+ /* Static array va_list have array->pointer conversions applied. */
+ if (decl->isParameter () && valist_array_p (decl->type))
+ {
+ Type *valist = decl->type->nextOf ()->pointerTo ();
+ valist = valist->castMod (decl->type->mod);
+ return build_ctype (valist);
+ }
+
+ tree type = build_ctype (decl->type);
+
+ /* Parameter is passed by reference. */
+ if (declaration_reference_p (decl))
+ return build_reference_type (type);
+
+ /* The 'this' parameter is always const. */
+ if (decl->isThisDeclaration ())
+ return insert_type_modifiers (type, MODconst);
+
+ return type;
+}
+
+/* These should match the Declaration versions above
+ Return TRUE if parameter ARG is a reference type. */
+
+bool
+argument_reference_p (Parameter *arg)
+{
+ Type *tb = arg->type->toBasetype ();
+
+ /* Parameter is a reference type. */
+ if (tb->ty == Treference || arg->storageClass & (STCout | STCref))
+ return true;
+
+ tree type = build_ctype (arg->type);
+ if (TREE_ADDRESSABLE (type))
+ return true;
+
+ return false;
+}
+
+/* Returns the real type for parameter ARG. */
+
+tree
+type_passed_as (Parameter *arg)
+{
+ /* Lazy parameters are converted to delegates. */
+ if (arg->storageClass & STClazy)
+ {
+ TypeFunction *tf = TypeFunction::create (NULL, arg->type, false, LINKd);
+ TypeDelegate *t = TypeDelegate::create (tf);
+ return build_ctype (t->merge2 ());
+ }
+
+ /* Static array va_list have array->pointer conversions applied. */
+ if (valist_array_p (arg->type))
+ {
+ Type *valist = arg->type->nextOf ()->pointerTo ();
+ valist = valist->castMod (arg->type->mod);
+ return build_ctype (valist);
+ }
+
+ tree type = build_ctype (arg->type);
+
+ /* Parameter is passed by reference. */
+ if (argument_reference_p (arg))
+ return build_reference_type (type);
+
+ return type;
+}
+
+/* Build INTEGER_CST of type TYPE with the value VALUE. */
+
+tree
+build_integer_cst (dinteger_t value, tree type)
+{
+ /* The type is error_mark_node, we can't do anything. */
+ if (error_operand_p (type))
+ return type;
+
+ return build_int_cst_type (type, value);
+}
+
+/* Build REAL_CST of type TOTYPE with the value VALUE. */
+
+tree
+build_float_cst (const real_t& value, Type *totype)
+{
+ real_t new_value;
+ TypeBasic *tb = totype->isTypeBasic ();
+
+ gcc_assert (tb != NULL);
+
+ tree type_node = build_ctype (tb);
+ real_convert (&new_value.rv (), TYPE_MODE (type_node), &value.rv ());
+
+ return build_real (type_node, new_value.rv ());
+}
+
+/* Returns the .length component from the D dynamic array EXP. */
+
+tree
+d_array_length (tree exp)
+{
+ if (error_operand_p (exp))
+ return exp;
+
+ gcc_assert (TYPE_DYNAMIC_ARRAY (TREE_TYPE (exp)));
+
+ /* Get the back-end type for the array and pick out the array
+ length field (assumed to be the first field). */
+ tree len_field = TYPE_FIELDS (TREE_TYPE (exp));
+ return component_ref (exp, len_field);
+}
+
+/* Returns the .ptr component from the D dynamic array EXP. */
+
+tree
+d_array_ptr (tree exp)
+{
+ if (error_operand_p (exp))
+ return exp;
+
+ gcc_assert (TYPE_DYNAMIC_ARRAY (TREE_TYPE (exp)));
+
+ /* Get the back-end type for the array and pick out the array
+ data pointer field (assumed to be the second field). */
+ tree ptr_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp)));
+ return component_ref (exp, ptr_field);
+}
+
+/* Returns a constructor for D dynamic array type TYPE of .length LEN
+ and .ptr pointing to DATA. */
+
+tree
+d_array_value (tree type, tree len, tree data)
+{
+ tree len_field, ptr_field;
+ vec<constructor_elt, va_gc> *ce = NULL;
+
+ gcc_assert (TYPE_DYNAMIC_ARRAY (type));
+ len_field = TYPE_FIELDS (type);
+ ptr_field = TREE_CHAIN (len_field);
+
+ len = convert (TREE_TYPE (len_field), len);
+ data = convert (TREE_TYPE (ptr_field), data);
+
+ CONSTRUCTOR_APPEND_ELT (ce, len_field, len);
+ CONSTRUCTOR_APPEND_ELT (ce, ptr_field, data);
+
+ return build_constructor (type, ce);
+}
+
+/* Returns value representing the array length of expression EXP.
+ TYPE could be a dynamic or static array. */
+
+tree
+get_array_length (tree exp, Type *type)
+{
+ Type *tb = type->toBasetype ();
+
+ switch (tb->ty)
+ {
+ case Tsarray:
+ return size_int (((TypeSArray *) tb)->dim->toUInteger ());
+
+ case Tarray:
+ return d_array_length (exp);
+
+ default:
+ error ("can't determine the length of a %qs", type->toChars ());
+ return error_mark_node;
+ }
+}
+
+/* Create BINFO for a ClassDeclaration's inheritance tree.
+ InterfaceDeclaration's are not included. */
+
+tree
+build_class_binfo (tree super, ClassDeclaration *cd)
+{
+ tree binfo = make_tree_binfo (1);
+ tree ctype = build_ctype (cd->type);
+
+ /* Want RECORD_TYPE, not POINTER_TYPE. */
+ BINFO_TYPE (binfo) = TREE_TYPE (ctype);
+ BINFO_INHERITANCE_CHAIN (binfo) = super;
+ BINFO_OFFSET (binfo) = integer_zero_node;
+
+ if (cd->baseClass)
+ BINFO_BASE_APPEND (binfo, build_class_binfo (binfo, cd->baseClass));
+
+ return binfo;
+}
+
+/* Create BINFO for an InterfaceDeclaration's inheritance tree.
+ In order to access all inherited methods in the debugger,
+ the entire tree must be described.
+ This function makes assumptions about interface layout. */
+
+tree
+build_interface_binfo (tree super, ClassDeclaration *cd, unsigned& offset)
+{
+ tree binfo = make_tree_binfo (cd->baseclasses->dim);
+ tree ctype = build_ctype (cd->type);
+
+ /* Want RECORD_TYPE, not POINTER_TYPE. */
+ BINFO_TYPE (binfo) = TREE_TYPE (ctype);
+ BINFO_INHERITANCE_CHAIN (binfo) = super;
+ BINFO_OFFSET (binfo) = size_int (offset * Target::ptrsize);
+ BINFO_VIRTUAL_P (binfo) = 1;
+
+ for (size_t i = 0; i < cd->baseclasses->dim; i++, offset++)
+ {
+ BaseClass *bc = (*cd->baseclasses)[i];
+ BINFO_BASE_APPEND (binfo, build_interface_binfo (binfo, bc->sym, offset));
+ }
+
+ return binfo;
+}
+
+/* Returns the .funcptr component from the D delegate EXP. */
+
+tree
+delegate_method (tree exp)
+{
+ /* Get the back-end type for the delegate and pick out the funcptr field
+ (assumed to be the second field). */
+ gcc_assert (TYPE_DELEGATE (TREE_TYPE (exp)));
+ tree method_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp)));
+ return component_ref (exp, method_field);
+}
+
+/* Returns the .object component from the delegate EXP. */
+
+tree
+delegate_object (tree exp)
+{
+ /* Get the back-end type for the delegate and pick out the object field
+ (assumed to be the first field). */
+ gcc_assert (TYPE_DELEGATE (TREE_TYPE (exp)));
+ tree obj_field = TYPE_FIELDS (TREE_TYPE (exp));
+ return component_ref (exp, obj_field);
+}
+
+/* Build a delegate literal of type TYPE whose pointer function is
+ METHOD, and hidden object is OBJECT. */
+
+tree
+build_delegate_cst (tree method, tree object, Type *type)
+{
+ tree ctor = make_node (CONSTRUCTOR);
+ tree ctype;
+
+ Type *tb = type->toBasetype ();
+ if (tb->ty == Tdelegate)
+ ctype = build_ctype (type);
+ else
+ {
+ /* Convert a function method into an anonymous delegate. */
+ ctype = make_struct_type ("delegate()", 2,
+ get_identifier ("object"), TREE_TYPE (object),
+ get_identifier ("func"), TREE_TYPE (method));
+ TYPE_DELEGATE (ctype) = 1;
+ }
+
+ vec<constructor_elt, va_gc> *ce = NULL;
+ CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (ctype), object);
+ CONSTRUCTOR_APPEND_ELT (ce, TREE_CHAIN (TYPE_FIELDS (ctype)), method);
+
+ CONSTRUCTOR_ELTS (ctor) = ce;
+ TREE_TYPE (ctor) = ctype;
+
+ return ctor;
+}
+
+/* Builds a temporary tree to store the CALLEE and OBJECT
+ of a method call expression of type TYPE. */
+
+tree
+build_method_call (tree callee, tree object, Type *type)
+{
+ tree t = build_delegate_cst (callee, object, type);
+ METHOD_CALL_EXPR (t) = 1;
+ return t;
+}
+
+/* Extract callee and object from T and return in to CALLEE and OBJECT. */
+
+void
+extract_from_method_call (tree t, tree& callee, tree& object)
+{
+ gcc_assert (METHOD_CALL_EXPR (t));
+ object = CONSTRUCTOR_ELT (t, 0)->value;
+ callee = CONSTRUCTOR_ELT (t, 1)->value;
+}
+
+/* Build a dereference into the virtual table for OBJECT to retrieve
+ a function pointer of type FNTYPE at position INDEX. */
+
+tree
+build_vindex_ref (tree object, tree fntype, size_t index)
+{
+ /* The vtable is the first field. Interface methods are also in the class's
+ vtable, so we don't need to convert from a class to an interface. */
+ tree result = build_deref (object);
+ result = component_ref (result, TYPE_FIELDS (TREE_TYPE (result)));
+
+ gcc_assert (POINTER_TYPE_P (fntype));
+
+ return build_memref (fntype, result, size_int (Target::ptrsize * index));
+}
+
+/* Return TRUE if EXP is a valid lvalue. Lvalue references cannot be
+ made into temporaries, otherwise any assignments will be lost. */
+
+static bool
+lvalue_p (tree exp)
+{
+ const enum tree_code code = TREE_CODE (exp);
+
+ switch (code)
+ {
+ case SAVE_EXPR:
+ return false;
+
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ return !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (exp));
+
+ case IMAGPART_EXPR:
+ case REALPART_EXPR:
+ case COMPONENT_REF:
+ CASE_CONVERT:
+ return lvalue_p (TREE_OPERAND (exp, 0));
+
+ case COND_EXPR:
+ return (lvalue_p (TREE_OPERAND (exp, 1)
+ ? TREE_OPERAND (exp, 1)
+ : TREE_OPERAND (exp, 0))
+ && lvalue_p (TREE_OPERAND (exp, 2)));
+
+ case TARGET_EXPR:
+ return true;
+
+ case COMPOUND_EXPR:
+ return lvalue_p (TREE_OPERAND (exp, 1));
+
+ default:
+ return false;
+ }
+}
+
+/* Create a SAVE_EXPR if EXP might have unwanted side effects if referenced
+ more than once in an expression. */
+
+tree
+d_save_expr (tree exp)
+{
+ if (TREE_SIDE_EFFECTS (exp))
+ {
+ if (lvalue_p (exp))
+ return stabilize_reference (exp);
+
+ return save_expr (exp);
+ }
+
+ return exp;
+}
+
+/* VALUEP is an expression we want to pre-evaluate or perform a computation on.
+ The expression returned by this function is the part whose value we don't
+ care about, storing the value in VALUEP. Callers must ensure that the
+ returned expression is evaluated before VALUEP. */
+
+tree
+stabilize_expr (tree *valuep)
+{
+ tree expr = *valuep;
+ const enum tree_code code = TREE_CODE (expr);
+ tree lhs;
+ tree rhs;
+
+ switch (code)
+ {
+ case COMPOUND_EXPR:
+ /* Given ((e1, ...), eN):
+ Store the last RHS 'eN' expression in VALUEP. */
+ lhs = TREE_OPERAND (expr, 0);
+ rhs = TREE_OPERAND (expr, 1);
+ lhs = compound_expr (lhs, stabilize_expr (&rhs));
+ *valuep = rhs;
+ return lhs;
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Return a TARGET_EXPR, initializing the DECL with EXP. */
+
+tree
+build_target_expr (tree decl, tree exp)
+{
+ tree type = TREE_TYPE (decl);
+ tree result = build4 (TARGET_EXPR, type, decl, exp, NULL_TREE, NULL_TREE);
+
+ if (EXPR_HAS_LOCATION (exp))
+ SET_EXPR_LOCATION (result, EXPR_LOCATION (exp));
+
+ /* If decl must always reside in memory. */
+ if (TREE_ADDRESSABLE (type))
+ d_mark_addressable (decl);
+
+ /* Always set TREE_SIDE_EFFECTS so that expand_expr does not ignore the
+ TARGET_EXPR. If there really turn out to be no side effects, then the
+ optimizer should be able to remove it. */
+ TREE_SIDE_EFFECTS (result) = 1;
+
+ return result;
+}
+
+/* Like the above function, but initializes a new temporary. */
+
+tree
+force_target_expr (tree exp)
+{
+ tree decl = create_temporary_var (TREE_TYPE (exp));
+
+ return build_target_expr (decl, exp);
+}
+
+/* Returns the address of the expression EXP. */
+
+tree
+build_address (tree exp)
+{
+ if (error_operand_p (exp))
+ return exp;
+
+ tree ptrtype;
+ tree type = TREE_TYPE (exp);
+
+ if (TREE_CODE (exp) == STRING_CST)
+ {
+ /* Just convert string literals (char[]) to C-style strings (char *),
+ otherwise the latter method (char[]*) causes conversion problems
+ during gimplification. */
+ ptrtype = build_pointer_type (TREE_TYPE (type));
+ }
+ else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node)
+ && TREE_CODE (TYPE_MAIN_VARIANT (type)) == ARRAY_TYPE)
+ {
+ /* Special case for va_list, allow arrays to decay to a pointer. */
+ ptrtype = build_pointer_type (TREE_TYPE (type));
+ }
+ else
+ ptrtype = build_pointer_type (type);
+
+ /* Maybe rewrite: &(e1, e2) => (e1, &e2). */
+ tree init = stabilize_expr (&exp);
+
+ /* Can't take the address of a manifest constant, instead use its value. */
+ if (TREE_CODE (exp) == CONST_DECL)
+ exp = DECL_INITIAL (exp);
+
+ /* Some expression lowering may request an address of a compile-time constant.
+ Make sure it is assigned to a location we can reference. */
+ if (CONSTANT_CLASS_P (exp) && TREE_CODE (exp) != STRING_CST)
+ exp = force_target_expr (exp);
+
+ d_mark_addressable (exp);
+ exp = build_fold_addr_expr_with_type_loc (input_location, exp, ptrtype);
+
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ TREE_NO_TRAMPOLINE (exp) = 1;
+
+ return compound_expr (init, exp);
+}
+
+/* Mark EXP saying that we need to be able to take the
+ address of it; it should not be allocated in a register. */
+
+tree
+d_mark_addressable (tree exp)
+{
+ switch (TREE_CODE (exp))
+ {
+ case ADDR_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ d_mark_addressable (TREE_OPERAND (exp, 0));
+ break;
+
+ case PARM_DECL:
+ case VAR_DECL:
+ case RESULT_DECL:
+ case CONST_DECL:
+ case FUNCTION_DECL:
+ TREE_ADDRESSABLE (exp) = 1;
+ break;
+
+ case CONSTRUCTOR:
+ TREE_ADDRESSABLE (exp) = 1;
+ break;
+
+ case TARGET_EXPR:
+ TREE_ADDRESSABLE (exp) = 1;
+ d_mark_addressable (TREE_OPERAND (exp, 0));
+ break;
+
+ default:
+ break;
+ }
+
+ return exp;
+}
+
+/* Mark EXP as "used" in the program for the benefit of
+ -Wunused warning purposes. */
+
+tree
+d_mark_used (tree exp)
+{
+ switch (TREE_CODE (exp))
+ {
+ case VAR_DECL:
+ case CONST_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case FUNCTION_DECL:
+ TREE_USED (exp) = 1;
+ break;
+
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ case MODIFY_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case ADDR_EXPR:
+ d_mark_used (TREE_OPERAND (exp, 0));
+ break;
+
+ case COMPOUND_EXPR:
+ d_mark_used (TREE_OPERAND (exp, 0));
+ d_mark_used (TREE_OPERAND (exp, 1));
+ break;
+
+ default:
+ break;
+ }
+ return exp;
+}
+
+/* Mark EXP as read, not just set, for set but not used -Wunused
+ warning purposes. */
+
+tree
+d_mark_read (tree exp)
+{
+ switch (TREE_CODE (exp))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ TREE_USED (exp) = 1;
+ DECL_READ_P (exp) = 1;
+ break;
+
+ case ARRAY_REF:
+ case COMPONENT_REF:
+ case MODIFY_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case ADDR_EXPR:
+ d_mark_read (TREE_OPERAND (exp, 0));
+ break;
+
+ case COMPOUND_EXPR:
+ d_mark_read (TREE_OPERAND (exp, 1));
+ break;
+
+ default:
+ break;
+ }
+ return exp;
+}
+
+/* Return TRUE if the struct SD is suitable for comparison using memcmp.
+ This is because we don't guarantee that padding is zero-initialized for
+ a stack variable, so we can't use memcmp to compare struct values. */
+
+bool
+identity_compare_p (StructDeclaration *sd)
+{
+ if (sd->isUnionDeclaration ())
+ return true;
+
+ unsigned offset = 0;
+
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *vd = sd->fields[i];
+
+ /* Check inner data structures. */
+ if (vd->type->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *) vd->type;
+ if (!identity_compare_p (ts->sym))
+ return false;
+ }
+
+ if (offset <= vd->offset)
+ {
+ /* There's a hole in the struct. */
+ if (offset != vd->offset)
+ return false;
+
+ offset += vd->type->size ();
+ }
+ }
+
+ /* Any trailing padding may not be zero. */
+ if (offset < sd->structsize)
+ return false;
+
+ return true;
+}
+
+/* Lower a field-by-field equality expression between T1 and T2 of type SD.
+ CODE is the EQ_EXPR or NE_EXPR comparison. */
+
+static tree
+lower_struct_comparison (tree_code code, StructDeclaration *sd,
+ tree t1, tree t2)
+{
+ tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+ tree tmemcmp = NULL_TREE;
+
+ /* We can skip the compare if the structs are empty. */
+ if (sd->fields.dim == 0)
+ {
+ tmemcmp = build_boolop (code, integer_zero_node, integer_zero_node);
+ if (TREE_SIDE_EFFECTS (t2))
+ tmemcmp = compound_expr (t2, tmemcmp);
+ if (TREE_SIDE_EFFECTS (t1))
+ tmemcmp = compound_expr (t1, tmemcmp);
+
+ return tmemcmp;
+ }
+
+ /* Let back-end take care of union comparisons. */
+ if (sd->isUnionDeclaration ())
+ {
+ tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP), 3,
+ build_address (t1), build_address (t2),
+ size_int (sd->structsize));
+
+ return build_boolop (code, tmemcmp, integer_zero_node);
+ }
+
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *vd = sd->fields[i];
+ tree sfield = get_symbol_decl (vd);
+
+ tree t1ref = component_ref (t1, sfield);
+ tree t2ref = component_ref (t2, sfield);
+ tree tcmp;
+
+ if (vd->type->ty == Tstruct)
+ {
+ /* Compare inner data structures. */
+ StructDeclaration *decl = ((TypeStruct *) vd->type)->sym;
+ tcmp = lower_struct_comparison (code, decl, t1ref, t2ref);
+ }
+ else
+ {
+ tree stype = build_ctype (vd->type);
+ opt_scalar_int_mode mode = int_mode_for_mode (TYPE_MODE (stype));
+
+ if (vd->type->ty != Tvector && vd->type->isintegral ())
+ {
+ /* Integer comparison, no special handling required. */
+ tcmp = build_boolop (code, t1ref, t2ref);
+ }
+ else if (mode.exists ())
+ {
+ /* Compare field bits as their corresponding integer type.
+ *((T*) &t1) == *((T*) &t2) */
+ tree tmode = lang_hooks.types.type_for_mode (mode.require (), 1);
+
+ if (tmode == NULL_TREE)
+ tmode = make_unsigned_type (GET_MODE_BITSIZE (mode.require ()));
+
+ t1ref = build_vconvert (tmode, t1ref);
+ t2ref = build_vconvert (tmode, t2ref);
+
+ tcmp = build_boolop (code, t1ref, t2ref);
+ }
+ else
+ {
+ /* Simple memcmp between types. */
+ tcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP),
+ 3, build_address (t1ref),
+ build_address (t2ref),
+ TYPE_SIZE_UNIT (stype));
+
+ tcmp = build_boolop (code, tcmp, integer_zero_node);
+ }
+ }
+
+ tmemcmp = (tmemcmp) ? build_boolop (tcode, tmemcmp, tcmp) : tcmp;
+ }
+
+ return tmemcmp;
+}
+
+
+/* Build an equality expression between two RECORD_TYPES T1 and T2 of type SD.
+ If possible, use memcmp, otherwise field-by-field comparison is done.
+ CODE is the EQ_EXPR or NE_EXPR comparison. */
+
+tree
+build_struct_comparison (tree_code code, StructDeclaration *sd,
+ tree t1, tree t2)
+{
+ /* We can skip the compare if the structs are empty. */
+ if (sd->fields.dim == 0)
+ {
+ tree exp = build_boolop (code, integer_zero_node, integer_zero_node);
+ if (TREE_SIDE_EFFECTS (t2))
+ exp = compound_expr (t2, exp);
+ if (TREE_SIDE_EFFECTS (t1))
+ exp = compound_expr (t1, exp);
+
+ return exp;
+ }
+
+ /* Make temporaries to prevent multiple evaluations. */
+ tree t1init = stabilize_expr (&t1);
+ tree t2init = stabilize_expr (&t2);
+ tree result;
+
+ t1 = d_save_expr (t1);
+ t2 = d_save_expr (t2);
+
+ /* Bitwise comparison of structs not returned in memory may not work
+ due to data holes loosing its zero padding upon return.
+ As a heuristic, small structs are not compared using memcmp either. */
+ if (TYPE_MODE (TREE_TYPE (t1)) != BLKmode || !identity_compare_p (sd))
+ result = lower_struct_comparison (code, sd, t1, t2);
+ else
+ {
+ /* Do bit compare of structs. */
+ tree size = size_int (sd->structsize);
+ tree tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP),
+ 3, build_address (t1),
+ build_address (t2), size);
+
+ result = build_boolop (code, tmemcmp, integer_zero_node);
+ }
+
+ return compound_expr (compound_expr (t1init, t2init), result);
+}
+
+/* Build an equality expression between two ARRAY_TYPES of size LENGTH.
+ The pointer references are T1 and T2, and the element type is SD.
+ CODE is the EQ_EXPR or NE_EXPR comparison. */
+
+tree
+build_array_struct_comparison (tree_code code, StructDeclaration *sd,
+ tree length, tree t1, tree t2)
+{
+ tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+
+ /* Build temporary for the result of the comparison.
+ Initialize as either 0 or 1 depending on operation. */
+ tree result = build_local_temp (d_bool_type);
+ tree init = build_boolop (code, integer_zero_node, integer_zero_node);
+ add_stmt (build_assign (INIT_EXPR, result, init));
+
+ /* Cast pointer-to-array to pointer-to-struct. */
+ tree ptrtype = build_ctype (sd->type->pointerTo ());
+ tree lentype = TREE_TYPE (length);
+
+ push_binding_level (level_block);
+ push_stmt_list ();
+
+ /* Build temporary locals for length and pointers. */
+ tree t = build_local_temp (size_type_node);
+ add_stmt (build_assign (INIT_EXPR, t, length));
+ length = t;
+
+ t = build_local_temp (ptrtype);
+ add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t1)));
+ t1 = t;
+
+ t = build_local_temp (ptrtype);
+ add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t2)));
+ t2 = t;
+
+ /* Build loop for comparing each element. */
+ push_stmt_list ();
+
+ /* Exit logic for the loop.
+ if (length == 0 || result OP 0) break; */
+ t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node));
+ t = build_boolop (TRUTH_ORIF_EXPR, t, build_boolop (code, result,
+ boolean_false_node));
+ t = build1 (EXIT_EXPR, void_type_node, t);
+ add_stmt (t);
+
+ /* Do comparison, caching the value.
+ result = result OP (*t1 == *t2); */
+ t = build_struct_comparison (code, sd, build_deref (t1), build_deref (t2));
+ t = build_boolop (tcode, result, t);
+ t = modify_expr (result, t);
+ add_stmt (t);
+
+ /* Move both pointers to next element position.
+ t1++, t2++; */
+ tree size = d_convert (ptrtype, TYPE_SIZE_UNIT (TREE_TYPE (ptrtype)));
+ t = build2 (POSTINCREMENT_EXPR, ptrtype, t1, size);
+ add_stmt (t);
+ t = build2 (POSTINCREMENT_EXPR, ptrtype, t2, size);
+ add_stmt (t);
+
+ /* Decrease loop counter.
+ length -= 1; */
+ t = build2 (POSTDECREMENT_EXPR, lentype, length,
+ d_convert (lentype, integer_one_node));
+ add_stmt (t);
+
+ /* Pop statements and finish loop. */
+ tree body = pop_stmt_list ();
+ add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+ /* Wrap it up into a bind expression. */
+ tree stmt_list = pop_stmt_list ();
+ tree block = pop_binding_level ();
+
+ body = build3 (BIND_EXPR, void_type_node,
+ BLOCK_VARS (block), stmt_list, block);
+
+ return compound_expr (body, result);
+}
+
+/* Create an anonymous field of type ubyte[T] at OFFSET to fill
+ the alignment hole between OFFSET and FIELDPOS. */
+
+static tree
+build_alignment_field (tree type, HOST_WIDE_INT offset, HOST_WIDE_INT fieldpos)
+{
+ tree atype = make_array_type (Type::tuns8, fieldpos - offset);
+ tree field = create_field_decl (atype, NULL, 1, 1);
+
+ SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (atype));
+ DECL_FIELD_OFFSET (field) = size_int (offset);
+ DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
+ DECL_FIELD_CONTEXT (field) = type;
+ DECL_PADDING_P (field) = 1;
+
+ layout_decl (field, 0);
+
+ return field;
+}
+
+/* Build a constructor for a variable of aggregate type TYPE using the
+ initializer INIT, an ordered flat list of fields and values provided
+ by the frontend. The returned constructor should be a value that
+ matches the layout of TYPE. */
+
+tree
+build_struct_literal (tree type, vec<constructor_elt, va_gc> *init)
+{
+ /* If the initializer was empty, use default zero initialization. */
+ if (vec_safe_is_empty (init))
+ return build_constructor (type, NULL);
+
+ vec<constructor_elt, va_gc> *ve = NULL;
+ HOST_WIDE_INT offset = 0;
+ bool constant_p = true;
+ bool fillholes = true;
+ bool finished = false;
+
+ /* Filling alignment holes this only applies to structs. */
+ if (TREE_CODE (type) != RECORD_TYPE
+ || CLASS_TYPE_P (type) || TYPE_PACKED (type))
+ fillholes = false;
+
+ /* Walk through each field, matching our initializer list. */
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ bool is_initialized = false;
+ tree value;
+
+ if (DECL_NAME (field) == NULL_TREE
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ {
+ /* Search all nesting aggregates, if nothing is found, then
+ this will return an empty initializer to fill the hole. */
+ value = build_struct_literal (TREE_TYPE (field), init);
+
+ if (!initializer_zerop (value))
+ is_initialized = true;
+ }
+ else
+ {
+ /* Search for the value to initialize the next field. Once found,
+ pop it from the init list so we don't look at it again. */
+ unsigned HOST_WIDE_INT idx;
+ tree index;
+
+ FOR_EACH_CONSTRUCTOR_ELT (init, idx, index, value)
+ {
+ /* If the index is NULL, then just assign it to the next field.
+ This comes from layout_typeinfo(), which generates a flat
+ list of values that we must shape into the record type. */
+ if (index == field || index == NULL_TREE)
+ {
+ init->ordered_remove (idx);
+ if (!finished)
+ is_initialized = true;
+ break;
+ }
+ }
+ }
+
+ if (is_initialized)
+ {
+ HOST_WIDE_INT fieldpos = int_byte_position (field);
+ gcc_assert (value != NULL_TREE);
+
+ /* Insert anonymous fields in the constructor for padding out
+ alignment holes in-place between fields. */
+ if (fillholes && offset < fieldpos)
+ {
+ tree pfield = build_alignment_field (type, offset, fieldpos);
+ tree pvalue = build_zero_cst (TREE_TYPE (pfield));
+ CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
+ }
+
+ /* Must not initialize fields that overlap. */
+ if (fieldpos < offset)
+ {
+ /* Find the nearest user defined type and field. */
+ tree vtype = type;
+ while (ANON_AGGR_TYPE_P (vtype))
+ vtype = TYPE_CONTEXT (vtype);
+
+ tree vfield = field;
+ if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (vfield))
+ && ANON_AGGR_TYPE_P (TREE_TYPE (vfield)))
+ vfield = TYPE_FIELDS (TREE_TYPE (vfield));
+
+ /* Must not generate errors for compiler generated fields. */
+ gcc_assert (TYPE_NAME (vtype) && DECL_NAME (vfield));
+ error ("overlapping initializer for field %qT.%qD",
+ TYPE_NAME (vtype), DECL_NAME (vfield));
+ }
+
+ if (!TREE_CONSTANT (value))
+ constant_p = false;
+
+ CONSTRUCTOR_APPEND_ELT (ve, field, value);
+
+ /* For unions, only the first field is initialized, any other field
+ initializers found for this union are drained and ignored. */
+ if (TREE_CODE (type) == UNION_TYPE)
+ finished = true;
+ }
+
+ /* Move offset to the next position in the struct. */
+ if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ offset = int_byte_position (field)
+ + int_size_in_bytes (TREE_TYPE (field));
+ }
+
+ /* If all initializers have been assigned, there's nothing else to do. */
+ if (vec_safe_is_empty (init))
+ break;
+ }
+
+ /* Finally pad out the end of the record. */
+ if (fillholes && offset < int_size_in_bytes (type))
+ {
+ tree pfield = build_alignment_field (type, offset,
+ int_size_in_bytes (type));
+ tree pvalue = build_zero_cst (TREE_TYPE (pfield));
+ CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
+ }
+
+ /* Ensure that we have consumed all values. */
+ gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type));
+
+ tree ctor = build_constructor (type, ve);
+
+ if (constant_p)
+ TREE_CONSTANT (ctor) = 1;
+
+ return ctor;
+}
+
+/* Given the TYPE of an anonymous field inside T, return the
+ FIELD_DECL for the field. If not found return NULL_TREE.
+ Because anonymous types can nest, we must also search all
+ anonymous fields that are directly reachable. */
+
+static tree
+lookup_anon_field (tree t, tree type)
+{
+ t = TYPE_MAIN_VARIANT (t);
+
+ for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+ {
+ if (DECL_NAME (field) == NULL_TREE)
+ {
+ /* If we find it directly, return the field. */
+ if (type == TYPE_MAIN_VARIANT (TREE_TYPE (field)))
+ return field;
+
+ /* Otherwise, it could be nested, search harder. */
+ if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ {
+ tree subfield = lookup_anon_field (TREE_TYPE (field), type);
+ if (subfield)
+ return subfield;
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Builds OBJECT.FIELD component reference. */
+
+tree
+component_ref (tree object, tree field)
+{
+ if (error_operand_p (object) || error_operand_p (field))
+ return error_mark_node;
+
+ gcc_assert (TREE_CODE (field) == FIELD_DECL);
+
+ /* Maybe rewrite: (e1, e2).field => (e1, e2.field) */
+ tree init = stabilize_expr (&object);
+
+ /* If the FIELD is from an anonymous aggregate, generate a reference
+ to the anonymous data member, and recur to find FIELD. */
+ if (ANON_AGGR_TYPE_P (DECL_CONTEXT (field)))
+ {
+ tree anonymous_field = lookup_anon_field (TREE_TYPE (object),
+ DECL_CONTEXT (field));
+ object = component_ref (object, anonymous_field);
+ }
+
+ tree result = fold_build3_loc (input_location, COMPONENT_REF,
+ TREE_TYPE (field), object, field, NULL_TREE);
+
+ return compound_expr (init, result);
+}
+
+/* Build an assignment expression of lvalue LHS from value RHS.
+ CODE is the code for a binary operator that we use to combine
+ the old value of LHS with RHS to get the new value. */
+
+tree
+build_assign (tree_code code, tree lhs, tree rhs)
+{
+ tree init = stabilize_expr (&lhs);
+ init = compound_expr (init, stabilize_expr (&rhs));
+
+ /* If initializing the LHS using a function that returns via NRVO. */
+ if (code == INIT_EXPR && TREE_CODE (rhs) == CALL_EXPR
+ && AGGREGATE_TYPE_P (TREE_TYPE (rhs))
+ && aggregate_value_p (TREE_TYPE (rhs), rhs))
+ {
+ /* Mark as addressable here, which should ensure the return slot is the
+ address of the LHS expression, taken care of by back-end. */
+ d_mark_addressable (lhs);
+ CALL_EXPR_RETURN_SLOT_OPT (rhs) = true;
+ }
+
+ /* The LHS assignment replaces the temporary in TARGET_EXPR_SLOT. */
+ if (TREE_CODE (rhs) == TARGET_EXPR)
+ {
+ /* If CODE is not INIT_EXPR, can't initialize LHS directly,
+ since that would cause the LHS to be constructed twice.
+ So we force the TARGET_EXPR to be expanded without a target. */
+ if (code != INIT_EXPR)
+ rhs = compound_expr (rhs, TARGET_EXPR_SLOT (rhs));
+ else
+ {
+ d_mark_addressable (lhs);
+ rhs = TARGET_EXPR_INITIAL (rhs);
+ }
+ }
+
+ tree result = fold_build2_loc (input_location, code,
+ TREE_TYPE (lhs), lhs, rhs);
+ return compound_expr (init, result);
+}
+
+/* Build an assignment expression of lvalue LHS from value RHS. */
+
+tree
+modify_expr (tree lhs, tree rhs)
+{
+ return build_assign (MODIFY_EXPR, lhs, rhs);
+}
+
+/* Return EXP represented as TYPE. */
+
+tree
+build_nop (tree type, tree exp)
+{
+ if (error_operand_p (exp))
+ return exp;
+
+ /* Maybe rewrite: cast(TYPE)(e1, e2) => (e1, cast(TYPE) e2) */
+ tree init = stabilize_expr (&exp);
+ exp = fold_build1_loc (input_location, NOP_EXPR, type, exp);
+
+ return compound_expr (init, exp);
+}
+
+/* Return EXP to be viewed as being another type TYPE. Same as build_nop,
+ except that EXP is type-punned, rather than a straight-forward cast. */
+
+tree
+build_vconvert (tree type, tree exp)
+{
+ /* Building *(cast(TYPE *)&e1) directly rather then using VIEW_CONVERT_EXPR
+ makes sure this works for vector-to-array viewing, or if EXP ends up being
+ used as the LHS of a MODIFY_EXPR. */
+ return indirect_ref (type, build_address (exp));
+}
+
+/* Maybe warn about ARG being an address that can never be null. */
+
+static void
+warn_for_null_address (tree arg)
+{
+ if (TREE_CODE (arg) == ADDR_EXPR
+ && decl_with_nonnull_addr_p (TREE_OPERAND (arg, 0)))
+ warning (OPT_Waddress,
+ "the address of %qD will never be %<null%>",
+ TREE_OPERAND (arg, 0));
+}
+
+/* Build a boolean ARG0 op ARG1 expression. */
+
+tree
+build_boolop (tree_code code, tree arg0, tree arg1)
+{
+ /* Aggregate comparisons may get lowered to a call to builtin memcmp,
+ so need to remove all side effects incase its address is taken. */
+ if (AGGREGATE_TYPE_P (TREE_TYPE (arg0)))
+ arg0 = d_save_expr (arg0);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (arg1)))
+ arg1 = d_save_expr (arg1);
+
+ if (VECTOR_TYPE_P (TREE_TYPE (arg0)) && VECTOR_TYPE_P (TREE_TYPE (arg1)))
+ {
+ /* Build a vector comparison.
+ VEC_COND_EXPR <e1 op e2, { -1, -1, -1, -1 }, { 0, 0, 0, 0 }>; */
+ tree type = TREE_TYPE (arg0);
+ tree cmptype = build_same_sized_truth_vector_type (type);
+ tree cmp = fold_build2_loc (input_location, code, cmptype, arg0, arg1);
+
+ return fold_build3_loc (input_location, VEC_COND_EXPR, type, cmp,
+ build_minus_one_cst (type),
+ build_zero_cst (type));
+ }
+
+ if (code == EQ_EXPR || code == NE_EXPR)
+ {
+ /* Check if comparing the address of a variable to null. */
+ if (POINTER_TYPE_P (TREE_TYPE (arg0)) && integer_zerop (arg1))
+ warn_for_null_address (arg0);
+ if (POINTER_TYPE_P (TREE_TYPE (arg1)) && integer_zerop (arg0))
+ warn_for_null_address (arg1);
+ }
+
+ return fold_build2_loc (input_location, code, d_bool_type,
+ arg0, d_convert (TREE_TYPE (arg0), arg1));
+}
+
+/* Return a COND_EXPR. ARG0, ARG1, and ARG2 are the three
+ arguments to the conditional expression. */
+
+tree
+build_condition (tree type, tree arg0, tree arg1, tree arg2)
+{
+ if (arg1 == void_node)
+ arg1 = build_empty_stmt (input_location);
+
+ if (arg2 == void_node)
+ arg2 = build_empty_stmt (input_location);
+
+ return fold_build3_loc (input_location, COND_EXPR,
+ type, arg0, arg1, arg2);
+}
+
+tree
+build_vcondition (tree arg0, tree arg1, tree arg2)
+{
+ return build_condition (void_type_node, arg0, arg1, arg2);
+}
+
+/* Build a compound expr to join ARG0 and ARG1 together. */
+
+tree
+compound_expr (tree arg0, tree arg1)
+{
+ if (arg1 == NULL_TREE)
+ return arg0;
+
+ if (arg0 == NULL_TREE || !TREE_SIDE_EFFECTS (arg0))
+ return arg1;
+
+ if (TREE_CODE (arg1) == TARGET_EXPR)
+ {
+ /* If the rhs is a TARGET_EXPR, then build the compound expression
+ inside the target_expr's initializer. This helps the compiler
+ to eliminate unnecessary temporaries. */
+ tree init = compound_expr (arg0, TARGET_EXPR_INITIAL (arg1));
+ TARGET_EXPR_INITIAL (arg1) = init;
+
+ return arg1;
+ }
+
+ return fold_build2_loc (input_location, COMPOUND_EXPR,
+ TREE_TYPE (arg1), arg0, arg1);
+}
+
+/* Build a return expression. */
+
+tree
+return_expr (tree ret)
+{
+ return fold_build1_loc (input_location, RETURN_EXPR,
+ void_type_node, ret);
+}
+
+/* Return the product of ARG0 and ARG1 as a size_type_node. */
+
+tree
+size_mult_expr (tree arg0, tree arg1)
+{
+ return fold_build2_loc (input_location, MULT_EXPR, size_type_node,
+ d_convert (size_type_node, arg0),
+ d_convert (size_type_node, arg1));
+
+}
+
+/* Return the real part of CE, which should be a complex expression. */
+
+tree
+real_part (tree ce)
+{
+ return fold_build1_loc (input_location, REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (ce)), ce);
+}
+
+/* Return the imaginary part of CE, which should be a complex expression. */
+
+tree
+imaginary_part (tree ce)
+{
+ return fold_build1_loc (input_location, IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (ce)), ce);
+}
+
+/* Build a complex expression of type TYPE using RE and IM. */
+
+tree
+complex_expr (tree type, tree re, tree im)
+{
+ return fold_build2_loc (input_location, COMPLEX_EXPR,
+ type, re, im);
+}
+
+/* Cast EXP (which should be a pointer) to TYPE* and then indirect.
+ The back-end requires this cast in many cases. */
+
+tree
+indirect_ref (tree type, tree exp)
+{
+ if (error_operand_p (exp))
+ return exp;
+
+ /* Maybe rewrite: *(e1, e2) => (e1, *e2) */
+ tree init = stabilize_expr (&exp);
+
+ if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE)
+ exp = fold_build1 (INDIRECT_REF, type, exp);
+ else
+ {
+ exp = build_nop (build_pointer_type (type), exp);
+ exp = build_deref (exp);
+ }
+
+ return compound_expr (init, exp);
+}
+
+/* Returns indirect reference of EXP, which must be a pointer type. */
+
+tree
+build_deref (tree exp)
+{
+ if (error_operand_p (exp))
+ return exp;
+
+ /* Maybe rewrite: *(e1, e2) => (e1, *e2) */
+ tree init = stabilize_expr (&exp);
+
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp)));
+
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ exp = TREE_OPERAND (exp, 0);
+ else
+ exp = build_fold_indirect_ref (exp);
+
+ return compound_expr (init, exp);
+}
+
+/* Builds pointer offset expression PTR[INDEX]. */
+
+tree
+build_array_index (tree ptr, tree index)
+{
+ if (error_operand_p (ptr) || error_operand_p (index))
+ return error_mark_node;
+
+ tree ptr_type = TREE_TYPE (ptr);
+ tree target_type = TREE_TYPE (ptr_type);
+
+ tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
+ TYPE_UNSIGNED (sizetype));
+
+ /* Array element size. */
+ tree size_exp = size_in_bytes (target_type);
+
+ if (integer_zerop (size_exp))
+ {
+ /* Test for array of void. */
+ if (TYPE_MODE (target_type) == TYPE_MODE (void_type_node))
+ index = fold_convert (type, index);
+ else
+ {
+ /* Should catch this earlier. */
+ error ("invalid use of incomplete type %qD", TYPE_NAME (target_type));
+ ptr_type = error_mark_node;
+ }
+ }
+ else if (integer_onep (size_exp))
+ {
+ /* Array of bytes -- No need to multiply. */
+ index = fold_convert (type, index);
+ }
+ else
+ {
+ index = d_convert (type, index);
+ index = fold_build2 (MULT_EXPR, TREE_TYPE (index),
+ index, d_convert (TREE_TYPE (index), size_exp));
+ index = fold_convert (type, index);
+ }
+
+ if (integer_zerop (index))
+ return ptr;
+
+ return fold_build2 (POINTER_PLUS_EXPR, ptr_type, ptr, index);
+}
+
+/* Builds pointer offset expression *(PTR OP OFFSET)
+ OP could be a plus or minus expression. */
+
+tree
+build_offset_op (tree_code op, tree ptr, tree offset)
+{
+ gcc_assert (op == MINUS_EXPR || op == PLUS_EXPR);
+
+ tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
+ TYPE_UNSIGNED (sizetype));
+ offset = fold_convert (type, offset);
+
+ if (op == MINUS_EXPR)
+ offset = fold_build1 (NEGATE_EXPR, type, offset);
+
+ return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, offset);
+}
+
+/* Builds pointer offset expression *(PTR + OFFSET). */
+
+tree
+build_offset (tree ptr, tree offset)
+{
+ return build_offset_op (PLUS_EXPR, ptr, offset);
+}
+
+tree
+build_memref (tree type, tree ptr, tree offset)
+{
+ return fold_build2 (MEM_REF, type, ptr, fold_convert (type, offset));
+}
+
+/* Create a tree node to set multiple elements to a single value. */
+
+tree
+build_array_set (tree ptr, tree length, tree value)
+{
+ tree ptrtype = TREE_TYPE (ptr);
+ tree lentype = TREE_TYPE (length);
+
+ push_binding_level (level_block);
+ push_stmt_list ();
+
+ /* Build temporary locals for length and ptr, and maybe value. */
+ tree t = build_local_temp (size_type_node);
+ add_stmt (build_assign (INIT_EXPR, t, length));
+ length = t;
+
+ t = build_local_temp (ptrtype);
+ add_stmt (build_assign (INIT_EXPR, t, ptr));
+ ptr = t;
+
+ if (TREE_SIDE_EFFECTS (value))
+ {
+ t = build_local_temp (TREE_TYPE (value));
+ add_stmt (build_assign (INIT_EXPR, t, value));
+ value = t;
+ }
+
+ /* Build loop to initialize { .length=length, .ptr=ptr } with value. */
+ push_stmt_list ();
+
+ /* Exit logic for the loop.
+ if (length == 0) break; */
+ t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node));
+ t = build1 (EXIT_EXPR, void_type_node, t);
+ add_stmt (t);
+
+ /* Assign value to the current pointer position.
+ *ptr = value; */
+ t = modify_expr (build_deref (ptr), value);
+ add_stmt (t);
+
+ /* Move pointer to next element position.
+ ptr++; */
+ tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptrtype));
+ t = build2 (POSTINCREMENT_EXPR, ptrtype, ptr, d_convert (ptrtype, size));
+ add_stmt (t);
+
+ /* Decrease loop counter.
+ length -= 1; */
+ t = build2 (POSTDECREMENT_EXPR, lentype, length,
+ d_convert (lentype, integer_one_node));
+ add_stmt (t);
+
+ /* Pop statements and finish loop. */
+ tree loop_body = pop_stmt_list ();
+ add_stmt (build1 (LOOP_EXPR, void_type_node, loop_body));
+
+ /* Wrap it up into a bind expression. */
+ tree stmt_list = pop_stmt_list ();
+ tree block = pop_binding_level ();
+
+ return build3 (BIND_EXPR, void_type_node,
+ BLOCK_VARS (block), stmt_list, block);
+}
+
+
+/* Build an array of type TYPE where all the elements are VAL. */
+
+tree
+build_array_from_val (Type *type, tree val)
+{
+ gcc_assert (type->ty == Tsarray);
+
+ tree etype = build_ctype (type->nextOf ());
+
+ /* Initializing a multidimensional array. */
+ if (TREE_CODE (etype) == ARRAY_TYPE && TREE_TYPE (val) != etype)
+ val = build_array_from_val (type->nextOf (), val);
+
+ size_t dims = ((TypeSArray *) type)->dim->toInteger ();
+ vec<constructor_elt, va_gc> *elms = NULL;
+ vec_safe_reserve (elms, dims);
+
+ val = d_convert (etype, val);
+
+ for (size_t i = 0; i < dims; i++)
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), val);
+
+ return build_constructor (build_ctype (type), elms);
+}
+
+/* Implicitly converts void* T to byte* as D allows { void[] a; &a[3]; } */
+
+tree
+void_okay_p (tree t)
+{
+ tree type = TREE_TYPE (t);
+
+ if (VOID_TYPE_P (TREE_TYPE (type)))
+ {
+ tree totype = build_ctype (Type::tuns8->pointerTo ());
+ return fold_convert (totype, t);
+ }
+
+ return t;
+}
+
+/* Builds a bounds condition checking that INDEX is between 0 and LEN.
+ The condition returns the INDEX if true, or throws a RangeError.
+ If INCLUSIVE, we allow INDEX == LEN to return true also. */
+
+tree
+build_bounds_condition (const Loc& loc, tree index, tree len, bool inclusive)
+{
+ if (!array_bounds_check ())
+ return index;
+
+ /* Prevent multiple evaluations of the index. */
+ index = d_save_expr (index);
+
+ /* Generate INDEX >= LEN && throw RangeError.
+ No need to check whether INDEX >= 0 as the front-end should
+ have already taken care of implicit casts to unsigned. */
+ tree condition = fold_build2 (inclusive ? GT_EXPR : GE_EXPR,
+ d_bool_type, index, len);
+ tree boundserr = d_assert_call (loc, LIBCALL_ARRAY_BOUNDS);
+
+ return build_condition (TREE_TYPE (index), condition, boundserr, index);
+}
+
+/* Returns TRUE if array bounds checking code generation is turned on. */
+
+bool
+array_bounds_check (void)
+{
+ FuncDeclaration *fd;
+
+ switch (global.params.useArrayBounds)
+ {
+ case BOUNDSCHECKoff:
+ return false;
+
+ case BOUNDSCHECKon:
+ return true;
+
+ case BOUNDSCHECKsafeonly:
+ /* For D2 safe functions only. */
+ fd = d_function_chain->function;
+ if (fd && fd->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *) fd->type;
+ if (tf->trust == TRUSTsafe)
+ return true;
+ }
+ return false;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return an undeclared local temporary of type TYPE
+ for use with BIND_EXPR. */
+
+tree
+create_temporary_var (tree type)
+{
+ tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type);
+
+ DECL_CONTEXT (decl) = current_function_decl;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ layout_decl (decl, 0);
+
+ return decl;
+}
+
+/* Return an undeclared local temporary OUT_VAR initialized
+ with result of expression EXP. */
+
+tree
+maybe_temporary_var (tree exp, tree *out_var)
+{
+ tree t = exp;
+
+ /* Get the base component. */
+ while (TREE_CODE (t) == COMPONENT_REF)
+ t = TREE_OPERAND (t, 0);
+
+ if (!DECL_P (t) && !REFERENCE_CLASS_P (t))
+ {
+ *out_var = create_temporary_var (TREE_TYPE (exp));
+ DECL_INITIAL (*out_var) = exp;
+ return *out_var;
+ }
+ else
+ {
+ *out_var = NULL_TREE;
+ return exp;
+ }
+}
+
+/* Builds a BIND_EXPR around BODY for the variables VAR_CHAIN. */
+
+tree
+bind_expr (tree var_chain, tree body)
+{
+ /* Only handles one var. */
+ gcc_assert (TREE_CHAIN (var_chain) == NULL_TREE);
+
+ if (DECL_INITIAL (var_chain))
+ {
+ tree ini = build_assign (INIT_EXPR, var_chain, DECL_INITIAL (var_chain));
+ DECL_INITIAL (var_chain) = NULL_TREE;
+ body = compound_expr (ini, body);
+ }
+
+ return d_save_expr (build3 (BIND_EXPR, TREE_TYPE (body),
+ var_chain, body, NULL_TREE));
+}
+
+/* Returns the TypeFunction class for Type T.
+ Assumes T is already ->toBasetype(). */
+
+TypeFunction *
+get_function_type (Type *t)
+{
+ TypeFunction *tf = NULL;
+ if (t->ty == Tpointer)
+ t = t->nextOf ()->toBasetype ();
+ if (t->ty == Tfunction)
+ tf = (TypeFunction *) t;
+ else if (t->ty == Tdelegate)
+ tf = (TypeFunction *) ((TypeDelegate *) t)->next;
+ return tf;
+}
+
+/* Returns TRUE if CALLEE is a plain nested function outside the scope of
+ CALLER. In which case, CALLEE is being called through an alias that was
+ passed to CALLER. */
+
+bool
+call_by_alias_p (FuncDeclaration *caller, FuncDeclaration *callee)
+{
+ if (!callee->isNested ())
+ return false;
+
+ if (caller->toParent () == callee->toParent ())
+ return false;
+
+ Dsymbol *dsym = callee;
+
+ while (dsym)
+ {
+ if (dsym->isTemplateInstance ())
+ return false;
+ else if (dsym->isFuncDeclaration () == caller)
+ return false;
+ dsym = dsym->toParent ();
+ }
+
+ return true;
+}
+
+/* Entry point for call routines. Builds a function call to FD.
+ OBJECT is the 'this' reference passed and ARGS are the arguments to FD. */
+
+tree
+d_build_call_expr (FuncDeclaration *fd, tree object, Expressions *arguments)
+{
+ return d_build_call (get_function_type (fd->type),
+ build_address (get_symbol_decl (fd)), object, arguments);
+}
+
+/* Builds a CALL_EXPR of type TF to CALLABLE. OBJECT holds the 'this' pointer,
+ ARGUMENTS are evaluated in left to right order, saved and promoted
+ before passing. */
+
+tree
+d_build_call (TypeFunction *tf, tree callable, tree object,
+ Expressions *arguments)
+{
+ tree ctype = TREE_TYPE (callable);
+ tree callee = callable;
+
+ if (POINTER_TYPE_P (ctype))
+ ctype = TREE_TYPE (ctype);
+ else
+ callee = build_address (callable);
+
+ gcc_assert (FUNC_OR_METHOD_TYPE_P (ctype));
+ gcc_assert (tf != NULL);
+ gcc_assert (tf->ty == Tfunction);
+
+ if (TREE_CODE (ctype) != FUNCTION_TYPE && object == NULL_TREE)
+ {
+ /* Front-end apparently doesn't check this. */
+ if (TREE_CODE (callable) == FUNCTION_DECL)
+ {
+ error ("need %<this%> to access member %qE", DECL_NAME (callable));
+ return error_mark_node;
+ }
+
+ /* Probably an internal error. */
+ gcc_unreachable ();
+ }
+
+ /* Build the argument list for the call. */
+ vec<tree, va_gc> *args = NULL;
+ tree saved_args = NULL_TREE;
+
+ /* If this is a delegate call or a nested function being called as
+ a delegate, the object should not be NULL. */
+ if (object != NULL_TREE)
+ vec_safe_push (args, object);
+
+ if (arguments)
+ {
+ /* First pass, evaluated expanded tuples in function arguments. */
+ for (size_t i = 0; i < arguments->dim; ++i)
+ {
+ Lagain:
+ Expression *arg = (*arguments)[i];
+ gcc_assert (arg->op != TOKtuple);
+
+ if (arg->op == TOKcomma)
+ {
+ CommaExp *ce = (CommaExp *) arg;
+ tree tce = build_expr (ce->e1);
+ saved_args = compound_expr (saved_args, tce);
+ (*arguments)[i] = ce->e2;
+ goto Lagain;
+ }
+ }
+
+ size_t nparams = Parameter::dim (tf->parameters);
+ /* if _arguments[] is the first argument. */
+ size_t varargs = (tf->linkage == LINKd && tf->varargs == 1);
+
+ /* Assumes arguments->dim <= formal_args->dim if (!tf->varargs). */
+ for (size_t i = 0; i < arguments->dim; ++i)
+ {
+ Expression *arg = (*arguments)[i];
+ tree targ = build_expr (arg);
+
+ if (i - varargs < nparams && i >= varargs)
+ {
+ /* Actual arguments for declared formal arguments. */
+ Parameter *parg = Parameter::getNth (tf->parameters, i - varargs);
+ targ = convert_for_argument (targ, parg);
+ }
+
+ /* Don't pass empty aggregates by value. */
+ if (empty_aggregate_p (TREE_TYPE (targ)) && !TREE_ADDRESSABLE (targ)
+ && TREE_CODE (targ) != CONSTRUCTOR)
+ {
+ tree t = build_constructor (TREE_TYPE (targ), NULL);
+ targ = build2 (COMPOUND_EXPR, TREE_TYPE (t), targ, t);
+ }
+
+ vec_safe_push (args, targ);
+ }
+ }
+
+ /* Evaluate the callee before calling it. */
+ if (TREE_SIDE_EFFECTS (callee))
+ {
+ callee = d_save_expr (callee);
+ saved_args = compound_expr (callee, saved_args);
+ }
+
+ tree result = build_call_vec (TREE_TYPE (ctype), callee, args);
+
+ /* Enforce left to right evaluation. */
+ if (tf->linkage == LINKd)
+ CALL_EXPR_ARGS_ORDERED (result) = 1;
+
+ result = maybe_expand_intrinsic (result);
+
+ /* Return the value in a temporary slot so that it can be evaluated
+ multiple times by the caller. */
+ if (TREE_CODE (result) == CALL_EXPR
+ && AGGREGATE_TYPE_P (TREE_TYPE (result))
+ && TREE_ADDRESSABLE (TREE_TYPE (result)))
+ {
+ CALL_EXPR_RETURN_SLOT_OPT (result) = true;
+ result = force_target_expr (result);
+ }
+
+ return compound_expr (saved_args, result);
+}
+
+/* Builds a call to AssertError or AssertErrorMsg. */
+
+tree
+d_assert_call (const Loc& loc, libcall_fn libcall, tree msg)
+{
+ tree file;
+ tree line = size_int (loc.linnum);
+
+ /* File location is passed as a D string. */
+ if (loc.filename)
+ {
+ unsigned len = strlen (loc.filename);
+ tree str = build_string (len, loc.filename);
+ TREE_TYPE (str) = make_array_type (Type::tchar, len);
+
+ file = d_array_value (build_ctype (Type::tchar->arrayOf ()),
+ size_int (len), build_address (str));
+ }
+ else
+ file = null_array_node;
+
+ if (msg != NULL)
+ return build_libcall (libcall, Type::tvoid, 3, msg, file, line);
+ else
+ return build_libcall (libcall, Type::tvoid, 2, file, line);
+}
+
+/* Build and return the correct call to fmod depending on TYPE.
+ ARG0 and ARG1 are the arguments pass to the function. */
+
+tree
+build_float_modulus (tree type, tree arg0, tree arg1)
+{
+ tree fmodfn = NULL_TREE;
+ tree basetype = type;
+
+ if (COMPLEX_FLOAT_TYPE_P (basetype))
+ basetype = TREE_TYPE (basetype);
+
+ if (TYPE_MAIN_VARIANT (basetype) == double_type_node
+ || TYPE_MAIN_VARIANT (basetype) == idouble_type_node)
+ fmodfn = builtin_decl_explicit (BUILT_IN_FMOD);
+ else if (TYPE_MAIN_VARIANT (basetype) == float_type_node
+ || TYPE_MAIN_VARIANT (basetype) == ifloat_type_node)
+ fmodfn = builtin_decl_explicit (BUILT_IN_FMODF);
+ else if (TYPE_MAIN_VARIANT (basetype) == long_double_type_node
+ || TYPE_MAIN_VARIANT (basetype) == ireal_type_node)
+ fmodfn = builtin_decl_explicit (BUILT_IN_FMODL);
+
+ if (!fmodfn)
+ {
+ error ("tried to perform floating-point modulo division on %qT", type);
+ return error_mark_node;
+ }
+
+ if (COMPLEX_FLOAT_TYPE_P (type))
+ {
+ tree re = build_call_expr (fmodfn, 2, real_part (arg0), arg1);
+ tree im = build_call_expr (fmodfn, 2, imaginary_part (arg0), arg1);
+
+ return complex_expr (type, re, im);
+ }
+
+ if (SCALAR_FLOAT_TYPE_P (type))
+ return build_call_expr (fmodfn, 2, arg0, arg1);
+
+ /* Should have caught this above. */
+ gcc_unreachable ();
+}
+
+/* Build a function type whose first argument is a pointer to BASETYPE,
+ which is to be used for the 'vthis' context parameter for TYPE.
+ The base type may be a record for member functions, or a void for
+ nested functions and delegates. */
+
+tree
+build_vthis_function (tree basetype, tree type)
+{
+ gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
+
+ tree argtypes = tree_cons (NULL_TREE, build_pointer_type (basetype),
+ TYPE_ARG_TYPES (type));
+ tree fntype = build_function_type (TREE_TYPE (type), argtypes);
+
+ if (RECORD_OR_UNION_TYPE_P (basetype))
+ TYPE_METHOD_BASETYPE (fntype) = TYPE_MAIN_VARIANT (basetype);
+ else
+ gcc_assert (VOID_TYPE_P (basetype));
+
+ return fntype;
+}
+
+/* If SYM is a nested function, return the static chain to be
+ used when calling that function from the current function.
+
+ If SYM is a nested class or struct, return the static chain
+ to be used when creating an instance of the class from CFUN. */
+
+tree
+get_frame_for_symbol (Dsymbol *sym)
+{
+ FuncDeclaration *thisfd
+ = d_function_chain ? d_function_chain->function : NULL;
+ FuncDeclaration *fd = sym->isFuncDeclaration ();
+ FuncDeclaration *fdparent = NULL;
+ FuncDeclaration *fdoverride = NULL;
+
+ if (fd != NULL)
+ {
+ /* Check that the nested function is properly defined. */
+ if (!fd->fbody)
+ {
+ /* Should instead error on line that references 'fd'. */
+ error_at (make_location_t (fd->loc), "nested function missing body");
+ return null_pointer_node;
+ }
+
+ fdparent = fd->toParent2 ()->isFuncDeclaration ();
+
+ /* Special case for __ensure and __require. */
+ if ((fd->ident == Identifier::idPool ("__ensure")
+ || fd->ident == Identifier::idPool ("__require"))
+ && fdparent != thisfd)
+ {
+ fdoverride = fdparent;
+ fdparent = thisfd;
+ }
+ }
+ else
+ {
+ /* It's a class (or struct). NewExp codegen has already determined its
+ outer scope is not another class, so it must be a function. */
+ while (sym && !sym->isFuncDeclaration ())
+ sym = sym->toParent2 ();
+
+ fdparent = (FuncDeclaration *) sym;
+ }
+
+ gcc_assert (fdparent != NULL);
+
+ if (thisfd != fdparent)
+ {
+ /* If no frame pointer for this function. */
+ if (!thisfd->vthis)
+ {
+ error_at (make_location_t (sym->loc),
+ "is a nested function and cannot be accessed from %qs",
+ thisfd->toChars ());
+ return null_pointer_node;
+ }
+
+ /* Make sure we can get the frame pointer to the outer function.
+ Go up each nesting level until we find the enclosing function. */
+ Dsymbol *dsym = thisfd;
+
+ while (fd != dsym)
+ {
+ /* Check if enclosing function is a function. */
+ FuncDeclaration *fd = dsym->isFuncDeclaration ();
+
+ if (fd != NULL)
+ {
+ if (fdparent == fd->toParent2 ())
+ break;
+
+ gcc_assert (fd->isNested () || fd->vthis);
+ dsym = dsym->toParent2 ();
+ continue;
+ }
+
+ /* Check if enclosed by an aggregate. That means the current
+ function must be a member function of that aggregate. */
+ AggregateDeclaration *ad = dsym->isAggregateDeclaration ();
+
+ if (ad == NULL)
+ goto Lnoframe;
+ if (ad->isClassDeclaration () && fdparent == ad->toParent2 ())
+ break;
+ if (ad->isStructDeclaration () && fdparent == ad->toParent2 ())
+ break;
+
+ if (!ad->isNested () || !ad->vthis)
+ {
+ Lnoframe:
+ error_at (make_location_t (thisfd->loc),
+ "cannot get frame pointer to %qs",
+ sym->toPrettyChars ());
+ return null_pointer_node;
+ }
+
+ dsym = dsym->toParent2 ();
+ }
+ }
+
+ tree ffo = get_frameinfo (fdparent);
+ if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo))
+ {
+ tree frame_ref = get_framedecl (thisfd, fdparent);
+
+ /* If 'thisfd' is a derived member function, then 'fdparent' is the
+ overridden member function in the base class. Even if there's a
+ closure environment, we should give the original stack data as the
+ nested function frame. */
+ if (fdoverride)
+ {
+ ClassDeclaration *cdo = fdoverride->isThis ()->isClassDeclaration ();
+ ClassDeclaration *cd = thisfd->isThis ()->isClassDeclaration ();
+ gcc_assert (cdo && cd);
+
+ int offset;
+ if (cdo->isBaseOf (cd, &offset) && offset != 0)
+ {
+ /* Generate a new frame to pass to the overriden function that
+ has the 'this' pointer adjusted. */
+ gcc_assert (offset != OFFSET_RUNTIME);
+
+ tree type = FRAMEINFO_TYPE (get_frameinfo (fdoverride));
+ tree fields = TYPE_FIELDS (type);
+ /* The 'this' field comes immediately after the '__chain'. */
+ tree thisfield = chain_index (1, fields);
+ vec<constructor_elt, va_gc> *ve = NULL;
+
+ tree framefields = TYPE_FIELDS (FRAMEINFO_TYPE (ffo));
+ frame_ref = build_deref (frame_ref);
+
+ for (tree field = fields; field; field = DECL_CHAIN (field))
+ {
+ tree value = component_ref (frame_ref, framefields);
+ if (field == thisfield)
+ value = build_offset (value, size_int (offset));
+
+ CONSTRUCTOR_APPEND_ELT (ve, field, value);
+ framefields = DECL_CHAIN (framefields);
+ }
+
+ frame_ref = build_address (build_constructor (type, ve));
+ }
+ }
+
+ return frame_ref;
+ }
+
+ return null_pointer_node;
+}
+
+/* Return the parent function of a nested class CD. */
+
+static FuncDeclaration *
+d_nested_class (ClassDeclaration *cd)
+{
+ FuncDeclaration *fd = NULL;
+ while (cd && cd->isNested ())
+ {
+ Dsymbol *dsym = cd->toParent2 ();
+ if ((fd = dsym->isFuncDeclaration ()))
+ return fd;
+ else
+ cd = dsym->isClassDeclaration ();
+ }
+ return NULL;
+}
+
+/* Return the parent function of a nested struct SD. */
+
+static FuncDeclaration *
+d_nested_struct (StructDeclaration *sd)
+{
+ FuncDeclaration *fd = NULL;
+ while (sd && sd->isNested ())
+ {
+ Dsymbol *dsym = sd->toParent2 ();
+ if ((fd = dsym->isFuncDeclaration ()))
+ return fd;
+ else
+ sd = dsym->isStructDeclaration ();
+ }
+ return NULL;
+}
+
+
+/* Starting from the current function FD, try to find a suitable value of
+ 'this' in nested function instances. A suitable 'this' value is an
+ instance of OCD or a class that has OCD as a base. */
+
+static tree
+find_this_tree (ClassDeclaration *ocd)
+{
+ FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL;
+
+ while (fd)
+ {
+ AggregateDeclaration *ad = fd->isThis ();
+ ClassDeclaration *cd = ad ? ad->isClassDeclaration () : NULL;
+
+ if (cd != NULL)
+ {
+ if (ocd == cd)
+ return get_decl_tree (fd->vthis);
+ else if (ocd->isBaseOf (cd, NULL))
+ return convert_expr (get_decl_tree (fd->vthis),
+ cd->type, ocd->type);
+
+ fd = d_nested_class (cd);
+ }
+ else
+ {
+ if (fd->isNested ())
+ {
+ fd = fd->toParent2 ()->isFuncDeclaration ();
+ continue;
+ }
+
+ fd = NULL;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Retrieve the outer class/struct 'this' value of DECL from
+ the current function. */
+
+tree
+build_vthis (AggregateDeclaration *decl)
+{
+ ClassDeclaration *cd = decl->isClassDeclaration ();
+ StructDeclaration *sd = decl->isStructDeclaration ();
+
+ /* If an aggregate nested in a function has no methods and there are no
+ other nested functions, any static chain created here will never be
+ translated. Use a null pointer for the link in this case. */
+ tree vthis_value = null_pointer_node;
+
+ if (cd != NULL || sd != NULL)
+ {
+ Dsymbol *outer = decl->toParent2 ();
+
+ /* If the parent is a templated struct, the outer context is instead
+ the enclosing symbol of where the instantiation happened. */
+ if (outer->isStructDeclaration ())
+ {
+ gcc_assert (outer->parent && outer->parent->isTemplateInstance ());
+ outer = ((TemplateInstance *) outer->parent)->enclosing;
+ }
+
+ /* For outer classes, get a suitable 'this' value.
+ For outer functions, get a suitable frame/closure pointer. */
+ ClassDeclaration *cdo = outer->isClassDeclaration ();
+ FuncDeclaration *fdo = outer->isFuncDeclaration ();
+
+ if (cdo)
+ {
+ vthis_value = find_this_tree (cdo);
+ gcc_assert (vthis_value != NULL_TREE);
+ }
+ else if (fdo)
+ {
+ tree ffo = get_frameinfo (fdo);
+ if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo)
+ || fdo->hasNestedFrameRefs ())
+ vthis_value = get_frame_for_symbol (decl);
+ else if (cd != NULL)
+ {
+ /* Classes nested in methods are allowed to access any outer
+ class fields, use the function chain in this case. */
+ if (fdo->vthis && fdo->vthis->type != Type::tvoidptr)
+ vthis_value = get_decl_tree (fdo->vthis);
+ }
+ }
+ else
+ gcc_unreachable ();
+ }
+
+ return vthis_value;
+}
+
+/* Build the RECORD_TYPE that describes the function frame or closure type for
+ the function FD. FFI is the tree holding all frame information. */
+
+static tree
+build_frame_type (tree ffi, FuncDeclaration *fd)
+{
+ if (FRAMEINFO_TYPE (ffi))
+ return FRAMEINFO_TYPE (ffi);
+
+ tree frame_rec_type = make_node (RECORD_TYPE);
+ char *name = concat (FRAMEINFO_IS_CLOSURE (ffi) ? "CLOSURE." : "FRAME.",
+ fd->toPrettyChars (), NULL);
+ TYPE_NAME (frame_rec_type) = get_identifier (name);
+ free (name);
+
+ tree fields = NULL_TREE;
+
+ /* Function is a member or nested, so must have field for outer context. */
+ if (fd->vthis)
+ {
+ tree ptr_field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+ get_identifier ("__chain"), ptr_type_node);
+ DECL_FIELD_CONTEXT (ptr_field) = frame_rec_type;
+ fields = chainon (NULL_TREE, ptr_field);
+ DECL_NONADDRESSABLE_P (ptr_field) = 1;
+ }
+
+ /* The __ensure and __require are called directly, so never make the outer
+ functions closure, but nevertheless could still be referencing parameters
+ of the calling function non-locally. So we add all parameters with nested
+ refs to the function frame, this should also mean overriding methods will
+ have the same frame layout when inheriting a contract. */
+ if ((global.params.useIn && fd->frequire)
+ || (global.params.useOut && fd->fensure))
+ {
+ if (fd->parameters)
+ {
+ for (size_t i = 0; fd->parameters && i < fd->parameters->dim; i++)
+ {
+ VarDeclaration *v = (*fd->parameters)[i];
+ /* Remove if already in closureVars so can push to front. */
+ for (size_t j = i; j < fd->closureVars.dim; j++)
+ {
+ Dsymbol *s = fd->closureVars[j];
+ if (s == v)
+ {
+ fd->closureVars.remove (j);
+ break;
+ }
+ }
+ fd->closureVars.insert (i, v);
+ }
+ }
+
+ /* Also add hidden 'this' to outer context. */
+ if (fd->vthis)
+ {
+ for (size_t i = 0; i < fd->closureVars.dim; i++)
+ {
+ Dsymbol *s = fd->closureVars[i];
+ if (s == fd->vthis)
+ {
+ fd->closureVars.remove (i);
+ break;
+ }
+ }
+ fd->closureVars.insert (0, fd->vthis);
+ }
+ }
+
+ for (size_t i = 0; i < fd->closureVars.dim; i++)
+ {
+ VarDeclaration *v = fd->closureVars[i];
+ tree vsym = get_symbol_decl (v);
+ tree ident = v->ident
+ ? get_identifier (v->ident->toChars ()) : NULL_TREE;
+
+ tree field = build_decl (make_location_t (v->loc), FIELD_DECL, ident,
+ TREE_TYPE (vsym));
+ SET_DECL_LANG_FRAME_FIELD (vsym, field);
+ DECL_FIELD_CONTEXT (field) = frame_rec_type;
+ fields = chainon (fields, field);
+ TREE_USED (vsym) = 1;
+
+ TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (vsym);
+ DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (vsym);
+ TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (vsym);
+
+ /* Can't do nrvo if the variable is put in a frame. */
+ if (fd->nrvo_can && fd->nrvo_var == v)
+ fd->nrvo_can = 0;
+
+ if (FRAMEINFO_IS_CLOSURE (ffi))
+ {
+ /* Because the value needs to survive the end of the scope. */
+ if ((v->edtor && (v->storage_class & STCparameter))
+ || v->needsScopeDtor ())
+ error_at (make_location_t (v->loc),
+ "has scoped destruction, cannot build closure");
+ }
+ }
+
+ TYPE_FIELDS (frame_rec_type) = fields;
+ TYPE_READONLY (frame_rec_type) = 1;
+ layout_type (frame_rec_type);
+ d_keep (frame_rec_type);
+
+ return frame_rec_type;
+}
+
+/* Closures are implemented by taking the local variables that
+ need to survive the scope of the function, and copying them
+ into a GC allocated chuck of memory. That chunk, called the
+ closure here, is inserted into the linked list of stack
+ frames instead of the usual stack frame.
+
+ If a closure is not required, but FD still needs a frame to lower
+ nested refs, then instead build custom static chain decl on stack. */
+
+void
+build_closure (FuncDeclaration *fd)
+{
+ tree ffi = get_frameinfo (fd);
+
+ if (!FRAMEINFO_CREATES_FRAME (ffi))
+ return;
+
+ tree type = FRAMEINFO_TYPE (ffi);
+ gcc_assert (COMPLETE_TYPE_P (type));
+
+ tree decl, decl_ref;
+
+ if (FRAMEINFO_IS_CLOSURE (ffi))
+ {
+ decl = build_local_temp (build_pointer_type (type));
+ DECL_NAME (decl) = get_identifier ("__closptr");
+ decl_ref = build_deref (decl);
+
+ /* Allocate memory for closure. */
+ tree arg = convert (build_ctype (Type::tsize_t), TYPE_SIZE_UNIT (type));
+ tree init = build_libcall (LIBCALL_ALLOCMEMORY, Type::tvoidptr, 1, arg);
+
+ tree init_exp = build_assign (INIT_EXPR, decl,
+ build_nop (TREE_TYPE (decl), init));
+ add_stmt (init_exp);
+ }
+ else
+ {
+ decl = build_local_temp (type);
+ DECL_NAME (decl) = get_identifier ("__frame");
+ decl_ref = decl;
+ }
+
+ /* Set the first entry to the parent closure/frame, if any. */
+ if (fd->vthis)
+ {
+ tree chain_field = component_ref (decl_ref, TYPE_FIELDS (type));
+ tree chain_expr = modify_expr (chain_field,
+ d_function_chain->static_chain);
+ add_stmt (chain_expr);
+ }
+
+ /* Copy parameters that are referenced nonlocally. */
+ for (size_t i = 0; i < fd->closureVars.dim; i++)
+ {
+ VarDeclaration *v = fd->closureVars[i];
+
+ if (!v->isParameter ())
+ continue;
+
+ tree vsym = get_symbol_decl (v);
+
+ tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym));
+ tree expr = modify_expr (field, vsym);
+ add_stmt (expr);
+ }
+
+ if (!FRAMEINFO_IS_CLOSURE (ffi))
+ decl = build_address (decl);
+
+ d_function_chain->static_chain = decl;
+}
+
+/* Return the frame of FD. This could be a static chain or a closure
+ passed via the hidden 'this' pointer. */
+
+tree
+get_frameinfo (FuncDeclaration *fd)
+{
+ tree fds = get_symbol_decl (fd);
+ if (DECL_LANG_FRAMEINFO (fds))
+ return DECL_LANG_FRAMEINFO (fds);
+
+ tree ffi = make_node (FUNCFRAME_INFO);
+
+ DECL_LANG_FRAMEINFO (fds) = ffi;
+
+ if (fd->needsClosure ())
+ {
+ /* Set-up a closure frame, this will be allocated on the heap. */
+ FRAMEINFO_CREATES_FRAME (ffi) = 1;
+ FRAMEINFO_IS_CLOSURE (ffi) = 1;
+ }
+ else if (fd->hasNestedFrameRefs ())
+ {
+ /* Functions with nested refs must create a static frame for local
+ variables to be referenced from. */
+ FRAMEINFO_CREATES_FRAME (ffi) = 1;
+ }
+ else
+ {
+ /* For nested functions, default to creating a frame. Even if there are
+ no fields to populate the frame, create it anyway, as this will be
+ used as the record type instead of `void*` for the this parameter. */
+ if (fd->vthis && fd->vthis->type == Type::tvoidptr)
+ FRAMEINFO_CREATES_FRAME (ffi) = 1;
+
+ /* In checkNestedReference, references from contracts are not added to the
+ closureVars array, so assume all parameters referenced. */
+ if ((global.params.useIn && fd->frequire)
+ || (global.params.useOut && fd->fensure))
+ FRAMEINFO_CREATES_FRAME (ffi) = 1;
+
+ /* If however `fd` is nested (deeply) in a function that creates a
+ closure, then `fd` instead inherits that closure via hidden vthis
+ pointer, and doesn't create a stack frame at all. */
+ FuncDeclaration *ff = fd;
+
+ while (ff)
+ {
+ tree ffo = get_frameinfo (ff);
+
+ if (ff != fd && FRAMEINFO_CREATES_FRAME (ffo))
+ {
+ gcc_assert (FRAMEINFO_TYPE (ffo));
+ FRAMEINFO_CREATES_FRAME (ffi) = 0;
+ FRAMEINFO_STATIC_CHAIN (ffi) = 1;
+ FRAMEINFO_IS_CLOSURE (ffi) = FRAMEINFO_IS_CLOSURE (ffo);
+ gcc_assert (COMPLETE_TYPE_P (FRAMEINFO_TYPE (ffo)));
+ FRAMEINFO_TYPE (ffi) = FRAMEINFO_TYPE (ffo);
+ break;
+ }
+
+ /* Stop looking if no frame pointer for this function. */
+ if (ff->vthis == NULL)
+ break;
+
+ AggregateDeclaration *ad = ff->isThis ();
+ if (ad && ad->isNested ())
+ {
+ while (ad->isNested ())
+ {
+ Dsymbol *d = ad->toParent2 ();
+ ad = d->isAggregateDeclaration ();
+ ff = d->isFuncDeclaration ();
+
+ if (ad == NULL)
+ break;
+ }
+ }
+ else
+ ff = ff->toParent2 ()->isFuncDeclaration ();
+ }
+ }
+
+ /* Build type now as may be referenced from another module. */
+ if (FRAMEINFO_CREATES_FRAME (ffi))
+ FRAMEINFO_TYPE (ffi) = build_frame_type (ffi, fd);
+
+ return ffi;
+}
+
+/* Return a pointer to the frame/closure block of OUTER
+ so can be accessed from the function INNER. */
+
+tree
+get_framedecl (FuncDeclaration *inner, FuncDeclaration *outer)
+{
+ tree result = d_function_chain->static_chain;
+ FuncDeclaration *fd = inner;
+
+ while (fd && fd != outer)
+ {
+ AggregateDeclaration *ad;
+ ClassDeclaration *cd;
+ StructDeclaration *sd;
+
+ /* Parent frame link is the first field. */
+ if (FRAMEINFO_CREATES_FRAME (get_frameinfo (fd)))
+ result = indirect_ref (ptr_type_node, result);
+
+ if (fd->isNested ())
+ fd = fd->toParent2 ()->isFuncDeclaration ();
+ /* The frame/closure record always points to the outer function's
+ frame, even if there are intervening nested classes or structs.
+ So, we can just skip over these. */
+ else if ((ad = fd->isThis ()) && (cd = ad->isClassDeclaration ()))
+ fd = d_nested_class (cd);
+ else if ((ad = fd->isThis ()) && (sd = ad->isStructDeclaration ()))
+ fd = d_nested_struct (sd);
+ else
+ break;
+ }
+
+ /* Go get our frame record. */
+ gcc_assert (fd == outer);
+ tree frame_type = FRAMEINFO_TYPE (get_frameinfo (outer));
+
+ if (frame_type != NULL_TREE)
+ {
+ result = build_nop (build_pointer_type (frame_type), result);
+ return result;
+ }
+ else
+ {
+ error_at (make_location_t (inner->loc),
+ "forward reference to frame of %qs", outer->toChars ());
+ return null_pointer_node;
+ }
+}
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
new file mode 100644
index 0000000..7e07366
--- /dev/null
+++ b/gcc/d/d-convert.cc
@@ -0,0 +1,805 @@
+/* d-convert.cc -- Data type conversion routines.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/declaration.h"
+#include "dmd/expression.h"
+#include "dmd/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "convert.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+
+
+/* Build CODE expression with operands OP0 and OP1.
+ Helper function for d_truthvalue_conversion, so assumes bool result. */
+
+static tree
+d_build_truthvalue_op (tree_code code, tree op0, tree op1)
+{
+ tree type0, type1;
+
+ tree result_type = NULL_TREE;
+
+ type0 = TREE_TYPE (op0);
+ type1 = TREE_TYPE (op1);
+
+ /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue. */
+ STRIP_TYPE_NOPS (op0);
+ STRIP_TYPE_NOPS (op1);
+
+ /* Also need to convert pointer/int comparison. */
+ if (POINTER_TYPE_P (type0) && TREE_CODE (op1) == INTEGER_CST
+ && integer_zerop (op1))
+ {
+ result_type = type0;
+ }
+ else if (POINTER_TYPE_P (type1) && TREE_CODE (op0) == INTEGER_CST
+ && integer_zerop (op0))
+ {
+ result_type = type1;
+ }
+ /* If integral, need to convert unsigned/signed comparison.
+ Will also need to convert if type precisions differ. */
+ else if (INTEGRAL_TYPE_P (type0) && INTEGRAL_TYPE_P (type1))
+ {
+ if (TYPE_PRECISION (type0) > TYPE_PRECISION (type1))
+ result_type = type0;
+ else if (TYPE_PRECISION (type0) < TYPE_PRECISION (type1))
+ result_type = type1;
+ else if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1))
+ result_type = TYPE_UNSIGNED (type0) ? type0 : type1;
+ }
+
+ if (result_type)
+ {
+ if (TREE_TYPE (op0) != result_type)
+ op0 = convert (result_type, op0);
+ if (TREE_TYPE (op1) != result_type)
+ op1 = convert (result_type, op1);
+ }
+
+ return fold_build2 (code, d_bool_type, op0, op1);
+}
+
+/* Return whether EXPR is a declaration whose address can never be NULL. */
+
+bool
+decl_with_nonnull_addr_p (const_tree expr)
+{
+ return (DECL_P (expr)
+ && (TREE_CODE (expr) == PARM_DECL
+ || TREE_CODE (expr) == LABEL_DECL
+ || !DECL_WEAK (expr)));
+}
+
+/* Convert EXPR to be a truth-value, validating its type for this purpose. */
+
+tree
+d_truthvalue_conversion (tree expr)
+{
+ switch (TREE_CODE (expr))
+ {
+ case EQ_EXPR: case NE_EXPR: case LE_EXPR:
+ case GE_EXPR: case LT_EXPR: case GT_EXPR:
+ if (TREE_TYPE (expr) == d_bool_type)
+ return expr;
+ return build2 (TREE_CODE (expr), d_bool_type,
+ TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ if (TREE_TYPE (expr) == d_bool_type)
+ return expr;
+ return build2 (TREE_CODE (expr), d_bool_type,
+ d_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ d_truthvalue_conversion (TREE_OPERAND (expr, 1)));
+
+ case TRUTH_NOT_EXPR:
+ if (TREE_TYPE (expr) == d_bool_type)
+ return expr;
+ return build1 (TREE_CODE (expr), d_bool_type,
+ d_truthvalue_conversion (TREE_OPERAND (expr, 0)));
+
+ case ERROR_MARK:
+ return expr;
+
+ case INTEGER_CST:
+ return integer_zerop (expr) ? boolean_false_node
+ : boolean_true_node;
+
+ case REAL_CST:
+ return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0)
+ ? boolean_true_node
+ : boolean_false_node;
+
+ case ADDR_EXPR:
+ /* If we are taking the address of a decl that can never be null,
+ then the return result is always true. */
+ if (decl_with_nonnull_addr_p (TREE_OPERAND (expr, 0)))
+ {
+ warning (OPT_Waddress,
+ "the address of %qD will always evaluate as %<true%>",
+ TREE_OPERAND (expr, 0));
+ return boolean_true_node;
+ }
+ break;
+
+ case COMPLEX_EXPR:
+ return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
+ ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
+ d_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ d_truthvalue_conversion (TREE_OPERAND (expr, 1)));
+
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ case FLOAT_EXPR:
+ /* These don't change whether an object is nonzero or zero. */
+ return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ /* These don't change whether an object is zero or nonzero, but
+ we can't ignore them if their second arg has side-effects. */
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+ {
+ return build2 (COMPOUND_EXPR, d_bool_type, TREE_OPERAND (expr, 1),
+ d_truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ }
+ else
+ return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ case COND_EXPR:
+ /* Distribute the conversion into the arms of a COND_EXPR. */
+ return fold_build3 (COND_EXPR, d_bool_type, TREE_OPERAND (expr, 0),
+ d_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ d_truthvalue_conversion (TREE_OPERAND (expr, 2)));
+
+ case CONVERT_EXPR:
+ /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
+ since that affects how `default_conversion' will behave. */
+ if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
+ break;
+ /* Fall through. */
+
+ case NOP_EXPR:
+ /* If this isn't narrowing the argument, we can ignore it. */
+ if (TYPE_PRECISION (TREE_TYPE (expr))
+ >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
+ return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
+ break;
+
+ default:
+ break;
+ }
+
+ if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
+ {
+ tree t = save_expr (expr);
+ return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (expr)
+ ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
+ d_truthvalue_conversion (real_part (t)),
+ d_truthvalue_conversion (imaginary_part (t)));
+ }
+ else
+ return d_build_truthvalue_op (NE_EXPR, expr,
+ build_zero_cst (TREE_TYPE (expr)));
+}
+
+
+/* Creates an expression whose value is that of EXPR, converted to type TYPE.
+ This function implements all reasonable scalar conversions. */
+
+tree
+convert (tree type, tree expr)
+{
+ tree e = expr;
+ tree_code code = TREE_CODE (type);
+
+ if (type == error_mark_node
+ || expr == error_mark_node
+ || TREE_TYPE (expr) == error_mark_node)
+ return error_mark_node;
+
+ const char *invalid_conv_diag
+ = targetm.invalid_conversion (TREE_TYPE (expr), type);
+
+ if (invalid_conv_diag)
+ {
+ error ("%s", invalid_conv_diag);
+ return error_mark_node;
+ }
+
+ if (type == TREE_TYPE (expr))
+ return expr;
+
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+ && TYPE_DOMAIN (type) == TYPE_DOMAIN (TREE_TYPE (expr)))
+ return expr;
+
+ tree ret = targetm.convert_to_type (type, expr);
+ if (ret)
+ return ret;
+
+ STRIP_TYPE_NOPS (e);
+ tree etype = TREE_TYPE (e);
+
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
+ return fold_convert (type, expr);
+ if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE)
+ {
+ error ("void value not ignored as it ought to be");
+ return error_mark_node;
+ }
+
+ switch (code)
+ {
+ case VOID_TYPE:
+ return fold_convert (type, e);
+
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ if (TREE_CODE (etype) == POINTER_TYPE
+ || TREE_CODE (etype) == REFERENCE_TYPE)
+ {
+ if (integer_zerop (e))
+ return build_int_cst (type, 0);
+
+ /* Convert to an unsigned integer of the correct width first, and
+ from there widen/truncate to the required type. */
+ tree utype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
+ 1);
+ ret = fold_build1 (CONVERT_EXPR, utype, e);
+ return fold_convert (type, ret);
+ }
+
+ return fold (convert_to_integer (type, e));
+
+ case BOOLEAN_TYPE:
+ return fold_convert (type, d_truthvalue_conversion (expr));
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ return fold (convert_to_pointer (type, e));
+
+ case REAL_TYPE:
+ if (TREE_CODE (etype) == COMPLEX_TYPE && TYPE_IMAGINARY_FLOAT (type))
+ e = build1 (IMAGPART_EXPR, TREE_TYPE (etype), e);
+
+ return fold (convert_to_real (type, e));
+
+ case COMPLEX_TYPE:
+ if (TREE_CODE (etype) == REAL_TYPE && TYPE_IMAGINARY_FLOAT (etype))
+ return fold_build2 (COMPLEX_EXPR, type,
+ build_zero_cst (TREE_TYPE (type)),
+ convert (TREE_TYPE (type), expr));
+
+ return fold (convert_to_complex (type, e));
+
+ case VECTOR_TYPE:
+ return fold (convert_to_vector (type, e));
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr)))
+ return fold_build1 (VIEW_CONVERT_EXPR, type, expr);
+ break;
+
+ default:
+ break;
+ }
+
+ error ("conversion to non-scalar type requested");
+ return error_mark_node;
+}
+
+/* Return expression EXP, whose type has been converted to TYPE. */
+
+tree
+d_convert (tree type, tree exp)
+{
+ /* Check this first before retrieving frontend type. */
+ if (error_operand_p (type) || error_operand_p (exp))
+ return error_mark_node;
+
+ Type *totype = TYPE_LANG_FRONTEND (type);
+ Type *etype = TYPE_LANG_FRONTEND (TREE_TYPE (exp));
+
+ if (totype && etype)
+ return convert_expr (exp, etype, totype);
+
+ return convert (type, exp);
+}
+
+/* Return expression EXP, whose type has been convert from ETYPE to TOTYPE. */
+
+tree
+convert_expr (tree exp, Type *etype, Type *totype)
+{
+ tree result = NULL_TREE;
+
+ gcc_assert (etype && totype);
+ Type *ebtype = etype->toBasetype ();
+ Type *tbtype = totype->toBasetype ();
+
+ if (same_type_p (etype, totype))
+ return exp;
+
+ if (error_operand_p (exp))
+ return exp;
+
+ switch (ebtype->ty)
+ {
+ case Tdelegate:
+ if (tbtype->ty == Tdelegate)
+ {
+ exp = d_save_expr (exp);
+ return build_delegate_cst (delegate_method (exp),
+ delegate_object (exp), totype);
+ }
+ else if (tbtype->ty == Tpointer)
+ {
+ /* The front-end converts <delegate>.ptr to cast (void *)<delegate>.
+ Maybe should only allow void* ? */
+ exp = delegate_object (exp);
+ }
+ else
+ {
+ error ("can't convert a delegate expression to %qs",
+ totype->toChars ());
+ return error_mark_node;
+ }
+ break;
+
+ case Tstruct:
+ if (tbtype->ty == Tstruct)
+ {
+ if (totype->size () == etype->size ())
+ {
+ /* Allowed to cast to structs with same type size. */
+ result = build_vconvert (build_ctype (totype), exp);
+ }
+ else
+ {
+ error ("can't convert struct %qs to %qs",
+ etype->toChars (), totype->toChars ());
+ return error_mark_node;
+ }
+ }
+ /* else, default conversion, which should produce an error. */
+ break;
+
+ case Tclass:
+ if (tbtype->ty == Tclass)
+ {
+ ClassDeclaration *cdfrom = ebtype->isClassHandle ();
+ ClassDeclaration *cdto = tbtype->isClassHandle ();
+ int offset;
+
+ if (cdto->isBaseOf (cdfrom, &offset) && offset != OFFSET_RUNTIME)
+ {
+ /* Casting up the inheritance tree: Don't do anything special.
+ Cast to an implemented interface: Handle at compile-time. */
+ if (offset)
+ {
+ /* Forward references should not leak from the frontend. */
+ gcc_assert (offset != OFFSET_FWDREF);
+
+ tree type = build_ctype (totype);
+ exp = d_save_expr (exp);
+
+ tree cond = build_boolop (NE_EXPR, exp, null_pointer_node);
+ tree object = build_offset (exp, size_int (offset));
+
+ return build_condition (build_ctype (totype), cond,
+ build_nop (type, object),
+ build_nop (type, null_pointer_node));
+ }
+
+ /* d_convert will make a no-op cast. */
+ break;
+ }
+ else if (cdfrom->isCPPclass ())
+ {
+ /* Downcasting in C++ is a no-op. */
+ if (cdto->isCPPclass ())
+ break;
+
+ /* Casting from a C++ interface to a class/non-C++ interface
+ always results in null as there is no run-time information,
+ and no way one can derive from the other. */
+ warning (OPT_Wcast_result, "cast to %qs will produce null result",
+ totype->toChars ());
+ result = d_convert (build_ctype (totype), null_pointer_node);
+
+ /* Make sure the expression is still evaluated if necessary. */
+ if (TREE_SIDE_EFFECTS (exp))
+ result = compound_expr (exp, result);
+
+ break;
+ }
+
+ /* The offset can only be determined at run-time, do dynamic cast. */
+ libcall_fn libcall = cdfrom->isInterfaceDeclaration ()
+ ? LIBCALL_INTERFACE_CAST : LIBCALL_DYNAMIC_CAST;
+
+ return build_libcall (libcall, totype, 2, exp,
+ build_address (get_classinfo_decl (cdto)));
+ }
+ /* else default conversion. */
+ break;
+
+ case Tsarray:
+ if (tbtype->ty == Tpointer)
+ {
+ result = build_nop (build_ctype (totype), build_address (exp));
+ }
+ else if (tbtype->ty == Tarray)
+ {
+ dinteger_t dim = ((TypeSArray *) ebtype)->dim->toInteger ();
+ dinteger_t esize = ebtype->nextOf ()->size ();
+ dinteger_t tsize = tbtype->nextOf ()->size ();
+
+ tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ());
+
+ if ((dim * esize) % tsize != 0)
+ {
+ error ("cannot cast %qs to %qs since sizes don't line up",
+ etype->toChars (), totype->toChars ());
+ return error_mark_node;
+ }
+ dim = (dim * esize) / tsize;
+
+ /* Assumes casting to dynamic array of same type or void. */
+ return d_array_value (build_ctype (totype), size_int (dim),
+ build_nop (ptrtype, build_address (exp)));
+ }
+ else if (tbtype->ty == Tsarray)
+ {
+ /* D allows casting a static array to any static array type. */
+ return build_nop (build_ctype (totype), exp);
+ }
+ else if (tbtype->ty == Tstruct)
+ {
+ /* And allows casting a static array to any struct type too.
+ Type sizes should have already been checked by the frontend. */
+ gcc_assert (totype->size () == etype->size ());
+ result = build_vconvert (build_ctype (totype), exp);
+ }
+ else
+ {
+ error ("cannot cast expression of type %qs to type %qs",
+ etype->toChars (), totype->toChars ());
+ return error_mark_node;
+ }
+ break;
+
+ case Tarray:
+ if (tbtype->ty == Tpointer)
+ {
+ return d_convert (build_ctype (totype), d_array_ptr (exp));
+ }
+ else if (tbtype->ty == Tarray)
+ {
+ /* Assume tvoid->size() == 1. */
+ d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size ();
+ d_uns64 tsize = tbtype->nextOf ()->toBasetype ()->size ();
+
+ if (fsize != tsize)
+ {
+ /* Conversion requires a reinterpret cast of array. */
+ return build_libcall (LIBCALL_ARRAYCAST, totype, 3,
+ size_int (tsize), size_int (fsize), exp);
+ }
+ else
+ {
+ /* Convert from void[] or elements are the same size
+ -- don't change length. */
+ return build_vconvert (build_ctype (totype), exp);
+ }
+ }
+ else if (tbtype->ty == Tsarray)
+ {
+ /* Strings are treated as dynamic arrays in D2. */
+ if (ebtype->isString () && tbtype->isString ())
+ return indirect_ref (build_ctype (totype), d_array_ptr (exp));
+ }
+ else
+ {
+ error ("cannot cast expression of type %qs to %qs",
+ etype->toChars (), totype->toChars ());
+ return error_mark_node;
+ }
+ break;
+
+ case Taarray:
+ if (tbtype->ty == Taarray)
+ return build_vconvert (build_ctype (totype), exp);
+ /* Can convert associative arrays to void pointers. */
+ else if (tbtype->ty == Tpointer && tbtype->nextOf ()->ty == Tvoid)
+ return build_vconvert (build_ctype (totype), exp);
+ /* Else, default conversion, which should product an error. */
+ break;
+
+ case Tpointer:
+ /* Can convert void pointers to associative arrays too. */
+ if (tbtype->ty == Taarray && ebtype->nextOf ()->ty == Tvoid)
+ return build_vconvert (build_ctype (totype), exp);
+ break;
+
+ case Tnull:
+ /* Casting from typeof(null) is represented as all zeros. */
+ if (tbtype->ty == Tarray)
+ {
+ tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ());
+ return d_array_value (build_ctype (totype), size_int (0),
+ build_nop (ptrtype, exp));
+ }
+ else if (tbtype->ty == Taarray)
+ return build_constructor (build_ctype (totype), NULL);
+ else if (tbtype->ty == Tdelegate)
+ return build_delegate_cst (exp, null_pointer_node, totype);
+
+ return build_zero_cst (build_ctype (totype));
+
+ case Tvector:
+ if (tbtype->ty == Tsarray)
+ {
+ if (tbtype->size () == ebtype->size ())
+ return build_vconvert (build_ctype (totype), exp);
+ }
+ break;
+
+ default:
+ /* All casts between imaginary and non-imaginary result in 0.0,
+ except for casts between complex and imaginary types. */
+ if (!ebtype->iscomplex () && !tbtype->iscomplex ()
+ && (ebtype->isimaginary () != tbtype->isimaginary ()))
+ {
+ warning (OPT_Wcast_result,
+ "cast from %qs to %qs will produce zero result",
+ ebtype->toChars (), tbtype->toChars ());
+
+ return compound_expr (exp, build_zero_cst (build_ctype (tbtype)));
+ }
+
+ exp = fold_convert (build_ctype (etype), exp);
+ gcc_assert (TREE_CODE (exp) != STRING_CST);
+ break;
+ }
+
+ return result ? result : convert (build_ctype (totype), exp);
+}
+
+
+/* Apply semantics of assignment to a value of type TOTYPE to EXPR
+ (e.g., pointer = array -> pointer = &array[0])
+
+ Return a TREE representation of EXPR implicitly converted to TOTYPE
+ for use in assignment expressions MODIFY_EXPR, INIT_EXPR. */
+
+tree
+convert_for_assignment (tree expr, Type *etype, Type *totype)
+{
+ Type *ebtype = etype->toBasetype ();
+ Type *tbtype = totype->toBasetype ();
+
+ /* Assuming this only has to handle converting a non Tsarray type to
+ arbitrarily dimensioned Tsarrays. */
+ if (tbtype->ty == Tsarray)
+ {
+ Type *telem = tbtype->nextOf ()->baseElemOf ();
+
+ if (same_type_p (telem, ebtype))
+ {
+ TypeSArray *sa_type = (TypeSArray *) tbtype;
+ uinteger_t count = sa_type->dim->toUInteger ();
+
+ tree ctor = build_constructor (build_ctype (totype), NULL);
+ if (count)
+ {
+ vec<constructor_elt, va_gc> *ce = NULL;
+ tree index = build2 (RANGE_EXPR, build_ctype (Type::tsize_t),
+ size_zero_node, size_int (count - 1));
+ tree value = convert_for_assignment (expr, etype, sa_type->next);
+
+ /* Can't use VAR_DECLs in CONSTRUCTORS. */
+ if (VAR_P (value))
+ {
+ value = DECL_INITIAL (value);
+ gcc_assert (value);
+ }
+
+ CONSTRUCTOR_APPEND_ELT (ce, index, value);
+ CONSTRUCTOR_ELTS (ctor) = ce;
+ }
+ TREE_READONLY (ctor) = 1;
+ TREE_CONSTANT (ctor) = 1;
+ return ctor;
+ }
+ }
+
+ /* D Front end uses IntegerExp(0) to mean zero-init an array or structure. */
+ if ((tbtype->ty == Tsarray || tbtype->ty == Tstruct)
+ && ebtype->isintegral ())
+ {
+ if (!integer_zerop (expr))
+ gcc_unreachable ();
+
+ return expr;
+ }
+
+ return convert_expr (expr, etype, totype);
+}
+
+/* Return a TREE representation of EXPR converted to represent
+ the parameter type ARG. */
+
+tree
+convert_for_argument (tree expr, Parameter *arg)
+{
+ /* Lazy arguments: expr should already be a delegate. */
+ if (arg->storageClass & STClazy)
+ return expr;
+
+ if (valist_array_p (arg->type))
+ {
+ /* Do nothing if the va_list has already been decayed to a pointer. */
+ if (!POINTER_TYPE_P (TREE_TYPE (expr)))
+ return build_address (expr);
+ }
+ else if (argument_reference_p (arg))
+ {
+ /* Front-end shouldn't automatically take the address. */
+ return convert (type_passed_as (arg), build_address (expr));
+ }
+
+ return expr;
+}
+
+/* Perform default promotions for data used in expressions.
+ Arrays and functions are converted to pointers;
+ enumeral types or short or char, to int.
+ In addition, manifest constants symbols are replaced by their values.
+
+ Return truth-value conversion of expression EXPR from value type TYPE. */
+
+tree
+convert_for_condition (tree expr, Type *type)
+{
+ tree result = NULL_TREE;
+
+ switch (type->toBasetype ()->ty)
+ {
+ case Taarray:
+ /* Checks that aa.ptr !is null. */
+ result = component_ref (expr, TYPE_FIELDS (TREE_TYPE (expr)));
+ break;
+
+ case Tarray:
+ {
+ /* Checks (arr.length || arr.ptr) (i.e arr !is null). */
+ expr = d_save_expr (expr);
+ tree len = d_array_length (expr);
+ tree ptr = d_array_ptr (expr);
+ if (TYPE_MODE (TREE_TYPE (len)) == TYPE_MODE (TREE_TYPE (ptr)))
+ {
+ result = build2 (BIT_IOR_EXPR, TREE_TYPE (len), len,
+ d_convert (TREE_TYPE (len), ptr));
+ }
+ else
+ {
+ len = d_truthvalue_conversion (len);
+ ptr = d_truthvalue_conversion (ptr);
+ /* Probably not worth using TRUTH_OROR here. */
+ result = build2 (TRUTH_OR_EXPR, TREE_TYPE (len), len, ptr);
+ }
+ break;
+ }
+
+ case Tdelegate:
+ {
+ /* Checks (function || object), but what good is it if there is
+ a null function pointer? */
+ tree obj, func;
+ if (METHOD_CALL_EXPR (expr))
+ extract_from_method_call (expr, obj, func);
+ else
+ {
+ expr = d_save_expr (expr);
+ obj = delegate_object (expr);
+ func = delegate_method (expr);
+ }
+
+ obj = d_truthvalue_conversion (obj);
+ func = d_truthvalue_conversion (func);
+ /* Probably not worth using TRUTH_ORIF here. */
+ result = build2 (BIT_IOR_EXPR, TREE_TYPE (obj), obj, func);
+ break;
+ }
+
+ default:
+ result = expr;
+ break;
+ }
+
+ return d_truthvalue_conversion (result);
+}
+
+
+/* Convert EXP to a dynamic array.
+ EXP must be a static array or dynamic array. */
+
+tree
+d_array_convert (Expression *exp)
+{
+ Type *tb = exp->type->toBasetype ();
+
+ if (tb->ty == Tarray)
+ return build_expr (exp);
+
+ if (tb->ty == Tsarray)
+ {
+ Type *totype = tb->nextOf ()->arrayOf ();
+ return convert_expr (build_expr (exp), exp->type, totype);
+ }
+
+ /* Invalid type passed. */
+ gcc_unreachable ();
+}
+
+/* Convert EXP to a dynamic array, where ETYPE is the element type.
+ Similar to above, except that EXP is allowed to be an element of an array.
+ Temporary variables that need some kind of BIND_EXPR are pushed to VARS. */
+
+tree
+d_array_convert (Type *etype, Expression *exp, vec<tree, va_gc> **vars)
+{
+ Type *tb = exp->type->toBasetype ();
+
+ if ((tb->ty != Tarray && tb->ty != Tsarray) || same_type_p (tb, etype))
+ {
+ /* Convert single element to an array. */
+ tree var = NULL_TREE;
+ tree expr = maybe_temporary_var (build_expr (exp), &var);
+
+ if (var != NULL_TREE)
+ vec_safe_push (*vars, var);
+
+ return d_array_value (build_ctype (exp->type->arrayOf ()),
+ size_int (1), build_address (expr));
+ }
+ else
+ return d_array_convert (exp);
+}
diff --git a/gcc/d/d-diagnostic.cc b/gcc/d/d-diagnostic.cc
new file mode 100644
index 0000000..a21e7d6
--- /dev/null
+++ b/gcc/d/d-diagnostic.cc
@@ -0,0 +1,358 @@
+/* d-diagnostics.cc -- D frontend interface to gcc diagnostics.
+ Copyright (C) 2017-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/globals.h"
+#include "dmd/errors.h"
+
+#include "tree.h"
+#include "options.h"
+#include "diagnostic.h"
+
+#include "d-tree.h"
+
+
+/* Rewrite the format string FORMAT to deal with any format extensions not
+ supported by pp_format().
+
+ The following format specifiers are handled:
+ `...`: text within backticks gets quoted as '%<...%>'.
+ %-10s: left-justify format flag is removed leaving '%s' remaining.
+ %02x: zero-padding format flag is removed leaving '%x' remaining.
+ %X: uppercase unsigned hexadecimals are rewritten as '%x'.
+
+ The result should be freed by the caller. */
+
+static char *
+expand_d_format (const char *format)
+{
+ OutBuffer buf;
+ bool inbacktick = false;
+
+ for (const char *p = format; *p;)
+ {
+ while (*p != '\0' && *p != '%' && *p != '`')
+ {
+ buf.writeByte (*p);
+ p++;
+ }
+
+ if (*p == '\0')
+ break;
+
+ if (*p == '`')
+ {
+ /* Text enclosed by `...` are translated as a quoted string. */
+ if (inbacktick)
+ {
+ buf.writestring ("%>");
+ inbacktick = false;
+ }
+ else
+ {
+ buf.writestring ("%<");
+ inbacktick = true;
+ }
+ p++;
+ continue;
+ }
+
+ /* Check the conversion specification for unhandled flags. */
+ buf.writeByte (*p);
+ p++;
+
+ Lagain:
+ switch (*p)
+ {
+ case '\0':
+ /* Malformed format string. */
+ gcc_unreachable ();
+
+ case '-':
+ /* Remove whitespace formatting. */
+ p++;
+ while (ISDIGIT (*p))
+ p++;
+ goto Lagain;
+
+ case '0':
+ /* Remove zero padding from format string. */
+ while (ISDIGIT (*p))
+ p++;
+ goto Lagain;
+
+ case 'X':
+ /* Hex format only supports lower-case. */
+ buf.writeByte ('x');
+ p++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ gcc_assert (!inbacktick);
+ return buf.extractString ();
+}
+
+/* Helper routine for all error routines. Reports a diagnostic specified by
+ KIND at the explicit location LOC. The message FORMAT comes from the dmd
+ front-end, which does not get translated by the gcc diagnostic routines. */
+
+static void ATTRIBUTE_GCC_DIAG(3,0)
+d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format,
+ va_list ap, diagnostic_t kind, bool verbatim)
+{
+ va_list argp;
+ va_copy (argp, ap);
+
+ if (loc.filename || !verbatim)
+ {
+ rich_location rich_loc (line_table, make_location_t (loc));
+ diagnostic_info diagnostic;
+ char *xformat = expand_d_format (format);
+
+ diagnostic_set_info_translated (&diagnostic, xformat, &argp,
+ &rich_loc, kind);
+ if (opt != 0)
+ diagnostic.option_index = opt;
+
+ diagnostic_report_diagnostic (global_dc, &diagnostic);
+ free (xformat);
+ }
+ else
+ {
+ /* Write verbatim messages with no location direct to stream. */
+ text_info text;
+ text.err_no = errno;
+ text.args_ptr = &argp;
+ text.format_spec = expand_d_format (format);
+ text.x_data = NULL;
+
+ pp_format_verbatim (global_dc->printer, &text);
+ pp_newline_and_flush (global_dc->printer);
+ }
+
+ va_end (argp);
+}
+
+/* Print a hard error message with explicit location LOC with an optional
+ message prefix PREFIX1 and PREFIX2, increasing the global or gagged
+ error count. */
+
+void ATTRIBUTE_GCC_DIAG(2,3)
+error (const Loc& loc, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ verror (loc, format, ap);
+ va_end (ap);
+}
+
+void ATTRIBUTE_GCC_DIAG(2,0)
+verror (const Loc& loc, const char *format, va_list ap,
+ const char *prefix1, const char *prefix2, const char *)
+{
+ if (!global.gag || global.params.showGaggedErrors)
+ {
+ char *xformat;
+
+ /* Build string and emit. */
+ if (prefix2 != NULL)
+ xformat = xasprintf ("%s %s %s", prefix1, prefix2, format);
+ else if (prefix1 != NULL)
+ xformat = xasprintf ("%s %s", prefix1, format);
+ else
+ xformat = xasprintf ("%s", format);
+
+ d_diagnostic_report_diagnostic (loc, 0, xformat, ap,
+ global.gag ? DK_ANACHRONISM : DK_ERROR,
+ false);
+ free (xformat);
+ }
+
+ if (global.gag)
+ global.gaggedErrors++;
+
+ global.errors++;
+}
+
+/* Print supplementary message about the last error with explicit location LOC.
+ This doesn't increase the global error count. */
+
+void ATTRIBUTE_GCC_DIAG(2,3)
+errorSupplemental (const Loc& loc, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ verrorSupplemental (loc, format, ap);
+ va_end (ap);
+}
+
+void ATTRIBUTE_GCC_DIAG(2,0)
+verrorSupplemental (const Loc& loc, const char *format, va_list ap)
+{
+ if (global.gag && !global.params.showGaggedErrors)
+ return;
+
+ d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
+}
+
+/* Print a warning message with explicit location LOC, increasing the
+ global warning count. */
+
+void ATTRIBUTE_GCC_DIAG(2,3)
+warning (const Loc& loc, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ vwarning (loc, format, ap);
+ va_end (ap);
+}
+
+void ATTRIBUTE_GCC_DIAG(2,0)
+vwarning (const Loc& loc, const char *format, va_list ap)
+{
+ if (!global.gag && global.params.warnings != DIAGNOSTICoff)
+ {
+ /* Warnings don't count if not treated as errors. */
+ if (global.params.warnings == DIAGNOSTICerror)
+ global.warnings++;
+
+ d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false);
+ }
+}
+
+/* Print supplementary message about the last warning with explicit location
+ LOC. This doesn't increase the global warning count. */
+
+void ATTRIBUTE_GCC_DIAG(2,3)
+warningSupplemental (const Loc& loc, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ vwarningSupplemental (loc, format, ap);
+ va_end (ap);
+}
+
+void ATTRIBUTE_GCC_DIAG(2,0)
+vwarningSupplemental (const Loc& loc, const char *format, va_list ap)
+{
+ if (global.params.warnings == DIAGNOSTICoff || global.gag)
+ return;
+
+ d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
+}
+
+/* Print a deprecation message with explicit location LOC with an optional
+ message prefix PREFIX1 and PREFIX2, increasing the global warning or
+ error count depending on how deprecations are treated. */
+
+void ATTRIBUTE_GCC_DIAG(2,3)
+deprecation (const Loc& loc, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ vdeprecation (loc, format, ap);
+ va_end (ap);
+}
+
+void ATTRIBUTE_GCC_DIAG(2,0)
+vdeprecation (const Loc& loc, const char *format, va_list ap,
+ const char *prefix1, const char *prefix2)
+{
+ if (global.params.useDeprecated == DIAGNOSTICerror)
+ verror (loc, format, ap, prefix1, prefix2);
+ else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
+ {
+ char *xformat;
+
+ /* Build string and emit. */
+ if (prefix2 != NULL)
+ xformat = xasprintf ("%s %s %s", prefix1, prefix2, format);
+ else if (prefix1 != NULL)
+ xformat = xasprintf ("%s %s", prefix1, format);
+ else
+ xformat = xasprintf ("%s", format);
+
+ d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap,
+ DK_WARNING, false);
+ free (xformat);
+ }
+}
+
+/* Print supplementary message about the last deprecation with explicit
+ location LOC. This does not increase the global error count. */
+
+void ATTRIBUTE_GCC_DIAG(2,3)
+deprecationSupplemental (const Loc& loc, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ vdeprecationSupplemental (loc, format, ap);
+ va_end (ap);
+}
+
+void ATTRIBUTE_GCC_DIAG(2,0)
+vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap)
+{
+ if (global.params.useDeprecated == DIAGNOSTICerror)
+ verrorSupplemental (loc, format, ap);
+ else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
+ d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
+}
+
+/* Print a verbose message with explicit location LOC. */
+
+void ATTRIBUTE_GCC_DIAG(2, 3)
+message (const Loc& loc, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ vmessage (loc, format, ap);
+ va_end (ap);
+}
+
+void ATTRIBUTE_GCC_DIAG(2,0)
+vmessage (const Loc& loc, const char *format, va_list ap)
+{
+ d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true);
+}
+
+/* Same as above, but doesn't take a location argument. */
+
+void ATTRIBUTE_GCC_DIAG(1, 2)
+message (const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ vmessage (Loc (), format, ap);
+ va_end (ap);
+}
+
+/* Call this after printing out fatal error messages to clean up and
+ exit the compiler. */
+
+void
+fatal (void)
+{
+ exit (FATAL_EXIT_CODE);
+}
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
new file mode 100644
index 0000000..3cba25b
--- /dev/null
+++ b/gcc/d/d-frontend.cc
@@ -0,0 +1,628 @@
+/* d-frontend.cc -- D frontend interface to the gcc back-end.
+ Copyright (C) 2013-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/compiler.h"
+#include "dmd/declaration.h"
+#include "dmd/errors.h"
+#include "dmd/expression.h"
+#include "dmd/identifier.h"
+#include "dmd/module.h"
+#include "dmd/mtype.h"
+#include "dmd/scope.h"
+#include "dmd/statement.h"
+#include "dmd/target.h"
+
+#include "tree.h"
+#include "options.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+
+
+/* Implements the Global interface defined by the frontend.
+ Used for managing the state of the current compilation. */
+
+Global global;
+
+void
+Global::_init (void)
+{
+ this->mars_ext = "d";
+ this->hdr_ext = "di";
+ this->doc_ext = "html";
+ this->ddoc_ext = "ddoc";
+ this->json_ext = "json";
+ this->obj_ext = "o";
+
+ this->run_noext = true;
+ this->version = "v"
+#include "verstr.h"
+ ;
+
+ this->stdmsg = stderr;
+ this->errorLimit = flag_max_errors;
+}
+
+/* Start gagging. Return the current number of gagged errors. */
+
+unsigned
+Global::startGagging (void)
+{
+ this->gag++;
+ return this->gaggedErrors;
+}
+
+/* End gagging, restoring the old gagged state. Return true if errors
+ occured while gagged. */
+
+bool
+Global::endGagging (unsigned oldGagged)
+{
+ bool anyErrs = (this->gaggedErrors != oldGagged);
+ this->gag--;
+
+ /* Restore the original state of gagged errors; set total errors
+ to be original errors + new ungagged errors. */
+ this->errors -= (this->gaggedErrors - oldGagged);
+ this->gaggedErrors = oldGagged;
+
+ return anyErrs;
+}
+
+/* Increment the error count to record that an error has occured in the
+ current context. An error message may or may not have been printed. */
+
+void
+Global::increaseErrorCount (void)
+{
+ if (gag)
+ this->gaggedErrors++;
+
+ this->errors++;
+}
+
+
+/* Implements the Loc interface defined by the frontend.
+ Used for keeping track of current file/line position in code. */
+
+Loc::Loc (const char *filename, unsigned linnum, unsigned charnum)
+{
+ this->linnum = linnum;
+ this->charnum = charnum;
+ this->filename = filename;
+}
+
+const char *
+Loc::toChars (void) const
+{
+ OutBuffer buf;
+
+ if (this->filename)
+ buf.printf ("%s", this->filename);
+
+ if (this->linnum)
+ {
+ buf.printf (":%u", this->linnum);
+ if (this->charnum)
+ buf.printf (":%u", this->charnum);
+ }
+
+ return buf.extractString ();
+}
+
+bool
+Loc::equals (const Loc& loc)
+{
+ if (this->linnum != loc.linnum || this->charnum != loc.charnum)
+ return false;
+
+ if (!FileName::equals (this->filename, loc.filename))
+ return false;
+
+ return true;
+}
+
+
+/* Implements the Port interface defined by the frontend.
+ A mini library for doing compiler/system specific things. */
+
+/* Compare the first N bytes of S1 and S2 without regard to the case. */
+
+int
+Port::memicmp (const char *s1, const char *s2, size_t n)
+{
+ int result = 0;
+
+ for (size_t i = 0; i < n; i++)
+ {
+ char c1 = s1[i];
+ char c2 = s2[i];
+
+ result = c1 - c2;
+ if (result)
+ {
+ result = TOUPPER (c1) - TOUPPER (c2);
+ if (result)
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Convert all characters in S to uppercase. */
+
+char *
+Port::strupr (char *s)
+{
+ char *t = s;
+
+ while (*s)
+ {
+ *s = TOUPPER (*s);
+ s++;
+ }
+
+ return t;
+}
+
+/* Return true if the real_t value from string BUFFER overflows
+ as a result of rounding down to float mode. */
+
+bool
+Port::isFloat32LiteralOutOfRange (const char *buffer)
+{
+ real_t r;
+
+ real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
+
+ return r == Target::RealProperties::infinity;
+}
+
+/* Return true if the real_t value from string BUFFER overflows
+ as a result of rounding down to double mode. */
+
+bool
+Port::isFloat64LiteralOutOfRange (const char *buffer)
+{
+ real_t r;
+
+ real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
+
+ return r == Target::RealProperties::infinity;
+}
+
+/* Fetch a little-endian 16-bit value from BUFFER. */
+
+unsigned
+Port::readwordLE (void *buffer)
+{
+ unsigned char *p = (unsigned char*) buffer;
+
+ return ((unsigned) p[1] << 8) | (unsigned) p[0];
+}
+
+/* Fetch a big-endian 16-bit value from BUFFER. */
+
+unsigned
+Port::readwordBE (void *buffer)
+{
+ unsigned char *p = (unsigned char*) buffer;
+
+ return ((unsigned) p[0] << 8) | (unsigned) p[1];
+}
+
+/* Fetch a little-endian 32-bit value from BUFFER. */
+
+unsigned
+Port::readlongLE (void *buffer)
+{
+ unsigned char *p = (unsigned char*) buffer;
+
+ return (((unsigned) p[3] << 24)
+ | ((unsigned) p[2] << 16)
+ | ((unsigned) p[1] << 8)
+ | (unsigned) p[0]);
+}
+
+/* Fetch a big-endian 32-bit value from BUFFER. */
+
+unsigned
+Port::readlongBE (void *buffer)
+{
+ unsigned char *p = (unsigned char*) buffer;
+
+ return (((unsigned) p[0] << 24)
+ | ((unsigned) p[1] << 16)
+ | ((unsigned) p[2] << 8)
+ | (unsigned) p[3]);
+}
+
+/* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */
+
+void
+Port::valcpy (void *buffer, uint64_t value, size_t sz)
+{
+ switch (sz)
+ {
+ case 1:
+ *(uint8_t *) buffer = (uint8_t) value;
+ break;
+
+ case 2:
+ *(uint16_t *) buffer = (uint16_t) value;
+ break;
+
+ case 4:
+ *(uint32_t *) buffer = (uint32_t) value;
+ break;
+
+ case 8:
+ *(uint64_t *) buffer = (uint64_t) value;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+
+/* Implements the CTFloat interface defined by the frontend.
+ Compile-time floating-pointer helper functions. */
+
+/* Return the absolute value of R. */
+
+real_t
+CTFloat::fabs (real_t r)
+{
+ real_t x;
+ real_arithmetic (&x.rv (), ABS_EXPR, &r.rv (), NULL);
+ return x.normalize ();
+}
+
+/* Return the value of R * 2 ^^ EXP. */
+
+real_t
+CTFloat::ldexp (real_t r, int exp)
+{
+ real_t x;
+ real_ldexp (&x.rv (), &r.rv (), exp);
+ return x.normalize ();
+}
+
+/* Return true if longdouble value X is identical to Y. */
+
+bool
+CTFloat::isIdentical (real_t x, real_t y)
+{
+ real_value rx = x.rv ();
+ real_value ry = y.rv ();
+ return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
+ || real_identical (&rx, &ry);
+}
+
+/* Return true if real_t value R is NaN. */
+
+bool
+CTFloat::isNaN (real_t r)
+{
+ return REAL_VALUE_ISNAN (r.rv ());
+}
+
+/* Same as isNaN, but also check if is signalling. */
+
+bool
+CTFloat::isSNaN (real_t r)
+{
+ return REAL_VALUE_ISSIGNALING_NAN (r.rv ());
+}
+
+/* Return true if real_t value is +Inf. */
+
+bool
+CTFloat::isInfinity (real_t r)
+{
+ return REAL_VALUE_ISINF (r.rv ());
+}
+
+/* Return a real_t value from string BUFFER rounded to long double mode. */
+
+real_t
+CTFloat::parse (const char *buffer, bool *overflow)
+{
+ real_t r;
+ real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node));
+
+ /* Front-end checks overflow to see if the value is representable. */
+ if (overflow && r == Target::RealProperties::infinity)
+ *overflow = true;
+
+ return r;
+}
+
+/* Format the real_t value R to string BUFFER as a decimal or hexadecimal,
+ converting the result to uppercase if FMT requests it. */
+
+int
+CTFloat::sprint (char *buffer, char fmt, real_t r)
+{
+ if (fmt == 'a' || fmt == 'A')
+ {
+ /* Converting to a hexadecimal string. */
+ real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1);
+ int buflen;
+
+ switch (fmt)
+ {
+ case 'A':
+ buflen = strlen (buffer);
+ for (int i = 0; i < buflen; i++)
+ buffer[i] = TOUPPER (buffer[i]);
+
+ return buflen;
+
+ case 'a':
+ return strlen (buffer);
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ /* Note: restricting the precision of significant digits to 18. */
+ real_to_decimal (buffer, &r.rv (), 32, 18, 1);
+ return strlen (buffer);
+ }
+}
+
+/* Return a hash value for real_t value R. */
+
+size_t
+CTFloat::hash (real_t r)
+{
+ return real_hash (&r.rv ());
+}
+
+/* Implements the Compiler interface used by the frontend. */
+
+/* Generate C main() in response to seeing D main(). This used to be in
+ libdruntime, but contained a reference to _Dmain which didn't work when
+ druntime was made into a shared library and was linked to a program, such
+ as a C++ program, that didn't have a _Dmain. */
+
+void
+Compiler::genCmain (Scope *sc)
+{
+ static bool initialized = false;
+
+ if (initialized)
+ return;
+
+ /* The D code to be generated is provided by __entrypoint.di, try to load it,
+ but don't fail if unfound. */
+ unsigned errors = global.startGagging ();
+ Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__entrypoint"));
+
+ if (global.endGagging (errors))
+ m = NULL;
+
+ if (m != NULL)
+ {
+ m->importedFrom = m;
+ m->importAll (NULL);
+ m->semantic (NULL);
+ m->semantic2 (NULL);
+ m->semantic3 (NULL);
+ d_add_entrypoint_module (m, sc->_module);
+ }
+
+ initialized = true;
+}
+
+/* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
+ The front end should have already ensured that EXPR is a constant,
+ so we just lower the value to GCC and return the converted CST. */
+
+Expression *
+Compiler::paintAsType (Expression *expr, Type *type)
+{
+ /* We support up to 512-bit values. */
+ unsigned char buffer[64];
+ tree cst;
+
+ Type *tb = type->toBasetype ();
+
+ if (expr->type->isintegral ())
+ cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
+ else if (expr->type->isfloating ())
+ cst = build_float_cst (expr->toReal (), expr->type);
+ else if (expr->op == TOKarrayliteral)
+ {
+ /* Build array as VECTOR_CST, assumes EXPR is constant. */
+ Expressions *elements = ((ArrayLiteralExp *) expr)->elements;
+ vec<constructor_elt, va_gc> *elms = NULL;
+
+ vec_safe_reserve (elms, elements->dim);
+ for (size_t i = 0; i < elements->dim; i++)
+ {
+ Expression *e = (*elements)[i];
+ if (e->type->isintegral ())
+ {
+ tree value = build_integer_cst (e->toInteger (),
+ build_ctype (e->type));
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+ }
+ else if (e->type->isfloating ())
+ {
+ tree value = build_float_cst (e->toReal (), e->type);
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+ }
+ else
+ gcc_unreachable ();
+ }
+
+ /* Build vector type. */
+ int nunits = ((TypeSArray *) expr->type)->dim->toUInteger ();
+ Type *telem = expr->type->nextOf ();
+ tree vectype = build_vector_type (build_ctype (telem), nunits);
+
+ cst = build_vector_from_ctor (vectype, elms);
+ }
+ else
+ gcc_unreachable ();
+
+ /* Encode CST to buffer. */
+ int len = native_encode_expr (cst, buffer, sizeof (buffer));
+
+ if (tb->ty == Tsarray)
+ {
+ /* Interpret value as a vector of the same size,
+ then return the array literal. */
+ int nunits = ((TypeSArray *) type)->dim->toUInteger ();
+ Type *elem = type->nextOf ();
+ tree vectype = build_vector_type (build_ctype (elem), nunits);
+
+ cst = native_interpret_expr (vectype, buffer, len);
+
+ Expression *e = d_eval_constant_expression (cst);
+ gcc_assert (e != NULL && e->op == TOKvector);
+
+ return ((VectorExp *) e)->e1;
+ }
+ else
+ {
+ /* Normal interpret cast. */
+ cst = native_interpret_expr (build_ctype (type), buffer, len);
+
+ Expression *e = d_eval_constant_expression (cst);
+ gcc_assert (e != NULL);
+
+ return e;
+ }
+}
+
+/* Check imported module M for any special processing.
+ Modules we look out for are:
+ - object: For D runtime type information.
+ - gcc.builtins: For all gcc builtins.
+ - core.stdc.*: For all gcc library builtins. */
+
+void
+Compiler::loadModule (Module *m)
+{
+ ModuleDeclaration *md = m->md;
+
+ if (!md || !md->id || !md->packages)
+ {
+ Identifier *id = (md && md->id) ? md->id : m->ident;
+ if (!strcmp (id->toChars (), "object"))
+ create_tinfo_types (m);
+ }
+ else if (md->packages->dim == 1)
+ {
+ if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+ && !strcmp (md->id->toChars (), "builtins"))
+ d_build_builtins_module (m);
+ }
+ else if (md->packages->dim == 2)
+ {
+ if (!strcmp ((*md->packages)[0]->toChars (), "core")
+ && !strcmp ((*md->packages)[1]->toChars (), "stdc"))
+ d_add_builtin_module (m);
+ }
+}
+
+/* Implements back-end specific interfaces used by the frontend. */
+
+/* Determine return style of function - whether in registers or through a
+ hidden pointer to the caller's stack. */
+
+RET
+retStyle (TypeFunction *)
+{
+ /* Need the backend type to determine this, but this is called from the
+ frontend before semantic processing is finished. An accurate value
+ is not currently needed anyway. */
+ return RETstack;
+}
+
+/* Determine if function FD is a builtin one that we can evaluate in CTFE. */
+
+BUILTIN
+isBuiltin (FuncDeclaration *fd)
+{
+ if (fd->builtin != BUILTINunknown)
+ return fd->builtin;
+
+ maybe_set_intrinsic (fd);
+
+ return fd->builtin;
+}
+
+/* Evaluate builtin D function FD whose argument list is ARGUMENTS.
+ Return result; NULL if cannot evaluate it. */
+
+Expression *
+eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
+{
+ if (fd->builtin != BUILTINyes)
+ return NULL;
+
+ tree decl = get_symbol_decl (fd);
+ gcc_assert (fndecl_built_in_p (decl)
+ || DECL_INTRINSIC_CODE (decl) != INTRINSIC_NONE);
+
+ TypeFunction *tf = (TypeFunction *) fd->type;
+ Expression *e = NULL;
+ input_location = make_location_t (loc);
+
+ tree result = d_build_call (tf, decl, NULL, arguments);
+ result = fold (result);
+
+ /* Builtin should be successfully evaluated.
+ Will only return NULL if we can't convert it. */
+ if (TREE_CONSTANT (result) && TREE_CODE (result) != CALL_EXPR)
+ e = d_eval_constant_expression (result);
+
+ return e;
+}
+
+/* Build and return typeinfo type for TYPE. */
+
+Type *
+getTypeInfoType (Type *type, Scope *sc)
+{
+ gcc_assert (type->ty != Terror);
+ create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
+ return type->vtinfo->type;
+}
+
+/* Return an inlined copy of a default argument for a function parameter. */
+
+Expression *
+inlineCopy (Expression *e, Scope *)
+{
+ return e->copy ();
+}
diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc
new file mode 100644
index 0000000..be08ccb
--- /dev/null
+++ b/gcc/d/d-incpath.cc
@@ -0,0 +1,195 @@
+/* d-incpath.cc -- Set up combined import paths for the D frontend.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/globals.h"
+
+#include "cppdefault.h"
+
+/* Look for directories that start with the standard prefix.
+ "Translate" them, i.e: replace /usr/local/lib/gcc with
+ IPREFIX and search them first. Based on incpath.c. */
+
+static char *
+prefixed_path (const char *path, const char *iprefix)
+{
+ size_t len;
+
+ if (cpp_relocated () && (len = cpp_PREFIX_len) != 0)
+ {
+ if (!strncmp (path, cpp_PREFIX, len))
+ {
+ static const char *relocated_prefix;
+ /* If this path starts with the configure-time prefix,
+ but the compiler has been relocated, replace it
+ with the run-time prefix. */
+ if (!relocated_prefix)
+ {
+ /* Make relative prefix expects the first argument
+ to be a program, not a directory. */
+ char *dummy = concat (gcc_exec_prefix, "dummy", NULL);
+ relocated_prefix
+ = make_relative_prefix (dummy,
+ cpp_EXEC_PREFIX,
+ cpp_PREFIX);
+ free (dummy);
+ }
+
+ return concat (relocated_prefix, path + len, NULL);
+ }
+ }
+
+ if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0)
+ {
+ if (!strncmp (path, cpp_GCC_INCLUDE_DIR, len))
+ return concat (iprefix, path + len, NULL);
+ }
+
+ return xstrdup (path);
+}
+
+/* Add PATHS to the global import lookup path. */
+
+static void
+add_globalpaths (Strings *paths)
+{
+ if (paths)
+ {
+ if (!global.path)
+ global.path = new Strings ();
+
+ for (size_t i = 0; i < paths->dim; i++)
+ {
+ const char *path = (*paths)[i];
+ const char *target = FileName::canonicalName (path);
+
+ if (target == NULL || !FileName::exists (target))
+ {
+ if (target)
+ free (CONST_CAST (char *, target));
+ continue;
+ }
+
+ global.path->push (target);
+ }
+ }
+}
+
+/* Add PATHS to the global file import lookup path. */
+
+static void
+add_filepaths (Strings *paths)
+{
+ if (paths)
+ {
+ if (!global.filePath)
+ global.filePath = new Strings ();
+
+ for (size_t i = 0; i < paths->dim; i++)
+ {
+ const char *path = (*paths)[i];
+ const char *target = FileName::canonicalName (path);
+
+ if (!FileName::exists (target))
+ {
+ free (CONST_CAST (char *, target));
+ continue;
+ }
+
+ global.filePath->push (target);
+ }
+ }
+}
+
+/* Add all search directories to compiler runtime.
+ if STDINC, also include standard library paths. */
+
+void
+add_import_paths (const char *iprefix, const char *imultilib, bool stdinc)
+{
+ if (stdinc)
+ {
+ for (const default_include *p = cpp_include_defaults; p->fname; p++)
+ {
+ char *path;
+
+ /* Ignore C++ paths. */
+ if (p->cplusplus)
+ continue;
+
+ if (!p->add_sysroot)
+ path = prefixed_path (p->fname, iprefix);
+ else
+ path = xstrdup (p->fname);
+
+ /* Add D-specific suffix. */
+ path = concat (path, "/d", NULL);
+
+ /* Ignore duplicate entries. */
+ bool found = false;
+ for (size_t i = 0; i < global.params.imppath->dim; i++)
+ {
+ if (strcmp (path, (*global.params.imppath)[i]) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ free (path);
+ continue;
+ }
+
+ /* Multilib support. */
+ if (imultilib)
+ {
+ char *target_path = concat (path, "/", imultilib, NULL);
+ global.params.imppath->shift (target_path);
+ }
+
+ global.params.imppath->shift (path);
+ }
+ }
+
+ /* Add import search paths. */
+ if (global.params.imppath)
+ {
+ for (size_t i = 0; i < global.params.imppath->dim; i++)
+ {
+ const char *path = (*global.params.imppath)[i];
+ if (path)
+ add_globalpaths (FileName::splitPath (path));
+ }
+ }
+
+ /* Add string import search paths. */
+ if (global.params.fileImppath)
+ {
+ for (size_t i = 0; i < global.params.fileImppath->dim; i++)
+ {
+ const char *path = (*global.params.fileImppath)[i];
+ if (path)
+ add_filepaths (FileName::splitPath (path));
+ }
+ }
+}
+
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
new file mode 100644
index 0000000..42fefaf
--- /dev/null
+++ b/gcc/d/d-lang.cc
@@ -0,0 +1,1797 @@
+/* d-lang.cc -- Language-dependent hooks for D.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/cond.h"
+#include "dmd/declaration.h"
+#include "dmd/doc.h"
+#include "dmd/errors.h"
+#include "dmd/expression.h"
+#include "dmd/hdrgen.h"
+#include "dmd/identifier.h"
+#include "dmd/json.h"
+#include "dmd/mangle.h"
+#include "dmd/mars.h"
+#include "dmd/module.h"
+#include "dmd/mtype.h"
+#include "dmd/target.h"
+
+#include "opts.h"
+#include "alias.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "toplev.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "target.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "output.h"
+#include "print-tree.h"
+#include "gimple-expr.h"
+#include "gimplify.h"
+#include "debug.h"
+
+#include "d-tree.h"
+#include "id.h"
+
+
+/* Array of D frontend type/decl nodes. */
+tree d_global_trees[DTI_MAX];
+
+/* True if compilation is currently inside the D frontend semantic passes. */
+bool doing_semantic_analysis_p = false;
+
+/* Options handled by the compiler that are separate from the frontend. */
+struct d_option_data
+{
+ const char *fonly; /* -fonly=<arg> */
+ const char *multilib; /* -imultilib <dir> */
+ const char *prefix; /* -iprefix <dir> */
+
+ bool deps; /* -M */
+ bool deps_skip_system; /* -MM */
+ const char *deps_filename; /* -M[M]D */
+ const char *deps_filename_user; /* -MF <arg> */
+ OutBuffer *deps_target; /* -M[QT] <arg> */
+ bool deps_phony; /* -MP */
+
+ bool stdinc; /* -nostdinc */
+}
+d_option;
+
+/* List of modules being compiled. */
+static Modules builtin_modules;
+
+/* Module where `C main' is defined, compiled in if needed. */
+static Module *entrypoint_module = NULL;
+static Module *entrypoint_root_module = NULL;
+
+/* The current and global binding level in effect. */
+struct binding_level *current_binding_level;
+struct binding_level *global_binding_level;
+
+/* The context to be used for global declarations. */
+static GTY(()) tree global_context;
+
+/* Array of all global declarations to pass back to the middle-end. */
+static GTY(()) vec<tree, va_gc> *global_declarations;
+
+/* Support for GCC-style command-line make dependency generation.
+ Adds TARGET to the make dependencies target buffer.
+ QUOTED is true if the string should be quoted. */
+
+static void
+deps_add_target (const char *target, bool quoted)
+{
+ if (!d_option.deps_target)
+ d_option.deps_target = new OutBuffer ();
+ else
+ d_option.deps_target->writeByte (' ');
+
+ d_option.deps_target->reserve (strlen (target));
+
+ if (!quoted)
+ {
+ d_option.deps_target->writestring (target);
+ return;
+ }
+
+ /* Quote characters in target which are significant to Make. */
+ for (const char *p = target; *p != '\0'; p++)
+ {
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ for (const char *q = p - 1; target <= q && *q == '\\'; q--)
+ d_option.deps_target->writeByte ('\\');
+ d_option.deps_target->writeByte ('\\');
+ break;
+
+ case '$':
+ d_option.deps_target->writeByte ('$');
+ break;
+
+ case '#':
+ d_option.deps_target->writeByte ('\\');
+ break;
+
+ default:
+ break;
+ }
+
+ d_option.deps_target->writeByte (*p);
+ }
+}
+
+/* Write out all dependencies of a given MODULE to the specified BUFFER.
+ COLMAX is the number of columns to word-wrap at (0 means don't wrap). */
+
+static void
+deps_write (Module *module, OutBuffer *buffer, unsigned colmax = 72)
+{
+ hash_set <const char *> dependencies;
+
+ Modules modlist;
+ modlist.push (module);
+
+ Modules phonylist;
+
+ const char *str;
+ unsigned size;
+ unsigned column = 0;
+
+ /* Write out make target module name. */
+ if (d_option.deps_target)
+ {
+ size = d_option.deps_target->offset;
+ str = d_option.deps_target->extractString ();
+ }
+ else
+ {
+ str = module->objfile->name->str;
+ size = strlen (str);
+ }
+
+ buffer->writestring (str);
+ column = size;
+ buffer->writestring (":");
+ column++;
+
+ /* Write out all make dependencies. */
+ while (modlist.dim > 0)
+ {
+ Module *depmod = modlist.pop ();
+
+ str = depmod->srcfile->name->str;
+ size = strlen (str);
+
+ /* Skip dependencies that have already been written. */
+ if (dependencies.add (str))
+ continue;
+
+ column += size;
+
+ if (colmax && column > colmax)
+ {
+ buffer->writestring (" \\\n ");
+ column = size + 1;
+ }
+ else
+ {
+ buffer->writestring (" ");
+ column++;
+ }
+
+ buffer->writestring (str);
+
+ /* Add to list of phony targets if is not being compile. */
+ if (d_option.deps_phony && !depmod->isRoot ())
+ phonylist.push (depmod);
+
+ /* Search all imports of the written dependency. */
+ for (size_t i = 0; i < depmod->aimports.dim; i++)
+ {
+ Module *m = depmod->aimports[i];
+
+ /* Ignore compiler-generated modules. */
+ if ((m->ident == Identifier::idPool ("__entrypoint")
+ || m->ident == Identifier::idPool ("__main"))
+ && m->parent == NULL)
+ continue;
+
+ /* Don't search system installed modules, this includes
+ object, core.*, std.*, and gcc.* packages. */
+ if (d_option.deps_skip_system)
+ {
+ if (m->ident == Identifier::idPool ("object")
+ && m->parent == NULL)
+ continue;
+
+ if (m->md && m->md->packages)
+ {
+ Identifier *package = (*m->md->packages)[0];
+
+ if (package == Identifier::idPool ("core")
+ || package == Identifier::idPool ("std")
+ || package == Identifier::idPool ("gcc"))
+ continue;
+ }
+ }
+
+ modlist.push (m);
+ }
+ }
+
+ buffer->writenl ();
+
+ /* Write out all phony targets. */
+ for (size_t i = 0; i < phonylist.dim; i++)
+ {
+ Module *m = phonylist[i];
+
+ buffer->writenl ();
+ buffer->writestring (m->srcfile->name->str);
+ buffer->writestring (":\n");
+ }
+}
+
+/* Implements the lang_hooks.init_options routine for language D.
+ This initializes the global state for the D frontend before calling
+ the option handlers. */
+
+static void
+d_init_options (unsigned int, cl_decoded_option *decoded_options)
+{
+ /* Set default values. */
+ global._init ();
+
+ global.vendor = lang_hooks.name;
+ global.params.argv0 = xstrdup (decoded_options[0].arg);
+ global.params.link = true;
+ global.params.useAssert = true;
+ global.params.useInvariants = true;
+ global.params.useIn = true;
+ global.params.useOut = true;
+ global.params.useArrayBounds = BOUNDSCHECKdefault;
+ global.params.useSwitchError = true;
+ global.params.useInline = false;
+ global.params.obj = true;
+ global.params.hdrStripPlainFunctions = true;
+ global.params.betterC = false;
+ global.params.allInst = false;
+
+ global.params.linkswitches = new Strings ();
+ global.params.libfiles = new Strings ();
+ global.params.objfiles = new Strings ();
+ global.params.ddocfiles = new Strings ();
+
+ /* Warnings and deprecations are disabled by default. */
+ global.params.useDeprecated = DIAGNOSTICoff;
+ global.params.warnings = DIAGNOSTICoff;
+
+ global.params.imppath = new Strings ();
+ global.params.fileImppath = new Strings ();
+ global.params.modFileAliasStrings = new Strings ();
+
+ /* Extra GDC-specific options. */
+ d_option.fonly = NULL;
+ d_option.multilib = NULL;
+ d_option.prefix = NULL;
+ d_option.deps = false;
+ d_option.deps_skip_system = false;
+ d_option.deps_filename = NULL;
+ d_option.deps_filename_user = NULL;
+ d_option.deps_target = NULL;
+ d_option.deps_phony = false;
+ d_option.stdinc = true;
+}
+
+/* Implements the lang_hooks.init_options_struct routine for language D.
+ Initializes the options structure OPTS. */
+
+static void
+d_init_options_struct (gcc_options *opts)
+{
+ /* GCC options. */
+ opts->x_flag_exceptions = 1;
+
+ /* Avoid range issues for complex multiply and divide. */
+ opts->x_flag_complex_method = 2;
+
+ /* Unlike C, there is no global 'errno' variable. */
+ opts->x_flag_errno_math = 0;
+ opts->frontend_set_flag_errno_math = true;
+
+ /* Keep in sync with existing -fbounds-check flag. */
+ opts->x_flag_bounds_check = global.params.useArrayBounds;
+
+ /* D says that signed overflow is precisely defined. */
+ opts->x_flag_wrapv = 1;
+}
+
+/* Implements the lang_hooks.lang_mask routine for language D.
+ Returns language mask for option parsing. */
+
+static unsigned int
+d_option_lang_mask (void)
+{
+ return CL_D;
+}
+
+/* Implements the lang_hooks.init routine for language D. */
+
+static bool
+d_init (void)
+{
+ Type::_init ();
+ Id::initialize ();
+ Module::_init ();
+ Expression::_init ();
+ Objc::_init ();
+
+ /* Back-end init. */
+ global_binding_level = ggc_cleared_alloc<binding_level> ();
+ current_binding_level = global_binding_level;
+
+ /* This allows the code in d-builtins.cc to not have to worry about
+ converting (C signed char *) to (D char *) for string arguments of
+ built-in functions. The parameter (signed_char = false) specifies
+ whether char is signed. */
+ build_common_tree_nodes (false);
+
+ d_init_builtins ();
+
+ if (flag_exceptions)
+ using_eh_for_cleanups ();
+
+ if (!supports_one_only ())
+ flag_weak = 0;
+
+ /* This is the C main, not the D main. */
+ main_identifier_node = get_identifier ("main");
+
+ Target::_init ();
+ d_init_versions ();
+
+ /* Insert all library-configured identifiers and import paths. */
+ add_import_paths (d_option.prefix, d_option.multilib, d_option.stdinc);
+
+ return 1;
+}
+
+/* Implements the lang_hooks.init_ts routine for language D. */
+
+static void
+d_init_ts (void)
+{
+ MARK_TS_TYPED (FLOAT_MOD_EXPR);
+ MARK_TS_TYPED (UNSIGNED_RSHIFT_EXPR);
+}
+
+/* Implements the lang_hooks.handle_option routine for language D.
+ Handles D specific options. Return false if we didn't do anything. */
+
+static bool
+d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
+ int kind ATTRIBUTE_UNUSED,
+ location_t loc ATTRIBUTE_UNUSED,
+ const cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+ opt_code code = (opt_code) scode;
+ bool result = true;
+
+ switch (code)
+ {
+ case OPT_fall_instantiations:
+ global.params.allInst = value;
+ break;
+
+ case OPT_fassert:
+ global.params.useAssert = value;
+ break;
+
+ case OPT_fbounds_check:
+ global.params.useArrayBounds = value
+ ? BOUNDSCHECKon : BOUNDSCHECKoff;
+ break;
+
+ case OPT_fbounds_check_:
+ global.params.useArrayBounds = (value == 2) ? BOUNDSCHECKon
+ : (value == 1) ? BOUNDSCHECKsafeonly : BOUNDSCHECKoff;
+ break;
+
+ case OPT_fdebug:
+ global.params.debuglevel = value ? 1 : 0;
+ break;
+
+ case OPT_fdebug_:
+ if (ISDIGIT (arg[0]))
+ {
+ int level = integral_argument (arg);
+ if (level != -1)
+ {
+ DebugCondition::setGlobalLevel (level);
+ break;
+ }
+ }
+
+ if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
+ {
+ DebugCondition::addGlobalIdent (arg);
+ break;
+ }
+
+ error ("bad argument for -fdebug %qs", arg);
+ break;
+
+ case OPT_fdoc:
+ global.params.doDocComments = value;
+ break;
+
+ case OPT_fdoc_dir_:
+ global.params.doDocComments = true;
+ global.params.docdir = arg;
+ break;
+
+ case OPT_fdoc_file_:
+ global.params.doDocComments = true;
+ global.params.docname = arg;
+ break;
+
+ case OPT_fdoc_inc_:
+ global.params.ddocfiles->push (arg);
+ break;
+
+ case OPT_fdump_d_original:
+ global.params.vcg_ast = value;
+ break;
+
+ case OPT_fignore_unknown_pragmas:
+ global.params.ignoreUnsupportedPragmas = value;
+ break;
+
+ case OPT_finvariants:
+ global.params.useInvariants = value;
+ break;
+
+ case OPT_fmain:
+ global.params.addMain = value;
+ break;
+
+ case OPT_fmodule_file_:
+ global.params.modFileAliasStrings->push (arg);
+ if (!strchr (arg, '='))
+ error ("bad argument for -fmodule-file %qs", arg);
+ break;
+
+ case OPT_fmoduleinfo:
+ global.params.betterC = !value;
+ break;
+
+ case OPT_fonly_:
+ d_option.fonly = arg;
+ break;
+
+ case OPT_fpostconditions:
+ global.params.useOut = value;
+ break;
+
+ case OPT_fpreconditions:
+ global.params.useIn = value;
+ break;
+
+ case OPT_frelease:
+ global.params.release = value;
+ break;
+
+ case OPT_fswitch_errors:
+ global.params.useSwitchError = value;
+ break;
+
+ case OPT_ftransition_all:
+ global.params.vtls = value;
+ global.params.vfield = value;
+ global.params.vcomplex = value;
+ break;
+
+ case OPT_ftransition_checkimports:
+ global.params.check10378 = value;
+ break;
+
+ case OPT_ftransition_complex:
+ global.params.vcomplex = value;
+ break;
+
+ case OPT_ftransition_dip1000:
+ global.params.vsafe = value;
+ global.params.useDIP25 = value;
+ break;
+
+ case OPT_ftransition_dip25:
+ global.params.useDIP25 = value;
+ break;
+
+ case OPT_ftransition_field:
+ global.params.vfield = value;
+ break;
+
+ case OPT_ftransition_import:
+ global.params.bug10378 = value;
+ break;
+
+ case OPT_ftransition_nogc:
+ global.params.vgc = value;
+ break;
+
+ case OPT_ftransition_tls:
+ global.params.vtls = value;
+ break;
+
+ case OPT_funittest:
+ global.params.useUnitTests = value;
+ break;
+
+ case OPT_fversion_:
+ if (ISDIGIT (arg[0]))
+ {
+ int level = integral_argument (arg);
+ if (level != -1)
+ {
+ VersionCondition::setGlobalLevel (level);
+ break;
+ }
+ }
+
+ if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
+ {
+ VersionCondition::addGlobalIdent (arg);
+ break;
+ }
+
+ error ("bad argument for -fversion %qs", arg);
+ break;
+
+ case OPT_H:
+ global.params.doHdrGeneration = true;
+ break;
+
+ case OPT_Hd:
+ global.params.doHdrGeneration = true;
+ global.params.hdrdir = arg;
+ break;
+
+ case OPT_Hf:
+ global.params.doHdrGeneration = true;
+ global.params.hdrname = arg;
+ break;
+
+ case OPT_imultilib:
+ d_option.multilib = arg;
+ break;
+
+ case OPT_iprefix:
+ d_option.prefix = arg;
+ break;
+
+ case OPT_I:
+ global.params.imppath->push (arg);
+ break;
+
+ case OPT_J:
+ global.params.fileImppath->push (arg);
+ break;
+
+ case OPT_MM:
+ d_option.deps_skip_system = true;
+ /* Fall through. */
+
+ case OPT_M:
+ d_option.deps = true;
+ break;
+
+ case OPT_MMD:
+ d_option.deps_skip_system = true;
+ /* Fall through. */
+
+ case OPT_MD:
+ d_option.deps = true;
+ d_option.deps_filename = arg;
+ break;
+
+ case OPT_MF:
+ /* If specified multiple times, last one wins. */
+ d_option.deps_filename_user = arg;
+ break;
+
+ case OPT_MP:
+ d_option.deps_phony = true;
+ break;
+
+ case OPT_MQ:
+ deps_add_target (arg, true);
+ break;
+
+ case OPT_MT:
+ deps_add_target (arg, false);
+ break;
+
+ case OPT_nostdinc:
+ d_option.stdinc = false;
+ break;
+
+ case OPT_v:
+ global.params.verbose = value;
+ break;
+
+ case OPT_Wall:
+ if (value)
+ global.params.warnings = DIAGNOSTICinform;
+ break;
+
+ case OPT_Wdeprecated:
+ global.params.useDeprecated = value ? DIAGNOSTICinform : DIAGNOSTICoff;
+ break;
+
+ case OPT_Werror:
+ if (value)
+ global.params.warnings = DIAGNOSTICerror;
+ break;
+
+ case OPT_Wspeculative:
+ if (value)
+ global.params.showGaggedErrors = 1;
+ break;
+
+ case OPT_Xf:
+ global.params.jsonfilename = arg;
+ /* Fall through. */
+
+ case OPT_X:
+ global.params.doJsonGeneration = true;
+ break;
+
+ default:
+ break;
+ }
+
+ D_handle_option_auto (&global_options, &global_options_set,
+ scode, arg, value,
+ d_option_lang_mask (), kind,
+ loc, handlers, global_dc);
+
+ return result;
+}
+
+/* Implements the lang_hooks.post_options routine for language D.
+ Deal with any options that imply the turning on/off of features.
+ FN is the main input filename passed on the command line. */
+
+static bool
+d_post_options (const char ** fn)
+{
+ /* Verify the input file name. */
+ const char *filename = *fn;
+ if (!filename || strcmp (filename, "-") == 0)
+ filename = "";
+
+ /* The front end considers the first input file to be the main one. */
+ *fn = filename;
+
+ /* Release mode doesn't turn off bounds checking for safe functions. */
+ if (global.params.useArrayBounds == BOUNDSCHECKdefault)
+ {
+ global.params.useArrayBounds = global.params.release
+ ? BOUNDSCHECKsafeonly : BOUNDSCHECKon;
+ flag_bounds_check = !global.params.release;
+ }
+
+ if (global.params.release)
+ {
+ if (!global_options_set.x_flag_invariants)
+ global.params.useInvariants = false;
+
+ if (!global_options_set.x_flag_preconditions)
+ global.params.useIn = false;
+
+ if (!global_options_set.x_flag_postconditions)
+ global.params.useOut = false;
+
+ if (!global_options_set.x_flag_assert)
+ global.params.useAssert = false;
+
+ if (!global_options_set.x_flag_switch_errors)
+ global.params.useSwitchError = false;
+ }
+
+ /* Error about use of deprecated features. */
+ if (global.params.useDeprecated == DIAGNOSTICinform
+ && global.params.warnings == DIAGNOSTICerror)
+ global.params.useDeprecated = DIAGNOSTICerror;
+
+ /* Make -fmax-errors visible to frontend's diagnostic machinery. */
+ if (global_options_set.x_flag_max_errors)
+ global.errorLimit = flag_max_errors;
+
+ if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT)
+ flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
+
+ if (global.params.useUnitTests)
+ global.params.useAssert = true;
+
+ global.params.symdebug = write_symbols != NO_DEBUG;
+ global.params.useInline = flag_inline_functions;
+ global.params.showColumns = flag_show_column;
+
+ if (global.params.useInline)
+ global.params.hdrStripPlainFunctions = false;
+
+ global.params.obj = !flag_syntax_only;
+
+ /* Has no effect yet. */
+ global.params.pic = flag_pic != 0;
+
+ if (warn_return_type == -1)
+ warn_return_type = 0;
+
+ return false;
+}
+
+/* Return TRUE if an operand OP of a given TYPE being copied has no data.
+ The middle-end does a similar check with zero sized types. */
+
+static bool
+empty_modify_p (tree type, tree op)
+{
+ tree_code code = TREE_CODE (op);
+ switch (code)
+ {
+ case COMPOUND_EXPR:
+ return empty_modify_p (type, TREE_OPERAND (op, 1));
+
+ case CONSTRUCTOR:
+ /* Non-empty construcors are valid. */
+ if (CONSTRUCTOR_NELTS (op) != 0 || TREE_CLOBBER_P (op))
+ return false;
+ break;
+
+ case CALL_EXPR:
+ /* Leave nrvo alone because it isn't a copy. */
+ if (CALL_EXPR_RETURN_SLOT_OPT (op))
+ return false;
+ break;
+
+ default:
+ /* If the operand doesn't have a simple form. */
+ if (!is_gimple_lvalue (op) && !INDIRECT_REF_P (op))
+ return false;
+ break;
+ }
+
+ return empty_aggregate_p (type);
+}
+
+/* Implements the lang_hooks.gimplify_expr routine for language D.
+ Do gimplification of D specific expression trees in EXPR_P. */
+
+int
+d_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
+ gimple_seq *post_p ATTRIBUTE_UNUSED)
+{
+ tree_code code = TREE_CODE (*expr_p);
+ enum gimplify_status ret = GS_UNHANDLED;
+ tree op0, op1;
+ tree type;
+
+ switch (code)
+ {
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ op0 = TREE_OPERAND (*expr_p, 0);
+ op1 = TREE_OPERAND (*expr_p, 1);
+
+ if (!error_operand_p (op0) && !error_operand_p (op1)
+ && (AGGREGATE_TYPE_P (TREE_TYPE (op0))
+ || AGGREGATE_TYPE_P (TREE_TYPE (op1)))
+ && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0)))
+ {
+ /* If the back end isn't clever enough to know that the lhs and rhs
+ types are the same, add an explicit conversion. */
+ TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR,
+ TREE_TYPE (op0), op1);
+ ret = GS_OK;
+ }
+ else if (empty_modify_p (TREE_TYPE (op0), op1))
+ {
+ /* Remove any copies of empty aggregates. */
+ gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+ is_gimple_lvalue, fb_lvalue);
+
+ if (TREE_SIDE_EFFECTS (op1))
+ gimplify_and_add (op1, pre_p);
+
+ *expr_p = TREE_OPERAND (*expr_p, 0);
+ ret = GS_OK;
+ }
+ break;
+
+ case ADDR_EXPR:
+ op0 = TREE_OPERAND (*expr_p, 0);
+ /* Constructors are not lvalues, so make them one. */
+ if (TREE_CODE (op0) == CONSTRUCTOR)
+ {
+ TREE_OPERAND (*expr_p, 0) = force_target_expr (op0);
+ ret = GS_OK;
+ }
+ break;
+
+ case CALL_EXPR:
+ if (CALL_EXPR_ARGS_ORDERED (*expr_p))
+ {
+ /* Strictly evaluate all arguments from left to right. */
+ int nargs = call_expr_nargs (*expr_p);
+ location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
+
+ /* No need to enforce evaluation order if only one argument. */
+ if (nargs < 2)
+ break;
+
+ /* Or if all arguments are already free of side-effects. */
+ bool has_side_effects = false;
+ for (int i = 0; i < nargs; i++)
+ {
+ if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i)))
+ {
+ has_side_effects = true;
+ break;
+ }
+ }
+
+ if (!has_side_effects)
+ break;
+
+ /* Leave the last argument for gimplify_call_expr. */
+ for (int i = 0; i < nargs - 1; i++)
+ {
+ tree new_arg = CALL_EXPR_ARG (*expr_p, i);
+
+ /* If argument has a side-effect, gimplify_arg will handle it. */
+ if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR)
+ ret = GS_ERROR;
+
+ /* Even if an argument itself doesn't have any side-effects, it
+ might be altered by another argument in the list. */
+ if (new_arg == CALL_EXPR_ARG (*expr_p, i)
+ && !really_constant_p (new_arg))
+ new_arg = get_formal_tmp_var (new_arg, pre_p);
+
+ CALL_EXPR_ARG (*expr_p, i) = new_arg;
+ }
+
+ if (ret != GS_ERROR)
+ ret = GS_OK;
+ }
+ break;
+
+ case UNSIGNED_RSHIFT_EXPR:
+ /* Convert op0 to an unsigned type. */
+ op0 = TREE_OPERAND (*expr_p, 0);
+ op1 = TREE_OPERAND (*expr_p, 1);
+
+ type = d_unsigned_type (TREE_TYPE (op0));
+
+ *expr_p = convert (TREE_TYPE (*expr_p),
+ build2 (RSHIFT_EXPR, type, convert (type, op0), op1));
+ ret = GS_OK;
+ break;
+
+ case FLOAT_MOD_EXPR:
+ gcc_unreachable ();
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/* Add the module M to the list of modules that may declare GCC builtins.
+ These are scanned after first semantic and before codegen passes.
+ See d_maybe_set_builtin() for the implementation. */
+
+void
+d_add_builtin_module (Module *m)
+{
+ builtin_modules.push (m);
+}
+
+/* Record the entrypoint module ENTRY which will be compiled in the current
+ compilation. ROOT is the module scope where this was requested from. */
+
+void
+d_add_entrypoint_module (Module *entry, Module *root)
+{
+ /* We are emitting this straight to object file. */
+ entrypoint_module = entry;
+ entrypoint_root_module = root;
+}
+
+/* Implements the lang_hooks.parse_file routine for language D. */
+
+void
+d_parse_file (void)
+{
+ if (global.params.verbose)
+ {
+ message ("binary %s", global.params.argv0);
+ message ("version %s", global.version);
+
+ if (global.params.versionids)
+ {
+ OutBuffer buf;
+ buf.writestring ("predefs ");
+ for (size_t i = 0; i < global.params.versionids->dim; i++)
+ {
+ const char *s = (*global.params.versionids)[i];
+ buf.writestring (" ");
+ buf.writestring (s);
+ }
+
+ message ("%.*s", (int) buf.offset, (char *) buf.data);
+ }
+ }
+
+ /* Start the main input file, if the debug writer wants it. */
+ if (debug_hooks->start_end_main_source_file)
+ debug_hooks->start_source_file (0, main_input_filename);
+
+ /* Create Module's for all sources we will load. */
+ Modules modules;
+ modules.reserve (num_in_fnames);
+
+ /* In this mode, the first file name is supposed to be a duplicate
+ of one of the input files. */
+ if (d_option.fonly && strcmp (d_option.fonly, main_input_filename) != 0)
+ error ("-fonly= argument is different from first input file name");
+
+ for (size_t i = 0; i < num_in_fnames; i++)
+ {
+ if (strcmp (in_fnames[i], "-") == 0)
+ {
+ /* Handling stdin, generate a unique name for the module. */
+ obstack buffer;
+ gcc_obstack_init (&buffer);
+ int c;
+
+ Module *m = Module::create (in_fnames[i],
+ Identifier::generateId ("__stdin"),
+ global.params.doDocComments,
+ global.params.doHdrGeneration);
+ modules.push (m);
+
+ /* Load the entire contents of stdin into memory. */
+ while ((c = getc (stdin)) != EOF)
+ obstack_1grow (&buffer, c);
+
+ if (!obstack_object_size (&buffer))
+ obstack_1grow (&buffer, '\0');
+
+ /* Overwrite the source file for the module, the one created by
+ Module::create would have a forced a `.d' suffix. */
+ m->srcfile = File::create ("<stdin>");
+ m->srcfile->len = obstack_object_size (&buffer);
+ m->srcfile->buffer = (unsigned char *) obstack_finish (&buffer);
+
+ /* Tell the front-end not to free the buffer after parsing. */
+ m->srcfile->ref = 1;
+ }
+ else
+ {
+ /* Handling a D source file, strip off the path and extension. */
+ const char *basename = FileName::name (in_fnames[i]);
+ const char *name = FileName::removeExt (basename);
+
+ Module *m = Module::create (in_fnames[i], Identifier::idPool (name),
+ global.params.doDocComments,
+ global.params.doHdrGeneration);
+ modules.push (m);
+ FileName::free (name);
+ }
+ }
+
+ /* Read all D source files. */
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+ m->read (Loc ());
+ }
+
+ /* Parse all D source files. */
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+
+ if (global.params.verbose)
+ message ("parse %s", m->toChars ());
+
+ if (!Module::rootModule)
+ Module::rootModule = m;
+
+ m->importedFrom = m;
+ m->parse ();
+ Compiler::loadModule (m);
+
+ if (m->isDocFile)
+ {
+ gendocfile (m);
+ /* Remove M from list of modules. */
+ modules.remove (i);
+ i--;
+ }
+ }
+
+ /* Load the module containing D main. */
+ if (global.params.addMain)
+ {
+ unsigned errors = global.startGagging ();
+ Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
+
+ if (! global.endGagging (errors))
+ {
+ m->importedFrom = m;
+ modules.push (m);
+ }
+ }
+
+ if (global.errors)
+ goto had_errors;
+
+ if (global.params.doHdrGeneration)
+ {
+ /* Generate 'header' import files. Since 'header' import files must be
+ independent of command line switches and what else is imported, they
+ are generated before any semantic analysis. */
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+ if (d_option.fonly && m != Module::rootModule)
+ continue;
+
+ if (global.params.verbose)
+ message ("import %s", m->toChars ());
+
+ genhdrfile (m);
+ }
+ }
+
+ if (global.errors)
+ goto had_errors;
+
+ /* Load all unconditional imports for better symbol resolving. */
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+
+ if (global.params.verbose)
+ message ("importall %s", m->toChars ());
+
+ m->importAll (NULL);
+ }
+
+ if (global.errors)
+ goto had_errors;
+
+ /* Do semantic analysis. */
+ doing_semantic_analysis_p = true;
+
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+
+ if (global.params.verbose)
+ message ("semantic %s", m->toChars ());
+
+ m->semantic (NULL);
+ }
+
+ /* Do deferred semantic analysis. */
+ Module::dprogress = 1;
+ Module::runDeferredSemantic ();
+
+ if (Module::deferred.dim)
+ {
+ for (size_t i = 0; i < Module::deferred.dim; i++)
+ {
+ Dsymbol *sd = Module::deferred[i];
+ error_at (make_location_t (sd->loc),
+ "unable to resolve forward reference in definition");
+ }
+ }
+
+ /* Process all built-in modules or functions now for CTFE. */
+ while (builtin_modules.dim != 0)
+ {
+ Module *m = builtin_modules.pop ();
+ d_maybe_set_builtin (m);
+ }
+
+ /* Do pass 2 semantic analysis. */
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+
+ if (global.params.verbose)
+ message ("semantic2 %s", m->toChars ());
+
+ m->semantic2 (NULL);
+ }
+
+ Module::runDeferredSemantic2 ();
+
+ if (global.errors)
+ goto had_errors;
+
+ /* Do pass 3 semantic analysis. */
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+
+ if (global.params.verbose)
+ message ("semantic3 %s", m->toChars ());
+
+ m->semantic3 (NULL);
+ }
+
+ Module::runDeferredSemantic3 ();
+
+ /* Check again, incase semantic3 pass loaded any more modules. */
+ while (builtin_modules.dim != 0)
+ {
+ Module *m = builtin_modules.pop ();
+ d_maybe_set_builtin (m);
+ }
+
+ /* Do not attempt to generate output files if errors or warnings occurred. */
+ if (global.errors || global.warnings)
+ goto had_errors;
+
+ /* Generate output files. */
+ doing_semantic_analysis_p = false;
+
+ if (Module::rootModule)
+ {
+ /* Declare the name of the root module as the first global name in order
+ to make the middle-end fully deterministic. */
+ OutBuffer buf;
+ mangleToBuffer (Module::rootModule, &buf);
+ first_global_object_name = buf.extractString ();
+ }
+
+ /* Make dependencies. */
+ if (d_option.deps)
+ {
+ OutBuffer buf;
+
+ for (size_t i = 0; i < modules.dim; i++)
+ deps_write (modules[i], &buf);
+
+ /* -MF <arg> overrides -M[M]D. */
+ if (d_option.deps_filename_user)
+ d_option.deps_filename = d_option.deps_filename_user;
+
+ if (d_option.deps_filename)
+ {
+ File *fdeps = File::create (d_option.deps_filename);
+ fdeps->setbuffer ((void *) buf.data, buf.offset);
+ fdeps->ref = 1;
+ writeFile (Loc (), fdeps);
+ }
+ else
+ message ("%.*s", (int) buf.offset, (char *) buf.data);
+ }
+
+ /* Generate JSON files. */
+ if (global.params.doJsonGeneration)
+ {
+ OutBuffer buf;
+ json_generate (&buf, &modules);
+
+ const char *name = global.params.jsonfilename;
+
+ if (name && (name[0] != '-' || name[1] != '\0'))
+ {
+ const char *nameext = FileName::defaultExt (name, global.json_ext);
+ File *fjson = File::create (nameext);
+ fjson->setbuffer ((void *) buf.data, buf.offset);
+ fjson->ref = 1;
+ writeFile (Loc (), fjson);
+ }
+ else
+ message ("%.*s", (int) buf.offset, (char *) buf.data);
+ }
+
+ /* Generate Ddoc files. */
+ if (global.params.doDocComments && !global.errors && !errorcount)
+ {
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+ gendocfile (m);
+ }
+ }
+
+ /* Handle -fdump-d-original. */
+ if (global.params.vcg_ast)
+ {
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+ OutBuffer buf;
+ buf.doindent = 1;
+
+ moduleToBuffer (&buf, m);
+ message ("%.*s", (int) buf.offset, (char *) buf.data);
+ }
+ }
+
+ for (size_t i = 0; i < modules.dim; i++)
+ {
+ Module *m = modules[i];
+ if (d_option.fonly && m != Module::rootModule)
+ continue;
+
+ if (global.params.verbose)
+ message ("code %s", m->toChars ());
+
+ if (!flag_syntax_only)
+ {
+ if ((entrypoint_module != NULL) && (m == entrypoint_root_module))
+ build_decl_tree (entrypoint_module);
+
+ build_decl_tree (m);
+ }
+ }
+
+ /* And end the main input file, if the debug writer wants it. */
+ if (debug_hooks->start_end_main_source_file)
+ debug_hooks->end_source_file (0);
+
+ had_errors:
+ /* Add the D frontend error count to the GCC error count to correctly
+ exit with an error status. */
+ errorcount += (global.errors + global.warnings);
+
+ /* Write out globals. */
+ d_finish_compilation (vec_safe_address (global_declarations),
+ vec_safe_length (global_declarations));
+}
+
+/* Implements the lang_hooks.types.type_for_mode routine for language D. */
+
+static tree
+d_type_for_mode (machine_mode mode, int unsignedp)
+{
+ if (mode == QImode)
+ return unsignedp ? d_ubyte_type : d_byte_type;
+
+ if (mode == HImode)
+ return unsignedp ? d_ushort_type : d_short_type;
+
+ if (mode == SImode)
+ return unsignedp ? d_uint_type : d_int_type;
+
+ if (mode == DImode)
+ return unsignedp ? d_ulong_type : d_long_type;
+
+ if (mode == TYPE_MODE (d_cent_type))
+ return unsignedp ? d_ucent_type : d_cent_type;
+
+ if (mode == TYPE_MODE (float_type_node))
+ return float_type_node;
+
+ if (mode == TYPE_MODE (double_type_node))
+ return double_type_node;
+
+ if (mode == TYPE_MODE (long_double_type_node))
+ return long_double_type_node;
+
+ if (mode == TYPE_MODE (build_pointer_type (char8_type_node)))
+ return build_pointer_type (char8_type_node);
+
+ if (mode == TYPE_MODE (build_pointer_type (d_int_type)))
+ return build_pointer_type (d_int_type);
+
+ if (COMPLEX_MODE_P (mode))
+ {
+ machine_mode inner_mode;
+ tree inner_type;
+
+ if (mode == TYPE_MODE (complex_float_type_node))
+ return complex_float_type_node;
+ if (mode == TYPE_MODE (complex_double_type_node))
+ return complex_double_type_node;
+ if (mode == TYPE_MODE (complex_long_double_type_node))
+ return complex_long_double_type_node;
+
+ inner_mode = (machine_mode) GET_MODE_INNER (mode);
+ inner_type = d_type_for_mode (inner_mode, unsignedp);
+ if (inner_type != NULL_TREE)
+ return build_complex_type (inner_type);
+ }
+ else if (VECTOR_MODE_P (mode))
+ {
+ machine_mode inner_mode = (machine_mode) GET_MODE_INNER (mode);
+ tree inner_type = d_type_for_mode (inner_mode, unsignedp);
+ if (inner_type != NULL_TREE)
+ return build_vector_type_for_mode (inner_type, mode);
+ }
+
+ return 0;
+}
+
+/* Implements the lang_hooks.types.type_for_size routine for language D. */
+
+static tree
+d_type_for_size (unsigned bits, int unsignedp)
+{
+ if (bits <= TYPE_PRECISION (d_byte_type))
+ return unsignedp ? d_ubyte_type : d_byte_type;
+
+ if (bits <= TYPE_PRECISION (d_short_type))
+ return unsignedp ? d_ushort_type : d_short_type;
+
+ if (bits <= TYPE_PRECISION (d_int_type))
+ return unsignedp ? d_uint_type : d_int_type;
+
+ if (bits <= TYPE_PRECISION (d_long_type))
+ return unsignedp ? d_ulong_type : d_long_type;
+
+ if (bits <= TYPE_PRECISION (d_cent_type))
+ return unsignedp ? d_ucent_type : d_cent_type;
+
+ return 0;
+}
+
+/* Return the signed or unsigned version of TYPE, an integral type, the
+ signedness being specified by UNSIGNEDP. */
+
+static tree
+d_signed_or_unsigned_type (int unsignedp, tree type)
+{
+ if (TYPE_UNSIGNED (type) == (unsigned) unsignedp)
+ return type;
+
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (d_cent_type))
+ return unsignedp ? d_ucent_type : d_cent_type;
+
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (d_long_type))
+ return unsignedp ? d_ulong_type : d_long_type;
+
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (d_int_type))
+ return unsignedp ? d_uint_type : d_int_type;
+
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (d_short_type))
+ return unsignedp ? d_ushort_type : d_short_type;
+
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (d_byte_type))
+ return unsignedp ? d_ubyte_type : d_byte_type;
+
+ return signed_or_unsigned_type_for (unsignedp, type);
+}
+
+/* Return the unsigned version of TYPE, an integral type. */
+
+tree
+d_unsigned_type (tree type)
+{
+ return d_signed_or_unsigned_type (1, type);
+}
+
+/* Return the signed version of TYPE, an integral type. */
+
+tree
+d_signed_type (tree type)
+{
+ return d_signed_or_unsigned_type (0, type);
+}
+
+/* Implements the lang_hooks.types.type_promotes_to routine for language D.
+ All promotions for variable arguments are handled by the D frontend. */
+
+static tree
+d_type_promotes_to (tree type)
+{
+ return type;
+}
+
+/* Implements the lang_hooks.decls.global_bindings_p routine for language D.
+ Return true if we are in the global binding level. */
+
+static bool
+d_global_bindings_p (void)
+{
+ return (current_binding_level == global_binding_level);
+}
+
+/* Return global_context, but create it first if need be. */
+
+static tree
+get_global_context (void)
+{
+ if (!global_context)
+ {
+ global_context = build_translation_unit_decl (NULL_TREE);
+ debug_hooks->register_main_translation_unit (global_context);
+ }
+
+ return global_context;
+}
+
+/* Implements the lang_hooks.decls.pushdecl routine for language D.
+ Record DECL as belonging to the current lexical scope. */
+
+tree
+d_pushdecl (tree decl)
+{
+ /* Set the context of the decl. If current_function_decl did not help in
+ determining the context, use global scope. */
+ if (!DECL_CONTEXT (decl))
+ {
+ if (current_function_decl)
+ DECL_CONTEXT (decl) = current_function_decl;
+ else
+ DECL_CONTEXT (decl) = get_global_context ();
+ }
+
+ /* Put decls on list in reverse order. */
+ if (TREE_STATIC (decl) || d_global_bindings_p ())
+ vec_safe_push (global_declarations, decl);
+ else
+ {
+ TREE_CHAIN (decl) = current_binding_level->names;
+ current_binding_level->names = decl;
+ }
+
+ return decl;
+}
+
+/* Implements the lang_hooks.decls.getdecls routine for language D.
+ Return the list of declarations of the current level. */
+
+static tree
+d_getdecls (void)
+{
+ if (current_binding_level)
+ return current_binding_level->names;
+
+ return NULL_TREE;
+}
+
+
+/* Implements the lang_hooks.get_alias_set routine for language D.
+ Get the alias set corresponding to type or expression T.
+ Return -1 if we don't do anything special. */
+
+static alias_set_type
+d_get_alias_set (tree)
+{
+ /* For now in D, assume everything aliases everything else, until we define
+ some solid rules backed by a specification. There are also some parts
+ of code generation routines that don't adhere to C alias rules, such as
+ build_vconvert. In any case, a lot of user code already assumes there
+ is no strict aliasing and will break if we were to change that. */
+ return 0;
+}
+
+/* Implements the lang_hooks.types_compatible_p routine for language D.
+ Compares two types for equivalence in the D programming language.
+ This routine should only return 1 if it is sure, even though the frontend
+ should have already ensured that all types are compatible before handing
+ over the parsed ASTs to the code generator. */
+
+static int
+d_types_compatible_p (tree x, tree y)
+{
+ Type *tx = TYPE_LANG_FRONTEND (x);
+ Type *ty = TYPE_LANG_FRONTEND (y);
+
+ /* Try validating the types in the frontend. */
+ if (tx != NULL && ty != NULL)
+ {
+ /* Types are equivalent. */
+ if (same_type_p (tx, ty))
+ return true;
+
+ /* Type system allows implicit conversion between. */
+ if (tx->implicitConvTo (ty) || ty->implicitConvTo (tx))
+ return true;
+ }
+
+ /* Fallback on using type flags for comparison. E.g: all dynamic arrays
+ are distinct types in D, but are VIEW_CONVERT compatible. */
+ if (TREE_CODE (x) == RECORD_TYPE && TREE_CODE (y) == RECORD_TYPE)
+ {
+ if (TYPE_DYNAMIC_ARRAY (x) && TYPE_DYNAMIC_ARRAY (y))
+ return true;
+
+ if (TYPE_DELEGATE (x) && TYPE_DELEGATE (y))
+ return true;
+
+ if (TYPE_ASSOCIATIVE_ARRAY (x) && TYPE_ASSOCIATIVE_ARRAY (y))
+ return true;
+ }
+
+ return false;
+}
+
+/* Implements the lang_hooks.finish_incomplete_decl routine for language D. */
+
+static void
+d_finish_incomplete_decl (tree decl)
+{
+ if (VAR_P (decl))
+ {
+ /* D allows zero-length declarations. Such a declaration ends up with
+ DECL_SIZE (t) == NULL_TREE which is what the back-end function
+ assembler_variable checks. This could change in later versions, or
+ maybe all of these variables should be aliased to one symbol. */
+ if (DECL_SIZE (decl) == 0)
+ {
+ DECL_SIZE (decl) = bitsize_zero_node;
+ DECL_SIZE_UNIT (decl) = size_zero_node;
+ }
+ }
+}
+
+/* Implements the lang_hooks.types.classify_record routine for language D.
+ Return the true debug type for TYPE. */
+
+static classify_record
+d_classify_record (tree type)
+{
+ Type *t = TYPE_LANG_FRONTEND (type);
+
+ if (t && t->ty == Tclass)
+ {
+ TypeClass *tc = (TypeClass *) t;
+
+ /* extern(C++) interfaces get emitted as classes. */
+ if (tc->sym->isInterfaceDeclaration ()
+ && !tc->sym->isCPPinterface ())
+ return RECORD_IS_INTERFACE;
+
+ return RECORD_IS_CLASS;
+ }
+
+ return RECORD_IS_STRUCT;
+}
+
+/* Implements the lang_hooks.tree_size routine for language D.
+ Determine the size of our tcc_constant or tcc_exceptional nodes. */
+
+static size_t
+d_tree_size (tree_code code)
+{
+ switch (code)
+ {
+ case FUNCFRAME_INFO:
+ return sizeof (tree_frame_info);
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Implements the lang_hooks.print_xnode routine for language D. */
+
+static void
+d_print_xnode (FILE *file, tree node, int indent)
+{
+ switch (TREE_CODE (node))
+ {
+ case FUNCFRAME_INFO:
+ print_node (file, "frame_type", FRAMEINFO_TYPE (node), indent + 4);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Return which tree structure is used by NODE, or TS_D_GENERIC if NODE
+ is one of the language-independent trees. */
+
+d_tree_node_structure_enum
+d_tree_node_structure (lang_tree_node *t)
+{
+ switch (TREE_CODE (&t->generic))
+ {
+ case IDENTIFIER_NODE:
+ return TS_D_IDENTIFIER;
+
+ case FUNCFRAME_INFO:
+ return TS_D_FRAMEINFO;
+
+ default:
+ return TS_D_GENERIC;
+ }
+}
+
+/* Allocate and return a lang specific structure for the frontend type. */
+
+struct lang_type *
+build_lang_type (Type *t)
+{
+ struct lang_type *lt = ggc_cleared_alloc<struct lang_type> ();
+ lt->type = t;
+ return lt;
+}
+
+/* Allocate and return a lang specific structure for the frontend decl. */
+
+struct lang_decl *
+build_lang_decl (Declaration *d)
+{
+ /* For compiler generated run-time typeinfo, a lang_decl is allocated even if
+ there's no associated frontend symbol to refer to (yet). If the symbol
+ appears later in the compilation, then the slot will be re-used. */
+ if (d == NULL)
+ return ggc_cleared_alloc<struct lang_decl> ();
+
+ struct lang_decl *ld = (d->csym) ? DECL_LANG_SPECIFIC (d->csym) : NULL;
+ if (ld == NULL)
+ ld = ggc_cleared_alloc<struct lang_decl> ();
+
+ if (ld->decl == NULL)
+ ld->decl = d;
+
+ return ld;
+}
+
+/* Implements the lang_hooks.dup_lang_specific_decl routine for language D.
+ Replace the DECL_LANG_SPECIFIC field of NODE with a copy. */
+
+static void
+d_dup_lang_specific_decl (tree node)
+{
+ if (! DECL_LANG_SPECIFIC (node))
+ return;
+
+ struct lang_decl *ld = ggc_alloc<struct lang_decl> ();
+ memcpy (ld, DECL_LANG_SPECIFIC (node), sizeof (struct lang_decl));
+ DECL_LANG_SPECIFIC (node) = ld;
+}
+
+/* This preserves trees we create from the garbage collector. */
+
+static GTY(()) tree d_keep_list = NULL_TREE;
+
+void
+d_keep (tree t)
+{
+ d_keep_list = tree_cons (NULL_TREE, t, d_keep_list);
+}
+
+/* Implements the lang_hooks.eh_personality routine for language D.
+ Return the GDC personality function decl. */
+
+static GTY(()) tree d_eh_personality_decl;
+
+static tree
+d_eh_personality (void)
+{
+ if (!d_eh_personality_decl)
+ d_eh_personality_decl = build_personality_function ("gdc");
+
+ return d_eh_personality_decl;
+}
+
+/* Implements the lang_hooks.eh_runtime_type routine for language D. */
+
+static tree
+d_build_eh_runtime_type (tree type)
+{
+ Type *t = TYPE_LANG_FRONTEND (type);
+
+ if (t != NULL)
+ t = t->toBasetype ();
+
+ gcc_assert (t != NULL && t->ty == Tclass);
+ ClassDeclaration *cd = ((TypeClass *) t)->sym;
+ tree decl;
+
+ if (cd->isCPPclass ())
+ decl = get_cpp_typeinfo_decl (cd);
+ else
+ decl = get_classinfo_decl (cd);
+
+ return convert (ptr_type_node, build_address (decl));
+}
+
+/* Definitions for our language-specific hooks. */
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_INIT_TS
+#undef LANG_HOOKS_INIT_OPTIONS
+#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_HANDLE_OPTION
+#undef LANG_HOOKS_POST_OPTIONS
+#undef LANG_HOOKS_PARSE_FILE
+#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
+#undef LANG_HOOKS_ATTRIBUTE_TABLE
+#undef LANG_HOOKS_GET_ALIAS_SET
+#undef LANG_HOOKS_TYPES_COMPATIBLE_P
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_REGISTER_BUILTIN_TYPE
+#undef LANG_HOOKS_FINISH_INCOMPLETE_DECL
+#undef LANG_HOOKS_GIMPLIFY_EXPR
+#undef LANG_HOOKS_CLASSIFY_RECORD
+#undef LANG_HOOKS_TREE_SIZE
+#undef LANG_HOOKS_PRINT_XNODE
+#undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL
+#undef LANG_HOOKS_EH_PERSONALITY
+#undef LANG_HOOKS_EH_RUNTIME_TYPE
+#undef LANG_HOOKS_PUSHDECL
+#undef LANG_HOOKS_GETDECLS
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#undef LANG_HOOKS_TYPE_PROMOTES_TO
+
+#define LANG_HOOKS_NAME "GNU D"
+#define LANG_HOOKS_INIT d_init
+#define LANG_HOOKS_INIT_TS d_init_ts
+#define LANG_HOOKS_INIT_OPTIONS d_init_options
+#define LANG_HOOKS_INIT_OPTIONS_STRUCT d_init_options_struct
+#define LANG_HOOKS_OPTION_LANG_MASK d_option_lang_mask
+#define LANG_HOOKS_HANDLE_OPTION d_handle_option
+#define LANG_HOOKS_POST_OPTIONS d_post_options
+#define LANG_HOOKS_PARSE_FILE d_parse_file
+#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE d_langhook_common_attribute_table
+#define LANG_HOOKS_ATTRIBUTE_TABLE d_langhook_attribute_table
+#define LANG_HOOKS_GET_ALIAS_SET d_get_alias_set
+#define LANG_HOOKS_TYPES_COMPATIBLE_P d_types_compatible_p
+#define LANG_HOOKS_BUILTIN_FUNCTION d_builtin_function
+#define LANG_HOOKS_REGISTER_BUILTIN_TYPE d_register_builtin_type
+#define LANG_HOOKS_FINISH_INCOMPLETE_DECL d_finish_incomplete_decl
+#define LANG_HOOKS_GIMPLIFY_EXPR d_gimplify_expr
+#define LANG_HOOKS_CLASSIFY_RECORD d_classify_record
+#define LANG_HOOKS_TREE_SIZE d_tree_size
+#define LANG_HOOKS_PRINT_XNODE d_print_xnode
+#define LANG_HOOKS_DUP_LANG_SPECIFIC_DECL d_dup_lang_specific_decl
+#define LANG_HOOKS_EH_PERSONALITY d_eh_personality
+#define LANG_HOOKS_EH_RUNTIME_TYPE d_build_eh_runtime_type
+#define LANG_HOOKS_PUSHDECL d_pushdecl
+#define LANG_HOOKS_GETDECLS d_getdecls
+#define LANG_HOOKS_GLOBAL_BINDINGS_P d_global_bindings_p
+#define LANG_HOOKS_TYPE_FOR_MODE d_type_for_mode
+#define LANG_HOOKS_TYPE_FOR_SIZE d_type_for_size
+#define LANG_HOOKS_TYPE_PROMOTES_TO d_type_promotes_to
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-d-d-lang.h"
+#include "gtype-d.h"
diff --git a/gcc/d/d-longdouble.cc b/gcc/d/d-longdouble.cc
new file mode 100644
index 0000000..fdea91f
--- /dev/null
+++ b/gcc/d/d-longdouble.cc
@@ -0,0 +1,204 @@
+/* d-longdouble.cc -- Software floating-point emulation for the frontend.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "longdouble.h"
+
+
+/* Constant real values 0, 1, -1 and 0.5. */
+real_t CTFloat::zero;
+real_t CTFloat::one;
+real_t CTFloat::minusone;
+real_t CTFloat::half;
+
+/* Truncate longdouble to the highest precision supported by target. */
+
+longdouble
+longdouble::normalize (void)
+{
+ const machine_mode mode = TYPE_MODE (long_double_type_node);
+ real_convert (&this->rv (), mode, &this->rv ());
+ return *this;
+}
+
+/* Assign a real_value to a longdouble type. */
+
+void
+longdouble::set (real_value& d)
+{
+ real_convert (&this->rv (), TYPE_MODE (long_double_type_node), &d);
+}
+
+/* Conversion routines between longdouble and integer types. */
+
+void
+longdouble::set (int32_t d)
+{
+ real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, SIGNED);
+}
+
+void
+longdouble::set (int64_t d)
+{
+ real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d,
+ SIGNED);
+}
+
+int64_t
+longdouble::to_int (void) const
+{
+ bool overflow;
+ wide_int wi = real_to_integer (&this->rv (), &overflow, 64);
+ return wi.to_shwi ();
+}
+
+/* Unsigned variants of the same conversion routines. */
+
+void
+longdouble::set (uint32_t d)
+{
+ real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, UNSIGNED);
+}
+
+void
+longdouble::set (uint64_t d)
+{
+ real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d,
+ UNSIGNED);
+}
+
+uint64_t
+longdouble::to_uint (void) const
+{
+ bool overflow;
+ wide_int wi = real_to_integer (&this->rv (), &overflow, 64);
+ return wi.to_uhwi ();
+}
+
+/* For conversion between boolean, only need to check if is zero. */
+
+void
+longdouble::set (bool d)
+{
+ this->rv () = (d == false) ? dconst0 : dconst1;
+}
+
+bool
+longdouble::to_bool (void) const
+{
+ return this->rv ().cl != rvc_zero;
+}
+
+/* Overload numeric operators for longdouble types. */
+
+longdouble
+longdouble::add (const longdouble& r) const
+{
+ longdouble x;
+ real_arithmetic (&x.rv (), PLUS_EXPR, &this->rv (), &r.rv ());
+ return x.normalize ();
+}
+
+longdouble
+longdouble::sub (const longdouble& r) const
+{
+ longdouble x;
+ real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &r.rv ());
+ return x.normalize ();
+}
+
+longdouble
+longdouble::mul (const longdouble& r) const
+{
+ longdouble x;
+ real_arithmetic (&x.rv (), MULT_EXPR, &this->rv (), &r.rv ());
+ return x.normalize ();
+}
+
+longdouble
+longdouble::div (const longdouble& r) const
+{
+ longdouble x;
+ real_arithmetic (&x.rv (), RDIV_EXPR, &this->rv (), &r.rv ());
+ return x.normalize ();
+}
+
+longdouble
+longdouble::mod (const longdouble& r) const
+{
+ longdouble x;
+ real_value q;
+
+ if (r.rv ().cl == rvc_zero || REAL_VALUE_ISINF (this->rv ()))
+ {
+ real_nan (&x.rv (), "", 1, TYPE_MODE (long_double_type_node));
+ return x;
+ }
+
+ if (this->rv ().cl == rvc_zero)
+ return *this;
+
+ if (REAL_VALUE_ISINF (r.rv ()))
+ return *this;
+
+ /* Need to check for NaN? */
+ real_arithmetic (&q, RDIV_EXPR, &this->rv (), &r.rv ());
+ real_arithmetic (&q, FIX_TRUNC_EXPR, &q, NULL);
+ real_arithmetic (&q, MULT_EXPR, &q, &r.rv ());
+ real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &q);
+
+ return x.normalize ();
+}
+
+longdouble
+longdouble::neg (void) const
+{
+ longdouble x;
+ real_arithmetic (&x.rv (), NEGATE_EXPR, &this->rv (), NULL);
+ return x.normalize ();
+}
+
+/* Overload equality operators for longdouble types. */
+
+int
+longdouble::cmp (const longdouble& r) const
+{
+ if (real_compare (LT_EXPR, &this->rv (), &r.rv ()))
+ return -1;
+
+ if (real_compare (GT_EXPR, &this->rv (), &r.rv ()))
+ return 1;
+
+ return 0;
+}
+
+int
+longdouble::equals (const longdouble& r) const
+{
+ return real_compare (EQ_EXPR, &this->rv (), &r.rv ());
+}
diff --git a/gcc/d/d-spec.cc b/gcc/d/d-spec.cc
new file mode 100644
index 0000000..d0b7844
--- /dev/null
+++ b/gcc/d/d-spec.cc
@@ -0,0 +1,503 @@
+/* d-spec.c -- Specific flags and argument handling of the D front end.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opt-suggestions.h"
+#include "gcc.h"
+#include "tm.h"
+#include "opts.h"
+
+/* This bit is set if the arguments is a D source file. */
+#define DSOURCE (1<<1)
+/* This bit is set if they did `-lstdc++'. */
+#define WITHLIBCXX (1<<2)
+/* Skip this option. */
+#define SKIPOPT (1<<3)
+
+#ifndef LIBSTDCXX
+#define LIBSTDCXX "stdc++"
+#endif
+#ifndef LIBSTDCXX_PROFILE
+#define LIBSTDCXX_PROFILE LIBSTDCXX
+#endif
+
+#ifndef LIBPHOBOS
+#define LIBPHOBOS "gphobos"
+#endif
+#ifndef LIBPHOBOS_PROFILE
+#define LIBPHOBOS_PROFILE LIBPHOBOS
+#endif
+
+#ifndef LIBDRUNTIME
+#define LIBDRUNTIME "gdruntime"
+#endif
+#ifndef LIBDRUNTIME_PROFILE
+#define LIBDRUNTIME_PROFILE LIBDRUNTIME
+#endif
+
+/* What do with libgphobos. */
+enum phobos_action
+{
+ /* libgphobos should not be linked in. */
+ PHOBOS_NOLINK = -1,
+ /* libgphobos should be linked in if it is needed. */
+ PHOBOS_DEFAULT = 0,
+ /* libgphobos is needed and should be linked in. */
+ PHOBOS_LINK,
+ /* libgphobos is needed and should be linked statically. */
+ PHOBOS_STATIC,
+ /* libgphobos is needed and should be linked dynamically. */
+ PHOBOS_DYNAMIC,
+};
+
+static phobos_action phobos_library = PHOBOS_DEFAULT;
+
+/* If true, use the standard D runtime library when linking with
+ standard libraries. */
+static bool need_phobos = true;
+
+void
+lang_specific_driver (cl_decoded_option **in_decoded_options,
+ unsigned int *in_decoded_options_count,
+ int *in_added_libraries)
+{
+ unsigned int i, j;
+
+ /* If nonzero, the user gave us the `-p' or `-pg' flag. */
+ int saw_profile_flag = 0;
+
+ /* If true, the user gave `-g'. Used by -debuglib. */
+ bool saw_debug_flag = false;
+
+ /* The new argument list will be contained in this. */
+ cl_decoded_option *new_decoded_options;
+
+ /* "-lstdc++" if it appears on the command line. */
+ const cl_decoded_option *saw_libcxx = 0;
+
+ /* Whether we need the C++ STD library. */
+ bool need_stdcxx = false;
+
+ /* True if we saw -static. */
+ bool static_link = false;
+
+ /* True if we should add -shared-libgcc to the command-line. */
+ bool shared_libgcc = true;
+
+ /* What default library to use instead of phobos. */
+ const char *defaultlib = NULL;
+
+ /* What debug library to use instead of phobos. */
+ const char *debuglib = NULL;
+
+ /* The total number of arguments with the new stuff. */
+ unsigned int num_args = 1;
+
+ /* "-fonly" if it appears on the command line. */
+ const char *only_source_option = 0;
+
+ /* Whether the -o option was used. */
+ bool saw_opt_o = false;
+
+ /* Whether the -c option was used. Also used for -E, -fsyntax-only,
+ in general anything which implies only compilation and not linking. */
+ bool saw_opt_c = false;
+
+ /* Whether the -S option was used. */
+ bool saw_opt_S = false;
+
+ /* The first input file with an extension of .d. */
+ const char *first_d_file = NULL;
+
+ /* The total number of arguments with the new stuff. */
+ unsigned int argc = *in_decoded_options_count;
+
+ /* The argument list. */
+ cl_decoded_option *decoded_options = *in_decoded_options;
+
+ /* The number of libraries added in. */
+ int added_libraries = *in_added_libraries;
+
+ /* An array used to flag each argument that needs a bit set for
+ DSOURCE, MATHLIB, WITHTHREAD, WITHLIBC or WITHLIBCXX. */
+ int *args = XCNEWVEC (int, argc);
+
+ for (i = 1; i < argc; i++)
+ {
+ const char *arg = decoded_options[i].arg;
+
+ switch (decoded_options[i].opt_index)
+ {
+ case OPT_nostdlib:
+ case OPT_nodefaultlibs:
+ phobos_library = PHOBOS_NOLINK;
+ break;
+
+ case OPT_nophoboslib:
+ need_phobos = false;
+ args[i] |= SKIPOPT;
+ break;
+
+ case OPT_defaultlib_:
+ if (defaultlib != NULL)
+ free (CONST_CAST (char *, defaultlib));
+ if (arg != NULL)
+ {
+ need_phobos = false;
+ args[i] |= SKIPOPT;
+ defaultlib = XNEWVEC (char, strlen (arg));
+ strcpy (CONST_CAST (char *, defaultlib), arg);
+ }
+ break;
+
+ case OPT_debuglib_:
+ if (debuglib != NULL)
+ free (CONST_CAST (char *, debuglib));
+ if (arg != NULL)
+ {
+ need_phobos = false;
+ args[i] |= SKIPOPT;
+ debuglib = XNEWVEC (char, strlen (arg));
+ strcpy (CONST_CAST (char *, debuglib), arg);
+ }
+ break;
+
+ case OPT_l:
+ if ((strcmp (arg, LIBSTDCXX) == 0)
+ || (strcmp (arg, LIBSTDCXX_PROFILE) == 0))
+ {
+ args[i] |= WITHLIBCXX;
+ need_stdcxx = false;
+ }
+ /* Unrecognized libraries (e.g. -ltango) may require libphobos. */
+ else if (phobos_library == PHOBOS_DEFAULT)
+ phobos_library = PHOBOS_LINK;
+ break;
+
+ case OPT_pg:
+ case OPT_p:
+ saw_profile_flag++;
+ break;
+
+ case OPT_g:
+ saw_debug_flag = true;
+ break;
+
+ case OPT_v:
+ /* If they only gave us `-v', don't try to link in libphobos. */
+ if (argc == 2)
+ phobos_library = PHOBOS_NOLINK;
+ break;
+
+ case OPT_x:
+ if (phobos_library == PHOBOS_DEFAULT && (strcmp (arg, "d") == 0))
+ phobos_library = PHOBOS_LINK;
+ break;
+
+ case OPT_Xlinker:
+ case OPT_Wl_:
+ /* Arguments that go directly to the linker might be .o files
+ or something, and so might cause libphobos to be needed. */
+ if (phobos_library == PHOBOS_DEFAULT)
+ phobos_library = PHOBOS_LINK;
+ break;
+
+ case OPT_c:
+ case OPT_E:
+ case OPT_M:
+ case OPT_MM:
+ case OPT_fsyntax_only:
+ /* Don't specify libaries if we won't link, since that would
+ cause a warning. */
+ saw_opt_c = true;
+ phobos_library = PHOBOS_NOLINK;
+ break;
+
+ case OPT_S:
+ saw_opt_S = true;
+ phobos_library = PHOBOS_NOLINK;
+ break;
+
+ case OPT_o:
+ saw_opt_o = true;
+ break;
+
+ case OPT_static:
+ static_link = true;
+ break;
+
+ case OPT_static_libgcc:
+ shared_libgcc = false;
+ break;
+
+ case OPT_static_libphobos:
+ if (phobos_library != PHOBOS_NOLINK)
+ phobos_library = PHOBOS_STATIC;
+ args[i] |= SKIPOPT;
+ break;
+
+ case OPT_shared_libphobos:
+ if (phobos_library != PHOBOS_NOLINK)
+ phobos_library = PHOBOS_DYNAMIC;
+ args[i] |= SKIPOPT;
+ break;
+
+ case OPT_fonly_:
+ args[i] |= SKIPOPT;
+ only_source_option = decoded_options[i].orig_option_with_args_text;
+
+ if (arg != NULL)
+ {
+ const char *suffix = strrchr (only_source_option, '.');
+ if (suffix == NULL || strcmp (suffix, ".d") != 0)
+ only_source_option = concat (only_source_option, ".d", NULL);
+ }
+ break;
+
+ case OPT_SPECIAL_input_file:
+ {
+ if (arg[0] == '\0' || arg[1] == '\0')
+ continue;
+
+ if (phobos_library == PHOBOS_DEFAULT)
+ phobos_library = PHOBOS_LINK;
+
+ /* Record that this is a D source file. */
+ const char *suffix = strrchr (arg, '.');
+ if (suffix != NULL && strcmp (suffix, ".d") == 0)
+ {
+ if (first_d_file == NULL)
+ first_d_file = arg;
+
+ args[i] |= DSOURCE;
+ }
+
+ /* If this is a C++ source file, we'll need to link
+ against libstdc++ library. */
+ if (suffix != NULL
+ && (strcmp (suffix, ".cc") == 0
+ || (strcmp (suffix, ".cpp") == 0)
+ || (strcmp (suffix, ".c++") == 0)))
+ need_stdcxx = true;
+
+ break;
+ }
+ }
+ }
+
+ /* There's no point adding -shared-libgcc if we don't have a shared
+ libgcc. */
+#ifndef ENABLE_SHARED_LIBGCC
+ shared_libgcc = false;
+#endif
+
+ /* Make sure to have room for the trailing NULL argument.
+ - needstdcxx might add `-lstdcxx'
+ - libphobos adds `-Bstatic -lphobos -ldruntime -Bdynamic'
+ - only_source adds 1 more arg, also maybe add `-o'. */
+ num_args = argc + need_stdcxx + shared_libgcc + need_phobos * 4 + 2;
+ new_decoded_options = XNEWVEC (cl_decoded_option, num_args);
+
+ i = 0;
+ j = 0;
+
+ /* Copy the 0th argument, i.e., the name of the program itself. */
+ new_decoded_options[j++] = decoded_options[i++];
+
+ /* NOTE: We start at 1 now, not 0. */
+ while (i < argc)
+ {
+ if (args[i] & SKIPOPT)
+ {
+ ++i;
+ continue;
+ }
+
+ new_decoded_options[j] = decoded_options[i];
+
+ if (!saw_libcxx && (args[i] & WITHLIBCXX))
+ {
+ --j;
+ saw_libcxx = &decoded_options[i];
+ }
+
+ if (args[i] & DSOURCE)
+ {
+ if (only_source_option)
+ --j;
+ }
+
+ i++;
+ j++;
+ }
+
+ if (only_source_option)
+ {
+ const char *only_source_arg = only_source_option + 7;
+ generate_option (OPT_fonly_, only_source_arg, 1, CL_DRIVER,
+ &new_decoded_options[j]);
+ j++;
+
+ generate_option_input_file (only_source_arg,
+ &new_decoded_options[j++]);
+ }
+
+ /* If no reason to link against libphobos library, then don't add it. */
+ if (phobos_library == PHOBOS_DEFAULT)
+ phobos_library = PHOBOS_NOLINK;
+
+ /* If we didn't see a -o option, add one. This is because we need the
+ driver to pass all .d files to the D compiler. Without a -o option
+ the driver will invoke the compiler separately for each input file. */
+ if (first_d_file != NULL && !saw_opt_o)
+ {
+ if (saw_opt_c || saw_opt_S)
+ {
+ const char *base = lbasename (first_d_file);
+ int baselen = strlen (base) - 2;
+ char *out = XNEWVEC (char, baselen + 3);
+
+ memcpy (out, base, baselen);
+ /* The driver will convert .o to some other suffix if appropriate. */
+ out[baselen] = '.';
+ if (saw_opt_S)
+ out[baselen + 1] = 's';
+ else
+ out[baselen + 1] = 'o';
+ out[baselen + 2] = '\0';
+ generate_option (OPT_o, out, 1, CL_DRIVER,
+ &new_decoded_options[j]);
+ }
+ else
+ {
+ /* Wouldn't be necessary if the driver converted .out also. */
+ const char *out = NULL;
+
+#ifdef TARGET_EXECUTABLE_SUFFIX
+ if (TARGET_EXECUTABLE_SUFFIX[0] != 0)
+ out = "a" TARGET_EXECUTABLE_SUFFIX;
+#endif
+ if (out == NULL)
+ out = "a.out";
+
+ generate_option (OPT_o, out, 1, CL_DRIVER,
+ &new_decoded_options[j]);
+ }
+ j++;
+ }
+
+ /* Add `-lgphobos' if we haven't already done so. */
+ if (phobos_library != PHOBOS_NOLINK && need_phobos)
+ {
+ /* Default to static linking. */
+ if (phobos_library != PHOBOS_DYNAMIC)
+ phobos_library = PHOBOS_STATIC;
+
+#ifdef HAVE_LD_STATIC_DYNAMIC
+ if (phobos_library == PHOBOS_DYNAMIC && static_link)
+ {
+ generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER,
+ &new_decoded_options[j]);
+ j++;
+ }
+ else if (phobos_library == PHOBOS_STATIC && !static_link)
+ {
+ generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER,
+ &new_decoded_options[j]);
+ j++;
+ }
+#endif
+
+ generate_option (OPT_l,
+ saw_profile_flag ? LIBPHOBOS_PROFILE : LIBPHOBOS, 1,
+ CL_DRIVER, &new_decoded_options[j]);
+ added_libraries++;
+ j++;
+ generate_option (OPT_l,
+ saw_profile_flag ? LIBDRUNTIME_PROFILE : LIBDRUNTIME, 1,
+ CL_DRIVER, &new_decoded_options[j]);
+ added_libraries++;
+ j++;
+
+#ifdef HAVE_LD_STATIC_DYNAMIC
+ if (phobos_library == PHOBOS_DYNAMIC && static_link)
+ {
+ generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER,
+ &new_decoded_options[j]);
+ j++;
+ }
+ else if (phobos_library == PHOBOS_STATIC && !static_link)
+ {
+ generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER,
+ &new_decoded_options[j]);
+ j++;
+ }
+#endif
+ }
+ else if (saw_debug_flag && debuglib)
+ {
+ generate_option (OPT_l, debuglib, 1, CL_DRIVER,
+ &new_decoded_options[j++]);
+ added_libraries++;
+ }
+ else if (defaultlib)
+ {
+ generate_option (OPT_l, defaultlib, 1, CL_DRIVER,
+ &new_decoded_options[j++]);
+ added_libraries++;
+ }
+
+ if (saw_libcxx)
+ new_decoded_options[j++] = *saw_libcxx;
+ else if (need_stdcxx)
+ {
+ generate_option (OPT_l,
+ (saw_profile_flag
+ ? LIBSTDCXX_PROFILE
+ : LIBSTDCXX),
+ 1, CL_DRIVER, &new_decoded_options[j++]);
+ added_libraries++;
+ }
+
+ if (shared_libgcc && !static_link)
+ {
+ generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER,
+ &new_decoded_options[j++]);
+ }
+
+ *in_decoded_options_count = j;
+ *in_decoded_options = new_decoded_options;
+ *in_added_libraries = added_libraries;
+}
+
+/* Called before linking. Returns 0 on success and -1 on failure. */
+
+int
+lang_specific_pre_link (void)
+{
+ if (phobos_library != PHOBOS_NOLINK && need_phobos)
+ do_spec ("%:include(libgphobos.spec)");
+
+ return 0;
+}
+
+/* Number of extra output files that lang_specific_pre_link may generate. */
+
+int lang_specific_extra_outfiles = 0; /* Not used for D. */
+
diff --git a/gcc/d/d-target-def.h b/gcc/d/d-target-def.h
new file mode 100644
index 0000000..ef3e948
--- /dev/null
+++ b/gcc/d/d-target-def.h
@@ -0,0 +1,20 @@
+/* d-target-def.h -- Default initializers for D target hooks.
+ Copyright (C) 2017-2018 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "d/d-target-hooks-def.h"
+#include "tree.h"
+#include "hooks.h"
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
new file mode 100644
index 0000000..3ae791b
--- /dev/null
+++ b/gcc/d/d-target.cc
@@ -0,0 +1,394 @@
+/* d-target.cc -- Target interface for the D front end.
+ Copyright (C) 2013-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/declaration.h"
+#include "dmd/expression.h"
+#include "dmd/mangle.h"
+#include "dmd/mtype.h"
+#include "dmd/tokens.h"
+#include "dmd/target.h"
+
+#include "tree.h"
+#include "memmodel.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "tm.h"
+#include "tm_p.h"
+#include "target.h"
+
+#include "d-tree.h"
+#include "d-target.h"
+
+/* Implements the Target interface defined by the front end.
+ Used for retrieving target-specific information. */
+
+/* Type size information used by frontend. */
+int Target::ptrsize;
+int Target::c_longsize;
+int Target::realsize;
+int Target::realpad;
+int Target::realalignsize;
+bool Target::reverseCppOverloads;
+bool Target::cppExceptions;
+int Target::classinfosize;
+unsigned long long Target::maxStaticDataSize;
+
+/* Floating-point constants for for .max, .min, and other properties. */
+template <typename T> real_t Target::FPTypeProperties<T>::max;
+template <typename T> real_t Target::FPTypeProperties<T>::min_normal;
+template <typename T> real_t Target::FPTypeProperties<T>::nan;
+template <typename T> real_t Target::FPTypeProperties<T>::snan;
+template <typename T> real_t Target::FPTypeProperties<T>::infinity;
+template <typename T> real_t Target::FPTypeProperties<T>::epsilon;
+template <typename T> d_int64 Target::FPTypeProperties<T>::dig;
+template <typename T> d_int64 Target::FPTypeProperties<T>::mant_dig;
+template <typename T> d_int64 Target::FPTypeProperties<T>::max_exp;
+template <typename T> d_int64 Target::FPTypeProperties<T>::min_exp;
+template <typename T> d_int64 Target::FPTypeProperties<T>::max_10_exp;
+template <typename T> d_int64 Target::FPTypeProperties<T>::min_10_exp;
+
+
+/* Initialize the floating-point constants for TYPE. */
+
+template <typename T>
+static void
+define_float_constants (tree type)
+{
+ const double log10_2 = 0.30102999566398119521;
+ char buf[128];
+
+ /* Get back-end real mode format. */
+ const machine_mode mode = TYPE_MODE (type);
+ const real_format *fmt = REAL_MODE_FORMAT (mode);
+
+ /* The largest representable value that's not infinity. */
+ get_max_float (fmt, buf, sizeof (buf));
+ real_from_string (&T::max.rv (), buf);
+
+ /* The smallest representable normalized value that's not 0. */
+ snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - 1);
+ real_from_string (&T::min_normal.rv (), buf);
+
+ /* Floating-point NaN. */
+ real_nan (&T::nan.rv (), "", 1, mode);
+
+ /* Signalling floating-point NaN. */
+ real_nan (&T::snan.rv (), "", 0, mode);
+
+ /* Floating-point +Infinity if the target supports infinities. */
+ real_inf (&T::infinity.rv ());
+
+ /* The smallest increment to the value 1. */
+ if (fmt->pnan < fmt->p)
+ snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - fmt->p);
+ else
+ snprintf (buf, sizeof (buf), "0x1p%d", 1 - fmt->p);
+ real_from_string (&T::epsilon.rv (), buf);
+
+ /* The number of decimal digits of precision. */
+ T::dig = (fmt->p - 1) * log10_2;
+
+ /* The number of bits in mantissa. */
+ T::mant_dig = fmt->p;
+
+ /* The maximum int value such that 2** (value-1) is representable. */
+ T::max_exp = fmt->emax;
+
+ /* The minimum int value such that 2** (value-1) is representable as a
+ normalized value. */
+ T::min_exp = fmt->emin;
+
+ /* The maximum int value such that 10**value is representable. */
+ T::max_10_exp = fmt->emax * log10_2;
+
+ /* The minimum int value such that 10**value is representable as a
+ normalized value. */
+ T::min_10_exp = (fmt->emin - 1) * log10_2;
+}
+
+/* Initialize all variables of the Target structure. */
+
+void
+Target::_init (void)
+{
+ /* Map D frontend type and sizes to GCC back-end types. */
+ Target::ptrsize = (POINTER_SIZE / BITS_PER_UNIT);
+ Target::realsize = int_size_in_bytes (long_double_type_node);
+ Target::realpad = (Target::realsize -
+ (TYPE_PRECISION (long_double_type_node) / BITS_PER_UNIT));
+ Target::realalignsize = TYPE_ALIGN_UNIT (long_double_type_node);
+
+ /* Size of run-time TypeInfo object. */
+ Target::classinfosize = 19 * Target::ptrsize;
+
+ /* Allow data sizes up to half of the address space. */
+ Target::maxStaticDataSize = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node));
+
+ /* Define what type to use for size_t, ptrdiff_t. */
+ if (POINTER_SIZE == 64)
+ {
+ global.params.isLP64 = true;
+ Tsize_t = Tuns64;
+ Tptrdiff_t = Tint64;
+ }
+ else
+ {
+ Tsize_t = Tuns32;
+ Tptrdiff_t = Tint32;
+ }
+
+ Type::tsize_t = Type::basic[Tsize_t];
+ Type::tptrdiff_t = Type::basic[Tptrdiff_t];
+ Type::thash_t = Type::tsize_t;
+
+ /* Set-up target C ABI. */
+ Target::c_longsize = int_size_in_bytes (long_integer_type_node);
+
+ /* Set-up target C++ ABI. */
+ Target::reverseCppOverloads = false;
+ Target::cppExceptions = true;
+
+ /* Initialize all compile-time properties for floating-point types.
+ Should ensure that our real_t type is able to represent real_value. */
+ gcc_assert (sizeof (real_t) >= sizeof (real_value));
+
+ define_float_constants <Target::FloatProperties> (float_type_node);
+ define_float_constants <Target::DoubleProperties> (double_type_node);
+ define_float_constants <Target::RealProperties> (long_double_type_node);
+
+ /* Commonly used floating-point constants. */
+ const machine_mode mode = TYPE_MODE (long_double_type_node);
+ real_convert (&CTFloat::zero.rv (), mode, &dconst0);
+ real_convert (&CTFloat::one.rv (), mode, &dconst1);
+ real_convert (&CTFloat::minusone.rv (), mode, &dconstm1);
+ real_convert (&CTFloat::half.rv (), mode, &dconsthalf);
+}
+
+/* Return GCC memory alignment size for type TYPE. */
+
+unsigned
+Target::alignsize (Type *type)
+{
+ gcc_assert (type->isTypeBasic ());
+ return TYPE_ALIGN_UNIT (build_ctype (type));
+}
+
+/* Return GCC field alignment size for type TYPE. */
+
+unsigned
+Target::fieldalign (Type *type)
+{
+ /* Work out the correct alignment for the field decl. */
+ unsigned int align = type->alignsize () * BITS_PER_UNIT;
+
+#ifdef BIGGEST_FIELD_ALIGNMENT
+ align = MIN (align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
+#endif
+
+#ifdef ADJUST_FIELD_ALIGN
+ if (type->isTypeBasic ())
+ align = ADJUST_FIELD_ALIGN (NULL_TREE, build_ctype (type), align);
+#endif
+
+ /* Also controlled by -fpack-struct= */
+ if (maximum_field_alignment)
+ align = MIN (align, maximum_field_alignment);
+
+ return align / BITS_PER_UNIT;
+}
+
+/* Return size of OS critical section.
+ Can't use the sizeof () calls directly since cross compiling is supported
+ and would end up using the host sizes rather than the target sizes. */
+
+unsigned
+Target::critsecsize (void)
+{
+ return targetdm.d_critsec_size ();
+}
+
+/* Returns a Type for the va_list type of the target. */
+
+Type *
+Target::va_listType (void)
+{
+ return Type::tvalist;
+}
+
+/* Checks whether the target supports a vector type with total size SZ
+ (in bytes) and element type TYPE. */
+
+int
+Target::isVectorTypeSupported (int sz, Type *type)
+{
+ /* Size must be greater than zero, and a power of two. */
+ if (sz <= 0 || sz & (sz - 1))
+ return 2;
+
+ /* __vector(void[]) is treated same as __vector(ubyte[]) */
+ if (type == Type::tvoid)
+ type = Type::tuns8;
+
+ /* No support for non-trivial types. */
+ if (!type->isTypeBasic ())
+ return 3;
+
+ /* If there is no hardware support, check if we can safely emulate it. */
+ tree ctype = build_ctype (type);
+ machine_mode mode = TYPE_MODE (ctype);
+
+ if (!targetm.vector_mode_supported_p (mode)
+ && !targetm.scalar_mode_supported_p (as_a <scalar_mode> (mode)))
+ return 3;
+
+ return 0;
+}
+
+/* Checks whether the target supports operation OP for vectors of type TYPE.
+ For binary ops T2 is the type of the right-hand operand.
+ Returns true if the operation is supported or type is not a vector. */
+
+bool
+Target::isVectorOpSupported (Type *type, TOK op, Type *)
+{
+ if (type->ty != Tvector)
+ return true;
+
+ /* Don't support if type is non-scalar, such as __vector(void[]). */
+ if (!type->isscalar ())
+ return false;
+
+ /* Don't support if expression cannot be represented. */
+ switch (op)
+ {
+ case TOKpow:
+ case TOKpowass:
+ /* pow() is lowered as a function call. */
+ return false;
+
+ case TOKmod:
+ case TOKmodass:
+ /* fmod() is lowered as a function call. */
+ if (type->isfloating ())
+ return false;
+ break;
+
+ case TOKandand:
+ case TOKoror:
+ /* Logical operators must have a result type of bool. */
+ return false;
+
+ case TOKue:
+ case TOKlg:
+ case TOKule:
+ case TOKul:
+ case TOKuge:
+ case TOKug:
+ case TOKle:
+ case TOKlt:
+ case TOKge:
+ case TOKgt:
+ case TOKleg:
+ case TOKunord:
+ case TOKequal:
+ case TOKnotequal:
+ case TOKidentity:
+ case TOKnotidentity:
+ /* Comparison operators must have a result type of bool. */
+ return false;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/* Return the symbol mangling of S for C++ linkage. */
+
+const char *
+Target::toCppMangle (Dsymbol *s)
+{
+ return toCppMangleItanium (s);
+}
+
+/* Return the symbol mangling of CD for C++ linkage. */
+
+const char *
+Target::cppTypeInfoMangle (ClassDeclaration *cd)
+{
+ return cppTypeInfoMangleItanium (cd);
+}
+
+/* For a vendor-specific type, return a string containing the C++ mangling.
+ In all other cases, return NULL. */
+
+const char *
+Target::cppTypeMangle (Type *type)
+{
+ if (type->isTypeBasic () || type->ty == Tvector || type->ty == Tstruct)
+ {
+ tree ctype = build_ctype (type);
+ return targetm.mangle_type (ctype);
+ }
+
+ return NULL;
+}
+
+/* Return the type that will really be used for passing the given parameter
+ ARG to an extern(C++) function. */
+
+Type *
+Target::cppParameterType (Parameter *arg)
+{
+ Type *t = arg->type->merge2 ();
+ if (arg->storageClass & (STCout | STCref))
+ t = t->referenceTo ();
+ else if (arg->storageClass & STClazy)
+ {
+ /* Mangle as delegate. */
+ Type *td = TypeFunction::create (NULL, t, 0, LINKd);
+ td = TypeDelegate::create (td);
+ t = t->merge2 ();
+ }
+
+ /* Could be a va_list, which we mangle as a pointer. */
+ if (t->ty == Tsarray && Type::tvalist->ty == Tsarray)
+ {
+ Type *tb = t->toBasetype ()->mutableOf ();
+ if (tb == Type::tvalist)
+ {
+ tb = t->nextOf ()->pointerTo ();
+ t = tb->castMod (t->mod);
+ }
+ }
+
+ return t;
+}
+
+/* Return the default system linkage for the target. */
+
+LINK
+Target::systemLinkage (void)
+{
+ return LINKc;
+}
diff --git a/gcc/d/d-target.def b/gcc/d/d-target.def
new file mode 100644
index 0000000..d2ff07f
--- /dev/null
+++ b/gcc/d/d-target.def
@@ -0,0 +1,60 @@
+/* d-target.def -- Target hook definitions for the D front end.
+ Copyright (C) 2017-2018 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* See target-hooks-macros.h for details of macros that should be
+ provided by the including file, and how to use them here. */
+
+#include "target-hooks-macros.h"
+
+#undef HOOK_TYPE
+#define HOOK_TYPE "D Target Hook"
+
+HOOK_VECTOR (TARGETDM_INITIALIZER, gcc_targetdm)
+
+#undef HOOK_PREFIX
+#define HOOK_PREFIX "TARGET_"
+
+/* Environmental version identifiers relating to the target CPU. */
+DEFHOOK
+(d_cpu_versions,
+ "Declare all environmental version identifiers relating to the target CPU\n\
+using the function @code{builtin_version}, which takes a string representing\n\
+the name of the version. Version identifiers predefined by this hook apply\n\
+to all modules that are being compiled and imported.",
+ void, (void),
+ hook_void_void)
+
+/* Environmental version identifiers relating to the target OS. */
+DEFHOOK
+(d_os_versions,
+ "Similarly to @code{TARGET_D_CPU_VERSIONS}, but is used for versions\n\
+relating to the target operating system.",
+ void, (void),
+ hook_void_void)
+
+/* The sizeof CRITICAL_SECTION or pthread_mutex_t. */
+DEFHOOK
+(d_critsec_size,
+ "Returns the size of the data structure used by the target operating system\n\
+for critical sections and monitors. For example, on Microsoft Windows this\n\
+would return the @code{sizeof(CRITICAL_SECTION)}, while other platforms that\n\
+implement pthreads would return @code{sizeof(pthread_mutex_t)}.",
+ unsigned, (void),
+ hook_uint_void_0)
+
+/* Close the 'struct gcc_targetdm' definition. */
+HOOK_VECTOR_END (C90_EMPTY_HACK)
diff --git a/gcc/d/d-target.h b/gcc/d/d-target.h
new file mode 100644
index 0000000..283eb24
--- /dev/null
+++ b/gcc/d/d-target.h
@@ -0,0 +1,34 @@
+/* d-target.h -- Data structure definitions for target-specific D behavior.
+ Copyright (C) 2017-2018 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_D_TARGET_H
+#define GCC_D_TARGET_H
+
+#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
+#define DEFHOOK(NAME, DOC, TYPE, PARAMS, INIT) TYPE (* NAME) PARAMS;
+#define DEFHOOK_UNDOC DEFHOOK
+#define HOOKSTRUCT(FRAGMENT) FRAGMENT
+
+#include "d-target.def"
+
+/* Each target can provide their own. */
+extern struct gcc_targetdm targetdm;
+
+/* Used by target to add predefined version idenditiers. */
+extern void d_add_builtin_version (const char *);
+
+#endif /* GCC_D_TARGET_H */
diff --git a/gcc/d/d-tree.def b/gcc/d/d-tree.def
new file mode 100644
index 0000000..86b6461
--- /dev/null
+++ b/gcc/d/d-tree.def
@@ -0,0 +1,29 @@
+/* d-tree.def -- Definitions and documentation for additional tree codes used
+ in the D compiler (see tree.def for standard codes).
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Logical shift done on an unsigned type. If the first operand is
+ signed, it will be converted to the unsigned equivalent. The second
+ operand is the number of bits to shift by; it need not be the same
+ type as the first operand and result. */
+DEFTREECODE (UNSIGNED_RSHIFT_EXPR, "unsigned_rshift_expr", tcc_binary, 2)
+
+/* Floating point modulus that expands to a call to fmod. */
+DEFTREECODE (FLOAT_MOD_EXPR, "float_mod_expr", tcc_binary, 2)
+
+/* Used to represent information associated with a function closure. */
+DEFTREECODE (FUNCFRAME_INFO, "funcframe_info", tcc_exceptional, 0)
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
new file mode 100644
index 0000000..6f18e40
--- /dev/null
+++ b/gcc/d/d-tree.h
@@ -0,0 +1,675 @@
+/* d-tree.h -- Definitions and declarations for code generation.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_D_TREE_H
+#define GCC_D_TREE_H
+
+/* Forward type declarations to avoid including unnecessary headers. */
+
+class Dsymbol;
+class Declaration;
+class AggregateDeclaration;
+class ClassDeclaration;
+class EnumDeclaration;
+class FuncDeclaration;
+class StructDeclaration;
+class TypeInfoDeclaration;
+class VarDeclaration;
+class UserAttributeDeclaration;
+class Expression;
+class ClassReferenceExp;
+class Module;
+class Statement;
+class Type;
+class TypeFunction;
+class Parameter;
+struct BaseClass;
+struct Scope;
+struct Loc;
+
+template <typename TYPE> struct Array;
+typedef Array<Expression *> Expressions;
+
+/* Usage of TREE_LANG_FLAG_?:
+ 0: METHOD_CALL_EXPR
+ 1: CALL_EXPR_ARGS_ORDERED (in CALL_EXPR).
+
+ Usage of TYPE_LANG_FLAG_?:
+ 0: TYPE_SHARED
+ 1: TYPE_IMAGINARY_FLOAT (in REAL_TYPE).
+ ANON_AGGR_TYPE_P (in RECORD_TYPE, UNION_TYPE).
+ 2: CLASS_TYPE_P (in RECORD_TYPE).
+ 3: TYPE_DYNAMIC_ARRAY (in RECORD_TYPE).
+ 4: TYPE_DELEGATE (in RECORD_TYPE).
+ 5: TYPE_ASSOCIATIVE_ARRAY (in RECORD_TYPE).
+
+ Usage of DECL_LANG_FLAG_?:
+ 0: LABEL_VARIABLE_CASE (in LABEL_DECL).
+ DECL_BUILT_IN_CTFE (in FUNCTION_DECL). */
+
+/* The kinds of scopes we recognize. */
+
+enum level_kind
+{
+ level_block, /* An ordinary block scope. */
+ level_try, /* A try-block. */
+ level_catch, /* A catch-block. */
+ level_finally, /* A finally-block. */
+ level_cond, /* The scope for an if condition. */
+ level_switch, /* The scope for a switch statement. */
+ level_loop, /* A for, do-while, or unrolled-loop block. */
+ level_with, /* The scope for a with statement. */
+ level_function /* The block representing an entire function. */
+};
+
+/* List of codes for internally recognised compiler intrinsics. */
+
+enum intrinsic_code
+{
+#define DEF_D_INTRINSIC(CODE, A, N, M, D, C) INTRINSIC_ ## CODE,
+
+#include "intrinsics.def"
+
+#undef DEF_D_INTRINSIC
+ INTRINSIC_LAST
+};
+
+/* For use with break and continue statements. */
+
+enum bc_kind
+{
+ bc_break = 0,
+ bc_continue = 1
+};
+
+/* The datatype used to implement D scope. It is needed primarily to support
+ the back-end, but also helps debugging information for local variables. */
+
+struct GTY((chain_next ("%h.level_chain"))) binding_level
+{
+ /* A chain of declarations for all variables, constants and functions.
+ These are in the reverse of the order supplied. */
+ tree names;
+
+ /* For each level (except the global one), a chain of BLOCK nodes for
+ all the levels that were entered and exited one level down. */
+ tree blocks;
+
+ /* The binding level this one is contained in. */
+ binding_level *level_chain;
+
+ /* The kind of scope this object represents. */
+ ENUM_BITFIELD (level_kind) kind : 4;
+};
+
+/* The binding level currently in effect. */
+extern GTY(()) binding_level *current_binding_level;
+extern GTY(()) binding_level *global_binding_level;
+
+/* Used only for jumps to as-yet undefined labels, since jumps to
+ defined labels can have their validity checked immediately. */
+
+struct GTY((chain_next ("%h.next"))) d_label_use_entry
+{
+ d_label_use_entry *next;
+
+ /* The frontend Statement associated with the jump. */
+ Statement * GTY((skip)) statement;
+
+ /* The binding level to which this entry is *currently* attached.
+ This is initially the binding level in which the goto appeared,
+ but is modified as scopes are closed. */
+ binding_level *level;
+};
+
+/* A list of all LABEL_DECLs in the function that have names. Here so
+ we can clear out their names' definitions at the end of the
+ function, and so we can check the validity of jumps to these labels. */
+
+struct GTY(()) d_label_entry
+{
+ /* The label decl itself. */
+ tree label;
+
+ /* The frontend Statement associated with the label. */
+ Statement * GTY((skip)) statement;
+
+ /* The binding level to which the label is *currently* attached.
+ This is initially set to the binding level in which the label
+ is defined, but is modified as scopes are closed. */
+ binding_level *level;
+
+ /* A list of forward references of the label. */
+ d_label_use_entry *fwdrefs;
+
+ /* The following bits are set after the label is defined, and are
+ updated as scopes are popped. They indicate that a backward jump
+ to the label will illegally enter a scope of the given flavor. */
+ bool in_try_scope;
+ bool in_catch_scope;
+
+ /* If set, the label we reference represents a break/continue pair. */
+ bool bc_label;
+};
+
+/* Frame information for a function declaration. */
+
+struct GTY(()) tree_frame_info
+{
+ struct tree_common common;
+ tree frame_type;
+};
+
+/* True if the function creates a nested frame. */
+#define FRAMEINFO_CREATES_FRAME(NODE) \
+ (TREE_LANG_FLAG_0 (FUNCFRAME_INFO_CHECK (NODE)))
+
+/* True if the function has a static chain passed in its DECL_ARGUMENTS. */
+#define FRAMEINFO_STATIC_CHAIN(NODE) \
+ (TREE_LANG_FLAG_1 (FUNCFRAME_INFO_CHECK (NODE)))
+
+/* True if the function frame is a closure (initialized on the heap). */
+#define FRAMEINFO_IS_CLOSURE(NODE) \
+ (TREE_LANG_FLAG_2 (FUNCFRAME_INFO_CHECK (NODE)))
+
+#define FRAMEINFO_TYPE(NODE) \
+ (((tree_frame_info *) FUNCFRAME_INFO_CHECK (NODE))->frame_type)
+
+/* Language-dependent contents of an identifier. */
+
+struct GTY(()) lang_identifier
+{
+ struct tree_identifier common;
+
+ /* The identifier as the user sees it. */
+ tree pretty_ident;
+
+ /* The back-end tree associated with this identifier. */
+ tree decl_tree;
+
+ /* The frontend Declaration associated with this identifier. */
+ Declaration * GTY((skip)) dsymbol;
+};
+
+#define IDENTIFIER_LANG_SPECIFIC(NODE) \
+ ((struct lang_identifier *) IDENTIFIER_NODE_CHECK (NODE))
+
+#define IDENTIFIER_PRETTY_NAME(NODE) \
+ (IDENTIFIER_LANG_SPECIFIC (NODE)->pretty_ident)
+
+#define IDENTIFIER_DECL_TREE(NODE) \
+ (IDENTIFIER_LANG_SPECIFIC (NODE)->decl_tree)
+
+#define IDENTIFIER_DSYMBOL(NODE) \
+ (IDENTIFIER_LANG_SPECIFIC (NODE)->dsymbol)
+
+/* Global state pertinent to the current function. */
+
+struct GTY(()) language_function
+{
+ /* Our function and enclosing module. */
+ FuncDeclaration * GTY((skip)) function;
+ Module * GTY((skip)) module;
+
+ /* Static chain of function, for D2, this is a closure. */
+ tree static_chain;
+
+ /* Stack of statement lists being collected while we are
+ compiling the function. */
+ vec<tree, va_gc> *stmt_list;
+
+ /* Variables that are in scope that will need destruction later. */
+ vec<tree, va_gc> *vars_in_scope;
+
+ /* Table of all used or defined labels in the function. */
+ hash_map<Statement *, d_label_entry> *labels;
+};
+
+/* The D front end types have not been integrated into the GCC garbage
+ collection system. Handle this by using the "skip" attribute. */
+
+struct GTY(()) lang_decl
+{
+ Declaration * GTY((skip)) decl;
+
+ /* FIELD_DECL in frame struct that this variable is allocated in. */
+ tree frame_field;
+
+ /* RESULT_DECL in a function that returns by nrvo. */
+ tree named_result;
+
+ /* Chain of DECL_LANG_THUNKS in a function. */
+ tree thunks;
+
+ /* In a FUNCTION_DECL, this is the THUNK_LANG_OFFSET. */
+ int offset;
+
+ /* In a FUNCTION_DECL, if this is an intrinsic, the code for it. */
+ enum intrinsic_code intrinsic;
+
+ /* FUNCFRAME_INFO in a function that has non-local references. */
+ tree frame_info;
+};
+
+/* The current D per-function global variables. */
+
+#define d_function_chain (cfun ? cfun->language : NULL)
+
+/* The D frontend Declaration AST for GCC decl NODE. */
+#define DECL_LANG_FRONTEND(NODE) \
+ (DECL_LANG_SPECIFIC (NODE) \
+ ? DECL_LANG_SPECIFIC (NODE)->decl : NULL)
+
+#define SET_DECL_LANG_FRAME_FIELD(NODE, VAL) \
+ DECL_LANG_SPECIFIC (NODE)->frame_field = VAL
+
+#define DECL_LANG_FRAME_FIELD(NODE) \
+ (DECL_P (NODE) \
+ ? DECL_LANG_SPECIFIC (NODE)->frame_field : NULL)
+
+#define SET_DECL_LANG_NRVO(NODE, VAL) \
+ DECL_LANG_SPECIFIC (NODE)->named_result = VAL
+
+#define DECL_LANG_NRVO(NODE) \
+ (DECL_P (NODE) \
+ ? DECL_LANG_SPECIFIC (NODE)->named_result : NULL)
+
+#define DECL_LANG_THUNKS(NODE) \
+ DECL_LANG_SPECIFIC (NODE)->thunks
+
+#define THUNK_LANG_OFFSET(NODE) \
+ DECL_LANG_SPECIFIC (NODE)->offset
+
+#define DECL_INTRINSIC_CODE(NODE) \
+ DECL_LANG_SPECIFIC (NODE)->intrinsic
+
+#define DECL_LANG_FRAMEINFO(NODE) \
+ DECL_LANG_SPECIFIC (NODE)->frame_info
+
+/* The lang_type field is not set for every GCC type. */
+
+struct GTY(()) lang_type
+{
+ Type * GTY((skip)) type;
+};
+
+/* The D frontend Type AST for GCC type NODE. */
+#define TYPE_LANG_FRONTEND(NODE) \
+ (TYPE_LANG_SPECIFIC (NODE) \
+ ? TYPE_LANG_SPECIFIC (NODE)->type : NULL)
+
+
+enum d_tree_node_structure_enum
+{
+ TS_D_GENERIC,
+ TS_D_IDENTIFIER,
+ TS_D_FRAMEINFO,
+ LAST_TS_D_ENUM
+};
+
+/* The resulting tree type. */
+
+union GTY((desc ("d_tree_node_structure (&%h)"),
+ chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON)"
+ " ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+ union tree_node GTY ((tag ("TS_D_GENERIC"),
+ desc ("tree_node_structure (&%h)"))) generic;
+ lang_identifier GTY ((tag ("TS_D_IDENTIFIER"))) identifier;
+ tree_frame_info GTY ((tag ("TS_D_FRAMEINFO"))) frameinfo;
+};
+
+/* True if the Tdelegate typed expression is not really a variable,
+ but a literal function / method reference. */
+#define METHOD_CALL_EXPR(NODE) \
+ (TREE_LANG_FLAG_0 (NODE))
+
+/* True if all arguments in a call expression should be evaluated in the
+ order they are given (left to right). */
+#define CALL_EXPR_ARGS_ORDERED(NODE) \
+ (TREE_LANG_FLAG_1 (CALL_EXPR_CHECK (NODE)))
+
+/* True if the type was declared 'shared'. */
+#define TYPE_SHARED(NODE) \
+ (TYPE_LANG_FLAG_0 (NODE))
+
+/* True if the type is an imaginary float type. */
+#define TYPE_IMAGINARY_FLOAT(NODE) \
+ (TYPE_LANG_FLAG_1 (REAL_TYPE_CHECK (NODE)))
+
+/* True if the type is an anonymous record or union. */
+#define ANON_AGGR_TYPE_P(NODE) \
+ (TYPE_LANG_FLAG_1 (RECORD_OR_UNION_CHECK (NODE)))
+
+/* True if the type is the underlying record for a class. */
+#define CLASS_TYPE_P(NODE) \
+ (TYPE_LANG_FLAG_2 (RECORD_TYPE_CHECK (NODE)))
+
+/* True if the type is a D dynamic array. */
+#define TYPE_DYNAMIC_ARRAY(NODE) \
+ (TYPE_LANG_FLAG_3 (RECORD_TYPE_CHECK (NODE)))
+
+/* True if the type is a D delegate. */
+#define TYPE_DELEGATE(NODE) \
+ (TYPE_LANG_FLAG_4 (RECORD_TYPE_CHECK (NODE)))
+
+/* True if the type is a D associative array. */
+#define TYPE_ASSOCIATIVE_ARRAY(NODE) \
+ (TYPE_LANG_FLAG_5 (RECORD_TYPE_CHECK (NODE)))
+
+/* True if the decl is a variable case label decl. */
+#define LABEL_VARIABLE_CASE(NODE) \
+ (DECL_LANG_FLAG_0 (LABEL_DECL_CHECK (NODE)))
+
+/* True if the decl is a CTFE built-in. */
+#define DECL_BUILT_IN_CTFE(NODE) \
+ (DECL_LANG_FLAG_0 (FUNCTION_DECL_CHECK (NODE)))
+
+enum d_tree_index
+{
+ DTI_VTABLE_ENTRY_TYPE,
+ DTI_VTBL_PTR_TYPE,
+ DTI_VTBL_INTERFACE_TYPE,
+
+ DTI_BOOL_TYPE,
+ DTI_CHAR_TYPE,
+ DTI_WCHAR_TYPE,
+ DTI_DCHAR_TYPE,
+
+ DTI_BYTE_TYPE,
+ DTI_UBYTE_TYPE,
+ DTI_SHORT_TYPE,
+ DTI_USHORT_TYPE,
+ DTI_INT_TYPE,
+ DTI_UINT_TYPE,
+ DTI_LONG_TYPE,
+ DTI_ULONG_TYPE,
+ DTI_CENT_TYPE,
+ DTI_UCENT_TYPE,
+
+ DTI_IFLOAT_TYPE,
+ DTI_IDOUBLE_TYPE,
+ DTI_IREAL_TYPE,
+
+ DTI_UNKNOWN_TYPE,
+
+ DTI_ARRAY_TYPE,
+ DTI_NULL_ARRAY,
+
+ DTI_MAX
+};
+
+extern GTY(()) tree d_global_trees[DTI_MAX];
+
+#define vtable_entry_type d_global_trees[DTI_VTABLE_ENTRY_TYPE]
+#define vtbl_ptr_type_node d_global_trees[DTI_VTBL_PTR_TYPE]
+#define vtbl_interface_type_node d_global_trees[DTI_VTBL_INTERFACE_TYPE]
+/* D built-in language types. */
+#define d_bool_type d_global_trees[DTI_BOOL_TYPE]
+#define d_byte_type d_global_trees[DTI_BYTE_TYPE]
+#define d_ubyte_type d_global_trees[DTI_UBYTE_TYPE]
+#define d_short_type d_global_trees[DTI_SHORT_TYPE]
+#define d_ushort_type d_global_trees[DTI_USHORT_TYPE]
+#define d_int_type d_global_trees[DTI_INT_TYPE]
+#define d_uint_type d_global_trees[DTI_UINT_TYPE]
+#define d_long_type d_global_trees[DTI_LONG_TYPE]
+#define d_ulong_type d_global_trees[DTI_ULONG_TYPE]
+#define d_cent_type d_global_trees[DTI_CENT_TYPE]
+#define d_ucent_type d_global_trees[DTI_UCENT_TYPE]
+/* Imaginary floating-point types. */
+#define ifloat_type_node d_global_trees[DTI_IFLOAT_TYPE]
+#define idouble_type_node d_global_trees[DTI_IDOUBLE_TYPE]
+#define ireal_type_node d_global_trees[DTI_IREAL_TYPE]
+/* UTF-8, 16 and 32 types. */
+#define char8_type_node d_global_trees[DTI_CHAR_TYPE]
+#define char16_type_node d_global_trees[DTI_DCHAR_TYPE]
+#define char32_type_node d_global_trees[DTI_WCHAR_TYPE]
+/* Empty record type used as placeholder when real type is unknown. */
+#define unknown_type_node d_global_trees[DTI_UNKNOWN_TYPE]
+/* Generic dynamic array type void[]. */
+#define array_type_node d_global_trees[DTI_ARRAY_TYPE]
+/* Null initializer for dynamic arrays. */
+#define null_array_node d_global_trees[DTI_NULL_ARRAY]
+
+/* A prefix for internal variables, which are not user-visible. */
+#if !defined (NO_DOT_IN_LABEL)
+# define GDC_PREFIX(x) "gdc." x
+#elif !defined (NO_DOLLAR_IN_LABEL)
+# define GDC_PREFIX(x) "gdc$" x
+#else
+# define GDC_PREFIX(x) "gdc_" x
+#endif
+
+/* Internally recognised D runtime library functions. */
+
+enum libcall_fn
+{
+#define DEF_D_RUNTIME(CODE, N, T, P, F) LIBCALL_ ## CODE,
+
+#include "runtime.def"
+
+#undef DEF_D_RUNTIME
+ LIBCALL_LAST
+};
+
+/* Gate for when the D frontend makes an early call into the codegen pass, such
+ as when it requires target information or CTFE evaluation. As full semantic
+ may not be completed, we only want to build the superficial tree structure
+ without finishing any decls or types. */
+extern bool doing_semantic_analysis_p;
+
+/* In d-attribs.c. */
+extern tree insert_type_attribute (tree, const char *, tree = NULL_TREE);
+extern tree insert_decl_attribute (tree, const char *, tree = NULL_TREE);
+extern tree build_attributes (Expressions *);
+
+/* In d-builtins.cc. */
+extern const attribute_spec d_langhook_attribute_table[];
+extern const attribute_spec d_langhook_common_attribute_table[];
+
+extern tree d_builtin_function (tree);
+extern void d_init_builtins (void);
+extern void d_register_builtin_type (tree, const char *);
+extern void d_build_builtins_module (Module *);
+extern void d_maybe_set_builtin (Module *);
+extern Expression *d_eval_constant_expression (tree);
+extern void d_init_versions (void);
+
+/* In d-codegen.cc. */
+extern location_t make_location_t (const Loc &);
+extern tree d_decl_context (Dsymbol *);
+extern tree copy_aggregate_type (tree);
+extern bool declaration_reference_p (Declaration *);
+extern tree declaration_type (Declaration *);
+extern bool argument_reference_p (Parameter *);
+extern tree type_passed_as (Parameter *);
+extern tree build_integer_cst (dinteger_t, tree = d_int_type);
+extern tree build_float_cst (const real_t &, Type *);
+extern tree d_array_length (tree);
+extern tree d_array_ptr (tree);
+extern tree d_array_value (tree, tree, tree);
+extern tree get_array_length (tree, Type *);
+extern tree build_class_binfo (tree, ClassDeclaration *);
+extern tree build_interface_binfo (tree, ClassDeclaration *, unsigned &);
+extern tree delegate_method (tree);
+extern tree delegate_object (tree);
+extern tree build_delegate_cst (tree, tree, Type *);
+extern tree build_method_call (tree, tree, Type *);
+extern void extract_from_method_call (tree, tree &, tree &);
+extern tree build_vindex_ref (tree, tree, size_t);
+extern tree d_save_expr (tree);
+extern tree stabilize_expr (tree *);
+extern tree build_target_expr (tree, tree);
+extern tree force_target_expr (tree);
+extern tree build_address (tree);
+extern tree d_mark_addressable (tree);
+extern tree d_mark_used (tree);
+extern tree d_mark_read (tree);
+extern bool identity_compare_p (StructDeclaration *);
+extern tree build_struct_comparison (tree_code, StructDeclaration *,
+ tree, tree);
+extern tree build_array_struct_comparison (tree_code, StructDeclaration *,
+ tree, tree, tree);
+extern tree build_struct_literal (tree, vec<constructor_elt, va_gc> *);
+extern tree component_ref (tree, tree);
+extern tree build_assign (tree_code, tree, tree);
+extern tree modify_expr (tree, tree);
+extern tree build_nop (tree, tree);
+extern tree build_vconvert (tree, tree);
+extern tree build_boolop (tree_code, tree, tree);
+extern tree build_condition (tree, tree, tree, tree);
+extern tree build_vcondition (tree, tree, tree);
+extern tree compound_expr (tree, tree);
+extern tree return_expr (tree);
+extern tree size_mult_expr (tree, tree);
+extern tree real_part (tree);
+extern tree imaginary_part (tree);
+extern tree complex_expr (tree, tree, tree);
+extern tree indirect_ref (tree, tree);
+extern tree build_deref (tree);
+extern tree build_array_index (tree, tree);
+extern tree build_offset_op (tree_code, tree, tree);
+extern tree build_offset (tree, tree);
+extern tree build_memref (tree, tree, tree);
+extern tree build_array_set (tree, tree, tree);
+extern tree build_array_from_val (Type *, tree);
+extern tree void_okay_p (tree);
+extern tree build_bounds_condition (const Loc &, tree, tree, bool);
+extern bool array_bounds_check (void);
+extern tree create_temporary_var (tree);
+extern tree maybe_temporary_var (tree, tree *);
+extern tree bind_expr (tree, tree);
+extern TypeFunction *get_function_type (Type *);
+extern bool call_by_alias_p (FuncDeclaration *, FuncDeclaration *);
+extern tree d_build_call_expr (FuncDeclaration *, tree, Expressions *);
+extern tree d_build_call (TypeFunction *, tree, tree, Expressions *);
+extern tree d_assert_call (const Loc &, libcall_fn, tree = NULL_TREE);
+extern tree build_float_modulus (tree, tree, tree);
+extern tree build_vthis_function (tree, tree);
+extern tree get_frame_for_symbol (Dsymbol *);
+extern tree build_vthis (AggregateDeclaration *);
+extern void build_closure (FuncDeclaration *);
+extern tree get_frameinfo (FuncDeclaration *);
+extern tree get_framedecl (FuncDeclaration *, FuncDeclaration *);
+
+/* In d-convert.cc. */
+extern bool decl_with_nonnull_addr_p (const_tree);
+extern tree d_truthvalue_conversion (tree);
+extern tree d_convert (tree, tree);
+extern tree convert_expr (tree, Type *, Type *);
+extern tree convert_for_assignment (tree, Type *, Type *);
+extern tree convert_for_argument (tree, Parameter *);
+extern tree convert_for_condition (tree, Type *);
+extern tree d_array_convert (Expression *);
+extern tree d_array_convert (Type *, Expression *, vec<tree, va_gc> **);
+
+/* In d-incpath.cc. */
+extern void add_import_paths (const char *, const char *, bool);
+
+/* In d-lang.cc. */
+extern void d_add_builtin_module (Module *);
+extern void d_add_entrypoint_module (Module *, Module *);
+extern d_tree_node_structure_enum d_tree_node_structure (lang_tree_node *);
+extern struct lang_type *build_lang_type (Type *);
+extern struct lang_decl *build_lang_decl (Declaration *);
+extern tree d_pushdecl (tree);
+extern tree d_unsigned_type (tree);
+extern tree d_signed_type (tree);
+extern void d_keep (tree);
+
+/* In decl.cc. */
+extern tree mangle_internal_decl (Dsymbol *, const char *, const char *);
+extern void build_decl_tree (Dsymbol *);
+extern tree get_symbol_decl (Declaration *);
+extern tree declare_extern_var (tree, tree);
+extern void declare_local_var (VarDeclaration *);
+extern tree build_local_temp (tree);
+extern tree get_decl_tree (Declaration *);
+extern void d_finish_decl (tree);
+extern tree make_thunk (FuncDeclaration *, int);
+extern tree start_function (FuncDeclaration *);
+extern void finish_function (tree);
+extern void mark_needed (tree);
+extern unsigned base_vtable_offset (ClassDeclaration *, BaseClass *);
+extern tree get_vtable_decl (ClassDeclaration *);
+extern tree build_new_class_expr (ClassReferenceExp *);
+extern tree aggregate_initializer_decl (AggregateDeclaration *);
+extern tree layout_struct_initializer (StructDeclaration *);
+extern tree layout_class_initializer (ClassDeclaration *);
+extern tree enum_initializer_decl (EnumDeclaration *);
+extern tree build_artificial_decl (tree, tree, const char * = NULL);
+extern tree create_field_decl (tree, const char *, int, int);
+extern void build_type_decl (tree, Dsymbol *);
+extern void d_comdat_linkage (tree);
+extern void d_linkonce_linkage (tree);
+
+/* In expr.cc. */
+extern tree build_expr (Expression *, bool = false);
+extern tree build_expr_dtor (Expression *);
+extern tree build_return_dtor (Expression *, Type *, TypeFunction *);
+
+/* In imports.cc. */
+extern tree build_import_decl (Dsymbol *);
+
+/* In intrinsics.cc. */
+extern void maybe_set_intrinsic (FuncDeclaration *);
+extern tree maybe_expand_intrinsic (tree);
+
+/* In modules.cc. */
+extern void build_module_tree (Module *);
+extern tree d_module_context (void);
+extern void register_module_decl (Declaration *);
+extern void d_finish_compilation (tree *, int);
+
+/* In runtime.cc. */
+extern tree build_libcall (libcall_fn, Type *, int ...);
+
+/* In typeinfo.cc. */
+extern tree layout_typeinfo (TypeInfoDeclaration *);
+extern tree layout_classinfo (ClassDeclaration *);
+extern tree get_typeinfo_decl (TypeInfoDeclaration *);
+extern tree get_classinfo_decl (ClassDeclaration *);
+extern tree build_typeinfo (Type *);
+extern void create_typeinfo (Type *, Module *);
+extern void create_tinfo_types (Module *);
+extern void layout_cpp_typeinfo (ClassDeclaration *);
+extern tree get_cpp_typeinfo_decl (ClassDeclaration *);
+extern bool speculative_type_p (Type *);
+
+/* In toir.cc. */
+extern void push_binding_level (level_kind);
+extern tree pop_binding_level (void);
+extern void push_stmt_list (void);
+extern tree pop_stmt_list (void);
+extern void add_stmt (tree);
+extern void build_function_body (FuncDeclaration *);
+
+/* In types.cc. */
+extern bool valist_array_p (Type *);
+extern bool empty_aggregate_p (tree);
+extern bool same_type_p (Type *, Type *);
+extern Type *get_object_type (void);
+extern tree make_array_type (Type *, unsigned HOST_WIDE_INT);
+extern tree make_struct_type (const char *, int n, ...);
+extern tree insert_type_modifiers (tree, unsigned);
+extern void insert_aggregate_field (tree, tree, size_t);
+extern void finish_aggregate_type (unsigned, unsigned, tree,
+ UserAttributeDeclaration *);
+extern tree build_ctype (Type *);
+
+#endif /* GCC_D_TREE_H */
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
new file mode 100644
index 0000000..6fd0808
--- /dev/null
+++ b/gcc/d/decl.cc
@@ -0,0 +1,2312 @@
+/* decl.cc -- Lower D frontend declarations to GCC trees.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/attrib.h"
+#include "dmd/ctfe.h"
+#include "dmd/declaration.h"
+#include "dmd/enum.h"
+#include "dmd/errors.h"
+#include "dmd/globals.h"
+#include "dmd/hdrgen.h"
+#include "dmd/identifier.h"
+#include "dmd/import.h"
+#include "dmd/init.h"
+#include "dmd/mangle.h"
+#include "dmd/module.h"
+#include "dmd/nspace.h"
+#include "dmd/target.h"
+#include "dmd/template.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "stringpool.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "attribs.h"
+#include "function.h"
+#include "debug.h"
+#include "tree-pretty-print.h"
+
+#include "d-tree.h"
+
+
+/* Return identifier for the external mangled name of DECL. */
+
+static const char *
+mangle_decl (Dsymbol *decl)
+{
+ if (decl->isFuncDeclaration ())
+ return mangleExact ((FuncDeclaration *)decl);
+ else
+ {
+ OutBuffer buf;
+ mangleToBuffer (decl, &buf);
+ return buf.extractString ();
+ }
+}
+
+/* Generate a mangled identifier using NAME and SUFFIX, prefixed by the
+ assembler name for DECL. */
+
+tree
+mangle_internal_decl (Dsymbol *decl, const char *name, const char *suffix)
+{
+ const char *prefix = mangle_decl (decl);
+ unsigned namelen = strlen (name);
+ unsigned buflen = (2 + strlen (prefix) + namelen + strlen (suffix)) * 2;
+ char *buf = (char *) alloca (buflen);
+
+ snprintf (buf, buflen, "_D%s%u%s%s", prefix, namelen, name, suffix);
+ tree ident = get_identifier (buf);
+
+ /* Symbol is not found in user code, but generate a readable name for it
+ anyway for debug and diagnostic reporting. */
+ snprintf (buf, buflen, "%s.%s", decl->toPrettyChars (), name);
+ IDENTIFIER_PRETTY_NAME (ident) = get_identifier (buf);
+
+ return ident;
+}
+
+/* Returns true if DECL is from the gcc.attribute module. */
+
+static bool
+gcc_attribute_p (Dsymbol *decl)
+{
+ ModuleDeclaration *md = decl->getModule ()->md;
+
+ if (md && md->packages && md->packages->dim == 1)
+ {
+ if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+ && !strcmp (md->id->toChars (), "attribute"))
+ return true;
+ }
+
+ return false;
+}
+
+/* Implements the visitor interface to lower all Declaration AST classes
+ emitted from the D Front-end to GCC trees.
+ All visit methods accept one parameter D, which holds the frontend AST
+ of the declaration to compile. These also don't return any value, instead
+ generated code are appened to global_declarations or added to the
+ current_binding_level by d_pushdecl(). */
+
+class DeclVisitor : public Visitor
+{
+ using Visitor::visit;
+
+public:
+ DeclVisitor (void)
+ {
+ }
+
+ /* This should be overridden by each declaration class. */
+
+ void visit (Dsymbol *)
+ {
+ }
+
+ /* Compile a D module, and all members of it. */
+
+ void visit (Module *d)
+ {
+ if (d->semanticRun >= PASSobj)
+ return;
+
+ build_module_tree (d);
+ d->semanticRun = PASSobj;
+ }
+
+ /* Write the imported symbol to debug. */
+
+ void visit (Import *d)
+ {
+ /* Implements import declarations by telling the debug back-end we are
+ importing the NAMESPACE_DECL of the module or IMPORTED_DECL of the
+ declaration into the current lexical scope CONTEXT. NAME is set if
+ this is a renamed import. */
+ if (d->isstatic)
+ return;
+
+ /* Get the context of this import, this should never be null. */
+ tree context = d_module_context ();
+
+ if (d->ident == NULL)
+ {
+ /* Importing declaration list. */
+ for (size_t i = 0; i < d->names.dim; i++)
+ {
+ AliasDeclaration *aliasdecl = d->aliasdecls[i];
+ tree decl = build_import_decl (aliasdecl);
+
+ /* Skip over unhandled imports. */
+ if (decl == NULL_TREE)
+ continue;
+
+ Identifier *alias = d->aliases[i];
+ tree name = (alias != NULL)
+ ? get_identifier (alias->toChars ()) : NULL_TREE;
+
+ debug_hooks->imported_module_or_decl (decl, name, context,
+ false, false);
+ }
+ }
+ else
+ {
+ /* Importing the entire module. */
+ tree decl = build_import_decl (d->mod);
+
+ tree name = (d->aliasId != NULL)
+ ? get_identifier (d->aliasId->toChars ()) : NULL_TREE;
+
+ debug_hooks->imported_module_or_decl (decl, name, context,
+ false, false);
+ }
+ }
+
+ /* Expand any local variables found in tuples. */
+
+ void visit (TupleDeclaration *d)
+ {
+ for (size_t i = 0; i < d->objects->dim; i++)
+ {
+ RootObject *o = (*d->objects)[i];
+ if ((o->dyncast () == DYNCAST_EXPRESSION)
+ && ((Expression *) o)->op == TOKdsymbol)
+ {
+ Declaration *d = ((DsymbolExp *) o)->s->isDeclaration ();
+ if (d)
+ d->accept (this);
+ }
+ }
+ }
+
+ /* Walk over all declarations in the attribute scope. */
+
+ void visit (AttribDeclaration *d)
+ {
+ Dsymbols *ds = d->include (NULL, NULL);
+
+ if (!ds)
+ return;
+
+ for (size_t i = 0; i < ds->dim; i++)
+ {
+ Dsymbol *s = (*ds)[i];
+ s->accept (this);
+ }
+ }
+
+ /* Pragmas are a way to pass special information to the compiler and to add
+ vendor specific extensions to D. We don't do anything here, yet. */
+
+ void visit (PragmaDeclaration *d)
+ {
+ if (!global.params.ignoreUnsupportedPragmas)
+ {
+ if (d->ident == Identifier::idPool ("lib")
+ || d->ident == Identifier::idPool ("startaddress"))
+ {
+ warning_at (make_location_t (d->loc), OPT_Wunknown_pragmas,
+ "pragma(%s) not implemented", d->ident->toChars ());
+ }
+ }
+
+ visit ((AttribDeclaration *) d);
+ }
+
+ /* Walk over all members in the namespace scope. */
+
+ void visit (Nspace *d)
+ {
+ if (isError (d) || !d->members)
+ return;
+
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept (this);
+ }
+ }
+
+ /* Walk over all members in the instantiated template. */
+
+ void visit (TemplateInstance *d)
+ {
+ if (isError (d)|| !d->members)
+ return;
+
+ if (!d->needsCodegen ())
+ return;
+
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept (this);
+ }
+ }
+
+ /* Walk over all members in the mixin template scope. */
+
+ void visit (TemplateMixin *d)
+ {
+ if (isError (d)|| !d->members)
+ return;
+
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept (this);
+ }
+ }
+
+ /* Write out compiler generated TypeInfo, initializer and functions for the
+ given struct declaration, walking over all static members. */
+
+ void visit (StructDeclaration *d)
+ {
+ if (d->type->ty == Terror)
+ {
+ error_at (make_location_t (d->loc),
+ "had semantic errors when compiling");
+ return;
+ }
+
+ /* Add this decl to the current binding level. */
+ tree ctype = build_ctype (d->type);
+ if (TYPE_NAME (ctype))
+ d_pushdecl (TYPE_NAME (ctype));
+
+ /* Anonymous structs/unions only exist as part of others,
+ do not output forward referenced structs. */
+ if (d->isAnonymous () || !d->members)
+ return;
+
+ /* Don't emit any symbols from gcc.attribute module. */
+ if (gcc_attribute_p (d))
+ return;
+
+ /* Generate TypeInfo. */
+ create_typeinfo (d->type, NULL);
+
+ /* Generate static initializer. */
+ d->sinit = aggregate_initializer_decl (d);
+ DECL_INITIAL (d->sinit) = layout_struct_initializer (d);
+
+ if (d->isInstantiated ())
+ d_linkonce_linkage (d->sinit);
+
+ d_finish_decl (d->sinit);
+
+ /* Put out the members. */
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *member = (*d->members)[i];
+ /* There might be static ctors in the members, and they cannot
+ be put in separate object files. */
+ member->accept (this);
+ }
+
+ /* Put out xopEquals, xopCmp and xopHash. */
+ if (d->xeq && d->xeq != d->xerreq)
+ d->xeq->accept (this);
+
+ if (d->xcmp && d->xcmp != d->xerrcmp)
+ d->xcmp->accept (this);
+
+ if (d->xhash)
+ d->xhash->accept (this);
+ }
+
+ /* Finish semantic analysis of functions in vtbl for class CD. */
+
+ bool finish_vtable (ClassDeclaration *d)
+ {
+ bool has_errors = false;
+
+ /* Finish semantic analysis of functions in vtbl[]. */
+ for (size_t i = d->vtblOffset (); i < d->vtbl.dim; i++)
+ {
+ FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration ();
+
+ if (!fd || (!fd->fbody && d->isAbstract ()))
+ continue;
+
+ /* Ensure function has a return value. */
+ if (!fd->functionSemantic ())
+ has_errors = true;
+
+ /* No name hiding to check for. */
+ if (!d->isFuncHidden (fd) || fd->isFuture ())
+ continue;
+
+ /* The function fd is hidden from the view of the class.
+ If it overlaps with any function in the vtbl[], then
+ issue an error. */
+ for (size_t j = 1; j < d->vtbl.dim; j++)
+ {
+ if (j == i)
+ continue;
+
+ FuncDeclaration *fd2 = d->vtbl[j]->isFuncDeclaration ();
+ if (!fd2->ident->equals (fd->ident))
+ continue;
+
+ /* The function is marked as @__future, a deprecation has
+ already been given by the frontend. */
+ if (fd2->isFuture ())
+ continue;
+
+ if (fd->leastAsSpecialized (fd2) || fd2->leastAsSpecialized (fd))
+ {
+ TypeFunction *tf = (TypeFunction *) fd->type;
+ if (tf->ty == Tfunction)
+ {
+ error_at (make_location_t (fd->loc), "use of %qs",
+ fd->toPrettyChars ());
+ inform (make_location_t (fd2->loc), "is hidden by %qs",
+ fd2->toPrettyChars ());
+ inform (make_location_t (d->loc),
+ "use %<alias %s = %s.%s;%> to introduce base class "
+ "overload set.", fd->toChars (),
+ fd->parent->toChars (), fd->toChars ());
+ }
+ else
+ {
+ error_at (make_location_t (fd->loc), "use of %qs",
+ fd->toPrettyChars ());
+ inform (make_location_t (fd2->loc), "is hidden by %qs",
+ fd2->toPrettyChars ());
+ }
+
+ has_errors = true;
+ break;
+ }
+ }
+ }
+
+ return !has_errors;
+ }
+
+ /* Write out compiler generated TypeInfo, initializer and vtables for the
+ given class declaration, walking over all static members. */
+
+ void visit (ClassDeclaration *d)
+ {
+ if (d->type->ty == Terror)
+ {
+ error_at (make_location_t (d->loc),
+ "had semantic errors when compiling");
+ return;
+ }
+
+ if (!d->members)
+ return;
+
+ /* Put out the members. */
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *member = (*d->members)[i];
+ member->accept (this);
+ }
+
+ /* If something goes wrong during final semantic pass, don't bother with
+ the rest as we may have incomplete info. */
+ if (!this->finish_vtable (d))
+ return;
+
+ /* Generate C symbols. */
+ d->csym = get_classinfo_decl (d);
+ d->vtblsym = get_vtable_decl (d);
+ d->sinit = aggregate_initializer_decl (d);
+
+ /* Generate static initializer. */
+ DECL_INITIAL (d->sinit) = layout_class_initializer (d);
+ d_linkonce_linkage (d->sinit);
+ d_finish_decl (d->sinit);
+
+ /* Put out the TypeInfo. */
+ create_typeinfo (d->type, NULL);
+ DECL_INITIAL (d->csym) = layout_classinfo (d);
+ d_linkonce_linkage (d->csym);
+ d_finish_decl (d->csym);
+
+ /* Put out the vtbl[]. */
+ vec<constructor_elt, va_gc> *elms = NULL;
+
+ /* First entry is ClassInfo reference. */
+ if (d->vtblOffset ())
+ CONSTRUCTOR_APPEND_ELT (elms, size_zero_node, build_address (d->csym));
+
+ for (size_t i = d->vtblOffset (); i < d->vtbl.dim; i++)
+ {
+ FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration ();
+
+ if (fd && (fd->fbody || !d->isAbstract()))
+ {
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+ build_address (get_symbol_decl (fd)));
+ }
+ }
+
+ DECL_INITIAL (d->vtblsym)
+ = build_constructor (TREE_TYPE (d->vtblsym), elms);
+ d_comdat_linkage (d->vtblsym);
+ d_finish_decl (d->vtblsym);
+
+ /* Add this decl to the current binding level. */
+ tree ctype = TREE_TYPE (build_ctype (d->type));
+ if (TYPE_NAME (ctype))
+ d_pushdecl (TYPE_NAME (ctype));
+ }
+
+ /* Write out compiler generated TypeInfo and vtables for the given interface
+ declaration, walking over all static members. */
+
+ void visit (InterfaceDeclaration *d)
+ {
+ if (d->type->ty == Terror)
+ {
+ error_at (make_location_t (d->loc),
+ "had semantic errors when compiling");
+ return;
+ }
+
+ if (!d->members)
+ return;
+
+ /* Put out the members. */
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *member = (*d->members)[i];
+ member->accept (this);
+ }
+
+ /* Generate C symbols. */
+ d->csym = get_classinfo_decl (d);
+
+ /* Put out the TypeInfo. */
+ create_typeinfo (d->type, NULL);
+ d->type->vtinfo->accept (this);
+
+ DECL_INITIAL (d->csym) = layout_classinfo (d);
+ d_linkonce_linkage (d->csym);
+ d_finish_decl (d->csym);
+
+ /* Add this decl to the current binding level. */
+ tree ctype = TREE_TYPE (build_ctype (d->type));
+ if (TYPE_NAME (ctype))
+ d_pushdecl (TYPE_NAME (ctype));
+ }
+
+ /* Write out compiler generated TypeInfo and initializer for the given
+ enum declaration. */
+
+ void visit (EnumDeclaration *d)
+ {
+ if (d->semanticRun >= PASSobj)
+ return;
+
+ if (d->errors || d->type->ty == Terror)
+ {
+ error_at (make_location_t (d->loc),
+ "had semantic errors when compiling");
+ return;
+ }
+
+ if (d->isAnonymous ())
+ return;
+
+ /* Generate TypeInfo. */
+ create_typeinfo (d->type, NULL);
+
+ TypeEnum *tc = (TypeEnum *) d->type;
+ if (tc->sym->members && !d->type->isZeroInit ())
+ {
+ /* Generate static initializer. */
+ d->sinit = enum_initializer_decl (d);
+ DECL_INITIAL (d->sinit) = build_expr (tc->sym->defaultval, true);
+
+ if (d->isInstantiated ())
+ d_linkonce_linkage (d->sinit);
+
+ d_finish_decl (d->sinit);
+
+ /* Add this decl to the current binding level. */
+ tree ctype = build_ctype (d->type);
+ if (TREE_CODE (ctype) == ENUMERAL_TYPE && TYPE_NAME (ctype))
+ d_pushdecl (TYPE_NAME (ctype));
+ }
+
+ d->semanticRun = PASSobj;
+ }
+
+ /* Finish up a variable declaration and push it into the current scope.
+ This can either be a static, local or manifest constant. */
+
+ void visit (VarDeclaration *d)
+ {
+ if (d->type->ty == Terror)
+ {
+ error_at (make_location_t (d->loc),
+ "had semantic errors when compiling");
+ return;
+ }
+
+ if (d->aliassym)
+ {
+ d->toAlias ()->accept (this);
+ return;
+ }
+
+ /* Do not store variables we cannot take the address of,
+ but keep the values for purposes of debugging. */
+ if (!d->canTakeAddressOf ())
+ {
+ /* Don't know if there is a good way to handle instantiations. */
+ if (d->isInstantiated ())
+ return;
+
+ tree decl = get_symbol_decl (d);
+ gcc_assert (d->_init && !d->_init->isVoidInitializer ());
+ Expression *ie = initializerToExpression (d->_init);
+
+ /* CONST_DECL was initially intended for enumerals and may be used for
+ scalars in general, but not for aggregates. Here a non-constant
+ value is generated anyway so as the CONST_DECL only serves as a
+ placeholder for the value, however the DECL itself should never be
+ referenced in any generated code, or passed to the back-end. */
+ if (!d->type->isscalar ())
+ DECL_INITIAL (decl) = build_expr (ie, false);
+ else
+ {
+ DECL_INITIAL (decl) = build_expr (ie, true);
+ d_pushdecl (decl);
+ rest_of_decl_compilation (decl, 1, 0);
+ }
+ }
+ else if (d->isDataseg () && !(d->storage_class & STCextern))
+ {
+ tree decl = get_symbol_decl (d);
+
+ /* Duplicated VarDeclarations map to the same symbol. Check if this
+ is the one declaration which will be emitted. */
+ tree ident = DECL_ASSEMBLER_NAME (decl);
+ if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d)
+ return;
+
+ /* How big a symbol can be should depend on back-end. */
+ tree size = build_integer_cst (d->type->size (d->loc),
+ build_ctype (Type::tsize_t));
+ if (!valid_constant_size_p (size))
+ {
+ error_at (make_location_t (d->loc), "size is too large");
+ return;
+ }
+
+ if (d->_init && !d->_init->isVoidInitializer ())
+ {
+ Expression *e = initializerToExpression (d->_init, d->type);
+ DECL_INITIAL (decl) = build_expr (e, true);
+ }
+ else
+ {
+ if (d->type->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *) d->type)->sym;
+ DECL_INITIAL (decl) = layout_struct_initializer (sd);
+ }
+ else
+ {
+ Expression *e = d->type->defaultInitLiteral (d->loc);
+ DECL_INITIAL (decl) = build_expr (e, true);
+ }
+ }
+
+ /* Frontend should have already caught this. */
+ gcc_assert (!integer_zerop (size)
+ || d->type->toBasetype ()->ty == Tsarray);
+
+ d_finish_decl (decl);
+
+ /* Maybe record the var against the current module. */
+ register_module_decl (d);
+ }
+ else if (!d->isDataseg () && !d->isMember ())
+ {
+ /* This is needed for VarDeclarations in mixins that are to be local
+ variables of a function. Otherwise, it would be enough to make
+ a check for isVarDeclaration() in DeclarationExp codegen. */
+ declare_local_var (d);
+
+ if (d->_init)
+ {
+ tree decl = get_symbol_decl (d);
+
+ if (!d->_init->isVoidInitializer ())
+ {
+ ExpInitializer *vinit = d->_init->isExpInitializer ();
+ Expression *ie = initializerToExpression (vinit);
+ tree exp = build_expr (ie);
+
+ /* Maybe put variable on list of things needing destruction. */
+ if (d->needsScopeDtor ())
+ {
+ vec_safe_push (d_function_chain->vars_in_scope, decl);
+ /* Force a TARGET_EXPR to add the corresponding cleanup. */
+ exp = force_target_expr (compound_expr (exp, decl));
+ TARGET_EXPR_CLEANUP (exp) = build_expr (d->edtor);
+ }
+
+ add_stmt (exp);
+ }
+ else if (d->size (d->loc) != 0)
+ {
+ /* Zero-length arrays do not have an initializer. */
+ warning (OPT_Wuninitialized, "uninitialized variable '%s'",
+ d->ident ? d->ident->toChars () : "(no name)");
+ }
+ }
+ }
+ }
+
+ /* Generate and compile a static TypeInfo declaration, but only if it is
+ needed in the current compilation. */
+
+ void visit (TypeInfoDeclaration *d)
+ {
+ if (speculative_type_p (d->tinfo))
+ return;
+
+ tree t = get_typeinfo_decl (d);
+ DECL_INITIAL (t) = layout_typeinfo (d);
+ d_finish_decl (t);
+ }
+
+ /* Finish up a function declaration and compile it all the way
+ down to assembler language output. */
+
+ void visit (FuncDeclaration *d)
+ {
+ /* Already generated the function. */
+ if (d->semanticRun >= PASSobj)
+ return;
+
+ /* Don't emit any symbols from gcc.attribute module. */
+ if (gcc_attribute_p (d))
+ return;
+
+ /* Not emitting unittest functions. */
+ if (!global.params.useUnitTests && d->isUnitTestDeclaration ())
+ return;
+
+ /* Check if any errors occurred when running semantic. */
+ if (d->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *) d->type;
+ if (tf->next == NULL || tf->next->ty == Terror)
+ return;
+ }
+
+ if (d->semantic3Errors)
+ return;
+
+ if (d->isNested ())
+ {
+ FuncDeclaration *fdp = d;
+ while (fdp && fdp->isNested ())
+ {
+ fdp = fdp->toParent2 ()->isFuncDeclaration ();
+
+ if (fdp == NULL)
+ break;
+
+ /* Parent failed to compile, but errors were gagged. */
+ if (fdp->semantic3Errors)
+ return;
+ }
+ }
+
+ /* Ensure all semantic passes have run. */
+ if (d->semanticRun < PASSsemantic3)
+ {
+ d->functionSemantic3 ();
+ Module::runDeferredSemantic3 ();
+ }
+
+ if (global.errors)
+ return;
+
+ /* Duplicated FuncDeclarations map to the same symbol. Check if this
+ is the one declaration which will be emitted. */
+ tree fndecl = get_symbol_decl (d);
+ tree ident = DECL_ASSEMBLER_NAME (fndecl);
+ if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d)
+ return;
+
+ if (!d->fbody)
+ {
+ rest_of_decl_compilation (fndecl, 1, 0);
+ return;
+ }
+
+ if (global.params.verbose)
+ message ("function %s", d->toPrettyChars ());
+
+ /* Start generating code for this function. */
+ gcc_assert (d->semanticRun == PASSsemantic3done);
+ d->semanticRun = PASSobj;
+
+ tree old_context = start_function (d);
+
+ tree parm_decl = NULL_TREE;
+ tree param_list = NULL_TREE;
+
+ /* Special arguments... */
+
+ /* 'this' parameter:
+ For nested functions, D still generates a vthis, but it
+ should not be referenced in any expression. */
+ if (d->vthis)
+ {
+ parm_decl = get_symbol_decl (d->vthis);
+ DECL_ARTIFICIAL (parm_decl) = 1;
+ TREE_READONLY (parm_decl) = 1;
+
+ if (d->vthis->type == Type::tvoidptr)
+ {
+ /* Replace generic pointer with back-end closure type
+ (this wins for gdb). */
+ tree frame_type = FRAMEINFO_TYPE (get_frameinfo (d));
+ gcc_assert (frame_type != NULL_TREE);
+ TREE_TYPE (parm_decl) = build_pointer_type (frame_type);
+ }
+
+ param_list = chainon (param_list, parm_decl);
+ d_function_chain->static_chain = parm_decl;
+ }
+
+ /* _arguments parameter. */
+ if (d->v_arguments)
+ {
+ parm_decl = get_symbol_decl (d->v_arguments);
+ param_list = chainon (param_list, parm_decl);
+ }
+
+ /* formal function parameters. */
+ size_t n_parameters = d->parameters ? d->parameters->dim : 0;
+
+ for (size_t i = 0; i < n_parameters; i++)
+ {
+ VarDeclaration *param = (*d->parameters)[i];
+ parm_decl = get_symbol_decl (param);
+ /* Chain them in the correct order. */
+ param_list = chainon (param_list, parm_decl);
+ }
+
+ DECL_ARGUMENTS (fndecl) = param_list;
+ rest_of_decl_compilation (fndecl, 1, 0);
+
+ /* If this is a member function that nested (possibly indirectly) in another
+ function, construct an expession for this member function's static chain
+ by going through parent link of nested classes. */
+ if (d->isThis ())
+ {
+ AggregateDeclaration *ad = d->isThis ();
+ tree this_tree = get_symbol_decl (d->vthis);
+
+ while (ad->isNested ())
+ {
+ Dsymbol *pd = ad->toParent2 ();
+ tree vthis_field = get_symbol_decl (ad->vthis);
+ this_tree = component_ref (build_deref (this_tree), vthis_field);
+
+ ad = pd->isAggregateDeclaration ();
+ if (ad == NULL)
+ {
+ cfun->language->static_chain = this_tree;
+ break;
+ }
+ }
+ }
+
+ /* May change cfun->static_chain. */
+ build_closure (d);
+
+ if (d->vresult)
+ declare_local_var (d->vresult);
+
+ if (d->v_argptr)
+ push_stmt_list ();
+
+ /* Named return value optimisation support for D.
+ Implemented by overriding all the RETURN_EXPRs and replacing all
+ occurrences of VAR with the RESULT_DECL for the function.
+ This is only worth doing for functions that can return in memory. */
+ if (d->nrvo_can)
+ {
+ tree restype = TREE_TYPE (DECL_RESULT (fndecl));
+
+ if (!AGGREGATE_TYPE_P (restype))
+ d->nrvo_can = 0;
+ else
+ d->nrvo_can = aggregate_value_p (restype, fndecl);
+ }
+
+ if (d->nrvo_can)
+ {
+ tree resdecl = DECL_RESULT (fndecl);
+
+ TREE_TYPE (resdecl)
+ = build_reference_type (TREE_TYPE (resdecl));
+ DECL_BY_REFERENCE (resdecl) = 1;
+ TREE_ADDRESSABLE (resdecl) = 0;
+ relayout_decl (resdecl);
+
+ if (d->nrvo_var)
+ {
+ tree var = get_symbol_decl (d->nrvo_var);
+
+ /* Copy name from VAR to RESULT. */
+ DECL_NAME (resdecl) = DECL_NAME (var);
+ /* Don't forget that we take its address. */
+ TREE_ADDRESSABLE (var) = 1;
+ resdecl = build_deref (resdecl);
+
+ SET_DECL_VALUE_EXPR (var, resdecl);
+ DECL_HAS_VALUE_EXPR_P (var) = 1;
+ SET_DECL_LANG_NRVO (var, resdecl);
+ }
+ }
+
+ build_function_body (d);
+
+ /* Initialize the _argptr variable. */
+ if (d->v_argptr)
+ {
+ tree body = pop_stmt_list ();
+ tree var = get_decl_tree (d->v_argptr);
+ var = build_address (var);
+
+ tree init = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_START),
+ 2, var, parm_decl);
+ declare_local_var (d->v_argptr);
+ add_stmt (init);
+
+ tree cleanup = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_END),
+ 1, var);
+ add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, body, cleanup));
+ }
+
+ finish_function (old_context);
+
+ /* Maybe record the function against the current module. */
+ register_module_decl (d);
+ }
+};
+
+/* Main entry point for the DeclVisitor interface to send
+ the Declaration AST class D to GCC back-end. */
+
+void
+build_decl_tree (Dsymbol *d)
+{
+ location_t saved_location = input_location;
+
+ /* Set input location, empty DECL_SOURCE_FILE can crash debug generator. */
+ if (d->loc.filename)
+ input_location = make_location_t (d->loc);
+ else
+ input_location = make_location_t (Loc ("<no_file>", 1, 0));
+
+ DeclVisitor v = DeclVisitor ();
+ d->accept (&v);
+
+ input_location = saved_location;
+}
+
+/* Return the decl for the symbol, create it if it doesn't already exist. */
+
+tree
+get_symbol_decl (Declaration *decl)
+{
+ if (decl->csym)
+ return decl->csym;
+
+ /* Deal with placeholder symbols immediately:
+ SymbolDeclaration is used as a shell around an initializer symbol. */
+ SymbolDeclaration *sd = decl->isSymbolDeclaration ();
+ if (sd)
+ {
+ decl->csym = aggregate_initializer_decl (sd->dsym);
+ return decl->csym;
+ }
+
+ /* Global static TypeInfo declaration. */
+ if (decl->isTypeInfoDeclaration ())
+ return get_typeinfo_decl ((TypeInfoDeclaration *) decl);
+
+ /* FuncAliasDeclaration is used to import functions from another scope. */
+ FuncAliasDeclaration *fad = decl->isFuncAliasDeclaration ();
+ if (fad)
+ {
+ decl->csym = get_symbol_decl (fad->funcalias);
+ return decl->csym;
+ }
+
+ /* It is possible for a field declaration symbol to be requested
+ before the parent type has been built. */
+ if (decl->isField ())
+ {
+ AggregateDeclaration *ad = decl->toParent ()->isAggregateDeclaration ();
+ gcc_assert (ad != NULL);
+
+ /* Finishing off the type should create the associated FIELD_DECL. */
+ build_ctype (ad->type);
+ gcc_assert (decl->csym != NULL);
+
+ return decl->csym;
+ }
+
+ /* Build the tree for the symbol. */
+ FuncDeclaration *fd = decl->isFuncDeclaration ();
+ if (fd)
+ {
+ /* Run full semantic on functions we need to know about. */
+ if (!fd->functionSemantic ())
+ {
+ decl->csym = error_mark_node;
+ return decl->csym;
+ }
+
+ decl->csym = build_decl (make_location_t (decl->loc), FUNCTION_DECL,
+ get_identifier (decl->ident->toChars ()),
+ NULL_TREE);
+
+ /* Set function type afterwards as there could be self references. */
+ TREE_TYPE (decl->csym) = build_ctype (fd->type);
+
+ if (!fd->fbody)
+ DECL_EXTERNAL (decl->csym) = 1;
+ }
+ else
+ {
+ /* Build the variable declaration. */
+ VarDeclaration *vd = decl->isVarDeclaration ();
+ gcc_assert (vd != NULL);
+
+ tree_code code = vd->isParameter () ? PARM_DECL
+ : !vd->canTakeAddressOf () ? CONST_DECL
+ : VAR_DECL;
+ decl->csym = build_decl (make_location_t (decl->loc), code,
+ get_identifier (decl->ident->toChars ()),
+ declaration_type (vd));
+
+ /* If any alignment was set on the declaration. */
+ if (vd->alignment != STRUCTALIGN_DEFAULT)
+ {
+ SET_DECL_ALIGN (decl->csym, vd->alignment * BITS_PER_UNIT);
+ DECL_USER_ALIGN (decl->csym) = 1;
+ }
+
+ if (vd->storage_class & STCextern)
+ DECL_EXTERNAL (decl->csym) = 1;
+ }
+
+ /* Set the declaration mangled identifier if static. */
+ if (decl->isCodeseg () || decl->isDataseg ())
+ {
+ tree mangled_name;
+
+ if (decl->mangleOverride)
+ mangled_name = get_identifier (decl->mangleOverride);
+ else
+ mangled_name = get_identifier (mangle_decl (decl));
+
+ mangled_name = targetm.mangle_decl_assembler_name (decl->csym,
+ mangled_name);
+ /* The frontend doesn't handle duplicate definitions of unused symbols
+ with the same mangle. So a check is done here instead. */
+ if (!DECL_EXTERNAL (decl->csym))
+ {
+ if (IDENTIFIER_DSYMBOL (mangled_name))
+ {
+ Declaration *other = IDENTIFIER_DSYMBOL (mangled_name);
+
+ /* Non-templated variables shouldn't be defined twice. */
+ if (!decl->isInstantiated ())
+ ScopeDsymbol::multiplyDefined (decl->loc, decl, other);
+
+ decl->csym = get_symbol_decl (other);
+ return decl->csym;
+ }
+
+ IDENTIFIER_PRETTY_NAME (mangled_name)
+ = get_identifier (decl->toPrettyChars (true));
+ IDENTIFIER_DSYMBOL (mangled_name) = decl;
+ }
+
+ SET_DECL_ASSEMBLER_NAME (decl->csym, mangled_name);
+ }
+
+ DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (decl);
+ DECL_CONTEXT (decl->csym) = d_decl_context (decl);
+
+ if (TREE_CODE (decl->csym) == PARM_DECL)
+ {
+ /* Pass non-trivial structs by invisible reference. */
+ if (TREE_ADDRESSABLE (TREE_TYPE (decl->csym)))
+ {
+ tree argtype = build_reference_type (TREE_TYPE (decl->csym));
+ argtype = build_qualified_type (argtype, TYPE_QUAL_RESTRICT);
+ gcc_assert (!DECL_BY_REFERENCE (decl->csym));
+ TREE_TYPE (decl->csym) = argtype;
+ DECL_BY_REFERENCE (decl->csym) = 1;
+ TREE_ADDRESSABLE (decl->csym) = 0;
+ relayout_decl (decl->csym);
+ decl->storage_class |= STCref;
+ }
+
+ DECL_ARG_TYPE (decl->csym) = TREE_TYPE (decl->csym);
+ gcc_assert (TREE_CODE (DECL_CONTEXT (decl->csym)) == FUNCTION_DECL);
+ }
+ else if (TREE_CODE (decl->csym) == CONST_DECL)
+ {
+ /* Manifest constants have no address in memory. */
+ TREE_CONSTANT (decl->csym) = 1;
+ TREE_READONLY (decl->csym) = 1;
+ }
+ else if (TREE_CODE (decl->csym) == FUNCTION_DECL)
+ {
+ /* The real function type may differ from its declaration. */
+ tree fntype = TREE_TYPE (decl->csym);
+ tree newfntype = NULL_TREE;
+
+ if (fd->isNested ())
+ {
+ /* Add an extra argument for the frame/closure pointer, this is also
+ required to be compatible with D delegates. */
+ newfntype = build_vthis_function (void_type_node, fntype);
+ }
+ else if (fd->isThis ())
+ {
+ /* Add an extra argument for the 'this' parameter. The handle type is
+ used even if there is no debug info. It is needed to make sure
+ virtual member functions are not called statically. */
+ AggregateDeclaration *ad = fd->isMember2 ();
+ tree handle = build_ctype (ad->handleType ());
+
+ /* If handle is a pointer type, get record type. */
+ if (!ad->isStructDeclaration ())
+ handle = TREE_TYPE (handle);
+
+ newfntype = build_vthis_function (handle, fntype);
+
+ /* Set the vindex on virtual functions. */
+ if (fd->isVirtual () && fd->vtblIndex != -1)
+ {
+ DECL_VINDEX (decl->csym) = size_int (fd->vtblIndex);
+ DECL_VIRTUAL_P (decl->csym) = 1;
+ }
+ }
+ else if (fd->isMain () || fd->isCMain ())
+ {
+ /* The main function is named 'D main' to distinguish from C main. */
+ if (fd->isMain ())
+ DECL_NAME (decl->csym) = get_identifier (fd->toPrettyChars (true));
+
+ /* 'void main' is implicitly converted to returning an int. */
+ newfntype = build_function_type (d_int_type, TYPE_ARG_TYPES (fntype));
+ }
+
+ if (newfntype != NULL_TREE)
+ {
+ /* Copy the old attributes from the original type. */
+ TYPE_ATTRIBUTES (newfntype) = TYPE_ATTRIBUTES (fntype);
+ TYPE_LANG_SPECIFIC (newfntype) = TYPE_LANG_SPECIFIC (fntype);
+ TREE_ADDRESSABLE (newfntype) = TREE_ADDRESSABLE (fntype);
+ TREE_TYPE (decl->csym) = newfntype;
+ d_keep (newfntype);
+ }
+
+ /* Miscellaneous function flags. */
+ if (fd->isMember2 () || fd->isFuncLiteralDeclaration ())
+ {
+ /* See grokmethod in cp/decl.c. Maybe we shouldn't be setting inline
+ flags without reason or proper handling. */
+ DECL_DECLARED_INLINE_P (decl->csym) = 1;
+ DECL_NO_INLINE_WARNING_P (decl->csym) = 1;
+ }
+
+ /* Function was declared 'naked'. */
+ if (fd->naked)
+ {
+ insert_decl_attribute (decl->csym, "naked");
+ DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1;
+ }
+
+ /* Vector array operations are always compiler generated. */
+ if (fd->isArrayOp)
+ {
+ TREE_PUBLIC (decl->csym) = 1;
+ DECL_ARTIFICIAL (decl->csym) = 1;
+ DECL_DECLARED_INLINE_P (decl->csym) = 1;
+ d_comdat_linkage (decl->csym);
+ }
+
+ /* And so are ensure and require contracts. */
+ if (fd->ident == Identifier::idPool ("ensure")
+ || fd->ident == Identifier::idPool ("require"))
+ {
+ DECL_ARTIFICIAL (decl->csym) = 1;
+ TREE_PUBLIC (decl->csym) = 1;
+ }
+
+ if (decl->storage_class & STCfinal)
+ DECL_FINAL_P (decl->csym) = 1;
+
+ /* Check whether this function is expanded by the frontend. */
+ DECL_INTRINSIC_CODE (decl->csym) = INTRINSIC_NONE;
+ maybe_set_intrinsic (fd);
+
+ /* For nested functions in particular, unnest fndecl in the cgraph, as
+ all static chain passing is handled by the front-end. Do this even
+ if we are not emitting the body. */
+ struct cgraph_node *node = cgraph_node::get_create (decl->csym);
+ if (node->origin)
+ node->unnest ();
+ }
+
+ /* Mark compiler generated temporaries as artificial. */
+ if (decl->storage_class & STCtemp)
+ DECL_ARTIFICIAL (decl->csym) = 1;
+
+ /* Propagate shared on the decl. */
+ if (TYPE_SHARED (TREE_TYPE (decl->csym)))
+ TREE_ADDRESSABLE (decl->csym) = 1;
+
+ /* Symbol was marked volatile. */
+ if (decl->storage_class & STCvolatile)
+ TREE_THIS_VOLATILE (decl->csym) = 1;
+
+ /* Protection attributes are used by the debugger. */
+ if (decl->protection.kind == PROTprivate)
+ TREE_PRIVATE (decl->csym) = 1;
+ else if (decl->protection.kind == PROTprotected)
+ TREE_PROTECTED (decl->csym) = 1;
+
+ /* Likewise, so could the deprecated attribute. */
+ if (decl->storage_class & STCdeprecated)
+ TREE_DEPRECATED (decl->csym) = 1;
+
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+ /* Have to test for import first. */
+ if (decl->isImportedSymbol ())
+ {
+ insert_decl_attribute (decl->csym, "dllimport");
+ DECL_DLLIMPORT_P (decl->csym) = 1;
+ }
+ else if (decl->isExport ())
+ insert_decl_attribute (decl->csym, "dllexport");
+#endif
+
+ if (decl->isDataseg () || decl->isCodeseg () || decl->isThreadlocal ())
+ {
+ /* Set TREE_PUBLIC by default, but allow private template to override. */
+ if (!fd || !fd->isNested ())
+ TREE_PUBLIC (decl->csym) = 1;
+
+ TREE_STATIC (decl->csym) = 1;
+ /* The decl has not been defined -- yet. */
+ DECL_EXTERNAL (decl->csym) = 1;
+
+ if (decl->isInstantiated ())
+ d_linkonce_linkage (decl->csym);
+ }
+
+ /* Symbol is going in thread local storage. */
+ if (decl->isThreadlocal () && !DECL_ARTIFICIAL (decl->csym))
+ {
+ if (global.params.vtls)
+ message (decl->loc, "`%s` is thread local", decl->toChars ());
+
+ set_decl_tls_model (decl->csym, decl_default_tls_model (decl->csym));
+ }
+
+ /* Apply any user attributes that may affect semantic meaning. */
+ if (decl->userAttribDecl)
+ {
+ Expressions *attrs = decl->userAttribDecl->getAttributes ();
+ decl_attributes (&decl->csym, build_attributes (attrs), 0);
+ }
+ else if (DECL_ATTRIBUTES (decl->csym) != NULL)
+ decl_attributes (&decl->csym, DECL_ATTRIBUTES (decl->csym), 0);
+
+ /* %% Probably should be a little more intelligent about setting this. */
+ TREE_USED (decl->csym) = 1;
+ d_keep (decl->csym);
+
+ return decl->csym;
+}
+
+/* Returns a declaration for a VAR_DECL. Used to create compiler-generated
+ global variables. */
+
+tree
+declare_extern_var (tree ident, tree type)
+{
+ /* If the VAR_DECL has already been declared, return it. */
+ if (IDENTIFIER_DECL_TREE (ident))
+ return IDENTIFIER_DECL_TREE (ident);
+
+ tree name = IDENTIFIER_PRETTY_NAME (ident)
+ ? IDENTIFIER_PRETTY_NAME (ident) : ident;
+ tree decl = build_decl (input_location, VAR_DECL, name, type);
+
+ IDENTIFIER_DECL_TREE (ident) = decl;
+ d_keep (decl);
+
+ SET_DECL_ASSEMBLER_NAME (decl, ident);
+ DECL_ARTIFICIAL (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+
+ /* The decl has not been defined -- yet. */
+ DECL_EXTERNAL (decl) = 1;
+
+ return decl;
+}
+
+/* Add local variable VAR into the current function body. */
+
+void
+declare_local_var (VarDeclaration *var)
+{
+ gcc_assert (!var->isDataseg () && !var->isMember ());
+ gcc_assert (current_function_decl != NULL_TREE);
+
+ FuncDeclaration *fd = cfun->language->function;
+ tree decl = get_symbol_decl (var);
+
+ gcc_assert (!TREE_STATIC (decl));
+ d_pushdecl (decl);
+ DECL_CONTEXT (decl) = current_function_decl;
+
+ /* Compiler generated symbols. */
+ if (var == fd->vresult || var == fd->v_argptr)
+ DECL_ARTIFICIAL (decl) = 1;
+
+ if (DECL_LANG_FRAME_FIELD (decl))
+ {
+ /* Fixes debugging local variables. */
+ SET_DECL_VALUE_EXPR (decl, get_decl_tree (var));
+ DECL_HAS_VALUE_EXPR_P (decl) = 1;
+ }
+}
+
+/* Return an unnamed local temporary of type TYPE. */
+
+tree
+build_local_temp (tree type)
+{
+ tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type);
+
+ DECL_CONTEXT (decl) = current_function_decl;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ d_pushdecl (decl);
+
+ return decl;
+}
+
+/* Return the correct decl to be used for DECL. For VAR_DECLs, this could
+ instead be a FIELD_DECL from a closure, or a RESULT_DECL from a named return
+ value. For PARM_DECLs, this could be a FIELD_DECL for a non-local `this'.
+ For all other kinds of decls, this just returns the result of
+ get_symbol_decl(). */
+
+tree
+get_decl_tree (Declaration *decl)
+{
+ tree t = get_symbol_decl (decl);
+ FuncDeclaration *fd = cfun ? cfun->language->function : NULL;
+ VarDeclaration *vd = decl->isVarDeclaration ();
+
+ /* If cfun is NULL, then this is a global static. */
+ if (vd == NULL || fd == NULL)
+ return t;
+
+ /* Get the named return value. */
+ if (DECL_LANG_NRVO (t))
+ return DECL_LANG_NRVO (t);
+
+ /* Get the closure holding the var decl. */
+ if (DECL_LANG_FRAME_FIELD (t))
+ {
+ FuncDeclaration *parent = vd->toParent2 ()->isFuncDeclaration ();
+ tree frame_ref = get_framedecl (fd, parent);
+
+ return component_ref (build_deref (frame_ref),
+ DECL_LANG_FRAME_FIELD (t));
+ }
+
+ /* Get the non-local 'this' value by going through parent link
+ of nested classes, this routine pretty much undoes what
+ getRightThis in the frontend removes from codegen. */
+ if (vd->parent != fd && vd->isThisDeclaration ())
+ {
+ /* Find the first parent that is a member function. */
+ while (!fd->isMember2 ())
+ {
+ gcc_assert (fd->vthis);
+ fd = fd->toParent2 ()->isFuncDeclaration ();
+ gcc_assert (fd != NULL);
+ }
+
+ AggregateDeclaration *ad = fd->isThis ();
+ gcc_assert (ad != NULL);
+
+ t = get_decl_tree (fd->vthis);
+ Dsymbol *outer = fd;
+
+ while (outer != vd->parent)
+ {
+ gcc_assert (ad != NULL);
+ outer = ad->toParent2 ();
+
+ /* Get the this->this parent link. */
+ tree vfield = get_symbol_decl (ad->vthis);
+ t = component_ref (build_deref (t), vfield);
+
+ ad = outer->isAggregateDeclaration ();
+ if (ad != NULL)
+ continue;
+
+ fd = outer->isFuncDeclaration ();
+ while (fd != NULL)
+ {
+ /* If outer function creates a closure, then the 'this'
+ value would be the closure pointer, and the real
+ 'this' the first field of that closure. */
+ tree ff = get_frameinfo (fd);
+ if (FRAMEINFO_CREATES_FRAME (ff))
+ {
+ t = build_nop (build_pointer_type (FRAMEINFO_TYPE (ff)), t);
+ t = indirect_ref (build_ctype (fd->vthis->type), t);
+ }
+
+ if (fd == vd->parent)
+ break;
+
+ /* Continue looking for the right `this'. */
+ outer = outer->toParent2 ();
+ fd = outer->isFuncDeclaration ();
+ }
+
+ ad = outer->isAggregateDeclaration ();
+ }
+
+ return t;
+ }
+
+ /* Auto variable that the back end will handle for us. */
+ return t;
+}
+
+/* Finish up a variable declaration and compile it all the way to
+ the assembler language output. */
+
+void
+d_finish_decl (tree decl)
+{
+ gcc_assert (!error_operand_p (decl));
+
+ /* We are sending this symbol to object file, can't be extern. */
+ TREE_STATIC (decl) = 1;
+ DECL_EXTERNAL (decl) = 0;
+
+ /* Update the TLS model as the linkage has been modified. */
+ if (DECL_THREAD_LOCAL_P (decl))
+ set_decl_tls_model (decl, decl_default_tls_model (decl));
+
+ relayout_decl (decl);
+
+ if (flag_checking && DECL_INITIAL (decl))
+ {
+ /* Initializer must never be bigger than symbol size. */
+ dinteger_t tsize = int_size_in_bytes (TREE_TYPE (decl));
+ dinteger_t dtsize = int_size_in_bytes (TREE_TYPE (DECL_INITIAL (decl)));
+
+ if (tsize < dtsize)
+ {
+ tree name = DECL_ASSEMBLER_NAME (decl);
+
+ internal_error ("Mismatch between declaration %qE size (%wd) and "
+ "its initializer size (%wd).",
+ IDENTIFIER_PRETTY_NAME (name)
+ ? IDENTIFIER_PRETTY_NAME (name) : name,
+ tsize, dtsize);
+ }
+ }
+
+ /* Without weak symbols, symbol should be put in .common, but that can't
+ be done if there is a nonzero initializer. */
+ if (DECL_COMDAT (decl) && DECL_COMMON (decl)
+ && initializer_zerop (DECL_INITIAL (decl)))
+ DECL_INITIAL (decl) = error_mark_node;
+
+ /* Add this decl to the current binding level. */
+ d_pushdecl (decl);
+
+ rest_of_decl_compilation (decl, 1, 0);
+}
+
+/* Thunk code is based on g++. */
+
+static int thunk_labelno;
+
+/* Create a static alias to function. */
+
+static tree
+make_alias_for_thunk (tree function)
+{
+ tree alias;
+ char buf[256];
+
+ /* Thunks may reference extern functions which cannot be aliased. */
+ if (DECL_EXTERNAL (function))
+ return function;
+
+ targetm.asm_out.generate_internal_label (buf, "LTHUNK", thunk_labelno);
+ thunk_labelno++;
+
+ alias = build_decl (DECL_SOURCE_LOCATION (function), FUNCTION_DECL,
+ get_identifier (buf), TREE_TYPE (function));
+ DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
+ lang_hooks.dup_lang_specific_decl (alias);
+ DECL_CONTEXT (alias) = NULL_TREE;
+ TREE_READONLY (alias) = TREE_READONLY (function);
+ TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
+ TREE_PUBLIC (alias) = 0;
+
+ DECL_EXTERNAL (alias) = 0;
+ DECL_ARTIFICIAL (alias) = 1;
+
+ DECL_DECLARED_INLINE_P (alias) = 0;
+ DECL_INITIAL (alias) = error_mark_node;
+ DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (function));
+
+ TREE_ADDRESSABLE (alias) = 1;
+ TREE_USED (alias) = 1;
+ SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
+
+ if (!flag_syntax_only)
+ {
+ cgraph_node *aliasn;
+ aliasn = cgraph_node::create_same_body_alias (alias, function);
+ gcc_assert (aliasn != NULL);
+ }
+ return alias;
+}
+
+/* Emit the definition of a D vtable thunk. */
+
+static void
+finish_thunk (tree thunk, tree function)
+{
+ /* Setup how D thunks are outputted. */
+ int fixed_offset = -THUNK_LANG_OFFSET (thunk);
+ bool this_adjusting = true;
+ tree alias;
+
+ if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
+ alias = make_alias_for_thunk (function);
+ else
+ alias = function;
+
+ TREE_ADDRESSABLE (function) = 1;
+ TREE_USED (function) = 1;
+
+ if (flag_syntax_only)
+ {
+ TREE_ASM_WRITTEN (thunk) = 1;
+ return;
+ }
+
+ if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
+ && targetm_common.have_named_sections)
+ {
+ tree fn = function;
+ symtab_node *symbol = symtab_node::get (function);
+
+ if (symbol != NULL && symbol->alias)
+ {
+ if (symbol->analyzed)
+ fn = symtab_node::get (function)->ultimate_alias_target ()->decl;
+ else
+ fn = symtab_node::get (function)->alias_target;
+ }
+ resolve_unique_section (fn, 0, flag_function_sections);
+
+ if (DECL_SECTION_NAME (fn) != NULL && DECL_ONE_ONLY (fn))
+ {
+ resolve_unique_section (thunk, 0, flag_function_sections);
+
+ /* Output the thunk into the same section as function. */
+ set_decl_section_name (thunk, DECL_SECTION_NAME (fn));
+ symtab_node::get (thunk)->implicit_section
+ = symtab_node::get (fn)->implicit_section;
+ }
+ }
+
+ /* Set up cloned argument trees for the thunk. */
+ tree t = NULL_TREE;
+ for (tree a = DECL_ARGUMENTS (function); a; a = DECL_CHAIN (a))
+ {
+ tree x = copy_node (a);
+ DECL_CHAIN (x) = t;
+ DECL_CONTEXT (x) = thunk;
+ SET_DECL_RTL (x, NULL);
+ DECL_HAS_VALUE_EXPR_P (x) = 0;
+ TREE_ADDRESSABLE (x) = 0;
+ t = x;
+ }
+ DECL_ARGUMENTS (thunk) = nreverse (t);
+ TREE_ASM_WRITTEN (thunk) = 1;
+
+ cgraph_node *funcn, *thunk_node;
+
+ funcn = cgraph_node::get_create (function);
+ gcc_assert (funcn);
+ thunk_node = funcn->create_thunk (thunk, thunk, this_adjusting,
+ fixed_offset, 0, 0, 0, alias);
+
+ if (DECL_ONE_ONLY (function))
+ thunk_node->add_to_same_comdat_group (funcn);
+
+ /* Target assemble_mi_thunk doesn't work across section boundaries
+ on many targets, instead force thunk to be expanded in gimple. */
+ if (DECL_EXTERNAL (function))
+ {
+ /* cgraph::expand_thunk writes over current_function_decl, so if this
+ could ever be in use by the codegen pass, we want to know about it. */
+ gcc_assert (current_function_decl == NULL_TREE);
+
+ if (!stdarg_p (TREE_TYPE (thunk)))
+ {
+ thunk_node->create_edge (funcn, NULL, thunk_node->count);
+ thunk_node->expand_thunk (false, true);
+ }
+
+ /* Tell the back-end to not bother inlining the function, this is
+ assumed not to work as it could be referencing symbols outside
+ of the current compilation unit. */
+ DECL_UNINLINABLE (function) = 1;
+ }
+}
+
+/* Return a thunk to DECL. Thunks adjust the incoming `this' pointer by OFFSET.
+ Adjustor thunks are created and pointers to them stored in the method entries
+ in the vtable in order to set the this pointer to the start of the object
+ instance corresponding to the implementing method. */
+
+tree
+make_thunk (FuncDeclaration *decl, int offset)
+{
+ tree function = get_symbol_decl (decl);
+
+ if (!DECL_ARGUMENTS (function) || !DECL_RESULT (function))
+ {
+ /* Compile the function body before generating the thunk, this is done
+ even if the decl is external to the current module. */
+ if (decl->fbody)
+ build_decl_tree (decl);
+ else
+ {
+ /* Build parameters for functions that are not being compiled,
+ so that they can be correctly cloned in finish_thunk. */
+ tree fntype = TREE_TYPE (function);
+ tree params = NULL_TREE;
+
+ for (tree t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
+ {
+ if (t == void_list_node)
+ break;
+
+ tree param = build_decl (DECL_SOURCE_LOCATION (function),
+ PARM_DECL, NULL_TREE, TREE_VALUE (t));
+ DECL_ARG_TYPE (param) = TREE_TYPE (param);
+ DECL_ARTIFICIAL (param) = 1;
+ DECL_IGNORED_P (param) = 1;
+ DECL_CONTEXT (param) = function;
+ params = chainon (params, param);
+ }
+
+ DECL_ARGUMENTS (function) = params;
+
+ /* Also build the result decl, which is needed when force creating
+ the thunk in gimple inside cgraph_node::expand_thunk. */
+ tree resdecl = build_decl (DECL_SOURCE_LOCATION (function),
+ RESULT_DECL, NULL_TREE,
+ TREE_TYPE (fntype));
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_CONTEXT (resdecl) = function;
+ DECL_RESULT (function) = resdecl;
+ }
+ }
+
+ /* Don't build the thunk if the compilation step failed. */
+ if (global.errors)
+ return error_mark_node;
+
+ /* See if we already have the thunk in question. */
+ for (tree t = DECL_LANG_THUNKS (function); t; t = DECL_CHAIN (t))
+ {
+ if (THUNK_LANG_OFFSET (t) == offset)
+ return t;
+ }
+
+ tree thunk = build_decl (DECL_SOURCE_LOCATION (function),
+ FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
+ DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
+ lang_hooks.dup_lang_specific_decl (thunk);
+ THUNK_LANG_OFFSET (thunk) = offset;
+
+ TREE_READONLY (thunk) = TREE_READONLY (function);
+ TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
+ TREE_NOTHROW (thunk) = TREE_NOTHROW (function);
+
+ DECL_CONTEXT (thunk) = d_decl_context (decl);
+
+ /* Thunks inherit the public access of the function they are targetting. */
+ TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
+ DECL_EXTERNAL (thunk) = 0;
+
+ /* Thunks are always addressable. */
+ TREE_ADDRESSABLE (thunk) = 1;
+ TREE_USED (thunk) = 1;
+ DECL_ARTIFICIAL (thunk) = 1;
+ DECL_DECLARED_INLINE_P (thunk) = 0;
+
+ DECL_VISIBILITY (thunk) = DECL_VISIBILITY (function);
+ DECL_COMDAT (thunk) = DECL_COMDAT (function);
+ DECL_WEAK (thunk) = DECL_WEAK (function);
+
+ tree target_name = DECL_ASSEMBLER_NAME (function);
+ unsigned identlen = IDENTIFIER_LENGTH (target_name) + 14;
+ const char *ident = XNEWVEC (const char, identlen);
+ snprintf (CONST_CAST (char *, ident), identlen,
+ "_DT%u%s", offset, IDENTIFIER_POINTER (target_name));
+
+ DECL_NAME (thunk) = get_identifier (ident);
+ SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk));
+
+ d_keep (thunk);
+
+ finish_thunk (thunk, function);
+
+ /* Add it to the list of thunks associated with the function. */
+ DECL_LANG_THUNKS (thunk) = NULL_TREE;
+ DECL_CHAIN (thunk) = DECL_LANG_THUNKS (function);
+ DECL_LANG_THUNKS (function) = thunk;
+
+ return thunk;
+}
+
+/* Create the FUNCTION_DECL for a function definition.
+ This function creates a binding context for the function body
+ as well as setting up the FUNCTION_DECL in current_function_decl.
+ Returns the previous function context if it was already set. */
+
+tree
+start_function (FuncDeclaration *fd)
+{
+ tree fndecl = get_symbol_decl (fd);
+
+ /* Function has been defined, check now whether we intend to send it to
+ object file, or it really is extern. Such as inlinable functions from
+ modules not in this compilation, or thunk aliases. */
+ TemplateInstance *ti = fd->isInstantiated ();
+ if (ti && ti->needsCodegen ())
+ {
+ /* Warn about templates instantiated in this compilation. */
+ if (ti == fd->parent)
+ {
+ warning (OPT_Wtemplates, "%s %qs instantiated",
+ ti->kind (), ti->toPrettyChars (false));
+ }
+
+ DECL_EXTERNAL (fndecl) = 0;
+ }
+ else
+ {
+ Module *md = fd->getModule ();
+ if (md && md->isRoot ())
+ DECL_EXTERNAL (fndecl) = 0;
+ }
+
+ DECL_INITIAL (fndecl) = error_mark_node;
+
+ /* Add this decl to the current binding level. */
+ d_pushdecl (fndecl);
+
+ /* Save the current function context. */
+ tree old_context = current_function_decl;
+
+ if (old_context)
+ push_function_context ();
+
+ /* Let GCC know the current scope is this function. */
+ current_function_decl = fndecl;
+
+ tree restype = TREE_TYPE (TREE_TYPE (fndecl));
+ tree resdecl = build_decl (make_location_t (fd->loc), RESULT_DECL,
+ NULL_TREE, restype);
+
+ DECL_RESULT (fndecl) = resdecl;
+ DECL_CONTEXT (resdecl) = fndecl;
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+
+ /* Initialize the RTL code for the function. */
+ allocate_struct_function (fndecl, false);
+
+ /* Store the end of the function. */
+ if (fd->endloc.filename)
+ cfun->function_end_locus = make_location_t (fd->endloc);
+ else
+ cfun->function_end_locus = DECL_SOURCE_LOCATION (fndecl);
+
+ cfun->language = ggc_cleared_alloc<language_function> ();
+ cfun->language->function = fd;
+
+ /* Default chain value is 'null' unless parent found. */
+ cfun->language->static_chain = null_pointer_node;
+
+ /* Find module for this function. */
+ for (Dsymbol *p = fd->parent; p != NULL; p = p->parent)
+ {
+ cfun->language->module = p->isModule ();
+ if (cfun->language->module)
+ break;
+ }
+ gcc_assert (cfun->language->module != NULL);
+
+ /* Begin the statement tree for this function. */
+ push_stmt_list ();
+ push_binding_level (level_function);
+
+ return old_context;
+}
+
+/* Finish up a function declaration and compile that function all
+ the way to assembler language output. The free the storage for
+ the function definition. Restores the previous function context. */
+
+void
+finish_function (tree old_context)
+{
+ tree fndecl = current_function_decl;
+
+ /* Tie off the statement tree for this function. */
+ tree block = pop_binding_level ();
+ tree body = pop_stmt_list ();
+ tree bind = build3 (BIND_EXPR, void_type_node,
+ BLOCK_VARS (block), body, block);
+
+ gcc_assert (vec_safe_is_empty (d_function_chain->stmt_list));
+
+ /* Back-end expects a statement list to come from somewhere, however
+ pop_stmt_list returns expressions when there is a single statement.
+ So here we create a statement list unconditionally. */
+ if (TREE_CODE (body) != STATEMENT_LIST)
+ {
+ tree stmtlist = alloc_stmt_list ();
+ append_to_statement_list_force (body, &stmtlist);
+ BIND_EXPR_BODY (bind) = stmtlist;
+ }
+ else if (!STATEMENT_LIST_HEAD (body))
+ {
+ /* For empty functions add a void return. */
+ append_to_statement_list_force (return_expr (NULL_TREE), &body);
+ }
+
+ DECL_SAVED_TREE (fndecl) = bind;
+
+ if (!errorcount && !global.errors)
+ {
+ /* Dump the D-specific tree IR. */
+ dump_function (TDI_original, fndecl);
+
+ cgraph_node::finalize_function (fndecl, true);
+ }
+
+ /* We're leaving the context of this function, so free it. */
+ ggc_free (cfun->language);
+ cfun->language = NULL;
+ set_cfun (NULL);
+
+ if (old_context)
+ pop_function_context ();
+
+ current_function_decl = old_context;
+}
+
+/* Mark DECL, which is a VAR_DECL or FUNCTION_DECL as a symbol that
+ must be emitted in this, output module. */
+
+void
+mark_needed (tree decl)
+{
+ TREE_USED (decl) = 1;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ struct cgraph_node *node = cgraph_node::get_create (decl);
+ node->forced_by_abi = true;
+ }
+ else if (VAR_P (decl))
+ {
+ struct varpool_node *node = varpool_node::get_create (decl);
+ node->forced_by_abi = true;
+ }
+}
+
+/* Get the offset to the BC's vtbl[] initializer from the start of CD.
+ Returns "~0u" if the base class is not found in any vtable interfaces. */
+
+unsigned
+base_vtable_offset (ClassDeclaration *cd, BaseClass *bc)
+{
+ unsigned csymoffset = Target::classinfosize;
+ unsigned interfacesize = int_size_in_bytes (vtbl_interface_type_node);
+ csymoffset += cd->vtblInterfaces->dim * interfacesize;
+
+ for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+ {
+ BaseClass *b = (*cd->vtblInterfaces)[i];
+ if (b == bc)
+ return csymoffset;
+ csymoffset += b->sym->vtbl.dim * Target::ptrsize;
+ }
+
+ /* Check all overriding interface vtbl[]s. */
+ for (ClassDeclaration *cd2 = cd->baseClass; cd2; cd2 = cd2->baseClass)
+ {
+ for (size_t k = 0; k < cd2->vtblInterfaces->dim; k++)
+ {
+ BaseClass *bs = (*cd2->vtblInterfaces)[k];
+ if (bs->fillVtbl (cd, NULL, 0))
+ {
+ if (bc == bs)
+ return csymoffset;
+ csymoffset += bs->sym->vtbl.dim * Target::ptrsize;
+ }
+ }
+ }
+
+ return ~0u;
+}
+
+/* Get the VAR_DECL of the vtable symbol for DECL. If this does not yet exist,
+ create it. The vtable is accessible via ClassInfo, but since it is needed
+ frequently (like for rtti comparisons), make it directly accessible. */
+
+tree
+get_vtable_decl (ClassDeclaration *decl)
+{
+ if (decl->vtblsym)
+ return decl->vtblsym;
+
+ tree ident = mangle_internal_decl (decl, "__vtbl", "Z");
+ /* Note: Using a static array type for the VAR_DECL, the DECL_INITIAL value
+ will have a different type. However the back-end seems to accept this. */
+ tree type = build_ctype (Type::tvoidptr->sarrayOf (decl->vtbl.dim));
+
+ decl->vtblsym = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (decl->vtblsym) = build_lang_decl (NULL);
+
+ /* Class is a reference, want the record type. */
+ DECL_CONTEXT (decl->vtblsym) = TREE_TYPE (build_ctype (decl->type));
+ TREE_READONLY (decl->vtblsym) = 1;
+ DECL_VIRTUAL_P (decl->vtblsym) = 1;
+
+ SET_DECL_ALIGN (decl->vtblsym, TARGET_VTABLE_ENTRY_ALIGN);
+ DECL_USER_ALIGN (decl->vtblsym) = true;
+
+ return decl->vtblsym;
+}
+
+/* Helper function of build_class_instance. Find the field inside aggregate
+ TYPE identified by IDENT at field OFFSET. */
+
+static tree
+find_aggregate_field (tree type, tree ident, tree offset)
+{
+ tree fields = TYPE_FIELDS (type);
+
+ for (tree field = fields; field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ if (DECL_NAME (field) == NULL_TREE
+ && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ {
+ /* Search nesting anonymous structs and unions. */
+ tree vfield = find_aggregate_field (TREE_TYPE (field),
+ ident, offset);
+ if (vfield != NULL_TREE)
+ return vfield;
+ }
+ else if (DECL_NAME (field) == ident
+ && (offset == NULL_TREE
+ || DECL_FIELD_OFFSET (field) == offset))
+ {
+ /* Found matching field at offset. */
+ return field;
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Helper function of build_new_class_expr. Return a constructor that matches
+ the layout of the class expression EXP. */
+
+static tree
+build_class_instance (ClassReferenceExp *exp)
+{
+ ClassDeclaration *cd = exp->originalClass ();
+ tree type = TREE_TYPE (build_ctype (exp->value->stype));
+ vec<constructor_elt, va_gc> *ve = NULL;
+
+ /* The set base vtable field. */
+ tree vptr = build_address (get_vtable_decl (cd));
+ CONSTRUCTOR_APPEND_ELT (ve, TYPE_FIELDS (type), vptr);
+
+ /* Go through the inheritance graph from top to bottom. This will add all
+ values to the constructor out of order, however build_struct_literal
+ will re-order all values before returning the finished literal. */
+ for (ClassDeclaration *bcd = cd; bcd != NULL; bcd = bcd->baseClass)
+ {
+ /* Anonymous vtable interface fields are laid out before the fields of
+ each class. The interface offset is used to determine where to put
+ the classinfo offset reference. */
+ for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++)
+ {
+ BaseClass *bc = (*bcd->vtblInterfaces)[i];
+
+ for (ClassDeclaration *cd2 = cd; 1; cd2 = cd2->baseClass)
+ {
+ gcc_assert (cd2 != NULL);
+
+ unsigned csymoffset = base_vtable_offset (cd2, bc);
+ /* If the base class vtable was found. */
+ if (csymoffset != ~0u)
+ {
+ tree csym = build_address (get_classinfo_decl (cd2));
+ csym = build_offset (csym, size_int (csymoffset));
+
+ tree field = find_aggregate_field (type, NULL_TREE,
+ size_int (bc->offset));
+ gcc_assert (field != NULL_TREE);
+
+ CONSTRUCTOR_APPEND_ELT (ve, field, csym);
+ break;
+ }
+ }
+ }
+
+ /* Generate initial values of all fields owned by current class.
+ Use both the name and offset to find the right field. */
+ for (size_t i = 0; i < bcd->fields.dim; i++)
+ {
+ VarDeclaration *vfield = bcd->fields[i];
+ int index = exp->findFieldIndexByName (vfield);
+ gcc_assert (index != -1);
+
+ Expression *value = (*exp->value->elements)[index];
+ if (!value)
+ continue;
+
+ /* Use find_aggregate_field to get the overridden field decl,
+ instead of the field associated with the base class. */
+ tree field = get_symbol_decl (bcd->fields[i]);
+ field = find_aggregate_field (type, DECL_NAME (field),
+ DECL_FIELD_OFFSET (field));
+ gcc_assert (field != NULL_TREE);
+
+ CONSTRUCTOR_APPEND_ELT (ve, field, build_expr (value, true));
+ }
+ }
+
+ return build_struct_literal (type, ve);
+}
+
+/* Get the VAR_DECL of a class instance representing EXPR as static data.
+ If this does not yet exist, create it. This is used to support initializing
+ a static variable that is of a class type using values known during CTFE.
+ In user code, it is analogous to the following code snippet.
+
+ enum E = new C(1, 2, 3);
+
+ That we write the contents of `C(1, 2, 3)' to static data is only a compiler
+ implementation detail. The initialization of these symbols could be done at
+ run-time using during as part of the module initialization or shared static
+ constructors phase of run-time start-up - whichever comes after `gc_init()'.
+ And infact that would be the better thing to do here eventually. */
+
+tree
+build_new_class_expr (ClassReferenceExp *expr)
+{
+ if (expr->value->sym)
+ return expr->value->sym;
+
+ /* Build the reference symbol. */
+ tree type = build_ctype (expr->value->stype);
+ expr->value->sym = build_artificial_decl (TREE_TYPE (type), NULL_TREE, "C");
+
+ DECL_INITIAL (expr->value->sym) = build_class_instance (expr);
+ d_pushdecl (expr->value->sym);
+ rest_of_decl_compilation (expr->value->sym, 1, 0);
+
+ return expr->value->sym;
+}
+
+/* Get the VAR_DECL of the static initializer symbol for the struct/class DECL.
+ If this does not yet exist, create it. The static initializer data is
+ accessible via TypeInfo, and is also used in 'new class' and default
+ initializing struct literals. */
+
+tree
+aggregate_initializer_decl (AggregateDeclaration *decl)
+{
+ if (decl->sinit)
+ return decl->sinit;
+
+ /* Class is a reference, want the record type. */
+ tree type = build_ctype (decl->type);
+ StructDeclaration *sd = decl->isStructDeclaration ();
+ if (!sd)
+ type = TREE_TYPE (type);
+
+ tree ident = mangle_internal_decl (decl, "__init", "Z");
+
+ decl->sinit = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (decl->sinit) = build_lang_decl (NULL);
+
+ DECL_CONTEXT (decl->sinit) = type;
+ TREE_READONLY (decl->sinit) = 1;
+
+ /* Honor struct alignment set by user. */
+ if (sd && sd->alignment != STRUCTALIGN_DEFAULT)
+ {
+ SET_DECL_ALIGN (decl->sinit, sd->alignment * BITS_PER_UNIT);
+ DECL_USER_ALIGN (decl->sinit) = true;
+ }
+
+ return decl->sinit;
+}
+
+/* Generate the data for the static initializer. */
+
+tree
+layout_class_initializer (ClassDeclaration *cd)
+{
+ NewExp *ne = NewExp::create (cd->loc, NULL, NULL, cd->type, NULL);
+ ne->type = cd->type;
+
+ Expression *e = ne->ctfeInterpret ();
+ gcc_assert (e->op == TOKclassreference);
+
+ return build_class_instance ((ClassReferenceExp *) e);
+}
+
+tree
+layout_struct_initializer (StructDeclaration *sd)
+{
+ StructLiteralExp *sle = StructLiteralExp::create (sd->loc, sd, NULL);
+
+ if (!sd->fill (sd->loc, sle->elements, true))
+ gcc_unreachable ();
+
+ sle->type = sd->type;
+ return build_expr (sle, true);
+}
+
+/* Get the VAR_DECL of the static initializer symbol for the enum DECL.
+ If this does not yet exist, create it. The static initializer data is
+ accessible via TypeInfo_Enum, but the field member type is a byte[] that
+ requires a pointer to a symbol reference. */
+
+tree
+enum_initializer_decl (EnumDeclaration *decl)
+{
+ if (decl->sinit)
+ return decl->sinit;
+
+ tree type = build_ctype (decl->type);
+
+ Identifier *ident_save = decl->ident;
+ if (!decl->ident)
+ decl->ident = Identifier::generateId ("__enum");
+ tree ident = mangle_internal_decl (decl, "__init", "Z");
+ decl->ident = ident_save;
+
+ decl->sinit = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (decl->sinit) = build_lang_decl (NULL);
+
+ DECL_CONTEXT (decl->sinit) = d_decl_context (decl);
+ TREE_READONLY (decl->sinit) = 1;
+
+ return decl->sinit;
+}
+
+/* Return an anonymous static variable of type TYPE, initialized with INIT,
+ and optionally prefixing the name with PREFIX. */
+
+tree
+build_artificial_decl (tree type, tree init, const char *prefix)
+{
+ tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, NULL_TREE, type);
+ const char *name = prefix ? prefix : "___s";
+ char *label;
+
+ ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label));
+ DECL_NAME (decl) = DECL_ASSEMBLER_NAME (decl);
+
+ TREE_PUBLIC (decl) = 0;
+ TREE_STATIC (decl) = 1;
+ TREE_USED (decl) = 1;
+ DECL_IGNORED_P (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ /* Perhaps at some point the initializer constant should be hashed
+ to remove duplicates. */
+ DECL_INITIAL (decl) = init;
+
+ return decl;
+}
+
+/* Build TYPE_DECL for the declaration DSYM. */
+
+void
+build_type_decl (tree type, Dsymbol *dsym)
+{
+ if (TYPE_STUB_DECL (type))
+ return;
+
+ gcc_assert (!POINTER_TYPE_P (type));
+
+ tree decl = build_decl (make_location_t (dsym->loc), TYPE_DECL,
+ get_identifier (dsym->ident->toChars ()), type);
+ SET_DECL_ASSEMBLER_NAME (decl, get_identifier (mangle_decl (dsym)));
+ TREE_PUBLIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_CONTEXT (decl) = d_decl_context (dsym);
+
+ TYPE_CONTEXT (type) = DECL_CONTEXT (decl);
+ TYPE_NAME (type) = decl;
+
+ /* Not sure if there is a need for separate TYPE_DECLs in
+ TYPE_NAME and TYPE_STUB_DECL. */
+ if (TREE_CODE (type) == ENUMERAL_TYPE || RECORD_OR_UNION_TYPE_P (type))
+ TYPE_STUB_DECL (type) = decl;
+
+ rest_of_decl_compilation (decl, SCOPE_FILE_SCOPE_P (decl), 0);
+}
+
+/* Create a declaration for field NAME of a given TYPE, setting the flags
+ for whether the field is ARTIFICIAL and/or IGNORED. */
+
+tree
+create_field_decl (tree type, const char *name, int artificial, int ignored)
+{
+ tree decl = build_decl (input_location, FIELD_DECL,
+ name ? get_identifier (name) : NULL_TREE, type);
+ DECL_ARTIFICIAL (decl) = artificial;
+ DECL_IGNORED_P (decl) = ignored;
+
+ return decl;
+}
+
+/* Return the COMDAT group into which DECL should be placed. */
+
+static tree
+d_comdat_group (tree decl)
+{
+ /* If already part of a comdat group, use that. */
+ if (DECL_COMDAT_GROUP (decl))
+ return DECL_COMDAT_GROUP (decl);
+
+ return DECL_ASSEMBLER_NAME (decl);
+}
+
+/* Set DECL up to have the closest approximation of "initialized common"
+ linkage available. */
+
+void
+d_comdat_linkage (tree decl)
+{
+ if (flag_weak)
+ make_decl_one_only (decl, d_comdat_group (decl));
+ else if (TREE_CODE (decl) == FUNCTION_DECL
+ || (VAR_P (decl) && DECL_ARTIFICIAL (decl)))
+ /* We can just emit function and compiler-generated variables statically;
+ having multiple copies is (for the most part) only a waste of space. */
+ TREE_PUBLIC (decl) = 0;
+ else if (DECL_INITIAL (decl) == NULL_TREE
+ || DECL_INITIAL (decl) == error_mark_node)
+ /* Fallback, cannot have multiple copies. */
+ DECL_COMMON (decl) = 1;
+
+ if (TREE_PUBLIC (decl))
+ DECL_COMDAT (decl) = 1;
+}
+
+/* Set DECL up to have the closest approximation of "linkonce" linkage. */
+
+void
+d_linkonce_linkage (tree decl)
+{
+ /* Weak definitions have to be public. */
+ if (!TREE_PUBLIC (decl))
+ return;
+
+ /* Necessary to allow DECL_ONE_ONLY or DECL_WEAK functions to be inlined. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ DECL_DECLARED_INLINE_P (decl) = 1;
+
+ /* No weak support, fallback to COMDAT linkage. */
+ if (!flag_weak)
+ return d_comdat_linkage (decl);
+
+ make_decl_one_only (decl, d_comdat_group (decl));
+}
diff --git a/gcc/d/dmd/access.c b/gcc/d/dmd/access.c
new file mode 100644
index 0000000..37e9c86
--- /dev/null
+++ b/gcc/d/dmd/access.c
@@ -0,0 +1,572 @@
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/access.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root/root.h"
+#include "root/rmem.h"
+
+#include "errors.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"
+#include "template.h"
+
+/* Code to do access checks
+ */
+
+bool hasPackageAccess(Scope *sc, Dsymbol *s);
+bool hasPackageAccess(Module *mod, Dsymbol *s);
+bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember);
+bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd);
+static Dsymbol *mostVisibleOverload(Dsymbol *s);
+
+/****************************************
+ * Return Prot access for Dsymbol smember in this declaration.
+ */
+Prot getAccess(AggregateDeclaration *ad, Dsymbol *smember)
+{
+ Prot access_ret = Prot(PROTnone);
+
+ assert(ad->isStructDeclaration() || ad->isClassDeclaration());
+ if (smember->toParent() == ad)
+ {
+ access_ret = smember->prot();
+ }
+ else if (smember->isDeclaration()->isStatic())
+ {
+ access_ret = smember->prot();
+ }
+ if (ClassDeclaration *cd = ad->isClassDeclaration())
+ {
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ BaseClass *b = (*cd->baseclasses)[i];
+
+ Prot access = getAccess(b->sym, smember);
+ switch (access.kind)
+ {
+ case PROTnone:
+ break;
+
+ case PROTprivate:
+ access_ret = Prot(PROTnone); // private members of base class not accessible
+ break;
+
+ case PROTpackage:
+ case PROTprotected:
+ case PROTpublic:
+ case PROTexport:
+ // If access is to be tightened
+ if (PROTpublic < access.kind)
+ access = Prot(PROTpublic);
+
+ // Pick path with loosest access
+ if (access_ret.isMoreRestrictiveThan(access))
+ access_ret = access;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ }
+
+ return access_ret;
+}
+
+/********************************************************
+ * Helper function for checkAccess()
+ * Returns:
+ * false is not accessible
+ * true is accessible
+ */
+static bool isAccessible(
+ Dsymbol *smember,
+ Dsymbol *sfunc,
+ AggregateDeclaration *dthis,
+ AggregateDeclaration *cdscope)
+{
+ assert(dthis);
+
+ if (hasPrivateAccess(dthis, sfunc) ||
+ isFriendOf(dthis, cdscope))
+ {
+ if (smember->toParent() == dthis)
+ return true;
+
+ if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
+ {
+ for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
+ {
+ BaseClass *b = (*cdthis->baseclasses)[i];
+ Prot access = getAccess(b->sym, smember);
+ if (access.kind >= PROTprotected ||
+ isAccessible(smember, sfunc, b->sym, cdscope))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (smember->toParent() != dthis)
+ {
+ if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
+ {
+ for (size_t i = 0; i < cdthis->baseclasses->dim; i++)
+ {
+ BaseClass *b = (*cdthis->baseclasses)[i];
+ if (isAccessible(smember, sfunc, b->sym, cdscope))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/*******************************
+ * Do access check for member of this class, this class being the
+ * type of the 'this' pointer used to access smember.
+ * Returns true if the member is not accessible.
+ */
+bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)
+{
+ FuncDeclaration *f = sc->func;
+ AggregateDeclaration *cdscope = sc->getStructClassScope();
+
+ Dsymbol *smemberparent = smember->toParent();
+ if (!smemberparent || !smemberparent->isAggregateDeclaration())
+ {
+ return false; // then it is accessible
+ }
+
+ // BUG: should enable this check
+ //assert(smember->parent->isBaseOf(this, NULL));
+
+ bool result;
+ Prot access;
+ if (smemberparent == ad)
+ {
+ access = smember->prot();
+ result = access.kind >= PROTpublic ||
+ hasPrivateAccess(ad, f) ||
+ isFriendOf(ad, cdscope) ||
+ (access.kind == PROTpackage && hasPackageAccess(sc, smember)) ||
+ ad->getAccessModule() == sc->_module;
+ }
+ else if ((access = getAccess(ad, smember)).kind >= PROTpublic)
+ {
+ result = true;
+ }
+ else if (access.kind == PROTpackage && hasPackageAccess(sc, ad))
+ {
+ result = true;
+ }
+ else
+ {
+ result = isAccessible(smember, f, ad, cdscope);
+ }
+ if (!result)
+ {
+ ad->error(loc, "member %s is not accessible", smember->toChars());
+ //printf("smember = %s %s, prot = %d, semanticRun = %d\n",
+ // smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun);
+ return true;
+ }
+ return false;
+}
+
+/****************************************
+ * Determine if this is the same or friend of cd.
+ */
+bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd)
+{
+ if (ad == cd)
+ return true;
+
+ // Friends if both are in the same module
+ //if (toParent() == cd->toParent())
+ if (cd && ad->getAccessModule() == cd->getAccessModule())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+bool hasPackageAccess(Scope *sc, Dsymbol *s)
+{
+ return hasPackageAccess(sc->_module, s);
+}
+
+bool hasPackageAccess(Module *mod, Dsymbol *s)
+{
+ Package *pkg = NULL;
+
+ if (s->prot().pkg)
+ pkg = s->prot().pkg;
+ else
+ {
+ // no explicit package for protection, inferring most qualified one
+ for (; s; s = s->parent)
+ {
+ if (Module *m = s->isModule())
+ {
+ DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL);
+ assert(dst);
+ Dsymbol *s2 = dst->lookup(m->ident);
+ assert(s2);
+ Package *p = s2->isPackage();
+ if (p && p->isPackageMod())
+ {
+ pkg = p;
+ break;
+ }
+ }
+ else if ((pkg = s->isPackage()) != NULL)
+ break;
+ }
+ }
+
+ if (pkg)
+ {
+ if (pkg == mod->parent)
+ {
+ return true;
+ }
+ if (pkg->isPackageMod() == mod)
+ {
+ return true;
+ }
+ Dsymbol* ancestor = mod->parent;
+ for (; ancestor; ancestor = ancestor->parent)
+ {
+ if (ancestor == pkg)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/****************************************
+ * Determine if scope sc has protected level access to cd.
+ */
+bool hasProtectedAccess(Scope *sc, Dsymbol *s)
+{
+ if (ClassDeclaration *cd = s->isClassMember()) // also includes interfaces
+ {
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (!scx->scopesym)
+ continue;
+ ClassDeclaration *cd2 = scx->scopesym->isClassDeclaration();
+ if (cd2 && cd->isBaseOf(cd2, NULL))
+ return true;
+ }
+ }
+ return sc->_module == s->getAccessModule();
+}
+
+/**********************************
+ * Determine if smember has access to private members of this declaration.
+ */
+bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember)
+{
+ if (smember)
+ {
+ AggregateDeclaration *cd = NULL;
+ Dsymbol *smemberparent = smember->toParent();
+ if (smemberparent)
+ cd = smemberparent->isAggregateDeclaration();
+
+ if (ad == cd) // smember is a member of this class
+ {
+ return true; // 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 && ad->toParent() == smember->toParent())
+ {
+ return true;
+ }
+ if (!cd && ad->getAccessModule() == smember->getAccessModule())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ * Returns true if the declaration is not accessible.
+ */
+bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d)
+{
+ if (sc->flags & SCOPEnoaccesscheck)
+ return false;
+
+ if (d->isUnitTestDeclaration())
+ {
+ // Unittests are always accessible.
+ return false;
+ }
+ if (!e)
+ {
+ if ((d->prot().kind == PROTprivate && d->getAccessModule() != sc->_module) ||
+ (d->prot().kind == PROTpackage && !hasPackageAccess(sc, d)))
+ {
+ error(loc, "%s %s is not accessible from module %s",
+ d->kind(), d->toPrettyChars(), sc->_module->toChars());
+ return true;
+ }
+ }
+ else if (e->type->ty == Tclass)
+ {
+ // Do access check
+ ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
+ if (e->op == TOKsuper)
+ {
+ ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
+ if (cd2)
+ cd = cd2;
+ }
+ return checkAccess(cd, loc, sc, d);
+ }
+ else if (e->type->ty == Tstruct)
+ {
+ // Do access check
+ StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
+ return checkAccess(cd, loc, sc, d);
+ }
+ return false;
+}
+
+/****************************************
+ * Check access to package/module `p` from scope `sc`.
+ *
+ * Params:
+ * loc = source location for issued error message
+ * sc = scope from which to access to a fully qualified package name
+ * p = the package/module to check access for
+ * Returns: true if the package is not accessible.
+ *
+ * Because a global symbol table tree is used for imported packages/modules,
+ * access to them needs to be checked based on the imports in the scope chain
+ * (see Bugzilla 313).
+ *
+ */
+bool checkAccess(Loc loc, Scope *sc, Package *p)
+{
+ if (sc->_module == p)
+ return false;
+ for (; sc; sc = sc->enclosing)
+ {
+ if (sc->scopesym && sc->scopesym->isPackageAccessible(p, Prot(PROTprivate)))
+ return false;
+ }
+ const char *name = p->toPrettyChars();
+ if (p->isPkgMod == PKGmodule || p->isModule())
+ deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", p->kind(), name, name);
+ else
+ deprecation(loc, "%s %s is not accessible here", p->kind(), name);
+ return true;
+}
+
+/**
+ * Check whether symbols `s` is visible in `mod`.
+ *
+ * Params:
+ * mod = lookup origin
+ * s = symbol to check for visibility
+ * Returns: true if s is visible in mod
+ */
+bool symbolIsVisible(Module *mod, Dsymbol *s)
+{
+ // should sort overloads by ascending protection instead of iterating here
+ s = mostVisibleOverload(s);
+
+ switch (s->prot().kind)
+ {
+ case PROTundefined:
+ return true;
+ case PROTnone:
+ return false; // no access
+ case PROTprivate:
+ return s->getAccessModule() == mod;
+ case PROTpackage:
+ return s->getAccessModule() == mod || hasPackageAccess(mod, s);
+ case PROTprotected:
+ return s->getAccessModule() == mod;
+ case PROTpublic:
+ case PROTexport:
+ return true;
+ default:
+ assert(0);
+ }
+}
+
+/**
+ * Same as above, but determines the lookup module from symbols `origin`.
+ */
+bool symbolIsVisible(Dsymbol *origin, Dsymbol *s)
+{
+ return symbolIsVisible(origin->getAccessModule(), s);
+}
+
+/**
+ * Same as above but also checks for protected symbols visible from scope `sc`.
+ * Used for qualified name lookup.
+ *
+ * Params:
+ * sc = lookup scope
+ * s = symbol to check for visibility
+ * Returns: true if s is visible by origin
+ */
+bool symbolIsVisible(Scope *sc, Dsymbol *s)
+{
+ s = mostVisibleOverload(s);
+
+ switch (s->prot().kind)
+ {
+ case PROTundefined:
+ return true;
+ case PROTnone:
+ return false; // no access
+ case PROTprivate:
+ return sc->_module == s->getAccessModule();
+ case PROTpackage:
+ return sc->_module == s->getAccessModule() || hasPackageAccess(sc->_module, s);
+ case PROTprotected:
+ return hasProtectedAccess(sc, s);
+ case PROTpublic:
+ case PROTexport:
+ return true;
+ default:
+ assert(0);
+ }
+}
+
+/**
+ * Use the most visible overload to check visibility. Later perform an access
+ * check on the resolved overload. This function is similar to overloadApply,
+ * but doesn't recurse nor resolve aliases because protection/visibility is an
+ * attribute of the alias not the aliasee.
+ */
+static Dsymbol *mostVisibleOverload(Dsymbol *s)
+{
+ if (!s->isOverloadable())
+ return s;
+
+ Dsymbol *next = NULL;
+ Dsymbol *fstart = s;
+ Dsymbol *mostVisible = s;
+ for (; s; s = next)
+ {
+ // void func() {}
+ // private void func(int) {}
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ next = fd->overnext;
+ // template temp(T) {}
+ // private template temp(T:int) {}
+ else if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ next = td->overnext;
+ // alias common = mod1.func1;
+ // alias common = mod2.func2;
+ else if (FuncAliasDeclaration *fa = s->isFuncAliasDeclaration())
+ next = fa->overnext;
+ // alias common = mod1.templ1;
+ // alias common = mod2.templ2;
+ else if (OverDeclaration *od = s->isOverDeclaration())
+ next = od->overnext;
+ // alias name = sym;
+ // private void name(int) {}
+ else if (AliasDeclaration *ad = s->isAliasDeclaration())
+ {
+ if (!ad->isOverloadable())
+ {
+ //printf("Non overloadable Aliasee in overload list\n");
+ assert(0);
+ }
+ // Yet unresolved aliases store overloads in overnext.
+ if (ad->semanticRun < PASSsemanticdone)
+ next = ad->overnext;
+ else
+ {
+ /* This is a bit messy due to the complicated implementation of
+ * alias. Aliases aren't overloadable themselves, but if their
+ * Aliasee is overloadable they can be converted to an overloadable
+ * alias.
+ *
+ * This is done by replacing the Aliasee w/ FuncAliasDeclaration
+ * (for functions) or OverDeclaration (for templates) which are
+ * simply overloadable aliases w/ weird names.
+ *
+ * Usually aliases should not be resolved for visibility checking
+ * b/c public aliases to private symbols are public. But for the
+ * overloadable alias situation, the Alias (_ad_) has been moved
+ * into it's own Aliasee, leaving a shell that we peel away here.
+ */
+ Dsymbol *aliasee = ad->toAlias();
+ if (aliasee->isFuncAliasDeclaration() || aliasee->isOverDeclaration())
+ next = aliasee;
+ else
+ {
+ /* A simple alias can be at the end of a function or template overload chain.
+ * It can't have further overloads b/c it would have been
+ * converted to an overloadable alias.
+ */
+ if (ad->overnext)
+ {
+ //printf("Unresolved overload of alias\n");
+ assert(0);
+ }
+ break;
+ }
+ }
+
+ // handled by overloadApply for unknown reason
+ assert(next != ad); // should not alias itself
+ assert(next != fstart); // should not alias the overload list itself
+ }
+ else
+ break;
+
+ if (next && mostVisible->prot().isMoreRestrictiveThan(next->prot()))
+ mostVisible = next;
+ }
+ return mostVisible;
+}
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
new file mode 100644
index 0000000..d7db82b
--- /dev/null
+++ b/gcc/d/dmd/aggregate.h
@@ -0,0 +1,336 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+
+#include "dsymbol.h"
+#include "declaration.h"
+#include "objc.h"
+
+class Identifier;
+class Type;
+class TypeFunction;
+class Expression;
+class FuncDeclaration;
+class CtorDeclaration;
+class DtorDeclaration;
+class InvariantDeclaration;
+class NewDeclaration;
+class DeleteDeclaration;
+class InterfaceDeclaration;
+class TypeInfoClassDeclaration;
+class VarDeclaration;
+
+enum Sizeok
+{
+ SIZEOKnone, // size of aggregate is not yet able to compute
+ SIZEOKfwd, // size of aggregate is ready to compute
+ SIZEOKdone // size of aggregate is set correctly
+};
+
+enum Baseok
+{
+ BASEOKnone, // base classes not computed yet
+ BASEOKin, // in process of resolving base classes
+ BASEOKdone, // all base classes are resolved
+ BASEOKsemanticdone // all base classes semantic done
+};
+
+enum StructPOD
+{
+ ISPODno, // struct is not POD
+ ISPODyes, // struct is POD
+ ISPODfwd // POD not yet computed
+};
+
+enum Abstract
+{
+ ABSfwdref = 0, // whether an abstract class is not yet computed
+ ABSyes, // is abstract class
+ ABSno // is not abstract class
+};
+
+FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc);
+FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc);
+bool needOpEquals(StructDeclaration *sd);
+FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildXtoHash(StructDeclaration *ad, Scope *sc);
+FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc);
+FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc);
+FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc);
+FuncDeclaration *search_toString(StructDeclaration *sd);
+
+class AggregateDeclaration : public ScopeDsymbol
+{
+public:
+ Type *type;
+ StorageClass storage_class;
+ Prot protection;
+ unsigned structsize; // size of struct
+ unsigned alignsize; // size of struct for alignment purposes
+ VarDeclarations fields; // VarDeclaration fields
+ Sizeok sizeok; // set when structsize contains valid data
+ Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol
+ bool isdeprecated; // true if deprecated
+
+ /* !=NULL if is nested
+ * pointing to the dsymbol that directly enclosing it.
+ * 1. The function that enclosing it (nested struct and class)
+ * 2. The class that enclosing it (nested class only)
+ * 3. If enclosing aggregate is template, its enclosing dsymbol.
+ * See AggregateDeclaraton::makeNested for the details.
+ */
+ Dsymbol *enclosing;
+ VarDeclaration *vthis; // 'this' parameter if this aggregate is nested
+ // Special member functions
+ FuncDeclarations invs; // Array of invariants
+ FuncDeclaration *inv; // invariant
+ NewDeclaration *aggNew; // allocator
+ DeleteDeclaration *aggDelete; // deallocator
+
+ Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration
+
+ // default constructor - should have no arguments, because
+ // it would be stored in TypeInfo_Class.defaultConstructor
+ CtorDeclaration *defaultCtor;
+
+ Dsymbol *aliasthis; // forward unresolved lookups to aliasthis
+ bool noDefaultCtor; // no default construction
+
+ FuncDeclarations dtors; // Array of destructors
+ FuncDeclaration *dtor; // aggregate destructor
+
+ Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this)
+
+ AggregateDeclaration(Loc loc, Identifier *id);
+ virtual Scope *newScope(Scope *sc);
+ void setScope(Scope *sc);
+ void semantic2(Scope *sc);
+ void semantic3(Scope *sc);
+ bool determineFields();
+ bool determineSize(Loc loc);
+ virtual void finalizeSize() = 0;
+ d_uns64 size(Loc loc);
+ bool checkOverlappedFields();
+ bool fill(Loc loc, Expressions *elements, bool ctorinit);
+ static void alignmember(structalign_t salign, unsigned size, unsigned *poffset);
+ static unsigned placeField(unsigned *nextoffset,
+ unsigned memsize, unsigned memalignsize, structalign_t memalign,
+ unsigned *paggsize, unsigned *paggalignsize, bool isunion);
+ Type *getType();
+ bool isDeprecated(); // is aggregate deprecated?
+ bool isNested();
+ void makeNested();
+ bool isExport() const;
+ Dsymbol *searchCtor();
+
+ Prot prot();
+
+ // 'this' type
+ Type *handleType() { return type; }
+
+ // Back end
+ Symbol *stag; // tag symbol for debug data
+ Symbol *sinit;
+
+ AggregateDeclaration *isAggregateDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+struct StructFlags
+{
+ typedef unsigned Type;
+ enum Enum
+ {
+ none = 0x0,
+ hasPointers = 0x1 // NB: should use noPointers as in ClassFlags
+ };
+};
+
+class StructDeclaration : public AggregateDeclaration
+{
+public:
+ int zeroInit; // !=0 if initialize with 0 fill
+ bool hasIdentityAssign; // true if has identity opAssign
+ bool hasIdentityEquals; // true if has identity opEquals
+ FuncDeclarations postblits; // Array of postblit functions
+ FuncDeclaration *postblit; // aggregate postblit
+
+ FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals
+ FuncDeclaration *xcmp; // TypeInfo_Struct.xopCmp
+ FuncDeclaration *xhash; // TypeInfo_Struct.xtoHash
+ static FuncDeclaration *xerreq; // object.xopEquals
+ static FuncDeclaration *xerrcmp; // object.xopCmp
+
+ structalign_t alignment; // alignment applied outside of the struct
+ StructPOD ispod; // if struct is POD
+
+ // For 64 bit Efl function call/return ABI
+ Type *arg1type;
+ Type *arg2type;
+
+ // Even if struct is defined as non-root symbol, some built-in operations
+ // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
+ // For those, today TypeInfo_Struct is generated in COMDAT.
+ bool requestTypeInfo;
+
+ StructDeclaration(Loc loc, Identifier *id, bool inObject);
+ static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ void semantic(Scope *sc);
+ void semanticTypeInfoMembers();
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ const char *kind();
+ void finalizeSize();
+ bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype);
+ bool isPOD();
+
+ StructDeclaration *isStructDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class UnionDeclaration : public StructDeclaration
+{
+public:
+ UnionDeclaration(Loc loc, Identifier *id);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ const char *kind();
+
+ UnionDeclaration *isUnionDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+struct BaseClass
+{
+ Type *type; // (before semantic processing)
+
+ ClassDeclaration *sym;
+ unsigned offset; // 'this' pointer offset
+ // for interfaces: Array of FuncDeclaration's
+ // making up the vtbl[]
+ FuncDeclarations vtbl;
+
+ DArray<BaseClass> baseInterfaces; // if BaseClass is an interface, these
+ // are a copy of the InterfaceDeclaration::interfaces
+
+ BaseClass();
+ BaseClass(Type *type);
+
+ bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
+ void copyBaseInterfaces(BaseClasses *);
+};
+
+struct ClassFlags
+{
+ typedef unsigned Type;
+ enum Enum
+ {
+ isCOMclass = 0x1,
+ noPointers = 0x2,
+ hasOffTi = 0x4,
+ hasCtor = 0x8,
+ hasGetMembers = 0x10,
+ hasTypeInfo = 0x20,
+ isAbstract = 0x40,
+ isCPPclass = 0x80,
+ hasDtor = 0x100
+ };
+};
+
+class ClassDeclaration : public AggregateDeclaration
+{
+public:
+ static ClassDeclaration *object;
+ static ClassDeclaration *throwable;
+ static ClassDeclaration *exception;
+ static ClassDeclaration *errorException;
+ static ClassDeclaration *cpp_type_info_ptr;
+
+ ClassDeclaration *baseClass; // NULL only if this is Object
+ FuncDeclaration *staticCtor;
+ FuncDeclaration *staticDtor;
+ Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[]
+ Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[]
+
+ BaseClasses *baseclasses; // Array of BaseClass's; first is super,
+ // rest are Interface's
+
+ DArray<BaseClass*> interfaces; // interfaces[interfaces_dim] for this class
+ // (does not include baseClass)
+
+ BaseClasses *vtblInterfaces; // array of base interfaces that have
+ // their own vtbl[]
+
+ TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration
+ bool com; // true if this is a COM class (meaning it derives from IUnknown)
+ bool cpp; // true if this is a C++ interface
+ bool isobjc; // true if this is an Objective-C class/interface
+ bool isscope; // true if this is a scope class
+ Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract
+ int inuse; // to prevent recursive attempts
+ Baseok baseok; // set the progress of base classes resolving
+ Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
+
+ ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject = false);
+ static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ void semantic(Scope *sc);
+ bool isBaseOf2(ClassDeclaration *cd);
+
+ #define OFFSET_RUNTIME 0x76543210
+ #define OFFSET_FWDREF 0x76543211
+ virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
+
+ bool isBaseInfoComplete();
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ ClassDeclaration *searchBase(Identifier *ident);
+ void finalizeSize();
+ bool isFuncHidden(FuncDeclaration *fd);
+ FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
+ void interfaceSemantic(Scope *sc);
+ bool isCOMclass() const;
+ virtual bool isCOMinterface() const;
+ bool isCPPclass() const;
+ virtual bool isCPPinterface() const;
+ bool isAbstract();
+ virtual int vtblOffset() const;
+ const char *kind();
+
+ void addLocalClass(ClassDeclarations *);
+
+ // Back end
+ Symbol *vtblsym;
+
+ ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class InterfaceDeclaration : public ClassDeclaration
+{
+public:
+ InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ void semantic(Scope *sc);
+ bool isBaseOf(ClassDeclaration *cd, int *poffset);
+ bool isBaseOf(BaseClass *bc, int *poffset);
+ const char *kind();
+ int vtblOffset() const;
+ bool isCPPinterface() const;
+ bool isCOMinterface() const;
+
+ InterfaceDeclaration *isInterfaceDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/aliasthis.c b/gcc/d/dmd/aliasthis.c
new file mode 100644
index 0000000..50921ec
--- /dev/null
+++ b/gcc/d/dmd/aliasthis.c
@@ -0,0 +1,169 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2009-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/aliasthis.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "identifier.h"
+#include "aliasthis.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag)
+{
+ AggregateDeclaration *ad = isAggregate(e->type);
+
+ if (ad && ad->aliasthis)
+ {
+ unsigned olderrors = gag ? global.startGagging() : 0;
+
+ Loc loc = e->loc;
+ Type *tthis = (e->op == TOKtype ? e->type : NULL);
+ e = new DotIdExp(loc, e, ad->aliasthis->ident);
+ e = semantic(e, sc);
+ if (tthis && ad->aliasthis->needThis())
+ {
+ if (e->op == TOKvar)
+ {
+ if (FuncDeclaration *fd = ((VarExp *)e)->var->isFuncDeclaration())
+ {
+ // Bugzilla 13009: Support better match for the overloaded alias this.
+ bool hasOverloads = false;
+ if (FuncDeclaration *f = fd->overloadModMatch(loc, tthis, hasOverloads))
+ {
+ if (!hasOverloads)
+ fd = f; // use exact match
+ e = new VarExp(loc, fd, hasOverloads);
+ e->type = f->type;
+ e = new CallExp(loc, e);
+ goto L1;
+ }
+ }
+ }
+ /* non-@property function is not called inside typeof(),
+ * so resolve it ahead.
+ */
+ {
+ int save = sc->intypeof;
+ sc->intypeof = 1; // bypass "need this" error check
+ e = resolveProperties(sc, e);
+ sc->intypeof = save;
+ }
+
+ L1:
+ e = new TypeExp(loc, new TypeTypeof(loc, e));
+ e = semantic(e, sc);
+ }
+ e = resolveProperties(sc, e);
+
+ if (gag && global.endGagging(olderrors))
+ e = NULL;
+ }
+
+ return e;
+}
+
+AliasThis::AliasThis(Loc loc, Identifier *ident)
+ : Dsymbol(NULL) // it's anonymous (no identifier)
+{
+ this->loc = loc;
+ this->ident = ident;
+}
+
+Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new AliasThis(loc, ident);
+}
+
+void AliasThis::semantic(Scope *sc)
+{
+ if (semanticRun != PASSinit)
+ return;
+
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ if (!sc)
+ return;
+
+ semanticRun = PASSsemantic;
+
+ Dsymbol *p = sc->parent->pastMixin();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ ::error(loc, "alias this can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ return;
+ }
+
+ assert(ad->members);
+ Dsymbol *s = ad->search(loc, ident);
+ if (!s)
+ {
+ s = sc->search(loc, ident, NULL);
+ if (s)
+ ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
+ else
+ ::error(loc, "undefined identifier %s", ident->toChars());
+ return;
+ }
+ else if (ad->aliasthis && s != ad->aliasthis)
+ {
+ ::error(loc, "there can be only one alias this");
+ return;
+ }
+
+ if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad)
+ {
+ AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym;
+ assert(ad2->type == Type::terror);
+ ad->aliasthis = ad2->aliasthis;
+ return;
+ }
+
+ /* disable the alias this conversion so the implicit conversion check
+ * doesn't use it.
+ */
+ ad->aliasthis = NULL;
+
+ Dsymbol *sx = s;
+ if (sx->isAliasDeclaration())
+ sx = sx->toAlias();
+ Declaration *d = sx->isDeclaration();
+ if (d && !d->isTupleDeclaration())
+ {
+ Type *t = d->type;
+ assert(t);
+ if (ad->type->implicitConvTo(t) > MATCHnomatch)
+ {
+ ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars());
+ }
+ }
+
+ ad->aliasthis = s;
+ semanticRun = PASSsemanticdone;
+}
+
+const char *AliasThis::kind()
+{
+ return "alias this";
+}
diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h
new file mode 100644
index 0000000..e5b0280
--- /dev/null
+++ b/gcc/d/dmd/aliasthis.h
@@ -0,0 +1,30 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2009-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/aliasthis.h
+ */
+
+#pragma once
+
+#include "dsymbol.h"
+
+/**************************************************************/
+
+class AliasThis : public Dsymbol
+{
+public:
+ // alias Identifier this;
+ Identifier *ident;
+
+ AliasThis(Loc loc, Identifier *ident);
+
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ const char *kind();
+ AliasThis *isAliasThis() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/apply.c b/gcc/d/dmd/apply.c
new file mode 100644
index 0000000..f20e411
--- /dev/null
+++ b/gcc/d/dmd/apply.c
@@ -0,0 +1,150 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/apply.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "expression.h"
+#include "template.h"
+#include "visitor.h"
+
+
+/**************************************
+ * An Expression tree walker that will visit each Expression e in the tree,
+ * in depth-first evaluation order, and call fp(e,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ * 0 continue
+ * 1 done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+
+class PostorderExpressionVisitor : public StoppableVisitor
+{
+public:
+ StoppableVisitor *v;
+ PostorderExpressionVisitor(StoppableVisitor *v) : v(v) {}
+
+ bool doCond(Expression *e)
+ {
+ if (!stop && e)
+ e->accept(this);
+ return stop;
+ }
+ bool doCond(Expressions *e)
+ {
+ if (!e)
+ return false;
+ for (size_t i = 0; i < e->dim && !stop; i++)
+ doCond((*e)[i]);
+ return stop;
+ }
+ bool applyTo(Expression *e)
+ {
+ e->accept(v);
+ stop = v->stop;
+ return true;
+ }
+
+ void visit(Expression *e)
+ {
+ applyTo(e);
+ }
+
+ void visit(NewExp *e)
+ {
+ //printf("NewExp::apply(): %s\n", toChars());
+
+ doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
+ }
+
+ void visit(NewAnonClassExp *e)
+ {
+ //printf("NewAnonClassExp::apply(): %s\n", toChars());
+
+ doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
+ }
+
+ void visit(TypeidExp *e)
+ {
+ doCond(isExpression(e->obj)) || applyTo(e);
+ }
+
+ void visit(UnaExp *e)
+ {
+ doCond(e->e1) || applyTo(e);
+ }
+
+ void visit(BinExp *e)
+ {
+ doCond(e->e1) || doCond(e->e2) || applyTo(e);
+ }
+
+ void visit(AssertExp *e)
+ {
+ //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e->e1) || doCond(e->msg) || applyTo(e);
+ }
+
+ void visit(CallExp *e)
+ {
+ //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e->e1) || doCond(e->arguments) || applyTo(e);
+ }
+
+ void visit(ArrayExp *e)
+ {
+ //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e->e1) || doCond(e->arguments) || applyTo(e);
+ }
+
+ void visit(SliceExp *e)
+ {
+ doCond(e->e1) || doCond(e->lwr) || doCond(e->upr) || applyTo(e);
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ doCond(e->basis) || doCond(e->elements) || applyTo(e);
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ doCond(e->keys) || doCond(e->values) || applyTo(e);
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ if (e->stageflags & stageApply) return;
+ int old = e->stageflags;
+ e->stageflags |= stageApply;
+ doCond(e->elements) || applyTo(e);
+ e->stageflags = old;
+ }
+
+ void visit(TupleExp *e)
+ {
+ doCond(e->e0) || doCond(e->exps) || applyTo(e);
+ }
+
+ void visit(CondExp *e)
+ {
+ doCond(e->econd) || doCond(e->e1) || doCond(e->e2) || applyTo(e);
+ }
+};
+
+bool walkPostorder(Expression *e, StoppableVisitor *v)
+{
+ PostorderExpressionVisitor pv(v);
+ e->accept(&pv);
+ return v->stop;
+}
diff --git a/gcc/d/dmd/argtypes.c b/gcc/d/dmd/argtypes.c
new file mode 100644
index 0000000..cad8d4e
--- /dev/null
+++ b/gcc/d/dmd/argtypes.c
@@ -0,0 +1,486 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2010-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/argtypes.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "checkedint.h"
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+#include "hdrgen.h"
+
+/****************************************************
+ * This breaks a type down into 'simpler' types that can be passed to a function
+ * in registers, and returned in registers.
+ * It's highly platform dependent.
+ * Params:
+ * t = type to break down
+ * Returns:
+ * tuple of types, each element can be passed in a register.
+ * A tuple of zero length means the type cannot be passed/returned in registers.
+ */
+
+TypeTuple *toArgTypes(Type *t)
+{
+ class ToArgTypes : public Visitor
+ {
+ public:
+ TypeTuple *result;
+
+ ToArgTypes()
+ {
+ result = NULL;
+ }
+
+ void visit(Type *)
+ {
+ // not valid for a parameter
+ }
+
+ void visit(TypeError *)
+ {
+ result = new TypeTuple(Type::terror);
+ }
+
+ void visit(TypeBasic *t)
+ {
+ Type *t1 = NULL;
+ Type *t2 = NULL;
+ switch (t->ty)
+ {
+ case Tvoid:
+ return;
+
+ case Tbool:
+ case Tint8:
+ case Tuns8:
+ case Tint16:
+ case Tuns16:
+ case Tint32:
+ case Tuns32:
+ case Tfloat32:
+ case Tint64:
+ case Tuns64:
+ case Tint128:
+ case Tuns128:
+ case Tfloat64:
+ case Tfloat80:
+ t1 = t;
+ break;
+
+ case Timaginary32:
+ t1 = Type::tfloat32;
+ break;
+
+ case Timaginary64:
+ t1 = Type::tfloat64;
+ break;
+
+ case Timaginary80:
+ t1 = Type::tfloat80;
+ break;
+
+ case Tcomplex32:
+ if (global.params.is64bit)
+ t1 = Type::tfloat64;
+ else
+ {
+ t1 = Type::tfloat64;
+ t2 = Type::tfloat64;
+ }
+ break;
+
+ case Tcomplex64:
+ t1 = Type::tfloat64;
+ t2 = Type::tfloat64;
+ break;
+
+ case Tcomplex80:
+ t1 = Type::tfloat80;
+ t2 = Type::tfloat80;
+ break;
+
+ case Tchar:
+ t1 = Type::tuns8;
+ break;
+
+ case Twchar:
+ t1 = Type::tuns16;
+ break;
+
+ case Tdchar:
+ t1 = Type::tuns32;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ if (t1)
+ {
+ if (t2)
+ result = new TypeTuple(t1, t2);
+ else
+ result = new TypeTuple(t1);
+ }
+ else
+ result = new TypeTuple();
+ }
+
+ void visit(TypeVector *t)
+ {
+ result = new TypeTuple(t);
+ }
+
+ void visit(TypeSArray *t)
+ {
+ if (t->dim)
+ {
+ /* Should really be done as if it were a struct with dim members
+ * of the array's elements.
+ * I.e. int[2] should be done like struct S { int a; int b; }
+ */
+ dinteger_t sz = t->dim->toInteger();
+ // T[1] should be passed like T
+ if (sz == 1)
+ {
+ t->next->accept(this);
+ return;
+ }
+ }
+ result = new TypeTuple(); // pass on the stack for efficiency
+ }
+
+ void visit(TypeAArray *)
+ {
+ result = new TypeTuple(Type::tvoidptr);
+ }
+
+ void visit(TypePointer *)
+ {
+ result = new TypeTuple(Type::tvoidptr);
+ }
+
+ /*************************************
+ * Convert a floating point type into the equivalent integral type.
+ */
+
+ static Type *mergeFloatToInt(Type *t)
+ {
+ switch (t->ty)
+ {
+ case Tfloat32:
+ case Timaginary32:
+ t = Type::tint32;
+ break;
+ case Tfloat64:
+ case Timaginary64:
+ case Tcomplex32:
+ t = Type::tint64;
+ break;
+ default:
+ assert(0);
+ }
+ return t;
+ }
+
+ /*************************************
+ * This merges two types into an 8byte type.
+ * Params:
+ * t1 = first type (can be null)
+ * t2 = second type (can be null)
+ * offset2 = offset of t2 from start of t1
+ * Returns:
+ * type that encompasses both t1 and t2, null if cannot be done
+ */
+
+ static Type *argtypemerge(Type *t1, Type *t2, unsigned offset2)
+ {
+ //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2);
+ if (!t1)
+ { assert(!t2 || offset2 == 0);
+ return t2;
+ }
+ if (!t2)
+ return t1;
+
+ const d_uns64 sz1 = t1->size(Loc());
+ const d_uns64 sz2 = t2->size(Loc());
+ assert(sz1 != SIZE_INVALID && sz2 != SIZE_INVALID);
+
+ if (t1->ty != t2->ty &&
+ (t1->ty == Tfloat80 || t2->ty == Tfloat80))
+ return NULL;
+
+ // [float,float] => [cfloat]
+ if (t1->ty == Tfloat32 && t2->ty == Tfloat32 && offset2 == 4)
+ return Type::tfloat64;
+
+ // Merging floating and non-floating types produces the non-floating type
+ if (t1->isfloating())
+ {
+ if (!t2->isfloating())
+ t1 = mergeFloatToInt(t1);
+ }
+ else if (t2->isfloating())
+ t2 = mergeFloatToInt(t2);
+
+ Type *t;
+
+ // Pick type with larger size
+ if (sz1 < sz2)
+ t = t2;
+ else
+ t = t1;
+
+ // If t2 does not lie within t1, need to increase the size of t to enclose both
+ assert(sz2 < UINT64_MAX - UINT32_MAX);
+ if (offset2 && sz1 < offset2 + sz2)
+ {
+ switch (offset2 + sz2)
+ {
+ case 2:
+ t = Type::tint16;
+ break;
+ case 3:
+ case 4:
+ t = Type::tint32;
+ break;
+ default:
+ t = Type::tint64;
+ break;
+ }
+ }
+ return t;
+ }
+
+ void visit(TypeDArray *)
+ {
+ /* Should be done as if it were:
+ * struct S { size_t length; void* ptr; }
+ */
+ if (global.params.is64bit && !global.params.isLP64)
+ {
+ // For AMD64 ILP32 ABI, D arrays fit into a single integer register.
+ unsigned offset = (unsigned)Type::tsize_t->size(Loc());
+ Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset);
+ if (t)
+ {
+ result = new TypeTuple(t);
+ return;
+ }
+ }
+ result = new TypeTuple(Type::tsize_t, Type::tvoidptr);
+ }
+
+ void visit(TypeDelegate *)
+ {
+ /* Should be done as if it were:
+ * struct S { size_t length; void* ptr; }
+ */
+ if (global.params.is64bit && !global.params.isLP64)
+ {
+ // For AMD64 ILP32 ABI, delegates fit into a single integer register.
+ unsigned offset = (unsigned)Type::tsize_t->size(Loc());
+ Type *t = argtypemerge(Type::tsize_t, Type::tvoidptr, offset);
+ if (t)
+ {
+ result = new TypeTuple(t);
+ return;
+ }
+ }
+ result = new TypeTuple(Type::tvoidptr, Type::tvoidptr);
+ }
+
+ void visit(TypeStruct *t)
+ {
+ //printf("TypeStruct::toArgTypes() %s\n", t->toChars());
+ if (!t->sym->isPOD() || t->sym->fields.dim == 0)
+ {
+ Lmemory:
+ //printf("\ttoArgTypes() %s => [ ]\n", t->toChars());
+ result = new TypeTuple(); // pass on the stack
+ return;
+ }
+ Type *t1 = NULL;
+ Type *t2 = NULL;
+ const d_uns64 sz = t->size(Loc());
+ assert(sz < 0xFFFFFFFF);
+ switch ((unsigned)sz)
+ {
+ case 1:
+ t1 = Type::tint8;
+ break;
+ case 2:
+ t1 = Type::tint16;
+ break;
+ case 3:
+ if (!global.params.is64bit)
+ goto Lmemory;
+ /* fall through */
+ case 4:
+ t1 = Type::tint32;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ if (!global.params.is64bit)
+ goto Lmemory;
+ /* fall through */
+ case 8:
+ t1 = Type::tint64;
+ break;
+ case 16:
+ t1 = NULL; // could be a TypeVector
+ break;
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ if (!global.params.is64bit)
+ goto Lmemory;
+ t1 = NULL;
+ break;
+ default:
+ goto Lmemory;
+ }
+ if (global.params.is64bit && t->sym->fields.dim)
+ {
+ t1 = NULL;
+ for (size_t i = 0; i < t->sym->fields.dim; i++)
+ {
+ VarDeclaration *f = t->sym->fields[i];
+ //printf(" [%d] %s f->type = %s\n", (int)i, f->toChars(), f->type->toChars());
+
+ TypeTuple *tup = toArgTypes(f->type);
+ if (!tup)
+ goto Lmemory;
+ size_t dim = tup->arguments->dim;
+ Type *ft1 = NULL;
+ Type *ft2 = NULL;
+ switch (dim)
+ {
+ case 2:
+ ft1 = (*tup->arguments)[0]->type;
+ ft2 = (*tup->arguments)[1]->type;
+ break;
+ case 1:
+ if (f->offset < 8)
+ ft1 = (*tup->arguments)[0]->type;
+ else
+ ft2 = (*tup->arguments)[0]->type;
+ break;
+ default:
+ goto Lmemory;
+ }
+
+ if (f->offset & 7)
+ {
+ // Misaligned fields goto Lmemory
+ unsigned alignsz = f->type->alignsize();
+ if (f->offset & (alignsz - 1))
+ goto Lmemory;
+
+ // Fields that overlap the 8byte boundary goto Lmemory
+ const d_uns64 fieldsz = f->type->size(Loc());
+ assert(fieldsz != SIZE_INVALID && fieldsz < UINT64_MAX - UINT32_MAX);
+ if (f->offset < 8 && (f->offset + fieldsz) > 8)
+ goto Lmemory;
+ }
+
+ // First field in 8byte must be at start of 8byte
+ assert(t1 || f->offset == 0);
+ //printf("ft1 = %s\n", ft1 ? ft1->toChars() : "null");
+ //printf("ft2 = %s\n", ft2 ? ft2->toChars() : "null");
+ if (ft1)
+ {
+ t1 = argtypemerge(t1, ft1, f->offset);
+ if (!t1)
+ goto Lmemory;
+ }
+
+ if (ft2)
+ {
+ unsigned off2 = f->offset;
+ if (ft1)
+ off2 = 8;
+ if (!t2 && off2 != 8)
+ goto Lmemory;
+ assert(t2 || off2 == 8);
+ t2 = argtypemerge(t2, ft2, off2 - 8);
+ if (!t2)
+ goto Lmemory;
+ }
+ }
+
+ if (t2)
+ {
+ if (t1->isfloating() && t2->isfloating())
+ {
+ if ((t1->ty == Tfloat32 || t1->ty == Tfloat64) &&
+ (t2->ty == Tfloat32 || t2->ty == Tfloat64))
+ ;
+ else
+ goto Lmemory;
+ }
+ else if (t1->isfloating())
+ goto Lmemory;
+ else if (t2->isfloating())
+ goto Lmemory;
+ else
+ {
+ }
+ }
+ }
+
+ //printf("\ttoArgTypes() %s => [%s,%s]\n", t->toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : "");
+
+ if (t1)
+ {
+ //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars());
+ if (t2)
+ result = new TypeTuple(t1, t2);
+ else
+ result = new TypeTuple(t1);
+ }
+ else
+ goto Lmemory;
+ }
+
+ void visit(TypeEnum *t)
+ {
+ t->toBasetype()->accept(this);
+ }
+
+ void visit(TypeClass *)
+ {
+ result = new TypeTuple(Type::tvoidptr);
+ }
+ };
+
+ ToArgTypes v;
+ t->accept(&v);
+ return v.result;
+}
diff --git a/gcc/d/dmd/arrayop.c b/gcc/d/dmd/arrayop.c
new file mode 100644
index 0000000..0ea0d32
--- /dev/null
+++ b/gcc/d/dmd/arrayop.c
@@ -0,0 +1,638 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/arrayop.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "root/rmem.h"
+#include "root/aav.h"
+
+#include "mars.h"
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "scope.h"
+#include "id.h"
+#include "module.h"
+#include "init.h"
+#include "tokens.h"
+
+void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments);
+Expression *buildArrayLoop(Expression *e, Parameters *fparams);
+Expression *semantic(Expression *e, Scope *sc);
+
+/**************************************
+ * Hash table of array op functions already generated or known about.
+ */
+
+AA *arrayfuncs;
+
+/**************************************
+ * Structure to contain information needed to insert an array op call
+ */
+
+FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc)
+{
+ Parameters *fparams = new Parameters();
+ Expression *loopbody = buildArrayLoop(exp, fparams);
+
+ /* Construct the function body:
+ * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++)
+ * loopbody;
+ * return p;
+ */
+
+ Parameter *p = (*fparams)[0];
+ // foreach (i; 0 .. p.length)
+ Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
+ new Parameter(0, NULL, Id::p, NULL),
+ new IntegerExp(Loc(), 0, Type::tsize_t),
+ new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
+ new ExpStatement(Loc(), loopbody),
+ Loc());
+ //printf("%s\n", s1->toChars());
+ Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
+ //printf("s2: %s\n", s2->toChars());
+ Statement *fbody = new CompoundStatement(Loc(), s1, s2);
+
+ // Built-in array ops should be @trusted, pure, nothrow and nogc
+ StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc;
+
+ /* Construct the function
+ */
+ TypeFunction *ftype = new TypeFunction(fparams, exp->e1->type, 0, LINKc, stc);
+ //printf("fd: %s %s\n", ident->toChars(), ftype->toChars());
+ FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
+ fd->fbody = fbody;
+ fd->protection = Prot(PROTpublic);
+ fd->linkage = LINKc;
+ fd->isArrayOp = 1;
+
+ sc->_module->importedFrom->members->push(fd);
+
+ sc = sc->push();
+ sc->parent = sc->_module->importedFrom;
+ sc->stc = 0;
+ sc->linkage = LINKc;
+ fd->semantic(sc);
+ fd->semantic2(sc);
+ unsigned errors = global.startGagging();
+ fd->semantic3(sc);
+ if (global.endGagging(errors))
+ {
+ fd->type = Type::terror;
+ fd->errors = true;
+ fd->fbody = NULL;
+ }
+ sc->pop();
+
+ return fd;
+}
+
+/**********************************************
+ * Check that there are no uses of arrays without [].
+ */
+bool isArrayOpValid(Expression *e)
+{
+ if (e->op == TOKslice)
+ return true;
+ if (e->op == TOKarrayliteral)
+ {
+ Type *t = e->type->toBasetype();
+ while (t->ty == Tarray || t->ty == Tsarray)
+ t = t->nextOf()->toBasetype();
+ return (t->ty != Tvoid);
+ }
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (isUnaArrayOp(e->op))
+ {
+ return isArrayOpValid(((UnaExp *)e)->e1);
+ }
+ if (isBinArrayOp(e->op) ||
+ isBinAssignArrayOp(e->op) ||
+ e->op == TOKassign)
+ {
+ BinExp *be = (BinExp *)e;
+ return isArrayOpValid(be->e1) && isArrayOpValid(be->e2);
+ }
+ if (e->op == TOKconstruct)
+ {
+ BinExp *be = (BinExp *)e;
+ return be->e1->op == TOKslice && isArrayOpValid(be->e2);
+ }
+ if (e->op == TOKcall)
+ {
+ return false; // TODO: Decide if [] is required after arrayop calls.
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool isNonAssignmentArrayOp(Expression *e)
+{
+ if (e->op == TOKslice)
+ return isNonAssignmentArrayOp(((SliceExp *)e)->e1);
+
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ return (isUnaArrayOp(e->op) || isBinArrayOp(e->op));
+ }
+ return false;
+}
+
+bool checkNonAssignmentArrayOp(Expression *e, bool suggestion)
+{
+ if (isNonAssignmentArrayOp(e))
+ {
+ const char *s = "";
+ if (suggestion)
+ s = " (possible missing [])";
+ e->error("array operation %s without destination memory not allowed%s", e->toChars(), s);
+ return true;
+ }
+ return false;
+}
+
+/***********************************
+ * Construct the array operation expression.
+ */
+
+Expression *arrayOp(BinExp *e, Scope *sc)
+{
+ //printf("BinExp::arrayOp() %s\n", toChars());
+
+ Type *tb = e->type->toBasetype();
+ assert(tb->ty == Tarray || tb->ty == Tsarray);
+ Type *tbn = tb->nextOf()->toBasetype();
+ if (tbn->ty == Tvoid)
+ {
+ e->error("cannot perform array operations on void[] arrays");
+ return new ErrorExp();
+ }
+ if (!isArrayOpValid(e))
+ {
+ e->error("invalid array operation %s (possible missing [])", e->toChars());
+ return new ErrorExp();
+ }
+
+ Expressions *arguments = new Expressions();
+
+ /* The expression to generate an array operation for is mangled
+ * into a name to use as the array operation function name.
+ * Mangle in the operands and operators in RPN order, and type.
+ */
+ OutBuffer buf;
+ buf.writestring("_array");
+ buildArrayIdent(e, &buf, arguments);
+ buf.writeByte('_');
+
+ /* Append deco of array element type
+ */
+ buf.writestring(e->type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
+
+ char *name = buf.peekString();
+ Identifier *ident = Identifier::idPool(name);
+
+ FuncDeclaration **pFd = (FuncDeclaration **)dmd_aaGet(&arrayfuncs, (void *)ident);
+ FuncDeclaration *fd = *pFd;
+
+ if (!fd)
+ fd = buildArrayOp(ident, e, sc);
+
+ if (fd && fd->errors)
+ {
+ const char *fmt;
+ if (tbn->ty == Tstruct || tbn->ty == Tclass)
+ fmt = "invalid array operation '%s' because %s doesn't support necessary arithmetic operations";
+ else if (!tbn->isscalar())
+ fmt = "invalid array operation '%s' because %s is not a scalar type";
+ else
+ fmt = "invalid array operation '%s' for element type %s";
+
+ e->error(fmt, e->toChars(), tbn->toChars());
+ return new ErrorExp();
+ }
+
+ *pFd = fd;
+
+ Expression *ev = new VarExp(e->loc, fd);
+ Expression *ec = new CallExp(e->loc, ev, arguments);
+
+ return semantic(ec, sc);
+}
+
+Expression *arrayOp(BinAssignExp *e, Scope *sc)
+{
+ //printf("BinAssignExp::arrayOp() %s\n", toChars());
+
+ /* Check that the elements of e1 can be assigned to
+ */
+ Type *tn = e->e1->type->toBasetype()->nextOf();
+
+ if (tn && (!tn->isMutable() || !tn->isAssignable()))
+ {
+ e->error("slice %s is not mutable", e->e1->toChars());
+ return new ErrorExp();
+ }
+ if (e->e1->op == TOKarrayliteral)
+ {
+ return e->e1->modifiableLvalue(sc, e->e1);
+ }
+
+ return arrayOp((BinExp *)e, sc);
+}
+
+/******************************************
+ * Construct the identifier for the array operation function,
+ * and build the argument list to pass to it.
+ */
+
+void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments)
+{
+ class BuildArrayIdentVisitor : public Visitor
+ {
+ OutBuffer *buf;
+ Expressions *arguments;
+ public:
+ BuildArrayIdentVisitor(OutBuffer *buf, Expressions *arguments)
+ : buf(buf), arguments(arguments)
+ {
+ }
+
+ void visit(Expression *e)
+ {
+ buf->writestring("Exp");
+ arguments->shift(e);
+ }
+
+ void visit(CastExp *e)
+ {
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ e->e1->accept(this);
+ }
+ else
+ visit((Expression *)e);
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ buf->writestring("Slice");
+ arguments->shift(e);
+ }
+
+ void visit(SliceExp *e)
+ {
+ buf->writestring("Slice");
+ arguments->shift(e);
+ }
+
+ void visit(AssignExp *e)
+ {
+ /* Evaluate assign expressions right to left
+ */
+ e->e2->accept(this);
+ e->e1->accept(this);
+ buf->writestring("Assign");
+ }
+
+ void visit(BinAssignExp *e)
+ {
+ /* Evaluate assign expressions right to left
+ */
+ e->e2->accept(this);
+ e->e1->accept(this);
+ const char *s;
+ switch(e->op)
+ {
+ case TOKaddass: s = "Addass"; break;
+ case TOKminass: s = "Minass"; break;
+ case TOKmulass: s = "Mulass"; break;
+ case TOKdivass: s = "Divass"; break;
+ case TOKmodass: s = "Modass"; break;
+ case TOKxorass: s = "Xorass"; break;
+ case TOKandass: s = "Andass"; break;
+ case TOKorass: s = "Orass"; break;
+ case TOKpowass: s = "Powass"; break;
+ default: assert(0);
+ }
+ buf->writestring(s);
+ }
+
+ void visit(NegExp *e)
+ {
+ e->e1->accept(this);
+ buf->writestring("Neg");
+ }
+
+ void visit(ComExp *e)
+ {
+ e->e1->accept(this);
+ buf->writestring("Com");
+ }
+
+ void visit(BinExp *e)
+ {
+ /* Evaluate assign expressions left to right
+ */
+ const char *s = NULL;
+ switch(e->op)
+ {
+ case TOKadd: s = "Add"; break;
+ case TOKmin: s = "Min"; break;
+ case TOKmul: s = "Mul"; break;
+ case TOKdiv: s = "Div"; break;
+ case TOKmod: s = "Mod"; break;
+ case TOKxor: s = "Xor"; break;
+ case TOKand: s = "And"; break;
+ case TOKor: s = "Or"; break;
+ case TOKpow: s = "Pow"; break;
+ default: break;
+ }
+ if (s)
+ {
+ Type *tb = e->type->toBasetype();
+ Type *t1 = e->e1->type->toBasetype();
+ Type *t2 = e->e2->type->toBasetype();
+ e->e1->accept(this);
+ if (t1->ty == Tarray &&
+ ((t2->ty == Tarray && !t1->equivalent(tb)) ||
+ (t2->ty != Tarray && !t1->nextOf()->equivalent(e->e2->type))))
+ {
+ // Bugzilla 12780: if A is narrower than B
+ // A[] op B[]
+ // A[] op B
+ buf->writestring("Of");
+ buf->writestring(t1->nextOf()->mutableOf()->deco);
+ }
+ e->e2->accept(this);
+ if (t2->ty == Tarray &&
+ ((t1->ty == Tarray && !t2->equivalent(tb)) ||
+ (t1->ty != Tarray && !t2->nextOf()->equivalent(e->e1->type))))
+ {
+ // Bugzilla 12780: if B is narrower than A:
+ // A[] op B[]
+ // A op B[]
+ buf->writestring("Of");
+ buf->writestring(t2->nextOf()->mutableOf()->deco);
+ }
+ buf->writestring(s);
+ }
+ else
+ visit((Expression *)e);
+ }
+ };
+
+ BuildArrayIdentVisitor v(buf, arguments);
+ e->accept(&v);
+}
+
+/******************************************
+ * Construct the inner loop for the array operation function,
+ * and build the parameter list.
+ */
+
+Expression *buildArrayLoop(Expression *e, Parameters *fparams)
+{
+ class BuildArrayLoopVisitor : public Visitor
+ {
+ Parameters *fparams;
+ Expression *result;
+
+ public:
+ BuildArrayLoopVisitor(Parameters *fparams)
+ : fparams(fparams), result(NULL)
+ {
+ }
+
+ void visit(Expression *e)
+ {
+ Identifier *id = Identifier::generateId("c", fparams->dim);
+ Parameter *param = new Parameter(0, e->type, id, NULL);
+ fparams->shift(param);
+ result = new IdentifierExp(Loc(), id);
+ }
+
+ void visit(CastExp *e)
+ {
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ e->e1->accept(this);
+ }
+ else
+ visit((Expression *)e);
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ Identifier *id = Identifier::generateId("p", fparams->dim);
+ Parameter *param = new Parameter(STCconst, e->type, id, NULL);
+ fparams->shift(param);
+ Expression *ie = new IdentifierExp(Loc(), id);
+ Expression *index = new IdentifierExp(Loc(), Id::p);
+ result = new ArrayExp(Loc(), ie, index);
+ }
+
+ void visit(SliceExp *e)
+ {
+ Identifier *id = Identifier::generateId("p", fparams->dim);
+ Parameter *param = new Parameter(STCconst, e->type, id, NULL);
+ fparams->shift(param);
+ Expression *ie = new IdentifierExp(Loc(), id);
+ Expression *index = new IdentifierExp(Loc(), Id::p);
+ result = new ArrayExp(Loc(), ie, index);
+ }
+
+ void visit(AssignExp *e)
+ {
+ /* Evaluate assign expressions right to left
+ */
+ Expression *ex2 = buildArrayLoop(e->e2);
+ /* Need the cast because:
+ * b = c + p[i];
+ * where b is a byte fails because (c + p[i]) is an int
+ * which cannot be implicitly cast to byte.
+ */
+ ex2 = new CastExp(Loc(), ex2, e->e1->type->nextOf());
+ Expression *ex1 = buildArrayLoop(e->e1);
+ Parameter *param = (*fparams)[0];
+ param->storageClass = 0;
+ result = new AssignExp(Loc(), ex1, ex2);
+ }
+
+ void visit(BinAssignExp *e)
+ {
+ /* Evaluate assign expressions right to left
+ */
+ Expression *ex2 = buildArrayLoop(e->e2);
+ Expression *ex1 = buildArrayLoop(e->e1);
+ Parameter *param = (*fparams)[0];
+ param->storageClass = 0;
+ switch(e->op)
+ {
+ case TOKaddass: result = new AddAssignExp(e->loc, ex1, ex2); return;
+ case TOKminass: result = new MinAssignExp(e->loc, ex1, ex2); return;
+ case TOKmulass: result = new MulAssignExp(e->loc, ex1, ex2); return;
+ case TOKdivass: result = new DivAssignExp(e->loc, ex1, ex2); return;
+ case TOKmodass: result = new ModAssignExp(e->loc, ex1, ex2); return;
+ case TOKxorass: result = new XorAssignExp(e->loc, ex1, ex2); return;
+ case TOKandass: result = new AndAssignExp(e->loc, ex1, ex2); return;
+ case TOKorass: result = new OrAssignExp(e->loc, ex1, ex2); return;
+ case TOKpowass: result = new PowAssignExp(e->loc, ex1, ex2); return;
+ default:
+ assert(0);
+ }
+ }
+
+ void visit(NegExp *e)
+ {
+ Expression *ex1 = buildArrayLoop(e->e1);
+ result = new NegExp(Loc(), ex1);
+ }
+
+ void visit(ComExp *e)
+ {
+ Expression *ex1 = buildArrayLoop(e->e1);
+ result = new ComExp(Loc(), ex1);
+ }
+
+ void visit(BinExp *e)
+ {
+ if (isBinArrayOp(e->op))
+ {
+ /* Evaluate assign expressions left to right
+ */
+ BinExp *be = (BinExp *)e->copy();
+ be->e1 = buildArrayLoop(be->e1);
+ be->e2 = buildArrayLoop(be->e2);
+ be->type = NULL;
+ result = be;
+ return;
+ }
+ else
+ {
+ visit((Expression *)e);
+ return;
+ }
+ }
+
+ Expression *buildArrayLoop(Expression *e)
+ {
+ e->accept(this);
+ return result;
+ }
+ };
+
+ BuildArrayLoopVisitor v(fparams);
+ return v.buildArrayLoop(e);
+}
+
+/***********************************************
+ * Test if expression is a unary array op.
+ */
+
+bool isUnaArrayOp(TOK op)
+{
+ switch (op)
+ {
+ case TOKneg:
+ case TOKtilde:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************************
+ * Test if expression is a binary array op.
+ */
+
+bool isBinArrayOp(TOK op)
+{
+ switch (op)
+ {
+ case TOKadd:
+ case TOKmin:
+ case TOKmul:
+ case TOKdiv:
+ case TOKmod:
+ case TOKxor:
+ case TOKand:
+ case TOKor:
+ case TOKpow:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************************
+ * Test if expression is a binary assignment array op.
+ */
+
+bool isBinAssignArrayOp(TOK op)
+{
+ switch (op)
+ {
+ case TOKaddass:
+ case TOKminass:
+ case TOKmulass:
+ case TOKdivass:
+ case TOKmodass:
+ case TOKxorass:
+ case TOKandass:
+ case TOKorass:
+ case TOKpowass:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************************
+ * Test if operand is a valid array op operand.
+ */
+
+bool isArrayOpOperand(Expression *e)
+{
+ //printf("Expression::isArrayOpOperand() %s\n", e->toChars());
+ if (e->op == TOKslice)
+ return true;
+ if (e->op == TOKarrayliteral)
+ {
+ Type *t = e->type->toBasetype();
+ while (t->ty == Tarray || t->ty == Tsarray)
+ t = t->nextOf()->toBasetype();
+ return (t->ty != Tvoid);
+ }
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tarray)
+ {
+ return (isUnaArrayOp(e->op) ||
+ isBinArrayOp(e->op) ||
+ isBinAssignArrayOp(e->op) ||
+ e->op == TOKassign);
+ }
+ return false;
+}
diff --git a/gcc/d/dmd/arraytypes.h b/gcc/d/dmd/arraytypes.h
new file mode 100644
index 0000000..a3d305e
--- /dev/null
+++ b/gcc/d/dmd/arraytypes.h
@@ -0,0 +1,62 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2006-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+
+typedef Array<class TemplateParameter *> TemplateParameters;
+
+typedef Array<class Expression *> Expressions;
+
+typedef Array<class Statement *> Statements;
+
+typedef Array<struct BaseClass *> BaseClasses;
+
+typedef Array<class ClassDeclaration *> ClassDeclarations;
+
+typedef Array<class Dsymbol *> Dsymbols;
+
+typedef Array<class RootObject *> Objects;
+
+typedef Array<class FuncDeclaration *> FuncDeclarations;
+
+typedef Array<class Parameter *> Parameters;
+
+typedef Array<class Identifier *> Identifiers;
+
+typedef Array<class Initializer *> Initializers;
+
+typedef Array<class VarDeclaration *> VarDeclarations;
+
+typedef Array<class Type *> Types;
+typedef Array<class Catch *> Catches;
+
+typedef Array<class StaticDtorDeclaration *> StaticDtorDeclarations;
+
+typedef Array<class SharedStaticDtorDeclaration *> SharedStaticDtorDeclarations;
+
+typedef Array<class AliasDeclaration *> AliasDeclarations;
+
+typedef Array<class Module *> Modules;
+
+typedef Array<struct File *> Files;
+
+typedef Array<class CaseStatement *> CaseStatements;
+
+typedef Array<class ScopeStatement *> ScopeStatements;
+
+typedef Array<class GotoCaseStatement *> GotoCaseStatements;
+
+typedef Array<class ReturnStatement *> ReturnStatements;
+
+typedef Array<class GotoStatement *> GotoStatements;
+
+typedef Array<class TemplateInstance *> TemplateInstances;
diff --git a/gcc/d/dmd/attrib.c b/gcc/d/dmd/attrib.c
new file mode 100644
index 0000000..c4270ea
--- /dev/null
+++ b/gcc/d/dmd/attrib.c
@@ -0,0 +1,1602 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/attrib.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h> // memcpy()
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#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 "target.h"
+#include "template.h"
+#include "utf.h"
+#include "mtype.h"
+
+bool definitelyValueParameter(Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+
+/********************************* AttribDeclaration ****************************/
+
+AttribDeclaration::AttribDeclaration(Dsymbols *decl)
+ : Dsymbol()
+{
+ this->decl = decl;
+}
+
+Dsymbols *AttribDeclaration::include(Scope *, ScopeDsymbol *)
+{
+ return decl;
+}
+
+int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+ Dsymbols *d = include(_scope, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ if (s)
+ {
+ if (s->apply(fp, param))
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/****************************************
+ * Create a new scope if one or more given attributes
+ * are different from the sc's.
+ * If the returned scope != sc, the caller should pop
+ * the scope after it used.
+ */
+Scope *AttribDeclaration::createNewScope(Scope *sc,
+ StorageClass stc, LINK linkage, CPPMANGLE cppmangle, Prot protection,
+ int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining)
+{
+ Scope *sc2 = sc;
+ if (stc != sc->stc ||
+ linkage != sc->linkage ||
+ cppmangle != sc->cppmangle ||
+ !protection.isSubsetOf(sc->protection) ||
+ explicitProtection != sc->explicitProtection ||
+ aligndecl != sc->aligndecl ||
+ inlining != sc->inlining)
+ {
+ // create new one for changes
+ sc2 = sc->copy();
+ sc2->stc = stc;
+ sc2->linkage = linkage;
+ sc2->cppmangle = cppmangle;
+ sc2->protection = protection;
+ sc2->explicitProtection = explicitProtection;
+ sc2->aligndecl = aligndecl;
+ sc2->inlining = inlining;
+ }
+ return sc2;
+}
+
+/****************************************
+ * A hook point to supply scope for members.
+ * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
+ */
+Scope *AttribDeclaration::newScope(Scope *sc)
+{
+ return sc;
+}
+
+void AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+ Dsymbols *d = include(sc, sds);
+
+ if (d)
+ {
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ //printf("\taddMember %s to %s\n", s->toChars(), sds->toChars());
+ s->addMember(sc2, sds);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+}
+
+void AttribDeclaration::setScope(Scope *sc)
+{
+ Dsymbols *d = include(sc, NULL);
+
+ //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
+ if (d)
+ {
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->setScope(sc2);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+}
+
+void AttribDeclaration::importAll(Scope *sc)
+{
+ Dsymbols *d = include(sc, NULL);
+
+ //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
+ if (d)
+ {
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->importAll(sc2);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+}
+
+void AttribDeclaration::semantic(Scope *sc)
+{
+ if (semanticRun != PASSinit)
+ return;
+ semanticRun = PASSsemantic;
+ Dsymbols *d = include(sc, NULL);
+
+ //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
+ if (d)
+ {
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->semantic(sc2);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+ semanticRun = PASSsemanticdone;
+}
+
+void AttribDeclaration::semantic2(Scope *sc)
+{
+ Dsymbols *d = include(sc, NULL);
+
+ if (d)
+ {
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->semantic2(sc2);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+}
+
+void AttribDeclaration::semantic3(Scope *sc)
+{
+ Dsymbols *d = include(sc, NULL);
+
+ if (d)
+ {
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->semantic3(sc2);
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+}
+
+void AttribDeclaration::addComment(const utf8_t *comment)
+{
+ //printf("AttribDeclaration::addComment %s\n", comment);
+ if (comment)
+ {
+ Dsymbols *d = include(NULL, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ //printf("AttribDeclaration::addComment %s\n", s->toChars());
+ s->addComment(comment);
+ }
+ }
+ }
+}
+
+void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+ Dsymbols *d = include(NULL, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->setFieldOffset(ad, poffset, isunion);
+ }
+ }
+}
+
+bool AttribDeclaration::hasPointers()
+{
+ Dsymbols *d = include(NULL, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ if (s->hasPointers())
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AttribDeclaration::hasStaticCtorOrDtor()
+{
+ Dsymbols *d = include(NULL, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ if (s->hasStaticCtorOrDtor())
+ return true;
+ }
+ }
+ return false;
+}
+
+const char *AttribDeclaration::kind() const
+{
+ return "attribute";
+}
+
+bool AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+ Dsymbols *d = include(NULL, NULL);
+
+ return Dsymbol::oneMembers(d, ps, ident);
+}
+
+void AttribDeclaration::checkCtorConstInit()
+{
+ Dsymbols *d = include(NULL, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->checkCtorConstInit();
+ }
+ }
+}
+
+/****************************************
+ */
+
+void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
+{
+ Dsymbols *d = include(NULL, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->addLocalClass(aclasses);
+ }
+ }
+}
+
+/************************* StorageClassDeclaration ****************************/
+
+StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ this->stc = stc;
+}
+
+Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
+}
+
+bool StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+ bool t = Dsymbol::oneMembers(decl, ps, ident);
+ if (t && *ps)
+ {
+ /* This is to deal with the following case:
+ * struct Tick {
+ * template to(T) { const T to() { ... } }
+ * }
+ * For eponymous function templates, the 'const' needs to get attached to 'to'
+ * before the semantic analysis of 'to', so that template overloading based on the
+ * 'this' pointer can be successful.
+ */
+
+ FuncDeclaration *fd = (*ps)->isFuncDeclaration();
+ if (fd)
+ {
+ /* Use storage_class2 instead of storage_class otherwise when we do .di generation
+ * we'll wind up with 'const const' rather than 'const'.
+ */
+ /* Don't think we need to worry about mutually exclusive storage classes here
+ */
+ fd->storage_class2 |= stc;
+ }
+ }
+ return t;
+}
+
+void StorageClassDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+ Dsymbols *d = include(sc, sds);
+ if (d)
+ {
+ Scope *sc2 = newScope(sc);
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ //printf("\taddMember %s to %s\n", s->toChars(), sds->toChars());
+ // STClocal needs to be attached before the member is added to the scope (because it influences the parent symbol)
+ if (Declaration *decl = s->isDeclaration())
+ {
+ decl->storage_class |= stc & STClocal;
+ if (StorageClassDeclaration *sdecl = s->isStorageClassDeclaration())
+ {
+ sdecl->stc |= stc & STClocal;
+ }
+ }
+ s->addMember(sc2, sds);
+ }
+ if (sc2 != sc)
+ sc2->pop();
+ }
+}
+
+Scope *StorageClassDeclaration::newScope(Scope *sc)
+{
+ StorageClass scstc = sc->stc;
+
+ /* These sets of storage classes are mutually exclusive,
+ * so choose the innermost or most recent one.
+ */
+ if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest))
+ scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest);
+ if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared))
+ scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared);
+ if (stc & (STCconst | STCimmutable | STCmanifest))
+ scstc &= ~(STCconst | STCimmutable | STCmanifest);
+ if (stc & (STCgshared | STCshared | STCtls))
+ scstc &= ~(STCgshared | STCshared | STCtls);
+ if (stc & (STCsafe | STCtrusted | STCsystem))
+ scstc &= ~(STCsafe | STCtrusted | STCsystem);
+ scstc |= stc;
+ //printf("scstc = x%llx\n", scstc);
+
+ return createNewScope(sc, scstc, sc->linkage, sc->cppmangle,
+ sc->protection, sc->explicitProtection, sc->aligndecl,
+ sc->inlining);
+}
+
+/********************************* DeprecatedDeclaration ****************************/
+
+DeprecatedDeclaration::DeprecatedDeclaration(Expression *msg, Dsymbols *decl)
+ : StorageClassDeclaration(STCdeprecated, decl)
+{
+ this->msg = msg;
+ this->msgstr = NULL;
+}
+
+Dsymbol *DeprecatedDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new DeprecatedDeclaration(msg->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl));
+}
+
+/**
+ * Provides a new scope with `STCdeprecated` and `Scope.depdecl` set
+ *
+ * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
+ * in any function overriding `newScope`), then set the `Scope`'s depdecl.
+ *
+ * Returns:
+ * Always a new scope, to use for this `DeprecatedDeclaration`'s members.
+ */
+Scope *DeprecatedDeclaration::newScope(Scope *sc)
+{
+ Scope *scx = StorageClassDeclaration::newScope(sc);
+ // The enclosing scope is deprecated as well
+ if (scx == sc)
+ scx = sc->push();
+ scx->depdecl = this;
+ return scx;
+}
+
+void DeprecatedDeclaration::setScope(Scope *sc)
+{
+ //printf("DeprecatedDeclaration::setScope() %p\n", this);
+ if (decl)
+ Dsymbol::setScope(sc); // for forward reference
+ return AttribDeclaration::setScope(sc);
+}
+
+/**
+ * Run the DeprecatedDeclaration's semantic2 phase then its members.
+ *
+ * The message set via a `DeprecatedDeclaration` can be either of:
+ * - a string literal
+ * - an enum
+ * - a static immutable
+ * So we need to call ctfe to resolve it.
+ * Afterward forwards to the members' semantic2.
+ */
+void DeprecatedDeclaration::semantic2(Scope *sc)
+{
+ getMessage();
+ StorageClassDeclaration::semantic2(sc);
+}
+
+const char *DeprecatedDeclaration::getMessage()
+{
+ if (Scope *sc = _scope)
+ {
+ _scope = NULL;
+
+ sc = sc->startCTFE();
+ msg = ::semantic(msg, sc);
+ msg = resolveProperties(sc, msg);
+ sc = sc->endCTFE();
+ msg = msg->ctfeInterpret();
+
+ if (StringExp *se = msg->toStringExp())
+ msgstr = (char *)se->string;
+ else
+ msg->error("compile time constant expected, not '%s'", msg->toChars());
+ }
+ return msgstr;
+}
+
+/********************************* LinkDeclaration ****************************/
+
+LinkDeclaration::LinkDeclaration(LINK p, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
+ linkage = (p == LINKsystem) ? Target::systemLinkage() : p;
+}
+
+LinkDeclaration *LinkDeclaration::create(LINK p, Dsymbols *decl)
+{
+ return new LinkDeclaration(p, decl);
+}
+
+Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *LinkDeclaration::newScope(Scope *sc)
+{
+ return createNewScope(sc, sc->stc, this->linkage, sc->cppmangle,
+ sc->protection, sc->explicitProtection, sc->aligndecl,
+ sc->inlining);
+}
+
+const char *LinkDeclaration::toChars()
+{
+ return "extern ()";
+}
+
+/********************************* CPPMangleDeclaration ****************************/
+
+CPPMangleDeclaration::CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", p, decl);
+ cppmangle = p;
+}
+
+Dsymbol *CPPMangleDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new CPPMangleDeclaration(cppmangle, Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *CPPMangleDeclaration::newScope(Scope *sc)
+{
+ return createNewScope(sc, sc->stc, LINKcpp, this->cppmangle,
+ sc->protection, sc->explicitProtection, sc->aligndecl,
+ sc->inlining);
+}
+
+const char *CPPMangleDeclaration::toChars()
+{
+ return "extern ()";
+}
+
+/********************************* ProtDeclaration ****************************/
+
+/**
+ * Params:
+ * loc = source location of attribute token
+ * p = protection attribute data
+ * decl = declarations which are affected by this protection attribute
+ */
+ProtDeclaration::ProtDeclaration(Loc loc, Prot p, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ this->loc = loc;
+ this->protection = p;
+ this->pkg_identifiers = NULL;
+ //printf("decl = %p\n", decl);
+}
+
+/**
+ * Params:
+ * loc = source location of attribute token
+ * pkg_identifiers = list of identifiers for a qualified package name
+ * decl = declarations which are affected by this protection attribute
+ */
+ProtDeclaration::ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ this->loc = loc;
+ this->protection.kind = PROTpackage;
+ this->protection.pkg = NULL;
+ this->pkg_identifiers = pkg_identifiers;
+}
+
+Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ if (protection.kind == PROTpackage)
+ return new ProtDeclaration(this->loc, pkg_identifiers, Dsymbol::arraySyntaxCopy(decl));
+ else
+ return new ProtDeclaration(this->loc, protection, Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *ProtDeclaration::newScope(Scope *sc)
+{
+ if (pkg_identifiers)
+ semantic(sc);
+ return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
+ this->protection, 1, sc->aligndecl,
+ sc->inlining);
+}
+
+void ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+ if (pkg_identifiers)
+ {
+ Dsymbol* tmp;
+ Package::resolve(pkg_identifiers, &tmp, NULL);
+ protection.pkg = tmp ? tmp->isPackage() : NULL;
+ pkg_identifiers = NULL;
+ }
+
+ if (protection.kind == PROTpackage && protection.pkg && sc->_module)
+ {
+ Module *m = sc->_module;
+ Package* pkg = m->parent ? m->parent->isPackage() : NULL;
+ if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
+ error("does not bind to one of ancestor packages of module '%s'",
+ m->toPrettyChars(true));
+ }
+
+ return AttribDeclaration::addMember(sc, sds);
+}
+
+const char *ProtDeclaration::kind() const
+{
+ return "protection attribute";
+}
+
+const char *ProtDeclaration::toPrettyChars(bool)
+{
+ assert(protection.kind > PROTundefined);
+
+ OutBuffer buf;
+ buf.writeByte('\'');
+ protectionToBuffer(&buf, protection);
+ buf.writeByte('\'');
+ return buf.extractString();
+}
+
+/********************************* AlignDeclaration ****************************/
+
+AlignDeclaration::AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ this->loc = loc;
+ this->ealign = ealign;
+ this->salign = 0;
+}
+
+Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new AlignDeclaration(loc,
+ ealign->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *AlignDeclaration::newScope(Scope *sc)
+{
+ return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
+ sc->protection, sc->explicitProtection, this,
+ sc->inlining);
+}
+
+void AlignDeclaration::semantic2(Scope *sc)
+{
+ getAlignment(sc);
+ AttribDeclaration::semantic2(sc);
+}
+
+structalign_t AlignDeclaration::getAlignment(Scope *sc)
+{
+ if (salign != 0)
+ return salign;
+
+ if (!ealign)
+ return salign = STRUCTALIGN_DEFAULT;
+
+ sc = sc->startCTFE();
+ ealign = ::semantic(ealign, sc);
+ ealign = resolveProperties(sc, ealign);
+ sc = sc->endCTFE();
+ ealign = ealign->ctfeInterpret();
+
+ if (ealign->op == TOKerror)
+ return salign = STRUCTALIGN_DEFAULT;
+
+ Type *tb = ealign->type->toBasetype();
+ sinteger_t n = ealign->toInteger();
+
+ if (n < 1 || n & (n - 1) || STRUCTALIGN_DEFAULT < n || !tb->isintegral())
+ {
+ ::error(loc, "alignment must be an integer positive power of 2, not %s", ealign->toChars());
+ return salign = STRUCTALIGN_DEFAULT;
+ }
+
+ return salign = (structalign_t)n;
+}
+
+/********************************* AnonDeclaration ****************************/
+
+AnonDeclaration::AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ this->loc = loc;
+ this->isunion = isunion;
+ this->sem = 0;
+ this->anonoffset = 0;
+ this->anonstructsize = 0;
+ this->anonalignsize = 0;
+}
+
+Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
+}
+
+void AnonDeclaration::setScope(Scope *sc)
+{
+ //printf("AnonDeclaration::setScope() %p\n", this);
+ if (decl)
+ Dsymbol::setScope(sc);
+ AttribDeclaration::setScope(sc);
+}
+
+void AnonDeclaration::semantic(Scope *sc)
+{
+ //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+
+ assert(sc->parent);
+
+ Dsymbol *p = sc->parent->pastMixin();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ ::error(loc, "%s can only be a part of an aggregate, not %s %s",
+ kind(), p->kind(), p->toChars());
+ return;
+ }
+
+ if (decl)
+ {
+ sc = sc->push();
+ sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared);
+ sc->inunion = isunion;
+ sc->flags = 0;
+
+ for (size_t i = 0; i < decl->dim; i++)
+ {
+ Dsymbol *s = (*decl)[i];
+ s->semantic(sc);
+ }
+ sc = sc->pop();
+ }
+}
+
+void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+ //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
+
+ if (decl)
+ {
+ /* This works by treating an AnonDeclaration as an aggregate 'member',
+ * so in order to place that member we need to compute the member's
+ * size and alignment.
+ */
+
+ size_t fieldstart = ad->fields.dim;
+
+ /* Hackishly hijack ad's structsize and alignsize fields
+ * for use in our fake anon aggregate member.
+ */
+ unsigned savestructsize = ad->structsize;
+ unsigned savealignsize = ad->alignsize;
+ ad->structsize = 0;
+ ad->alignsize = 0;
+
+ unsigned offset = 0;
+ for (size_t i = 0; i < decl->dim; i++)
+ {
+ Dsymbol *s = (*decl)[i];
+ s->setFieldOffset(ad, &offset, this->isunion);
+ if (this->isunion)
+ offset = 0;
+ }
+
+ /* Bugzilla 13613: If the fields in this->members had been already
+ * added in ad->fields, just update *poffset for the subsequent
+ * field offset calculation.
+ */
+ if (fieldstart == ad->fields.dim)
+ {
+ ad->structsize = savestructsize;
+ ad->alignsize = savealignsize;
+ *poffset = ad->structsize;
+ return;
+ }
+
+ anonstructsize = ad->structsize;
+ anonalignsize = ad->alignsize;
+ ad->structsize = savestructsize;
+ ad->alignsize = savealignsize;
+
+ // 0 sized structs are set to 1 byte
+ // TODO: is this corect hebavior?
+ if (anonstructsize == 0)
+ {
+ anonstructsize = 1;
+ anonalignsize = 1;
+ }
+
+ assert(_scope);
+ structalign_t alignment = _scope->alignment();
+
+ /* Given the anon 'member's size and alignment,
+ * go ahead and place it.
+ */
+ anonoffset = AggregateDeclaration::placeField(
+ poffset,
+ anonstructsize, anonalignsize, alignment,
+ &ad->structsize, &ad->alignsize,
+ isunion);
+
+ // Add to the anon fields the base offset of this anonymous aggregate
+ //printf("anon fields, anonoffset = %d\n", anonoffset);
+ for (size_t i = fieldstart; i < ad->fields.dim; i++)
+ {
+ VarDeclaration *v = ad->fields[i];
+ //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset);
+ v->offset += anonoffset;
+ }
+ }
+}
+
+const char *AnonDeclaration::kind() const
+{
+ return (isunion ? "anonymous union" : "anonymous struct");
+}
+
+/********************************* PragmaDeclaration ****************************/
+
+PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ this->loc = loc;
+ this->ident = ident;
+ this->args = args;
+}
+
+Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
+{
+ //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
+ assert(!s);
+ return new PragmaDeclaration(loc, ident,
+ Expression::arraySyntaxCopy(args),
+ Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *PragmaDeclaration::newScope(Scope *sc)
+{
+ if (ident == Id::Pinline)
+ {
+ PINLINE inlining = PINLINEdefault;
+ if (!args || args->dim == 0)
+ inlining = PINLINEdefault;
+ else if (args->dim != 1)
+ {
+ error("one boolean expression expected for pragma(inline), not %d", args->dim);
+ args->setDim(1);
+ (*args)[0] = new ErrorExp();
+ }
+ else
+ {
+ Expression *e = (*args)[0];
+
+ if (e->op != TOKint64 || !e->type->equals(Type::tbool))
+ {
+ if (e->op != TOKerror)
+ {
+ error("pragma(inline, true or false) expected, not %s", e->toChars());
+ (*args)[0] = new ErrorExp();
+ }
+ }
+ else if (e->isBool(true))
+ inlining = PINLINEalways;
+ else if (e->isBool(false))
+ inlining = PINLINEnever;
+ }
+
+ return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
+ sc->protection, sc->explicitProtection, sc->aligndecl,
+ inlining);
+ }
+ return sc;
+}
+
+static unsigned setMangleOverride(Dsymbol *s, char *sym)
+{
+ AttribDeclaration *ad = s->isAttribDeclaration();
+
+ if (ad)
+ {
+ Dsymbols *decls = ad->include(NULL, NULL);
+ unsigned nestedCount = 0;
+
+ if (decls && decls->dim)
+ for (size_t i = 0; i < decls->dim; ++i)
+ nestedCount += setMangleOverride((*decls)[i], sym);
+
+ return nestedCount;
+ }
+ else if (s->isFuncDeclaration() || s->isVarDeclaration())
+ {
+ s->isDeclaration()->mangleOverride = sym;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+void PragmaDeclaration::semantic(Scope *sc)
+{
+ // Should be merged with PragmaStatement
+
+ //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
+ if (ident == Id::msg)
+ {
+ if (args)
+ {
+ for (size_t i = 0; i < args->dim; i++)
+ {
+ Expression *e = (*args)[i];
+
+ sc = sc->startCTFE();
+ e = ::semantic(e, sc);
+ e = resolveProperties(sc, e);
+ sc = sc->endCTFE();
+
+ // pragma(msg) is allowed to contain types as well as expressions
+ e = ctfeInterpretForPragmaMsg(e);
+ if (e->op == TOKerror)
+ {
+ errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars());
+ return;
+ }
+ StringExp *se = e->toStringExp();
+ if (se)
+ {
+ se = se->toUTF8(sc);
+ fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
+ }
+ else
+ fprintf(stderr, "%s", e->toChars());
+ }
+ fprintf(stderr, "\n");
+ }
+ goto Lnodecl;
+ }
+ else if (ident == Id::lib)
+ {
+ if (!args || args->dim != 1)
+ error("string expected for library name");
+ else
+ {
+ Expression *e = (*args)[0];
+
+ sc = sc->startCTFE();
+ e = ::semantic(e, sc);
+ e = resolveProperties(sc, e);
+ sc = sc->endCTFE();
+
+ e = e->ctfeInterpret();
+ (*args)[0] = e;
+ if (e->op == TOKerror)
+ goto Lnodecl;
+ StringExp *se = e->toStringExp();
+ if (!se)
+ error("string expected for library name, not '%s'", e->toChars());
+ else
+ {
+ char *name = (char *)mem.xmalloc(se->len + 1);
+ memcpy(name, se->string, se->len);
+ name[se->len] = 0;
+ if (global.params.verbose)
+ message("library %s", name);
+ if (global.params.moduleDeps && !global.params.moduleDepsFile)
+ {
+ OutBuffer *ob = global.params.moduleDeps;
+ Module *imod = sc->instantiatingModule();
+ ob->writestring("depsLib ");
+ ob->writestring(imod->toPrettyChars());
+ ob->writestring(" (");
+ escapePath(ob, imod->srcfile->toChars());
+ ob->writestring(") : ");
+ ob->writestring((char *) name);
+ ob->writenl();
+ }
+ mem.xfree(name);
+ }
+ }
+ goto Lnodecl;
+ }
+ else if (ident == Id::startaddress)
+ {
+ if (!args || args->dim != 1)
+ error("function name expected for start address");
+ else
+ {
+ /* Bugzilla 11980:
+ * resolveProperties and ctfeInterpret call are not necessary.
+ */
+ Expression *e = (*args)[0];
+
+ sc = sc->startCTFE();
+ e = ::semantic(e, sc);
+ sc = sc->endCTFE();
+
+ (*args)[0] = e;
+ Dsymbol *sa = getDsymbol(e);
+ if (!sa || !sa->isFuncDeclaration())
+ error("function name expected for start address, not '%s'", e->toChars());
+ }
+ goto Lnodecl;
+ }
+ else if (ident == Id::Pinline)
+ {
+ goto Ldecl;
+ }
+ else if (ident == Id::mangle)
+ {
+ if (!args)
+ args = new Expressions();
+ if (args->dim != 1)
+ {
+ error("string expected for mangled name");
+ args->setDim(1);
+ (*args)[0] = new ErrorExp(); // error recovery
+ goto Ldecl;
+ }
+
+ Expression *e = (*args)[0];
+ e = ::semantic(e, sc);
+ e = e->ctfeInterpret();
+ (*args)[0] = e;
+ if (e->op == TOKerror)
+ goto Ldecl;
+
+ StringExp *se = e->toStringExp();
+ if (!se)
+ {
+ error("string expected for mangled name, not '%s'", e->toChars());
+ goto Ldecl;
+ }
+ if (!se->len)
+ {
+ error("zero-length string not allowed for mangled name");
+ goto Ldecl;
+ }
+ if (se->sz != 1)
+ {
+ error("mangled name characters can only be of type char");
+ goto Ldecl;
+ }
+
+ /* Note: D language specification should not have any assumption about backend
+ * implementation. Ideally pragma(mangle) can accept a string of any content.
+ *
+ * Therefore, this validation is compiler implementation specific.
+ */
+ for (size_t i = 0; i < se->len; )
+ {
+ utf8_t *p = (utf8_t *)se->string;
+ dchar_t c = p[i];
+ if (c < 0x80)
+ {
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ (c != 0 && strchr("$%().:?@[]_", c)))
+ {
+ ++i;
+ continue;
+ }
+ else
+ {
+ error("char 0x%02x not allowed in mangled name", c);
+ break;
+ }
+ }
+
+ if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c))
+ {
+ error("%s", msg);
+ break;
+ }
+
+ if (!isUniAlpha(c))
+ {
+ error("char 0x%04x not allowed in mangled name", c);
+ break;
+ }
+ }
+ }
+ else if (global.params.ignoreUnsupportedPragmas)
+ {
+ if (global.params.verbose)
+ {
+ /* Print unrecognized pragmas
+ */
+ OutBuffer buf;
+ buf.writestring(ident->toChars());
+ if (args)
+ {
+ for (size_t i = 0; i < args->dim; i++)
+ {
+ Expression *e = (*args)[i];
+
+ sc = sc->startCTFE();
+ e = ::semantic(e, sc);
+ e = resolveProperties(sc, e);
+ sc = sc->endCTFE();
+
+ e = e->ctfeInterpret();
+ if (i == 0)
+ buf.writestring(" (");
+ else
+ buf.writeByte(',');
+ buf.writestring(e->toChars());
+ }
+ if (args->dim)
+ buf.writeByte(')');
+ }
+ message("pragma %s", buf.peekString());
+ }
+ goto Lnodecl;
+ }
+ else
+ error("unrecognized pragma(%s)", ident->toChars());
+
+Ldecl:
+ if (decl)
+ {
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < decl->dim; i++)
+ {
+ Dsymbol *s = (*decl)[i];
+
+ s->semantic(sc2);
+
+ if (ident == Id::mangle)
+ {
+ assert(args && args->dim == 1);
+ if (StringExp *se = (*args)[0]->toStringExp())
+ {
+ char *name = (char *)mem.xmalloc(se->len + 1);
+ memcpy(name, se->string, se->len);
+ name[se->len] = 0;
+
+ unsigned cnt = setMangleOverride(s, name);
+ if (cnt > 1)
+ error("can only apply to a single declaration");
+ }
+ }
+ }
+
+ if (sc2 != sc)
+ sc2->pop();
+ }
+ return;
+
+Lnodecl:
+ if (decl)
+ {
+ error("pragma is missing closing ';'");
+ goto Ldecl; // do them anyway, to avoid segfaults.
+ }
+}
+
+const char *PragmaDeclaration::kind() const
+{
+ return "pragma";
+}
+
+/********************************* ConditionalDeclaration ****************************/
+
+ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl)
+ : AttribDeclaration(decl)
+{
+ //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+ this->condition = condition;
+ this->elsedecl = elsedecl;
+}
+
+Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new ConditionalDeclaration(condition->syntaxCopy(),
+ Dsymbol::arraySyntaxCopy(decl),
+ Dsymbol::arraySyntaxCopy(elsedecl));
+}
+
+bool ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+ //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
+ if (condition->inc)
+ {
+ Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl;
+ return Dsymbol::oneMembers(d, ps, ident);
+ }
+ else
+ {
+ bool res = (Dsymbol::oneMembers( decl, ps, ident) && *ps == NULL &&
+ Dsymbol::oneMembers(elsedecl, ps, ident) && *ps == NULL);
+ *ps = NULL;
+ return res;
+ }
+}
+
+// Decide if 'then' or 'else' code should be included
+
+Dsymbols *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sds)
+{
+ //printf("ConditionalDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
+ assert(condition);
+ return condition->include(_scope ? _scope : sc, sds) ? decl : elsedecl;
+}
+
+void ConditionalDeclaration::setScope(Scope *sc)
+{
+ Dsymbols *d = include(sc, NULL);
+
+ //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d);
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->setScope(sc);
+ }
+ }
+}
+
+void ConditionalDeclaration::addComment(const utf8_t *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)
+ {
+ Dsymbols *d = decl;
+
+ for (int j = 0; j < 2; j++)
+ {
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
+ s->addComment(comment);
+ }
+ }
+ d = elsedecl;
+ }
+ }
+}
+
+/***************************** StaticIfDeclaration ****************************/
+
+StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
+ Dsymbols *decl, Dsymbols *elsedecl)
+ : ConditionalDeclaration(condition, decl, elsedecl)
+{
+ //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
+ scopesym = NULL;
+ addisdone = false;
+}
+
+Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new StaticIfDeclaration(condition->syntaxCopy(),
+ Dsymbol::arraySyntaxCopy(decl),
+ Dsymbol::arraySyntaxCopy(elsedecl));
+}
+
+/****************************************
+ * Different from other AttribDeclaration subclasses, include() call requires
+ * the completion of addMember and setScope phases.
+ */
+Dsymbols *StaticIfDeclaration::include(Scope *sc, ScopeDsymbol *)
+{
+ //printf("StaticIfDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
+
+ if (condition->inc == 0)
+ {
+ assert(scopesym); // addMember is already done
+ assert(_scope); // setScope is already done
+
+ Dsymbols *d = ConditionalDeclaration::include(_scope, scopesym);
+
+ if (d && !addisdone)
+ {
+ // Add members lazily.
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->addMember(_scope, scopesym);
+ }
+
+ // Set the member scopes lazily.
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ s->setScope(_scope);
+ }
+
+ addisdone = true;
+ }
+ return d;
+ }
+ else
+ {
+ return ConditionalDeclaration::include(sc, scopesym);
+ }
+}
+
+void StaticIfDeclaration::addMember(Scope *, ScopeDsymbol *sds)
+{
+ //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
+ /* This is deferred until the condition evaluated later (by the include() call),
+ * 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->scopesym = sds;
+}
+
+void StaticIfDeclaration::importAll(Scope *)
+{
+ // do not evaluate condition before semantic pass
+}
+
+void StaticIfDeclaration::setScope(Scope *sc)
+{
+ // do not evaluate condition before semantic pass
+
+ // But do set the scope, in case we need it for forward referencing
+ Dsymbol::setScope(sc);
+}
+
+void StaticIfDeclaration::semantic(Scope *sc)
+{
+ AttribDeclaration::semantic(sc);
+}
+
+const char *StaticIfDeclaration::kind() const
+{
+ return "static if";
+}
+
+/***************************** CompileDeclaration *****************************/
+
+// These are mixin declarations, like mixin("int x");
+
+CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+ : AttribDeclaration(NULL)
+{
+ //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
+ this->loc = loc;
+ this->exp = exp;
+ this->scopesym = NULL;
+ this->compiled = false;
+}
+
+Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *)
+{
+ //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
+ return new CompileDeclaration(loc, exp->syntaxCopy());
+}
+
+void CompileDeclaration::addMember(Scope *, ScopeDsymbol *sds)
+{
+ //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
+ this->scopesym = sds;
+}
+
+void CompileDeclaration::setScope(Scope *sc)
+{
+ Dsymbol::setScope(sc);
+}
+
+void CompileDeclaration::compileIt(Scope *sc)
+{
+ //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars());
+ sc = sc->startCTFE();
+ exp = ::semantic(exp, sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc->endCTFE();
+
+ if (exp->op != TOKerror)
+ {
+ Expression *e = exp->ctfeInterpret();
+ if (e->op == TOKerror) // Bugzilla 15974
+ return;
+ StringExp *se = e->toStringExp();
+ if (!se)
+ exp->error("argument to mixin must be a string, not (%s) of type %s", exp->toChars(), exp->type->toChars());
+ else
+ {
+ se = se->toUTF8(sc);
+ unsigned errors = global.errors;
+ Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+ p.nextToken();
+
+ decl = p.parseDeclDefs(0);
+ if (p.token.value != TOKeof)
+ exp->error("incomplete mixin declaration (%s)", se->toChars());
+ if (p.errors)
+ {
+ assert(global.errors != errors);
+ decl = NULL;
+ }
+ }
+ }
+}
+
+void CompileDeclaration::semantic(Scope *sc)
+{
+ //printf("CompileDeclaration::semantic()\n");
+
+ if (!compiled)
+ {
+ compileIt(sc);
+ AttribDeclaration::addMember(sc, scopesym);
+ compiled = true;
+
+ if (_scope && decl)
+ {
+ for (size_t i = 0; i < decl->dim; i++)
+ {
+ Dsymbol *s = (*decl)[i];
+ s->setScope(_scope);
+ }
+ }
+ }
+ AttribDeclaration::semantic(sc);
+}
+
+const char *CompileDeclaration::kind() const
+{
+ return "mixin";
+}
+
+/***************************** UserAttributeDeclaration *****************************/
+
+UserAttributeDeclaration::UserAttributeDeclaration(Expressions *atts, Dsymbols *decl)
+ : AttribDeclaration(decl)
+{
+ //printf("UserAttributeDeclaration()\n");
+ this->atts = atts;
+}
+
+Dsymbol *UserAttributeDeclaration::syntaxCopy(Dsymbol *s)
+{
+ //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
+ assert(!s);
+ return new UserAttributeDeclaration(
+ Expression::arraySyntaxCopy(this->atts),
+ Dsymbol::arraySyntaxCopy(decl));
+}
+
+Scope *UserAttributeDeclaration::newScope(Scope *sc)
+{
+ Scope *sc2 = sc;
+ if (atts && atts->dim)
+ {
+ // create new one for changes
+ sc2 = sc->copy();
+ sc2->userAttribDecl = this;
+ }
+ return sc2;
+}
+
+void UserAttributeDeclaration::setScope(Scope *sc)
+{
+ //printf("UserAttributeDeclaration::setScope() %p\n", this);
+ if (decl)
+ Dsymbol::setScope(sc); // for forward reference of UDAs
+
+ return AttribDeclaration::setScope(sc);
+}
+
+void UserAttributeDeclaration::semantic(Scope *sc)
+{
+ //printf("UserAttributeDeclaration::semantic() %p\n", this);
+ if (decl && !_scope)
+ Dsymbol::setScope(sc); // for function local symbols
+
+ return AttribDeclaration::semantic(sc);
+}
+
+static void udaExpressionEval(Scope *sc, Expressions *exps)
+{
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *e = (*exps)[i];
+ if (e)
+ {
+ e = ::semantic(e, sc);
+ if (definitelyValueParameter(e))
+ e = e->ctfeInterpret();
+ if (e->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)e;
+ udaExpressionEval(sc, te->exps);
+ }
+ (*exps)[i] = e;
+ }
+ }
+}
+
+void UserAttributeDeclaration::semantic2(Scope *sc)
+{
+ if (decl && atts && atts->dim && _scope)
+ {
+ _scope = NULL;
+ udaExpressionEval(sc, atts);
+ }
+
+ AttribDeclaration::semantic2(sc);
+}
+
+Expressions *UserAttributeDeclaration::concat(Expressions *udas1, Expressions *udas2)
+{
+ Expressions *udas;
+ if (!udas1 || udas1->dim == 0)
+ udas = udas2;
+ else if (!udas2 || udas2->dim == 0)
+ udas = udas1;
+ else
+ {
+ /* Create a new tuple that combines them
+ * (do not append to left operand, as this is a copy-on-write operation)
+ */
+ udas = new Expressions();
+ udas->push(new TupleExp(Loc(), udas1));
+ udas->push(new TupleExp(Loc(), udas2));
+ }
+ return udas;
+}
+
+Expressions *UserAttributeDeclaration::getAttributes()
+{
+ if (Scope *sc = _scope)
+ {
+ _scope = NULL;
+ arrayExpressionSemantic(atts, sc);
+ }
+
+ Expressions *exps = new Expressions();
+ if (userAttribDecl)
+ exps->push(new TupleExp(Loc(), userAttribDecl->getAttributes()));
+ if (atts && atts->dim)
+ exps->push(new TupleExp(Loc(), atts));
+
+ return exps;
+}
+
+const char *UserAttributeDeclaration::kind() const
+{
+ return "UserAttribute";
+}
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
new file mode 100644
index 0000000..83486a9
--- /dev/null
+++ b/gcc/d/dmd/attrib.h
@@ -0,0 +1,275 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/attrib.h
+ */
+
+#pragma once
+
+#include "dsymbol.h"
+
+class Expression;
+class Statement;
+class LabelDsymbol;
+class Initializer;
+class Module;
+class Condition;
+class StaticForeach;
+
+/**************************************************************/
+
+class AttribDeclaration : public Dsymbol
+{
+public:
+ Dsymbols *decl; // array of Dsymbol's
+
+ AttribDeclaration(Dsymbols *decl);
+ virtual Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+ int apply(Dsymbol_apply_ft_t fp, void *param);
+ static Scope *createNewScope(Scope *sc,
+ StorageClass newstc, LINK linkage, CPPMANGLE cppmangle, Prot protection,
+ int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining);
+ virtual Scope *newScope(Scope *sc);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void setScope(Scope *sc);
+ void importAll(Scope *sc);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ void semantic3(Scope *sc);
+ void addComment(const utf8_t *comment);
+ const char *kind() const;
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ bool hasPointers();
+ bool hasStaticCtorOrDtor();
+ void checkCtorConstInit();
+ void addLocalClass(ClassDeclarations *);
+ AttribDeclaration *isAttribDeclaration() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StorageClassDeclaration : public AttribDeclaration
+{
+public:
+ StorageClass stc;
+
+ StorageClassDeclaration(StorageClass stc, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ StorageClassDeclaration *isStorageClassDeclaration() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DeprecatedDeclaration : public StorageClassDeclaration
+{
+public:
+ Expression *msg;
+ const char *msgstr;
+
+ DeprecatedDeclaration(Expression *msg, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ void setScope(Scope *sc);
+ void semantic2(Scope *sc);
+ const char *getMessage();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class LinkDeclaration : public AttribDeclaration
+{
+public:
+ LINK linkage;
+
+ LinkDeclaration(LINK p, Dsymbols *decl);
+ static LinkDeclaration *create(LINK p, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ const char *toChars();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CPPMangleDeclaration : public AttribDeclaration
+{
+public:
+ CPPMANGLE cppmangle;
+
+ CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ const char *toChars();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ProtDeclaration : public AttribDeclaration
+{
+public:
+ Prot protection;
+ Identifiers* pkg_identifiers;
+
+ ProtDeclaration(Loc loc, Prot p, Dsymbols *decl);
+ ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl);
+
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ const char *kind() const;
+ const char *toPrettyChars(bool unused);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AlignDeclaration : public AttribDeclaration
+{
+public:
+ Expression *ealign;
+ structalign_t salign;
+
+ AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ void semantic2(Scope *sc);
+ structalign_t getAlignment(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AnonDeclaration : public AttribDeclaration
+{
+public:
+ bool isunion;
+ int sem; // 1 if successful semantic()
+ unsigned anonoffset; // offset of anonymous struct
+ unsigned anonstructsize; // size of anonymous struct
+ unsigned anonalignsize; // size of anonymous struct for alignment purposes
+
+ AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ void setScope(Scope *sc);
+ void semantic(Scope *sc);
+ void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ const char *kind() const;
+ AnonDeclaration *isAnonDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PragmaDeclaration : public AttribDeclaration
+{
+public:
+ Expressions *args; // array of Expression's
+
+ PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ void semantic(Scope *sc);
+ const char *kind() const;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ConditionalDeclaration : public AttribDeclaration
+{
+public:
+ Condition *condition;
+ Dsymbols *elsedecl; // array of Dsymbol's for else block
+
+ ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+ void addComment(const utf8_t *comment);
+ void setScope(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticIfDeclaration : public ConditionalDeclaration
+{
+public:
+ ScopeDsymbol *scopesym;
+ bool addisdone;
+
+ StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void setScope(Scope *sc);
+ void importAll(Scope *sc);
+ void semantic(Scope *sc);
+ const char *kind() const;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticForeachDeclaration : public ConditionalDeclaration
+{
+public:
+ StaticForeach *sfe;
+ ScopeDsymbol *scopesym;
+ bool cached;
+ Dsymbols *cache;
+
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ bool oneMember(Dsymbol *ps, Identifier *ident);
+ Dsymbols *include(Scope *sc, ScopeDsymbol *sds);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void addComment(const char *comment);
+ void setScope(Scope *sc);
+ void importAll(Scope *sc);
+ void semantic(Scope *sc);
+ const char *kind() const;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForwardingAttribDeclaration : AttribDeclaration
+{
+public:
+ ForwardingScopeDsymbol *sym;
+
+ Scope *newScope(Scope *sc);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; }
+};
+
+// Mixin declarations
+
+class CompileDeclaration : public AttribDeclaration
+{
+public:
+ Expression *exp;
+
+ ScopeDsymbol *scopesym;
+ bool compiled;
+
+ CompileDeclaration(Loc loc, Expression *exp);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void setScope(Scope *sc);
+ void compileIt(Scope *sc);
+ void semantic(Scope *sc);
+ const char *kind() const;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**
+ * User defined attributes look like:
+ * @(args, ...)
+ */
+class UserAttributeDeclaration : public AttribDeclaration
+{
+public:
+ Expressions *atts;
+
+ UserAttributeDeclaration(Expressions *atts, Dsymbols *decl);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ void setScope(Scope *sc);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ static Expressions *concat(Expressions *udas1, Expressions *udas2);
+ Expressions *getAttributes();
+ const char *kind() const;
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/blockexit.c b/gcc/d/dmd/blockexit.c
new file mode 100644
index 0000000..0516f13
--- /dev/null
+++ b/gcc/d/dmd/blockexit.c
@@ -0,0 +1,502 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+
+/* Only valid after semantic analysis
+ * If 'mustNotThrow' is true, generate an error if it throws
+ */
+int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow)
+{
+ class BlockExit : public Visitor
+ {
+ public:
+ FuncDeclaration *func;
+ bool mustNotThrow;
+ int result;
+
+ BlockExit(FuncDeclaration *func, bool mustNotThrow)
+ : func(func), mustNotThrow(mustNotThrow)
+ {
+ result = BEnone;
+ }
+
+ void visit(Statement *s)
+ {
+ printf("Statement::blockExit(%p)\n", s);
+ printf("%s\n", s->toChars());
+ assert(0);
+ result = BEany;
+ }
+
+ void visit(ErrorStatement *)
+ {
+ result = BEany;
+ }
+
+ void visit(ExpStatement *s)
+ {
+ result = BEfallthru;
+ if (s->exp)
+ {
+ if (s->exp->op == TOKhalt)
+ {
+ result = BEhalt;
+ return;
+ }
+ if (s->exp->op == TOKassert)
+ {
+ AssertExp *a = (AssertExp *)s->exp;
+ if (a->e1->isBool(false)) // if it's an assert(0)
+ {
+ result = BEhalt;
+ return;
+ }
+ }
+ if (canThrow(s->exp, func, mustNotThrow))
+ result |= BEthrow;
+ }
+ }
+
+ void visit(CompileStatement *)
+ {
+ assert(global.errors);
+ result = BEfallthru;
+ }
+
+ void visit(CompoundStatement *cs)
+ {
+ //printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->dim, result);
+ result = BEfallthru;
+ Statement *slast = NULL;
+ for (size_t i = 0; i < cs->statements->dim; i++)
+ {
+ Statement *s = (*cs->statements)[i];
+ if (s)
+ {
+ //printf("result = x%x\n", result);
+ //printf("s: %s\n", s->toChars());
+ if (result & BEfallthru && slast)
+ {
+ slast = slast->last();
+ if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) &&
+ (s->isCaseStatement() || s->isDefaultStatement()))
+ {
+ // Allow if last case/default was empty
+ CaseStatement *sc = slast->isCaseStatement();
+ DefaultStatement *sd = slast->isDefaultStatement();
+ if (sc && (!sc->statement->hasCode() || sc->statement->isCaseStatement() || sc->statement->isErrorStatement()))
+ ;
+ else if (sd && (!sd->statement->hasCode() || sd->statement->isCaseStatement() || sd->statement->isErrorStatement()))
+ ;
+ else
+ {
+ const char *gototype = s->isCaseStatement() ? "case" : "default";
+ s->deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
+ }
+ }
+ }
+
+ if (!(result & BEfallthru) && !s->comeFrom())
+ {
+ if (blockExit(s, func, mustNotThrow) != BEhalt && s->hasCode())
+ s->warning("statement is not reachable");
+ }
+ else
+ {
+ result &= ~BEfallthru;
+ result |= blockExit(s, func, mustNotThrow);
+ }
+ slast = s;
+ }
+ }
+ }
+
+ void visit(UnrolledLoopStatement *uls)
+ {
+ result = BEfallthru;
+ for (size_t i = 0; i < uls->statements->dim; i++)
+ {
+ Statement *s = (*uls->statements)[i];
+ if (s)
+ {
+ int r = blockExit(s, func, mustNotThrow);
+ result |= r & ~(BEbreak | BEcontinue | BEfallthru);
+ if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0)
+ result &= ~BEfallthru;
+ }
+ }
+ }
+
+ void visit(ScopeStatement *s)
+ {
+ //printf("ScopeStatement::blockExit(%p)\n", s->statement);
+ result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
+ }
+
+ void visit(WhileStatement *)
+ {
+ assert(global.errors);
+ result = BEfallthru;
+ }
+
+ void visit(DoStatement *s)
+ {
+ if (s->_body)
+ {
+ result = blockExit(s->_body, func, mustNotThrow);
+ if (result == BEbreak)
+ {
+ result = BEfallthru;
+ return;
+ }
+ if (result & BEcontinue)
+ result |= BEfallthru;
+ }
+ else
+ result = BEfallthru;
+ if (result & BEfallthru)
+ {
+ if (canThrow(s->condition, func, mustNotThrow))
+ result |= BEthrow;
+ if (!(result & BEbreak) && s->condition->isBool(true))
+ result &= ~BEfallthru;
+ }
+ result &= ~(BEbreak | BEcontinue);
+ }
+
+ void visit(ForStatement *s)
+ {
+ result = BEfallthru;
+ if (s->_init)
+ {
+ result = blockExit(s->_init, func, mustNotThrow);
+ if (!(result & BEfallthru))
+ return;
+ }
+ if (s->condition)
+ {
+ if (canThrow(s->condition, func, mustNotThrow))
+ result |= BEthrow;
+ if (s->condition->isBool(true))
+ result &= ~BEfallthru;
+ else if (s->condition->isBool(false))
+ return;
+ }
+ else
+ result &= ~BEfallthru; // the body must do the exiting
+ if (s->_body)
+ {
+ int r = blockExit(s->_body, func, mustNotThrow);
+ if (r & (BEbreak | BEgoto))
+ result |= BEfallthru;
+ result |= r & ~(BEfallthru | BEbreak | BEcontinue);
+ }
+ if (s->increment && canThrow(s->increment, func, mustNotThrow))
+ result |= BEthrow;
+ }
+
+ void visit(ForeachStatement *s)
+ {
+ result = BEfallthru;
+ if (canThrow(s->aggr, func, mustNotThrow))
+ result |= BEthrow;
+ if (s->_body)
+ result |= blockExit(s->_body, func, mustNotThrow) & ~(BEbreak | BEcontinue);
+ }
+
+ void visit(ForeachRangeStatement *)
+ {
+ assert(global.errors);
+ result = BEfallthru;
+ }
+
+ void visit(IfStatement *s)
+ {
+ //printf("IfStatement::blockExit(%p)\n", s);
+
+ result = BEnone;
+ if (canThrow(s->condition, func, mustNotThrow))
+ result |= BEthrow;
+ if (s->condition->isBool(true))
+ {
+ if (s->ifbody)
+ result |= blockExit(s->ifbody, func, mustNotThrow);
+ else
+ result |= BEfallthru;
+ }
+ else if (s->condition->isBool(false))
+ {
+ if (s->elsebody)
+ result |= blockExit(s->elsebody, func, mustNotThrow);
+ else
+ result |= BEfallthru;
+ }
+ else
+ {
+ if (s->ifbody)
+ result |= blockExit(s->ifbody, func, mustNotThrow);
+ else
+ result |= BEfallthru;
+ if (s->elsebody)
+ result |= blockExit(s->elsebody, func, mustNotThrow);
+ else
+ result |= BEfallthru;
+ }
+ //printf("IfStatement::blockExit(%p) = x%x\n", s, result);
+ }
+
+ void visit(ConditionalStatement *s)
+ {
+ result = blockExit(s->ifbody, func, mustNotThrow);
+ if (s->elsebody)
+ result |= blockExit(s->elsebody, func, mustNotThrow);
+ }
+
+ void visit(PragmaStatement *)
+ {
+ result = BEfallthru;
+ }
+
+ void visit(StaticAssertStatement *)
+ {
+ result = BEfallthru;
+ }
+
+ void visit(SwitchStatement *s)
+ {
+ result = BEnone;
+ if (canThrow(s->condition, func, mustNotThrow))
+ result |= BEthrow;
+ if (s->_body)
+ {
+ result |= blockExit(s->_body, func, mustNotThrow);
+ if (result & BEbreak)
+ {
+ result |= BEfallthru;
+ result &= ~BEbreak;
+ }
+ }
+ else
+ result |= BEfallthru;
+ }
+
+ void visit(CaseStatement *s)
+ {
+ result = blockExit(s->statement, func, mustNotThrow);
+ }
+
+ void visit(DefaultStatement *s)
+ {
+ result = blockExit(s->statement, func, mustNotThrow);
+ }
+
+ void visit(GotoDefaultStatement *)
+ {
+ result = BEgoto;
+ }
+
+ void visit(GotoCaseStatement *)
+ {
+ result = BEgoto;
+ }
+
+ void visit(SwitchErrorStatement *)
+ {
+ // Switch errors are non-recoverable
+ result = BEhalt;
+ }
+
+ void visit(ReturnStatement *s)
+ {
+ result = BEreturn;
+ if (s->exp && canThrow(s->exp, func, mustNotThrow))
+ result |= BEthrow;
+ }
+
+ void visit(BreakStatement *s)
+ {
+ //printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak);
+ result = s->ident ? BEgoto : BEbreak;
+ }
+
+ void visit(ContinueStatement *s)
+ {
+ result = s->ident ? BEgoto : BEcontinue;
+ }
+
+ void visit(SynchronizedStatement *s)
+ {
+ result = s->_body ? blockExit(s->_body, func, mustNotThrow) : BEfallthru;
+ }
+
+ void visit(WithStatement *s)
+ {
+ result = BEnone;
+ if (canThrow(s->exp, func, mustNotThrow))
+ result = BEthrow;
+ if (s->_body)
+ result |= blockExit(s->_body, func, mustNotThrow);
+ else
+ result |= BEfallthru;
+ }
+
+ void visit(TryCatchStatement *s)
+ {
+ assert(s->_body);
+ result = blockExit(s->_body, func, false);
+
+ int catchresult = 0;
+ for (size_t i = 0; i < s->catches->dim; i++)
+ {
+ Catch *c = (*s->catches)[i];
+ if (c->type == Type::terror)
+ continue;
+
+ int cresult;
+ if (c->handler)
+ cresult = blockExit(c->handler, func, mustNotThrow);
+ else
+ cresult = BEfallthru;
+
+ /* If we're catching Object, then there is no throwing
+ */
+ Identifier *id = c->type->toBasetype()->isClassHandle()->ident;
+ if (c->internalCatch && (cresult & BEfallthru))
+ {
+ // Bugzilla 11542: leave blockExit flags of the body
+ cresult &= ~BEfallthru;
+ }
+ else if (id == Id::Object || id == Id::Throwable)
+ {
+ result &= ~(BEthrow | BEerrthrow);
+ }
+ else if (id == Id::Exception)
+ {
+ result &= ~BEthrow;
+ }
+ catchresult |= cresult;
+ }
+ if (mustNotThrow && (result & BEthrow))
+ {
+ // now explain why this is nothrow
+ blockExit(s->_body, func, mustNotThrow);
+ }
+ result |= catchresult;
+ }
+
+ void visit(TryFinallyStatement *s)
+ {
+ result = BEfallthru;
+ if (s->_body)
+ result = blockExit(s->_body, func, false);
+
+ // check finally body as well, it may throw (bug #4082)
+ int finalresult = BEfallthru;
+ if (s->finalbody)
+ finalresult = blockExit(s->finalbody, func, false);
+
+ // If either body or finalbody halts
+ if (result == BEhalt)
+ finalresult = BEnone;
+ if (finalresult == BEhalt)
+ result = BEnone;
+
+ if (mustNotThrow)
+ {
+ // now explain why this is nothrow
+ if (s->_body && (result & BEthrow))
+ blockExit(s->_body, func, mustNotThrow);
+ if (s->finalbody && (finalresult & BEthrow))
+ blockExit(s->finalbody, func, mustNotThrow);
+ }
+
+ #if 0
+ // Bugzilla 13201: Mask to prevent spurious warnings for
+ // destructor call, exit of synchronized statement, etc.
+ if (result == BEhalt && finalresult != BEhalt && s->finalbody &&
+ s->finalbody->hasCode())
+ {
+ s->finalbody->warning("statement is not reachable");
+ }
+ #endif
+
+ if (!(finalresult & BEfallthru))
+ result &= ~BEfallthru;
+ result |= finalresult & ~BEfallthru;
+ }
+
+ void visit(OnScopeStatement *)
+ {
+ // At this point, this statement is just an empty placeholder
+ result = BEfallthru;
+ }
+
+ void visit(ThrowStatement *s)
+ {
+ if (s->internalThrow)
+ {
+ // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow.
+ result = BEfallthru;
+ return;
+ }
+
+ Type *t = s->exp->type->toBasetype();
+ ClassDeclaration *cd = t->isClassHandle();
+ assert(cd);
+
+ if (cd == ClassDeclaration::errorException ||
+ ClassDeclaration::errorException->isBaseOf(cd, NULL))
+ {
+ result = BEerrthrow;
+ return;
+ }
+ if (mustNotThrow)
+ s->error("%s is thrown but not caught", s->exp->type->toChars());
+
+ result = BEthrow;
+ }
+
+ void visit(GotoStatement *)
+ {
+ //printf("GotoStatement::blockExit(%p)\n", s);
+ result = BEgoto;
+ }
+
+ void visit(LabelStatement *s)
+ {
+ //printf("LabelStatement::blockExit(%p)\n", s);
+ result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
+ if (s->breaks)
+ result |= BEfallthru;
+ }
+
+ void visit(CompoundAsmStatement *s)
+ {
+ if (mustNotThrow && !(s->stc & STCnothrow))
+ s->deprecation("asm statement is assumed to throw - mark it with 'nothrow' if it does not");
+
+ // Assume the worst
+ result = BEfallthru | BEreturn | BEgoto | BEhalt;
+ if (!(s->stc & STCnothrow)) result |= BEthrow;
+ }
+
+ void visit(ImportStatement *)
+ {
+ result = BEfallthru;
+ }
+ };
+
+ BlockExit be(func, mustNotThrow);
+ s->accept(&be);
+ return be.result;
+}
diff --git a/gcc/d/dmd/boostlicense.txt b/gcc/d/dmd/boostlicense.txt
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/gcc/d/dmd/boostlicense.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/gcc/d/dmd/canthrow.c b/gcc/d/dmd/canthrow.c
new file mode 100644
index 0000000..a00741b
--- /dev/null
+++ b/gcc/d/dmd/canthrow.c
@@ -0,0 +1,317 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/canthrow.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "statement.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "attrib.h"
+#include "tokens.h"
+
+bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow);
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+
+/********************************************
+ * Returns true if the expression may throw exceptions.
+ * If 'mustNotThrow' is true, generate an error if it throws
+ */
+
+bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow)
+{
+ //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
+
+ // stop walking if we determine this expression can throw
+ class CanThrow : public StoppableVisitor
+ {
+ FuncDeclaration *func;
+ bool mustNotThrow;
+
+ public:
+ CanThrow(FuncDeclaration *func, bool mustNotThrow)
+ : func(func), mustNotThrow(mustNotThrow)
+ {
+ }
+
+ void visit(Expression *)
+ {
+ }
+
+ void visit(DeclarationExp *de)
+ {
+ stop = Dsymbol_canThrow(de->declaration, func, mustNotThrow);
+ }
+
+ void visit(CallExp *ce)
+ {
+ if (global.errors && !ce->e1->type)
+ return; // error recovery
+
+ /* If calling a function or delegate that is typed as nothrow,
+ * then this expression cannot throw.
+ * Note that pure functions can throw.
+ */
+ Type *t = ce->e1->type->toBasetype();
+ if (ce->f && ce->f == func)
+ return;
+ if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
+ return;
+ if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
+ return;
+
+ if (mustNotThrow)
+ {
+ if (ce->f)
+ {
+ ce->error("%s '%s' is not nothrow",
+ ce->f->kind(), ce->f->toPrettyChars());
+ }
+ else
+ {
+ Expression *e1 = ce->e1;
+ if (e1->op == TOKstar) // print 'fp' if e1 is (*fp)
+ e1 = ((PtrExp *)e1)->e1;
+ ce->error("'%s' is not nothrow", e1->toChars());
+ }
+ }
+ stop = true;
+ }
+
+ void visit(NewExp *ne)
+ {
+ if (ne->member)
+ {
+ if (ne->allocator)
+ {
+ // Bugzilla 14407
+ Type *t = ne->allocator->type->toBasetype();
+ if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+ {
+ if (mustNotThrow)
+ {
+ ne->error("%s '%s' is not nothrow",
+ ne->allocator->kind(), ne->allocator->toPrettyChars());
+ }
+ stop = true;
+ }
+ }
+ // See if constructor call can throw
+ Type *t = ne->member->type->toBasetype();
+ if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+ {
+ if (mustNotThrow)
+ {
+ ne->error("%s '%s' is not nothrow",
+ ne->member->kind(), ne->member->toPrettyChars());
+ }
+ stop = true;
+ }
+ }
+ // regard storage allocation failures as not recoverable
+ }
+
+ void visit(DeleteExp *de)
+ {
+ Type *tb = de->e1->type->toBasetype();
+ AggregateDeclaration *ad = NULL;
+ switch (tb->ty)
+ {
+ case Tclass:
+ ad = ((TypeClass *)tb)->sym;
+ break;
+
+ case Tpointer:
+ tb = ((TypePointer *)tb)->next->toBasetype();
+ if (tb->ty == Tstruct)
+ ad = ((TypeStruct *)tb)->sym;
+ break;
+
+ case Tarray:
+ {
+ Type *tv = tb->nextOf()->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ ad = ((TypeStruct *)tv)->sym;
+ break;
+ }
+ }
+
+ default:
+ break;
+ }
+ if (!ad)
+ return;
+
+ if (ad->dtor)
+ {
+ Type *t = ad->dtor->type->toBasetype();
+ if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+ {
+ if (mustNotThrow)
+ {
+ de->error("%s '%s' is not nothrow",
+ ad->dtor->kind(), ad->dtor->toPrettyChars());
+ }
+ stop = true;
+ }
+ }
+ if (ad->aggDelete && tb->ty != Tarray)
+ {
+ Type *t = ad->aggDelete->type;
+ if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
+ {
+ if (mustNotThrow)
+ {
+ de->error("%s '%s' is not nothrow",
+ ad->aggDelete->kind(), ad->aggDelete->toPrettyChars());
+ }
+ stop = true;
+ }
+ }
+ }
+
+ void visit(AssignExp *ae)
+ {
+ // blit-init cannot throw
+ if (ae->op == TOKblit)
+ return;
+
+ /* Element-wise assignment could invoke postblits.
+ */
+ Type *t;
+ if (ae->type->toBasetype()->ty == Tsarray)
+ {
+ if (!ae->e2->isLvalue())
+ return;
+ t = ae->type;
+ }
+ else if (ae->e1->op == TOKslice)
+ t = ((SliceExp *)ae->e1)->e1->type;
+ else
+ return;
+
+ Type *tv = t->baseElemOf();
+ if (tv->ty != Tstruct)
+ return;
+ StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+ if (!sd->postblit || sd->postblit->type->ty != Tfunction)
+ return;
+
+ if (((TypeFunction *)sd->postblit->type)->isnothrow)
+ ;
+ else
+ {
+ if (mustNotThrow)
+ {
+ ae->error("%s '%s' is not nothrow",
+ sd->postblit->kind(), sd->postblit->toPrettyChars());
+ }
+ stop = true;
+ }
+ }
+
+ void visit(NewAnonClassExp *)
+ {
+ assert(0); // should have been lowered by semantic()
+ }
+ };
+
+ CanThrow ct(func, mustNotThrow);
+ return walkPostorder(e, &ct);
+}
+
+/**************************************
+ * Does symbol, when initialized, throw?
+ * Mirrors logic in Dsymbol_toElem().
+ */
+
+bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow)
+{
+ AttribDeclaration *ad;
+ VarDeclaration *vd;
+ TemplateMixin *tm;
+ TupleDeclaration *td;
+
+ //printf("Dsymbol_toElem() %s\n", s->toChars());
+ ad = s->isAttribDeclaration();
+ if (ad)
+ {
+ Dsymbols *decl = ad->include(NULL, NULL);
+ if (decl && decl->dim)
+ {
+ for (size_t i = 0; i < decl->dim; i++)
+ {
+ s = (*decl)[i];
+ if (Dsymbol_canThrow(s, func, mustNotThrow))
+ return true;
+ }
+ }
+ }
+ else if ((vd = s->isVarDeclaration()) != NULL)
+ {
+ s = s->toAlias();
+ if (s != vd)
+ return Dsymbol_canThrow(s, func, mustNotThrow);
+ if (vd->storage_class & STCmanifest)
+ ;
+ else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
+ ;
+ else
+ {
+ if (vd->_init)
+ {
+ ExpInitializer *ie = vd->_init->isExpInitializer();
+ if (ie && canThrow(ie->exp, func, mustNotThrow))
+ return true;
+ }
+ if (vd->needsScopeDtor())
+ return canThrow(vd->edtor, func, mustNotThrow);
+ }
+ }
+ else if ((tm = s->isTemplateMixin()) != NULL)
+ {
+ //printf("%s\n", tm->toChars());
+ if (tm->members)
+ {
+ for (size_t i = 0; i < tm->members->dim; i++)
+ {
+ Dsymbol *sm = (*tm->members)[i];
+ if (Dsymbol_canThrow(sm, func, mustNotThrow))
+ return true;
+ }
+ }
+ }
+ else if ((td = s->isTupleDeclaration()) != NULL)
+ {
+ for (size_t i = 0; i < td->objects->dim; i++)
+ {
+ RootObject *o = (*td->objects)[i];
+ if (o->dyncast() == DYNCAST_EXPRESSION)
+ {
+ Expression *eo = (Expression *)o;
+ if (eo->op == TOKdsymbol)
+ {
+ DsymbolExp *se = (DsymbolExp *)eo;
+ if (Dsymbol_canThrow(se->s, func, mustNotThrow))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/gcc/d/dmd/checkedint.c b/gcc/d/dmd/checkedint.c
new file mode 100644
index 0000000..b9ccb5b
--- /dev/null
+++ b/gcc/d/dmd/checkedint.c
@@ -0,0 +1,238 @@
+
+/**********************************************
+ * This module implements integral arithmetic primitives that check
+ * for out-of-range results.
+ * This is a translation to C++ of D's core.checkedint
+ *
+ * Integral arithmetic operators operate on fixed width types.
+ * Results that are not representable in those fixed widths are silently
+ * truncated to fit.
+ * This module offers integral arithmetic primitives that produce the
+ * same results, but set an 'overflow' flag when such truncation occurs.
+ * The setting is sticky, meaning that numerous operations can be cascaded
+ * and then the flag need only be checked at the end.
+ * Whether the operation is signed or unsigned is indicated by an 's' or 'u'
+ * suffix, respectively. While this could be achieved without such suffixes by
+ * using overloading on the signedness of the types, the suffix makes it clear
+ * which is happening without needing to examine the types.
+ *
+ * While the generic versions of these functions are computationally expensive
+ * relative to the cost of the operation itself, compiler implementations are free
+ * to recognize them and generate equivalent and faster code.
+ *
+ * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
+ * Copyright: Copyright (C) 2014-2018 by The D Language Foundation, All Rights Reserved
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors: Walter Bright
+ * Source: https://github.com/D-Programming-Language/dmd/blob/master/src/root/port.c
+ */
+
+#include <assert.h>
+
+#include "checkedint.h"
+
+/*******************************
+ * Add two signed integers, checking for overflow.
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ * x = left operand
+ * y = right operand
+ * overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ * the sum
+ */
+
+int adds(int x, int y, bool& overflow)
+{
+ int64_t r = (int64_t)x + (int64_t)y;
+ if (r < INT32_MIN || r > INT32_MAX)
+ overflow = true;
+ return (int)r;
+}
+
+/// ditto
+int64_t adds(int64_t x, int64_t y, bool& overflow)
+{
+ int64_t r = (uint64_t)x + (uint64_t)y;
+ if ((x < 0 && y < 0 && r >= 0) ||
+ (x >= 0 && y >= 0 && r < 0))
+ overflow = true;
+ return r;
+}
+
+/*******************************
+ * Add two unsigned integers, checking for overflow (aka carry).
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ * x = left operand
+ * y = right operand
+ * overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ * the sum
+ */
+
+unsigned addu(unsigned x, unsigned y, bool& overflow)
+{
+ unsigned r = x + y;
+ if (r < x || r < y)
+ overflow = true;
+ return r;
+}
+
+/// ditto
+uint64_t addu(uint64_t x, uint64_t y, bool& overflow)
+{
+ uint64_t r = x + y;
+ if (r < x || r < y)
+ overflow = true;
+ return r;
+}
+
+/*******************************
+ * Subtract two signed integers, checking for overflow.
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ * x = left operand
+ * y = right operand
+ * overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ * the sum
+ */
+
+int subs(int x, int y, bool& overflow)
+{
+ int64_t r = (int64_t)x - (int64_t)y;
+ if (r < INT32_MIN || r > INT32_MAX)
+ overflow = true;
+ return (int)r;
+}
+
+/// ditto
+int64_t subs(int64_t x, int64_t y, bool& overflow)
+{
+ int64_t r = (uint64_t)x - (uint64_t)y;
+ if ((x < 0 && y >= 0 && r >= 0) ||
+ (x >= 0 && y < 0 && (r < 0 || y == INT64_MIN)))
+ overflow = true;
+ return r;
+}
+
+/*******************************
+ * Subtract two unsigned integers, checking for overflow (aka borrow).
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ * x = left operand
+ * y = right operand
+ * overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ * the sum
+ */
+
+unsigned subu(unsigned x, unsigned y, bool& overflow)
+{
+ if (x < y)
+ overflow = true;
+ return x - y;
+}
+
+/// ditto
+uint64_t subu(uint64_t x, uint64_t y, bool& overflow)
+{
+ if (x < y)
+ overflow = true;
+ return x - y;
+}
+
+/***********************************************
+ * Negate an integer.
+ *
+ * Params:
+ * x = operand
+ * overflow = set if x cannot be negated, is not affected otherwise
+ * Returns:
+ * the negation of x
+ */
+
+int negs(int x, bool& overflow)
+{
+ if (x == (int)INT32_MIN)
+ overflow = true;
+ return -x;
+}
+
+/// ditto
+int64_t negs(int64_t x, bool& overflow)
+{
+ if (x == INT64_MIN)
+ overflow = true;
+ return -x;
+}
+
+/*******************************
+ * Multiply two signed integers, checking for overflow.
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ * x = left operand
+ * y = right operand
+ * overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ * the sum
+ */
+
+int muls(int x, int y, bool& overflow)
+{
+ int64_t r = (int64_t)x * (int64_t)y;
+ if (r < INT32_MIN || r > INT32_MAX)
+ overflow = true;
+ return (int)r;
+}
+
+/// ditto
+int64_t muls(int64_t x, int64_t y, bool& overflow)
+{
+ int64_t r = (uint64_t)x * (uint64_t)y;
+ int64_t not0or1 = ~(int64_t)1;
+ if ((x & not0or1) && ((r == y) ? r : (r / x) != y))
+ overflow = true;
+ return r;
+}
+
+/*******************************
+ * Multiply two unsigned integers, checking for overflow (aka carry).
+ *
+ * The overflow is sticky, meaning a sequence of operations can
+ * be done and overflow need only be checked at the end.
+ * Params:
+ * x = left operand
+ * y = right operand
+ * overflow = set if an overflow occurs, is not affected otherwise
+ * Returns:
+ * the sum
+ */
+
+unsigned mulu(unsigned x, unsigned y, bool& overflow)
+{
+ uint64_t r = (uint64_t)x * (uint64_t)y;
+ if (r > UINT32_MAX)
+ overflow = true;
+ return (unsigned)r;
+}
+
+/// ditto
+uint64_t mulu(uint64_t x, uint64_t y, bool& overflow)
+{
+ uint64_t r = x * y;
+ if (x && (r / x) != y)
+ overflow = true;
+ return r;
+}
diff --git a/gcc/d/dmd/checkedint.h b/gcc/d/dmd/checkedint.h
new file mode 100644
index 0000000..1f6545b
--- /dev/null
+++ b/gcc/d/dmd/checkedint.h
@@ -0,0 +1,35 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2003-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/checkedint.h
+ */
+
+#pragma once
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+#include <stdint.h>
+
+
+int adds(int x, int y, bool& overflow);
+int64_t adds(int64_t x, int64_t y, bool& overflow);
+unsigned addu(unsigned x, unsigned y, bool& overflow);
+uint64_t addu(uint64_t x, uint64_t y, bool& overflow);
+
+int subs(int x, int y, bool& overflow);
+int64_t subs(int64_t x, int64_t y, bool& overflow);
+unsigned subu(unsigned x, unsigned y, bool& overflow);
+uint64_t subu(uint64_t x, uint64_t y, bool& overflow);
+
+int negs(int x, bool& overflow);
+int64_t negs(int64_t x, bool& overflow);
+
+int muls(int x, int y, bool& overflow);
+int64_t muls(int64_t x, int64_t y, bool& overflow);
+unsigned mulu(unsigned x, unsigned y, bool& overflow);
+uint64_t mulu(uint64_t x, uint64_t y, bool& overflow);
diff --git a/gcc/d/dmd/clone.c b/gcc/d/dmd/clone.c
new file mode 100644
index 0000000..9105d11
--- /dev/null
+++ b/gcc/d/dmd/clone.c
@@ -0,0 +1,1198 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/clone.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <new>
+
+#include "root/root.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "module.h"
+#include "id.h"
+#include "expression.h"
+#include "statement.h"
+#include "init.h"
+#include "template.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/*******************************************
+ * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
+ */
+StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f)
+{
+ if (!f)
+ return s1;
+
+ StorageClass s2 = (f->storage_class & STCdisable);
+ TypeFunction *tf = (TypeFunction *)f->type;
+ if (tf->trust == TRUSTsafe)
+ s2 |= STCsafe;
+ else if (tf->trust == TRUSTsystem)
+ s2 |= STCsystem;
+ else if (tf->trust == TRUSTtrusted)
+ s2 |= STCtrusted;
+ if (tf->purity != PUREimpure)
+ s2 |= STCpure;
+ if (tf->isnothrow)
+ s2 |= STCnothrow;
+ if (tf->isnogc)
+ s2 |= STCnogc;
+
+ StorageClass stc = 0;
+ StorageClass sa = s1 & s2;
+ StorageClass so = s1 | s2;
+
+ if (so & STCsystem)
+ stc |= STCsystem;
+ else if (sa & STCtrusted)
+ stc |= STCtrusted;
+ else if ((so & (STCtrusted | STCsafe)) == (STCtrusted | STCsafe))
+ stc |= STCtrusted;
+ else if (sa & STCsafe)
+ stc |= STCsafe;
+
+ if (sa & STCpure)
+ stc |= STCpure;
+
+ if (sa & STCnothrow)
+ stc |= STCnothrow;
+
+ if (sa & STCnogc)
+ stc |= STCnogc;
+
+ if (so & STCdisable)
+ stc |= STCdisable;
+
+ return stc;
+}
+
+/*******************************************
+ * Check given aggregate actually has an identity opAssign or not.
+ * Params:
+ * ad = struct or class
+ * sc = current scope
+ * Returns:
+ * if found, returns FuncDeclaration of opAssign, otherwise null
+ */
+FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc)
+{
+ Dsymbol *assign = search_function(ad, Id::assign);
+ if (assign)
+ {
+ /* check identity opAssign exists
+ */
+ UnionExp er; new(&er) NullExp(ad->loc, ad->type); // dummy rvalue
+ UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
+ el.exp()->type = ad->type;
+ Expressions a;
+ a.setDim(1);
+
+ unsigned errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
+ sc = sc->push();
+ sc->tinst = NULL;
+ sc->minst = NULL;
+
+ a[0] = er.exp();
+ FuncDeclaration *f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
+ if (!f)
+ {
+ a[0] = el.exp();
+ f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
+ }
+
+ sc = sc->pop();
+ global.endGagging(errors);
+
+ if (f)
+ {
+ if (f->errors)
+ return NULL;
+ int varargs;
+ Parameters *fparams = f->getParameters(&varargs);
+ if (fparams->dim >= 1)
+ {
+ Parameter *fparam0 = Parameter::getNth(fparams, 0);
+ if (fparam0->type->toDsymbol(NULL) != ad)
+ f = NULL;
+ }
+ }
+ // BUGS: This detection mechanism cannot find some opAssign-s like follows:
+ // struct S { void opAssign(ref immutable S) const; }
+ return f;
+ }
+ return NULL;
+}
+
+/*******************************************
+ * We need an opAssign for the struct if
+ * it has a destructor or a postblit.
+ * We need to generate one if a user-specified one does not exist.
+ */
+bool needOpAssign(StructDeclaration *sd)
+{
+ //printf("StructDeclaration::needOpAssign() %s\n", sd->toChars());
+ if (sd->isUnionDeclaration())
+ return false;
+
+ if (sd->hasIdentityAssign)
+ goto Lneed; // because has identity==elaborate opAssign
+
+ if (sd->dtor || sd->postblit)
+ goto Lneed;
+
+ /* If any of the fields need an opAssign, then we
+ * need it too.
+ */
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ if (v->storage_class & STCref)
+ continue;
+ if (v->overlapped) // if field of a union
+ continue; // user must handle it themselves
+ Type *tv = v->type->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)tv;
+ if (ts->sym->isUnionDeclaration())
+ continue;
+ if (needOpAssign(ts->sym))
+ goto Lneed;
+ }
+ }
+ //printf("\tdontneed\n");
+ return false;
+
+Lneed:
+ //printf("\tneed\n");
+ return true;
+}
+
+/******************************************
+ * Build opAssign for struct.
+ * ref S opAssign(S s) { ... }
+ *
+ * Note that s will be constructed onto the stack, and probably
+ * copy-constructed in caller site.
+ *
+ * If S has copy copy construction and/or destructor,
+ * the body will make bit-wise object swap:
+ * S __swap = this; // bit copy
+ * this = s; // bit copy
+ * __swap.dtor();
+ * Instead of running the destructor on s, run it on tmp instead.
+ *
+ * Otherwise, the body will make member-wise assignments:
+ * Then, the body is:
+ * this.field1 = s.field1;
+ * this.field2 = s.field2;
+ * ...;
+ */
+FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
+{
+ if (FuncDeclaration *f = hasIdentityOpAssign(sd, sc))
+ {
+ sd->hasIdentityAssign = true;
+ return f;
+ }
+ // Even if non-identity opAssign is defined, built-in identity opAssign
+ // will be defined.
+
+ if (!needOpAssign(sd))
+ return NULL;
+
+ //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars());
+ StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+ Loc declLoc = sd->loc;
+ Loc loc = Loc(); // internal code should have no loc to prevent coverage
+
+ // One of our sub-field might have `@disable opAssign` so we need to
+ // check for it.
+ // In this event, it will be reflected by having `stc` (opAssign's
+ // storage class) include `STCdisabled`.
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ if (v->storage_class & STCref)
+ continue;
+ if (v->overlapped)
+ continue;
+ Type *tv = v->type->baseElemOf();
+ if (tv->ty != Tstruct)
+ continue;
+
+ StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
+ stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
+ }
+
+ if (sd->dtor || sd->postblit)
+ {
+ if (!sd->type->isAssignable()) // Bugzilla 13044
+ return NULL;
+ stc = mergeFuncAttrs(stc, sd->dtor);
+ if (stc & STCsafe)
+ stc = (stc & ~STCsafe) | STCtrusted;
+ }
+
+ Parameters *fparams = new Parameters;
+ fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL));
+ TypeFunction *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref);
+
+ FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
+ fop->storage_class |= STCinference;
+ fop->generated = true;
+ Expression *e = NULL;
+ if (stc & STCdisable)
+ {
+ }
+ else if (sd->dtor || sd->postblit)
+ {
+ /* Do swap this and rhs.
+ * __swap = this; this = s; __swap.dtor();
+ */
+ //printf("\tswap copy\n");
+ Identifier *idtmp = Identifier::generateId("__swap");
+ VarDeclaration *tmp = NULL;
+ AssignExp *ec = NULL;
+ if (sd->dtor)
+ {
+ tmp = new VarDeclaration(loc, sd->type, idtmp, new VoidInitializer(loc));
+ tmp->storage_class |= STCnodtor | STCtemp | STCctfe;
+ e = new DeclarationExp(loc, tmp);
+ ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc));
+ e = Expression::combine(e, ec);
+ }
+ ec = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id::p));
+ e = Expression::combine(e, ec);
+ if (sd->dtor)
+ {
+ /* Instead of running the destructor on s, run it
+ * on tmp. This avoids needing to copy tmp back in to s.
+ */
+ Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd->dtor, false);
+ ec2 = new CallExp(loc, ec2);
+ e = Expression::combine(e, ec2);
+ }
+ }
+ else
+ {
+ /* Do memberwise copy.
+ *
+ * If sd is a nested struct, its vthis field assignment is:
+ * 1. If it's nested in a class, it's a rebind of class reference.
+ * 2. If it's nested in a function or struct, it's an update of void*.
+ * In both cases, it will change the parent context.
+ */
+ //printf("\tmemberwise copy\n");
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ // this.v = s.v;
+ AssignExp *ec = new AssignExp(loc,
+ new DotVarExp(loc, new ThisExp(loc), v),
+ new DotVarExp(loc, new IdentifierExp(loc, Id::p), v));
+ e = Expression::combine(e, ec);
+ }
+ }
+ if (e)
+ {
+ Statement *s1 = new ExpStatement(loc, e);
+
+ /* Add:
+ * return this;
+ */
+ e = new ThisExp(loc);
+ Statement *s2 = new ReturnStatement(loc, e);
+
+ fop->fbody = new CompoundStatement(loc, s1, s2);
+ tf->isreturn = true;
+ }
+
+ sd->members->push(fop);
+ fop->addMember(sc, sd);
+ sd->hasIdentityAssign = true; // temporary mark identity assignable
+
+ unsigned errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
+ Scope *sc2 = sc->push();
+ sc2->stc = 0;
+ sc2->linkage = LINKd;
+
+ fop->semantic(sc2);
+ fop->semantic2(sc2);
+ // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.
+
+ sc2->pop();
+ if (global.endGagging(errors)) // if errors happened
+ {
+ // Disable generated opAssign, because some members forbid identity assignment.
+ fop->storage_class |= STCdisable;
+ fop->fbody = NULL; // remove fbody which contains the error
+ }
+
+ //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0);
+
+ return fop;
+}
+
+/*******************************************
+ * We need an opEquals for the struct if
+ * any fields has an opEquals.
+ * Generate one if a user-specified one does not exist.
+ */
+bool needOpEquals(StructDeclaration *sd)
+{
+ //printf("StructDeclaration::needOpEquals() %s\n", sd->toChars());
+ if (sd->isUnionDeclaration())
+ goto Ldontneed;
+
+ if (sd->hasIdentityEquals)
+ goto Lneed;
+
+ /* If any of the fields has an opEquals, then we
+ * need it too.
+ */
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ if (v->storage_class & STCref)
+ continue;
+ if (v->overlapped)
+ continue;
+ Type *tv = v->type->toBasetype();
+ Type *tvbase = tv->baseElemOf();
+ if (tvbase->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)tvbase;
+ if (ts->sym->isUnionDeclaration())
+ continue;
+ if (needOpEquals(ts->sym))
+ goto Lneed;
+ if (ts->sym->aliasthis) // Bugzilla 14806
+ goto Lneed;
+ }
+ if (tv->isfloating())
+ {
+ // This is necessray for:
+ // 1. comparison of +0.0 and -0.0 should be true.
+ // 2. comparison of NANs should be false always.
+ goto Lneed;
+ }
+ if (tv->ty == Tarray)
+ goto Lneed;
+ if (tv->ty == Taarray)
+ goto Lneed;
+ if (tv->ty == Tclass)
+ goto Lneed;
+ }
+Ldontneed:
+ //printf("\tdontneed\n");
+ return false;
+
+Lneed:
+ //printf("\tneed\n");
+ return true;
+}
+
+/*******************************************
+ * Check given aggregate actually has an identity opEquals or not.
+ */
+FuncDeclaration *hasIdentityOpEquals(AggregateDeclaration *ad, Scope *sc)
+{
+ Dsymbol *eq = search_function(ad, Id::eq);
+ if (eq)
+ {
+ /* check identity opEquals exists
+ */
+ UnionExp er; new(&er) NullExp(ad->loc, NULL); // dummy rvalue
+ UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
+ Expressions a;
+ a.setDim(1);
+ for (size_t i = 0; i < 5; i++)
+ {
+ Type *tthis = NULL; // dead-store to prevent spurious warning
+ switch (i)
+ {
+ case 0: tthis = ad->type; break;
+ case 1: tthis = ad->type->constOf(); break;
+ case 2: tthis = ad->type->immutableOf(); break;
+ case 3: tthis = ad->type->sharedOf(); break;
+ case 4: tthis = ad->type->sharedConstOf(); break;
+ default: assert(0);
+ }
+ FuncDeclaration *f = NULL;
+
+ unsigned errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
+ sc = sc->push();
+ sc->tinst = NULL;
+ sc->minst = NULL;
+
+ for (size_t j = 0; j < 2; j++)
+ {
+ a[0] = (j == 0 ? er.exp() : el.exp());
+ a[0]->type = tthis;
+ f = resolveFuncCall(ad->loc, sc, eq, NULL, tthis, &a, 1);
+ if (f)
+ break;
+ }
+
+ sc = sc->pop();
+ global.endGagging(errors);
+
+ if (f)
+ {
+ if (f->errors)
+ return NULL;
+ return f;
+ }
+ }
+ }
+ return NULL;
+}
+
+/******************************************
+ * Build opEquals for struct.
+ * const bool opEquals(const S s) { ... }
+ *
+ * By fixing bugzilla 3789, opEquals is changed to be never implicitly generated.
+ * Now, struct objects comparison s1 == s2 is translated to:
+ * s1.tupleof == s2.tupleof
+ * to calculate structural equality. See EqualExp::op_overload.
+ */
+FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc)
+{
+ if (hasIdentityOpEquals(sd, sc))
+ {
+ sd->hasIdentityEquals = true;
+ }
+ return NULL;
+}
+
+/******************************************
+ * Build __xopEquals for TypeInfo_Struct
+ * static bool __xopEquals(ref const S p, ref const S q)
+ * {
+ * return p == q;
+ * }
+ *
+ * This is called by TypeInfo.equals(p1, p2). If the struct does not support
+ * const objects comparison, it will throw "not implemented" Error in runtime.
+ */
+FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
+{
+ if (!needOpEquals(sd))
+ return NULL; // bitwise comparison would work
+
+ //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars());
+ if (Dsymbol *eq = search_function(sd, Id::eq))
+ {
+ if (FuncDeclaration *fd = eq->isFuncDeclaration())
+ {
+ TypeFunction *tfeqptr;
+ {
+ Scope scx;
+
+ /* const bool opEquals(ref const S s);
+ */
+ Parameters *parameters = new Parameters;
+ parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
+ tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd);
+ tfeqptr->mod = MODconst;
+ tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx);
+ }
+ fd = fd->overloadExactMatch(tfeqptr);
+ if (fd)
+ return fd;
+ }
+ }
+
+ if (!sd->xerreq)
+ {
+ // object._xopEquals
+ Identifier *id = Identifier::idPool("_xopEquals");
+ Expression *e = new IdentifierExp(sd->loc, Id::empty);
+ e = new DotIdExp(sd->loc, e, Id::object);
+ e = new DotIdExp(sd->loc, e, id);
+ e = semantic(e, sc);
+ Dsymbol *s = getDsymbol(e);
+ assert(s);
+ sd->xerreq = s->isFuncDeclaration();
+ }
+
+ Loc declLoc = Loc(); // loc is unnecessary so __xopEquals is never called directly
+ Loc loc = Loc(); // loc is unnecessary so errors are gagged
+
+ Parameters *parameters = new Parameters;
+ parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
+ parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
+ TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
+
+ Identifier *id = Id::xopEquals;
+ FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
+ fop->generated = true;
+ Expression *e1 = new IdentifierExp(loc, Id::p);
+ Expression *e2 = new IdentifierExp(loc, Id::q);
+ Expression *e = new EqualExp(TOKequal, loc, e1, e2);
+
+ fop->fbody = new ReturnStatement(loc, e);
+
+ unsigned errors = global.startGagging(); // Do not report errors
+ Scope *sc2 = sc->push();
+ sc2->stc = 0;
+ sc2->linkage = LINKd;
+
+ fop->semantic(sc2);
+ fop->semantic2(sc2);
+
+ sc2->pop();
+ if (global.endGagging(errors)) // if errors happened
+ fop = sd->xerreq;
+
+ return fop;
+}
+
+/******************************************
+ * Build __xopCmp for TypeInfo_Struct
+ * static bool __xopCmp(ref const S p, ref const S q)
+ * {
+ * return p.opCmp(q);
+ * }
+ *
+ * This is called by TypeInfo.compare(p1, p2). If the struct does not support
+ * const objects comparison, it will throw "not implemented" Error in runtime.
+ */
+FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
+{
+ //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
+ if (Dsymbol *cmp = search_function(sd, Id::cmp))
+ {
+ if (FuncDeclaration *fd = cmp->isFuncDeclaration())
+ {
+ TypeFunction *tfcmpptr;
+ {
+ Scope scx;
+
+ /* const int opCmp(ref const S s);
+ */
+ Parameters *parameters = new Parameters;
+ parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
+ tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd);
+ tfcmpptr->mod = MODconst;
+ tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx);
+ }
+ fd = fd->overloadExactMatch(tfcmpptr);
+ if (fd)
+ return fd;
+ }
+ }
+ else
+ {
+ // FIXME: doesn't work for recursive alias this
+ return NULL;
+ }
+
+ if (!sd->xerrcmp)
+ {
+ // object._xopCmp
+ Identifier *id = Identifier::idPool("_xopCmp");
+ Expression *e = new IdentifierExp(sd->loc, Id::empty);
+ e = new DotIdExp(sd->loc, e, Id::object);
+ e = new DotIdExp(sd->loc, e, id);
+ e = semantic(e, sc);
+ Dsymbol *s = getDsymbol(e);
+ assert(s);
+ sd->xerrcmp = s->isFuncDeclaration();
+ }
+
+ Loc declLoc = Loc(); // loc is unnecessary so __xopCmp is never called directly
+ Loc loc = Loc(); // loc is unnecessary so errors are gagged
+
+ Parameters *parameters = new Parameters;
+ parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
+ parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
+ TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd);
+
+ Identifier *id = Id::xopCmp;
+ FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
+ fop->generated = true;
+ Expression *e1 = new IdentifierExp(loc, Id::p);
+ Expression *e2 = new IdentifierExp(loc, Id::q);
+#ifdef IN_GCC
+ Expression *e = new CallExp(loc, new DotIdExp(loc, e1, Id::cmp), e2);
+#else
+ Expression *e = new CallExp(loc, new DotIdExp(loc, e2, Id::cmp), e1);
+#endif
+
+ fop->fbody = new ReturnStatement(loc, e);
+
+ unsigned errors = global.startGagging(); // Do not report errors
+ Scope *sc2 = sc->push();
+ sc2->stc = 0;
+ sc2->linkage = LINKd;
+
+ fop->semantic(sc2);
+ fop->semantic2(sc2);
+
+ sc2->pop();
+ if (global.endGagging(errors)) // if errors happened
+ fop = sd->xerrcmp;
+
+ return fop;
+}
+
+/*******************************************
+ * We need a toHash for the struct if
+ * any fields has a toHash.
+ * Generate one if a user-specified one does not exist.
+ */
+bool needToHash(StructDeclaration *sd)
+{
+ //printf("StructDeclaration::needToHash() %s\n", sd->toChars());
+ if (sd->isUnionDeclaration())
+ goto Ldontneed;
+
+ if (sd->xhash)
+ goto Lneed;
+
+ /* If any of the fields has an opEquals, then we
+ * need it too.
+ */
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ if (v->storage_class & STCref)
+ continue;
+ if (v->overlapped)
+ continue;
+ Type *tv = v->type->toBasetype();
+ Type *tvbase = tv->baseElemOf();
+ if (tvbase->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)tvbase;
+ if (ts->sym->isUnionDeclaration())
+ continue;
+ if (needToHash(ts->sym))
+ goto Lneed;
+ if (ts->sym->aliasthis) // Bugzilla 14948
+ goto Lneed;
+ }
+ if (tv->isfloating())
+ {
+ // This is necessray for:
+ // 1. comparison of +0.0 and -0.0 should be true.
+ goto Lneed;
+ }
+ if (tv->ty == Tarray)
+ goto Lneed;
+ if (tv->ty == Taarray)
+ goto Lneed;
+ if (tv->ty == Tclass)
+ goto Lneed;
+ }
+Ldontneed:
+ //printf("\tdontneed\n");
+ return false;
+
+Lneed:
+ //printf("\tneed\n");
+ return true;
+}
+
+/******************************************
+ * Build __xtoHash for non-bitwise hashing
+ * static hash_t xtoHash(ref const S p) nothrow @trusted;
+ */
+FuncDeclaration *buildXtoHash(StructDeclaration *sd, Scope *sc)
+{
+ if (Dsymbol *s = search_function(sd, Id::tohash))
+ {
+ static TypeFunction *tftohash;
+ if (!tftohash)
+ {
+ tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
+ tftohash->mod = MODconst;
+ tftohash = (TypeFunction *)tftohash->merge();
+ }
+
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ fd = fd->overloadExactMatch(tftohash);
+ if (fd)
+ return fd;
+ }
+ }
+
+ if (!needToHash(sd))
+ return NULL;
+
+ //printf("StructDeclaration::buildXtoHash() %s\n", sd->toPrettyChars());
+ Loc declLoc = Loc(); // loc is unnecessary so __xtoHash is never called directly
+ Loc loc = Loc(); // internal code should have no loc to prevent coverage
+
+ Parameters *parameters = new Parameters();
+ parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
+ TypeFunction *tf = new TypeFunction(parameters, Type::thash_t, 0, LINKd, STCnothrow | STCtrusted);
+
+ Identifier *id = Id::xtoHash;
+ FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
+ fop->generated = true;
+
+ /* Do memberwise hashing.
+ *
+ * If sd is a nested struct, and if it's nested in a class, the calculated
+ * hash value will also contain the result of parent class's toHash().
+ */
+ const char *code =
+ "size_t h = 0;"
+ "foreach (i, T; typeof(p.tupleof))"
+ " h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);"
+ "return h;";
+ fop->fbody = new CompileStatement(loc, new StringExp(loc, const_cast<char *>(code)));
+
+ Scope *sc2 = sc->push();
+ sc2->stc = 0;
+ sc2->linkage = LINKd;
+
+ fop->semantic(sc2);
+ fop->semantic2(sc2);
+
+ sc2->pop();
+
+ //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars());
+ return fop;
+}
+
+/*****************************************
+ * Create inclusive postblit for struct by aggregating
+ * all the postblits in postblits[] with the postblits for
+ * all the members.
+ * Note the close similarity with AggregateDeclaration::buildDtor(),
+ * and the ordering changes (runs forward instead of backwards).
+ */
+FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
+{
+ //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
+ if (sd->isUnionDeclaration())
+ return NULL;
+
+ StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+ Loc declLoc = sd->postblits.dim ? sd->postblits[0]->loc : sd->loc;
+ Loc loc = Loc(); // internal code should have no loc to prevent coverage
+
+ for (size_t i = 0; i < sd->postblits.dim; i++)
+ {
+ stc |= sd->postblits[i]->storage_class & STCdisable;
+ }
+
+ Statements *a = new Statements();
+ for (size_t i = 0; i < sd->fields.dim && !(stc & STCdisable); i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ if (v->storage_class & STCref)
+ continue;
+ if (v->overlapped)
+ continue;
+ Type *tv = v->type->baseElemOf();
+ if (tv->ty != Tstruct)
+ continue;
+ StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
+ if (!sdv->postblit)
+ continue;
+ assert(!sdv->isUnionDeclaration());
+ sdv->postblit->functionSemantic();
+
+ stc = mergeFuncAttrs(stc, sdv->postblit);
+ stc = mergeFuncAttrs(stc, sdv->dtor);
+ if (stc & STCdisable)
+ {
+ a->setDim(0);
+ break;
+ }
+
+ Expression *ex = NULL;
+ tv = v->type->toBasetype();
+ if (tv->ty == Tstruct)
+ {
+ // this.v.__xpostblit()
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call postblits on const/immutable objects.
+ ex = new AddrExp(loc, ex);
+ ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
+ ex = new PtrExp(loc, ex);
+ if (stc & STCsafe)
+ stc = (stc & ~STCsafe) | STCtrusted;
+
+ ex = new DotVarExp(loc, ex, sdv->postblit, false);
+ ex = new CallExp(loc, ex);
+ }
+ else
+ {
+ // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
+
+ uinteger_t n = 1;
+ while (tv->ty == Tsarray)
+ {
+ n *= ((TypeSArray *)tv)->dim->toUInteger();
+ tv = tv->nextOf()->toBasetype();
+ }
+ if (n == 0)
+ continue;
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call postblits on const/immutable objects.
+ ex = new DotIdExp(loc, ex, Id::ptr);
+ ex = new CastExp(loc, ex, sdv->type->pointerTo());
+ if (stc & STCsafe)
+ stc = (stc & ~STCsafe) | STCtrusted;
+
+ ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
+ new IntegerExp(loc, n, Type::tsize_t));
+ // Prevent redundant bounds check
+ ((SliceExp *)ex)->upperIsInBounds = true;
+ ((SliceExp *)ex)->lowerIsLessThanUpper = true;
+
+ ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayPostblit), ex);
+ }
+ a->push(new ExpStatement(loc, ex)); // combine in forward order
+
+ /* Bugzilla 10972: When the following field postblit calls fail,
+ * this field should be destructed for Exception Safety.
+ */
+ if (!sdv->dtor)
+ continue;
+ sdv->dtor->functionSemantic();
+
+ tv = v->type->toBasetype();
+ if (v->type->toBasetype()->ty == Tstruct)
+ {
+ // this.v.__xdtor()
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ ex = new AddrExp(loc, ex);
+ ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
+ ex = new PtrExp(loc, ex);
+ if (stc & STCsafe)
+ stc = (stc & ~STCsafe) | STCtrusted;
+
+ ex = new DotVarExp(loc, ex, sdv->dtor, false);
+ ex = new CallExp(loc, ex);
+ }
+ else
+ {
+ // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
+
+ uinteger_t n = 1;
+ while (tv->ty == Tsarray)
+ {
+ n *= ((TypeSArray *)tv)->dim->toUInteger();
+ tv = tv->nextOf()->toBasetype();
+ }
+ //if (n == 0)
+ // continue;
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ ex = new DotIdExp(loc, ex, Id::ptr);
+ ex = new CastExp(loc, ex, sdv->type->pointerTo());
+ if (stc & STCsafe)
+ stc = (stc & ~STCsafe) | STCtrusted;
+
+ ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
+ new IntegerExp(loc, n, Type::tsize_t));
+ // Prevent redundant bounds check
+ ((SliceExp *)ex)->upperIsInBounds = true;
+ ((SliceExp *)ex)->lowerIsLessThanUpper = true;
+
+ ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
+ }
+ a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
+ }
+
+ // Build our own "postblit" which executes a, but only if needed.
+ if (a->dim || (stc & STCdisable))
+ {
+ //printf("Building __fieldPostBlit()\n");
+ PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit);
+ dd->generated = true;
+ dd->storage_class |= STCinference;
+ dd->fbody = (stc & STCdisable) ? NULL : new CompoundStatement(loc, a);
+ sd->postblits.shift(dd);
+ sd->members->push(dd);
+ dd->semantic(sc);
+ }
+
+ FuncDeclaration *xpostblit = NULL;
+ switch (sd->postblits.dim)
+ {
+ case 0:
+ break;
+
+ case 1:
+ xpostblit = sd->postblits[0];
+ break;
+
+ default:
+ Expression *e = NULL;
+ stc = STCsafe | STCnothrow | STCpure | STCnogc;
+ for (size_t i = 0; i < sd->postblits.dim; i++)
+ {
+ FuncDeclaration *fd = sd->postblits[i];
+ stc = mergeFuncAttrs(stc, fd);
+ if (stc & STCdisable)
+ {
+ e = NULL;
+ break;
+ }
+ Expression *ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, fd, false);
+ ex = new CallExp(loc, ex);
+ e = Expression::combine(e, ex);
+ }
+ PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit);
+ dd->storage_class |= STCinference;
+ dd->fbody = new ExpStatement(loc, e);
+ sd->members->push(dd);
+ dd->semantic(sc);
+ xpostblit = dd;
+ break;
+ }
+ // Add an __xpostblit alias to make the inclusive postblit accessible
+ if (xpostblit)
+ {
+ AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit);
+ alias->semantic(sc);
+ sd->members->push(alias);
+ alias->addMember(sc, sd); // add to symbol table
+ }
+ return xpostblit;
+}
+
+/*****************************************
+ * Create inclusive destructor for struct/class by aggregating
+ * all the destructors in dtors[] with the destructors for
+ * all the members.
+ * Note the close similarity with StructDeclaration::buildPostBlit(),
+ * and the ordering changes (runs backward instead of forwards).
+ */
+FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
+{
+ //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars());
+ if (ad->isUnionDeclaration())
+ return NULL;
+
+ StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+ Loc declLoc = ad->dtors.dim ? ad->dtors[0]->loc : ad->loc;
+ Loc loc = Loc(); // internal code should have no loc to prevent coverage
+
+ Expression *e = NULL;
+ for (size_t i = 0; i < ad->fields.dim; i++)
+ {
+ VarDeclaration *v = ad->fields[i];
+ if (v->storage_class & STCref)
+ continue;
+ if (v->overlapped)
+ continue;
+ Type *tv = v->type->baseElemOf();
+ if (tv->ty != Tstruct)
+ continue;
+ StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
+ if (!sdv->dtor)
+ continue;
+ sdv->dtor->functionSemantic();
+
+ stc = mergeFuncAttrs(stc, sdv->dtor);
+ if (stc & STCdisable)
+ {
+ e = NULL;
+ break;
+ }
+
+ Expression *ex = NULL;
+ tv = v->type->toBasetype();
+ if (tv->ty == Tstruct)
+ {
+ // this.v.__xdtor()
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ ex = new AddrExp(loc, ex);
+ ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
+ ex = new PtrExp(loc, ex);
+ if (stc & STCsafe)
+ stc = (stc & ~STCsafe) | STCtrusted;
+
+ ex = new DotVarExp(loc, ex, sdv->dtor, false);
+ ex = new CallExp(loc, ex);
+ }
+ else
+ {
+ // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
+
+ uinteger_t n = 1;
+ while (tv->ty == Tsarray)
+ {
+ n *= ((TypeSArray *)tv)->dim->toUInteger();
+ tv = tv->nextOf()->toBasetype();
+ }
+ if (n == 0)
+ continue;
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ ex = new DotIdExp(loc, ex, Id::ptr);
+ ex = new CastExp(loc, ex, sdv->type->pointerTo());
+ if (stc & STCsafe)
+ stc = (stc & ~STCsafe) | STCtrusted;
+
+ ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
+ new IntegerExp(loc, n, Type::tsize_t));
+ // Prevent redundant bounds check
+ ((SliceExp *)ex)->upperIsInBounds = true;
+ ((SliceExp *)ex)->lowerIsLessThanUpper = true;
+
+ ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
+ }
+ e = Expression::combine(ex, e); // combine in reverse order
+ }
+
+ /* Build our own "destructor" which executes e
+ */
+ if (e || (stc & STCdisable))
+ {
+ //printf("Building __fieldDtor()\n");
+ DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor);
+ dd->generated = true;
+ dd->storage_class |= STCinference;
+ dd->fbody = new ExpStatement(loc, e);
+ ad->dtors.shift(dd);
+ ad->members->push(dd);
+ dd->semantic(sc);
+ }
+
+ FuncDeclaration *xdtor = NULL;
+ switch (ad->dtors.dim)
+ {
+ case 0:
+ break;
+
+ case 1:
+ xdtor = ad->dtors[0];
+ break;
+
+ default:
+ e = NULL;
+ stc = STCsafe | STCnothrow | STCpure | STCnogc;
+ for (size_t i = 0; i < ad->dtors.dim; i++)
+ {
+ FuncDeclaration *fd = ad->dtors[i];
+ stc = mergeFuncAttrs(stc, fd);
+ if (stc & STCdisable)
+ {
+ e = NULL;
+ break;
+ }
+ Expression *ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, fd, false);
+ ex = new CallExp(loc, ex);
+ e = Expression::combine(ex, e);
+ }
+ DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor);
+ dd->generated = true;
+ dd->storage_class |= STCinference;
+ dd->fbody = new ExpStatement(loc, e);
+ ad->members->push(dd);
+ dd->semantic(sc);
+ xdtor = dd;
+ break;
+ }
+ // Add an __xdtor alias to make the inclusive dtor accessible
+ if (xdtor)
+ {
+ AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor);
+ alias->semantic(sc);
+ ad->members->push(alias);
+ alias->addMember(sc, ad); // add to symbol table
+ }
+ return xdtor;
+}
+
+/******************************************
+ * Create inclusive invariant for struct/class by aggregating
+ * all the invariants in invs[].
+ * void __invariant() const [pure nothrow @trusted]
+ * {
+ * invs[0](), invs[1](), ...;
+ * }
+ */
+FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc)
+{
+ StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
+ Loc declLoc = ad->loc;
+ Loc loc = Loc(); // internal code should have no loc to prevent coverage
+
+ switch (ad->invs.dim)
+ {
+ case 0:
+ return NULL;
+
+ case 1:
+ // Don't return invs[0] so it has uniquely generated name.
+ /* fall through */
+
+ default:
+ Expression *e = NULL;
+ StorageClass stcx = 0;
+ for (size_t i = 0; i < ad->invs.dim; i++)
+ {
+ stc = mergeFuncAttrs(stc, ad->invs[i]);
+ if (stc & STCdisable)
+ {
+ // What should do?
+ }
+ StorageClass stcy = (ad->invs[i]->storage_class & STCsynchronized) |
+ (ad->invs[i]->type->mod & MODshared ? STCshared : 0);
+ if (i == 0)
+ stcx = stcy;
+ else if (stcx ^ stcy)
+ {
+ #if 1 // currently rejects
+ ad->error(ad->invs[i]->loc, "mixing invariants with shared/synchronized differene is not supported");
+ e = NULL;
+ break;
+ #endif
+ }
+ e = Expression::combine(e, new CallExp(loc, new VarExp(loc, ad->invs[i], false)));
+ }
+ InvariantDeclaration *inv;
+ inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id::classInvariant);
+ inv->fbody = new ExpStatement(loc, e);
+ ad->members->push(inv);
+ inv->semantic(sc);
+ return inv;
+ }
+}
diff --git a/gcc/d/dmd/compiler.h b/gcc/d/dmd/compiler.h
new file mode 100644
index 0000000..cfcc317
--- /dev/null
+++ b/gcc/d/dmd/compiler.h
@@ -0,0 +1,29 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/compiler.h
+ */
+
+#pragma once
+
+// This file contains a data structure that describes a back-end compiler
+// and implements compiler-specific actions.
+
+class Expression;
+class Module;
+class Type;
+struct Scope;
+
+struct Compiler
+{
+ // CTFE support for cross-compilation.
+ static Expression *paintAsType(Expression *, Type *);
+ // Backend
+ static void loadModule(Module *);
+ static void genCmain(Scope *);
+ static bool onImport(Module *);
+};
diff --git a/gcc/d/dmd/complex_t.h b/gcc/d/dmd/complex_t.h
new file mode 100644
index 0000000..b4ee395
--- /dev/null
+++ b/gcc/d/dmd/complex_t.h
@@ -0,0 +1,71 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/complex_t.h
+ */
+
+#pragma once
+
+#include "root/ctfloat.h"
+
+/* Roll our own complex type for compilers that don't support complex
+ */
+
+struct complex_t
+{
+ real_t re;
+ real_t im;
+
+ complex_t(real_t re) : re(re), im(ldouble(0)) {}
+ complex_t(real_t re, real_t im) : re(re), im(im) {}
+
+ complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); }
+ complex_t operator - (complex_t y) { return complex_t(re - y.re, im - y.im); }
+ complex_t operator - () { return complex_t(-re, -im); }
+ 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)
+ {
+ if (CTFloat::fabs(y.re) < CTFloat::fabs(y.im))
+ {
+ real_t r = y.re / y.im;
+ real_t den = y.im + r * y.re;
+ return complex_t((re * r + im) / den,
+ (im * r - re) / den);
+ }
+ else
+ {
+ real_t r = y.im / y.re;
+ real_t 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; }
+
+private:
+ complex_t() : re(ldouble(0)), im(ldouble(0)) {}
+};
+
+inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; }
+inline complex_t operator * (complex_t x, real_t y) { return x * complex_t(y); }
+inline complex_t operator / (complex_t x, real_t y) { return x / complex_t(y); }
+
+
+inline real_t creall(complex_t x)
+{
+ return x.re;
+}
+
+inline real_t cimagl(complex_t x)
+{
+ return x.im;
+}
diff --git a/gcc/d/dmd/cond.c b/gcc/d/dmd/cond.c
new file mode 100644
index 0000000..047eca2
--- /dev/null
+++ b/gcc/d/dmd/cond.c
@@ -0,0 +1,369 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/cond.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h> // strcmp()
+
+#include "mars.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 "mtype.h"
+#include "scope.h"
+#include "arraytypes.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
+
+int findCondition(Strings *ids, Identifier *ident)
+{
+ if (ids)
+ {
+ for (size_t i = 0; i < ids->dim; i++)
+ {
+ const char *id = (*ids)[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(Loc())
+{
+ 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(const char *ident)
+{
+ if (!global.params.debugids)
+ global.params.debugids = new Strings();
+ global.params.debugids->push(ident);
+}
+
+
+DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
+ : DVCondition(mod, level, ident)
+{
+}
+
+// Helper for printing dependency information
+void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType)
+{
+ if (!global.params.moduleDeps || global.params.moduleDepsFile)
+ return;
+ OutBuffer *ob = global.params.moduleDeps;
+ Module* imod = sc ? sc->instantiatingModule() : condition->mod;
+ if (!imod)
+ return;
+ ob->writestring(depType);
+ ob->writestring(imod->toPrettyChars());
+ ob->writestring(" (");
+ escapePath(ob, imod->srcfile->toChars());
+ ob->writestring(") : ");
+ if (condition->ident)
+ ob->printf("%s\n", condition->ident->toChars());
+ else
+ ob->printf("%d\n", condition->level);
+}
+
+
+int DebugCondition::include(Scope *sc, ScopeDsymbol *)
+{
+ //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
+ if (inc == 0)
+ {
+ inc = 2;
+ bool definedInModule = false;
+ if (ident)
+ {
+ if (findCondition(mod->debugids, ident))
+ {
+ inc = 1;
+ definedInModule = true;
+ }
+ else if (findCondition(global.params.debugids, ident))
+ inc = 1;
+ else
+ { if (!mod->debugidsNot)
+ mod->debugidsNot = new Strings();
+ mod->debugidsNot->push(ident->toChars());
+ }
+ }
+ else if (level <= global.params.debuglevel || level <= mod->debuglevel)
+ inc = 1;
+ if (!definedInModule)
+ printDepsConditional(sc, this, "depsDebug ");
+ }
+ return (inc == 1);
+}
+
+/* ============================================================ */
+
+void VersionCondition::setGlobalLevel(unsigned level)
+{
+ global.params.versionlevel = level;
+}
+
+static bool isReserved(const char *ident)
+{
+ static const char* reserved[] =
+ {
+ "DigitalMars",
+ "GNU",
+ "LDC",
+ "SDC",
+ "Windows",
+ "Win32",
+ "Win64",
+ "linux",
+ "OSX",
+ "FreeBSD",
+ "OpenBSD",
+ "NetBSD",
+ "DragonFlyBSD",
+ "BSD",
+ "Solaris",
+ "Posix",
+ "AIX",
+ "Haiku",
+ "SkyOS",
+ "SysV3",
+ "SysV4",
+ "Hurd",
+ "Android",
+ "Cygwin",
+ "MinGW",
+ "FreeStanding",
+ "X86",
+ "X86_64",
+ "ARM",
+ "ARM_Thumb",
+ "ARM_SoftFloat",
+ "ARM_SoftFP",
+ "ARM_HardFloat",
+ "AArch64",
+ "Epiphany",
+ "PPC",
+ "PPC_SoftFloat",
+ "PPC_HardFloat",
+ "PPC64",
+ "IA64",
+ "MIPS32",
+ "MIPS64",
+ "MIPS_O32",
+ "MIPS_N32",
+ "MIPS_O64",
+ "MIPS_N64",
+ "MIPS_EABI",
+ "MIPS_SoftFloat",
+ "MIPS_HardFloat",
+ "NVPTX",
+ "NVPTX64",
+ "SPARC",
+ "SPARC_V8Plus",
+ "SPARC_SoftFloat",
+ "SPARC_HardFloat",
+ "SPARC64",
+ "S390",
+ "S390X",
+ "HPPA",
+ "HPPA64",
+ "SH",
+ "Alpha",
+ "Alpha_SoftFloat",
+ "Alpha_HardFloat",
+ "LittleEndian",
+ "BigEndian",
+ "ELFv1",
+ "ELFv2",
+ "CRuntime_Digitalmars",
+ "CRuntime_Glibc",
+ "CRuntime_Microsoft",
+ "D_Coverage",
+ "D_Ddoc",
+ "D_InlineAsm_X86",
+ "D_InlineAsm_X86_64",
+ "D_LP64",
+ "D_X32",
+ "D_HardFloat",
+ "D_SoftFloat",
+ "D_PIC",
+ "D_SIMD",
+ "D_Version2",
+ "D_NoBoundsChecks",
+ "unittest",
+ "assert",
+ "all",
+ "none",
+ NULL
+ };
+
+ for (unsigned i = 0; reserved[i]; i++)
+ {
+ if (strcmp(ident, reserved[i]) == 0)
+ return true;
+ }
+
+ if (ident[0] == 'D' && ident[1] == '_')
+ return true;
+ return false;
+}
+
+void checkReserved(Loc loc, const char *ident)
+{
+ if (isReserved(ident))
+ error(loc, "version identifier '%s' is reserved and cannot be set", ident);
+}
+
+void VersionCondition::addGlobalIdent(const char *ident)
+{
+ checkReserved(Loc(), ident);
+ addPredefinedGlobalIdent(ident);
+}
+
+void VersionCondition::addPredefinedGlobalIdent(const char *ident)
+{
+ if (!global.params.versionids)
+ global.params.versionids = new Strings();
+ global.params.versionids->push(ident);
+}
+
+
+VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
+ : DVCondition(mod, level, ident)
+{
+}
+
+int VersionCondition::include(Scope *sc, ScopeDsymbol *)
+{
+ //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;
+ bool definedInModule=false;
+ if (ident)
+ {
+ if (findCondition(mod->versionids, ident))
+ {
+ inc = 1;
+ definedInModule = true;
+ }
+ else if (findCondition(global.params.versionids, ident))
+ inc = 1;
+ else
+ {
+ if (!mod->versionidsNot)
+ mod->versionidsNot = new Strings();
+ mod->versionidsNot->push(ident->toChars());
+ }
+ }
+ else if (level <= global.params.versionlevel || level <= mod->versionlevel)
+ inc = 1;
+ if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert)))
+ printDepsConditional(sc, this, "depsVersion ");
+ }
+ return (inc == 1);
+}
+
+/**************************** StaticIfCondition *******************************/
+
+StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
+ : Condition(loc)
+{
+ this->exp = exp;
+ this->nest = 0;
+}
+
+Condition *StaticIfCondition::syntaxCopy()
+{
+ return new StaticIfCondition(loc, exp->syntaxCopy());
+}
+
+int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
+{
+ if (inc == 0)
+ {
+ if (exp->op == TOKerror || nest > 100)
+ {
+ error(loc, (nest > 1000) ? "unresolvable circular static if expression"
+ : "error evaluating static if expression");
+ goto Lerror;
+ }
+
+ if (!sc)
+ {
+ error(loc, "static if conditional cannot be at global scope");
+ inc = 2;
+ return 0;
+ }
+
+ ++nest;
+ sc = sc->push(sc->scopesym);
+ sc->sds = sds; // sds gets any addMember()
+
+ bool errors = false;
+ bool result = evalStaticCondition(sc, exp, exp, errors);
+ sc->pop();
+ --nest;
+
+ // Prevent repeated condition evaluation.
+ // See: fail_compilation/fail7815.d
+ if (inc != 0)
+ return (inc == 1);
+ if (errors)
+ goto Lerror;
+ if (result)
+ inc = 1;
+ else
+ inc = 2;
+ }
+ return (inc == 1);
+
+Lerror:
+ if (!global.gag)
+ inc = 2; // so we don't see the error message again
+ return 0;
+}
diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h
new file mode 100644
index 0000000..e7727cc
--- /dev/null
+++ b/gcc/d/dmd/cond.h
@@ -0,0 +1,107 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/cond.h
+ */
+
+#pragma once
+
+#include "globals.h"
+#include "visitor.h"
+
+class Expression;
+class Identifier;
+struct OutBuffer;
+class Module;
+struct Scope;
+class ScopeDsymbol;
+class DebugCondition;
+class ForeachStatement;
+class ForeachRangeStatement;
+
+int findCondition(Strings *ids, Identifier *ident);
+
+class Condition
+{
+public:
+ Loc loc;
+ // 0: not computed yet
+ // 1: include
+ // 2: do not include
+ int inc;
+
+ Condition(Loc loc);
+
+ virtual Condition *syntaxCopy() = 0;
+ virtual int include(Scope *sc, ScopeDsymbol *sds) = 0;
+ virtual DebugCondition *isDebugCondition() { return NULL; }
+ virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticForeach
+{
+public:
+ Loc loc;
+
+ ForeachStatement *aggrfe;
+ ForeachRangeStatement *rangefe;
+
+ bool needExpansion;
+
+ StaticForeach *syntaxCopy();
+};
+
+class DVCondition : public Condition
+{
+public:
+ unsigned level;
+ Identifier *ident;
+ Module *mod;
+
+ DVCondition(Module *mod, unsigned level, Identifier *ident);
+
+ Condition *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DebugCondition : public DVCondition
+{
+public:
+ static void setGlobalLevel(unsigned level);
+ static void addGlobalIdent(const char *ident);
+
+ DebugCondition(Module *mod, unsigned level, Identifier *ident);
+
+ int include(Scope *sc, ScopeDsymbol *sds);
+ DebugCondition *isDebugCondition() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class VersionCondition : public DVCondition
+{
+public:
+ static void setGlobalLevel(unsigned level);
+ static void addGlobalIdent(const char *ident);
+ static void addPredefinedGlobalIdent(const char *ident);
+
+ VersionCondition(Module *mod, unsigned level, Identifier *ident);
+
+ int include(Scope *sc, ScopeDsymbol *sds);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticIfCondition : public Condition
+{
+public:
+ Expression *exp;
+ int nest; // limit circular dependencies
+
+ StaticIfCondition(Loc loc, Expression *exp);
+ Condition *syntaxCopy();
+ int include(Scope *sc, ScopeDsymbol *sds);
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/constfold.c b/gcc/d/dmd/constfold.c
new file mode 100644
index 0000000..43e831f
--- /dev/null
+++ b/gcc/d/dmd/constfold.c
@@ -0,0 +1,1918 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/constfold.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h> // mem{cpy|set|cmp}()
+#include <math.h>
+#include <new>
+
+#include "root/rmem.h"
+#include "root/root.h"
+#include "root/port.h"
+
+#include "errors.h"
+#include "mtype.h"
+#include "expression.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "utf.h"
+#include "ctfe.h"
+#include "target.h"
+
+int RealEquals(real_t x1, real_t x2);
+
+Expression *expType(Type *type, Expression *e)
+{
+ if (type != e->type)
+ {
+ e = e->copy();
+ e->type = type;
+ }
+ return e;
+}
+
+/* ================================== isConst() ============================== */
+
+int isConst(Expression *e)
+{
+ //printf("Expression::isConst(): %s\n", e->toChars());
+ switch (e->op)
+ {
+ case TOKint64:
+ case TOKfloat64:
+ case TOKcomplex80:
+ return 1;
+ case TOKnull:
+ return 0;
+ case TOKsymoff:
+ return 2;
+ default:
+ return 0;
+ }
+ assert(0);
+ return 0;
+}
+
+/* =============================== constFold() ============================== */
+
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+
+/* ========================================================================== */
+
+UnionExp Neg(Type *type, Expression *e1)
+{
+ UnionExp ue;
+ Loc loc = e1->loc;
+
+ if (e1->type->isreal())
+ {
+ new(&ue) RealExp(loc, -e1->toReal(), type);
+ }
+ else if (e1->type->isimaginary())
+ {
+ new(&ue) RealExp(loc, -e1->toImaginary(), type);
+ }
+ else if (e1->type->iscomplex())
+ {
+ new(&ue) ComplexExp(loc, -e1->toComplex(), type);
+ }
+ else
+ {
+ new(&ue) IntegerExp(loc, -e1->toInteger(), type);
+ }
+ return ue;
+}
+
+UnionExp Com(Type *type, Expression *e1)
+{
+ UnionExp ue;
+ Loc loc = e1->loc;
+
+ new(&ue) IntegerExp(loc, ~e1->toInteger(), type);
+ return ue;
+}
+
+UnionExp Not(Type *type, Expression *e1)
+{
+ UnionExp ue;
+ Loc loc = e1->loc;
+
+ new(&ue) IntegerExp(loc, e1->isBool(false) ? 1 : 0, type);
+ return ue;
+}
+
+UnionExp Bool(Type *type, Expression *e1)
+{
+ UnionExp ue;
+ Loc loc = e1->loc;
+
+ new(&ue) IntegerExp(loc, e1->isBool(true) ? 1 : 0, type);
+ return ue;
+}
+
+UnionExp Add(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+
+ if (type->isreal())
+ {
+ new(&ue) RealExp(loc, e1->toReal() + e2->toReal(), type);
+ }
+ else if (type->isimaginary())
+ {
+ new(&ue) 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 = complex_t(CTFloat::zero);
+ real_t r1 = CTFloat::zero;
+ real_t i1 = CTFloat::zero;
+
+ complex_t c2 = complex_t(CTFloat::zero);
+ real_t r2 = CTFloat::zero;
+ real_t i2 = CTFloat::zero;
+
+ complex_t v = complex_t(CTFloat::zero);
+ 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)
+ {
+ case 0 + 0:
+ v = complex_t(r1 + r2);
+ 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(CTFloat::zero, 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;
+ default:
+ assert(0);
+ }
+ new(&ue) ComplexExp(loc, v, type);
+ }
+ else if (e1->op == TOKsymoff)
+ {
+ SymOffExp *soe = (SymOffExp *)e1;
+ new(&ue) SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
+ ue.exp()->type = type;
+ }
+ else if (e2->op == TOKsymoff)
+ {
+ SymOffExp *soe = (SymOffExp *)e2;
+ new(&ue) SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
+ ue.exp()->type = type;
+ }
+ else
+ new(&ue) IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
+ return ue;
+}
+
+
+UnionExp Min(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+
+ if (type->isreal())
+ {
+ new(&ue) RealExp(loc, e1->toReal() - e2->toReal(), type);
+ }
+ else if (type->isimaginary())
+ {
+ new(&ue) 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 = complex_t(CTFloat::zero);
+ real_t r1 = CTFloat::zero;
+ real_t i1 = CTFloat::zero;
+
+ complex_t c2 = complex_t(CTFloat::zero);
+ real_t r2 = CTFloat::zero;
+ real_t i2 = CTFloat::zero;
+
+ complex_t v = complex_t(CTFloat::zero);
+ 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)
+ {
+ case 0 + 0:
+ v = complex_t(r1 - r2);
+ 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(CTFloat::zero, 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;
+ default:
+ assert(0);
+ }
+ new(&ue) ComplexExp(loc, v, type);
+ }
+ else if (e1->op == TOKsymoff)
+ {
+ SymOffExp *soe = (SymOffExp *)e1;
+ new(&ue) SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
+ ue.exp()->type = type;
+ }
+ else
+ {
+ new(&ue) IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
+ }
+ return ue;
+}
+
+UnionExp Mul(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+
+ if (type->isfloating())
+ {
+ complex_t c = complex_t(CTFloat::zero);
+ real_t r;
+
+ if (e1->type->isreal())
+ {
+ r = e1->toReal();
+ c = e2->toComplex();
+ c = complex_t(r * creall(c), r * cimagl(c));
+ }
+ else if (e1->type->isimaginary())
+ {
+ r = e1->toImaginary();
+ c = e2->toComplex();
+ c = complex_t(-r * cimagl(c), r * creall(c));
+ }
+ else if (e2->type->isreal())
+ {
+ r = e2->toReal();
+ c = e1->toComplex();
+ c = complex_t(r * creall(c), r * cimagl(c));
+ }
+ else if (e2->type->isimaginary())
+ {
+ r = e2->toImaginary();
+ c = e1->toComplex();
+ c = complex_t(-r * cimagl(c), r * creall(c));
+ }
+ else
+ c = e1->toComplex() * e2->toComplex();
+
+ if (type->isreal())
+ new(&ue) RealExp(loc, creall(c), type);
+ else if (type->isimaginary())
+ new(&ue) RealExp(loc, cimagl(c), type);
+ else if (type->iscomplex())
+ new(&ue) ComplexExp(loc, c, type);
+ else
+ assert(0);
+ }
+ else
+ {
+ new(&ue) IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
+ }
+ return ue;
+}
+
+UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+
+ if (type->isfloating())
+ {
+ complex_t c = complex_t(CTFloat::zero);
+ real_t r;
+
+ //e1->type->print();
+ //e2->type->print();
+ if (e2->type->isreal())
+ {
+ if (e1->type->isreal())
+ {
+ new(&ue) RealExp(loc, e1->toReal() / e2->toReal(), type);
+ return ue;
+ }
+ r = e2->toReal();
+ c = e1->toComplex();
+ c = complex_t(creall(c) / r, cimagl(c) / r);
+ }
+ else if (e2->type->isimaginary())
+ {
+ r = e2->toImaginary();
+ c = e1->toComplex();
+ c = complex_t(cimagl(c) / r, -creall(c) / r);
+ }
+ else
+ {
+ c = e1->toComplex() / e2->toComplex();
+ }
+
+ if (type->isreal())
+ new(&ue) RealExp(loc, creall(c), type);
+ else if (type->isimaginary())
+ new(&ue) RealExp(loc, cimagl(c), type);
+ else if (type->iscomplex())
+ new(&ue) 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");
+ new(&ue) ErrorExp();
+ return ue;
+ }
+ if (n2 == -1 && !type->isunsigned())
+ {
+ // Check for int.min / -1
+ if ((dinteger_t)n1 == 0xFFFFFFFF80000000UL && type->toBasetype()->ty != Tint64)
+ {
+ e2->error("integer overflow: int.min / -1");
+ new(&ue) ErrorExp();
+ return ue;
+ }
+ else if ((dinteger_t)n1 == 0x8000000000000000L) // long.min / -1
+ {
+ e2->error("integer overflow: long.min / -1");
+ new(&ue) ErrorExp();
+ return ue;
+ }
+ }
+ if (e1->type->isunsigned() || e2->type->isunsigned())
+ n = ((dinteger_t) n1) / ((dinteger_t) n2);
+ else
+ n = n1 / n2;
+ new(&ue) IntegerExp(loc, n, type);
+ }
+ return ue;
+}
+
+UnionExp Mod(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+
+ if (type->isfloating())
+ {
+ complex_t c = complex_t(CTFloat::zero);
+
+ if (e2->type->isreal())
+ {
+ real_t r2 = e2->toReal();
+
+ c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
+ }
+ else if (e2->type->isimaginary())
+ {
+ real_t i2 = e2->toImaginary();
+
+ c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
+ }
+ else
+ assert(0);
+
+ if (type->isreal())
+ new(&ue) RealExp(loc, creall(c), type);
+ else if (type->isimaginary())
+ new(&ue) RealExp(loc, cimagl(c), type);
+ else if (type->iscomplex())
+ new(&ue) 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");
+ new(&ue) ErrorExp();
+ return ue;
+ }
+ if (n2 == -1 && !type->isunsigned())
+ {
+ // Check for int.min % -1
+ if ((dinteger_t)n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64)
+ {
+ e2->error("integer overflow: int.min %% -1");
+ new(&ue) ErrorExp();
+ return ue;
+ }
+ else if ((dinteger_t)n1 == 0x8000000000000000LL) // long.min % -1
+ {
+ e2->error("integer overflow: long.min %% -1");
+ new(&ue) ErrorExp();
+ return ue;
+ }
+ }
+ if (e1->type->isunsigned() || e2->type->isunsigned())
+ n = ((dinteger_t) n1) % ((dinteger_t) n2);
+ else
+ n = n1 % n2;
+ new(&ue) IntegerExp(loc, n, type);
+ }
+ return ue;
+}
+
+UnionExp Pow(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+
+ // Handle integer power operations.
+ if (e2->type->isintegral())
+ {
+ dinteger_t n = e2->toInteger();
+ bool neg;
+
+ if (!e2->type->isunsigned() && (sinteger_t)n < 0)
+ {
+ if (e1->type->isintegral())
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+
+ // Don't worry about overflow, from now on n is unsigned.
+ neg = true;
+ n = -n;
+ }
+ else
+ neg = false;
+
+ UnionExp ur, uv;
+ if (e1->type->iscomplex())
+ {
+ new(&ur) ComplexExp(loc, e1->toComplex(), e1->type);
+ new(&uv) ComplexExp(loc, complex_t(CTFloat::one), e1->type);
+ }
+ else if (e1->type->isfloating())
+ {
+ new(&ur) RealExp(loc, e1->toReal(), e1->type);
+ new(&uv) RealExp(loc, CTFloat::one, e1->type);
+ }
+ else
+ {
+ new(&ur) IntegerExp(loc, e1->toInteger(), e1->type);
+ new(&uv) IntegerExp(loc, 1, e1->type);
+ }
+
+ Expression* r = ur.exp();
+ Expression* v = uv.exp();
+ while (n != 0)
+ {
+ if (n & 1)
+ {
+ // v = v * r;
+ uv = Mul(loc, v->type, v, r);
+ }
+ n >>= 1;
+ // r = r * r
+ ur = Mul(loc, r->type, r, r);
+ }
+
+ if (neg)
+ {
+ // ue = 1.0 / v
+ UnionExp one;
+ new(&one) RealExp(loc, CTFloat::one, v->type);
+ uv = Div(loc, v->type, one.exp(), v);
+ }
+
+ if (type->iscomplex())
+ new(&ue) ComplexExp(loc, v->toComplex(), type);
+ else if (type->isintegral())
+ new(&ue) IntegerExp(loc, v->toInteger(), type);
+ else
+ new(&ue) RealExp(loc, v->toReal(), type);
+ }
+ else if (e2->type->isfloating())
+ {
+ // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
+ if (e1->toReal() < CTFloat::zero)
+ {
+ new(&ue) RealExp(loc, Target::RealProperties::nan, type);
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+
+ return ue;
+}
+
+UnionExp Shl(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ new(&ue) IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
+ return ue;
+}
+
+UnionExp Shr(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ dinteger_t value = e1->toInteger();
+ dinteger_t dcount = e2->toInteger();
+ assert(dcount <= 0xFFFFFFFF);
+ unsigned count = (unsigned)dcount;
+ switch (e1->type->toBasetype()->ty)
+ {
+ case Tint8:
+ value = (d_int8)(value) >> count;
+ break;
+
+ case Tuns8:
+ case Tchar:
+ value = (d_uns8)(value) >> count;
+ break;
+
+ case Tint16:
+ value = (d_int16)(value) >> count;
+ break;
+
+ case Tuns16:
+ case Twchar:
+ value = (d_uns16)(value) >> count;
+ break;
+
+ case Tint32:
+ value = (d_int32)(value) >> count;
+ break;
+
+ case Tuns32:
+ case Tdchar:
+ value = (d_uns32)(value) >> count;
+ break;
+
+ case Tint64:
+ value = (d_int64)(value) >> count;
+ break;
+
+ case Tuns64:
+ value = (d_uns64)(value) >> count;
+ break;
+
+ case Terror:
+ new(&ue) ErrorExp();
+ return ue;
+
+ default:
+ assert(0);
+ }
+ new(&ue) IntegerExp(loc, value, type);
+ return ue;
+}
+
+UnionExp Ushr(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ dinteger_t value = e1->toInteger();
+ dinteger_t dcount = e2->toInteger();
+ assert(dcount <= 0xFFFFFFFF);
+ unsigned count = (unsigned)dcount;
+ switch (e1->type->toBasetype()->ty)
+ {
+ case Tint8:
+ case Tuns8:
+ case Tchar:
+ // Possible only with >>>=. >>> always gets promoted to int.
+ value = (value & 0xFF) >> count;
+ break;
+
+ case Tint16:
+ case Tuns16:
+ case Twchar:
+ // Possible only with >>>=. >>> always gets promoted to int.
+ value = (value & 0xFFFF) >> count;
+ break;
+
+ case Tint32:
+ case Tuns32:
+ case Tdchar:
+ value = (value & 0xFFFFFFFF) >> count;
+ break;
+
+ case Tint64:
+ case Tuns64:
+ value = (d_uns64)(value) >> count;
+ break;
+
+ case Terror:
+ new(&ue) ErrorExp();
+ return ue;
+
+ default:
+ assert(0);
+ }
+ new(&ue) IntegerExp(loc, value, type);
+ return ue;
+}
+
+UnionExp And(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ new(&ue) IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
+ return ue;
+}
+
+UnionExp Or(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ new(&ue) IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
+ return ue;
+}
+
+UnionExp Xor(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ new(&ue) IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
+ return ue;
+}
+
+/* Also returns TOKcantexp if cannot be computed.
+ */
+UnionExp Equal(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ int cmp = 0;
+ 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 == TOKnull)
+ {
+ if (e2->op == TOKnull)
+ cmp = 1;
+ else if (e2->op == TOKstring)
+ {
+ StringExp *es2 = (StringExp *)e2;
+ cmp = (0 == es2->len);
+ }
+ else if (e2->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+ cmp = !es2->elements || (0 == es2->elements->dim);
+ }
+ else
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ }
+ else if (e2->op == TOKnull)
+ {
+ if (e1->op == TOKstring)
+ {
+ StringExp *es1 = (StringExp *)e1;
+ cmp = (0 == es1->len);
+ }
+ else if (e1->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+ cmp = !es1->elements || (0 == es1->elements->dim);
+ }
+ else
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ }
+ else if (e1->op == TOKstring && e2->op == TOKstring)
+ {
+ StringExp *es1 = (StringExp *)e1;
+ StringExp *es2 = (StringExp *)e2;
+
+ if (es1->sz != es2->sz)
+ {
+ assert(global.errors);
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ 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 = es1->getElement(i);
+ Expression *ee2 = es2->getElement(i);
+ ue = Equal(TOKequal, loc, Type::tint32, ee1, ee2);
+ if (CTFEExp::isCantExp(ue.exp()))
+ return ue;
+ cmp = (int)ue.exp()->toInteger();
+ if (cmp == 0)
+ break;
+ }
+ }
+ }
+ else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
+ {
+ // Swap operands and use common code
+ Expression *etmp = e1;
+ e1 = e2;
+ e2 = etmp;
+ goto Lsa;
+ }
+ else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
+ {
+ Lsa:
+ StringExp *es1 = (StringExp *)e1;
+ ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+ size_t dim1 = es1->len;
+ size_t dim2 = es2->elements ? es2->elements->dim : 0;
+ if (dim1 != dim2)
+ cmp = 0;
+ else
+ {
+ cmp = 1; // if dim1 winds up being 0
+ for (size_t i = 0; i < dim1; i++)
+ {
+ uinteger_t c = es1->charAt(i);
+ Expression *ee2 = es2->getElement(i);
+ if (ee2->isConst() != 1)
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ cmp = (c == ee2->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 = (*es1->elements)[i];
+ Expression *ee2 = (*es2->elements)[i];
+
+ if (ee1 == ee2)
+ continue;
+ if (!ee1 || !ee2)
+ {
+ cmp = 0;
+ break;
+ }
+ ue = Equal(TOKequal, loc, Type::tint32, ee1, ee2);
+ if (ue.exp()->op == TOKcantexp)
+ return ue;
+ cmp = (int)ue.exp()->toInteger();
+ if (cmp == 0)
+ break;
+ }
+ }
+ }
+ else if (e1->isConst() != 1 || e2->isConst() != 1)
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ 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 (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
+ {
+ cmp = 0;
+ }
+ else
+ {
+ cmp = (r1 == r2);
+ }
+ }
+ else if (e1->type->iscomplex())
+ {
+ cmp = e1->toComplex() == e2->toComplex();
+ }
+ else if (e1->type->isintegral() || e1->type->toBasetype()->ty == Tpointer)
+ {
+ cmp = (e1->toInteger() == e2->toInteger());
+ }
+ else
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+
+ if (op == TOKnotequal)
+ cmp ^= 1;
+ new(&ue) IntegerExp(loc, cmp, type);
+ return ue;
+}
+
+UnionExp Identity(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ int cmp;
+
+ if (e1->op == TOKnull)
+ {
+ cmp = (e2->op == TOKnull);
+ }
+ else if (e2->op == TOKnull)
+ {
+ cmp = 0;
+ }
+ else 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->type->isreal())
+ {
+ cmp = RealEquals(e1->toReal(), e2->toReal());
+ }
+ else if (e1->type->isimaginary())
+ {
+ cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
+ }
+ else if (e1->type->iscomplex())
+ {
+ complex_t v1 = e1->toComplex();
+ complex_t v2 = e2->toComplex();
+ cmp = RealEquals(creall(v1), creall(v2)) &&
+ RealEquals(cimagl(v1), cimagl(v1));
+ }
+ else
+ {
+ ue = Equal((op == TOKidentity) ? TOKequal : TOKnotequal, loc, type, e1, e2);
+ return ue;
+ }
+ }
+ if (op == TOKnotidentity)
+ cmp ^= 1;
+ new(&ue) IntegerExp(loc, cmp, type);
+ return ue;
+}
+
+
+UnionExp Cmp(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ dinteger_t n;
+ real_t r1;
+ real_t r2;
+
+ //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+
+ if (e1->op == TOKstring && e2->op == TOKstring)
+ {
+ StringExp *es1 = (StringExp *)e1;
+ StringExp *es2 = (StringExp *)e2;
+ size_t sz = es1->sz;
+ assert(sz == es2->sz);
+
+ size_t len = es1->len;
+ if (es2->len < len)
+ len = es2->len;
+
+ int rawCmp = memcmp(es1->string, es2->string, sz * len);
+ if (rawCmp == 0)
+ rawCmp = (int)(es1->len - es2->len);
+ n = specificCmp(op, rawCmp);
+ }
+ else if (e1->isConst() != 1 || e2->isConst() != 1)
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ 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:
+ n = realCmp(op, r1, r2);
+ }
+ 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())
+ n = intUnsignedCmp(op, n1, n2);
+ else
+ n = intSignedCmp(op, n1, n2);
+ }
+ new(&ue) IntegerExp(loc, n, type);
+ return ue;
+}
+
+/* Also returns TOKcantexp if cannot be computed.
+ * to: type to cast to
+ * type: type to paint the result
+ */
+
+UnionExp Cast(Loc loc, Type *type, Type *to, Expression *e1)
+{
+ UnionExp ue;
+ Type *tb = to->toBasetype();
+ Type *typeb = type->toBasetype();
+
+ //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
+ //printf("\te1->type = %s\n", e1->type->toChars());
+ if (e1->type->equals(type) && type->equals(to))
+ {
+ new(&ue) UnionExp(e1);
+ return ue;
+ }
+
+ if (e1->op == TOKvector && ((TypeVector *)e1->type)->basetype->equals(type) && type->equals(to))
+ {
+ Expression *ex = ((VectorExp *)e1)->e1;
+ new(&ue) UnionExp(ex);
+ return ue;
+ }
+
+ if (e1->type->implicitConvTo(to) >= MATCHconst ||
+ to->implicitConvTo(e1->type) >= MATCHconst)
+ {
+ goto L1;
+ }
+
+ // Allow covariant converions of delegates
+ // (Perhaps implicit conversion from pure to impure should be a MATCHconst,
+ // then we wouldn't need this extra check.)
+ if (e1->type->toBasetype()->ty == Tdelegate &&
+ e1->type->implicitConvTo(to) == MATCHconvert)
+ {
+ goto L1;
+ }
+
+ /* Allow casting from one string type to another
+ */
+ if (e1->op == TOKstring)
+ {
+ if (tb->ty == Tarray && typeb->ty == Tarray &&
+ tb->nextOf()->size() == typeb->nextOf()->size())
+ {
+ goto L1;
+ }
+ }
+
+ if (e1->op == TOKarrayliteral && typeb == tb)
+ {
+L1:
+ Expression *ex = expType(to, e1);
+ new(&ue) UnionExp(ex);
+ return ue;
+ }
+
+ if (e1->isConst() != 1)
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ }
+ else if (tb->ty == Tbool)
+ {
+ new(&ue) IntegerExp(loc, e1->toInteger() != 0, type);
+ }
+ else if (type->isintegral())
+ {
+ if (e1->type->isfloating())
+ {
+ dinteger_t result;
+ real_t r = e1->toReal();
+
+ switch (typeb->ty)
+ {
+ case Tint8:
+ result = (d_int8)(sinteger_t)r;
+ break;
+ case Tchar:
+ case Tuns8:
+ result = (d_uns8)(dinteger_t)r;
+ break;
+ case Tint16:
+ result = (d_int16)(sinteger_t)r;
+ break;
+ case Twchar:
+ case Tuns16:
+ result = (d_uns16)(dinteger_t)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);
+ }
+
+ new(&ue) IntegerExp(loc, result, type);
+ }
+ else if (type->isunsigned())
+ new(&ue) IntegerExp(loc, e1->toUInteger(), type);
+ else
+ new(&ue) IntegerExp(loc, e1->toInteger(), type);
+ }
+ else if (tb->isreal())
+ {
+ real_t value = e1->toReal();
+
+ new(&ue) RealExp(loc, value, type);
+ }
+ else if (tb->isimaginary())
+ {
+ real_t value = e1->toImaginary();
+
+ new(&ue) RealExp(loc, value, type);
+ }
+ else if (tb->iscomplex())
+ {
+ complex_t value = e1->toComplex();
+
+ new(&ue) ComplexExp(loc, value, type);
+ }
+ else if (tb->isscalar())
+ {
+ new(&ue) IntegerExp(loc, e1->toInteger(), type);
+ }
+ else if (tb->ty == Tvoid)
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ }
+ 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++)
+ {
+ VarDeclaration *v = sd->fields[i];
+ UnionExp zero;
+ new(&zero) IntegerExp(0);
+ ue = Cast(loc, v->type, v->type, zero.exp());
+ if (ue.exp()->op == TOKcantexp)
+ return ue;
+ elements->push(ue.exp()->copy());
+ }
+ new(&ue) StructLiteralExp(loc, sd, elements);
+ ue.exp()->type = type;
+ }
+ else
+ {
+ if (type != Type::terror)
+ {
+ // have to change to Internal Compiler Error
+ // all invalid casts should be handled already in Expression::castTo().
+ error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
+ }
+ new(&ue) ErrorExp();
+ }
+ return ue;
+}
+
+
+UnionExp ArrayLength(Type *type, Expression *e1)
+{
+ UnionExp ue;
+ Loc loc = e1->loc;
+
+ if (e1->op == TOKstring)
+ {
+ StringExp *es1 = (StringExp *)e1;
+
+ new(&ue) IntegerExp(loc, es1->len, type);
+ }
+ else if (e1->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+ size_t dim = ale->elements ? ale->elements->dim : 0;
+
+ new(&ue) IntegerExp(loc, dim, type);
+ }
+ else if (e1->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
+ size_t dim = ale->keys->dim;
+
+ new(&ue) IntegerExp(loc, dim, type);
+ }
+ else if (e1->type->toBasetype()->ty == Tsarray)
+ {
+ Expression *e = ((TypeSArray *)e1->type->toBasetype())->dim;
+ new(&ue) UnionExp(e);
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+}
+
+/* Also return TOKcantexp if this fails
+ */
+UnionExp Index(Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ 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 %llu is out of bounds [0 .. %llu]", i, (ulonglong)es1->len);
+ new(&ue) ErrorExp();
+ }
+ else
+ {
+ new(&ue) IntegerExp(loc, es1->charAt(i), 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)
+ {
+ e1->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
+ new(&ue) ErrorExp();
+ }
+ else if (e1->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+ Expression *e = ale->getElement((size_t)i);
+ e->type = type;
+ e->loc = loc;
+ if (hasSideEffect(e))
+ new(&ue) CTFEExp(TOKcantexp);
+ else
+ new(&ue) UnionExp(e);
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+ }
+ else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
+ {
+ uinteger_t i = e2->toInteger();
+
+ if (e1->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+ if (i >= ale->elements->dim)
+ {
+ e1->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
+ new(&ue) ErrorExp();
+ }
+ else
+ {
+ Expression *e = ale->getElement((size_t)i);
+ e->type = type;
+ e->loc = loc;
+ if (hasSideEffect(e))
+ new(&ue) CTFEExp(TOKcantexp);
+ else
+ new(&ue) UnionExp(e);
+ }
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+ }
+ else if (e1->op == TOKassocarrayliteral)
+ {
+ 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 = (*ae->keys)[i];
+ ue = Equal(TOKequal, loc, Type::tbool, ekey, e2);
+ if (CTFEExp::isCantExp(ue.exp()))
+ return ue;
+ if (ue.exp()->isBool(true))
+ {
+ Expression *e = (*ae->values)[i];
+ e->type = type;
+ e->loc = loc;
+ if (hasSideEffect(e))
+ new(&ue) CTFEExp(TOKcantexp);
+ else
+ new(&ue) UnionExp(e);
+ return ue;
+ }
+ }
+ new(&ue) CTFEExp(TOKcantexp);
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+}
+
+/* Also return TOKcantexp if this fails
+ */
+UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
+{
+ UnionExp ue;
+ Loc loc = e1->loc;
+
+ 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 [%llu .. %llu] is out of bounds", ilwr, iupr);
+ new(&ue) ErrorExp();
+ }
+ else
+ {
+ size_t len = (size_t)(iupr - ilwr);
+ unsigned char sz = es1->sz;
+
+ void *s = mem.xmalloc((len + 1) * sz);
+ memcpy((char *)s, (char *)es1->string + ilwr * sz, len * sz);
+ memset((char *)s + len * sz, 0, sz);
+
+ new(&ue) StringExp(loc, s, len, es1->postfix);
+ StringExp *es = (StringExp *)ue.exp();
+ es->sz = sz;
+ es->committed = es1->committed;
+ es->type = type;
+ }
+ }
+ else if (e1->op == TOKarrayliteral &&
+ lwr->op == TOKint64 && upr->op == TOKint64 &&
+ !hasSideEffect(e1))
+ {
+ 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 [%llu .. %llu] is out of bounds", ilwr, iupr);
+ new(&ue) ErrorExp();
+ }
+ else
+ {
+ Expressions *elements = new Expressions();
+ elements->setDim((size_t)(iupr - ilwr));
+ memcpy(elements->tdata(),
+ es1->elements->tdata() + ilwr,
+ (size_t)(iupr - ilwr) * sizeof((*es1->elements)[0]));
+ new(&ue) ArrayLiteralExp(e1->loc, elements);
+ ue.exp()->type = type;
+ }
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+ assert(ue.exp()->type);
+ return ue;
+}
+
+/* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
+ * existingAE[firstIndex..firstIndex+newval.length] = newval.
+ */
+void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, size_t firstIndex)
+{
+ size_t newlen = newval->len;
+ size_t sz = newval->sz;
+ void *s = newval->string;
+ Type *elemType = existingAE->type->nextOf();
+ for (size_t j = 0; j < newlen; j++)
+ {
+ dinteger_t val;
+ switch (sz)
+ {
+ case 1: val = (( utf8_t *)s)[j]; break;
+ case 2: val = ((utf16_t *)s)[j]; break;
+ case 4: val = ((utf32_t *)s)[j]; break;
+ default: assert(0); break;
+ }
+ (*existingAE->elements)[j + firstIndex]
+ = new IntegerExp(newval->loc, val, elemType);
+ }
+}
+
+/* Set a slice of string 'existingSE' from a char array literal 'newae'.
+ * existingSE[firstIndex..firstIndex+newae.length] = newae.
+ */
+void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex)
+{
+ void *s = existingSE->string;
+ for (size_t j = 0; j < newae->elements->dim; j++)
+ {
+ unsigned val = (unsigned)newae->getElement(j)->toInteger();
+ switch (existingSE->sz)
+ {
+ case 1: (( utf8_t *)s)[j + firstIndex] = ( utf8_t)val; break;
+ case 2: ((utf16_t *)s)[j + firstIndex] = (utf16_t)val; break;
+ case 4: ((utf32_t *)s)[j + firstIndex] = (utf32_t)val; break;
+ default: assert(0); break;
+ }
+ }
+}
+
+/* Set a slice of string 'existingSE' from a string 'newstr'.
+ * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
+ */
+void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex)
+{
+ void *s = existingSE->string;
+ size_t sz = existingSE->sz;
+ assert(sz == newstr->sz);
+ memcpy((char *)s + firstIndex * sz, newstr->string, sz * newstr->len);
+}
+
+/* Compare a string slice with another string slice.
+ * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
+ */
+int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len)
+{
+ void *s1 = se1->string;
+ void *s2 = se2->string;
+ size_t sz = se1->sz;
+ assert(sz == se2->sz);
+ return memcmp((char *)s1 + sz * lo1, (char *)s2 + sz * lo2, sz * len);
+}
+
+/* Compare a string slice with an array literal slice
+ * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
+ */
+int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len)
+{
+ void *s = se1->string;
+ size_t sz = se1->sz;
+
+ for (size_t j = 0; j < len; j++)
+ {
+ unsigned val2 = (unsigned)ae2->getElement(j + lo2)->toInteger();
+ unsigned val1;
+ switch (sz)
+ {
+ case 1: val1 = (( utf8_t *)s)[j + lo1]; break;
+ case 2: val1 = ((utf16_t *)s)[j + lo1]; break;
+ case 4: val1 = ((utf32_t *)s)[j + lo1]; break;
+ default: assert(0); break;
+ }
+ int c = val1 - val2;
+ if (c)
+ return c;
+ }
+ return 0;
+}
+
+/* Also return TOKcantexp if this fails
+ */
+UnionExp Cat(Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ Expression *e = CTFEExp::cantexp;
+ Loc loc = e1->loc;
+ Type *t;
+ Type *t1 = e1->type->toBasetype();
+ Type *t2 = e2->type->toBasetype();
+
+ //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
+ //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars());
+
+ if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
+ {
+ e = e2;
+ t = t1;
+ goto L2;
+ }
+ else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
+ {
+ e = e1;
+ t = t2;
+ L2:
+ Type *tn = e->type->toBasetype();
+ if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+ {
+ // Create a StringExp
+ if (t->nextOf())
+ t = t->nextOf()->toBasetype();
+ unsigned char sz = (unsigned char)t->size();
+
+ dinteger_t v = e->toInteger();
+
+ size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, (dchar_t)v);
+ void *s = mem.xmalloc((len + 1) * sz);
+ if (t->ty == tn->ty)
+ Port::valcpy(s, v, sz);
+ else
+ utf_encode(sz, s, (dchar_t)v);
+
+ // Add terminating 0
+ memset((char *)s + len * sz, 0, sz);
+
+ new(&ue) StringExp(loc, s, len);
+ StringExp *es = (StringExp *)ue.exp();
+ es->sz = sz;
+ es->committed = 1;
+ }
+ else
+ {
+ // Create an ArrayLiteralExp
+ Expressions *elements = new Expressions();
+ elements->push(e);
+ new(&ue) ArrayLiteralExp(e->loc, elements);
+ }
+ ue.exp()->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e1->op == TOKnull && e2->op == TOKnull)
+ {
+ if (type == e1->type)
+ {
+ // Handle null ~= null
+ if (t1->ty == Tarray && t2 == t1->nextOf())
+ {
+ new(&ue) ArrayLiteralExp(e1->loc, e2);
+ ue.exp()->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else
+ {
+ new(&ue) UnionExp(e1);
+ assert(ue.exp()->type);
+ return ue;
+ }
+ }
+ if (type == e2->type)
+ {
+ new(&ue) UnionExp(e2);
+ assert(ue.exp()->type);
+ return ue;
+ }
+ new(&ue) NullExp(e1->loc, type);
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e1->op == TOKstring && e2->op == TOKstring)
+ {
+ // Concatenate the strings
+ StringExp *es1 = (StringExp *)e1;
+ StringExp *es2 = (StringExp *)e2;
+ size_t len = es1->len + es2->len;
+ unsigned char sz = es1->sz;
+
+ if (sz != es2->sz)
+ {
+ /* Can happen with:
+ * auto s = "foo"d ~ "bar"c;
+ */
+ assert(global.errors);
+ new(&ue) CTFEExp(TOKcantexp);
+ assert(ue.exp()->type);
+ return ue;
+ }
+ void *s = mem.xmalloc((len + 1) * sz);
+ memcpy((char *)s, es1->string, es1->len * sz);
+ memcpy((char *)s + es1->len * sz, es2->string, es2->len * sz);
+
+ // Add terminating 0
+ memset((char *)s + len * sz, 0, sz);
+
+ new(&ue) StringExp(loc, s, len);
+ StringExp *es = (StringExp *)ue.exp();
+ es->sz = sz;
+ es->committed = es1->committed | es2->committed;
+ es->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
+ t1->nextOf()->isintegral())
+ {
+ // [chars] ~ string --> [chars]
+ StringExp *es = (StringExp *)e2;
+ ArrayLiteralExp *ea = (ArrayLiteralExp *)e1;
+ size_t len = es->len + ea->elements->dim;
+ Expressions * elems = new Expressions;
+ elems->setDim(len);
+ for (size_t i= 0; i < ea->elements->dim; ++i)
+ {
+ (*elems)[i] = ea->getElement(i);
+ }
+ new(&ue) ArrayLiteralExp(e1->loc, elems);
+ ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
+ dest->type = type;
+ sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim);
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
+ t2->nextOf()->isintegral())
+ {
+ // string ~ [chars] --> [chars]
+ StringExp *es = (StringExp *)e1;
+ ArrayLiteralExp *ea = (ArrayLiteralExp *)e2;
+ size_t len = es->len + ea->elements->dim;
+ Expressions * elems = new Expressions;
+ elems->setDim(len);
+ for (size_t i= 0; i < ea->elements->dim; ++i)
+ {
+ (*elems)[es->len + i] = ea->getElement(i);
+ }
+ new(&ue) ArrayLiteralExp(e1->loc, elems);
+ ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
+ dest->type = type;
+ sliceAssignArrayLiteralFromString(dest, es, 0);
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e1->op == TOKstring && e2->op == TOKint64)
+ {
+ // string ~ char --> string
+ StringExp *es1 = (StringExp *)e1;
+ StringExp *es;
+ unsigned char sz = es1->sz;
+ dinteger_t v = e2->toInteger();
+
+ // Is it a concatentation of homogenous types?
+ // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
+ bool homoConcat = (sz == t2->size());
+ size_t len = es1->len;
+ len += homoConcat ? 1 : utf_codeLength(sz, (dchar_t)v);
+
+ void *s = mem.xmalloc((len + 1) * sz);
+ memcpy(s, es1->string, es1->len * sz);
+ if (homoConcat)
+ Port::valcpy((char *)s + (sz * es1->len), v, sz);
+ else
+ utf_encode(sz, (char *)s + (sz * es1->len), (dchar_t)v);
+
+ // Add terminating 0
+ memset((char *)s + len * sz, 0, sz);
+
+ new(&ue) StringExp(loc, s, len);
+ es = (StringExp *)ue.exp();
+ es->sz = sz;
+ es->committed = es1->committed;
+ es->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e1->op == TOKint64 && e2->op == TOKstring)
+ {
+ // Concatenate the strings
+ StringExp *es2 = (StringExp *)e2;
+ size_t len = 1 + es2->len;
+ unsigned char sz = es2->sz;
+ dinteger_t v = e1->toInteger();
+
+ void *s = mem.xmalloc((len + 1) * sz);
+ memcpy((char *)s, &v, sz);
+ memcpy((char *)s + sz, es2->string, es2->len * sz);
+
+ // Add terminating 0
+ memset((char *)s + len * sz, 0, sz);
+
+ new(&ue) StringExp(loc, s, len);
+ StringExp *es = (StringExp *)ue.exp();
+ es->sz = sz;
+ es->committed = es2->committed;
+ es->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+ t1->nextOf()->equals(t2->nextOf()))
+ {
+ // Concatenate the arrays
+ Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
+
+ new(&ue) ArrayLiteralExp(e1->loc, elems);
+
+ e = ue.exp();
+ if (type->toBasetype()->ty == Tsarray)
+ {
+ e->type = t1->nextOf()->sarrayOf(elems->dim);
+ }
+ else
+ e->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
+ t1->nextOf()->equals(t2->nextOf()))
+ {
+ e = e1;
+ goto L3;
+ }
+ else if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
+ t1->nextOf()->equals(t2->nextOf()))
+ {
+ e = e2;
+ L3:
+ // Concatenate the array with null
+ Expressions *elems = ArrayLiteralExp::copyElements(e);
+
+ new(&ue) ArrayLiteralExp(e->loc, elems);
+
+ e = ue.exp();
+ if (type->toBasetype()->ty == Tsarray)
+ {
+ e->type = t1->nextOf()->sarrayOf(elems->dim);
+ }
+ else
+ e->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) &&
+ e1->type->toBasetype()->nextOf() &&
+ e1->type->toBasetype()->nextOf()->equals(e2->type))
+ {
+ Expressions *elems = (e1->op == TOKarrayliteral)
+ ? ArrayLiteralExp::copyElements(e1) : new Expressions();
+ elems->push(e2);
+
+ new(&ue) ArrayLiteralExp(e1->loc, elems);
+
+ e = ue.exp();
+ if (type->toBasetype()->ty == Tsarray)
+ {
+ e->type = e2->type->sarrayOf(elems->dim);
+ }
+ else
+ e->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ else if (e2->op == TOKarrayliteral &&
+ e2->type->toBasetype()->nextOf()->equals(e1->type))
+ {
+ Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
+
+ new(&ue) ArrayLiteralExp(e2->loc, elems);
+
+ e = ue.exp();
+ if (type->toBasetype()->ty == Tsarray)
+ {
+ e->type = e1->type->sarrayOf(elems->dim);
+ }
+ else
+ e->type = type;
+ assert(ue.exp()->type);
+ return ue;
+ }
+ 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->nextOf()->equivalent(e->type))
+ {
+ Expressions *expressions = new Expressions();
+ expressions->push(e);
+ new(&ue) ArrayLiteralExp(loc, expressions);
+ e = ue.exp();
+ e->type = t;
+ }
+ else
+ {
+ new(&ue) UnionExp(e);
+ e = ue.exp();
+ }
+ if (!e->type->equals(type))
+ {
+ StringExp *se = (StringExp *)e->copy();
+ e = se->castTo(NULL, type);
+ new(&ue) UnionExp(e);
+ e = ue.exp();
+ }
+ }
+ else
+ new(&ue) CTFEExp(TOKcantexp);
+ assert(ue.exp()->type);
+ return ue;
+}
+
+UnionExp Ptr(Type *type, Expression *e1)
+{
+ //printf("Ptr(e1 = %s)\n", e1->toChars());
+ UnionExp ue;
+ 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 = (unsigned)ae->e2->toInteger();
+ Expression *e = se->getField(type, offset);
+ if (e)
+ {
+ new(&ue) UnionExp(e);
+ return ue;
+ }
+ }
+ }
+ }
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+}
diff --git a/gcc/d/dmd/cppmangle.c b/gcc/d/dmd/cppmangle.c
new file mode 100644
index 0000000..bb919a5
--- /dev/null
+++ b/gcc/d/dmd/cppmangle.c
@@ -0,0 +1,1103 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/cppmangle.c
+ */
+
+/**
+ * Do mangling for C++ linkage.
+ *
+ * References:
+ * Follows Itanium C++ ABI 1.86 section 5.1
+ * http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling
+ * which is where the grammar comments come from.
+ *
+ * Bugs:
+ * https://issues.dlang.org/query.cgi
+ * enter `C++, mangling` as the keywords.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+#include "target.h"
+
+typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
+
+class CppMangleVisitor : public Visitor
+{
+ Objects components; // array of components available for substitution
+ OutBuffer *buf; // append the mangling to buf[]
+ Loc loc; // location for use in error messages
+
+ public:
+ // Write <seq-id> to buf
+ void write_seq_id(size_t i)
+ {
+ if (i >= 36)
+ {
+ write_seq_id(i / 36);
+ i %= 36;
+ }
+ i += (i < 10) ? '0' : 'A' - 10;
+ buf->writeByte((char)i);
+ }
+
+ bool substitute(RootObject *p)
+ {
+ //printf("substitute %s\n", p ? p->toChars() : NULL);
+ int i = find(p);
+ if (i >= 0)
+ {
+ //printf("\tmatch\n");
+ /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
+ */
+ buf->writeByte('S');
+ if (i)
+ {
+ write_seq_id(i - 1);
+ }
+ buf->writeByte('_');
+ return true;
+ }
+ return false;
+ }
+
+ /******
+ * See if `p` exists in components[]
+ * Returns:
+ * index if found, -1 if not
+ */
+ int find(RootObject *p)
+ {
+ //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : NULL);
+ for (size_t i = 0; i < components.dim; i++)
+ {
+ if (p == components[i])
+ return (int)i;
+ }
+ return -1;
+ }
+
+ /*********************
+ * Append p to components[]
+ */
+ void append(RootObject *p)
+ {
+ //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null");
+ components.push(p);
+ }
+
+ /************************
+ * Determine if symbol is indeed the global ::std namespace.
+ * Params:
+ * s = symbol to check
+ * Returns:
+ * true if it is ::std
+ */
+ static bool isStd(Dsymbol *s)
+ {
+ return (s &&
+ s->ident == Id::std && // the right name
+ s->isNspace() && // g++ disallows global "std" for other than a namespace
+ !getQualifier(s)); // at global level
+ }
+
+ /******************************
+ * Write the mangled representation of the template arguments.
+ * Params:
+ * ti = the template instance
+ */
+ void template_args(TemplateInstance *ti)
+ {
+ /* <template-args> ::= I <template-arg>+ E
+ */
+ if (!ti) // could happen if std::basic_string is not a template
+ return;
+ buf->writeByte('I');
+ for (size_t i = 0; i < ti->tiargs->dim; i++)
+ {
+ RootObject *o = (*ti->tiargs)[i];
+ TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
+ assert(td);
+ TemplateParameter *tp = (*td->parameters)[i];
+
+ /*
+ * <template-arg> ::= <type> # type or template
+ * ::= X <expression> E # expression
+ * ::= <expr-primary> # simple expressions
+ * ::= I <template-arg>* E # argument pack
+ */
+ if (tp->isTemplateTupleParameter())
+ {
+ buf->writeByte('I'); // argument pack
+
+ // mangle the rest of the arguments as types
+ for (size_t j = i; j < ti->tiargs->dim; j++)
+ {
+ Type *t = isType((*ti->tiargs)[j]);
+ assert(t);
+ t->accept(this);
+ }
+
+ buf->writeByte('E');
+ break;
+ }
+ if (tp->isTemplateTypeParameter())
+ {
+ Type *t = isType(o);
+ assert(t);
+ t->accept(this);
+ }
+ else if (TemplateValueParameter *tv = tp->isTemplateValueParameter())
+ {
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ if (tv->valType->isintegral())
+ {
+ Expression *e = isExpression(o);
+ assert(e);
+ buf->writeByte('L');
+ tv->valType->accept(this);
+ uinteger_t val = e->toUInteger();
+ if (!tv->valType->isunsigned() && (sinteger_t)val < 0)
+ {
+ val = -val;
+ buf->writeByte('n');
+ }
+ buf->printf("%llu", val);
+ buf->writeByte('E');
+ }
+ else
+ {
+ ti->error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv->valType->toChars());
+ fatal();
+ }
+ }
+ else if (tp->isTemplateAliasParameter())
+ {
+ Dsymbol *d = isDsymbol(o);
+ Expression *e = isExpression(o);
+ if (d && d->isFuncDeclaration())
+ {
+ bool is_nested = d->toParent() &&
+ !d->toParent()->isModule() &&
+ ((TypeFunction*)d->isFuncDeclaration()->type)->linkage == LINKcpp;
+ if (is_nested)
+ buf->writeByte('X');
+ buf->writeByte('L');
+ mangle_function(d->isFuncDeclaration());
+ buf->writeByte('E');
+ if (is_nested)
+ buf->writeByte('E');
+ }
+ else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration())
+ {
+ VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration();
+ buf->writeByte('L');
+ mangle_variable(vd, true);
+ buf->writeByte('E');
+ }
+ else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember)
+ {
+ if (!substitute(d))
+ {
+ cpp_mangle_name(d, false);
+ }
+ }
+ else
+ {
+ ti->error("Internal Compiler Error: `%s` is unsupported parameter for C++ template", o->toChars());
+ fatal();
+ }
+ }
+ else if(tp->isTemplateThisParameter())
+ {
+ ti->error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o->toChars());
+ fatal();
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+ buf->writeByte('E');
+ }
+
+ void source_name(Dsymbol *s)
+ {
+ //printf("source_name(%s)\n", s->toChars());
+ if (TemplateInstance *ti = s->isTemplateInstance())
+ {
+ if (!substitute(ti->tempdecl))
+ {
+ append(ti->tempdecl);
+ const char *name = ti->tempdecl->toAlias()->ident->toChars();
+ buf->printf("%d", strlen(name));
+ buf->writestring(name);
+ }
+ template_args(ti);
+ }
+ else
+ {
+ const char *name = s->ident->toChars();
+ buf->printf("%d", strlen(name));
+ buf->writestring(name);
+ }
+ }
+
+ /********
+ * See if s is actually an instance of a template
+ * Params:
+ * s = symbol
+ * Returns:
+ * if s is instance of a template, return the instance, otherwise return s
+ */
+ Dsymbol *getInstance(Dsymbol *s)
+ {
+ Dsymbol *p = s->toParent();
+ if (p)
+ {
+ if (TemplateInstance *ti = p->isTemplateInstance())
+ return ti;
+ }
+ return s;
+ }
+
+ /********
+ * Get qualifier for `s`, meaning the symbol
+ * that s is in the symbol table of.
+ * The module does not count as a qualifier, because C++
+ * does not have modules.
+ * Params:
+ * s = symbol that may have a qualifier
+ * Returns:
+ * qualifier, NULL if none
+ */
+ static Dsymbol *getQualifier(Dsymbol *s)
+ {
+ Dsymbol *p = s->toParent();
+ return (p && !p->isModule()) ? p : NULL;
+ }
+
+ // Detect type char
+ static bool isChar(RootObject *o)
+ {
+ Type *t = isType(o);
+ return (t && t->equals(Type::tchar));
+ }
+
+ // Detect type ::std::char_traits<char>
+ static bool isChar_traits_char(RootObject *o)
+ {
+ return isIdent_char(Id::char_traits, o);
+ }
+
+ // Detect type ::std::allocator<char>
+ static bool isAllocator_char(RootObject *o)
+ {
+ return isIdent_char(Id::allocator, o);
+ }
+
+ // Detect type ::std::ident<char>
+ static bool isIdent_char(Identifier *ident, RootObject *o)
+ {
+ Type *t = isType(o);
+ if (!t || t->ty != Tstruct)
+ return false;
+ Dsymbol *s = ((TypeStruct*)t)->toDsymbol(NULL);
+ if (s->ident != ident)
+ return false;
+ Dsymbol *p = s->toParent();
+ if (!p)
+ return false;
+ TemplateInstance *ti = p->isTemplateInstance();
+ if (!ti)
+ return false;
+ Dsymbol *q = getQualifier(ti);
+ return isStd(q) && ti->tiargs->dim == 1 && isChar((*ti->tiargs)[0]);
+ }
+
+ /***
+ * Detect template args <char, ::std::char_traits<char>>
+ * and write st if found.
+ * Returns:
+ * true if found
+ */
+ bool char_std_char_traits_char(TemplateInstance *ti, const char *st)
+ {
+ if (ti->tiargs->dim == 2 &&
+ isChar((*ti->tiargs)[0]) &&
+ isChar_traits_char((*ti->tiargs)[1]))
+ {
+ buf->writestring(st);
+ return true;
+ }
+ return false;
+ }
+
+
+ void prefix_name(Dsymbol *s)
+ {
+ //printf("prefix_name(%s)\n", s->toChars());
+ if (!substitute(s))
+ {
+ Dsymbol *si = getInstance(s);
+ Dsymbol *p = getQualifier(si);
+ if (p)
+ {
+ if (isStd(p))
+ {
+ TemplateInstance *ti = si->isTemplateInstance();
+ if (ti)
+ {
+ if (s->ident == Id::allocator)
+ {
+ buf->writestring("Sa");
+ template_args(ti);
+ append(ti);
+ return;
+ }
+ if (s->ident == Id::basic_string)
+ {
+ // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
+ if (ti->tiargs->dim == 3 &&
+ isChar((*ti->tiargs)[0]) &&
+ isChar_traits_char((*ti->tiargs)[1]) &&
+ isAllocator_char((*ti->tiargs)[2]))
+
+ {
+ buf->writestring("Ss");
+ return;
+ }
+ buf->writestring("Sb"); // ::std::basic_string
+ template_args(ti);
+ append(ti);
+ return;
+ }
+
+ // ::std::basic_istream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_istream &&
+ char_std_char_traits_char(ti, "Si"))
+ return;
+
+ // ::std::basic_ostream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_ostream &&
+ char_std_char_traits_char(ti, "So"))
+ return;
+
+ // ::std::basic_iostream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_iostream &&
+ char_std_char_traits_char(ti, "Sd"))
+ return;
+ }
+ buf->writestring("St");
+ }
+ else
+ prefix_name(p);
+ }
+ source_name(si);
+ if (!isStd(si))
+ {
+ /* Do this after the source_name() call to keep components[]
+ * in the right order.
+ * https://issues.dlang.org/show_bug.cgi?id=17947
+ */
+ append(si);
+ }
+ }
+ }
+
+ void cpp_mangle_name(Dsymbol *s, bool qualified)
+ {
+ //printf("cpp_mangle_name(%s, %d)\n", s->toChars(), qualified);
+ Dsymbol *p = s->toParent();
+ Dsymbol *se = s;
+ bool write_prefix = true;
+ if (p && p->isTemplateInstance())
+ {
+ se = p;
+ if (find(p->isTemplateInstance()->tempdecl) >= 0)
+ write_prefix = false;
+ p = p->toParent();
+ }
+
+ if (p && !p->isModule())
+ {
+ /* The N..E is not required if:
+ * 1. the parent is 'std'
+ * 2. 'std' is the initial qualifier
+ * 3. there is no CV-qualifier or a ref-qualifier for a member function
+ * ABI 5.1.8
+ */
+ if (isStd(p) && !qualified)
+ {
+ TemplateInstance *ti = se->isTemplateInstance();
+ if (s->ident == Id::allocator)
+ {
+ buf->writestring("Sa"); // "Sa" is short for ::std::allocator
+ template_args(ti);
+ }
+ else if (s->ident == Id::basic_string)
+ {
+ // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
+ if (ti->tiargs->dim == 3 &&
+ isChar((*ti->tiargs)[0]) &&
+ isChar_traits_char((*ti->tiargs)[1]) &&
+ isAllocator_char((*ti->tiargs)[2]))
+
+ {
+ buf->writestring("Ss");
+ return;
+ }
+ buf->writestring("Sb"); // ::std::basic_string
+ template_args(ti);
+ }
+ else
+ {
+ // ::std::basic_istream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_istream)
+ {
+ if (char_std_char_traits_char(ti, "Si"))
+ return;
+ }
+ else if (s->ident == Id::basic_ostream)
+ {
+ if (char_std_char_traits_char(ti, "So"))
+ return;
+ }
+ else if (s->ident == Id::basic_iostream)
+ {
+ if (char_std_char_traits_char(ti, "Sd"))
+ return;
+ }
+ buf->writestring("St");
+ source_name(se);
+ }
+ }
+ else
+ {
+ buf->writeByte('N');
+ if (write_prefix)
+ prefix_name(p);
+ source_name(se);
+ buf->writeByte('E');
+ }
+ }
+ else
+ source_name(se);
+ append(s);
+ }
+
+ void CV_qualifiers(Type *t)
+ {
+ // CV-qualifiers are 'r': restrict, 'V': volatile, 'K': const
+ if (t->isConst())
+ buf->writeByte('K');
+ }
+
+ void mangle_variable(VarDeclaration *d, bool is_temp_arg_ref)
+ {
+ // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525
+ if (!(d->storage_class & (STCextern | STCfield | STCgshared)))
+ {
+ d->error("Internal Compiler Error: C++ static non-`__gshared` non-`extern` variables not supported");
+ fatal();
+ }
+
+ Dsymbol *p = d->toParent();
+ if (p && !p->isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE"
+ {
+ buf->writestring("_ZN");
+ prefix_name(p);
+ source_name(d);
+ buf->writeByte('E');
+ }
+ else //char beta[6] should mangle as "beta"
+ {
+ if (!is_temp_arg_ref)
+ {
+ buf->writestring(d->ident->toChars());
+ }
+ else
+ {
+ buf->writestring("_Z");
+ source_name(d);
+ }
+ }
+ }
+
+ void mangle_function(FuncDeclaration *d)
+ {
+ //printf("mangle_function(%s)\n", d->toChars());
+ /*
+ * <mangled-name> ::= _Z <encoding>
+ * <encoding> ::= <function name> <bare-function-type>
+ * ::= <data name>
+ * ::= <special-name>
+ */
+ TypeFunction *tf = (TypeFunction *)d->type;
+
+ buf->writestring("_Z");
+ if (getFuncTemplateDecl(d))
+ {
+ /* It's an instance of a function template
+ */
+ TemplateInstance *ti = d->parent->isTemplateInstance();
+ assert(ti);
+ Dsymbol *p = ti->toParent();
+ if (p && !p->isModule() && tf->linkage == LINKcpp)
+ {
+ buf->writeByte('N');
+ CV_qualifiers(d->type);
+ prefix_name(p);
+ if (d->isCtorDeclaration())
+ buf->writestring("C1");
+ else if (d->isDtorDeclaration())
+ buf->writestring("D1");
+ else
+ source_name(ti);
+ buf->writeByte('E');
+ }
+ else
+ source_name(ti);
+ headOfType(tf->nextOf()); // mangle return type
+ }
+ else
+ {
+ Dsymbol *p = d->toParent();
+ if (p && !p->isModule() && tf->linkage == LINKcpp)
+ {
+ /* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+ * ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+ */
+ buf->writeByte('N');
+ CV_qualifiers(d->type);
+
+ /* <prefix> ::= <prefix> <unqualified-name>
+ * ::= <template-prefix> <template-args>
+ * ::= <template-param>
+ * ::= # empty
+ * ::= <substitution>
+ * ::= <prefix> <data-member-prefix>
+ */
+ prefix_name(p);
+ //printf("p: %s\n", buf.peekString());
+
+ if (d->isCtorDeclaration())
+ {
+ buf->writestring("C1");
+ }
+ else if (d->isDtorDeclaration())
+ {
+ buf->writestring("D1");
+ }
+ else
+ {
+ source_name(d);
+ }
+ buf->writeByte('E');
+ }
+ else
+ {
+ source_name(d);
+ }
+ }
+
+ if (tf->linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling
+ {
+ assert(tf->ty == Tfunction);
+ mangleFunctionParameters(tf->parameters, tf->varargs);
+ }
+ }
+
+ void mangleFunctionParameters(Parameters *parameters, int varargs)
+ {
+ struct ParamsCppMangle
+ {
+ int numparams;
+ CppMangleVisitor *mangler;
+
+ static int dg(void *ctx, size_t, Parameter *fparam)
+ {
+ ParamsCppMangle *p = (ParamsCppMangle *)ctx;
+ CppMangleVisitor *mangler = p->mangler;
+ Type *t = Target::cppParameterType(fparam);
+ if (t->ty == Tsarray)
+ {
+ // Static arrays in D are passed by value; no counterpart in C++
+ t->error(mangler->loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead",
+ t->toChars());
+ fatal();
+ }
+ mangler->headOfType(t);
+ p->numparams++;
+ return 0;
+ }
+ };
+
+ ParamsCppMangle p;
+ p.numparams = 0;
+ p.mangler = this;
+
+ if (parameters)
+ Parameter_foreach(parameters, &ParamsCppMangle::dg, (void*)&p);
+
+ if (varargs)
+ buf->writeByte('z');
+ else if (!p.numparams)
+ buf->writeByte('v'); // encode (void) parameters
+ }
+
+public:
+ CppMangleVisitor(OutBuffer *buf, Loc loc)
+ : components(), buf(buf), loc(loc)
+ {
+ }
+
+ /*****
+ * Entry point. Append mangling to buf[]
+ * Params:
+ * s = symbol to mangle
+ */
+ void mangleOf(Dsymbol *s)
+ {
+ if (VarDeclaration *vd = s->isVarDeclaration())
+ {
+ mangle_variable(vd, false);
+ }
+ else if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ mangle_function(fd);
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ /****** The rest is type mangling ************/
+
+ void error(Type *t)
+ {
+ const char *p;
+ if (t->isImmutable())
+ p = "`immutable` ";
+ else if (t->isShared())
+ p = "`shared` ";
+ else
+ p = "";
+ t->error(loc, "Internal Compiler Error: %stype `%s` can not be mapped to C++", p, t->toChars());
+ fatal(); //Fatal, because this error should be handled in frontend
+ }
+
+ /****************************
+ * Mangle a type,
+ * treating it as a Head followed by a Tail.
+ * Params:
+ * t = Head of a type
+ */
+ void headOfType(Type *t)
+ {
+ if (t->ty == Tclass)
+ {
+ mangleTypeClass((TypeClass*)t, true);
+ }
+ else
+ {
+ // For value types, strip const/immutable/shared from the head of the type
+ t->mutableOf()->unSharedOf()->accept(this);
+ }
+ }
+
+ void visit(Type *t)
+ {
+ error(t);
+ }
+
+ /******
+ * Write out 1 or 2 character basic type mangling.
+ * Handle const and substitutions.
+ * Params:
+ * t = type to mangle
+ * p = if not 0, then character prefix
+ * c = mangling character
+ */
+ void writeBasicType(Type *t, char p, char c)
+ {
+ if (p || t->isConst())
+ {
+ if (substitute(t))
+ return;
+ else
+ append(t);
+ }
+ CV_qualifiers(t);
+ if (p)
+ buf->writeByte(p);
+ buf->writeByte(c);
+ }
+
+ void visit(TypeNull *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ writeBasicType(t, 'D', 'n');
+ }
+
+ void visit(TypeBasic *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ /* <builtin-type>:
+ * v void
+ * w wchar_t
+ * b bool
+ * c char
+ * a signed char
+ * h unsigned char
+ * s short
+ * t unsigned short
+ * i int
+ * j unsigned int
+ * l long
+ * m unsigned long
+ * x long long, __int64
+ * y unsigned long long, __int64
+ * n __int128
+ * o unsigned __int128
+ * f float
+ * d double
+ * e long double, __float80
+ * g __float128
+ * z ellipsis
+ * Dd 64 bit IEEE 754r decimal floating point
+ * De 128 bit IEEE 754r decimal floating point
+ * Df 32 bit IEEE 754r decimal floating point
+ * Dh 16 bit IEEE 754r half-precision floating point
+ * Di char32_t
+ * Ds char16_t
+ * u <source-name> # vendor extended type
+ */
+
+ char c;
+ char p = 0;
+ switch (t->ty)
+ {
+ case Tvoid: c = 'v'; break;
+ case Tint8: c = 'a'; break;
+ case Tuns8: c = 'h'; break;
+ case Tint16: c = 's'; break;
+ case Tuns16: c = 't'; break;
+ case Tint32: c = 'i'; break;
+ case Tuns32: c = 'j'; break;
+ case Tfloat32: c = 'f'; break;
+ case Tint64:
+ c = (Target::c_longsize == 8 ? 'l' : 'x');
+ break;
+ case Tuns64:
+ c = (Target::c_longsize == 8 ? 'm' : 'y');
+ break;
+ case Tint128: c = 'n'; break;
+ case Tuns128: c = 'o'; break;
+ case Tfloat64: c = 'd'; break;
+ case Tfloat80: c = 'e'; break;
+ case Tbool: c = 'b'; break;
+ case Tchar: c = 'c'; break;
+ case Twchar: c = 't'; break; // unsigned short (perhaps use 'Ds' ?
+ case Tdchar: c = 'w'; break; // wchar_t (UTF-32) (perhaps use 'Di' ?
+ case Timaginary32: p = 'G'; c = 'f'; break; // 'G' means imaginary
+ case Timaginary64: p = 'G'; c = 'd'; break;
+ case Timaginary80: p = 'G'; c = 'e'; break;
+ case Tcomplex32: p = 'C'; c = 'f'; break; // 'C' means complex
+ case Tcomplex64: p = 'C'; c = 'd'; break;
+ case Tcomplex80: p = 'C'; c = 'e'; break;
+
+ default:
+ // Handle any target-specific basic types.
+ if (const char *tm = Target::cppTypeMangle(t))
+ {
+ if (substitute(t))
+ return;
+ else
+ append(t);
+ CV_qualifiers(t);
+ buf->writestring(tm);
+ return;
+ }
+ return error(t);
+ }
+ writeBasicType(t, p, c);
+ }
+
+ void visit(TypeVector *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ if (substitute(t))
+ return;
+ append(t);
+ CV_qualifiers(t);
+
+ // Handle any target-specific vector types.
+ if (const char *tm = Target::cppTypeMangle(t))
+ {
+ buf->writestring(tm);
+ }
+ else
+ {
+ assert(t->basetype && t->basetype->ty == Tsarray);
+ assert(((TypeSArray *)t->basetype)->dim);
+ buf->writestring("U8__vector"); //-- Gnu ABI v.3
+ t->basetype->nextOf()->accept(this);
+ }
+ }
+
+ void visit(TypeSArray *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ if (!substitute(t))
+ append(t);
+ CV_qualifiers(t);
+ buf->writeByte('A');
+ buf->printf("%llu", t->dim ? t->dim->toInteger() : 0);
+ buf->writeByte('_');
+ t->next->accept(this);
+ }
+
+ void visit(TypePointer *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ if (substitute(t))
+ return;
+ CV_qualifiers(t);
+ buf->writeByte('P');
+ t->next->accept(this);
+ append(t);
+ }
+
+ void visit(TypeReference *t)
+ {
+ //printf("TypeReference %s\n", t->toChars());
+ if (substitute(t))
+ return;
+ buf->writeByte('R');
+ t->next->accept(this);
+ append(t);
+ }
+
+ void visit(TypeFunction *t)
+ {
+ /*
+ * <function-type> ::= F [Y] <bare-function-type> E
+ * <bare-function-type> ::= <signature type>+
+ * # types are possible return type, then parameter types
+ */
+
+ /* ABI says:
+ "The type of a non-static member function is considered to be different,
+ for the purposes of substitution, from the type of a namespace-scope or
+ static member function whose type appears similar. The types of two
+ non-static member functions are considered to be different, for the
+ purposes of substitution, if the functions are members of different
+ classes. In other words, for the purposes of substitution, the class of
+ which the function is a member is considered part of the type of
+ function."
+
+ BUG: Right now, types of functions are never merged, so our simplistic
+ component matcher always finds them to be different.
+ We should use Type::equals on these, and use different
+ TypeFunctions for non-static member functions, and non-static
+ member functions of different classes.
+ */
+ if (substitute(t))
+ return;
+ buf->writeByte('F');
+ if (t->linkage == LINKc)
+ buf->writeByte('Y');
+ Type *tn = t->next;
+ if (t->isref)
+ tn = tn->referenceTo();
+ tn->accept(this);
+ mangleFunctionParameters(t->parameters, t->varargs);
+ buf->writeByte('E');
+ append(t);
+ }
+
+ void visit(TypeStruct *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ /* __c_long and __c_ulong get special mangling
+ */
+ Identifier *id = t->sym->ident;
+ //printf("struct id = '%s'\n", id->toChars());
+ if (id == Id::__c_long)
+ return writeBasicType(t, 0, 'l');
+ else if (id == Id::__c_ulong)
+ return writeBasicType(t, 0, 'm');
+
+ //printf("TypeStruct %s\n", t->toChars());
+ doSymbol(t);
+ }
+
+
+ void visit(TypeEnum *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ /* __c_(u)long(long) get special mangling
+ */
+ Identifier *id = t->sym->ident;
+ //printf("enum id = '%s'\n", id->toChars());
+ if (id == Id::__c_long)
+ return writeBasicType(t, 0, 'l');
+ else if (id == Id::__c_ulong)
+ return writeBasicType(t, 0, 'm');
+ else if (id == Id::__c_longlong)
+ return writeBasicType(t, 0, 'x');
+ else if (id == Id::__c_ulonglong)
+ return writeBasicType(t, 0, 'y');
+
+ doSymbol(t);
+ }
+
+ /****************
+ * Write structs and enums.
+ * Params:
+ * t = TypeStruct or TypeEnum
+ */
+ void doSymbol(Type *t)
+ {
+ if (substitute(t))
+ return;
+ CV_qualifiers(t);
+
+ // Handle any target-specific struct types.
+ if (const char *tm = Target::cppTypeMangle(t))
+ {
+ buf->writestring(tm);
+ }
+ else
+ {
+ Dsymbol *s = t->toDsymbol(NULL);
+ Dsymbol *p = s->toParent();
+ if (p && p->isTemplateInstance())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=17947
+ * Substitute the template instance symbol, not the struct/enum symbol
+ */
+ if (substitute(p))
+ return;
+ }
+ if (!substitute(s))
+ {
+ cpp_mangle_name(s, t->isConst());
+ }
+ }
+ if (t->isConst())
+ append(t);
+ }
+
+ void visit(TypeClass *t)
+ {
+ mangleTypeClass(t, false);
+ }
+
+ /************************
+ * Mangle a class type.
+ * If it's the head, treat the initial pointer as a value type.
+ * Params:
+ * t = class type
+ * head = true for head of a type
+ */
+ void mangleTypeClass(TypeClass *t, bool head)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ /* Mangle as a <pointer to><struct>
+ */
+ if (substitute(t))
+ return;
+ if (!head)
+ CV_qualifiers(t);
+ buf->writeByte('P');
+
+ CV_qualifiers(t);
+
+ {
+ Dsymbol *s = t->toDsymbol(NULL);
+ Dsymbol *p = s->toParent();
+ if (p && p->isTemplateInstance())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=17947
+ * Substitute the template instance symbol, not the class symbol
+ */
+ if (substitute(p))
+ return;
+ }
+ }
+
+ if (!substitute(t->sym))
+ {
+ cpp_mangle_name(t->sym, t->isConst());
+ }
+ if (t->isConst())
+ append(NULL); // C++ would have an extra type here
+ append(t);
+ }
+
+ const char *mangle_typeinfo(Dsymbol *s)
+ {
+ buf->writestring("_ZTI");
+ cpp_mangle_name(s, false);
+ return buf->extractString();
+ }
+};
+
+const char *toCppMangleItanium(Dsymbol *s)
+{
+ //printf("toCppMangleItanium(%s)\n", s->toChars());
+ OutBuffer buf;
+ CppMangleVisitor v(&buf, s->loc);
+ v.mangleOf(s);
+ return buf.extractString();
+}
+
+const char *cppTypeInfoMangleItanium(Dsymbol *s)
+{
+ //printf("cppTypeInfoMangleItanium(%s)\n", s->toChars());
+ OutBuffer buf;
+ buf.writestring("_ZTI"); // "TI" means typeinfo structure
+ CppMangleVisitor v(&buf, s->loc);
+ v.cpp_mangle_name(s, false);
+ return buf.extractString();
+}
diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h
new file mode 100644
index 0000000..f7f7c85
--- /dev/null
+++ b/gcc/d/dmd/ctfe.h
@@ -0,0 +1,267 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/ctfe.h
+ */
+
+#pragma once
+
+#include "arraytypes.h"
+#include "tokens.h"
+#include "expression.h"
+
+/**
+ Global status of the CTFE engine. Mostly used for performance diagnostics
+ */
+struct CtfeStatus
+{
+ static int callDepth; // current number of recursive calls
+ /* When printing a stack trace,
+ * suppress this number of calls
+ */
+ static int stackTraceCallsToSuppress;
+ static int maxCallDepth; // highest number of recursive calls
+ static int numArrayAllocs; // Number of allocated arrays
+ static int numAssignments; // total number of assignments executed
+};
+
+/**
+ A reference to a class, or an interface. We need this when we
+ point to a base class (we must record what the type is).
+ */
+class ClassReferenceExp : public Expression
+{
+public:
+ StructLiteralExp *value;
+ ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type);
+ ClassDeclaration *originalClass();
+
+ /// Return index of the field, or -1 if not found
+ int getFieldIndex(Type *fieldtype, unsigned fieldoffset);
+ /// Return index of the field, or -1 if not found
+ /// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+ int findFieldIndexByName(VarDeclaration *v);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// The various functions are used only to detect compiler CTFE bugs
+Expression *getValue(VarDeclaration *vd);
+bool hasValue(VarDeclaration *vd);
+void setValueNull(VarDeclaration *vd);
+void setValueWithoutChecking(VarDeclaration *vd, Expression *newval);
+void setValue(VarDeclaration *vd, Expression *newval);
+
+/// Return index of the field, or -1 if not found
+/// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v);
+
+
+/** An uninitialized value
+ */
+class VoidInitExp : public Expression
+{
+public:
+ VarDeclaration *var;
+
+ VoidInitExp(VarDeclaration *var, Type *type);
+ const char *toChars();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Create an appropriate void initializer
+UnionExp voidInitLiteral(Type *t, VarDeclaration *var);
+
+/** Fake class which holds the thrown exception.
+ Used for implementing exception handling.
+*/
+class ThrownExceptionExp : public Expression
+{
+public:
+ ClassReferenceExp *thrown; // the thing being tossed
+ ThrownExceptionExp(Loc loc, ClassReferenceExp *victim);
+ const char *toChars();
+ /// Generate an error message when this exception is not caught
+ void generateUncaughtError();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+// This type is only used by the interpreter.
+
+class CTFEExp : public Expression
+{
+public:
+ CTFEExp(TOK tok);
+
+ const char *toChars();
+
+ // Handy instances to share
+ static CTFEExp *cantexp;
+ static CTFEExp *voidexp;
+ static CTFEExp *breakexp;
+ static CTFEExp *continueexp;
+ static CTFEExp *gotoexp;
+
+ static bool isCantExp(Expression *e) { return e && e->op == TOKcantexp; }
+ static bool isGotoExp(Expression *e) { return e && e->op == TOKgoto; }
+};
+
+/****************************************************************/
+
+
+/// True if 'e' is TOKcantexp, or an exception
+bool exceptionOrCantInterpret(Expression *e);
+
+// Used for debugging only
+void showCtfeExpr(Expression *e, int level = 0);
+
+/// Return true if this is a valid CTFE expression
+bool isCtfeValueValid(Expression *newval);
+bool isCtfeReferenceValid(Expression *newval);
+
+/// Given expr, which evaluates to an array/AA/string literal,
+/// return true if it needs to be copied
+bool needToCopyLiteral(Expression *expr);
+
+/// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
+/// This value will be used for in-place modification.
+UnionExp copyLiteral(Expression *e);
+
+/// Set this literal to the given type, copying it if necessary
+Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
+UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit);
+
+/// Convert from a CTFE-internal slice, into a normal Expression
+Expression *resolveSlice(Expression *e, UnionExp *pue = NULL);
+
+/// Determine the array length, without interpreting the expression.
+uinteger_t resolveArrayLength(Expression *e);
+
+/// Create an array literal consisting of 'elem' duplicated 'dim' times.
+ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
+ Expression *elem, size_t dim);
+
+/// Create a string literal consisting of 'value' duplicated 'dim' times.
+StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
+ unsigned value, size_t dim, unsigned char sz);
+
+
+/* Set dest = src, where both dest and src are container value literals
+ * (ie, struct literals, or static arrays (can be an array literal or a string)
+ * Assignment is recursively in-place.
+ * Purpose: any reference to a member of 'dest' will remain valid after the
+ * assignment.
+ */
+void assignInPlace(Expression *dest, Expression *src);
+
+/// Duplicate the elements array, then set field 'indexToChange' = newelem.
+Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem);
+
+/// Given an AA literal aae, set arr[index] = newval and return the new array.
+Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
+ Expression *index, Expression *newval);
+
+/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
+/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
+/// all new elements will be set to the default initializer for the element type.
+UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
+ Expression *oldval, size_t oldlen, size_t newlen);
+
+
+
+/// Return true if t is a pointer (not a function pointer)
+bool isPointer(Type *t);
+
+// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer.
+bool isTrueBool(Expression *e);
+
+/// Is it safe to convert from srcPointee* to destPointee* ?
+/// srcPointee is the genuine type (never void).
+/// destPointee may be void.
+bool isSafePointerCast(Type *srcPointee, Type *destPointee);
+
+/// Given pointer e, return the memory block expression it points to,
+/// and set ofs to the offset within that memory block.
+Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs);
+
+/// Return true if agg1 and agg2 are pointers to the same memory block
+bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2);
+
+// return e1 - e2 as an integer, or error if not possible
+UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2);
+
+/// Return 1 if true, 0 if false
+/// -1 if comparison is illegal because they point to non-comparable memory blocks
+int comparePointers(TOK op, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2);
+
+// Return eptr op e2, where eptr is a pointer, e2 is an integer,
+// and op is TOKadd or TOKmin
+UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
+ Expression *eptr, Expression *e2);
+
+// True if conversion from type 'from' to 'to' involves a reinterpret_cast
+// floating point -> integer or integer -> floating point
+bool isFloatIntPaint(Type *to, Type *from);
+
+// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
+Expression *paintFloatInt(Expression *fromVal, Type *to);
+
+/// Return true if t is an AA
+bool isAssocArray(Type *t);
+
+/// Given a template AA type, extract the corresponding built-in AA type
+TypeAArray *toBuiltinAAType(Type *t);
+
+/* Given an AA literal 'ae', and a key 'e2':
+ * Return ae[e2] if present, or NULL if not found.
+ * Return TOKcantexp on error.
+ */
+Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2);
+
+/// True if type is TypeInfo_Class
+bool isTypeInfo_Class(Type *type);
+
+
+/***********************************************
+ COW const-folding operations
+***********************************************/
+
+/// Return true if non-pointer expression e can be compared
+/// with >,is, ==, etc, using ctfeCmp, ctfeEquals, ctfeIdentity
+bool isCtfeComparable(Expression *e);
+
+/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
+int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2);
+
+/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
+int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2);
+
+/// Returns rawCmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int specificCmp(TOK op, int rawCmp);
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2);
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2);
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int realCmp(TOK op, real_t r1, real_t r2);
+
+/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
+int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2);
+
+/// Returns e1 ~ e2. Resolves slices before concatenation.
+UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2);
+
+/// Same as for constfold.Index, except that it only works for static arrays,
+/// dynamic arrays, and strings.
+Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx);
+
+/// Cast 'e' of type 'type' to type 'to'.
+Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e);
diff --git a/gcc/d/dmd/ctfeexpr.c b/gcc/d/dmd/ctfeexpr.c
new file mode 100644
index 0000000..ad5b827
--- /dev/null
+++ b/gcc/d/dmd/ctfeexpr.c
@@ -0,0 +1,2108 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/ctfeexpr.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h> // mem{cpy|set}()
+#include <new>
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "expression.h"
+#include "declaration.h"
+#include "aggregate.h"
+// for AssocArray
+#include "id.h"
+#include "utf.h"
+#include "template.h"
+#include "ctfe.h"
+
+int RealEquals(real_t x1, real_t x2);
+
+/************** ClassReferenceExp ********************************************/
+
+ClassReferenceExp::ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type)
+ : Expression(loc, TOKclassreference, sizeof(ClassReferenceExp))
+{
+ assert(lit && lit->sd && lit->sd->isClassDeclaration());
+ this->value = lit;
+ this->type = type;
+}
+
+ClassDeclaration *ClassReferenceExp::originalClass()
+{
+ return value->sd->isClassDeclaration();
+}
+
+// Return index of the field, or -1 if not found
+int ClassReferenceExp::getFieldIndex(Type *fieldtype, unsigned fieldoffset)
+{
+ ClassDeclaration *cd = originalClass();
+ unsigned fieldsSoFar = 0;
+ for (size_t j = 0; j < value->elements->dim; j++)
+ {
+ while (j - fieldsSoFar >= cd->fields.dim)
+ {
+ fieldsSoFar += cd->fields.dim;
+ cd = cd->baseClass;
+ }
+ VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
+ if (fieldoffset == v2->offset &&
+ fieldtype->size() == v2->type->size())
+ {
+ return (int)(value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar));
+ }
+ }
+ return -1;
+}
+
+// Return index of the field, or -1 if not found
+// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+int ClassReferenceExp::findFieldIndexByName(VarDeclaration *v)
+{
+ ClassDeclaration *cd = originalClass();
+ size_t fieldsSoFar = 0;
+ for (size_t j = 0; j < value->elements->dim; j++)
+ {
+ while (j - fieldsSoFar >= cd->fields.dim)
+ {
+ fieldsSoFar += cd->fields.dim;
+ cd = cd->baseClass;
+ }
+ VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
+ if (v == v2)
+ {
+ return (int)(value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar));
+ }
+ }
+ return -1;
+}
+
+/************** VoidInitExp ********************************************/
+
+VoidInitExp::VoidInitExp(VarDeclaration *var, Type *)
+ : Expression(var->loc, TOKvoid, sizeof(VoidInitExp))
+{
+ this->var = var;
+ this->type = var->type;
+}
+
+const char *VoidInitExp::toChars()
+{
+ return "void";
+}
+
+// Return index of the field, or -1 if not found
+// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v)
+{
+ for (size_t i = 0; i < sd->fields.dim; ++i)
+ {
+ if (sd->fields[i] == v)
+ return (int)i;
+ }
+ return -1;
+}
+
+/************** ThrownExceptionExp ********************************************/
+
+ThrownExceptionExp::ThrownExceptionExp(Loc loc, ClassReferenceExp *victim) : Expression(loc, TOKthrownexception, sizeof(ThrownExceptionExp))
+{
+ this->thrown = victim;
+ this->type = victim->type;
+}
+
+const char *ThrownExceptionExp::toChars()
+{
+ return "CTFE ThrownException";
+}
+
+// Generate an error message when this exception is not caught
+void ThrownExceptionExp::generateUncaughtError()
+{
+ UnionExp ue;
+ Expression *e = resolveSlice((*thrown->value->elements)[0], &ue);
+ StringExp *se = e->toStringExp();
+ thrown->error("uncaught CTFE exception %s(%s)", thrown->type->toChars(), se ? se->toChars() : e->toChars());
+
+ /* Also give the line where the throw statement was. We won't have it
+ * in the case where the ThrowStatement is generated internally
+ * (eg, in ScopeStatement)
+ */
+ if (loc.filename && !loc.equals(thrown->loc))
+ errorSupplemental(loc, "thrown from here");
+}
+
+// True if 'e' is CTFEExp::cantexp, or an exception
+bool exceptionOrCantInterpret(Expression *e)
+{
+ return e && (e->op == TOKcantexp || e->op == TOKthrownexception);
+}
+
+/********************** CTFEExp ******************************************/
+
+CTFEExp *CTFEExp::cantexp;
+CTFEExp *CTFEExp::voidexp;
+CTFEExp *CTFEExp::breakexp;
+CTFEExp *CTFEExp::continueexp;
+CTFEExp *CTFEExp::gotoexp;
+
+CTFEExp::CTFEExp(TOK tok)
+ : Expression(Loc(), tok, sizeof(CTFEExp))
+{
+ type = Type::tvoid;
+}
+
+const char *CTFEExp::toChars()
+{
+ switch (op)
+ {
+ case TOKcantexp: return "<cant>";
+ case TOKvoidexp: return "<void>";
+ case TOKbreak: return "<break>";
+ case TOKcontinue: return "<continue>";
+ case TOKgoto: return "<goto>";
+ default: assert(0); return NULL;
+ }
+}
+
+Expression *UnionExp::copy()
+{
+ Expression *e = exp();
+ //if (e->size > sizeof(u)) printf("%s\n", Token::toChars(e->op));
+ assert(e->size <= sizeof(u));
+ if (e->op == TOKcantexp) return CTFEExp::cantexp;
+ if (e->op == TOKvoidexp) return CTFEExp::voidexp;
+ if (e->op == TOKbreak) return CTFEExp::breakexp;
+ if (e->op == TOKcontinue) return CTFEExp::continueexp;
+ if (e->op == TOKgoto) return CTFEExp::gotoexp;
+ return e->copy();
+}
+
+/************** Aggregate literals (AA/string/array/struct) ******************/
+
+// Given expr, which evaluates to an array/AA/string literal,
+// return true if it needs to be copied
+bool needToCopyLiteral(Expression *expr)
+{
+ for (;;)
+ {
+ switch (expr->op)
+ {
+ case TOKarrayliteral:
+ return ((ArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
+ case TOKassocarrayliteral:
+ return ((AssocArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
+ case TOKstructliteral:
+ return ((StructLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
+ case TOKstring:
+ case TOKthis:
+ case TOKvar:
+ return false;
+ case TOKassign:
+ return false;
+ case TOKindex:
+ case TOKdotvar:
+ case TOKslice:
+ case TOKcast:
+ expr = ((UnaExp *)expr)->e1;
+ continue;
+ case TOKcat:
+ return needToCopyLiteral(((BinExp *)expr)->e1) ||
+ needToCopyLiteral(((BinExp *)expr)->e2);
+ case TOKcatass:
+ expr = ((BinExp *)expr)->e2;
+ continue;
+ default:
+ return false;
+ }
+ }
+}
+
+Expressions *copyLiteralArray(Expressions *oldelems, Expression *basis = NULL)
+{
+ if (!oldelems)
+ return oldelems;
+ CtfeStatus::numArrayAllocs++;
+ Expressions *newelems = new Expressions();
+ newelems->setDim(oldelems->dim);
+ for (size_t i = 0; i < oldelems->dim; i++)
+ {
+ Expression *el = (*oldelems)[i];
+ if (!el)
+ el = basis;
+ (*newelems)[i] = copyLiteral(el).copy();
+ }
+ return newelems;
+}
+
+// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
+// This value will be used for in-place modification.
+UnionExp copyLiteral(Expression *e)
+{
+ UnionExp ue;
+ if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp!
+ {
+ StringExp *se = (StringExp *)e;
+ utf8_t *s = (utf8_t *)mem.xcalloc(se->len + 1, se->sz);
+ memcpy(s, se->string, se->len * se->sz);
+ new(&ue) StringExp(se->loc, s, se->len);
+ StringExp *se2 = (StringExp *)ue.exp();
+ se2->committed = se->committed;
+ se2->postfix = se->postfix;
+ se2->type = se->type;
+ se2->sz = se->sz;
+ se2->ownedByCtfe = OWNEDctfe;
+ return ue;
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+ Expressions *elements = copyLiteralArray(ale->elements, ale->basis);
+
+ new(&ue) ArrayLiteralExp(e->loc, elements);
+
+ ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
+ r->type = e->type;
+ r->ownedByCtfe = OWNEDctfe;
+ return ue;
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+ new(&ue) AssocArrayLiteralExp(e->loc, copyLiteralArray(aae->keys), copyLiteralArray(aae->values));
+ AssocArrayLiteralExp *r = (AssocArrayLiteralExp *)ue.exp();
+ r->type = e->type;
+ r->ownedByCtfe = OWNEDctfe;
+ return ue;
+ }
+ if (e->op == TOKstructliteral)
+ {
+ /* syntaxCopy doesn't work for struct literals, because of a nasty special
+ * case: block assignment is permitted inside struct literals, eg,
+ * an int[4] array can be initialized with a single int.
+ */
+ StructLiteralExp *sle = (StructLiteralExp *)e;
+ Expressions *oldelems = sle->elements;
+ Expressions * newelems = new Expressions();
+ newelems->setDim(oldelems->dim);
+ for (size_t i = 0; i < newelems->dim; i++)
+ {
+ // We need the struct definition to detect block assignment
+ VarDeclaration *v = sle->sd->fields[i];
+ Expression *m = (*oldelems)[i];
+
+ // If it is a void assignment, use the default initializer
+ if (!m)
+ m = voidInitLiteral(v->type, v).copy();
+
+ if (v->type->ty == Tarray || v->type->ty == Taarray)
+ {
+ // Don't have to copy array references
+ }
+ else
+ {
+ // Buzilla 15681: Copy the source element always.
+ m = copyLiteral(m).copy();
+
+ // Block assignment from inside struct literals
+ if (v->type->ty != m->type->ty && v->type->ty == Tsarray)
+ {
+ TypeSArray *tsa = (TypeSArray *)v->type;
+ size_t len = (size_t)tsa->dim->toInteger();
+ m = createBlockDuplicatedArrayLiteral(e->loc, v->type, m, len);
+ }
+ }
+ (*newelems)[i] = m;
+ }
+ new(&ue) StructLiteralExp(e->loc, sle->sd, newelems, sle->stype);
+ StructLiteralExp *r = (StructLiteralExp *)ue.exp();
+ r->type = e->type;
+ r->ownedByCtfe = OWNEDctfe;
+ r->origin = ((StructLiteralExp *)e)->origin;
+ return ue;
+ }
+ if (e->op == TOKfunction || e->op == TOKdelegate ||
+ e->op == TOKsymoff || e->op == TOKnull ||
+ e->op == TOKvar || e->op == TOKdotvar ||
+ e->op == TOKint64 || e->op == TOKfloat64 ||
+ e->op == TOKchar || e->op == TOKcomplex80 ||
+ e->op == TOKvoid || e->op == TOKvector ||
+ e->op == TOKtypeid)
+ {
+ // Simple value types
+ // Keep e1 for DelegateExp and DotVarExp
+ new(&ue) UnionExp(e);
+ Expression *r = ue.exp();
+ r->type = e->type;
+ return ue;
+ }
+ if (e->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *)e;
+ if (se->type->toBasetype()->ty == Tsarray)
+ {
+ // same with resolveSlice()
+ if (se->e1->op == TOKnull)
+ {
+ new(&ue) NullExp(se->loc, se->type);
+ return ue;
+ }
+ ue = Slice(se->type, se->e1, se->lwr, se->upr);
+ assert(ue.exp()->op == TOKarrayliteral);
+ ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
+ r->elements = copyLiteralArray(r->elements);
+ r->ownedByCtfe = OWNEDctfe;
+ return ue;
+ }
+ else
+ {
+ // Array slices only do a shallow copy
+ new(&ue) SliceExp(e->loc, se->e1, se->lwr, se->upr);
+ Expression *r = ue.exp();
+ r->type = e->type;
+ return ue;
+ }
+ }
+ if (isPointer(e->type))
+ {
+ // For pointers, we only do a shallow copy.
+ if (e->op == TOKaddress)
+ new(&ue) AddrExp(e->loc, ((AddrExp *)e)->e1);
+ else if (e->op == TOKindex)
+ new(&ue) IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2);
+ else if (e->op == TOKdotvar)
+ {
+ new(&ue) DotVarExp(e->loc, ((DotVarExp *)e)->e1,
+ ((DotVarExp *)e)->var, ((DotVarExp *)e)->hasOverloads);
+ }
+ else
+ assert(0);
+ Expression *r = ue.exp();
+ r->type = e->type;
+ return ue;
+ }
+ if (e->op == TOKclassreference)
+ {
+ new(&ue) ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type);
+ return ue;
+ }
+ if (e->op == TOKerror)
+ {
+ new(&ue) UnionExp(e);
+ return ue;
+ }
+ e->error("CTFE internal error: literal %s", e->toChars());
+ assert(0);
+ return ue;
+}
+
+/* Deal with type painting.
+ * Type painting is a major nuisance: we can't just set
+ * e->type = type, because that would change the original literal.
+ * But, we can't simply copy the literal either, because that would change
+ * the values of any pointers.
+ */
+Expression *paintTypeOntoLiteral(Type *type, Expression *lit)
+{
+ if (lit->type->equals(type))
+ return lit;
+ return paintTypeOntoLiteralCopy(type, lit).copy();
+}
+
+UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit)
+{
+ UnionExp ue;
+
+ if (lit->type->equals(type))
+ {
+ new(&ue) UnionExp(lit);
+ return ue;
+ }
+
+ // If it is a cast to inout, retain the original type of the referenced part.
+ if (type->hasWild() && type->hasPointers())
+ {
+ new(&ue) UnionExp(lit);
+ ue.exp()->type = type;
+ return ue;
+ }
+
+ if (lit->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *)lit;
+ new(&ue) SliceExp(lit->loc, se->e1, se->lwr, se->upr);
+ }
+ else if (lit->op == TOKindex)
+ {
+ IndexExp *ie = (IndexExp *)lit;
+ new(&ue) IndexExp(lit->loc, ie->e1, ie->e2);
+ }
+ else if (lit->op == TOKarrayliteral)
+ {
+ new(&ue) SliceExp(lit->loc, lit,
+ new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
+ }
+ else if (lit->op == TOKstring)
+ {
+ // For strings, we need to introduce another level of indirection
+ new(&ue) SliceExp(lit->loc, lit,
+ new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
+ }
+ else if (lit->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit;
+ // TODO: we should be creating a reference to this AAExp, not
+ // just a ref to the keys and values.
+ OwnedBy wasOwned = aae->ownedByCtfe;
+ new(&ue) AssocArrayLiteralExp(lit->loc, aae->keys, aae->values);
+ aae = (AssocArrayLiteralExp *)ue.exp();
+ aae->ownedByCtfe = wasOwned;
+ }
+ else
+ {
+ // Can't type paint from struct to struct*; this needs another
+ // level of indirection
+ if (lit->op == TOKstructliteral && isPointer(type))
+ lit->error("CTFE internal error: painting %s", type->toChars());
+ ue = copyLiteral(lit);
+ }
+ ue.exp()->type = type;
+ return ue;
+}
+
+/*************************************
+ * If e is a SliceExp, constant fold it.
+ * Params:
+ * e = expression to resolve
+ * pue = if not null, store resulting expression here
+ * Returns:
+ * resulting expression
+ */
+Expression *resolveSlice(Expression *e, UnionExp *pue)
+{
+ if (e->op != TOKslice)
+ return e;
+ SliceExp *se = (SliceExp *)e;
+ if (se->e1->op == TOKnull)
+ return se->e1;
+ if (pue)
+ {
+ *pue = Slice(e->type, se->e1, se->lwr, se->upr);
+ return pue->exp();
+ }
+ else
+ return Slice(e->type, se->e1, se->lwr, se->upr).copy();
+}
+
+/* Determine the array length, without interpreting it.
+ * e must be an array literal, or a slice
+ * It's very wasteful to resolve the slice when we only
+ * need the length.
+ */
+uinteger_t resolveArrayLength(Expression *e)
+{
+ if (e->op == TOKvector)
+ e = ((VectorExp *)e)->e1;
+
+ if (e->op == TOKnull)
+ return 0;
+ if (e->op == TOKslice)
+ {
+ uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger();
+ uinteger_t iup = ((SliceExp *)e)->upr->toInteger();
+ return iup - ilo;
+ }
+ if (e->op == TOKstring)
+ {
+ return ((StringExp *)e)->len;
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+ return ale->elements ? ale->elements->dim : 0;
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e;
+ return ale->keys->dim;
+ }
+ assert(0);
+ return 0;
+}
+
+/******************************
+ * Helper for NewExp
+ * Create an array literal consisting of 'elem' duplicated 'dim' times.
+ * Params:
+ * loc = source location where the interpretation occurs
+ * type = target type of the result
+ * elem = the source of array element, it will be owned by the result
+ * dim = element number of the result
+ * Returns:
+ * Constructed ArrayLiteralExp
+ */
+ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type,
+ Expression *elem, size_t dim)
+{
+ if (type->ty == Tsarray && type->nextOf()->ty == Tsarray && elem->type->ty != Tsarray)
+ {
+ // If it is a multidimensional array literal, do it recursively
+ TypeSArray *tsa = (TypeSArray *)type->nextOf();
+ size_t len = (size_t)tsa->dim->toInteger();
+ elem = createBlockDuplicatedArrayLiteral(loc, type->nextOf(), elem, len);
+ }
+
+ // Buzilla 15681
+ Type *tb = elem->type->toBasetype();
+ const bool mustCopy = tb->ty == Tstruct || tb->ty == Tsarray;
+
+ Expressions *elements = new Expressions();
+ elements->setDim(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ (*elements)[i] = mustCopy ? copyLiteral(elem).copy() : elem;
+ }
+ ArrayLiteralExp *ale = new ArrayLiteralExp(loc, elements);
+ ale->type = type;
+ ale->ownedByCtfe = OWNEDctfe;
+ return ale;
+}
+
+/******************************
+ * Helper for NewExp
+ * Create a string literal consisting of 'value' duplicated 'dim' times.
+ */
+StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
+ unsigned value, size_t dim, unsigned char sz)
+{
+ utf8_t *s = (utf8_t *)mem.xcalloc(dim + 1, sz);
+ for (size_t elemi = 0; elemi < dim; ++elemi)
+ {
+ switch (sz)
+ {
+ case 1: s[elemi] = (utf8_t)value; break;
+ case 2: ((unsigned short *)s)[elemi] = (unsigned short)value; break;
+ case 4: ((unsigned *)s)[elemi] = value; break;
+ default: assert(0);
+ }
+ }
+ StringExp *se = new StringExp(loc, s, dim);
+ se->type = type;
+ se->sz = sz;
+ se->committed = true;
+ se->ownedByCtfe = OWNEDctfe;
+ return se;
+}
+
+// Return true if t is an AA
+bool isAssocArray(Type *t)
+{
+ t = t->toBasetype();
+ if (t->ty == Taarray)
+ return true;
+ return false;
+}
+
+// Given a template AA type, extract the corresponding built-in AA type
+TypeAArray *toBuiltinAAType(Type *t)
+{
+ t = t->toBasetype();
+ if (t->ty == Taarray)
+ return (TypeAArray *)t;
+ assert(0);
+ return NULL;
+}
+
+/************** TypeInfo operations ************************************/
+
+// Return true if type is TypeInfo_Class
+bool isTypeInfo_Class(Type *type)
+{
+ return type->ty == Tclass &&
+ (Type::dtypeinfo == ((TypeClass *)type)->sym ||
+ Type::dtypeinfo->isBaseOf(((TypeClass *)type)->sym, NULL));
+}
+
+/************** Pointer operations ************************************/
+
+// Return true if t is a pointer (not a function pointer)
+bool isPointer(Type *t)
+{
+ Type * tb = t->toBasetype();
+ return tb->ty == Tpointer && tb->nextOf()->ty != Tfunction;
+}
+
+// For CTFE only. Returns true if 'e' is true or a non-null pointer.
+bool isTrueBool(Expression *e)
+{
+ return e->isBool(true) ||
+ ((e->type->ty == Tpointer || e->type->ty == Tclass) && e->op != TOKnull);
+}
+
+/* Is it safe to convert from srcPointee* to destPointee* ?
+ * srcPointee is the genuine type (never void).
+ * destPointee may be void.
+ */
+bool isSafePointerCast(Type *srcPointee, Type *destPointee)
+{
+ // It's safe to cast S** to D** if it's OK to cast S* to D*
+ while (srcPointee->ty == Tpointer && destPointee->ty == Tpointer)
+ {
+ srcPointee = srcPointee->nextOf();
+ destPointee = destPointee->nextOf();
+ }
+
+ // It's OK if both are the same (modulo const)
+ if (srcPointee->constConv(destPointee))
+ return true;
+
+ // It's OK if function pointers differ only in safe/pure/nothrow
+ if (srcPointee->ty == Tfunction && destPointee->ty == Tfunction)
+ return srcPointee->covariant(destPointee) == 1;
+
+ // it's OK to cast to void*
+ if (destPointee->ty == Tvoid)
+ return true;
+
+ // It's OK to cast from V[K] to void*
+ if (srcPointee->ty == Taarray && destPointee == Type::tvoidptr)
+ return true;
+
+ // It's OK if they are the same size (static array of) integers, eg:
+ // int* --> uint*
+ // int[5][] --> uint[5][]
+ if (srcPointee->ty == Tsarray && destPointee->ty == Tsarray)
+ {
+ if (srcPointee->size() != destPointee->size())
+ return false;
+ srcPointee = srcPointee->baseElemOf();
+ destPointee = destPointee->baseElemOf();
+ }
+ return srcPointee->isintegral() &&
+ destPointee->isintegral() &&
+ srcPointee->size() == destPointee->size();
+}
+
+Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs)
+{
+ *ofs = 0;
+ if (e->op == TOKaddress)
+ e = ((AddrExp *)e)->e1;
+ if (e->op == TOKsymoff)
+ *ofs = ((SymOffExp *)e)->offset;
+ if (e->op == TOKdotvar)
+ {
+ Expression *ex = ((DotVarExp *)e)->e1;
+ VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration();
+ assert(v);
+ StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex;
+ // We can't use getField, because it makes a copy
+ unsigned i;
+ if (ex->op == TOKclassreference)
+ i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset);
+ else
+ i = se->getFieldIndex(e->type, v->offset);
+ e = (*se->elements)[i];
+ }
+ if (e->op == TOKindex)
+ {
+ IndexExp *ie = (IndexExp *)e;
+ // Note that each AA element is part of its own memory block
+ if ((ie->e1->type->ty == Tarray ||
+ ie->e1->type->ty == Tsarray ||
+ ie->e1->op == TOKstring ||
+ ie->e1->op == TOKarrayliteral) &&
+ ie->e2->op == TOKint64)
+ {
+ *ofs = ie->e2->toInteger();
+ return ie->e1;
+ }
+ }
+ if (e->op == TOKslice && e->type->toBasetype()->ty == Tsarray)
+ {
+ SliceExp *se = (SliceExp *)e;
+ if ((se->e1->type->ty == Tarray ||
+ se->e1->type->ty == Tsarray ||
+ se->e1->op == TOKstring ||
+ se->e1->op == TOKarrayliteral) &&
+ se->lwr->op == TOKint64)
+ {
+ *ofs = se->lwr->toInteger();
+ return se->e1;
+ }
+ }
+ return e;
+}
+
+/** Return true if agg1 and agg2 are pointers to the same memory block
+*/
+bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2)
+{
+ if (agg1 == agg2)
+ return true;
+
+ // For integers cast to pointers, we regard them as non-comparable
+ // unless they are identical. (This may be overly strict).
+ if (agg1->op == TOKint64 && agg2->op == TOKint64 &&
+ agg1->toInteger() == agg2->toInteger())
+ {
+ return true;
+ }
+
+ // Note that type painting can occur with VarExp, so we
+ // must compare the variables being pointed to.
+ if (agg1->op == TOKvar && agg2->op == TOKvar &&
+ ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)
+ {
+ return true;
+ }
+ if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
+ ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// return e1 - e2 as an integer, or error if not possible
+UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ UnionExp ue;
+ dinteger_t ofs1, ofs2;
+ Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+ if (agg1 == agg2)
+ {
+ Type *pointee = ((TypePointer *)agg1->type)->next;
+ dinteger_t sz = pointee->size();
+ new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
+ }
+ else if (agg1->op == TOKstring && agg2->op == TOKstring)
+ {
+ if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string)
+ {
+ Type *pointee = ((TypePointer *)agg1->type)->next;
+ dinteger_t sz = pointee->size();
+ new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
+ }
+ }
+ else if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
+ ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
+ {
+ new(&ue) IntegerExp(loc, ofs1 - ofs2, type);
+ }
+ else
+ {
+ error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract "
+ "pointers to two different memory blocks",
+ e1->toChars(), e2->toChars());
+ new(&ue) CTFEExp(TOKcantexp);
+ }
+ return ue;
+}
+
+// Return eptr op e2, where eptr is a pointer, e2 is an integer,
+// and op is TOKadd or TOKmin
+UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
+ Expression *eptr, Expression *e2)
+{
+ UnionExp ue;
+
+ if (eptr->type->nextOf()->ty == Tvoid)
+ {
+ error(loc, "cannot perform arithmetic on void* pointers at compile time");
+ Lcant:
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+
+ dinteger_t ofs1;
+ if (eptr->op == TOKaddress)
+ eptr = ((AddrExp *)eptr)->e1;
+ Expression *agg1 = getAggregateFromPointer(eptr, &ofs1);
+ if (agg1->op == TOKsymoff)
+ {
+ if (((SymOffExp *)agg1)->var->type->ty != Tsarray)
+ {
+ error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
+ goto Lcant;
+ }
+ }
+ else if (agg1->op != TOKstring && agg1->op != TOKarrayliteral)
+ {
+ error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
+ goto Lcant;
+ }
+ dinteger_t ofs2 = e2->toInteger();
+
+ Type *pointee = ((TypeNext *)agg1->type->toBasetype())->next;
+ dinteger_t sz = pointee->size();
+
+ sinteger_t indx;
+ dinteger_t len;
+ if (agg1->op == TOKsymoff)
+ {
+ indx = ofs1 / sz;
+ len = ((TypeSArray *)((SymOffExp *)agg1)->var->type)->dim->toInteger();
+ }
+ else
+ {
+ Expression *dollar = ArrayLength(Type::tsize_t, agg1).copy();
+ assert(!CTFEExp::isCantExp(dollar));
+ indx = ofs1;
+ len = dollar->toInteger();
+ }
+ if (op == TOKadd || op == TOKaddass || op == TOKplusplus)
+ indx += ofs2 / sz;
+ else if (op == TOKmin || op == TOKminass || op == TOKminusminus)
+ indx -= ofs2 / sz;
+ else
+ {
+ error(loc, "CTFE internal error: bad pointer operation");
+ goto Lcant;
+ }
+
+ if (indx < 0 || len < (dinteger_t)indx)
+ {
+ error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", (ulonglong)indx, (ulonglong)len);
+ goto Lcant;
+ }
+
+ if (agg1->op == TOKsymoff)
+ {
+ new(&ue) SymOffExp(loc, ((SymOffExp *)agg1)->var, indx * sz);
+ SymOffExp *se = (SymOffExp *)ue.exp();
+ se->type = type;
+ return ue;
+ }
+
+ if (agg1->op != TOKarrayliteral && agg1->op != TOKstring)
+ {
+ error(loc, "CTFE internal error: pointer arithmetic %s", agg1->toChars());
+ goto Lcant;
+ }
+
+ if (eptr->type->toBasetype()->ty == Tsarray)
+ {
+ dinteger_t dim = ((TypeSArray *)eptr->type->toBasetype())->dim->toInteger();
+
+ // Create a CTFE pointer &agg1[indx .. indx+dim]
+ SliceExp *se = new SliceExp(loc, agg1,
+ new IntegerExp(loc, indx, Type::tsize_t),
+ new IntegerExp(loc, indx + dim, Type::tsize_t));
+ se->type = type->toBasetype()->nextOf();
+ new(&ue) AddrExp(loc, se);
+ ue.exp()->type = type;
+ return ue;
+ }
+
+ // Create a CTFE pointer &agg1[indx]
+ IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t);
+ Expression *ie = new IndexExp(loc, agg1, ofs);
+ ie->type = type->toBasetype()->nextOf(); // Bugzilla 13992
+ new(&ue) AddrExp(loc, ie);
+ ue.exp()->type = type;
+ return ue;
+}
+
+// Return 1 if true, 0 if false
+// -1 if comparison is illegal because they point to non-comparable memory blocks
+int comparePointers(TOK op, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2)
+{
+ if (pointToSameMemoryBlock(agg1, agg2))
+ {
+ int n;
+ switch (op)
+ {
+ case TOKlt: n = (ofs1 < ofs2); break;
+ case TOKle: n = (ofs1 <= ofs2); break;
+ case TOKgt: n = (ofs1 > ofs2); break;
+ case TOKge: n = (ofs1 >= ofs2); break;
+ case TOKidentity:
+ case TOKequal: n = (ofs1 == ofs2); break;
+ case TOKnotidentity:
+ case TOKnotequal: n = (ofs1 != ofs2); break;
+ default:
+ assert(0);
+ }
+ return n;
+ }
+ bool null1 = (agg1->op == TOKnull);
+ bool null2 = (agg2->op == TOKnull);
+
+ int cmp;
+ if (null1 || null2)
+ {
+ switch (op)
+ {
+ case TOKlt: cmp = null1 && !null2; break;
+ case TOKgt: cmp = !null1 && null2; break;
+ case TOKle: cmp = null1; break;
+ case TOKge: cmp = null2; break;
+ case TOKidentity:
+ case TOKequal:
+ case TOKnotidentity: // 'cmp' gets inverted below
+ case TOKnotequal:
+ cmp = (null1 == null2);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ else
+ {
+ switch (op)
+ {
+ case TOKidentity:
+ case TOKequal:
+ case TOKnotidentity: // 'cmp' gets inverted below
+ case TOKnotequal:
+ cmp = 0;
+ break;
+ default:
+ return -1; // memory blocks are different
+ }
+ }
+ if (op == TOKnotidentity || op == TOKnotequal)
+ cmp ^= 1;
+ return cmp;
+}
+
+// True if conversion from type 'from' to 'to' involves a reinterpret_cast
+// floating point -> integer or integer -> floating point
+bool isFloatIntPaint(Type *to, Type *from)
+{
+ return from->size() == to->size() &&
+ ((from->isintegral() && to->isfloating()) ||
+ (from->isfloating() && to->isintegral()));
+}
+
+// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
+Expression *paintFloatInt(Expression *fromVal, Type *to)
+{
+ if (exceptionOrCantInterpret(fromVal))
+ return fromVal;
+
+ assert(to->size() == 4 || to->size() == 8);
+ return Compiler::paintAsType(fromVal, to);
+}
+
+/******** Constant folding, with support for CTFE ***************************/
+
+/// Return true if non-pointer expression e can be compared
+/// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
+bool isCtfeComparable(Expression *e)
+{
+ if (e->op == TOKslice)
+ e = ((SliceExp *)e)->e1;
+
+ if (e->isConst() != 1)
+ {
+ if (e->op == TOKnull ||
+ e->op == TOKstring ||
+ e->op == TOKfunction ||
+ e->op == TOKdelegate ||
+ e->op == TOKarrayliteral ||
+ e->op == TOKstructliteral ||
+ e->op == TOKassocarrayliteral ||
+ e->op == TOKclassreference)
+ {
+ return true;
+ }
+ // Bugzilla 14123: TypeInfo object is comparable in CTFE
+ if (e->op == TOKtypeid)
+ return true;
+
+ return false;
+ }
+ return true;
+}
+
+/// Map TOK comparison ops
+template <typename N>
+static bool numCmp(TOK op, N n1, N n2)
+{
+ switch (op)
+ {
+ case TOKlt:
+ return n1 < n2;
+ case TOKle:
+ return n1 <= n2;
+ case TOKgt:
+ return n1 > n2;
+ case TOKge:
+ return n1 >= n2;
+
+ default:
+ assert(0);
+ }
+}
+
+/// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int specificCmp(TOK op, int rawCmp)
+{
+ return numCmp<int>(op, rawCmp, 0);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2)
+{
+ return numCmp<dinteger_t>(op, n1, n2);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
+{
+ return numCmp<sinteger_t>(op, n1, n2);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+int realCmp(TOK op, real_t r1, real_t r2)
+{
+ // Don't rely on compiler, handle NAN arguments separately
+ if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
+ {
+ switch (op)
+ {
+ case TOKlt:
+ case TOKle:
+ case TOKgt:
+ case TOKge:
+ return 0;
+
+ default:
+ assert(0);
+ }
+ }
+ else
+ {
+ return numCmp<real_t>(op, r1, r2);
+ }
+}
+
+int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2);
+
+/* Conceptually the same as memcmp(e1, e2).
+ * e1 and e2 may be strings, arrayliterals, or slices.
+ * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
+ * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
+ */
+int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len)
+{
+ // Resolve slices, if necessary
+ uinteger_t lo1 = 0;
+ uinteger_t lo2 = 0;
+
+ Expression *x = e1;
+ if (x->op == TOKslice)
+ {
+ lo1 = ((SliceExp *)x)->lwr->toInteger();
+ x = ((SliceExp *)x)->e1;
+ }
+ StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : NULL;
+ ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
+
+ x = e2;
+ if (x->op == TOKslice)
+ {
+ lo2 = ((SliceExp *)x)->lwr->toInteger();
+ x = ((SliceExp *)x)->e1;
+ }
+ StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : NULL;
+ ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
+
+ // Now both must be either TOKarrayliteral or TOKstring
+ if (se1 && se2)
+ return sliceCmpStringWithString(se1, se2, (size_t)lo1, (size_t)lo2, (size_t)len);
+ if (se1 && ae2)
+ return sliceCmpStringWithArray(se1, ae2, (size_t)lo1, (size_t)lo2, (size_t)len);
+ if (se2 && ae1)
+ return -sliceCmpStringWithArray(se2, ae1, (size_t)lo2, (size_t)lo1, (size_t)len);
+
+ assert (ae1 && ae2);
+ // Comparing two array literals. This case is potentially recursive.
+ // If they aren't strings, we just need an equality check rather than
+ // a full cmp.
+ bool needCmp = ae1->type->nextOf()->isintegral();
+ for (size_t i = 0; i < (size_t)len; i++)
+ {
+ Expression *ee1 = (*ae1->elements)[(size_t)(lo1 + i)];
+ Expression *ee2 = (*ae2->elements)[(size_t)(lo2 + i)];
+ if (needCmp)
+ {
+ sinteger_t c = ee1->toInteger() - ee2->toInteger();
+ if (c > 0)
+ return 1;
+ if (c < 0)
+ return -1;
+ }
+ else
+ {
+ if (ctfeRawCmp(loc, ee1, ee2))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Given a delegate expression e, return .funcptr.
+ * If e is NullExp, return NULL.
+ */
+FuncDeclaration *funcptrOf(Expression *e)
+{
+ assert(e->type->ty == Tdelegate);
+
+ if (e->op == TOKdelegate)
+ return ((DelegateExp *)e)->func;
+ if (e->op == TOKfunction)
+ return ((FuncExp *)e)->fd;
+ assert(e->op == TOKnull);
+ return NULL;
+}
+
+bool isArray(Expression *e)
+{
+ return e->op == TOKarrayliteral || e->op == TOKstring ||
+ e->op == TOKslice || e->op == TOKnull;
+}
+
+/* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
+ * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
+ */
+int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2)
+{
+ if (e1->op == TOKclassreference || e2->op == TOKclassreference)
+ {
+ if (e1->op == TOKclassreference && e2->op == TOKclassreference &&
+ ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value)
+ return 0;
+ return 1;
+ }
+ if (e1->op == TOKtypeid && e2->op == TOKtypeid)
+ {
+ // printf("e1: %s\n", e1->toChars());
+ // printf("e2: %s\n", e2->toChars());
+ Type *t1 = isType(((TypeidExp *)e1)->obj);
+ Type *t2 = isType(((TypeidExp *)e2)->obj);
+ assert(t1);
+ assert(t2);
+ return t1 != t2;
+ }
+
+ // null == null, regardless of type
+
+ if (e1->op == TOKnull && e2->op == TOKnull)
+ return 0;
+
+ if (e1->type->ty == Tpointer && e2->type->ty == Tpointer)
+ {
+ // Can only be an equality test.
+
+ dinteger_t ofs1, ofs2;
+ Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+ if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar &&
+ ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
+ {
+ if (ofs1 == ofs2)
+ return 0;
+ }
+ return 1;
+ }
+ if (e1->type->ty == Tdelegate && e2->type->ty == Tdelegate)
+ {
+ // If .funcptr isn't the same, they are not equal
+
+ if (funcptrOf(e1) != funcptrOf(e2))
+ return 1;
+
+ // If both are delegate literals, assume they have the
+ // same closure pointer. TODO: We don't support closures yet!
+ if (e1->op == TOKfunction && e2->op == TOKfunction)
+ return 0;
+ assert(e1->op == TOKdelegate && e2->op == TOKdelegate);
+
+ // Same .funcptr. Do they have the same .ptr?
+ Expression * ptr1 = ((DelegateExp *)e1)->e1;
+ Expression * ptr2 = ((DelegateExp *)e2)->e1;
+
+ dinteger_t ofs1, ofs2;
+ Expression *agg1 = getAggregateFromPointer(ptr1, &ofs1);
+ Expression *agg2 = getAggregateFromPointer(ptr2, &ofs2);
+ // If they are TOKvar, it means they are FuncDeclarations
+ if ((agg1 == agg2 && ofs1 == ofs2) ||
+ (agg1->op == TOKvar && agg2->op == TOKvar &&
+ ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
+ {
+ return 0;
+ }
+ return 1;
+ }
+ if (isArray(e1) && isArray(e2))
+ {
+ uinteger_t len1 = resolveArrayLength(e1);
+ uinteger_t len2 = resolveArrayLength(e2);
+ // workaround for dmc optimizer bug calculating wrong len for
+ // uinteger_t len = (len1 < len2 ? len1 : len2);
+ // if (len == 0) ...
+ if (len1 > 0 && len2 > 0)
+ {
+ uinteger_t len = (len1 < len2 ? len1 : len2);
+ int res = ctfeCmpArrays(loc, e1, e2, len);
+ if (res != 0)
+ return res;
+ }
+ return (int)(len1 - len2);
+ }
+ if (e1->type->isintegral())
+ {
+ return e1->toInteger() != e2->toInteger();
+ }
+ 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 (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
+ {
+ return 1;
+ }
+ else
+ {
+ return (r1 != r2);
+ }
+ }
+ else if (e1->type->iscomplex())
+ {
+ return e1->toComplex() != e2->toComplex();
+ }
+
+ if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
+ {
+ StructLiteralExp *es1 = (StructLiteralExp *)e1;
+ StructLiteralExp *es2 = (StructLiteralExp *)e2;
+ // For structs, we only need to return 0 or 1 (< and > aren't legal).
+
+ if (es1->sd != es2->sd)
+ return 1;
+ else if ((!es1->elements || !es1->elements->dim) &&
+ (!es2->elements || !es2->elements->dim))
+ return 0; // both arrays are empty
+ else if (!es1->elements || !es2->elements)
+ return 1;
+ else if (es1->elements->dim != es2->elements->dim)
+ return 1;
+ else
+ {
+ for (size_t i = 0; i < es1->elements->dim; i++)
+ {
+ Expression *ee1 = (*es1->elements)[i];
+ Expression *ee2 = (*es2->elements)[i];
+
+ if (ee1 == ee2)
+ continue;
+ if (!ee1 || !ee2)
+ return 1;
+ int cmp = ctfeRawCmp(loc, ee1, ee2);
+ if (cmp)
+ return 1;
+ }
+ return 0; // All elements are equal
+ }
+ }
+ if (e1->op == TOKassocarrayliteral && e2->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *es1 = (AssocArrayLiteralExp *)e1;
+ AssocArrayLiteralExp *es2 = (AssocArrayLiteralExp *)e2;
+
+ size_t dim = es1->keys->dim;
+ if (es2->keys->dim != dim)
+ return 1;
+
+ bool *used = (bool *)mem.xmalloc(sizeof(bool) * dim);
+ memset(used, 0, sizeof(bool) * dim);
+
+ for (size_t i = 0; i < dim; ++i)
+ {
+ Expression *k1 = (*es1->keys)[i];
+ Expression *v1 = (*es1->values)[i];
+ Expression *v2 = NULL;
+ for (size_t j = 0; j < dim; ++j)
+ {
+ if (used[j])
+ continue;
+ Expression *k2 = (*es2->keys)[j];
+
+ if (ctfeRawCmp(loc, k1, k2))
+ continue;
+ used[j] = true;
+ v2 = (*es2->values)[j];
+ break;
+ }
+ if (!v2 || ctfeRawCmp(loc, v1, v2))
+ {
+ mem.xfree(used);
+ return 1;
+ }
+ }
+ mem.xfree(used);
+ return 0;
+ }
+ error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1->toChars(), e2->toChars());
+ assert(0);
+ return 0;
+}
+
+/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
+int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2)
+{
+ int cmp = !ctfeRawCmp(loc, e1, e2);
+ if (op == TOKnotequal)
+ cmp ^= 1;
+ return cmp;
+}
+
+/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
+int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2)
+{
+ //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
+ // Token::toChars(e1->op), e1->toChars(), Token::toChars(e2->op), e1->toChars());
+ int cmp;
+ if (e1->op == TOKnull)
+ {
+ cmp = (e2->op == TOKnull);
+ }
+ else if (e2->op == TOKnull)
+ {
+ cmp = 0;
+ }
+ else 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->type->isreal())
+ cmp = RealEquals(e1->toReal(), e2->toReal());
+ else if (e1->type->isimaginary())
+ cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
+ else if (e1->type->iscomplex())
+ {
+ complex_t v1 = e1->toComplex();
+ complex_t v2 = e2->toComplex();
+ cmp = RealEquals(creall(v1), creall(v2)) &&
+ RealEquals(cimagl(v1), cimagl(v1));
+ }
+ else
+ cmp = !ctfeRawCmp(loc, e1, e2);
+
+ if (op == TOKnotidentity || op == TOKnotequal)
+ cmp ^= 1;
+ return cmp;
+}
+
+/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
+int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2)
+{
+ Type *t1 = e1->type->toBasetype();
+ Type *t2 = e2->type->toBasetype();
+
+ if (t1->isString() && t2->isString())
+ return specificCmp(op, ctfeRawCmp(loc, e1, e2));
+ else if (t1->isreal())
+ return realCmp(op, e1->toReal(), e2->toReal());
+ else if (t1->isimaginary())
+ return realCmp(op, e1->toImaginary(), e2->toImaginary());
+ else if (t1->isunsigned() || t2->isunsigned())
+ return intUnsignedCmp(op, e1->toInteger(), e2->toInteger());
+ else
+ return intSignedCmp(op, e1->toInteger(), e2->toInteger());
+}
+
+UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2)
+{
+ Type *t1 = e1->type->toBasetype();
+ Type *t2 = e2->type->toBasetype();
+ UnionExp ue;
+ if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
+ t1->nextOf()->isintegral())
+ {
+ // [chars] ~ string => string (only valid for CTFE)
+ StringExp *es1 = (StringExp *)e2;
+ ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
+ size_t len = es1->len + es2->elements->dim;
+ unsigned char sz = es1->sz;
+
+ void *s = mem.xmalloc((len + 1) * sz);
+ memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz);
+ for (size_t i = 0; i < es2->elements->dim; i++)
+ {
+ Expression *es2e = (*es2->elements)[i];
+ if (es2e->op != TOKint64)
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ dinteger_t v = es2e->toInteger();
+ Port::valcpy((utf8_t *)s + i * sz, v, sz);
+ }
+
+ // Add terminating 0
+ memset((utf8_t *)s + len * sz, 0, sz);
+
+ new(&ue) StringExp(loc, s, len);
+ StringExp *es = (StringExp *)ue.exp();
+ es->sz = sz;
+ es->committed = 0;
+ es->type = type;
+ return ue;
+ }
+ if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
+ t2->nextOf()->isintegral())
+ {
+ // string ~ [chars] => string (only valid for CTFE)
+ // Concatenate the strings
+ StringExp *es1 = (StringExp *)e1;
+ ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+ size_t len = es1->len + es2->elements->dim;
+ unsigned char sz = es1->sz;
+
+ void *s = mem.xmalloc((len + 1) * sz);
+ memcpy(s, es1->string, es1->len * sz);
+ for (size_t i = 0; i < es2->elements->dim; i++)
+ {
+ Expression *es2e = (*es2->elements)[i];
+ if (es2e->op != TOKint64)
+ {
+ new(&ue) CTFEExp(TOKcantexp);
+ return ue;
+ }
+ dinteger_t v = es2e->toInteger();
+ Port::valcpy((utf8_t *)s + (es1->len + i) * sz, v, sz);
+ }
+
+ // Add terminating 0
+ memset((utf8_t *)s + len * sz, 0, sz);
+
+ new(&ue) StringExp(loc, s, len);
+ StringExp *es = (StringExp *)ue.exp();
+ es->sz = sz;
+ es->committed = 0; //es1->committed;
+ es->type = type;
+ return ue;
+ }
+ if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
+ t1->nextOf()->equals(t2->nextOf()))
+ {
+ // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
+ ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
+ ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
+
+ new(&ue) ArrayLiteralExp(es1->loc, copyLiteralArray(es1->elements));
+ es1 = (ArrayLiteralExp *)ue.exp();
+ es1->elements->insert(es1->elements->dim, copyLiteralArray(es2->elements));
+ es1->type = type;
+ return ue;
+ }
+ if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
+ t1->nextOf()->equals(t2->nextOf()))
+ {
+ // [ e1 ] ~ null ----> [ e1 ].dup
+ ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
+ return ue;
+ }
+ if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
+ t1->nextOf()->equals(t2->nextOf()))
+ {
+ // null ~ [ e2 ] ----> [ e2 ].dup
+ ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
+ return ue;
+ }
+ ue = Cat(type, e1, e2);
+ return ue;
+}
+
+/* Given an AA literal 'ae', and a key 'e2':
+ * Return ae[e2] if present, or NULL if not found.
+ */
+Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2)
+{
+ /* Search the keys backwards, in case there are duplicate keys
+ */
+ for (size_t i = ae->keys->dim; i;)
+ {
+ i--;
+ Expression *ekey = (*ae->keys)[i];
+ int eq = ctfeEqual(loc, TOKequal, ekey, e2);
+ if (eq)
+ {
+ return (*ae->values)[i];
+ }
+ }
+ return NULL;
+}
+
+/* Same as for constfold.Index, except that it only works for static arrays,
+ * dynamic arrays, and strings. We know that e1 is an
+ * interpreted CTFE expression, so it cannot have side-effects.
+ */
+Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx)
+{
+ //printf("ctfeIndex(e1 = %s)\n", e1->toChars());
+ assert(e1->type);
+ if (e1->op == TOKstring)
+ {
+ StringExp *es1 = (StringExp *)e1;
+ if (indx >= es1->len)
+ {
+ error(loc, "string index %llu is out of bounds [0 .. %llu]", (ulonglong)indx, (ulonglong)es1->len);
+ return CTFEExp::cantexp;
+ }
+ return new IntegerExp(loc, es1->charAt(indx), type);
+ }
+ assert(e1->op == TOKarrayliteral);
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
+ if (indx >= ale->elements->dim)
+ {
+ error(loc, "array index %llu is out of bounds %s[0 .. %llu]", (ulonglong)indx, e1->toChars(), (ulonglong)ale->elements->dim);
+ return CTFEExp::cantexp;
+ }
+ Expression *e = (*ale->elements)[(size_t)indx];
+ return paintTypeOntoLiteral(type, e);
+ }
+}
+
+Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e)
+{
+ if (e->op == TOKnull)
+ return paintTypeOntoLiteral(to, e);
+ if (e->op == TOKclassreference)
+ {
+ // Disallow reinterpreting class casts. Do this by ensuring that
+ // the original class can implicitly convert to the target class
+ ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass();
+ if (originalClass->type->implicitConvTo(to->mutableOf()))
+ return paintTypeOntoLiteral(to, e);
+ else
+ return new NullExp(loc, to);
+ }
+ // Allow TypeInfo type painting
+ if (isTypeInfo_Class(e->type) && e->type->implicitConvTo(to))
+ return paintTypeOntoLiteral(to, e);
+ // Allow casting away const for struct literals
+ if (e->op == TOKstructliteral &&
+ e->type->toBasetype()->castMod(0) == to->toBasetype()->castMod(0))
+ {
+ return paintTypeOntoLiteral(to, e);
+ }
+
+ Expression *r;
+ if (e->type->equals(type) && type->equals(to))
+ {
+ // necessary not to change e's address for pointer comparisons
+ r = e;
+ }
+ else if (to->toBasetype()->ty == Tarray && type->toBasetype()->ty == Tarray &&
+ to->toBasetype()->nextOf()->size() == type->toBasetype()->nextOf()->size())
+ {
+ // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[]
+ return paintTypeOntoLiteral(to, e);
+ }
+ else
+ {
+ r = Cast(loc, type, to, e).copy();
+ }
+ if (CTFEExp::isCantExp(r))
+ error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars());
+ if (e->op == TOKarrayliteral)
+ ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDctfe;
+ if (e->op == TOKstring)
+ ((StringExp *)e)->ownedByCtfe = OWNEDctfe;
+ return r;
+}
+
+/******** Assignment helper functions ***************************/
+
+/* Set dest = src, where both dest and src are container value literals
+ * (ie, struct literals, or static arrays (can be an array literal or a string))
+ * Assignment is recursively in-place.
+ * Purpose: any reference to a member of 'dest' will remain valid after the
+ * assignment.
+ */
+void assignInPlace(Expression *dest, Expression *src)
+{
+ assert(dest->op == TOKstructliteral ||
+ dest->op == TOKarrayliteral ||
+ dest->op == TOKstring);
+ Expressions *oldelems;
+ Expressions *newelems;
+ if (dest->op == TOKstructliteral)
+ {
+ assert(dest->op == src->op);
+ oldelems = ((StructLiteralExp *)dest)->elements;
+ newelems = ((StructLiteralExp *)src)->elements;
+ if (((StructLiteralExp *)dest)->sd->isNested() && oldelems->dim == newelems->dim - 1)
+ oldelems->push(NULL);
+ }
+ else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral)
+ {
+ oldelems = ((ArrayLiteralExp *)dest)->elements;
+ newelems = ((ArrayLiteralExp *)src)->elements;
+ }
+ else if (dest->op == TOKstring && src->op == TOKstring)
+ {
+ sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0);
+ return;
+ }
+ else if (dest->op == TOKarrayliteral && src->op == TOKstring)
+ {
+ sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0);
+ return;
+ }
+ else if (src->op == TOKarrayliteral && dest->op == TOKstring)
+ {
+ sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0);
+ return;
+ }
+ else
+ assert(0);
+
+ assert(oldelems->dim == newelems->dim);
+
+ for (size_t i= 0; i < oldelems->dim; ++i)
+ {
+ Expression *e = (*newelems)[i];
+ Expression *o = (*oldelems)[i];
+ if (e->op == TOKstructliteral)
+ {
+ assert(o->op == e->op);
+ assignInPlace(o, e);
+ }
+ else if (e->type->ty == Tsarray && e->op != TOKvoid &&
+ o->type->ty == Tsarray)
+ {
+ assignInPlace(o, e);
+ }
+ else
+ {
+ (*oldelems)[i] = (*newelems)[i];
+ }
+ }
+}
+
+// Duplicate the elements array, then set field 'indexToChange' = newelem.
+Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem)
+{
+ Expressions *expsx = new Expressions();
+ ++CtfeStatus::numArrayAllocs;
+ expsx->setDim(oldelems->dim);
+ for (size_t j = 0; j < expsx->dim; j++)
+ {
+ if (j == indexToChange)
+ (*expsx)[j] = newelem;
+ else
+ (*expsx)[j] = (*oldelems)[j];
+ }
+ return expsx;
+}
+
+// Given an AA literal aae, set aae[index] = newval and return newval.
+Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
+ Expression *index, Expression *newval)
+{
+ /* Create new associative array literal reflecting updated key/value
+ */
+ Expressions *keysx = aae->keys;
+ Expressions *valuesx = aae->values;
+ int updated = 0;
+ for (size_t j = valuesx->dim; j; )
+ {
+ j--;
+ Expression *ekey = (*aae->keys)[j];
+ int eq = ctfeEqual(loc, TOKequal, ekey, index);
+ if (eq)
+ {
+ (*valuesx)[j] = newval;
+ updated = 1;
+ }
+ }
+ if (!updated)
+ {
+ // Append index/newval to keysx[]/valuesx[]
+ valuesx->push(newval);
+ keysx->push(index);
+ }
+ return newval;
+}
+
+/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
+/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
+/// all new elements will be set to the default initializer for the element type.
+UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
+ Expression *oldval, size_t oldlen, size_t newlen)
+{
+ UnionExp ue;
+ Type *elemType = arrayType->next;
+ assert(elemType);
+ Expression *defaultElem = elemType->defaultInitLiteral(loc);
+ Expressions *elements = new Expressions();
+ elements->setDim(newlen);
+
+ // Resolve slices
+ size_t indxlo = 0;
+ if (oldval->op == TOKslice)
+ {
+ indxlo = (size_t)((SliceExp *)oldval)->lwr->toInteger();
+ oldval = ((SliceExp *)oldval)->e1;
+ }
+ size_t copylen = oldlen < newlen ? oldlen : newlen;
+ if (oldval->op == TOKstring)
+ {
+ StringExp *oldse = (StringExp *)oldval;
+ void *s = mem.xcalloc(newlen + 1, oldse->sz);
+ memcpy(s, oldse->string, copylen * oldse->sz);
+ unsigned defaultValue = (unsigned)(defaultElem->toInteger());
+ for (size_t elemi = copylen; elemi < newlen; ++elemi)
+ {
+ switch (oldse->sz)
+ {
+ case 1: (( utf8_t *)s)[(size_t)(indxlo + elemi)] = ( utf8_t)defaultValue; break;
+ case 2: ((utf16_t *)s)[(size_t)(indxlo + elemi)] = (utf16_t)defaultValue; break;
+ case 4: ((utf32_t *)s)[(size_t)(indxlo + elemi)] = (utf32_t)defaultValue; break;
+ default: assert(0);
+ }
+ }
+ new(&ue) StringExp(loc, s, newlen);
+ StringExp *se = (StringExp *)ue.exp();
+ se->type = arrayType;
+ se->sz = oldse->sz;
+ se->committed = oldse->committed;
+ se->ownedByCtfe = OWNEDctfe;
+ }
+ else
+ {
+ if (oldlen != 0)
+ {
+ assert(oldval->op == TOKarrayliteral);
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval;
+ for (size_t i = 0; i < copylen; i++)
+ (*elements)[i] = (*ae->elements)[indxlo + i];
+ }
+ if (elemType->ty == Tstruct || elemType->ty == Tsarray)
+ {
+ /* If it is an aggregate literal representing a value type,
+ * we need to create a unique copy for each element
+ */
+ for (size_t i = copylen; i < newlen; i++)
+ (*elements)[i] = copyLiteral(defaultElem).copy();
+ }
+ else
+ {
+ for (size_t i = copylen; i < newlen; i++)
+ (*elements)[i] = defaultElem;
+ }
+ new(&ue) ArrayLiteralExp(loc, elements);
+ ArrayLiteralExp *aae = (ArrayLiteralExp *)ue.exp();
+ aae->type = arrayType;
+ aae->ownedByCtfe = OWNEDctfe;
+ }
+ return ue;
+}
+
+/*************************** CTFE Sanity Checks ***************************/
+
+bool isCtfeValueValid(Expression *newval)
+{
+ Type *tb = newval->type->toBasetype();
+
+ if (newval->op == TOKint64 ||
+ newval->op == TOKfloat64 ||
+ newval->op == TOKchar ||
+ newval->op == TOKcomplex80)
+ {
+ return tb->isscalar();
+ }
+ if (newval->op == TOKnull)
+ {
+ return tb->ty == Tnull ||
+ tb->ty == Tpointer ||
+ tb->ty == Tarray ||
+ tb->ty == Taarray ||
+ tb->ty == Tclass ||
+ tb->ty == Tdelegate;
+ }
+
+ if (newval->op == TOKstring)
+ return true; // CTFE would directly use the StringExp in AST.
+ if (newval->op == TOKarrayliteral)
+ return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
+ if (newval->op == TOKassocarrayliteral)
+ return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
+ if (newval->op == TOKstructliteral)
+ return true; //((StructLiteralExp *)newval)->ownedByCtfe;
+ if (newval->op == TOKclassreference)
+ return true;
+
+ if (newval->op == TOKvector)
+ return true; // vector literal
+
+ if (newval->op == TOKfunction)
+ return true; // function literal or delegate literal
+ if (newval->op == TOKdelegate)
+ {
+ // &struct.func or &clasinst.func
+ // &nestedfunc
+ Expression *ethis = ((DelegateExp *)newval)->e1;
+ return (ethis->op == TOKstructliteral ||
+ ethis->op == TOKclassreference ||
+ (ethis->op == TOKvar && ((VarExp *)ethis)->var == ((DelegateExp *)newval)->func));
+ }
+ if (newval->op == TOKsymoff)
+ {
+ // function pointer, or pointer to static variable
+ Declaration *d = ((SymOffExp *)newval)->var;
+ return d->isFuncDeclaration() || d->isDataseg();
+ }
+ if (newval->op == TOKtypeid)
+ {
+ // always valid
+ return true;
+ }
+ if (newval->op == TOKaddress)
+ {
+ // e1 should be a CTFE reference
+ Expression *e1 = ((AddrExp *)newval)->e1;
+ return tb->ty == Tpointer &&
+ ((e1->op == TOKstructliteral && isCtfeValueValid(e1)) ||
+ (e1->op == TOKvar) ||
+ (e1->op == TOKdotvar && isCtfeReferenceValid(e1)) ||
+ (e1->op == TOKindex && isCtfeReferenceValid(e1)) ||
+ (e1->op == TOKslice && e1->type->toBasetype()->ty == Tsarray));
+ }
+ if (newval->op == TOKslice)
+ {
+ // e1 should be an array aggregate
+ SliceExp *se = (SliceExp *)newval;
+ assert(se->lwr && se->lwr->op == TOKint64);
+ assert(se->upr && se->upr->op == TOKint64);
+ return (tb->ty == Tarray ||
+ tb->ty == Tsarray) &&
+ (se->e1->op == TOKstring ||
+ se->e1->op == TOKarrayliteral);
+ }
+
+ if (newval->op == TOKvoid)
+ return true; // uninitialized value
+
+ newval->error("CTFE internal error: illegal CTFE value %s", newval->toChars());
+ return false;
+}
+
+bool isCtfeReferenceValid(Expression *newval)
+{
+ if (newval->op == TOKthis)
+ return true;
+ if (newval->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)newval)->var->isVarDeclaration();
+ assert(v);
+ // Must not be a reference to a reference
+ return true;
+ }
+ if (newval->op == TOKindex)
+ {
+ Expression *eagg = ((IndexExp *)newval)->e1;
+ return eagg->op == TOKstring ||
+ eagg->op == TOKarrayliteral ||
+ eagg->op == TOKassocarrayliteral;
+ }
+ if (newval->op == TOKdotvar)
+ {
+ Expression *eagg = ((DotVarExp *)newval)->e1;
+ return (eagg->op == TOKstructliteral || eagg->op == TOKclassreference) &&
+ isCtfeValueValid(eagg);
+ }
+
+ // Internally a ref variable may directly point a stack memory.
+ // e.g. ref int v = 1;
+ return isCtfeValueValid(newval);
+}
+
+// Used for debugging only
+void showCtfeExpr(Expression *e, int level)
+{
+ for (int i = level; i > 0; --i) printf(" ");
+ Expressions *elements = NULL;
+ // We need the struct definition to detect block assignment
+ StructDeclaration *sd = NULL;
+ ClassDeclaration *cd = NULL;
+ if (e->op == TOKstructliteral)
+ {
+ elements = ((StructLiteralExp *)e)->elements;
+ sd = ((StructLiteralExp *)e)->sd;
+ printf("STRUCT type = %s %p:\n", e->type->toChars(),
+ e);
+ }
+ else if (e->op == TOKclassreference)
+ {
+ elements = ((ClassReferenceExp *)e)->value->elements;
+ cd = ((ClassReferenceExp *)e)->originalClass();
+ printf("CLASS type = %s %p:\n", e->type->toChars(),
+ ((ClassReferenceExp *)e)->value);
+ }
+ else if (e->op == TOKarrayliteral)
+ {
+ elements = ((ArrayLiteralExp *)e)->elements;
+ printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(),
+ e);
+ }
+ else if (e->op == TOKassocarrayliteral)
+ {
+ printf("AA LITERAL type=%s %p:\n", e->type->toChars(),
+ e);
+ }
+ else if (e->op == TOKstring)
+ {
+ printf("STRING %s %p\n", e->toChars(),
+ ((StringExp *)e)->string);
+ }
+ else if (e->op == TOKslice)
+ {
+ printf("SLICE %p: %s\n", e, e->toChars());
+ showCtfeExpr(((SliceExp *)e)->e1, level + 1);
+ }
+ else if (e->op == TOKvar)
+ {
+ printf("VAR %p %s\n", e, e->toChars());
+ VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+ if (v && getValue(v))
+ showCtfeExpr(getValue(v), level + 1);
+ }
+ else if (e->op == TOKaddress)
+ {
+ // This is potentially recursive. We mustn't try to print the thing we're pointing to.
+ printf("POINTER %p to %p: %s\n", e, ((AddrExp *)e)->e1, e->toChars());
+ }
+ else
+ printf("VALUE %p: %s\n", e, e->toChars());
+
+ if (elements)
+ {
+ size_t fieldsSoFar = 0;
+ for (size_t i = 0; i < elements->dim; i++)
+ {
+ Expression *z = NULL;
+ VarDeclaration *v = NULL;
+ if (i > 15)
+ {
+ printf("...(total %d elements)\n", (int)elements->dim);
+ return;
+ }
+ if (sd)
+ {
+ v = sd->fields[i];
+ z = (*elements)[i];
+ }
+ else if (cd)
+ {
+ while (i - fieldsSoFar >= cd->fields.dim)
+ {
+ fieldsSoFar += cd->fields.dim;
+ cd = cd->baseClass;
+ for (int j = level; j > 0; --j) printf(" ");
+ printf(" BASE CLASS: %s\n", cd->toChars());
+ }
+ v = cd->fields[i - fieldsSoFar];
+ assert((elements->dim + i) >= (fieldsSoFar + cd->fields.dim));
+ size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i;
+ assert(indx < elements->dim);
+ z = (*elements)[indx];
+ }
+ if (!z)
+ {
+ for (int j = level; j > 0; --j) printf(" ");
+ printf(" void\n");
+ continue;
+ }
+
+ if (v)
+ {
+ // If it is a void assignment, use the default initializer
+ if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray)
+ {
+ for (int j = level; --j; ) printf(" ");
+ printf(" field: block initalized static array\n");
+ continue;
+ }
+ }
+ showCtfeExpr(z, level + 1);
+ }
+ }
+}
+
+/*************************** Void initialization ***************************/
+
+UnionExp voidInitLiteral(Type *t, VarDeclaration *var)
+{
+ UnionExp ue;
+ if (t->ty == Tsarray)
+ {
+ TypeSArray *tsa = (TypeSArray *)t;
+ Expression *elem = voidInitLiteral(tsa->next, var).copy();
+
+ // For aggregate value types (structs, static arrays) we must
+ // create an a separate copy for each element.
+ bool mustCopy = (elem->op == TOKarrayliteral || elem->op == TOKstructliteral);
+
+ Expressions *elements = new Expressions();
+ size_t d = (size_t)tsa->dim->toInteger();
+ elements->setDim(d);
+ for (size_t i = 0; i < d; i++)
+ {
+ if (mustCopy && i > 0)
+ elem = copyLiteral(elem).copy();
+ (*elements)[i] = elem;
+ }
+ new(&ue) ArrayLiteralExp(var->loc, elements);
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)ue.exp();
+ ae->type = tsa;
+ ae->ownedByCtfe = OWNEDctfe;
+ }
+ else if (t->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)t;
+ Expressions *exps = new Expressions();
+ exps->setDim(ts->sym->fields.dim);
+ for (size_t i = 0; i < ts->sym->fields.dim; i++)
+ {
+ (*exps)[i] = voidInitLiteral(ts->sym->fields[i]->type, ts->sym->fields[i]).copy();
+ }
+ new(&ue) StructLiteralExp(var->loc, ts->sym, exps);
+ StructLiteralExp *se = (StructLiteralExp *)ue.exp();
+ se->type = ts;
+ se->ownedByCtfe = OWNEDctfe;
+ }
+ else
+ new(&ue) VoidInitExp(var, t);
+ return ue;
+}
diff --git a/gcc/d/dmd/dcast.c b/gcc/d/dmd/dcast.c
new file mode 100644
index 0000000..ee3bfd9
--- /dev/null
+++ b/gcc/d/dmd/dcast.c
@@ -0,0 +1,3732 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/cast.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h> // mem{set|cpy}()
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "expression.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "template.h"
+#include "scope.h"
+#include "id.h"
+#include "init.h"
+#include "tokens.h"
+
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+bool isCommutative(TOK op);
+MOD MODmerge(MOD mod1, MOD mod2);
+Expression *semantic(Expression *e, Scope *sc);
+
+/* ==================== implicitCast ====================== */
+
+/**************************************
+ * Do an implicit cast.
+ * Issue error if it can't be done.
+ */
+
+
+Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
+{
+ class ImplicitCastTo : public Visitor
+ {
+ public:
+ Type *t;
+ Scope *sc;
+ Expression *result;
+
+ ImplicitCastTo(Scope *sc, Type *t)
+ : t(t), sc(sc)
+ {
+ result = NULL;
+ }
+
+ void visit(Expression *e)
+ {
+ //printf("Expression::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars());
+
+ MATCH match = e->implicitConvTo(t);
+ if (match)
+ {
+ if (match == MATCHconst &&
+ (e->type->constConv(t) ||
+ (!e->isLvalue() && e->type->equivalent(t))))
+ {
+ /* Do not emit CastExp for const conversions and
+ * unique conversions on rvalue.
+ */
+ result = e->copy();
+ result->type = t;
+ return;
+ }
+ result = e->castTo(sc, t);
+ return;
+ }
+
+ result = e->optimize(WANTvalue);
+ if (result != e)
+ {
+ result->accept(this);
+ return;
+ }
+
+ if (t->ty != Terror && e->type->ty != Terror)
+ {
+ if (!t->deco)
+ {
+ e->error("forward reference to type %s", t->toChars());
+ }
+ else
+ {
+ //printf("type %p ty %d deco %p\n", type, type->ty, type->deco);
+ //type = type->semantic(loc, sc);
+ //printf("type %s t %s\n", type->deco, t->deco);
+ e->error("cannot implicitly convert expression (%s) of type %s to %s",
+ e->toChars(), e->type->toChars(), t->toChars());
+ }
+ }
+ result = new ErrorExp();
+ }
+
+ void visit(StringExp *e)
+ {
+ //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars());
+ visit((Expression *)e);
+ if (result->op == TOKstring)
+ {
+ // Retain polysemous nature if it started out that way
+ ((StringExp *)result)->committed = e->committed;
+ }
+ }
+
+ void visit(ErrorExp *e)
+ {
+ result = e;
+ }
+
+ void visit(FuncExp *e)
+ {
+ //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars());
+ FuncExp *fe;
+ if (e->matchType(t, sc, &fe) > MATCHnomatch)
+ {
+ result = fe;
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ visit((Expression *)e);
+
+ Type *tb = result->type->toBasetype();
+ if (tb->ty == Tarray)
+ semanticTypeInfo(sc, ((TypeDArray *)tb)->next);
+ }
+
+ void visit(SliceExp *e)
+ {
+ visit((Expression *)e);
+ if (result->op != TOKslice)
+ return;
+
+ e = (SliceExp *)result;
+ if (e->e1->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e->e1;
+ Type *tb = t->toBasetype();
+ Type *tx;
+ if (tb->ty == Tsarray)
+ tx = tb->nextOf()->sarrayOf(ale->elements ? ale->elements->dim : 0);
+ else
+ tx = tb->nextOf()->arrayOf();
+ e->e1 = ale->implicitCastTo(sc, tx);
+ }
+ }
+ };
+
+ ImplicitCastTo v(sc, t);
+ e->accept(&v);
+ return v.result;
+}
+
+/*******************************************
+ * Return MATCH level of implicitly converting e to type t.
+ * Don't do the actual cast; don't change e.
+ */
+
+MATCH implicitConvTo(Expression *e, Type *t)
+{
+ class ImplicitConvTo : public Visitor
+ {
+ public:
+ Type *t;
+ MATCH result;
+
+ ImplicitConvTo(Type *t)
+ : t(t)
+ {
+ result = MATCHnomatch;
+ }
+
+ void visit(Expression *e)
+ {
+ //static int nest; if (++nest == 10) halt();
+ if (t == Type::terror)
+ return;
+ if (!e->type)
+ {
+ e->error("%s is not an expression", e->toChars());
+ e->type = Type::terror;
+ }
+ Expression *ex = e->optimize(WANTvalue);
+ if (ex->type->equals(t))
+ {
+ result = MATCHexact;
+ return;
+ }
+ if (ex != e)
+ {
+ //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
+ result = ex->implicitConvTo(t);
+ return;
+ }
+ MATCH match = e->type->implicitConvTo(t);
+ if (match != MATCHnomatch)
+ {
+ result = match;
+ return;
+ }
+
+ /* See if we can do integral narrowing conversions
+ */
+ if (e->type->isintegral() && t->isintegral() &&
+ e->type->isTypeBasic() && t->isTypeBasic())
+ {
+ IntRange src = getIntRange(e);
+ IntRange target = IntRange::fromType(t);
+ if (target.contains(src))
+ {
+ result = MATCHconvert;
+ return;
+ }
+ }
+ }
+
+ /******
+ * Given expression e of type t, see if we can implicitly convert e
+ * to type tprime, where tprime is type t with mod bits added.
+ * Returns:
+ * match level
+ */
+ static MATCH implicitMod(Expression *e, Type *t, MOD mod)
+ {
+ Type *tprime;
+ if (t->ty == Tpointer)
+ tprime = t->nextOf()->castMod(mod)->pointerTo();
+ else if (t->ty == Tarray)
+ tprime = t->nextOf()->castMod(mod)->arrayOf();
+ else if (t->ty == Tsarray)
+ tprime = t->nextOf()->castMod(mod)->sarrayOf(t->size() / t->nextOf()->size());
+ else
+ tprime = t->castMod(mod);
+
+ return e->implicitConvTo(tprime);
+ }
+
+ static MATCH implicitConvToAddMin(BinExp *e, Type *t)
+ {
+ /* Is this (ptr +- offset)? If so, then ask ptr
+ * if the conversion can be done.
+ * This is to support doing things like implicitly converting a mutable unique
+ * pointer to an immutable pointer.
+ */
+
+ Type *typeb = e->type->toBasetype();
+ Type *tb = t->toBasetype();
+ if (typeb->ty != Tpointer || tb->ty != Tpointer)
+ return MATCHnomatch;
+
+ Type *t1b = e->e1->type->toBasetype();
+ Type *t2b = e->e2->type->toBasetype();
+ if (t1b->ty == Tpointer && t2b->isintegral() &&
+ t1b->equivalent(tb))
+ {
+ // ptr + offset
+ // ptr - offset
+ MATCH m = e->e1->implicitConvTo(t);
+ return (m > MATCHconst) ? MATCHconst : m;
+ }
+ if (t2b->ty == Tpointer && t1b->isintegral() &&
+ t2b->equivalent(tb))
+ {
+ // offset + ptr
+ MATCH m = e->e2->implicitConvTo(t);
+ return (m > MATCHconst) ? MATCHconst : m;
+ }
+
+ return MATCHnomatch;
+ }
+
+ void visit(AddExp *e)
+ {
+ visit((Expression *)e);
+ if (result == MATCHnomatch)
+ result = implicitConvToAddMin(e, t);
+ }
+
+ void visit(MinExp *e)
+ {
+ visit((Expression *)e);
+ if (result == MATCHnomatch)
+ result = implicitConvToAddMin(e, t);
+ }
+
+ void visit(IntegerExp *e)
+ {
+ MATCH m = e->type->implicitConvTo(t);
+ if (m >= MATCHconst)
+ {
+ result = m;
+ return;
+ }
+
+ TY ty = e->type->toBasetype()->ty;
+ TY toty = t->toBasetype()->ty;
+ TY oldty = ty;
+
+ if (m == MATCHnomatch && t->ty == Tenum)
+ return;
+
+ if (t->ty == Tvector)
+ {
+ TypeVector *tv = (TypeVector *)t;
+ TypeBasic *tb = tv->elementType();
+ if (tb->ty == Tvoid)
+ return;
+ toty = tb->ty;
+ }
+
+ switch (ty)
+ {
+ case Tbool:
+ case Tint8:
+ case Tchar:
+ case Tuns8:
+ case Tint16:
+ case Tuns16:
+ case Twchar:
+ ty = Tint32;
+ break;
+
+ case Tdchar:
+ ty = Tuns32;
+ break;
+
+ default:
+ break;
+ }
+
+ // Only allow conversion if no change in value
+ dinteger_t value = e->toInteger();
+ switch (toty)
+ {
+ case Tbool:
+ if ((value & 1) != value)
+ return;
+ break;
+
+ case Tint8:
+ if (ty == Tuns64 && value & ~0x7FUL)
+ return;
+ else if ((signed char)value != (sinteger_t)value)
+ return;
+ break;
+
+ case Tchar:
+ if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
+ return;
+ /* fall through */
+ case Tuns8:
+ //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
+ if ((unsigned char)value != value)
+ return;
+ break;
+
+ case Tint16:
+ if (ty == Tuns64 && value & ~0x7FFFUL)
+ return;
+ else if ((short)value != (sinteger_t)value)
+ return;
+ break;
+
+ case Twchar:
+ if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
+ return;
+ /* fall through */
+ case Tuns16:
+ if ((unsigned short)value != value)
+ return;
+ break;
+
+ case Tint32:
+ if (ty == Tuns32)
+ {
+ }
+ else if (ty == Tuns64 && value & ~0x7FFFFFFFUL)
+ return;
+ else if ((int)value != (sinteger_t)value)
+ return;
+ break;
+
+ case Tuns32:
+ if (ty == Tint32)
+ {
+ }
+ else if ((unsigned)value != value)
+ return;
+ break;
+
+ case Tdchar:
+ if (value > 0x10FFFFUL)
+ return;
+ break;
+
+ case Tfloat32:
+ {
+ volatile float f;
+ if (e->type->isunsigned())
+ {
+ f = (float)value;
+ if (f != value)
+ return;
+ }
+ else
+ {
+ f = (float)(sinteger_t)value;
+ if (f != (sinteger_t)value)
+ return;
+ }
+ break;
+ }
+
+ case Tfloat64:
+ {
+ volatile double f;
+ if (e->type->isunsigned())
+ {
+ f = (double)value;
+ if (f != value)
+ return;
+ }
+ else
+ {
+ f = (double)(sinteger_t)value;
+ if (f != (sinteger_t)value)
+ return;
+ }
+ break;
+ }
+
+ case Tfloat80:
+ {
+ volatile_longdouble f;
+ if (e->type->isunsigned())
+ {
+ f = ldouble(value);
+ if ((dinteger_t)f != value) // isn't this a noop, because the compiler prefers ld
+ return;
+ }
+ else
+ {
+ f = ldouble((sinteger_t)value);
+ if ((sinteger_t)f != (sinteger_t)value)
+ return;
+ }
+ break;
+ }
+
+ case Tpointer:
+ //printf("type = %s\n", type->toBasetype()->toChars());
+ //printf("t = %s\n", t->toBasetype()->toChars());
+ if (ty == Tpointer &&
+ e->type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
+ {
+ /* Allow things like:
+ * const char* P = cast(char *)3;
+ * char* q = P;
+ */
+ break;
+ }
+ /* fall through */
+
+ default:
+ visit((Expression *)e);
+ return;
+ }
+
+ //printf("MATCHconvert\n");
+ result = MATCHconvert;
+ }
+
+ void visit(ErrorExp *)
+ {
+ // no match
+ }
+
+ void visit(NullExp *e)
+ {
+ if (e->type->equals(t))
+ {
+ result = MATCHexact;
+ return;
+ }
+
+ /* Allow implicit conversions from immutable to mutable|const,
+ * and mutable to immutable. It works because, after all, a null
+ * doesn't actually point to anything.
+ */
+ if (t->equivalent(e->type))
+ {
+ result = MATCHconst;
+ return;
+ }
+
+ visit((Expression *)e);
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ visit((Expression *)e);
+ if (result != MATCHnomatch)
+ return;
+ if (e->type->ty == t->ty && e->type->ty == Tstruct &&
+ ((TypeStruct *)e->type)->sym == ((TypeStruct *)t)->sym)
+ {
+ result = MATCHconst;
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *el = (*e->elements)[i];
+ if (!el)
+ continue;
+ Type *te = el->type;
+ te = e->sd->fields[i]->type->addMod(t->mod);
+ MATCH m2 = el->implicitConvTo(te);
+ //printf("\t%s => %s, match = %d\n", el->toChars(), te->toChars(), m2);
+ if (m2 < result)
+ result = m2;
+ }
+ }
+ }
+
+ void visit(StringExp *e)
+ {
+ if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+ return;
+
+ if (e->type->ty == Tsarray || e->type->ty == Tarray || e->type->ty == Tpointer)
+ {
+ TY tyn = e->type->nextOf()->ty;
+ if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
+ {
+ switch (t->ty)
+ {
+ case Tsarray:
+ if (e->type->ty == Tsarray)
+ {
+ TY tynto = t->nextOf()->ty;
+ if (tynto == tyn)
+ {
+ if (((TypeSArray *)e->type)->dim->toInteger() ==
+ ((TypeSArray *)t)->dim->toInteger())
+ {
+ result = MATCHexact;
+ }
+ return;
+ }
+ if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
+ {
+ if (e->committed && tynto != tyn)
+ return;
+ size_t fromlen = e->numberOfCodeUnits(tynto);
+ size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger();
+ if (tolen < fromlen)
+ return;
+ if (tolen != fromlen)
+ {
+ // implicit length extending
+ result = MATCHconvert;
+ return;
+ }
+ }
+ if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
+ {
+ result = MATCHexact;
+ return;
+ }
+ }
+ else if (e->type->ty == Tarray)
+ {
+ TY tynto = t->nextOf()->ty;
+ if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
+ {
+ if (e->committed && tynto != tyn)
+ return;
+ size_t fromlen = e->numberOfCodeUnits(tynto);
+ size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger();
+ if (tolen < fromlen)
+ return;
+ if (tolen != fromlen)
+ {
+ // implicit length extending
+ result = MATCHconvert;
+ return;
+ }
+ }
+ if (tynto == tyn)
+ {
+ result = MATCHexact;
+ return;
+ }
+ if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
+ {
+ result = MATCHexact;
+ return;
+ }
+ }
+ /* fall through */
+ case Tarray:
+ case Tpointer:
+ Type *tn = t->nextOf();
+ MATCH m = MATCHexact;
+ if (e->type->nextOf()->mod != tn->mod)
+ {
+ if (!tn->isConst())
+ return;
+ m = MATCHconst;
+ }
+ if (!e->committed)
+ {
+ switch (tn->ty)
+ {
+ case Tchar:
+ if (e->postfix == 'w' || e->postfix == 'd')
+ m = MATCHconvert;
+ result = m;
+ return;
+ case Twchar:
+ if (e->postfix != 'w')
+ m = MATCHconvert;
+ result = m;
+ return;
+ case Tdchar:
+ if (e->postfix != 'd')
+ m = MATCHconvert;
+ result = m;
+ return;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ visit((Expression *)e);
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ Type *typeb = e->type->toBasetype();
+ Type *tb = t->toBasetype();
+ if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+ (typeb->ty == Tarray || typeb->ty == Tsarray))
+ {
+ result = MATCHexact;
+ Type *typen = typeb->nextOf()->toBasetype();
+
+ if (tb->ty == Tsarray)
+ {
+ TypeSArray *tsa = (TypeSArray *)tb;
+ if (e->elements->dim != tsa->dim->toInteger())
+ result = MATCHnomatch;
+ }
+
+ Type *telement = tb->nextOf();
+ if (!e->elements->dim)
+ {
+ if (typen->ty != Tvoid)
+ result = typen->implicitConvTo(telement);
+ }
+ else
+ {
+ if (e->basis)
+ {
+ MATCH m = e->basis->implicitConvTo(telement);
+ if (m < result)
+ result = m;
+ }
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *el = (*e->elements)[i];
+ if (result == MATCHnomatch)
+ break;
+ if (!el)
+ continue;
+ MATCH m = el->implicitConvTo(telement);
+ if (m < result)
+ result = m; // remember worst match
+ }
+ }
+
+ if (!result)
+ result = e->type->implicitConvTo(t);
+
+ return;
+ }
+ else if (tb->ty == Tvector &&
+ (typeb->ty == Tarray || typeb->ty == Tsarray))
+ {
+ result = MATCHexact;
+ // Convert array literal to vector type
+ TypeVector *tv = (TypeVector *)tb;
+ TypeSArray *tbase = (TypeSArray *)tv->basetype;
+ assert(tbase->ty == Tsarray);
+ const size_t edim = e->elements->dim;
+ const size_t tbasedim = tbase->dim->toInteger();
+ if (edim > tbasedim)
+ {
+ result = MATCHnomatch;
+ return;
+ }
+
+ Type *telement = tv->elementType();
+ if (edim < tbasedim)
+ {
+ Expression *el = typeb->nextOf()->defaultInitLiteral(e->loc);
+ MATCH m = el->implicitConvTo(telement);
+ if (m < result)
+ result = m; // remember worst match
+ }
+ for (size_t i = 0; i < edim; i++)
+ {
+ Expression *el = (*e->elements)[i];
+ MATCH m = el->implicitConvTo(telement);
+ if (m < result)
+ result = m; // remember worst match
+ if (result == MATCHnomatch)
+ break; // no need to check for worse
+ }
+ return;
+ }
+
+ visit((Expression *)e);
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ Type *typeb = e->type->toBasetype();
+ Type *tb = t->toBasetype();
+ if (tb->ty == Taarray && typeb->ty == Taarray)
+ {
+ result = MATCHexact;
+ for (size_t i = 0; i < e->keys->dim; i++)
+ {
+ Expression *el = (*e->keys)[i];
+ MATCH m = el->implicitConvTo(((TypeAArray *)tb)->index);
+ if (m < result)
+ result = m; // remember worst match
+ if (result == MATCHnomatch)
+ break; // no need to check for worse
+ el = (*e->values)[i];
+ m = el->implicitConvTo(tb->nextOf());
+ if (m < result)
+ result = m; // remember worst match
+ if (result == MATCHnomatch)
+ break; // no need to check for worse
+ }
+ return;
+ }
+ else
+ visit((Expression *)e);
+ }
+
+ void visit(CallExp *e)
+ {
+ visit((Expression *)e);
+ if (result != MATCHnomatch)
+ return;
+
+ /* Allow the result of strongly pure functions to
+ * convert to immutable
+ */
+ if (e->f && e->f->isolateReturn())
+ {
+ result = e->type->immutableOf()->implicitConvTo(t);
+ if (result > MATCHconst) // Match level is MATCHconst at best.
+ result = MATCHconst;
+ return;
+ }
+
+ /* Conversion is 'const' conversion if:
+ * 1. function is pure (weakly pure is ok)
+ * 2. implicit conversion only fails because of mod bits
+ * 3. each function parameter can be implicitly converted to the mod bits
+ */
+ Type *tx = e->f ? e->f->type : e->e1->type;
+ tx = tx->toBasetype();
+ if (tx->ty != Tfunction)
+ return;
+ TypeFunction *tf = (TypeFunction *)tx;
+
+ if (tf->purity == PUREimpure)
+ return;
+ if (e->f && e->f->isNested())
+ return;
+
+ /* See if fail only because of mod bits.
+ *
+ * Bugzilla 14155: All pure functions can access global immutable data.
+ * So the returned pointer may refer an immutable global data,
+ * and then the returned pointer that points non-mutable object
+ * cannot be unique pointer.
+ *
+ * Example:
+ * immutable g;
+ * static this() { g = 1; }
+ * const(int*) foo() pure { return &g; }
+ * void test() {
+ * immutable(int*) ip = foo(); // OK
+ * int* mp = foo(); // should be disallowed
+ * }
+ */
+ if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst &&
+ e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst &&
+ e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst)
+ {
+ return;
+ }
+ // Allow a conversion to immutable type, or
+ // conversions of mutable types between thread-local and shared.
+
+ /* Get mod bits of what we're converting to
+ */
+ Type *tb = t->toBasetype();
+ MOD mod = tb->mod;
+ if (tf->isref)
+ ;
+ else
+ {
+ Type *ti = getIndirection(t);
+ if (ti)
+ mod = ti->mod;
+ }
+ if (mod & MODwild)
+ return; // not sure what to do with this
+
+ /* Apply mod bits to each function parameter,
+ * and see if we can convert the function argument to the modded type
+ */
+
+ size_t nparams = Parameter::dim(tf->parameters);
+ size_t j = (tf->linkage == LINKd && tf->varargs == 1); // if TypeInfoArray was prepended
+ if (e->e1->op == TOKdotvar)
+ {
+ /* Treat 'this' as just another function argument
+ */
+ DotVarExp *dve = (DotVarExp *)e->e1;
+ Type *targ = dve->e1->type;
+ if (targ->constConv(targ->castMod(mod)) == MATCHnomatch)
+ return;
+ }
+ for (size_t i = j; i < e->arguments->dim; ++i)
+ {
+ Expression *earg = (*e->arguments)[i];
+ Type *targ = earg->type->toBasetype();
+ if (i - j < nparams)
+ {
+ Parameter *fparam = Parameter::getNth(tf->parameters, i - j);
+ if (fparam->storageClass & STClazy)
+ return; // not sure what to do with this
+ Type *tparam = fparam->type;
+ if (!tparam)
+ continue;
+ if (fparam->storageClass & (STCout | STCref))
+ {
+ if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch)
+ return;
+ continue;
+ }
+ }
+
+ if (implicitMod(earg, targ, mod) == MATCHnomatch)
+ return;
+ }
+
+ /* Success
+ */
+ result = MATCHconst;
+ }
+
+ void visit(AddrExp *e)
+ {
+ result = e->type->implicitConvTo(t);
+ //printf("\tresult = %d\n", result);
+
+ if (result != MATCHnomatch)
+ return;
+
+ // Look for pointers to functions where the functions are overloaded.
+
+ t = t->toBasetype();
+
+ if (e->e1->op == TOKoverloadset &&
+ (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+ {
+ OverExp *eo = (OverExp *)e->e1;
+ FuncDeclaration *f = NULL;
+ for (size_t i = 0; i < eo->vars->a.dim; i++)
+ {
+ Dsymbol *s = eo->vars->a[i];
+ FuncDeclaration *f2 = s->isFuncDeclaration();
+ assert(f2);
+ if (f2->overloadExactMatch(t->nextOf()))
+ {
+ if (f)
+ {
+ /* Error if match in more than one overload set,
+ * even if one is a 'better' match than the other.
+ */
+ ScopeDsymbol::multiplyDefined(e->loc, f, f2);
+ }
+ else
+ f = f2;
+ result = MATCHexact;
+ }
+ }
+ }
+
+ if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
+ t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
+ e->e1->op == TOKvar)
+ {
+ /* I don't think this can ever happen -
+ * it should have been
+ * converted to a SymOffExp.
+ */
+ assert(0);
+ }
+
+ //printf("\tresult = %d\n", result);
+ }
+
+ void visit(SymOffExp *e)
+ {
+ result = e->type->implicitConvTo(t);
+ //printf("\tresult = %d\n", result);
+ if (result != MATCHnomatch)
+ return;
+
+ // Look for pointers to functions where the functions are overloaded.
+ t = t->toBasetype();
+ if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
+ (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+ {
+ if (FuncDeclaration *f = e->var->isFuncDeclaration())
+ {
+ f = f->overloadExactMatch(t->nextOf());
+ if (f)
+ {
+ if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
+ (t->ty == Tpointer && !(f->needThis() || f->isNested())))
+ {
+ result = MATCHexact;
+ }
+ }
+ }
+ }
+ //printf("\tresult = %d\n", result);
+ }
+
+ void visit(DelegateExp *e)
+ {
+ result = e->type->implicitConvTo(t);
+ if (result != MATCHnomatch)
+ return;
+
+ // Look for pointers to functions where the functions are overloaded.
+ t = t->toBasetype();
+ if (e->type->ty == Tdelegate &&
+ t->ty == Tdelegate)
+ {
+ if (e->func && e->func->overloadExactMatch(t->nextOf()))
+ result = MATCHexact;
+ }
+ }
+
+ void visit(FuncExp *e)
+ {
+ //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars());
+ MATCH m = e->matchType(t, NULL, NULL, 1);
+ if (m > MATCHnomatch)
+ {
+ result = m;
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(OrExp *e)
+ {
+ visit((Expression *)e);
+ if (result != MATCHnomatch)
+ return;
+
+ MATCH m1 = e->e1->implicitConvTo(t);
+ MATCH m2 = e->e2->implicitConvTo(t);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
+ void visit(XorExp *e)
+ {
+ visit((Expression *)e);
+ if (result != MATCHnomatch)
+ return;
+
+ MATCH m1 = e->e1->implicitConvTo(t);
+ MATCH m2 = e->e2->implicitConvTo(t);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
+ void visit(CondExp *e)
+ {
+ MATCH m1 = e->e1->implicitConvTo(t);
+ MATCH m2 = e->e2->implicitConvTo(t);
+ //printf("CondExp: m1 %d m2 %d\n", m1, m2);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
+ void visit(CommaExp *e)
+ {
+ e->e2->accept(this);
+ }
+
+ void visit(CastExp *e)
+ {
+ result = e->type->implicitConvTo(t);
+ if (result != MATCHnomatch)
+ return;
+
+ if (t->isintegral() &&
+ e->e1->type->isintegral() &&
+ e->e1->implicitConvTo(t) != MATCHnomatch)
+ result = MATCHconvert;
+ else
+ visit((Expression *)e);
+ }
+
+ void visit(NewExp *e)
+ {
+ visit((Expression *)e);
+ if (result != MATCHnomatch)
+ return;
+
+ /* Calling new() is like calling a pure function. We can implicitly convert the
+ * return from new() to t using the same algorithm as in CallExp, with the function
+ * 'arguments' being:
+ * thisexp
+ * newargs
+ * arguments
+ * .init
+ * 'member' and 'allocator' need to be pure.
+ */
+
+ /* See if fail only because of mod bits
+ */
+ if (e->type->immutableOf()->implicitConvTo(t->immutableOf()) == MATCHnomatch)
+ return;
+
+ /* Get mod bits of what we're converting to
+ */
+ Type *tb = t->toBasetype();
+ MOD mod = tb->mod;
+ if (Type *ti = getIndirection(t))
+ mod = ti->mod;
+ if (mod & MODwild)
+ return; // not sure what to do with this
+
+ /* Apply mod bits to each argument,
+ * and see if we can convert the argument to the modded type
+ */
+
+ if (e->thisexp)
+ {
+ /* Treat 'this' as just another function argument
+ */
+ Type *targ = e->thisexp->type;
+ if (targ->constConv(targ->castMod(mod)) == MATCHnomatch)
+ return;
+ }
+
+ /* Check call to 'allocator', then 'member'
+ */
+ FuncDeclaration *fd = e->allocator;
+ for (int count = 0; count < 2; ++count, (fd = e->member))
+ {
+ if (!fd)
+ continue;
+ if (fd->errors || fd->type->ty != Tfunction)
+ return; // error
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (tf->purity == PUREimpure)
+ return; // impure
+
+ if (fd == e->member)
+ {
+ if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst &&
+ e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst &&
+ e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst)
+ {
+ return;
+ }
+ // Allow a conversion to immutable type, or
+ // conversions of mutable types between thread-local and shared.
+ }
+
+ Expressions *args = (fd == e->allocator) ? e->newargs : e->arguments;
+
+ size_t nparams = Parameter::dim(tf->parameters);
+ size_t j = (tf->linkage == LINKd && tf->varargs == 1); // if TypeInfoArray was prepended
+ for (size_t i = j; i < e->arguments->dim; ++i)
+ {
+ Expression *earg = (*args)[i];
+ Type *targ = earg->type->toBasetype();
+ if (i - j < nparams)
+ {
+ Parameter *fparam = Parameter::getNth(tf->parameters, i - j);
+ if (fparam->storageClass & STClazy)
+ return; // not sure what to do with this
+ Type *tparam = fparam->type;
+ if (!tparam)
+ continue;
+ if (fparam->storageClass & (STCout | STCref))
+ {
+ if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch)
+ return;
+ continue;
+ }
+ }
+
+ if (implicitMod(earg, targ, mod) == MATCHnomatch)
+ return;
+ }
+ }
+
+ /* If no 'member', then construction is by simple assignment,
+ * and just straight check 'arguments'
+ */
+ if (!e->member && e->arguments)
+ {
+ for (size_t i = 0; i < e->arguments->dim; ++i)
+ {
+ Expression *earg = (*e->arguments)[i];
+ if (!earg) // Bugzilla 14853: if it's on overlapped field
+ continue;
+ Type *targ = earg->type->toBasetype();
+ if (implicitMod(earg, targ, mod) == MATCHnomatch)
+ return;
+ }
+ }
+
+ /* Consider the .init expression as an argument
+ */
+ Type *ntb = e->newtype->toBasetype();
+ if (ntb->ty == Tarray)
+ ntb = ntb->nextOf()->toBasetype();
+ if (ntb->ty == Tstruct)
+ {
+ // Don't allow nested structs - uplevel reference may not be convertible
+ StructDeclaration *sd = ((TypeStruct *)ntb)->sym;
+ sd->size(e->loc); // resolve any forward references
+ if (sd->isNested())
+ return;
+ }
+ if (ntb->isZeroInit(e->loc))
+ {
+ /* Zeros are implicitly convertible, except for special cases.
+ */
+ if (ntb->ty == Tclass)
+ {
+ /* With new() must look at the class instance initializer.
+ */
+ ClassDeclaration *cd = ((TypeClass *)ntb)->sym;
+
+ cd->size(e->loc); // resolve any forward references
+
+ if (cd->isNested())
+ return; // uplevel reference may not be convertible
+
+ assert(!cd->isInterfaceDeclaration());
+
+ struct ClassCheck
+ {
+ static bool convertible(Loc loc, ClassDeclaration *cd, MOD mod)
+ {
+ for (size_t i = 0; i < cd->fields.dim; i++)
+ {
+ VarDeclaration *v = cd->fields[i];
+ Initializer *init = v->_init;
+ if (init)
+ {
+ if (init->isVoidInitializer())
+ ;
+ else if (ExpInitializer *ei = init->isExpInitializer())
+ {
+ Type *tb = v->type->toBasetype();
+ if (implicitMod(ei->exp, tb, mod) == MATCHnomatch)
+ return false;
+ }
+ else
+ {
+ /* Enhancement: handle StructInitializer and ArrayInitializer
+ */
+ return false;
+ }
+ }
+ else if (!v->type->isZeroInit(loc))
+ return false;
+ }
+ return cd->baseClass ? convertible(loc, cd->baseClass, mod) : true;
+ }
+ };
+
+ if (!ClassCheck::convertible(e->loc, cd, mod))
+ return;
+ }
+ }
+ else
+ {
+ Expression *earg = e->newtype->defaultInitLiteral(e->loc);
+ Type *targ = e->newtype->toBasetype();
+
+ if (implicitMod(earg, targ, mod) == MATCHnomatch)
+ return;
+ }
+
+ /* Success
+ */
+ result = MATCHconst;
+ }
+
+ void visit(SliceExp *e)
+ {
+ //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e->toChars(), e->type->toChars());
+ visit((Expression *)e);
+ if (result != MATCHnomatch)
+ return;
+
+ Type *tb = t->toBasetype();
+ Type *typeb = e->type->toBasetype();
+ if (tb->ty == Tsarray && typeb->ty == Tarray)
+ {
+ typeb = toStaticArrayType(e);
+ if (typeb)
+ result = typeb->implicitConvTo(t);
+ return;
+ }
+
+ /* If the only reason it won't convert is because of the mod bits,
+ * then test for conversion by seeing if e1 can be converted with those
+ * same mod bits.
+ */
+ Type *t1b = e->e1->type->toBasetype();
+ if (tb->ty == Tarray && typeb->equivalent(tb))
+ {
+ Type *tbn = tb->nextOf();
+ Type *tx = NULL;
+
+ /* If e->e1 is dynamic array or pointer, the uniqueness of e->e1
+ * is equivalent with the uniqueness of the referred data. And in here
+ * we can have arbitrary typed reference for that.
+ */
+ if (t1b->ty == Tarray)
+ tx = tbn->arrayOf();
+ if (t1b->ty == Tpointer)
+ tx = tbn->pointerTo();
+
+ /* If e->e1 is static array, at least it should be an rvalue.
+ * If not, e->e1 is a reference, and its uniqueness does not link
+ * to the uniqueness of the referred data.
+ */
+ if (t1b->ty == Tsarray && !e->e1->isLvalue())
+ tx = tbn->sarrayOf(t1b->size() / tbn->size());
+
+ if (tx)
+ {
+ result = e->e1->implicitConvTo(tx);
+ if (result > MATCHconst) // Match level is MATCHconst at best.
+ result = MATCHconst;
+ }
+ }
+
+ // Enhancement 10724
+ if (tb->ty == Tpointer && e->e1->op == TOKstring)
+ e->e1->accept(this);
+ }
+ };
+
+ ImplicitConvTo v(t);
+ e->accept(&v);
+ return v.result;
+}
+
+Type *toStaticArrayType(SliceExp *e)
+{
+ if (e->lwr && e->upr)
+ {
+ // For the following code to work, e should be optimized beforehand.
+ // (eg. $ in lwr and upr should be already resolved, if possible)
+ Expression *lwr = e->lwr->optimize(WANTvalue);
+ Expression *upr = e->upr->optimize(WANTvalue);
+ if (lwr->isConst() && upr->isConst())
+ {
+ size_t len = (size_t)(upr->toUInteger() - lwr->toUInteger());
+ return e->type->toBasetype()->nextOf()->sarrayOf(len);
+ }
+ }
+ else
+ {
+ Type *t1b = e->e1->type->toBasetype();
+ if (t1b->ty == Tsarray)
+ return t1b;
+ }
+ return NULL;
+}
+
+/* ==================== castTo ====================== */
+
+/**************************************
+ * Do an explicit cast.
+ * Assume that the 'this' expression does not have any indirections.
+ */
+
+Expression *castTo(Expression *e, Scope *sc, Type *t)
+{
+ class CastTo : public Visitor
+ {
+ public:
+ Type *t;
+ Scope *sc;
+ Expression *result;
+
+ CastTo(Scope *sc, Type *t)
+ : t(t), sc(sc)
+ {
+ result = NULL;
+ }
+
+ void visit(Expression *e)
+ {
+ //printf("Expression::castTo(this=%s, t=%s)\n", e->toChars(), t->toChars());
+ if (e->type->equals(t))
+ {
+ result = e;
+ return;
+ }
+ if (e->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+ if (v && v->storage_class & STCmanifest)
+ {
+ result = e->ctfeInterpret();
+ result = result->castTo(sc, t);
+ return;
+ }
+ }
+
+ Type *tob = t->toBasetype();
+ Type *t1b = e->type->toBasetype();
+ if (tob->equals(t1b))
+ {
+ result = e->copy(); // because of COW for assignment to e->type
+ result->type = t;
+ return;
+ }
+
+ /* Make semantic error against invalid cast between concrete types.
+ * Assume that 'e' is never be any placeholder expressions.
+ * The result of these checks should be consistent with CastExp::toElem().
+ */
+
+ // Fat Value types
+ const bool tob_isFV = (tob->ty == Tstruct || tob->ty == Tsarray || tob->ty == Tvector);
+ const bool t1b_isFV = (t1b->ty == Tstruct || t1b->ty == Tsarray || t1b->ty == Tvector);
+
+ // Fat Reference types
+ const bool tob_isFR = (tob->ty == Tarray || tob->ty == Tdelegate);
+ const bool t1b_isFR = (t1b->ty == Tarray || t1b->ty == Tdelegate);
+
+ // Reference types
+ const bool tob_isR = (tob_isFR || tob->ty == Tpointer || tob->ty == Taarray || tob->ty == Tclass);
+ const bool t1b_isR = (t1b_isFR || t1b->ty == Tpointer || t1b->ty == Taarray || t1b->ty == Tclass);
+
+ // Arithmetic types (== valueable basic types)
+ const bool tob_isA = ((tob->isintegral() || tob->isfloating()) && tob->ty != Tvector);
+ const bool t1b_isA = ((t1b->isintegral() || t1b->isfloating()) && t1b->ty != Tvector);
+
+ if (AggregateDeclaration *t1ad = isAggregate(t1b))
+ {
+ AggregateDeclaration *toad = isAggregate(tob);
+ if (t1ad != toad && t1ad->aliasthis)
+ {
+ if (t1b->ty == Tclass && tob->ty == Tclass)
+ {
+ ClassDeclaration *t1cd = t1b->isClassHandle();
+ ClassDeclaration *tocd = tob->isClassHandle();
+ int offset;
+ if (tocd->isBaseOf(t1cd, &offset))
+ goto Lok;
+ }
+
+ /* Forward the cast to our alias this member, rewrite to:
+ * cast(to)e1.aliasthis
+ */
+ result = resolveAliasThis(sc, e);
+ result = result->castTo(sc, t);
+ return;
+ }
+ }
+ else if (tob->ty == Tvector && t1b->ty != Tvector)
+ {
+ //printf("test1 e = %s, e->type = %s, tob = %s\n", e->toChars(), e->type->toChars(), tob->toChars());
+ TypeVector *tv = (TypeVector *)tob;
+ result = new CastExp(e->loc, e, tv->elementType());
+ result = new VectorExp(e->loc, result, tob);
+ result = ::semantic(result, sc);
+ return;
+ }
+ else if (tob->ty != Tvector && t1b->ty == Tvector)
+ {
+ // T[n] <-- __vector(U[m])
+ if (tob->ty == Tsarray)
+ {
+ if (t1b->size(e->loc) == tob->size(e->loc))
+ goto Lok;
+ }
+ goto Lfail;
+ }
+ else if (t1b->implicitConvTo(tob) == MATCHconst && t->equals(e->type->constOf()))
+ {
+ result = e->copy();
+ result->type = t;
+ return;
+ }
+
+ // arithmetic values vs. other arithmetic values
+ // arithmetic values vs. T*
+ if ((tob_isA && (t1b_isA || t1b->ty == Tpointer)) ||
+ (t1b_isA && (tob_isA || tob->ty == Tpointer)))
+ {
+ goto Lok;
+ }
+
+ // arithmetic values vs. references or fat values
+ if ((tob_isA && (t1b_isR || t1b_isFV)) ||
+ (t1b_isA && (tob_isR || tob_isFV)))
+ {
+ goto Lfail;
+ }
+
+ // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
+ if (tob_isFV && t1b_isFV)
+ {
+ if (t1b->size(e->loc) == tob->size(e->loc))
+ goto Lok;
+ e->error("cannot cast expression %s of type %s to %s because of different sizes",
+ e->toChars(), e->type->toChars(), t->toChars());
+ result = new ErrorExp();
+ return;
+ }
+
+ // Fat values vs. null or references
+ if ((tob_isFV && (t1b->ty == Tnull || t1b_isR)) ||
+ (t1b_isFV && (tob->ty == Tnull || tob_isR)))
+ {
+ if (tob->ty == Tpointer && t1b->ty == Tsarray)
+ {
+ // T[n] sa;
+ // cast(U*)sa; // ==> cast(U*)sa.ptr;
+ result = new AddrExp(e->loc, e, t);
+ return;
+ }
+ if (tob->ty == Tarray && t1b->ty == Tsarray)
+ {
+ // T[n] sa;
+ // cast(U[])sa; // ==> cast(U[])sa[];
+ d_uns64 fsize = t1b->nextOf()->size();
+ d_uns64 tsize = tob->nextOf()->size();
+ if ((((TypeSArray *)t1b)->dim->toInteger() * fsize) % tsize != 0)
+ {
+ // copied from sarray_toDarray() in e2ir.c
+ e->error("cannot cast expression %s of type %s to %s since sizes don't line up",
+ e->toChars(), e->type->toChars(), t->toChars());
+ result = new ErrorExp();
+ return;
+ }
+ goto Lok;
+ }
+ goto Lfail;
+ }
+
+ /* For references, any reinterpret casts are allowed to same 'ty' type.
+ * T* to U*
+ * R1 function(P1) to R2 function(P2)
+ * R1 delegate(P1) to R2 delegate(P2)
+ * T[] to U[]
+ * V1[K1] to V2[K2]
+ * class/interface A to B (will be a dynamic cast if possible)
+ */
+ if (tob->ty == t1b->ty && tob_isR && t1b_isR)
+ goto Lok;
+
+ // typeof(null) <-- non-null references or values
+ if (tob->ty == Tnull && t1b->ty != Tnull)
+ goto Lfail; // Bugzilla 14629
+ // typeof(null) --> non-null references or arithmetic values
+ if (t1b->ty == Tnull && tob->ty != Tnull)
+ goto Lok;
+
+ // Check size mismatch of references.
+ // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
+ if ((tob_isFR && t1b_isR) || (t1b_isFR && tob_isR))
+ {
+ if (tob->ty == Tpointer && t1b->ty == Tarray)
+ {
+ // T[] da;
+ // cast(U*)da; // ==> cast(U*)da.ptr;
+ goto Lok;
+ }
+ if (tob->ty == Tpointer && t1b->ty == Tdelegate)
+ {
+ // void delegate() dg;
+ // cast(U*)dg; // ==> cast(U*)dg.ptr;
+ // Note that it happens even when U is a Tfunction!
+ e->deprecation("casting from %s to %s is deprecated", e->type->toChars(), t->toChars());
+ goto Lok;
+ }
+ goto Lfail;
+ }
+
+ if (t1b->ty == Tvoid && tob->ty != Tvoid)
+ {
+ Lfail:
+ e->error("cannot cast expression %s of type %s to %s",
+ e->toChars(), e->type->toChars(), t->toChars());
+ result = new ErrorExp();
+ return;
+ }
+
+ Lok:
+ result = new CastExp(e->loc, e, t);
+ result->type = t; // Don't call semantic()
+ //printf("Returning: %s\n", result->toChars());
+ }
+
+ void visit(ErrorExp *e)
+ {
+ result = e;
+ }
+
+ void visit(RealExp *e)
+ {
+ if (!e->type->equals(t))
+ {
+ if ((e->type->isreal() && t->isreal()) ||
+ (e->type->isimaginary() && t->isimaginary())
+ )
+ {
+ result = e->copy();
+ result->type = t;
+ }
+ else
+ visit((Expression *)e);
+ return;
+ }
+ result = e;
+ }
+
+ void visit(ComplexExp *e)
+ {
+ if (!e->type->equals(t))
+ {
+ if (e->type->iscomplex() && t->iscomplex())
+ {
+ result = e->copy();
+ result->type = t;
+ }
+ else
+ visit((Expression *)e);
+ return;
+ }
+ result = e;
+ }
+
+ void visit(NullExp *e)
+ {
+ //printf("NullExp::castTo(t = %s) %s\n", t->toChars(), toChars());
+ visit((Expression *)e);
+ if (result->op == TOKnull)
+ {
+ NullExp *ex = (NullExp *)result;
+ ex->committed = 1;
+ return;
+ }
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ visit((Expression *)e);
+ if (result->op == TOKstructliteral)
+ ((StructLiteralExp *)result)->stype = t; // commit type
+ }
+
+ void visit(StringExp *e)
+ {
+ /* This follows copy-on-write; any changes to 'this'
+ * will result in a copy.
+ * The this->string member is considered immutable.
+ */
+ int copied = 0;
+
+ //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), e->toChars(), e->committed);
+
+ if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
+ {
+ e->error("cannot convert string literal to void*");
+ result = new ErrorExp();
+ return;
+ }
+
+ StringExp *se = e;
+ if (!e->committed)
+ {
+ se = (StringExp *)e->copy();
+ se->committed = 1;
+ copied = 1;
+ }
+
+ if (e->type->equals(t))
+ {
+ result = se;
+ return;
+ }
+
+ Type *tb = t->toBasetype();
+ //printf("\ttype = %s\n", e->type->toChars());
+ if (tb->ty == Tdelegate && e->type->toBasetype()->ty != Tdelegate)
+ {
+ visit((Expression *)e);
+ return;
+ }
+
+ Type *typeb = e->type->toBasetype();
+ if (typeb->equals(tb))
+ {
+ if (!copied)
+ {
+ se = (StringExp *)e->copy();
+ copied = 1;
+ }
+ se->type = t;
+ result = se;
+ return;
+ }
+
+ /* Handle reinterpret casts:
+ * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
+ * cast(wchar[2])"abcd"c --> [\u6261, \u6463]
+ * cast(wchar[1])"abcd"c --> [\u6261]
+ */
+ if (e->committed && tb->ty == Tsarray && typeb->ty == Tarray)
+ {
+ se = (StringExp *)e->copy();
+ d_uns64 szx = tb->nextOf()->size();
+ assert(szx <= 255);
+ se->sz = (unsigned char)szx;
+ se->len = (size_t)((TypeSArray *)tb)->dim->toInteger();
+ se->committed = 1;
+ se->type = t;
+
+ /* Assure space for terminating 0
+ */
+ if ((se->len + 1) * se->sz > (e->len + 1) * e->sz)
+ {
+ void *s = (void *)mem.xmalloc((se->len + 1) * se->sz);
+ memcpy(s, se->string, se->len * se->sz);
+ memset((char *)s + se->len * se->sz, 0, se->sz);
+ se->string = s;
+ }
+ result = se;
+ return;
+ }
+
+ if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
+ {
+ if (!copied)
+ {
+ se = (StringExp *)e->copy();
+ copied = 1;
+ }
+ goto Lcast;
+ }
+ if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
+ {
+ if (!copied)
+ {
+ se = (StringExp *)e->copy();
+ copied = 1;
+ }
+ goto Lcast;
+ }
+
+ if (typeb->nextOf()->size() == tb->nextOf()->size())
+ {
+ if (!copied)
+ {
+ se = (StringExp *)e->copy();
+ copied = 1;
+ }
+ if (tb->ty == Tsarray)
+ goto L2; // handle possible change in static array dimension
+ se->type = t;
+ result = se;
+ return;
+ }
+
+ if (e->committed)
+ goto Lcast;
+
+ #define X(tf,tt) ((int)(tf) * 256 + (int)(tt))
+ {
+ OutBuffer buffer;
+ size_t newlen = 0;
+ int tfty = typeb->nextOf()->toBasetype()->ty;
+ int ttty = tb->nextOf()->toBasetype()->ty;
+ switch (X(tfty, ttty))
+ {
+ case X(Tchar, Tchar):
+ case X(Twchar,Twchar):
+ case X(Tdchar,Tdchar):
+ break;
+
+ case X(Tchar, Twchar):
+ for (size_t u = 0; u < e->len;)
+ {
+ unsigned c;
+ const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c);
+ if (p)
+ e->error("%s", p);
+ else
+ buffer.writeUTF16(c);
+ }
+ newlen = buffer.offset / 2;
+ buffer.writeUTF16(0);
+ goto L1;
+
+ case X(Tchar, Tdchar):
+ for (size_t u = 0; u < e->len;)
+ {
+ unsigned c;
+ const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c);
+ if (p)
+ e->error("%s", p);
+ buffer.write4(c);
+ newlen++;
+ }
+ buffer.write4(0);
+ goto L1;
+
+ case X(Twchar,Tchar):
+ for (size_t u = 0; u < e->len;)
+ {
+ unsigned c;
+ const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c);
+ if (p)
+ e->error("%s", p);
+ else
+ buffer.writeUTF8(c);
+ }
+ newlen = buffer.offset;
+ buffer.writeUTF8(0);
+ goto L1;
+
+ case X(Twchar,Tdchar):
+ for (size_t u = 0; u < e->len;)
+ {
+ unsigned c;
+ const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c);
+ if (p)
+ e->error("%s", p);
+ buffer.write4(c);
+ newlen++;
+ }
+ buffer.write4(0);
+ goto L1;
+
+ case X(Tdchar,Tchar):
+ for (size_t u = 0; u < e->len; u++)
+ {
+ unsigned c = ((unsigned *)se->string)[u];
+ if (!utf_isValidDchar(c))
+ e->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 (size_t u = 0; u < e->len; u++)
+ {
+ unsigned c = ((unsigned *)se->string)[u];
+ if (!utf_isValidDchar(c))
+ e->error("invalid UCS-32 char \\U%08x", c);
+ else
+ buffer.writeUTF16(c);
+ newlen++;
+ }
+ newlen = buffer.offset / 2;
+ buffer.writeUTF16(0);
+ goto L1;
+
+ L1:
+ if (!copied)
+ {
+ se = (StringExp *)e->copy();
+ copied = 1;
+ }
+ se->string = buffer.extractData();
+ se->len = newlen;
+
+ {
+ d_uns64 szx = tb->nextOf()->size();
+ assert(szx <= 255);
+ se->sz = (unsigned char)szx;
+ }
+ break;
+
+ default:
+ assert(typeb->nextOf()->size() != tb->nextOf()->size());
+ goto Lcast;
+ }
+ }
+ #undef X
+ L2:
+ assert(copied);
+
+ // See if need to truncate or extend the literal
+ if (tb->ty == Tsarray)
+ {
+ size_t dim2 = (size_t)((TypeSArray *)tb)->dim->toInteger();
+
+ //printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2);
+
+ // Changing dimensions
+ if (dim2 != se->len)
+ {
+ // Copy when changing the string literal
+ size_t newsz = se->sz;
+ size_t d = (dim2 < se->len) ? dim2 : se->len;
+ void *s = (void *)mem.xmalloc((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->string = s;
+ se->len = dim2;
+ }
+ }
+ se->type = t;
+ result = se;
+ return;
+
+ Lcast:
+ result = new CastExp(e->loc, se, t);
+ result->type = t; // so semantic() won't be run on e
+ }
+
+ void visit(AddrExp *e)
+ {
+ Type *tb;
+
+ result = e;
+
+ tb = t->toBasetype();
+ e->type = e->type->toBasetype();
+ if (!tb->equals(e->type))
+ {
+ // Look for pointers to functions where the functions are overloaded.
+
+ if (e->e1->op == TOKoverloadset &&
+ (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
+ {
+ OverExp *eo = (OverExp *)e->e1;
+ FuncDeclaration *f = NULL;
+ for (size_t i = 0; i < eo->vars->a.dim; i++)
+ {
+ Dsymbol *s = eo->vars->a[i];
+ FuncDeclaration *f2 = s->isFuncDeclaration();
+ assert(f2);
+ if (f2->overloadExactMatch(t->nextOf()))
+ {
+ if (f)
+ {
+ /* Error if match in more than one overload set,
+ * even if one is a 'better' match than the other.
+ */
+ ScopeDsymbol::multiplyDefined(e->loc, f, f2);
+ }
+ else
+ f = f2;
+ }
+ }
+ if (f)
+ {
+ f->tookAddressOf++;
+ SymOffExp *se = new SymOffExp(e->loc, f, 0, false);
+ ::semantic(se, sc);
+ // Let SymOffExp::castTo() do the heavy lifting
+ visit(se);
+ return;
+ }
+ }
+
+ if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
+ tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
+ e->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e->e1;
+ FuncDeclaration *f = ve->var->isFuncDeclaration();
+ if (f)
+ {
+ assert(f->isImportedSymbol());
+ f = f->overloadExactMatch(tb->nextOf());
+ if (f)
+ {
+ result = new VarExp(e->loc, f, false);
+ result->type = f->type;
+ result = new AddrExp(e->loc, result, t);
+ return;
+ }
+ }
+ }
+
+ if (FuncDeclaration *f = isFuncAddress(e))
+ {
+ if (f->checkForwardRef(e->loc))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ visit((Expression *)e);
+ }
+ result->type = t;
+ }
+
+ void visit(TupleExp *e)
+ {
+ if (e->type->equals(t))
+ {
+ result = e;
+ return;
+ }
+
+ TupleExp *te = (TupleExp *)e->copy();
+ te->e0 = e->e0 ? e->e0->copy() : NULL;
+ te->exps = (Expressions *)e->exps->copy();
+ for (size_t i = 0; i < te->exps->dim; i++)
+ {
+ Expression *ex = (*te->exps)[i];
+ ex = ex->castTo(sc, t);
+ (*te->exps)[i] = ex;
+ }
+ result = te;
+
+ /* Questionable behavior: In here, result->type is not set to t.
+ * Therefoe:
+ * TypeTuple!(int, int) values;
+ * auto values2 = cast(long)values;
+ * // typeof(values2) == TypeTuple!(int, int) !!
+ *
+ * Only when the casted tuple is immediately expanded, it would work.
+ * auto arr = [cast(long)values];
+ * // typeof(arr) == long[]
+ */
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ if (e->type == t)
+ {
+ result = e;
+ return;
+ }
+ ArrayLiteralExp *ae = e;
+ Type *typeb = e->type->toBasetype();
+ Type *tb = t->toBasetype();
+ if ((tb->ty == Tarray || tb->ty == Tsarray) &&
+ (typeb->ty == Tarray || typeb->ty == Tsarray))
+ {
+ if (tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)
+ {
+ // Don't do anything to cast non-void[] to void[]
+ }
+ else if (typeb->ty == Tsarray && typeb->nextOf()->toBasetype()->ty == Tvoid)
+ {
+ // Don't do anything for casting void[n] to others
+ }
+ else
+ {
+ if (tb->ty == Tsarray)
+ {
+ TypeSArray *tsa = (TypeSArray *)tb;
+ if (e->elements->dim != tsa->dim->toInteger())
+ goto L1;
+ }
+
+ ae = (ArrayLiteralExp *)e->copy();
+ if (e->basis)
+ ae->basis = e->basis->castTo(sc, tb->nextOf());
+ ae->elements = e->elements->copy();
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *ex = (*e->elements)[i];
+ if (!ex)
+ continue;
+ ex = ex->castTo(sc, tb->nextOf());
+ (*ae->elements)[i] = ex;
+ }
+ ae->type = t;
+ result = ae;
+ return;
+ }
+ }
+ else if (tb->ty == Tpointer && typeb->ty == Tsarray)
+ {
+ Type *tp = typeb->nextOf()->pointerTo();
+ if (!tp->equals(ae->type))
+ {
+ ae = (ArrayLiteralExp *)e->copy();
+ ae->type = tp;
+ }
+ }
+ else if (tb->ty == Tvector &&
+ (typeb->ty == Tarray || typeb->ty == Tsarray))
+ {
+ // Convert array literal to vector type
+ TypeVector *tv = (TypeVector *)tb;
+ TypeSArray *tbase = (TypeSArray *)tv->basetype;
+ assert(tbase->ty == Tsarray);
+ const size_t edim = e->elements->dim;
+ const size_t tbasedim = tbase->dim->toInteger();
+ if (edim > tbasedim)
+ goto L1;
+
+ ae = (ArrayLiteralExp *)e->copy();
+ ae->type = tbase; // Bugzilla 12642
+ ae->elements = e->elements->copy();
+ Type *telement = tv->elementType();
+ for (size_t i = 0; i < edim; i++)
+ {
+ Expression *ex = (*e->elements)[i];
+ ex = ex->castTo(sc, telement);
+ (*ae->elements)[i] = ex;
+ }
+ // Fill in the rest with the default initializer
+ ae->elements->setDim(tbasedim);
+ for (size_t i = edim; i < tbasedim; i++)
+ {
+ Expression *ex = typeb->nextOf()->defaultInitLiteral(e->loc);
+ ex = ex->castTo(sc, telement);
+ (*ae->elements)[i] = ex;
+ }
+ Expression *ev = new VectorExp(e->loc, ae, tb);
+ ev = ::semantic(ev, sc);
+ result = ev;
+ return;
+ }
+ L1:
+ visit((Expression *)ae);
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ if (e->type == t)
+ {
+ result = e;
+ return;
+ }
+ Type *typeb = e->type->toBasetype();
+ Type *tb = t->toBasetype();
+ if (tb->ty == Taarray && typeb->ty == Taarray &&
+ tb->nextOf()->toBasetype()->ty != Tvoid)
+ {
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e->copy();
+ ae->keys = e->keys->copy();
+ ae->values = e->values->copy();
+ assert(e->keys->dim == e->values->dim);
+ for (size_t i = 0; i < e->keys->dim; i++)
+ {
+ Expression *ex = (*e->values)[i];
+ ex = ex->castTo(sc, tb->nextOf());
+ (*ae->values)[i] = ex;
+
+ ex = (*e->keys)[i];
+ ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
+ (*ae->keys)[i] = ex;
+ }
+ ae->type = t;
+ result = ae;
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(SymOffExp *e)
+ {
+ if (e->type == t && !e->hasOverloads)
+ {
+ result = e;
+ return;
+ }
+ Type *tb = t->toBasetype();
+ Type *typeb = e->type->toBasetype();
+
+ if (tb->equals(typeb))
+ {
+ result = e->copy();
+ result->type = t;
+ ((SymOffExp *)result)->hasOverloads = false;
+ return;
+ }
+
+ // Look for pointers to functions where the functions are overloaded.
+ if (e->hasOverloads &&
+ typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
+ (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
+ {
+ FuncDeclaration *f = e->var->isFuncDeclaration();
+ f = f ? f->overloadExactMatch(tb->nextOf()) : NULL;
+ if (f)
+ {
+ if (tb->ty == Tdelegate)
+ {
+ if (f->needThis() && hasThis(sc))
+ {
+ result = new DelegateExp(e->loc, new ThisExp(e->loc), f, false);
+ result = ::semantic(result, sc);
+ }
+ else if (f->isNested())
+ {
+ result = new DelegateExp(e->loc, new IntegerExp(0), f, false);
+ result = ::semantic(result, sc);
+ }
+ else if (f->needThis())
+ {
+ e->error("no 'this' to create delegate for %s", f->toChars());
+ result = new ErrorExp();
+ return;
+ }
+ else
+ {
+ e->error("cannot cast from function pointer to delegate");
+ result = new ErrorExp();
+ return;
+ }
+ }
+ else
+ {
+ result = new SymOffExp(e->loc, f, 0, false);
+ result->type = t;
+ }
+ f->tookAddressOf++;
+ return;
+ }
+ }
+
+ if (FuncDeclaration *f = isFuncAddress(e))
+ {
+ if (f->checkForwardRef(e->loc))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ visit((Expression *)e);
+ }
+
+ void visit(DelegateExp *e)
+ {
+ static const char msg[] = "cannot form delegate due to covariant return type";
+
+ Type *tb = t->toBasetype();
+ Type *typeb = e->type->toBasetype();
+ if (!tb->equals(typeb) || e->hasOverloads)
+ {
+ // Look for delegates to functions where the functions are overloaded.
+ if (typeb->ty == Tdelegate &&
+ tb->ty == Tdelegate)
+ {
+ if (e->func)
+ {
+ FuncDeclaration *f = e->func->overloadExactMatch(tb->nextOf());
+ if (f)
+ {
+ int offset;
+ if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
+ e->error("%s", msg);
+ if (f != e->func) // if address not already marked as taken
+ f->tookAddressOf++;
+ result = new DelegateExp(e->loc, e->e1, f, false);
+ result->type = t;
+ return;
+ }
+ if (e->func->tintro)
+ e->error("%s", msg);
+ }
+ }
+
+ if (FuncDeclaration *f = isFuncAddress(e))
+ {
+ if (f->checkForwardRef(e->loc))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ visit((Expression *)e);
+ }
+ else
+ {
+ int offset;
+ e->func->tookAddressOf++;
+ if (e->func->tintro && e->func->tintro->nextOf()->isBaseOf(e->func->type->nextOf(), &offset) && offset)
+ e->error("%s", msg);
+ result = e->copy();
+ result->type = t;
+ }
+ }
+
+ void visit(FuncExp *e)
+ {
+ //printf("FuncExp::castTo type = %s, t = %s\n", e->type->toChars(), t->toChars());
+ FuncExp *fe;
+ if (e->matchType(t, sc, &fe, 1) > MATCHnomatch)
+ {
+ result = fe;
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(CondExp *e)
+ {
+ if (!e->type->equals(t))
+ {
+ result = new CondExp(e->loc, e->econd, e->e1->castTo(sc, t), e->e2->castTo(sc, t));
+ result->type = t;
+ return;
+ }
+ result = e;
+ }
+
+ void visit(CommaExp *e)
+ {
+ Expression *e2c = e->e2->castTo(sc, t);
+
+ if (e2c != e->e2)
+ {
+ result = new CommaExp(e->loc, e->e1, e2c);
+ result->type = e2c->type;
+ }
+ else
+ {
+ result = e;
+ result->type = e->e2->type;
+ }
+ }
+
+ void visit(SliceExp *e)
+ {
+ //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e->toChars(), e->type->toChars(), t->toChars());
+ Type *typeb = e->type->toBasetype();
+ Type *tb = t->toBasetype();
+ if (e->type->equals(t) || typeb->ty != Tarray ||
+ (tb->ty != Tarray && tb->ty != Tsarray))
+ {
+ visit((Expression *)e);
+ return;
+ }
+
+ if (tb->ty == Tarray)
+ {
+ if (typeb->nextOf()->equivalent(tb->nextOf()))
+ {
+ // T[] to const(T)[]
+ result = e->copy();
+ result->type = t;
+ }
+ else
+ {
+ visit((Expression *)e);
+ }
+ return;
+ }
+
+ // Handle the cast from Tarray to Tsarray with CT-known slicing
+
+ TypeSArray *tsa = (TypeSArray *)toStaticArrayType(e);
+ if (tsa && tsa->size(e->loc) == tb->size(e->loc))
+ {
+ /* Match if the sarray sizes are equal:
+ * T[a .. b] to const(T)[b-a]
+ * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
+ *
+ * If a SliceExp has Tsarray, it will become lvalue.
+ * That's handled in SliceExp::isLvalue and toLvalue
+ */
+ result = e->copy();
+ result->type = t;
+ return;
+ }
+ if (tsa && tsa->dim->equals(((TypeSArray *)tb)->dim))
+ {
+ /* Match if the dimensions are equal
+ * with the implicit conversion of e->e1:
+ * cast(float[2]) [2.0, 1.0, 0.0][0..2];
+ */
+ Type *t1b = e->e1->type->toBasetype();
+ if (t1b->ty == Tsarray)
+ t1b = tb->nextOf()->sarrayOf(((TypeSArray *)t1b)->dim->toInteger());
+ else if (t1b->ty == Tarray)
+ t1b = tb->nextOf()->arrayOf();
+ else if (t1b->ty == Tpointer)
+ t1b = tb->nextOf()->pointerTo();
+ else
+ assert(0);
+ if (e->e1->implicitConvTo(t1b) > MATCHnomatch)
+ {
+ Expression *e1x = e->e1->implicitCastTo(sc, t1b);
+ assert(e1x->op != TOKerror);
+ e = (SliceExp *)e->copy();
+ e->e1 = e1x;
+ e->type = t;
+ result = e;
+ return;
+ }
+ }
+ e->error("cannot cast expression %s of type %s to %s",
+ e->toChars(), tsa ? tsa->toChars() : e->type->toChars(),
+ t->toChars());
+ result = new ErrorExp();
+ }
+ };
+
+ CastTo v(sc, t);
+ e->accept(&v);
+ return v.result;
+}
+
+/* ==================== inferType ====================== */
+
+/****************************************
+ * Set type inference target
+ * t Target type
+ * flag 1: don't put an error when inference fails
+ */
+
+Expression *inferType(Expression *e, Type *t, int flag)
+{
+ class InferType : public Visitor
+ {
+ public:
+ Type *t;
+ int flag;
+ Expression *result;
+
+ InferType(Type *t, int flag)
+ : t(t), flag(flag)
+ {
+ result = NULL;
+ }
+
+
+ void visit(Expression *e)
+ {
+ result = e;
+ }
+
+ void visit(ArrayLiteralExp *ale)
+ {
+ Type *tb = t->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ Type *tn = tb->nextOf();
+ if (ale->basis)
+ ale->basis = inferType(ale->basis, tn, flag);
+ for (size_t i = 0; i < ale->elements->dim; i++)
+ {
+ Expression *e = (*ale->elements)[i];
+ if (e)
+ {
+ e = inferType(e, tn, flag);
+ (*ale->elements)[i] = e;
+ }
+ }
+ }
+ result = ale;
+ }
+
+ void visit(AssocArrayLiteralExp *aale)
+ {
+ Type *tb = t->toBasetype();
+ if (tb->ty == Taarray)
+ {
+ TypeAArray *taa = (TypeAArray *)tb;
+ Type *ti = taa->index;
+ Type *tv = taa->nextOf();
+ for (size_t i = 0; i < aale->keys->dim; i++)
+ {
+ Expression *e = (*aale->keys)[i];
+ if (e)
+ {
+ e = inferType(e, ti, flag);
+ (*aale->keys)[i] = e;
+ }
+ }
+ for (size_t i = 0; i < aale->values->dim; i++)
+ {
+ Expression *e = (*aale->values)[i];
+ if (e)
+ {
+ e = inferType(e, tv, flag);
+ (*aale->values)[i] = e;
+ }
+ }
+ }
+ result = aale;
+ }
+
+ void visit(FuncExp *fe)
+ {
+ //printf("FuncExp::inferType('%s'), to=%s\n", fe->type ? fe->type->toChars() : "null", t->toChars());
+ if (t->ty == Tdelegate ||
+ (t->ty == Tpointer && t->nextOf()->ty == Tfunction))
+ {
+ fe->fd->treq = t;
+ }
+ result = fe;
+ }
+
+ void visit(CondExp *ce)
+ {
+ Type *tb = t->toBasetype();
+ ce->e1 = inferType(ce->e1, tb, flag);
+ ce->e2 = inferType(ce->e2, tb, flag);
+ result = ce;
+ }
+ };
+
+ if (!t)
+ return e;
+
+ InferType v(t, flag);
+ e->accept(&v);
+ return v.result;
+}
+
+/* ==================== ====================== */
+
+/****************************************
+ * Scale addition/subtraction to/from pointer.
+ */
+
+Expression *scaleFactor(BinExp *be, Scope *sc)
+{
+ Type *t1b = be->e1->type->toBasetype();
+ Type *t2b = be->e2->type->toBasetype();
+ Expression *eoff;
+
+ 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;
+
+ d_uns64 stride = t1b->nextOf()->size(be->loc);
+ if (!t->equals(t2b))
+ be->e2 = be->e2->castTo(sc, t);
+ eoff = be->e2;
+ be->e2 = new MulExp(be->loc, be->e2, new IntegerExp(Loc(), stride, t));
+ be->e2->type = t;
+ be->type = be->e1->type;
+ }
+ else if (t2b->ty == Tpointer && t1b->isintegral())
+ {
+ // Need to adjust operator by the stride
+ // Replace (int + ptr) with (ptr + (int * stride))
+ Type *t = Type::tptrdiff_t;
+ Expression *e;
+
+ d_uns64 stride = t2b->nextOf()->size(be->loc);
+ if (!t->equals(t1b))
+ e = be->e1->castTo(sc, t);
+ else
+ e = be->e1;
+ eoff = e;
+ e = new MulExp(be->loc, e, new IntegerExp(Loc(), stride, t));
+ e->type = t;
+ be->type = be->e2->type;
+ be->e1 = be->e2;
+ be->e2 = e;
+ }
+ else
+ assert(0);
+
+ if (sc->func && !sc->intypeof)
+ {
+ eoff = eoff->optimize(WANTvalue);
+ if (eoff->op == TOKint64 && eoff->toInteger() == 0)
+ ;
+ else if (sc->func->setUnsafe())
+ {
+ be->error("pointer arithmetic not allowed in @safe functions");
+ return new ErrorExp();
+ }
+ }
+
+ return be;
+}
+
+/**************************************
+ * Return true if e is an empty array literal with dimensionality
+ * equal to or less than type of other array.
+ * [], [[]], [[[]]], etc.
+ * I.e., make sure that [1,2] is compatible with [],
+ * [[1,2]] is compatible with [[]], etc.
+ */
+bool isVoidArrayLiteral(Expression *e, Type *other)
+{
+ while (e->op == TOKarrayliteral && e->type->ty == Tarray
+ && (((ArrayLiteralExp *)e)->elements->dim == 1))
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+ e = ale->getElement(0);
+ if (other->ty == Tsarray || other->ty == Tarray)
+ other = other->nextOf();
+ else
+ return false;
+ }
+ if (other->ty != Tsarray && other->ty != Tarray)
+ return false;
+ Type *t = e->type;
+ return (e->op == TOKarrayliteral && t->ty == Tarray &&
+ t->nextOf()->ty == Tvoid &&
+ ((ArrayLiteralExp *)e)->elements->dim == 0);
+}
+
+// used by deduceType()
+Type *rawTypeMerge(Type *t1, Type *t2)
+{
+ if (t1->equals(t2))
+ return t1;
+ if (t1->equivalent(t2))
+ return t1->castMod(MODmerge(t1->mod, t2->mod));
+
+ Type *t1b = t1->toBasetype();
+ Type *t2b = t2->toBasetype();
+ if (t1b->equals(t2b))
+ return t1b;
+ if (t1b->equivalent(t2b))
+ return t1b->castMod(MODmerge(t1b->mod, t2b->mod));
+
+ TY ty = (TY)impcnvResult[t1b->ty][t2b->ty];
+ if (ty != Terror)
+ return Type::basic[ty];
+
+ return NULL;
+}
+
+/**************************************
+ * Combine types.
+ * Output:
+ * *pt merged type, if *pt is not NULL
+ * *pe1 rewritten e1
+ * *pe2 rewritten e2
+ * Returns:
+ * true success
+ * false failed
+ */
+
+bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2)
+{
+ //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
+
+ MATCH m;
+ Expression *e1 = *pe1;
+ Expression *e2 = *pe2;
+ Type *t1b = e1->type->toBasetype();
+ Type *t2b = e2->type->toBasetype();
+
+ if (op != TOKquestion ||
+ (t1b->ty != t2b->ty && (t1b->isTypeBasic() && t2b->isTypeBasic())))
+ {
+ e1 = integralPromotions(e1, sc);
+ e2 = integralPromotions(e2, sc);
+ }
+
+ Type *t1 = e1->type;
+ Type *t2 = e2->type;
+ assert(t1);
+ Type *t = t1;
+
+ /* The start type of alias this type recursion.
+ * In following case, we should save A, and stop recursion
+ * if it appears again.
+ * X -> Y -> [A] -> B -> A -> B -> ...
+ */
+ Type *att1 = NULL;
+ Type *att2 = NULL;
+
+ //if (t1) printf("\tt1 = %s\n", t1->toChars());
+ //if (t2) printf("\tt2 = %s\n", t2->toChars());
+ assert(t2);
+
+ if (t1->mod != t2->mod &&
+ t1->ty == Tenum && t2->ty == Tenum &&
+ ((TypeEnum *)t1)->sym == ((TypeEnum *)t2)->sym)
+ {
+ unsigned char mod = MODmerge(t1->mod, t2->mod);
+ t1 = t1->castMod(mod);
+ t2 = t2->castMod(mod);
+ }
+
+Lagain:
+ t1b = t1->toBasetype();
+ t2b = t2->toBasetype();
+
+ TY ty = (TY)impcnvResult[t1b->ty][t2b->ty];
+ if (ty != Terror)
+ {
+ TY ty1 = (TY)impcnvType1[t1b->ty][t2b->ty];
+ TY ty2 = (TY)impcnvType2[t1b->ty][t2b->ty];
+
+ if (t1b->ty == ty1) // if no promotions
+ {
+ if (t1->equals(t2))
+ {
+ t = t1;
+ goto Lret;
+ }
+
+ if (t1b->equals(t2b))
+ {
+ t = t1b;
+ goto Lret;
+ }
+ }
+
+ t = Type::basic[ty];
+
+ t1 = Type::basic[ty1];
+ t2 = Type::basic[ty2];
+ e1 = e1->castTo(sc, t1);
+ e2 = e2->castTo(sc, t2);
+ //printf("after typeCombine():\n");
+ //print();
+ //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
+ goto Lret;
+ }
+
+ t1 = t1b;
+ t2 = t2b;
+
+ if (t1->ty == Ttuple || t2->ty == Ttuple)
+ goto Lincompatible;
+
+ if (t1->equals(t2))
+ {
+ // merging can not result in new enum type
+ if (t->ty == Tenum)
+ t = t1b;
+ }
+ else if ((t1->ty == Tpointer && t2->ty == Tpointer) ||
+ (t1->ty == Tdelegate && t2->ty == Tdelegate))
+ {
+ // Bring pointers to compatible type
+ Type *t1n = t1->nextOf();
+ Type *t2n = t2->nextOf();
+
+ if (t1n->equals(t2n))
+ ;
+ else if (t1n->ty == Tvoid) // pointers to void are always compatible
+ t = t2;
+ else if (t2n->ty == Tvoid)
+ ;
+ else if (t1->implicitConvTo(t2))
+ {
+ goto Lt2;
+ }
+ else if (t2->implicitConvTo(t1))
+ {
+ goto Lt1;
+ }
+ else if (t1n->ty == Tfunction && t2n->ty == Tfunction)
+ {
+ TypeFunction *tf1 = (TypeFunction *)t1n;
+ TypeFunction *tf2 = (TypeFunction *)t2n;
+ tf1->purityLevel();
+ tf2->purityLevel();
+
+ TypeFunction *d = (TypeFunction *)tf1->syntaxCopy();
+
+ if (tf1->purity != tf2->purity)
+ d->purity = PUREimpure;
+ assert(d->purity != PUREfwdref);
+
+ d->isnothrow = (tf1->isnothrow && tf2->isnothrow);
+ d->isnogc = (tf1->isnogc && tf2->isnogc);
+
+ if (tf1->trust == tf2->trust)
+ d->trust = tf1->trust;
+ else if (tf1->trust <= TRUSTsystem || tf2->trust <= TRUSTsystem)
+ d->trust = TRUSTsystem;
+ else
+ d->trust = TRUSTtrusted;
+
+ Type *tx = NULL;
+ if (t1->ty == Tdelegate)
+ {
+ tx = new TypeDelegate(d);
+ }
+ else
+ tx = d->pointerTo();
+
+ tx = tx->semantic(e1->loc, sc);
+
+ if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx))
+ {
+ t = tx;
+ e1 = e1->castTo(sc, t);
+ e2 = e2->castTo(sc, t);
+ goto Lret;
+ }
+ goto Lincompatible;
+ }
+ else if (t1n->mod != t2n->mod)
+ {
+ if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
+ goto Lincompatible;
+ unsigned char mod = MODmerge(t1n->mod, t2n->mod);
+ t1 = t1n->castMod(mod)->pointerTo();
+ t2 = t2n->castMod(mod)->pointerTo();
+ t = t1;
+ goto Lagain;
+ }
+ 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
+ {
+ t1 = t1n->constOf()->pointerTo();
+ t2 = t2n->constOf()->pointerTo();
+ if (t1->implicitConvTo(t2))
+ {
+ goto Lt2;
+ }
+ else if (t2->implicitConvTo(t1))
+ {
+ goto Lt1;
+ }
+ goto Lincompatible;
+ }
+ }
+ else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+ ((e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) ||
+ (e2->op == TOKarrayliteral && t2->ty == Tsarray && t2->nextOf()->ty == Tvoid && ((TypeSArray *)t2)->dim->toInteger() == 0) ||
+ (isVoidArrayLiteral(e2, t1)))
+ )
+ {
+ /* (T[n] op void*) => T[]
+ * (T[] op void*) => T[]
+ * (T[n] op void[0]) => T[]
+ * (T[] op void[0]) => T[]
+ * (T[n] op void[]) => T[]
+ * (T[] op void[]) => T[]
+ */
+ goto Lx1;
+ }
+ else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
+ ((e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) ||
+ (e1->op == TOKarrayliteral && t1->ty == Tsarray && t1->nextOf()->ty == Tvoid && ((TypeSArray *)t1)->dim->toInteger() == 0) ||
+ (isVoidArrayLiteral(e1, t2)))
+ )
+ {
+ /* (void* op T[n]) => T[]
+ * (void* op T[]) => T[]
+ * (void[0] op T[n]) => T[]
+ * (void[0] op T[]) => T[]
+ * (void[] op T[n]) => T[]
+ * (void[] op T[]) => T[]
+ */
+ goto Lx2;
+ }
+ else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
+ (m = t1->implicitConvTo(t2)) != MATCHnomatch)
+ {
+ // Bugzilla 7285: Tsarray op [x, y, ...] should to be Tsarray
+ // Bugzilla 14737: Tsarray ~ [x, y, ...] should to be Tarray
+ if (t1->ty == Tsarray && e2->op == TOKarrayliteral && op != TOKcat)
+ goto Lt1;
+ if (m == MATCHconst &&
+ (op == TOKaddass || op == TOKminass || op == TOKmulass ||
+ op == TOKdivass || op == TOKmodass || op == TOKpowass ||
+ op == TOKandass || op == TOKorass || op == TOKxorass)
+ )
+ {
+ // Don't make the lvalue const
+ t = t2;
+ goto Lret;
+ }
+ goto Lt2;
+ }
+ else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
+ {
+ // Bugzilla 7285 & 14737
+ if (t2->ty == Tsarray && e1->op == TOKarrayliteral && op != TOKcat)
+ goto Lt2;
+ goto Lt1;
+ }
+ else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
+ (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
+ t1->nextOf()->mod != t2->nextOf()->mod
+ )
+ {
+ /* If one is mutable and the other invariant, then retry
+ * with both of them as const
+ */
+ Type *t1n = t1->nextOf();
+ Type *t2n = t2->nextOf();
+ unsigned char mod;
+ if (e1->op == TOKnull && e2->op != TOKnull)
+ mod = t2n->mod;
+ else if (e1->op != TOKnull && e2->op == TOKnull)
+ mod = t1n->mod;
+ else if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
+ goto Lincompatible;
+ else
+ mod = MODmerge(t1n->mod, t2n->mod);
+
+ if (t1->ty == Tpointer)
+ t1 = t1n->castMod(mod)->pointerTo();
+ else
+ t1 = t1n->castMod(mod)->arrayOf();
+
+ if (t2->ty == Tpointer)
+ t2 = t2n->castMod(mod)->pointerTo();
+ else
+ t2 = t2n->castMod(mod)->arrayOf();
+ t = t1;
+ goto Lagain;
+ }
+ else if (t1->ty == Tclass && t2->ty == Tclass)
+ {
+ if (t1->mod != t2->mod)
+ {
+ unsigned char mod;
+ if (e1->op == TOKnull && e2->op != TOKnull)
+ mod = t2->mod;
+ else if (e1->op != TOKnull && e2->op == TOKnull)
+ mod = t1->mod;
+ else if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
+ goto Lincompatible;
+ else
+ mod = MODmerge(t1->mod, t2->mod);
+ t1 = t1->castMod(mod);
+ t2 = t2->castMod(mod);
+ t = t1;
+ goto Lagain;
+ }
+ goto Lcc;
+ }
+ else if (t1->ty == Tclass || t2->ty == Tclass)
+ {
+Lcc:
+ while (1)
+ {
+ MATCH i1 = e2->implicitConvTo(t1);
+ MATCH i2 = e1->implicitConvTo(t2);
+
+ if (i1 && i2)
+ {
+ // We have the case of class vs. void*, so pick class
+ if (t1->ty == Tpointer)
+ i1 = MATCHnomatch;
+ else if (t2->ty == Tpointer)
+ i2 = MATCHnomatch;
+ }
+
+ if (i2)
+ {
+ e2 = e2->castTo(sc, t2);
+ goto Lt2;
+ }
+ else if (i1)
+ {
+ e1 = e1->castTo(sc, t1);
+ goto Lt1;
+ }
+ else if (t1->ty == Tclass && t2->ty == Tclass)
+ {
+ TypeClass *tc1 = (TypeClass *)t1;
+ TypeClass *tc2 = (TypeClass *)t2;
+
+ /* Pick 'tightest' type
+ */
+ ClassDeclaration *cd1 = tc1->sym->baseClass;
+ ClassDeclaration *cd2 = tc2->sym->baseClass;
+
+ if (cd1 && cd2)
+ {
+ t1 = cd1->type->castMod(t1->mod);
+ t2 = cd2->type->castMod(t2->mod);
+ }
+ else if (cd1)
+ t1 = cd1->type;
+ else if (cd2)
+ t2 = cd2->type;
+ else
+ goto Lincompatible;
+ }
+ else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
+ {
+ if (att1 && e1->type == att1)
+ goto Lincompatible;
+ if (!att1 && e1->type->checkAliasThisRec())
+ att1 = e1->type;
+ //printf("att tmerge(c || c) e1 = %s\n", e1->type->toChars());
+ e1 = resolveAliasThis(sc, e1);
+ t1 = e1->type;
+ continue;
+ }
+ else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
+ {
+ if (att2 && e2->type == att2)
+ goto Lincompatible;
+ if (!att2 && e2->type->checkAliasThisRec())
+ att2 = e2->type;
+ //printf("att tmerge(c || c) e2 = %s\n", e2->type->toChars());
+ e2 = resolveAliasThis(sc, e2);
+ t2 = e2->type;
+ continue;
+ }
+ else
+ goto Lincompatible;
+ }
+ }
+ else if (t1->ty == Tstruct && t2->ty == Tstruct)
+ {
+ if (t1->mod != t2->mod)
+ {
+ if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
+ goto Lincompatible;
+ unsigned char mod = MODmerge(t1->mod, t2->mod);
+ t1 = t1->castMod(mod);
+ t2 = t2->castMod(mod);
+ t = t1;
+ goto Lagain;
+ }
+
+ TypeStruct *ts1 = (TypeStruct *)t1;
+ TypeStruct *ts2 = (TypeStruct *)t2;
+ if (ts1->sym != ts2->sym)
+ {
+ if (!ts1->sym->aliasthis && !ts2->sym->aliasthis)
+ goto Lincompatible;
+
+ MATCH i1 = MATCHnomatch;
+ MATCH i2 = MATCHnomatch;
+
+ Expression *e1b = NULL;
+ Expression *e2b = NULL;
+ if (ts2->sym->aliasthis)
+ {
+ if (att2 && e2->type == att2)
+ goto Lincompatible;
+ if (!att2 && e2->type->checkAliasThisRec())
+ att2 = e2->type;
+ //printf("att tmerge(s && s) e2 = %s\n", e2->type->toChars());
+ e2b = resolveAliasThis(sc, e2);
+ i1 = e2b->implicitConvTo(t1);
+ }
+ if (ts1->sym->aliasthis)
+ {
+ if (att1 && e1->type == att1)
+ goto Lincompatible;
+ if (!att1 && e1->type->checkAliasThisRec())
+ att1 = e1->type;
+ //printf("att tmerge(s && s) e1 = %s\n", e1->type->toChars());
+ e1b = resolveAliasThis(sc, e1);
+ i2 = e1b->implicitConvTo(t2);
+ }
+ if (i1 && i2)
+ goto Lincompatible;
+
+ if (i1)
+ goto Lt1;
+ else if (i2)
+ goto Lt2;
+
+ if (e1b)
+ {
+ e1 = e1b;
+ t1 = e1b->type->toBasetype();
+ }
+ if (e2b)
+ {
+ e2 = e2b;
+ t2 = e2b->type->toBasetype();
+ }
+ t = t1;
+ goto Lagain;
+ }
+ }
+ else if (t1->ty == Tstruct || t2->ty == Tstruct)
+ {
+ if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
+ {
+ if (att1 && e1->type == att1)
+ goto Lincompatible;
+ if (!att1 && e1->type->checkAliasThisRec())
+ att1 = e1->type;
+ //printf("att tmerge(s || s) e1 = %s\n", e1->type->toChars());
+ e1 = resolveAliasThis(sc, e1);
+ t1 = e1->type;
+ t = t1;
+ goto Lagain;
+ }
+ if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
+ {
+ if (att2 && e2->type == att2)
+ goto Lincompatible;
+ if (!att2 && e2->type->checkAliasThisRec())
+ att2 = e2->type;
+ //printf("att tmerge(s || s) e2 = %s\n", e2->type->toChars());
+ e2 = resolveAliasThis(sc, e2);
+ t2 = e2->type;
+ t = t2;
+ goto Lagain;
+ }
+ goto Lincompatible;
+ }
+ else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
+ {
+ goto Lt2;
+ }
+ else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
+ {
+ goto Lt1;
+ }
+ else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+ e2->implicitConvTo(t1->nextOf()->arrayOf()))
+ {
+ Lx1:
+ t = t1->nextOf()->arrayOf(); // T[]
+ e1 = e1->castTo(sc, t);
+ e2 = e2->castTo(sc, t);
+ }
+ else if (t1->ty == Tsarray && t2->ty == Tsarray &&
+ e1->implicitConvTo(t2->nextOf()->arrayOf()))
+ {
+ Lx2:
+ t = t2->nextOf()->arrayOf();
+ e1 = e1->castTo(sc, t);
+ e2 = e2->castTo(sc, t);
+ }
+ else if (t1->ty == Tvector && t2->ty == Tvector)
+ {
+ // Bugzilla 13841, all vector types should have no common types between
+ // different vectors, even though their sizes are same.
+ TypeVector *tv1 = (TypeVector *)t1;
+ TypeVector *tv2 = (TypeVector *)t2;
+ if (!tv1->basetype->equals(tv2->basetype))
+ goto Lincompatible;
+
+ goto LmodCompare;
+ }
+ else if (t1->ty == Tvector && t2->ty != Tvector &&
+ e2->implicitConvTo(t1))
+ {
+ e2 = e2->castTo(sc, t1);
+ t2 = t1;
+ t = t1;
+ goto Lagain;
+ }
+ else if (t2->ty == Tvector && t1->ty != Tvector &&
+ e1->implicitConvTo(t2))
+ {
+ e1 = e1->castTo(sc, t2);
+ t1 = t2;
+ t = t1;
+ goto Lagain;
+ }
+ else if (t1->isintegral() && t2->isintegral())
+ {
+ if (t1->ty != t2->ty)
+ {
+ if (t1->ty == Tvector || t2->ty == Tvector)
+ goto Lincompatible;
+ e1 = integralPromotions(e1, sc);
+ e2 = integralPromotions(e2, sc);
+ t1 = e1->type;
+ t2 = e2->type;
+ goto Lagain;
+ }
+ assert(t1->ty == t2->ty);
+LmodCompare:
+ if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
+ goto Lincompatible;
+ unsigned char mod = MODmerge(t1->mod, t2->mod);
+
+ t1 = t1->castMod(mod);
+ t2 = t2->castMod(mod);
+ t = t1;
+ e1 = e1->castTo(sc, t);
+ e2 = e2->castTo(sc, t);
+ goto Lagain;
+ }
+ else if (t1->ty == Tnull && t2->ty == Tnull)
+ {
+ unsigned char mod = MODmerge(t1->mod, t2->mod);
+
+ t = t1->castMod(mod);
+ e1 = e1->castTo(sc, t);
+ e2 = e2->castTo(sc, t);
+ goto Lret;
+ }
+ else if (t2->ty == Tnull &&
+ (t1->ty == Tpointer || t1->ty == Taarray || t1->ty == Tarray))
+ {
+ goto Lt1;
+ }
+ else if (t1->ty == Tnull &&
+ (t2->ty == Tpointer || t2->ty == Taarray || t2->ty == Tarray))
+ {
+ goto Lt2;
+ }
+ else if (t1->ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
+ {
+ if (e2->implicitConvTo(t1->nextOf()))
+ {
+ // T[] op T
+ // T[] op cast(T)U
+ e2 = e2->castTo(sc, t1->nextOf());
+ t = t1->nextOf()->arrayOf();
+ }
+ else if (t1->nextOf()->implicitConvTo(e2->type))
+ {
+ // (cast(T)U)[] op T (Bugzilla 12780)
+ // e1 is left as U[], it will be handled in arrayOp() later.
+ t = e2->type->arrayOf();
+ }
+ else if (t2->ty == Tarray && isArrayOpOperand(e2))
+ {
+ if (t1->nextOf()->implicitConvTo(t2->nextOf()))
+ {
+ // (cast(T)U)[] op T[] (Bugzilla 12780)
+ // e1 is left as U[], it will be handled in arrayOp() later.
+ t = t2->nextOf()->arrayOf();
+ }
+ else if (t2->nextOf()->implicitConvTo(t1->nextOf()))
+ {
+ // T[] op (cast(T)U)[] (Bugzilla 12780)
+ // e2 is left as U[], it will be handled in arrayOp() later.
+ t = t1->nextOf()->arrayOf();
+ }
+ else
+ goto Lincompatible;
+ }
+ else
+ goto Lincompatible;
+ }
+ else if (t2->ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
+ {
+ if (e1->implicitConvTo(t2->nextOf()))
+ {
+ // T op T[]
+ // cast(T)U op T[]
+ e1 = e1->castTo(sc, t2->nextOf());
+ t = t2->nextOf()->arrayOf();
+ }
+ else if (t2->nextOf()->implicitConvTo(e1->type))
+ {
+ // T op (cast(T)U)[] (Bugzilla 12780)
+ // e2 is left as U[], it will be handled in arrayOp() later.
+ t = e1->type->arrayOf();
+ }
+ else
+ goto Lincompatible;
+
+ //printf("test %s\n", Token::toChars(op));
+ e1 = e1->optimize(WANTvalue);
+ if (isCommutative(op) && e1->isConst())
+ {
+ /* Swap operands to minimize number of functions generated
+ */
+ //printf("swap %s\n", Token::toChars(op));
+ Expression *tmp = e1;
+ e1 = e2;
+ e2 = tmp;
+ }
+ }
+ else
+ {
+ Lincompatible:
+ return false;
+ }
+Lret:
+ if (!*pt)
+ *pt = t;
+ *pe1 = e1;
+ *pe2 = e2;
+ //print();
+ return true;
+
+
+Lt1:
+ e2 = e2->castTo(sc, t1);
+ t = t1;
+ goto Lret;
+
+Lt2:
+ e1 = e1->castTo(sc, t2);
+ t = t2;
+ goto Lret;
+}
+
+/************************************
+ * Bring leaves to common type.
+ * Returns ErrorExp if error occurs. otherwise returns NULL.
+ */
+
+Expression *typeCombine(BinExp *be, Scope *sc)
+{
+ Type *t1 = be->e1->type->toBasetype();
+ Type *t2 = be->e2->type->toBasetype();
+
+ if (be->op == TOKmin || be->op == TOKadd)
+ {
+ // struct+struct, and class+class are errors
+ if (t1->ty == Tstruct && t2->ty == Tstruct)
+ goto Lerror;
+ else if (t1->ty == Tclass && t2->ty == Tclass)
+ goto Lerror;
+ else if (t1->ty == Taarray && t2->ty == Taarray)
+ goto Lerror;
+ }
+
+ if (!typeMerge(sc, be->op, &be->type, &be->e1, &be->e2))
+ goto Lerror;
+ // If the types have no value, return an error
+ if (be->e1->op == TOKerror)
+ return be->e1;
+ if (be->e2->op == TOKerror)
+ return be->e2;
+ return NULL;
+
+Lerror:
+ Expression *ex = be->incompatibleTypes();
+ if (ex->op == TOKerror)
+ return ex;
+ return new ErrorExp();
+}
+
+/***********************************
+ * Do integral promotions (convertchk).
+ * Don't convert <array of> to <pointer to>
+ */
+
+Expression *integralPromotions(Expression *e, Scope *sc)
+{
+ //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
+ switch (e->type->toBasetype()->ty)
+ {
+ case Tvoid:
+ e->error("void has no value");
+ return new ErrorExp();
+
+ case Tint8:
+ case Tuns8:
+ case Tint16:
+ case Tuns16:
+ case Tbool:
+ case Tchar:
+ case Twchar:
+ e = e->castTo(sc, Type::tint32);
+ break;
+
+ case Tdchar:
+ e = e->castTo(sc, Type::tuns32);
+ break;
+ default:
+ break;
+ }
+ return e;
+}
+
+/***********************************
+ * See if both types are arrays that can be compared
+ * for equality. Return true if so.
+ * If they are arrays, but incompatible, issue error.
+ * This is to enable comparing things like an immutable
+ * array with a mutable one.
+ */
+
+bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2)
+{
+ t1 = t1->toBasetype()->merge2();
+ t2 = t2->toBasetype()->merge2();
+
+ if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
+ (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
+ {
+ if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst &&
+ t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst &&
+ (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid))
+ {
+ error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars());
+ }
+ return true;
+ }
+ return false;
+}
+
+/***********************************
+ * See if both types are arrays that can be compared
+ * for equality without any casting. Return true if so.
+ * This is to enable comparing things like an immutable
+ * array with a mutable one.
+ */
+bool arrayTypeCompatibleWithoutCasting(Type *t1, Type *t2)
+{
+ t1 = t1->toBasetype();
+ t2 = t2->toBasetype();
+
+ if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
+ t2->ty == t1->ty)
+ {
+ if (t1->nextOf()->implicitConvTo(t2->nextOf()) >= MATCHconst ||
+ t2->nextOf()->implicitConvTo(t1->nextOf()) >= MATCHconst)
+ return true;
+ }
+ return false;
+}
+
+/******************************************************************/
+
+/* Determine the integral ranges of an expression.
+ * This is used to determine if implicit narrowing conversions will
+ * be allowed.
+ */
+
+IntRange getIntRange(Expression *e)
+{
+ class IntRangeVisitor : public Visitor
+ {
+ private:
+ static uinteger_t getMask(uinteger_t v)
+ {
+ // Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v |= v >> 32;
+ return v;
+ }
+
+ // The algorithms for &, |, ^ are not yet the best! Sometimes they will produce
+ // not the tightest bound. See
+ // https://github.com/D-Programming-Language/dmd/pull/116
+ // for detail.
+ static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b)
+ {
+ // the DiffMasks stores the mask of bits which are variable in the range.
+ uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+ uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+ // Since '&' computes the digitwise-minimum, the we could set all varying
+ // digits to 0 to get a lower bound, and set all varying digits to 1 to get
+ // an upper bound.
+ IntRange result;
+ result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask);
+ result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask);
+ // Sometimes the upper bound is overestimated. The upper bound will never
+ // exceed the input.
+ if (result.imax.value > a.imax.value)
+ result.imax.value = a.imax.value;
+ if (result.imax.value > b.imax.value)
+ result.imax.value = b.imax.value;
+ result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative;
+ return result;
+ }
+ static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b)
+ {
+ // the DiffMasks stores the mask of bits which are variable in the range.
+ uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+ uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+ // The imax algorithm by Adam D. Ruppe.
+ // http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796
+ IntRange result;
+ result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask);
+ result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value);
+ // Sometimes the lower bound is underestimated. The lower bound will never
+ // less than the input.
+ if (result.imin.value < a.imin.value)
+ result.imin.value = a.imin.value;
+ if (result.imin.value < b.imin.value)
+ result.imin.value = b.imin.value;
+ result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative;
+ return result;
+ }
+ static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b)
+ {
+ // the DiffMasks stores the mask of bits which are variable in the range.
+ uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value);
+ uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value);
+ IntRange result;
+ result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask);
+ result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask);
+ result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative;
+ return result;
+ }
+
+ public:
+ IntRange range;
+
+ void visit(Expression *e)
+ {
+ range = IntRange::fromType(e->type);
+ }
+
+ void visit(IntegerExp *e)
+ {
+ range = IntRange(SignExtendedNumber(e->getInteger())).cast(e->type);
+ }
+
+ void visit(CastExp *e)
+ {
+ range = getIntRange(e->e1).cast(e->type);
+ }
+
+ void visit(AddExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+ range = IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(e->type);
+ }
+
+ void visit(MinExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+ range = IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(e->type);
+ }
+
+ void visit(DivExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+
+ // Should we ignore the possibility of div-by-0???
+ if (ir2.containsZero())
+ {
+ visit((Expression *)e);
+ return;
+ }
+
+ // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
+ SignExtendedNumber bdy[4];
+ bdy[0] = ir1.imin / ir2.imin;
+ bdy[1] = ir1.imin / ir2.imax;
+ bdy[2] = ir1.imax / ir2.imin;
+ bdy[3] = ir1.imax / ir2.imax;
+ range = IntRange::fromNumbers4(bdy).cast(e->type);
+ }
+
+ void visit(MulExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+
+ // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
+ SignExtendedNumber bdy[4];
+ bdy[0] = ir1.imin * ir2.imin;
+ bdy[1] = ir1.imin * ir2.imax;
+ bdy[2] = ir1.imax * ir2.imin;
+ bdy[3] = ir1.imax * ir2.imax;
+ range = IntRange::fromNumbers4(bdy).cast(e->type);
+ }
+
+ void visit(ModExp *e)
+ {
+ IntRange irNum = getIntRange(e->e1);
+ IntRange irDen = getIntRange(e->e2).absNeg();
+
+ /*
+ due to the rules of D (C)'s % operator, we need to consider the cases
+ separately in different range of signs.
+
+ case 1. [500, 1700] % [7, 23] (numerator is always positive)
+ = [0, 22]
+ case 2. [-500, 1700] % [7, 23] (numerator can be negative)
+ = [-22, 22]
+ case 3. [-1700, -500] % [7, 23] (numerator is always negative)
+ = [-22, 0]
+
+ the number 22 is the maximum absolute value in the denomator's range. We
+ don't care about divide by zero.
+ */
+
+ // Modding on 0 is invalid anyway.
+ if (!irDen.imin.negative)
+ {
+ visit((Expression *)e);
+ return;
+ }
+
+ ++ irDen.imin;
+ irDen.imax = -irDen.imin;
+
+ if (!irNum.imin.negative)
+ irNum.imin.value = 0;
+ else if (irNum.imin < irDen.imin)
+ irNum.imin = irDen.imin;
+
+ if (irNum.imax.negative)
+ {
+ irNum.imax.negative = false;
+ irNum.imax.value = 0;
+ }
+ else if (irNum.imax > irDen.imax)
+ irNum.imax = irDen.imax;
+
+ range = irNum.cast(e->type);
+ }
+
+ void visit(AndExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+
+ IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+ bool has1neg, has1pos, has2neg, has2pos;
+
+ ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+ ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
+
+ IntRange result;
+ bool hasResult = false;
+ if (has1pos && has2pos)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), hasResult);
+ if (has1pos && has2neg)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), hasResult);
+ if (has1neg && has2pos)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), hasResult);
+ if (has1neg && has2neg)
+ result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), hasResult);
+ assert(hasResult);
+ range = result.cast(e->type);
+ }
+
+ void visit(OrExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+
+ IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+ bool has1neg, has1pos, has2neg, has2pos;
+
+ ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+ ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
+
+ IntRange result;
+ bool hasResult = false;
+ if (has1pos && has2pos)
+ result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), hasResult);
+ if (has1pos && has2neg)
+ result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), hasResult);
+ if (has1neg && has2pos)
+ result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), hasResult);
+ if (has1neg && has2neg)
+ result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), hasResult);
+
+ assert(hasResult);
+ range = result.cast(e->type);
+ }
+
+ void visit(XorExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+
+ IntRange ir1neg, ir1pos, ir2neg, ir2pos;
+ bool has1neg, has1pos, has2neg, has2pos;
+
+ ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos);
+ ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos);
+
+ IntRange result;
+ bool hasResult = false;
+ if (has1pos && has2pos)
+ result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), hasResult);
+ if (has1pos && has2neg)
+ result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), hasResult);
+ if (has1neg && has2pos)
+ result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), hasResult);
+ if (has1neg && has2neg)
+ result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), hasResult);
+
+ assert(hasResult);
+ range = result.cast(e->type);
+ }
+
+ void visit(ShlExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+
+ if (ir2.imin.negative)
+ ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+
+ SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin);
+ SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax);
+
+ range = IntRange(lower, upper).cast(e->type);
+ }
+
+ void visit(ShrExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+
+ if (ir2.imin.negative)
+ ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+
+ SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax);
+ SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin);
+
+ range = IntRange(lower, upper).cast(e->type);
+ }
+
+ void visit(UshrExp *e)
+ {
+ IntRange ir1 = getIntRange(e->e1).castUnsigned(e->e1->type);
+ IntRange ir2 = getIntRange(e->e2);
+
+ if (ir2.imin.negative)
+ ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+
+ range = IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(e->type);
+ }
+
+ void visit(AssignExp *e)
+ {
+ range = getIntRange(e->e2).cast(e->type);
+ }
+
+ void visit(CondExp *e)
+ {
+ // No need to check e->econd; assume caller has called optimize()
+ IntRange ir1 = getIntRange(e->e1);
+ IntRange ir2 = getIntRange(e->e2);
+ range = ir1.unionWith(ir2).cast(e->type);
+ }
+
+ void visit(VarExp *e)
+ {
+ Expression *ie;
+ VarDeclaration* vd = e->var->isVarDeclaration();
+ if (vd && vd->range)
+ range = vd->range->cast(e->type);
+ else if (vd && vd->_init && !vd->type->isMutable() &&
+ (ie = vd->getConstInitializer()) != NULL)
+ ie->accept(this);
+ else
+ visit((Expression *)e);
+ }
+
+ void visit(CommaExp *e)
+ {
+ e->e2->accept(this);
+ }
+
+ void visit(ComExp *e)
+ {
+ IntRange ir = getIntRange(e->e1);
+ range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative),
+ SignExtendedNumber(~ir.imin.value, !ir.imin.negative)).cast(e->type);
+ }
+
+ void visit(NegExp *e)
+ {
+ IntRange ir = getIntRange(e->e1);
+ range = IntRange(-ir.imax, -ir.imin).cast(e->type);
+ }
+ };
+
+ IntRangeVisitor v;
+ e->accept(&v);
+ return v.range;
+}
diff --git a/gcc/d/dmd/dclass.c b/gcc/d/dmd/dclass.c
new file mode 100644
index 0000000..414332c
--- /dev/null
+++ b/gcc/d/dmd/dclass.c
@@ -0,0 +1,1947 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/class.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h> // mem{cpy|set}()
+
+#include "root/root.h"
+#include "root/rmem.h"
+
+#include "errors.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"
+#include "template.h"
+#include "target.h"
+#include "objc.h"
+
+bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
+Objc *objc();
+
+
+/********************************* ClassDeclaration ****************************/
+
+ClassDeclaration *ClassDeclaration::object;
+ClassDeclaration *ClassDeclaration::throwable;
+ClassDeclaration *ClassDeclaration::exception;
+ClassDeclaration *ClassDeclaration::errorException;
+ClassDeclaration *ClassDeclaration::cpp_type_info_ptr; // Object.__cpp_type_info_ptr
+
+ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject)
+ : AggregateDeclaration(loc, id ? id : Identifier::generateId("__anonclass"))
+{
+ static const char msg[] = "only object.d can define this reserved class name";
+
+ if (baseclasses)
+ {
+ // Actually, this is a transfer
+ this->baseclasses = baseclasses;
+ }
+ else
+ this->baseclasses = new BaseClasses();
+
+ this->members = members;
+
+ baseClass = NULL;
+
+ interfaces.length = 0;
+ interfaces.ptr = NULL;
+
+ vtblInterfaces = NULL;
+
+ //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->dim);
+
+ // For forward references
+ type = new TypeClass(this);
+
+ staticCtor = NULL;
+ staticDtor = NULL;
+
+ vtblsym = NULL;
+ vclassinfo = NULL;
+
+ if (id)
+ {
+ // Look for special class names
+
+ if (id == Id::__sizeof || id == Id::__xalignof || 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 (!inObject)
+ error("%s", msg);
+ Type::dtypeinfo = this;
+ }
+
+ if (id == Id::TypeInfo_Class)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfoclass = this;
+ }
+
+ if (id == Id::TypeInfo_Interface)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfointerface = this;
+ }
+
+ if (id == Id::TypeInfo_Struct)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfostruct = this;
+ }
+
+ if (id == Id::TypeInfo_Pointer)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfopointer = this;
+ }
+
+ if (id == Id::TypeInfo_Array)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfoarray = this;
+ }
+
+ if (id == Id::TypeInfo_StaticArray)
+ {
+ //if (!inObject)
+ // Type::typeinfostaticarray->error("%s", msg);
+ Type::typeinfostaticarray = this;
+ }
+
+ if (id == Id::TypeInfo_AssociativeArray)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfoassociativearray = this;
+ }
+
+ if (id == Id::TypeInfo_Enum)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfoenum = this;
+ }
+
+ if (id == Id::TypeInfo_Function)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfofunction = this;
+ }
+
+ if (id == Id::TypeInfo_Delegate)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfodelegate = this;
+ }
+
+ if (id == Id::TypeInfo_Tuple)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfotypelist = this;
+ }
+
+ if (id == Id::TypeInfo_Const)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfoconst = this;
+ }
+
+ if (id == Id::TypeInfo_Invariant)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfoinvariant = this;
+ }
+
+ if (id == Id::TypeInfo_Shared)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfoshared = this;
+ }
+
+ if (id == Id::TypeInfo_Wild)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfowild = this;
+ }
+
+ if (id == Id::TypeInfo_Vector)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type::typeinfovector = this;
+ }
+ }
+
+ if (id == Id::Object)
+ {
+ if (!inObject)
+ error("%s", msg);
+ object = this;
+ }
+
+ if (id == Id::Throwable)
+ {
+ if (!inObject)
+ error("%s", msg);
+ throwable = this;
+ }
+
+ if (id == Id::Exception)
+ {
+ if (!inObject)
+ error("%s", msg);
+ exception = this;
+ }
+
+ if (id == Id::Error)
+ {
+ if (!inObject)
+ error("%s", msg);
+ errorException = this;
+ }
+
+ if (id == Id::cpp_type_info_ptr)
+ {
+ if (!inObject)
+ error("%s", msg);
+ cpp_type_info_ptr = this;
+ }
+ }
+
+ com = false;
+ cpp = false;
+ isscope = false;
+ isabstract = ABSfwdref;
+ inuse = 0;
+ baseok = BASEOKnone;
+ isobjc = false;
+ cpp_type_info_ptr_sym = NULL;
+}
+
+ClassDeclaration *ClassDeclaration::create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject)
+{
+ return new ClassDeclaration(loc, id, baseclasses, members, inObject);
+}
+
+Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
+{
+ //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
+ ClassDeclaration *cd =
+ s ? (ClassDeclaration *)s
+ : new ClassDeclaration(loc, ident, NULL, NULL, false);
+
+ cd->storage_class |= storage_class;
+
+ cd->baseclasses->setDim(this->baseclasses->dim);
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ BaseClass *b = (*this->baseclasses)[i];
+ BaseClass *b2 = new BaseClass(b->type->syntaxCopy());
+ (*cd->baseclasses)[i] = b2;
+ }
+
+ return ScopeDsymbol::syntaxCopy(cd);
+}
+
+Scope *ClassDeclaration::newScope(Scope *sc)
+{
+ Scope *sc2 = AggregateDeclaration::newScope(sc);
+ if (isCOMclass())
+ {
+ if (global.params.isWindows)
+ sc2->linkage = LINKwindows;
+ else
+ {
+ /* This enables us to use COM objects under Linux and
+ * work with things like XPCOM
+ */
+ sc2->linkage = LINKc;
+ }
+ }
+ return sc2;
+}
+
+/* Bugzilla 12078, 12143 and 15733:
+ * While resolving base classes and interfaces, a base may refer
+ * the member of this derived class. In that time, if all bases of
+ * this class can be determined, we can go forward the semantc process
+ * beyond the Lancestorsdone. To do the recursive semantic analysis,
+ * temporarily set and unset `_scope` around exp().
+ */
+static Type *resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, Type *type)
+{
+ if (!scx)
+ {
+ scx = sc->copy();
+ scx->setNoFree();
+ }
+ cd->_scope = scx;
+ Type *t = type->semantic(cd->loc, sc);
+ cd->_scope = NULL;
+ return t;
+}
+
+static void resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, ClassDeclaration *sym)
+{
+ if (!scx)
+ {
+ scx = sc->copy();
+ scx->setNoFree();
+ }
+ cd->_scope = scx;
+ sym->semantic(NULL);
+ cd->_scope = NULL;
+}
+
+static void badObjectDotD(ClassDeclaration *cd)
+{
+ cd->error("missing or corrupt object.d");
+ fatal();
+}
+
+void ClassDeclaration::semantic(Scope *sc)
+{
+ //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 (semanticRun >= PASSsemanticdone)
+ return;
+ unsigned errors = global.errors;
+
+ //printf("+ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+
+ Scope *scx = NULL;
+ if (_scope)
+ {
+ sc = _scope;
+ scx = _scope; // save so we don't make redundant copies
+ _scope = NULL;
+ }
+
+ if (!parent)
+ {
+ assert(sc->parent);
+ parent = sc->parent;
+ }
+
+ if (this->errors)
+ type = Type::terror;
+ type = type->semantic(loc, sc);
+
+ if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
+ {
+ TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
+ if (ti && isError(ti))
+ ((TypeClass *)type)->sym = this;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = ungagSpeculative();
+
+ if (semanticRun == PASSinit)
+ {
+ protection = sc->protection;
+
+ storage_class |= sc->stc;
+ if (storage_class & STCdeprecated)
+ isdeprecated = true;
+ if (storage_class & STCauto)
+ error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?");
+ if (storage_class & STCscope)
+ isscope = true;
+ if (storage_class & STCabstract)
+ isabstract = ABSyes;
+
+ userAttribDecl = sc->userAttribDecl;
+
+ if (sc->linkage == LINKcpp)
+ cpp = true;
+ if (sc->linkage == LINKobjc)
+ objc()->setObjc(this);
+ }
+ else if (symtab && !scx)
+ {
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ semanticRun = PASSsemantic;
+
+ if (baseok < BASEOKdone)
+ {
+ baseok = BASEOKin;
+
+ // Expand any tuples in baseclasses[]
+ for (size_t i = 0; i < baseclasses->dim; )
+ {
+ BaseClass *b = (*baseclasses)[i];
+ b->type = resolveBase(this, sc, scx, b->type);
+
+ Type *tb = b->type->toBasetype();
+ if (tb->ty == Ttuple)
+ {
+ TypeTuple *tup = (TypeTuple *)tb;
+ baseclasses->remove(i);
+ size_t dim = Parameter::dim(tup->arguments);
+ for (size_t j = 0; j < dim; j++)
+ {
+ Parameter *arg = Parameter::getNth(tup->arguments, j);
+ b = new BaseClass(arg->type);
+ baseclasses->insert(i + j, b);
+ }
+ }
+ else
+ i++;
+ }
+
+ if (baseok >= BASEOKdone)
+ {
+ //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ goto Lancestorsdone;
+ }
+
+ // See if there's a base class as first in baseclasses[]
+ if (baseclasses->dim)
+ {
+ BaseClass *b = (*baseclasses)[0];
+ Type *tb = b->type->toBasetype();
+ TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+ if (!tc)
+ {
+ if (b->type != Type::terror)
+ error("base type must be class or interface, not %s", b->type->toChars());
+ baseclasses->remove(0);
+ goto L7;
+ }
+
+ if (tc->sym->isDeprecated())
+ {
+ if (!isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ isdeprecated = true;
+
+ tc->checkDeprecated(loc, sc);
+ }
+ }
+
+ if (tc->sym->isInterfaceDeclaration())
+ goto L7;
+
+ for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
+ {
+ if (cdb == this)
+ {
+ error("circular inheritance");
+ baseclasses->remove(0);
+ goto L7;
+ }
+ }
+
+ /* Bugzilla 11034: Essentially, class inheritance hierarchy
+ * and instance size of each classes are orthogonal information.
+ * Therefore, even if tc->sym->sizeof == SIZEOKnone,
+ * we need to set baseClass field for class covariance check.
+ */
+ baseClass = tc->sym;
+ b->sym = baseClass;
+
+ if (tc->sym->_scope && tc->sym->baseok < BASEOKdone)
+ resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
+ if (tc->sym->baseok < BASEOKdone)
+ {
+ //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ baseok = BASEOKnone;
+ }
+ L7: ;
+ }
+
+ // Treat the remaining entries in baseclasses as interfaces
+ // Check for errors, handle forward references
+ for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; )
+ {
+ BaseClass *b = (*baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+ if (!tc || !tc->sym->isInterfaceDeclaration())
+ {
+ if (b->type != Type::terror)
+ error("base type must be interface, not %s", b->type->toChars());
+ baseclasses->remove(i);
+ continue;
+ }
+
+ // Check for duplicate interfaces
+ for (size_t j = (baseClass ? 1 : 0); j < i; j++)
+ {
+ BaseClass *b2 = (*baseclasses)[j];
+ if (b2->sym == tc->sym)
+ {
+ error("inherits from duplicate interface %s", b2->sym->toChars());
+ baseclasses->remove(i);
+ continue;
+ }
+ }
+
+ if (tc->sym->isDeprecated())
+ {
+ if (!isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ isdeprecated = true;
+
+ tc->checkDeprecated(loc, sc);
+ }
+ }
+
+ b->sym = tc->sym;
+
+ if (tc->sym->_scope && tc->sym->baseok < BASEOKdone)
+ resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
+ if (tc->sym->baseok < BASEOKdone)
+ {
+ //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ baseok = BASEOKnone;
+ }
+ i++;
+ }
+ if (baseok == BASEOKnone)
+ {
+ // Forward referencee of one or more bases, try again later
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ _scope->_module->addDeferredSemantic(this);
+ //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
+ return;
+ }
+ baseok = BASEOKdone;
+
+ // If no base class, and this is not an Object, use Object as base class
+ if (!baseClass && ident != Id::Object && !cpp)
+ {
+ if (!object || object->errors)
+ badObjectDotD(this);
+
+ Type *t = object->type;
+ t = t->semantic(loc, sc)->toBasetype();
+ if (t->ty == Terror)
+ badObjectDotD(this);
+ assert(t->ty == Tclass);
+ TypeClass *tc = (TypeClass *)t;
+
+ BaseClass *b = new BaseClass(tc);
+ baseclasses->shift(b);
+
+ baseClass = tc->sym;
+ assert(!baseClass->isInterfaceDeclaration());
+ b->sym = baseClass;
+ }
+ if (baseClass)
+ {
+ if (baseClass->storage_class & STCfinal)
+ error("cannot inherit from final class %s", baseClass->toChars());
+
+ // Inherit properties from base class
+ if (baseClass->isCOMclass())
+ com = true;
+ if (baseClass->isCPPclass())
+ cpp = true;
+ if (baseClass->isscope)
+ isscope = true;
+ enclosing = baseClass->enclosing;
+ storage_class |= baseClass->storage_class & STC_TYPECTOR;
+ }
+
+ interfaces.length = baseclasses->dim - (baseClass ? 1 : 0);
+ interfaces.ptr = baseclasses->tdata() + (baseClass ? 1 : 0);
+
+ for (size_t i = 0; i < interfaces.length; i++)
+ {
+ BaseClass *b = interfaces.ptr[i];
+ // If this is an interface, and it derives from a COM interface,
+ // then this is a COM interface too.
+ if (b->sym->isCOMinterface())
+ com = true;
+ if (cpp && !b->sym->isCPPinterface())
+ {
+ ::error(loc, "C++ class '%s' cannot implement D interface '%s'",
+ toPrettyChars(), b->sym->toPrettyChars());
+ }
+ }
+
+ interfaceSemantic(sc);
+ }
+Lancestorsdone:
+ //printf("\tClassDeclaration::semantic(%s) baseok = %d\n", toChars(), baseok);
+
+ if (!members) // if opaque declaration
+ {
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ if (!symtab)
+ {
+ symtab = new DsymbolTable();
+
+ /* Bugzilla 12152: The semantic analysis of base classes should be finished
+ * before the members semantic analysis of this class, in order to determine
+ * vtbl in this class. However if a base class refers the member of this class,
+ * it can be resolved as a normal forward reference.
+ * Call addMember() and setScope() to make this class members visible from the base classes.
+ */
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->addMember(sc, this);
+ }
+
+ Scope *sc2 = newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("[%d] setScope %s %s, sc2 = %p\n", i, s->kind(), s->toChars(), sc2);
+ s->setScope(sc2);
+ }
+
+ sc2->pop();
+ }
+
+ for (size_t i = 0; i < baseclasses->dim; i++)
+ {
+ BaseClass *b = (*baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ assert(tb->ty == Tclass);
+ TypeClass *tc = (TypeClass *)tb;
+
+ if (tc->sym->semanticRun < PASSsemanticdone)
+ {
+ // Forward referencee of one or more bases, try again later
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ _scope->_module->addDeferredSemantic(this);
+ //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
+ return;
+ }
+ }
+
+ if (baseok == BASEOKdone)
+ {
+ baseok = BASEOKsemanticdone;
+
+ // initialize vtbl
+ if (baseClass)
+ {
+ if (cpp && baseClass->vtbl.dim == 0)
+ {
+ error("C++ base class %s needs at least one virtual function", baseClass->toChars());
+ }
+
+ // Copy vtbl[] from base class
+ vtbl.setDim(baseClass->vtbl.dim);
+ memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim);
+
+ vthis = baseClass->vthis;
+ }
+ else
+ {
+ // No base class, so this is the root of the class hierarchy
+ vtbl.setDim(0);
+ if (vtblOffset())
+ vtbl.push(this); // leave room for classinfo as first member
+ }
+
+ /* 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
+ if (storage_class & STCstatic)
+ error("static class cannot inherit from nested class %s", baseClass->toChars());
+ if (toParent2() != baseClass->toParent2() &&
+ (!toParent2() ||
+ !baseClass->toParent2()->getType() ||
+ !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL)))
+ {
+ if (toParent2())
+ {
+ error("is nested within %s, but super class %s is nested within %s",
+ toParent2()->toChars(),
+ baseClass->toChars(),
+ baseClass->toParent2()->toChars());
+ }
+ else
+ {
+ error("is not nested, but super class %s is nested within %s",
+ baseClass->toChars(),
+ baseClass->toParent2()->toChars());
+ }
+ enclosing = NULL;
+ }
+ }
+ else
+ makeNested();
+ }
+
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->importAll(sc2);
+ }
+
+ // Note that members.dim can grow due to tuple expansion during semantic()
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic(sc2);
+ }
+
+ if (!determineFields())
+ {
+ assert(type == Type::terror);
+ sc2->pop();
+ return;
+ }
+
+ /* Following special member functions creation needs semantic analysis
+ * completion of sub-structs in each field types.
+ */
+ for (size_t i = 0; i < fields.dim; i++)
+ {
+ VarDeclaration *v = fields[i];
+ Type *tb = v->type->baseElemOf();
+ if (tb->ty != Tstruct)
+ continue;
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ if (sd->semanticRun >= PASSsemanticdone)
+ continue;
+
+ sc2->pop();
+
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ _scope->_module->addDeferredSemantic(this);
+ //printf("\tdeferring %s\n", toChars());
+ return;
+ }
+
+ /* Look for special member functions.
+ * They must be in this class, not in a base class.
+ */
+
+ // Can be in base class
+ aggNew = (NewDeclaration *)search(Loc(), Id::classNew);
+ aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);
+
+ // Look for the constructor
+ ctor = searchCtor();
+
+ if (!ctor && noDefaultCtor)
+ {
+ // A class object is always created by constructor, so this check is legitimate.
+ for (size_t i = 0; i < fields.dim; i++)
+ {
+ VarDeclaration *v = fields[i];
+ if (v->storage_class & STCnodefaultctor)
+ ::error(v->loc, "field %s must be initialized in constructor", v->toChars());
+ }
+ }
+
+ // If this class has no constructor, but base class has a default
+ // ctor, create a constructor:
+ // this() { }
+ if (!ctor && baseClass && baseClass->ctor)
+ {
+ FuncDeclaration *fd = resolveFuncCall(loc, sc2, baseClass->ctor, NULL, type, NULL, 1);
+ if (!fd) // try shared base ctor instead
+ fd = resolveFuncCall(loc, sc2, baseClass->ctor, NULL, type->sharedOf(), NULL, 1);
+ if (fd && !fd->errors)
+ {
+ //printf("Creating default this(){} for class %s\n", toChars());
+ TypeFunction *btf = (TypeFunction *)fd->type;
+ TypeFunction *tf = new TypeFunction(NULL, NULL, 0, LINKd, fd->storage_class);
+ tf->mod = btf->mod;
+ tf->purity = btf->purity;
+ tf->isnothrow = btf->isnothrow;
+ tf->isnogc = btf->isnogc;
+ tf->trust = btf->trust;
+
+ CtorDeclaration *ctor = new CtorDeclaration(loc, Loc(), 0, tf);
+ ctor->fbody = new CompoundStatement(Loc(), new Statements());
+
+ members->push(ctor);
+ ctor->addMember(sc, this);
+ ctor->semantic(sc2);
+
+ this->ctor = ctor;
+ defaultCtor = ctor;
+ }
+ else
+ {
+ error("cannot implicitly generate a default ctor when base class %s is missing a default ctor",
+ baseClass->toPrettyChars());
+ }
+ }
+
+ dtor = buildDtor(this, sc2);
+
+ if (FuncDeclaration *f = hasIdentityOpAssign(this, sc2))
+ {
+ if (!(f->storage_class & STCdisable))
+ error(f->loc, "identity assignment operator overload is illegal");
+ }
+
+ inv = buildInv(this, sc2);
+
+ Module::dprogress++;
+ semanticRun = PASSsemanticdone;
+ //printf("-ClassDeclaration.semantic(%s), type = %p\n", toChars(), type);
+ //members.print();
+
+ sc2->pop();
+
+ if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=17492
+ ClassDeclaration *cd = ((TypeClass *)type)->sym;
+ error("already exists at %s. Perhaps in another function with the same name?", cd->loc.toChars());
+ }
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ type = Type::terror;
+ this->errors = true;
+ if (deferred)
+ deferred->errors = true;
+ }
+
+ // Verify fields of a synchronized class are not public
+ if (storage_class & STCsynchronized)
+ {
+ for (size_t i = 0; i < fields.dim; i++)
+ {
+ VarDeclaration *vd = fields[i];
+ if (!vd->isThisDeclaration() &&
+ !vd->prot().isMoreRestrictiveThan(Prot(PROTpublic)))
+ {
+ vd->error("Field members of a synchronized class cannot be %s",
+ protectionToChars(vd->prot().kind));
+ }
+ }
+ }
+
+ if (deferred && !global.gag)
+ {
+ deferred->semantic2(sc);
+ deferred->semantic3(sc);
+ }
+ //printf("-ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+}
+
+/*********************************************
+ * Determine if 'this' is a base class of cd.
+ * This is used to detect circular inheritance only.
+ */
+
+bool ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
+{
+ if (!cd)
+ return false;
+ //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ BaseClass *b = (*cd->baseclasses)[i];
+ if (b->sym == this || isBaseOf2(b->sym))
+ return true;
+ }
+ return false;
+}
+
+/*******************************************
+ * Determine if 'this' is a base class of cd.
+ */
+
+bool ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+ //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
+ if (poffset)
+ *poffset = 0;
+ while (cd)
+ {
+ /* cd->baseClass might not be set if cd is forward referenced.
+ */
+ if (!cd->baseClass && cd->_scope && !cd->isInterfaceDeclaration())
+ {
+ cd->semantic(NULL);
+ if (!cd->baseClass && cd->_scope)
+ cd->error("base class is forward referenced by %s", toChars());
+ }
+
+ if (this == cd->baseClass)
+ return true;
+
+ cd = cd->baseClass;
+ }
+ return false;
+}
+
+/*********************************************
+ * Determine if 'this' has complete base class information.
+ * This is used to detect forward references in covariant overloads.
+ */
+
+bool ClassDeclaration::isBaseInfoComplete()
+{
+ return baseok >= BASEOKdone;
+}
+
+Dsymbol *ClassDeclaration::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("%s.ClassDeclaration::search('%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
+
+ //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
+ if (_scope && baseok < BASEOKdone)
+ {
+ if (!inuse)
+ {
+ // must semantic on base class/interfaces
+ ++inuse;
+ semantic(NULL);
+ --inuse;
+ }
+ }
+
+ if (!members || !symtab) // opaque or addMember is not yet done
+ {
+ error("is forward referenced when looking for '%s'", ident->toChars());
+ //*(char*)0=0;
+ return NULL;
+ }
+
+ Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
+
+ // don't search imports of base classes
+ if (flags & SearchImportsOnly)
+ return s;
+
+ if (!s)
+ {
+ // Search bases classes in depth-first, left to right order
+
+ for (size_t i = 0; i < baseclasses->dim; i++)
+ {
+ BaseClass *b = (*baseclasses)[i];
+
+ if (b->sym)
+ {
+ if (!b->sym->symtab)
+ error("base %s is forward referenced", b->sym->ident->toChars());
+ else
+ {
+ s = b->sym->search(loc, ident, flags);
+ if (!s)
+ continue;
+ else if (s == this) // happens if s is nested in this and derives from this
+ s = NULL;
+ else if (!(flags & IgnoreSymbolVisibility) && !(s->prot().kind == PROTprotected) && !symbolIsVisible(this, s))
+ s = NULL;
+ else
+ break;
+ }
+ }
+ }
+ }
+ return s;
+}
+
+/************************************
+ * Search base classes in depth-first, left-to-right order for
+ * a class or interface named 'ident'.
+ * Stops at first found. Does not look for additional matches.
+ * Params:
+ * ident = identifier to search for
+ * Returns:
+ * ClassDeclaration if found, null if not
+ */
+ClassDeclaration *ClassDeclaration::searchBase(Identifier *ident)
+{
+ for (size_t i = 0; i < baseclasses->dim; i++)
+ {
+ BaseClass *b = (*baseclasses)[i];
+ ClassDeclaration *cdb = b->type->isClassHandle();
+ if (!cdb) // Bugzilla 10616
+ return NULL;
+ if (cdb->ident->equals(ident))
+ return cdb;
+ cdb = cdb->searchBase(ident);
+ if (cdb)
+ return cdb;
+ }
+ return NULL;
+}
+
+/****
+ * Runs through the inheritance graph to set the BaseClass.offset fields.
+ * Recursive in order to account for the size of the interface classes, if they are
+ * more than just interfaces.
+ * Params:
+ * cd = interface to look at
+ * baseOffset = offset of where cd will be placed
+ * Returns:
+ * subset of instantiated size used by cd for interfaces
+ */
+static unsigned membersPlace(BaseClasses *vtblInterfaces, size_t &bi, ClassDeclaration *cd, unsigned baseOffset)
+{
+ //printf(" membersPlace(%s, %d)\n", cd->toChars(), baseOffset);
+ unsigned offset = baseOffset;
+
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ if (b->sym->sizeok != SIZEOKdone)
+ b->sym->finalizeSize();
+ assert(b->sym->sizeok == SIZEOKdone);
+
+ if (!b->sym->alignsize)
+ b->sym->alignsize = Target::ptrsize;
+ cd->alignmember(b->sym->alignsize, b->sym->alignsize, &offset);
+ assert(bi < vtblInterfaces->dim);
+ BaseClass *bv = (*vtblInterfaces)[bi];
+ if (b->sym->interfaces.length == 0)
+ {
+ //printf("\tvtblInterfaces[%d] b=%p b->sym = %s, offset = %d\n", bi, bv, bv->sym->toChars(), offset);
+ bv->offset = offset;
+ ++bi;
+ // All the base interfaces down the left side share the same offset
+ for (BaseClass *b2 = bv; b2->baseInterfaces.length; )
+ {
+ b2 = &b2->baseInterfaces.ptr[0];
+ b2->offset = offset;
+ //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2->sym->toChars(), b2->offset);
+ }
+ }
+ membersPlace(vtblInterfaces, bi, b->sym, offset);
+ //printf(" %s size = %d\n", b->sym->toChars(), b->sym->structsize);
+ offset += b->sym->structsize;
+ if (cd->alignsize < b->sym->alignsize)
+ cd->alignsize = b->sym->alignsize;
+ }
+ return offset - baseOffset;
+}
+
+void ClassDeclaration::finalizeSize()
+{
+ assert(sizeok != SIZEOKdone);
+
+ // Set the offsets of the fields and determine the size of the class
+ if (baseClass)
+ {
+ assert(baseClass->sizeok == SIZEOKdone);
+
+ alignsize = baseClass->alignsize;
+ structsize = baseClass->structsize;
+ if (cpp && global.params.isWindows)
+ structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+ }
+ else if (isInterfaceDeclaration())
+ {
+ if (interfaces.length == 0)
+ {
+ alignsize = Target::ptrsize;
+ structsize = Target::ptrsize; // allow room for __vptr
+ }
+ }
+ else
+ {
+ alignsize = Target::ptrsize;
+ structsize = Target::ptrsize; // allow room for __vptr
+ if (!cpp)
+ structsize += Target::ptrsize; // allow room for __monitor
+ }
+
+ //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
+ size_t bi = 0; // index into vtblInterfaces[]
+
+ // Add vptr's for any interfaces implemented by this class
+ structsize += membersPlace(vtblInterfaces, bi, this, structsize);
+
+ if (isInterfaceDeclaration())
+ {
+ sizeok = SIZEOKdone;
+ return;
+ }
+
+ // FIXME: Currently setFieldOffset functions need to increase fields
+ // to calculate each variable offsets. It can be improved later.
+ fields.setDim(0);
+
+ unsigned offset = structsize;
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->setFieldOffset(this, &offset, false);
+ }
+
+ sizeok = SIZEOKdone;
+
+ // Calculate fields[i]->overlapped
+ checkOverlappedFields();
+}
+
+/**********************************************************
+ * fd is in the vtbl[] for this class.
+ * Return 1 if function is hidden (not findable through search).
+ */
+
+int isf(void *param, Dsymbol *s)
+{
+ FuncDeclaration *fd = s->isFuncDeclaration();
+ if (!fd)
+ return 0;
+ //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars());
+ return (RootObject *)param == fd;
+}
+
+bool ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
+{
+ //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars());
+ Dsymbol *s = search(Loc(), fd->ident, IgnoreAmbiguous | IgnoreErrors);
+ if (!s)
+ {
+ //printf("not found\n");
+ /* Because, due to a hack, if there are multiple definitions
+ * of fd->ident, NULL is returned.
+ */
+ return false;
+ }
+ s = s->toAlias();
+ OverloadSet *os = s->isOverloadSet();
+ if (os)
+ {
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ Dsymbol *s2 = os->a[i];
+ FuncDeclaration *f2 = s2->isFuncDeclaration();
+ if (f2 && overloadApply(f2, (void *)fd, &isf))
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ FuncDeclaration *fdstart = s->isFuncDeclaration();
+ //printf("%s fdstart = %p\n", s->kind(), fdstart);
+ if (overloadApply(fdstart, (void *)fd, &isf))
+ return false;
+
+ return !fd->parent->isTemplateMixin();
+ }
+}
+
+/****************
+ * 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());
+ FuncDeclaration *fdmatch = NULL;
+ FuncDeclaration *fdambig = NULL;
+
+ ClassDeclaration *cd = this;
+ Dsymbols *vtbl = &cd->vtbl;
+ while (1)
+ {
+ for (size_t i = 0; i < vtbl->dim; i++)
+ {
+ FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration();
+ if (!fd)
+ continue; // the first entry might be a ClassInfo
+
+ //printf("\t[%d] = %s\n", i, fd->toChars());
+ if (ident == fd->ident &&
+ fd->type->covariant(tf) == 1)
+ {
+ //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration());
+ if (!fdmatch)
+ goto Lfd;
+ if (fd == fdmatch)
+ goto Lfdmatch;
+
+ {
+ // Function type matcing: exact > covariant
+ MATCH m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch;
+ MATCH m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch;
+ if (m1 > m2)
+ goto Lfd;
+ else if (m1 < m2)
+ goto Lfdmatch;
+ }
+
+ {
+ MATCH m1 = (tf->mod == fd ->type->mod) ? MATCHexact : MATCHnomatch;
+ MATCH m2 = (tf->mod == fdmatch->type->mod) ? MATCHexact : MATCHnomatch;
+ if (m1 > m2)
+ goto Lfd;
+ else if (m1 < m2)
+ goto Lfdmatch;
+ }
+
+ {
+ // The way of definition: non-mixin > mixin
+ MATCH m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
+ MATCH m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
+ if (m1 > m2)
+ goto Lfd;
+ else if (m1 < m2)
+ goto Lfdmatch;
+ }
+
+ fdambig = fd;
+ //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars());
+ continue;
+
+ Lfd:
+ fdmatch = fd;
+ fdambig = NULL;
+ //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars());
+ continue;
+
+ Lfdmatch:
+ continue;
+ }
+ //else printf("\t\t%d\n", fd->type->covariant(tf));
+ }
+ if (!cd)
+ break;
+ vtbl = &cd->vtblFinal;
+ cd = cd->baseClass;
+ }
+
+ if (fdambig)
+ error("ambiguous virtual function %s", fdambig->toChars());
+ return fdmatch;
+}
+
+void ClassDeclaration::interfaceSemantic(Scope *)
+{
+ vtblInterfaces = new BaseClasses();
+ vtblInterfaces->reserve(interfaces.length);
+
+ for (size_t i = 0; i < interfaces.length; i++)
+ {
+ BaseClass *b = interfaces.ptr[i];
+ vtblInterfaces->push(b);
+ b->copyBaseInterfaces(vtblInterfaces);
+ }
+}
+
+/****************************************
+ */
+
+bool ClassDeclaration::isCOMclass() const
+{
+ return com;
+}
+
+bool ClassDeclaration::isCOMinterface() const
+{
+ return false;
+}
+
+bool ClassDeclaration::isCPPclass() const
+{
+ return cpp;
+}
+
+bool ClassDeclaration::isCPPinterface() const
+{
+ return false;
+}
+
+
+/****************************************
+ */
+
+bool ClassDeclaration::isAbstract()
+{
+ if (isabstract != ABSfwdref)
+ return isabstract == ABSyes;
+
+ /* Bugzilla 11169: Resolve forward references to all class member functions,
+ * and determine whether this class is abstract.
+ */
+ struct SearchAbstract
+ {
+ static int fp(Dsymbol *s, void *)
+ {
+ FuncDeclaration *fd = s->isFuncDeclaration();
+ if (!fd)
+ return 0;
+ if (fd->storage_class & STCstatic)
+ return 0;
+
+ if (fd->_scope)
+ fd->semantic(NULL);
+
+ if (fd->isAbstract())
+ return 1;
+ return 0;
+ }
+ };
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ if (s->apply(&SearchAbstract::fp, this))
+ {
+ isabstract = ABSyes;
+ return true;
+ }
+ }
+
+ /* Iterate inherited member functions and check their abstract attribute.
+ */
+ for (size_t i = 1; i < vtbl.dim; i++)
+ {
+ FuncDeclaration *fd = vtbl[i]->isFuncDeclaration();
+ //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd->loc.toChars(), fd->toChars());
+ if (!fd || fd->isAbstract())
+ {
+ isabstract = ABSyes;
+ return true;
+ }
+ }
+
+ isabstract = ABSno;
+ return false;
+}
+
+
+/****************************************
+ * 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.
+ * Returns:
+ * 0 vtbl[0] is first virtual function pointer
+ * 1 vtbl[0] is classinfo/interfaceinfo pointer
+ */
+
+int ClassDeclaration::vtblOffset() const
+{
+ return cpp ? 0 : 1;
+}
+
+/****************************************
+ */
+
+const 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, NULL, false)
+{
+ if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces
+ {
+ com = true;
+ cpp = true; // IUnknown is also a C++ interface
+ }
+}
+
+Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
+{
+ InterfaceDeclaration *id =
+ s ? (InterfaceDeclaration *)s
+ : new InterfaceDeclaration(loc, ident, NULL);
+ return ClassDeclaration::syntaxCopy(id);
+}
+
+Scope *InterfaceDeclaration::newScope(Scope *sc)
+{
+ Scope *sc2 = ClassDeclaration::newScope(sc);
+ if (com)
+ sc2->linkage = LINKwindows;
+ else if (cpp)
+ sc2->linkage = LINKcpp;
+ else if (isobjc)
+ sc2->linkage = LINKobjc;
+ return sc2;
+}
+
+void InterfaceDeclaration::semantic(Scope *sc)
+{
+ //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type);
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ unsigned errors = global.errors;
+
+ //printf("+InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);
+
+ Scope *scx = NULL;
+ if (_scope)
+ {
+ sc = _scope;
+ scx = _scope; // save so we don't make redundant copies
+ _scope = NULL;
+ }
+
+ if (!parent)
+ {
+ assert(sc->parent && sc->func);
+ parent = sc->parent;
+ }
+ assert(parent && !isAnonymous());
+
+ if (this->errors)
+ type = Type::terror;
+ type = type->semantic(loc, sc);
+
+ if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
+ {
+ TemplateInstance *ti = ((TypeClass *)type)->sym->isInstantiated();
+ if (ti && isError(ti))
+ ((TypeClass *)type)->sym = this;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = ungagSpeculative();
+
+ if (semanticRun == PASSinit)
+ {
+ protection = sc->protection;
+
+ storage_class |= sc->stc;
+ if (storage_class & STCdeprecated)
+ isdeprecated = true;
+
+ userAttribDecl = sc->userAttribDecl;
+ }
+ else if (symtab)
+ {
+ if (sizeok == SIZEOKdone || !scx)
+ {
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ }
+ semanticRun = PASSsemantic;
+
+ if (baseok < BASEOKdone)
+ {
+ baseok = BASEOKin;
+
+ // Expand any tuples in baseclasses[]
+ for (size_t i = 0; i < baseclasses->dim; )
+ {
+ BaseClass *b = (*baseclasses)[i];
+ b->type = resolveBase(this, sc, scx, b->type);
+
+ Type *tb = b->type->toBasetype();
+ if (tb->ty == Ttuple)
+ {
+ TypeTuple *tup = (TypeTuple *)tb;
+ baseclasses->remove(i);
+ size_t dim = Parameter::dim(tup->arguments);
+ for (size_t j = 0; j < dim; j++)
+ {
+ Parameter *arg = Parameter::getNth(tup->arguments, j);
+ b = new BaseClass(arg->type);
+ baseclasses->insert(i + j, b);
+ }
+ }
+ else
+ i++;
+ }
+
+ if (baseok >= BASEOKdone)
+ {
+ //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ goto Lancestorsdone;
+ }
+
+ if (!baseclasses->dim && sc->linkage == LINKcpp)
+ cpp = true;
+ if (sc->linkage == LINKobjc)
+ objc()->setObjc(this);
+
+ // Check for errors, handle forward references
+ for (size_t i = 0; i < baseclasses->dim; )
+ {
+ BaseClass *b = (*baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
+ if (!tc || !tc->sym->isInterfaceDeclaration())
+ {
+ if (b->type != Type::terror)
+ error("base type must be interface, not %s", b->type->toChars());
+ baseclasses->remove(i);
+ continue;
+ }
+
+ // Check for duplicate interfaces
+ for (size_t j = 0; j < i; j++)
+ {
+ BaseClass *b2 = (*baseclasses)[j];
+ if (b2->sym == tc->sym)
+ {
+ error("inherits from duplicate interface %s", b2->sym->toChars());
+ baseclasses->remove(i);
+ continue;
+ }
+ }
+
+ if (tc->sym == this || isBaseOf2(tc->sym))
+ {
+ error("circular inheritance of interface");
+ baseclasses->remove(i);
+ continue;
+ }
+
+ if (tc->sym->isDeprecated())
+ {
+ if (!isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ isdeprecated = true;
+
+ tc->checkDeprecated(loc, sc);
+ }
+ }
+
+ b->sym = tc->sym;
+
+ if (tc->sym->_scope && tc->sym->baseok < BASEOKdone)
+ resolveBase(this, sc, scx, tc->sym); // Try to resolve forward reference
+ if (tc->sym->baseok < BASEOKdone)
+ {
+ //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ baseok = BASEOKnone;
+ }
+ i++;
+ }
+ if (baseok == BASEOKnone)
+ {
+ // Forward referencee of one or more bases, try again later
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ _scope->_module->addDeferredSemantic(this);
+ return;
+ }
+ baseok = BASEOKdone;
+
+ interfaces.length = baseclasses->dim;
+ interfaces.ptr = baseclasses->tdata();
+
+ for (size_t i = 0; i < interfaces.length; i++)
+ {
+ BaseClass *b = interfaces.ptr[i];
+ // If this is an interface, and it derives from a COM interface,
+ // then this is a COM interface too.
+ if (b->sym->isCOMinterface())
+ com = true;
+ if (b->sym->isCPPinterface())
+ cpp = true;
+ }
+
+ interfaceSemantic(sc);
+ }
+Lancestorsdone:
+
+ if (!members) // if opaque declaration
+ {
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ if (!symtab)
+ symtab = new DsymbolTable();
+
+ for (size_t i = 0; i < baseclasses->dim; i++)
+ {
+ BaseClass *b = (*baseclasses)[i];
+ Type *tb = b->type->toBasetype();
+ assert(tb->ty == Tclass);
+ TypeClass *tc = (TypeClass *)tb;
+
+ if (tc->sym->semanticRun < PASSsemanticdone)
+ {
+ // Forward referencee of one or more bases, try again later
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ if (tc->sym->_scope)
+ tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+ _scope->_module->addDeferredSemantic(this);
+ return;
+ }
+ }
+
+ if (baseok == BASEOKdone)
+ {
+ baseok = BASEOKsemanticdone;
+
+ // initialize vtbl
+ if (vtblOffset())
+ vtbl.push(this); // leave room at vtbl[0] for classinfo
+
+ // Cat together the vtbl[]'s from base interfaces
+ for (size_t i = 0; i < interfaces.length; i++)
+ {
+ BaseClass *b = interfaces.ptr[i];
+
+ // Skip if b has already appeared
+ for (size_t k = 0; k < i; k++)
+ {
+ if (b == interfaces.ptr[k])
+ goto Lcontinue;
+ }
+
+ // Copy vtbl[] from base class
+ if (b->sym->vtblOffset())
+ {
+ size_t d = b->sym->vtbl.dim;
+ if (d > 1)
+ {
+ vtbl.reserve(d - 1);
+ for (size_t j = 1; j < d; j++)
+ vtbl.push(b->sym->vtbl[j]);
+ }
+ }
+ else
+ {
+ vtbl.append(&b->sym->vtbl);
+ }
+
+ Lcontinue:
+ ;
+ }
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->addMember(sc, this);
+ }
+
+ Scope *sc2 = newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("setScope %s %s\n", s->kind(), s->toChars());
+ s->setScope(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->importAll(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic(sc2);
+ }
+
+ Module::dprogress++;
+ semanticRun = PASSsemanticdone;
+ //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", toChars(), type);
+ //members->print();
+
+ sc2->pop();
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ type = Type::terror;
+ }
+
+ assert(type->ty != Tclass || ((TypeClass *)type)->sym == this);
+}
+
+/*******************************************
+ * 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:
+ * false not a base
+ * true is a base
+ */
+
+bool InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
+{
+ //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
+ assert(!baseClass);
+ for (size_t j = 0; j < cd->interfaces.length; j++)
+ {
+ BaseClass *b = cd->interfaces.ptr[j];
+
+ //printf("\tX base %s\n", b->sym->toChars());
+ if (this == b->sym)
+ {
+ if (poffset)
+ {
+ // don't return incorrect offsets https://issues.dlang.org/show_bug.cgi?id=16980
+ *poffset = cd->sizeok == SIZEOKdone ? b->offset : OFFSET_FWDREF;
+ }
+ //printf("\tfound at offset %d\n", b->offset);
+ return true;
+ }
+ if (isBaseOf(b, poffset))
+ return true;
+ }
+
+ if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
+ return true;
+
+ if (poffset)
+ *poffset = 0;
+ return false;
+}
+
+bool InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
+{
+ //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->sym->toChars());
+ for (size_t j = 0; j < bc->baseInterfaces.length; j++)
+ {
+ BaseClass *b = &bc->baseInterfaces.ptr[j];
+
+ //printf("\tY base %s\n", b->sym->toChars());
+ if (this == b->sym)
+ {
+ //printf("\tfound at offset %d\n", b->offset);
+ if (poffset)
+ {
+ *poffset = b->offset;
+ }
+ return true;
+ }
+ if (isBaseOf(b, poffset))
+ {
+ return true;
+ }
+ }
+ if (poffset)
+ *poffset = 0;
+ return false;
+}
+
+/****************************************
+ * 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() const
+{
+ if (isCOMinterface() || isCPPinterface())
+ return 0;
+ return 1;
+}
+
+bool InterfaceDeclaration::isCOMinterface() const
+{
+ return com;
+}
+
+bool InterfaceDeclaration::isCPPinterface() const
+{
+ return cpp;
+}
+
+/*******************************************
+ */
+
+const char *InterfaceDeclaration::kind()
+{
+ return "interface";
+}
+
+
+/******************************** BaseClass *****************************/
+
+BaseClass::BaseClass()
+{
+ this->type = NULL;
+ this->sym = NULL;
+ this->offset = 0;
+
+ this->baseInterfaces.length = 0;
+ this->baseInterfaces.ptr = NULL;
+}
+
+BaseClass::BaseClass(Type *type)
+{
+ //printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
+ this->type = type;
+ this->sym = NULL;
+ this->offset = 0;
+
+ this->baseInterfaces.length = 0;
+ this->baseInterfaces.ptr = 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:
+ * true if any entries were filled in by members of cd (not exclusively
+ * by base classes)
+ */
+
+bool BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance)
+{
+ bool result = false;
+
+ //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", sym->toChars(), cd->toChars());
+ if (vtbl)
+ vtbl->setDim(sym->vtbl.dim);
+
+ // first entry is ClassInfo reference
+ for (size_t j = sym->vtblOffset(); j < sym->vtbl.dim; j++)
+ {
+ FuncDeclaration *ifd = sym->vtbl[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;
+ assert(tf); // should always be non-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
+ //printf("newinstance = %d fd->toParent() = %s ifd->toParent() = %s\n",
+ //newinstance, fd->toParent()->toChars(), ifd->toParent()->toChars());
+ if (newinstance && fd->toParent() != cd && ifd->toParent() == sym)
+ cd->error("interface function '%s' is not implemented", ifd->toFullSignature());
+
+ if (fd->toParent() == cd)
+ result = true;
+ }
+ else
+ {
+ //printf(" not found %p\n", fd);
+ // BUG: should mark this class as abstract?
+ if (!cd->isAbstract())
+ cd->error("interface function '%s' is not implemented", ifd->toFullSignature());
+
+ fd = NULL;
+ }
+ if (vtbl)
+ (*vtbl)[j] = fd;
+ }
+
+ return result;
+}
+
+void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
+{
+ //printf("+copyBaseInterfaces(), %s\n", sym->toChars());
+// if (baseInterfaces.length)
+// return;
+
+ baseInterfaces.length = sym->interfaces.length;
+ baseInterfaces.ptr = (BaseClass *)mem.xcalloc(baseInterfaces.length, sizeof(BaseClass));
+
+ //printf("%s.copyBaseInterfaces()\n", sym->toChars());
+ for (size_t i = 0; i < baseInterfaces.length; i++)
+ {
+ void *pb = &baseInterfaces.ptr[i];
+ BaseClass *b2 = sym->interfaces.ptr[i];
+
+ assert(b2->vtbl.dim == 0); // should not be filled yet
+ BaseClass *b = (BaseClass *)memcpy(pb, b2, sizeof(BaseClass));
+
+ if (i) // single inheritance is i==0
+ vtblInterfaces->push(b); // only need for M.I.
+ b->copyBaseInterfaces(vtblInterfaces);
+ }
+ //printf("-copyBaseInterfaces\n");
+}
diff --git a/gcc/d/dmd/declaration.c b/gcc/d/dmd/declaration.c
new file mode 100644
index 0000000..76132b9
--- /dev/null
+++ b/gcc/d/dmd/declaration.c
@@ -0,0 +1,2534 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/declaration.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "checkedint.h"
+
+#include "errors.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 "import.h"
+#include "id.h"
+#include "expression.h"
+#include "statement.h"
+#include "ctfe.h"
+#include "target.h"
+#include "hdrgen.h"
+
+bool checkNestedRef(Dsymbol *s, Dsymbol *p);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+Initializer *inferType(Initializer *init, Scope *sc);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+/************************************
+ * Check to see the aggregate type is nested and its context pointer is
+ * accessible from the current scope.
+ * Returns true if error occurs.
+ */
+bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t iStart = 0)
+{
+ Dsymbol *sparent = ad->toParent2();
+ Dsymbol *s = sc->func;
+ if (ad->isNested() && s)
+ {
+ //printf("ad = %p %s [%s], parent:%p\n", ad, ad->toChars(), ad->loc.toChars(), ad->parent);
+ //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent->toChars(), sparent->loc.toChars(), sparent->parent->toChars());
+ if (checkNestedRef(s, sparent))
+ {
+ error(loc, "cannot access frame pointer of %s", ad->toPrettyChars());
+ return true;
+ }
+ }
+
+ bool result = false;
+ for (size_t i = iStart; i < ad->fields.dim; i++)
+ {
+ VarDeclaration *vd = ad->fields[i];
+ Type *tb = vd->type->baseElemOf();
+ if (tb->ty == Tstruct)
+ {
+ result |= checkFrameAccess(loc, sc, ((TypeStruct *)tb)->sym);
+ }
+ }
+ return result;
+}
+
+/********************************* Declaration ****************************/
+
+Declaration::Declaration(Identifier *id)
+ : Dsymbol(id)
+{
+ type = NULL;
+ originalType = NULL;
+ storage_class = STCundefined;
+ protection = Prot(PROTundefined);
+ linkage = LINKdefault;
+ inuse = 0;
+ mangleOverride = NULL;
+}
+
+void Declaration::semantic(Scope *)
+{
+}
+
+const char *Declaration::kind()
+{
+ return "declaration";
+}
+
+d_uns64 Declaration::size(Loc)
+{
+ assert(type);
+ return type->size();
+}
+
+bool Declaration::isDelete()
+{
+ return false;
+}
+
+bool Declaration::isDataseg()
+{
+ return false;
+}
+
+bool Declaration::isThreadlocal()
+{
+ return false;
+}
+
+bool Declaration::isCodeseg() const
+{
+ return false;
+}
+
+Prot Declaration::prot()
+{
+ return protection;
+}
+
+/*************************************
+ * Check to see if declaration can be modified in this context (sc).
+ * Issue error if not.
+ */
+
+int Declaration::checkModify(Loc loc, Scope *sc, Type *, Expression *e1, int flag)
+{
+ VarDeclaration *v = isVarDeclaration();
+ if (v && v->canassign)
+ return 2;
+
+ if (isParameter() || isResult())
+ {
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (scx->func == parent && (scx->flags & SCOPEcontract))
+ {
+ const char *s = isParameter() && parent->ident != Id::ensure ? "parameter" : "result";
+ if (!flag) error(loc, "cannot modify %s '%s' in contract", s, toChars());
+ return 2; // do not report type related errors
+ }
+ }
+ }
+
+ if (v && (isCtorinit() || isField()))
+ {
+ // It's only modifiable if inside the right constructor
+ if ((storage_class & (STCforeach | STCref)) == (STCforeach | STCref))
+ return 2;
+ return modifyFieldVar(loc, sc, v, e1) ? 2 : 1;
+ }
+ return 1;
+}
+
+Dsymbol *Declaration::search(const Loc &loc, Identifier *ident, int flags)
+{
+ Dsymbol *s = Dsymbol::search(loc, ident, flags);
+ if (!s && type)
+ {
+ s = type->toDsymbol(_scope);
+ if (s)
+ s = s->search(loc, ident, flags);
+ }
+ return s;
+}
+
+
+/********************************* TupleDeclaration ****************************/
+
+TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
+ : Declaration(id)
+{
+ this->loc = loc;
+ this->type = NULL;
+ this->objects = objects;
+ this->isexp = false;
+ this->tupletype = NULL;
+}
+
+Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *)
+{
+ assert(0);
+ return NULL;
+}
+
+const 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++)
+ {
+ RootObject *o = (*objects)[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
+ */
+ Types *types = (Types *)objects;
+ Parameters *args = new Parameters();
+ args->setDim(objects->dim);
+ OutBuffer buf;
+ int hasdeco = 1;
+ for (size_t i = 0; i < types->dim; i++)
+ {
+ Type *t = (*types)[i];
+ //printf("type = %s\n", t->toChars());
+ Parameter *arg = new Parameter(0, t, NULL, NULL);
+ (*args)[i] = arg;
+ if (!t->deco)
+ hasdeco = 0;
+ }
+
+ tupletype = new TypeTuple(args);
+ if (hasdeco)
+ return tupletype->semantic(Loc(), NULL);
+ }
+
+ return tupletype;
+}
+
+Dsymbol *TupleDeclaration::toAlias2()
+{
+ //printf("TupleDeclaration::toAlias2() '%s' objects = %s\n", toChars(), objects->toChars());
+
+ for (size_t i = 0; i < objects->dim; i++)
+ {
+ RootObject *o = (*objects)[i];
+ if (Dsymbol *s = isDsymbol(o))
+ {
+ s = s->toAlias2();
+ (*objects)[i] = s;
+ }
+ }
+ return this;
+}
+
+bool TupleDeclaration::needThis()
+{
+ //printf("TupleDeclaration::needThis(%s)\n", toChars());
+ for (size_t i = 0; i < objects->dim; i++)
+ {
+ RootObject *o = (*objects)[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 true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/********************************* 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;
+ this->_import = NULL;
+ this->overnext = NULL;
+ 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;
+ this->_import = NULL;
+ this->overnext = NULL;
+ assert(s);
+}
+
+AliasDeclaration *AliasDeclaration::create(Loc loc, Identifier *id, Type *type)
+{
+ return new AliasDeclaration(loc, id, type);
+}
+
+Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
+{
+ //printf("AliasDeclaration::syntaxCopy()\n");
+ assert(!s);
+ AliasDeclaration *sa =
+ type ? new AliasDeclaration(loc, ident, type->syntaxCopy())
+ : new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL));
+ sa->storage_class = storage_class;
+ return sa;
+}
+
+void AliasDeclaration::semantic(Scope *sc)
+{
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ assert(semanticRun <= PASSsemantic);
+
+ storage_class |= sc->stc & STCdeprecated;
+ protection = sc->protection;
+ userAttribDecl = sc->userAttribDecl;
+
+ if (!sc->func && inNonRoot())
+ return;
+
+ aliasSemantic(sc);
+}
+
+void AliasDeclaration::aliasSemantic(Scope *sc)
+{
+ //printf("AliasDeclaration::semantic() %s\n", toChars());
+ if (aliassym)
+ {
+ FuncDeclaration *fd = aliassym->isFuncLiteralDeclaration();
+ TemplateDeclaration *td = aliassym->isTemplateDeclaration();
+ if (fd || (td && td->literal))
+ {
+ if (fd && fd->semanticRun >= PASSsemanticdone)
+ return;
+
+ Expression *e = new FuncExp(loc, aliassym);
+ e = ::semantic(e, sc);
+ if (e->op == TOKfunction)
+ {
+ FuncExp *fe = (FuncExp *)e;
+ aliassym = fe->td ? (Dsymbol *)fe->td : fe->fd;
+ }
+ else
+ {
+ aliassym = NULL;
+ type = Type::terror;
+ }
+ return;
+ }
+
+ if (aliassym->isTemplateInstance())
+ aliassym->semantic(sc);
+ return;
+ }
+ inuse = 1;
+
+ // 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.
+
+ unsigned int errors = global.errors;
+ Type *oldtype = type;
+
+ // Ungag errors when not instantiated DeclDefs scope alias
+ Ungag ungag(global.gag);
+ //printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated());
+ if (parent && global.gag && !isInstantiated() && !toParent2()->isFuncDeclaration())
+ {
+ //printf("%s type = %s\n", toPrettyChars(), type->toChars());
+ global.gag = 0;
+ }
+
+ /* This section is needed because Type::resolve() will:
+ * const x = 3;
+ * alias y = x;
+ * try to convert identifier x to 3.
+ */
+ Dsymbol *s = type->toDsymbol(sc);
+ if (errors != global.errors)
+ {
+ s = NULL;
+ type = Type::terror;
+ }
+ if (s && s == this)
+ {
+ error("cannot resolve");
+ s = NULL;
+ type = Type::terror;
+ }
+ if (!s || !s->isEnumMember())
+ {
+ Type *t;
+ Expression *e;
+ Scope *sc2 = sc;
+ if (storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCdisable))
+ {
+ // For 'ref' to be attached to function types, and picked
+ // up by Type::resolve(), it has to go into sc.
+ sc2 = sc->push();
+ sc2->stc |= storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCshared | STCdisable);
+ }
+ type = type->addSTC(storage_class);
+ type->resolve(loc, sc2, &e, &t, &s);
+ if (sc2 != sc)
+ sc2->pop();
+
+ if (e) // Try to convert Expression to Dsymbol
+ {
+ s = getDsymbol(e);
+ if (!s)
+ {
+ if (e->op != TOKerror)
+ error("cannot alias an expression %s", e->toChars());
+ t = Type::terror;
+ }
+ }
+ type = t;
+ }
+ if (s == this)
+ {
+ assert(global.errors);
+ type = Type::terror;
+ s = NULL;
+ }
+ if (!s) // it's a type alias
+ {
+ //printf("alias %s resolved to type %s\n", toChars(), type->toChars());
+ type = type->semantic(loc, sc);
+ aliassym = NULL;
+ }
+ else // it's a symbolic alias
+ {
+ //printf("alias %s resolved to %s %s\n", toChars(), s->kind(), s->toChars());
+ type = NULL;
+ aliassym = s;
+ }
+ if (global.gag && errors != global.errors)
+ {
+ type = oldtype;
+ aliassym = NULL;
+ }
+ inuse = 0;
+ semanticRun = PASSsemanticdone;
+
+ if (Dsymbol *sx = overnext)
+ {
+ overnext = NULL;
+
+ if (!overloadInsert(sx))
+ ScopeDsymbol::multiplyDefined(Loc(), sx, this);
+ }
+}
+
+bool AliasDeclaration::overloadInsert(Dsymbol *s)
+{
+ //printf("[%s] AliasDeclaration::overloadInsert('%s') s = %s %s @ [%s]\n",
+ // loc.toChars(), toChars(), s->kind(), s->toChars(), s->loc.toChars());
+
+ /** Aliases aren't overloadable themselves, but if their Aliasee is
+ * overloadable they are converted to an overloadable Alias (either
+ * FuncAliasDeclaration or OverDeclaration).
+ *
+ * This is done by moving the Aliasee into such an overloadable alias
+ * which is then used to replace the existing Aliasee. The original
+ * Alias (_this_) remains a useless shell.
+ *
+ * This is a horrible mess. It was probably done to avoid replacing
+ * existing AST nodes and references, but it needs a major
+ * simplification b/c it's too complex to maintain.
+ *
+ * A simpler approach might be to merge any colliding symbols into a
+ * simple Overload class (an array) and then later have that resolve
+ * all collisions.
+ */
+ if (semanticRun >= PASSsemanticdone)
+ {
+ /* Semantic analysis is already finished, and the aliased entity
+ * is not overloadable.
+ */
+ if (type)
+ return false;
+
+ /* When s is added in member scope by static if, mixin("code") or others,
+ * aliassym is determined already. See the case in: test/compilable/test61.d
+ */
+ Dsymbol *sa = aliassym->toAlias();
+ if (FuncDeclaration *fd = sa->isFuncDeclaration())
+ {
+ FuncAliasDeclaration *fa = new FuncAliasDeclaration(ident, fd);
+ fa->protection = protection;
+ fa->parent = parent;
+ aliassym = fa;
+ return aliassym->overloadInsert(s);
+ }
+ if (TemplateDeclaration *td = sa->isTemplateDeclaration())
+ {
+ OverDeclaration *od = new OverDeclaration(ident, td);
+ od->protection = protection;
+ od->parent = parent;
+ aliassym = od;
+ return aliassym->overloadInsert(s);
+ }
+ if (OverDeclaration *od = sa->isOverDeclaration())
+ {
+ if (sa->ident != ident || sa->parent != parent)
+ {
+ od = new OverDeclaration(ident, od);
+ od->protection = protection;
+ od->parent = parent;
+ aliassym = od;
+ }
+ return od->overloadInsert(s);
+ }
+ if (OverloadSet *os = sa->isOverloadSet())
+ {
+ if (sa->ident != ident || sa->parent != parent)
+ {
+ os = new OverloadSet(ident, os);
+ // TODO: protection is lost here b/c OverloadSets have no protection attribute
+ // Might no be a practical issue, b/c the code below fails to resolve the overload anyhow.
+ // ----
+ // module os1;
+ // import a, b;
+ // private alias merged = foo; // private alias to overload set of a.foo and b.foo
+ // ----
+ // module os2;
+ // import a, b;
+ // public alias merged = bar; // public alias to overload set of a.bar and b.bar
+ // ----
+ // module bug;
+ // import os1, os2;
+ // void test() { merged(123); } // should only look at os2.merged
+ //
+ // os.protection = protection;
+ os->parent = parent;
+ aliassym = os;
+ }
+ os->push(s);
+ return true;
+ }
+ return false;
+ }
+
+ /* Don't know yet what the aliased symbol is, so assume it can
+ * be overloaded and check later for correctness.
+ */
+ if (overnext)
+ return overnext->overloadInsert(s);
+ if (s == this)
+ return true;
+ overnext = s;
+ return true;
+}
+
+const char *AliasDeclaration::kind()
+{
+ return "alias";
+}
+
+Type *AliasDeclaration::getType()
+{
+ if (type)
+ return type;
+ return toAlias()->getType();
+}
+
+Dsymbol *AliasDeclaration::toAlias()
+{
+ //printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n",
+ // loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym->kind() : "", inuse);
+ assert(this != aliassym);
+ //static int count; if (++count == 10) *(char*)0=0;
+ if (inuse == 1 && type && _scope)
+ {
+ inuse = 2;
+ unsigned olderrors = global.errors;
+ Dsymbol *s = type->toDsymbol(_scope);
+ //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type->toChars(), s, this);
+ if (global.errors != olderrors)
+ goto Lerr;
+ if (s)
+ {
+ s = s->toAlias();
+ if (global.errors != olderrors)
+ goto Lerr;
+ aliassym = s;
+ inuse = 0;
+ }
+ else
+ {
+ Type *t = type->semantic(loc, _scope);
+ if (t->ty == Terror)
+ goto Lerr;
+ if (global.errors != olderrors)
+ goto Lerr;
+ //printf("t = %s\n", t->toChars());
+ inuse = 0;
+ }
+ }
+ if (inuse)
+ {
+ error("recursive alias declaration");
+
+ Lerr:
+ // Avoid breaking "recursive alias" state during errors gagged
+ if (global.gag)
+ return this;
+
+ aliassym = new AliasDeclaration(loc, ident, Type::terror);
+ type = Type::terror;
+ return aliassym;
+ }
+
+ if (semanticRun >= PASSsemanticdone)
+ {
+ // semantic is already done.
+
+ // Do not see aliassym !is null, because of lambda aliases.
+
+ // Do not see type.deco !is null, even so "alias T = const int;` needs
+ // semantic analysis to take the storage class `const` as type qualifier.
+ }
+ else
+ {
+ if (_import && _import->_scope)
+ {
+ /* If this is an internal alias for selective/renamed import,
+ * load the module first.
+ */
+ _import->semantic(NULL);
+ }
+ if (_scope)
+ {
+ aliasSemantic(_scope);
+ }
+ }
+
+ inuse = 1;
+ Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+ inuse = 0;
+ return s;
+}
+
+Dsymbol *AliasDeclaration::toAlias2()
+{
+ if (inuse)
+ {
+ error("recursive alias declaration");
+ return this;
+ }
+ inuse = 1;
+ Dsymbol *s = aliassym ? aliassym->toAlias2() : this;
+ inuse = 0;
+ return s;
+}
+
+bool AliasDeclaration::isOverloadable()
+{
+ // assume overloadable until alias is resolved
+ return semanticRun < PASSsemanticdone ||
+ (aliassym && aliassym->isOverloadable());
+}
+
+/****************************** OverDeclaration **************************/
+
+OverDeclaration::OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads)
+ : Declaration(ident)
+{
+ this->overnext = NULL;
+ this->aliassym = s;
+
+ this->hasOverloads = hasOverloads;
+ if (hasOverloads)
+ {
+ if (OverDeclaration *od = aliassym->isOverDeclaration())
+ this->hasOverloads = od->hasOverloads;
+ }
+ else
+ {
+ // for internal use
+ assert(!aliassym->isOverDeclaration());
+ }
+}
+
+const char *OverDeclaration::kind()
+{
+ return "overload alias"; // todo
+}
+
+void OverDeclaration::semantic(Scope *)
+{
+}
+
+bool OverDeclaration::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+
+ Dsymbol *s = isDsymbol(o);
+ if (!s)
+ return false;
+
+ OverDeclaration *od1 = this;
+ if (OverDeclaration *od2 = s->isOverDeclaration())
+ {
+ return od1->aliassym->equals(od2->aliassym) &&
+ od1->hasOverloads == od2->hasOverloads;
+ }
+ if (aliassym == s)
+ {
+ if (hasOverloads)
+ return true;
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ return fd->isUnique() != NULL;
+ }
+ if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ {
+ return td->overnext == NULL;
+ }
+ }
+ return false;
+}
+
+bool OverDeclaration::overloadInsert(Dsymbol *s)
+{
+ //printf("OverDeclaration::overloadInsert('%s') aliassym = %p, overnext = %p\n", s->toChars(), aliassym, overnext);
+ if (overnext)
+ return overnext->overloadInsert(s);
+ if (s == this)
+ return true;
+ overnext = s;
+ return true;
+}
+
+Dsymbol *OverDeclaration::toAlias()
+{
+ return this;
+}
+
+bool OverDeclaration::isOverloadable()
+{
+ return true;
+}
+
+Dsymbol *OverDeclaration::isUnique()
+{
+ if (!hasOverloads)
+ {
+ if (aliassym->isFuncDeclaration() ||
+ aliassym->isTemplateDeclaration())
+ {
+ return aliassym;
+ }
+ }
+
+ struct ParamUniqueSym
+ {
+ static int fp(void *param, Dsymbol *s)
+ {
+ Dsymbol **ps = (Dsymbol **)param;
+ if (*ps)
+ {
+ *ps = NULL;
+ return 1; // ambiguous, done
+ }
+ else
+ {
+ *ps = s;
+ return 0;
+ }
+ }
+ };
+ Dsymbol *result = NULL;
+ overloadApply(aliassym, &result, &ParamUniqueSym::fp);
+ return result;
+}
+
+/********************************* VarDeclaration ****************************/
+
+VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init)
+ : Declaration(id)
+{
+ //printf("VarDeclaration('%s')\n", id->toChars());
+ assert(id);
+ assert(type || init);
+ this->type = type;
+ this->_init = init;
+ this->loc = loc;
+ offset = 0;
+ isargptr = false;
+ alignment = 0;
+ ctorinit = 0;
+ aliassym = NULL;
+ onstack = false;
+ mynew = false;
+ canassign = 0;
+ overlapped = false;
+ overlapUnsafe = false;
+ doNotInferScope = false;
+ isdataseg = 0;
+ lastVar = NULL;
+ endlinnum = 0;
+ ctfeAdrOnStack = -1;
+ edtor = NULL;
+ range = NULL;
+
+ static unsigned nextSequenceNumber = 0;
+ this->sequenceNumber = ++nextSequenceNumber;
+}
+
+Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
+{
+ //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
+ assert(!s);
+ VarDeclaration *v = new VarDeclaration(loc,
+ type ? type->syntaxCopy() : NULL,
+ ident,
+ _init ? _init->syntaxCopy() : NULL);
+ v->storage_class = storage_class;
+ return v;
+}
+
+
+void VarDeclaration::semantic(Scope *sc)
+{
+// if (semanticRun > PASSinit)
+// return;
+// semanticRun = PASSsemantic;
+
+ if (semanticRun >= PASSsemanticdone)
+ return;
+
+ Scope *scx = NULL;
+ if (_scope)
+ {
+ sc = _scope;
+ scx = sc;
+ _scope = NULL;
+ }
+
+ /* Pick up storage classes from context, but except synchronized,
+ * override, abstract, and final.
+ */
+ storage_class |= (sc->stc & ~(STCsynchronized | STCoverride | STCabstract | STCfinal));
+ if (storage_class & STCextern && _init)
+ error("extern symbols cannot have initializers");
+
+ userAttribDecl = sc->userAttribDecl;
+
+ AggregateDeclaration *ad = isThis();
+ if (ad)
+ storage_class |= ad->storage_class & STC_TYPECTOR;
+
+ /* If auto type inference, do the inference
+ */
+ int inferred = 0;
+ if (!type)
+ {
+ inuse++;
+
+ // Infering the type requires running semantic,
+ // so mark the scope as ctfe if required
+ bool needctfe = (storage_class & (STCmanifest | STCstatic)) != 0;
+ if (needctfe) sc = sc->startCTFE();
+
+ //printf("inferring type for %s with init %s\n", toChars(), _init->toChars());
+ _init = inferType(_init, sc);
+ type = initializerToExpression(_init)->type;
+
+ if (needctfe) sc = sc->endCTFE();
+
+ inuse--;
+ inferred = 1;
+
+ /* This is a kludge to support the existing syntax for RAII
+ * declarations.
+ */
+ storage_class &= ~STCauto;
+ originalType = type->syntaxCopy();
+ }
+ else
+ {
+ if (!originalType)
+ originalType = type->syntaxCopy();
+
+ /* Prefix function attributes of variable declaration can affect
+ * its type:
+ * pure nothrow void function() fp;
+ * static assert(is(typeof(fp) == void function() pure nothrow));
+ */
+ Scope *sc2 = sc->push();
+ sc2->stc |= (storage_class & STC_FUNCATTR);
+ inuse++;
+ type = type->semantic(loc, sc2);
+ inuse--;
+ sc2->pop();
+ }
+ //printf(" semantic type = %s\n", type ? type->toChars() : "null");
+ if (type->ty == Terror)
+ errors = true;
+
+ 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;
+
+ /* If scope's alignment is the default, use the type's alignment,
+ * otherwise the scope overrrides.
+ */
+ alignment = sc->alignment();
+ if (alignment == STRUCTALIGN_DEFAULT)
+ alignment = type->alignment(); // use type's alignment
+
+ //printf("sc->stc = %x\n", sc->stc);
+ //printf("storage_class = x%x\n", storage_class);
+
+ if (global.params.vcomplex)
+ type->checkComplexTransition(loc);
+
+ // Calculate type size + safety checks
+ if (sc->func && !sc->intypeof)
+ {
+ if ((storage_class & STCgshared) && !isMember())
+ {
+ if (sc->func->setUnsafe())
+ error("__gshared not allowed in safe functions; use shared");
+ }
+ }
+
+ Dsymbol *parent = toParent();
+
+ Type *tb = type->toBasetype();
+ Type *tbn = tb->baseElemOf();
+ if (tb->ty == Tvoid && !(storage_class & STClazy))
+ {
+ if (inferred)
+ {
+ error("type %s is inferred from initializer %s, and variables cannot be of type void",
+ type->toChars(), _init->toChars());
+ }
+ else
+ error("variables cannot be of type void");
+ 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 ((storage_class & STCauto) && !inferred)
+ error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?");
+
+ if (tb->ty == Ttuple)
+ {
+ /* Instead, declare variables for each of the tuple elements
+ * and add those.
+ */
+ TypeTuple *tt = (TypeTuple *)tb;
+ size_t nelems = Parameter::dim(tt->arguments);
+ Expression *ie = (_init && !_init->isVoidInitializer()) ? initializerToExpression(_init) : NULL;
+ if (ie)
+ ie = ::semantic(ie, sc);
+
+ if (nelems > 0 && ie)
+ {
+ Expressions *iexps = new Expressions();
+ iexps->push(ie);
+
+ Expressions *exps = new Expressions();
+
+ for (size_t pos = 0; pos < iexps->dim; pos++)
+ {
+ Lexpand1:
+ Expression *e = (*iexps)[pos];
+ Parameter *arg = Parameter::getNth(tt->arguments, pos);
+ arg->type = arg->type->semantic(loc, sc);
+ //printf("[%d] iexps->dim = %d, ", pos, iexps->dim);
+ //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
+ //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
+
+ if (e != ie)
+ {
+ if (iexps->dim > nelems)
+ goto Lnomatch;
+ if (e->type->implicitConvTo(arg->type))
+ continue;
+ }
+
+ if (e->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)e;
+ if (iexps->dim - 1 + te->exps->dim > nelems)
+ goto Lnomatch;
+
+ iexps->remove(pos);
+ iexps->insert(pos, te->exps);
+ (*iexps)[pos] = Expression::combine(te->e0, (*iexps)[pos]);
+ goto Lexpand1;
+ }
+ else if (isAliasThisTuple(e))
+ {
+ VarDeclaration *v = copyToTemp(0, "__tup", e);
+ VarExp *ve = new VarExp(loc, v);
+ ve->type = e->type;
+
+ exps->setDim(1);
+ (*exps)[0] = ve;
+ expandAliasThisTuples(exps, 0);
+
+ for (size_t u = 0; u < exps->dim ; u++)
+ {
+ Lexpand2:
+ Expression *ee = (*exps)[u];
+ arg = Parameter::getNth(tt->arguments, pos + u);
+ arg->type = arg->type->semantic(loc, sc);
+ //printf("[%d+%d] exps->dim = %d, ", pos, u, exps->dim);
+ //printf("ee = (%s %s, %s), ", Token::tochars[ee->op], ee->toChars(), ee->type->toChars());
+ //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
+
+ size_t iexps_dim = iexps->dim - 1 + exps->dim;
+ if (iexps_dim > nelems)
+ goto Lnomatch;
+ if (ee->type->implicitConvTo(arg->type))
+ continue;
+
+ if (expandAliasThisTuples(exps, u) != -1)
+ goto Lexpand2;
+ }
+
+ if ((*exps)[0] != ve)
+ {
+ Expression *e0 = (*exps)[0];
+ (*exps)[0] = new CommaExp(loc, new DeclarationExp(loc, v), e0);
+ (*exps)[0]->type = e0->type;
+
+ iexps->remove(pos);
+ iexps->insert(pos, exps);
+ goto Lexpand1;
+ }
+ }
+ }
+ if (iexps->dim < nelems)
+ goto Lnomatch;
+
+ ie = new TupleExp(_init->loc, iexps);
+ }
+Lnomatch:
+
+ if (ie && ie->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)ie;
+ size_t tedim = te->exps->dim;
+ if (tedim != nelems)
+ {
+ ::error(loc, "tuple of %d elements cannot be assigned to tuple of %d elements", (int)tedim, (int)nelems);
+ for (size_t u = tedim; u < nelems; u++) // fill dummy expression
+ te->exps->push(new ErrorExp());
+ }
+ }
+
+ Objects *exps = new Objects();
+ exps->setDim(nelems);
+ for (size_t i = 0; i < nelems; i++)
+ {
+ Parameter *arg = Parameter::getNth(tt->arguments, i);
+
+ OutBuffer buf;
+ buf.printf("__%s_field_%llu", ident->toChars(), (ulonglong)i);
+ const char *name = buf.extractString();
+ Identifier *id = Identifier::idPool(name);
+
+ Initializer *ti;
+ if (ie)
+ {
+ Expression *einit = ie;
+ if (ie->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)ie;
+ einit = (*te->exps)[i];
+ if (i == 0)
+ einit = Expression::combine(te->e0, einit);
+ }
+ ti = new ExpInitializer(einit->loc, einit);
+ }
+ else
+ ti = _init ? _init->syntaxCopy() : NULL;
+
+ VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti);
+ v->storage_class |= STCtemp | storage_class;
+ if (arg->storageClass & STCparameter)
+ v->storage_class |= arg->storageClass;
+ //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)[i] = e;
+ }
+ TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps);
+ v2->parent = this->parent;
+ v2->isexp = true;
+ aliassym = v2;
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+
+ /* Storage class can modify the type
+ */
+ type = type->addStorageClass(storage_class);
+
+ /* Adjust storage class to reflect type
+ */
+ if (type->isConst())
+ {
+ storage_class |= STCconst;
+ if (type->isShared())
+ storage_class |= STCshared;
+ }
+ else if (type->isImmutable())
+ storage_class |= STCimmutable;
+ else if (type->isShared())
+ storage_class |= STCshared;
+ else if (type->isWild())
+ storage_class |= STCwild;
+
+ if (StorageClass stc = storage_class & (STCsynchronized | STCoverride | STCabstract | STCfinal))
+ {
+ if (stc == STCfinal)
+ error("cannot be final, perhaps you meant const?");
+ else
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, stc);
+ error("cannot be %s", buf.peekString());
+ }
+ storage_class &= ~stc; // strip off
+ }
+
+ if (storage_class & STCscope)
+ {
+ StorageClass stc = storage_class & (STCstatic | STCextern | STCmanifest | STCtls | STCgshared);
+ if (stc)
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, stc);
+ error("cannot be 'scope' and '%s'", buf.peekString());
+ }
+ else if (isMember())
+ {
+ error("field cannot be 'scope'");
+ }
+ else if (!type->hasPointers())
+ {
+ storage_class &= ~STCscope; // silently ignore; may occur in generic code
+ }
+ }
+
+ if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe))
+ {
+ }
+ else
+ {
+ AggregateDeclaration *aad = parent->isAggregateDeclaration();
+ if (aad)
+ {
+ if (global.params.vfield &&
+ storage_class & (STCconst | STCimmutable) && _init && !_init->isVoidInitializer())
+ {
+ const char *s = (storage_class & STCimmutable) ? "immutable" : "const";
+ message(loc, "`%s.%s` is `%s` field", ad->toPrettyChars(), toChars(), s);
+ }
+ storage_class |= STCfield;
+ if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor)
+ {
+ if (!isThisDeclaration() && !_init)
+ aad->noDefaultCtor = true;
+ }
+ }
+
+ InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+ if (id)
+ {
+ error("field not allowed in interface");
+ }
+ else if (aad && aad->sizeok == SIZEOKdone)
+ {
+ error("cannot be further field because it will change the determined %s size", aad->toChars());
+ }
+
+ /* Templates cannot add fields to aggregates
+ */
+ 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 *ad2 = ti->tempdecl->isMember();
+ if (ad2 && storage_class != STCundefined)
+ {
+ error("cannot use template to add field to aggregate '%s'", ad2->toChars());
+ }
+ }
+ }
+
+ if ((storage_class & (STCref | STCparameter | STCforeach | STCtemp | STCresult)) == STCref && ident != Id::This)
+ {
+ error("only parameters or foreach declarations can be ref");
+ }
+
+ if (type->hasWild())
+ {
+ if (storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) ||
+ isDataseg()
+ )
+ {
+ error("only parameters or stack based variables can be inout");
+ }
+ FuncDeclaration *func = sc->func;
+ if (func)
+ {
+ if (func->fes)
+ func = func->fes->func;
+ bool isWild = false;
+ for (FuncDeclaration *fd = func; fd; fd = fd->toParent2()->isFuncDeclaration())
+ {
+ if (((TypeFunction *)fd->type)->iswild)
+ {
+ isWild = true;
+ break;
+ }
+ }
+ if (!isWild)
+ {
+ error("inout variables can only be declared inside inout functions");
+ }
+ }
+ }
+
+ if (!(storage_class & (STCctfe | STCref | STCresult)) && tbn->ty == Tstruct &&
+ ((TypeStruct *)tbn)->sym->noDefaultCtor)
+ {
+ if (!_init)
+ {
+ if (isField())
+ {
+ /* For fields, we'll check the constructor later to make sure it is initialized
+ */
+ storage_class |= STCnodefaultctor;
+ }
+ else if (storage_class & STCparameter)
+ ;
+ else
+ error("default construction is disabled for type %s", type->toChars());
+ }
+ }
+
+ FuncDeclaration *fd = parent->isFuncDeclaration();
+ if (type->isscope() && !(storage_class & STCnodtor))
+ {
+ if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd)
+ {
+ error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope");
+ }
+
+ if (!(storage_class & STCscope))
+ {
+ if (!(storage_class & STCparameter) && ident != Id::withSym)
+ error("reference to scope class must be scope");
+ }
+ }
+
+ // Calculate type size + safety checks
+ if (sc->func && !sc->intypeof)
+ {
+ if (_init && _init->isVoidInitializer() && type->hasPointers()) // get type size
+ {
+ if (sc->func->setUnsafe())
+ error("void initializers for pointers not allowed in safe functions");
+ }
+ else if (!_init &&
+ !(storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield | STCparameter)) &&
+ type->hasVoidInitPointers())
+ {
+ if (sc->func->setUnsafe())
+ error("void initializers for pointers not allowed in safe functions");
+ }
+ }
+
+ if (!_init && !fd)
+ {
+ // If not mutable, initializable by constructor only
+ storage_class |= STCctorinit;
+ }
+
+ if (_init)
+ storage_class |= STCinit; // remember we had an explicit initializer
+ else if (storage_class & STCmanifest)
+ error("manifest constants must have initializers");
+
+ bool isBlit = false;
+ d_uns64 sz = 0;
+ if (!_init && !sc->inunion && !(storage_class & (STCstatic | STCgshared | STCextern)) && fd &&
+ (!(storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult))
+ || (storage_class & STCout)) &&
+ (sz = type->size()) != 0)
+ {
+ // Provide a default initializer
+ //printf("Providing default initializer for '%s'\n", toChars());
+ if (sz == SIZE_INVALID && type->ty != Terror)
+ error("size of type %s is invalid", type->toChars());
+
+ Type *tv = type;
+ while (tv->ty == Tsarray) // Don't skip Tenum
+ tv = tv->nextOf();
+ if (tv->needsNested())
+ {
+ /* Nested struct requires valid enclosing frame pointer.
+ * In StructLiteralExp::toElem(), it's calculated.
+ */
+ assert(tv->toBasetype()->ty == Tstruct);
+ checkFrameAccess(loc, sc, ((TypeStruct *)tbn)->sym);
+
+ Expression *e = tv->defaultInitLiteral(loc);
+ e = new BlitExp(loc, new VarExp(loc, this), e);
+ e = ::semantic(e, sc);
+ _init = new ExpInitializer(loc, e);
+ goto Ldtor;
+ }
+ if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->zeroInit == 1)
+ {
+ /* If a struct is all zeros, as a special case
+ * set it's initializer to the integer 0.
+ * In AssignExp::toElem(), we check for this and issue
+ * a memset() to initialize the struct.
+ * Must do same check in interpreter.
+ */
+ Expression *e = new IntegerExp(loc, 0, Type::tint32);
+ e = new BlitExp(loc, new VarExp(loc, this), e);
+ e->type = type; // don't type check this, it would fail
+ _init = new ExpInitializer(loc, e);
+ goto Ldtor;
+ }
+ if (type->baseElemOf()->ty == Tvoid)
+ {
+ error("%s does not have a default initializer", type->toChars());
+ }
+ else if (Expression *e = type->defaultInit(loc))
+ {
+ _init = new ExpInitializer(loc, e);
+ }
+ // Default initializer is always a blit
+ isBlit = true;
+ }
+
+ if (_init)
+ {
+ sc = sc->push();
+ sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCnogc | STCref | STCdisable);
+
+ ExpInitializer *ei = _init->isExpInitializer();
+ if (ei) // Bugzilla 13424: Preset the required type to fail in FuncLiteralDeclaration::semantic3
+ ei->exp = inferType(ei->exp, type);
+
+ // If inside function, there is no semantic3() call
+ if (sc->func || sc->intypeof == 1)
+ {
+ // If local variable, use AssignExp to handle all the various
+ // possibilities.
+ if (fd &&
+ !(storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) &&
+ !_init->isVoidInitializer())
+ {
+ //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars());
+ if (!ei)
+ {
+ ArrayInitializer *ai = _init->isArrayInitializer();
+ Expression *e;
+ if (ai && tb->ty == Taarray)
+ e = ai->toAssocArrayLiteral();
+ else
+ e = initializerToExpression(_init);
+ if (!e)
+ {
+ // Run semantic, but don't need to interpret
+ _init = ::semantic(_init, sc, type, INITnointerpret);
+ e = initializerToExpression(_init);
+ if (!e)
+ {
+ error("is not a static and cannot have static initializer");
+ return;
+ }
+ }
+ ei = new ExpInitializer(_init->loc, e);
+ _init = ei;
+ }
+
+ Expression *exp = ei->exp;
+ Expression *e1 = new VarExp(loc, this);
+ if (isBlit)
+ exp = new BlitExp(loc, e1, exp);
+ else
+ exp = new ConstructExp(loc, e1, exp);
+ canassign++;
+ exp = ::semantic(exp, sc);
+ canassign--;
+ exp = exp->optimize(WANTvalue);
+
+ if (exp->op == TOKerror)
+ {
+ _init = new ErrorInitializer();
+ ei = NULL;
+ }
+ else
+ ei->exp = exp;
+
+ if (ei && isScope())
+ {
+ Expression *ex = ei->exp;
+ while (ex->op == TOKcomma)
+ ex = ((CommaExp *)ex)->e2;
+ if (ex->op == TOKblit || ex->op == TOKconstruct)
+ ex = ((AssignExp *)ex)->e2;
+ if (ex->op == TOKnew)
+ {
+ // See if initializer is a NewExp that can be allocated on the stack
+ NewExp *ne = (NewExp *)ex;
+ if (type->toBasetype()->ty == Tclass)
+ {
+ if (ne->newargs && ne->newargs->dim > 1)
+ {
+ mynew = true;
+ }
+ else
+ {
+ ne->onstack = true;
+ onstack = true;
+ }
+ }
+ }
+ else if (ex->op == TOKfunction)
+ {
+ // or a delegate that doesn't escape a reference to the function
+ FuncDeclaration *f = ((FuncExp *)ex)->fd;
+ f->tookAddressOf--;
+ }
+ }
+ }
+ else
+ {
+ // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
+ _init = ::semantic(_init, sc, type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
+ }
+ }
+ else if (parent->isAggregateDeclaration())
+ {
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ }
+ else if (storage_class & (STCconst | STCimmutable | STCmanifest) ||
+ type->isConst() || type->isImmutable())
+ {
+ /* 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 (!inferred)
+ {
+ unsigned errors = global.errors;
+ inuse++;
+ if (ei)
+ {
+ Expression *exp = ei->exp->syntaxCopy();
+
+ bool needctfe = isDataseg() || (storage_class & STCmanifest);
+ if (needctfe) sc = sc->startCTFE();
+ exp = ::semantic(exp, sc);
+ exp = resolveProperties(sc, exp);
+ if (needctfe) sc = sc->endCTFE();
+
+ Type *tb2 = type->toBasetype();
+ Type *ti = exp->type->toBasetype();
+
+ /* The problem is the following code:
+ * struct CopyTest {
+ * double x;
+ * this(double a) { x = a * 10.0;}
+ * this(this) { x += 2.0; }
+ * }
+ * const CopyTest z = CopyTest(5.3); // ok
+ * const CopyTest w = z; // not ok, postblit not run
+ * static assert(w.x == 55.0);
+ * because the postblit doesn't get run on the initialization of w.
+ */
+ if (ti->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)ti)->sym;
+ /* Look to see if initializer involves a copy constructor
+ * (which implies a postblit)
+ */
+ // there is a copy constructor
+ // and exp is the same struct
+ if (sd->postblit &&
+ tb2->toDsymbol(NULL) == sd)
+ {
+ // The only allowable initializer is a (non-copy) constructor
+ if (exp->isLvalue())
+ error("of type struct %s uses this(this), which is not allowed in static initialization", tb2->toChars());
+ }
+ }
+ ei->exp = exp;
+ }
+ _init = ::semantic(_init, sc, type, INITinterpret);
+ inuse--;
+ if (global.errors > errors)
+ {
+ _init = new ErrorInitializer();
+ type = Type::terror;
+ }
+ }
+ else
+ {
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ }
+ }
+ sc = sc->pop();
+ }
+
+Ldtor:
+ /* Build code to execute destruction, if necessary
+ */
+ edtor = callScopeDtor(sc);
+ if (edtor)
+ {
+ if (sc->func && storage_class & (STCstatic | STCgshared))
+ edtor = ::semantic(edtor, sc->_module->_scope);
+ else
+ edtor = ::semantic(edtor, sc);
+
+#if 0 // currently disabled because of std.stdio.stdin, stdout and stderr
+ if (isDataseg() && !(storage_class & STCextern))
+ error("static storage variables cannot have destructors");
+#endif
+ }
+
+ semanticRun = PASSsemanticdone;
+
+ if (type->toBasetype()->ty == Terror)
+ errors = true;
+
+ if (sc->scopesym && !sc->scopesym->isAggregateDeclaration())
+ {
+ for (ScopeDsymbol *sym = sc->scopesym; sym && endlinnum == 0;
+ sym = sym->parent ? sym->parent->isScopeDsymbol() : NULL)
+ endlinnum = sym->endlinnum;
+ }
+}
+
+void VarDeclaration::semantic2(Scope *sc)
+{
+ if (semanticRun < PASSsemanticdone && inuse)
+ return;
+
+ //printf("VarDeclaration::semantic2('%s')\n", toChars());
+
+ if (_init && !toParent()->isFuncDeclaration())
+ {
+ inuse++;
+ // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
+ _init = ::semantic(_init, sc, type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
+ inuse--;
+ }
+ if (_init && storage_class & STCmanifest)
+ {
+ /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
+ * Scan initializer looking for them. Issue error if found.
+ */
+ if (ExpInitializer *ei = _init->isExpInitializer())
+ {
+ struct EnumInitializer
+ {
+ static bool arrayHasInvalidEnumInitializer(Expressions *elems)
+ {
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ Expression *e = (*elems)[i];
+ if (e && hasInvalidEnumInitializer(e))
+ return true;
+ }
+ return false;
+ }
+
+ static bool hasInvalidEnumInitializer(Expression *e)
+ {
+ if (e->op == TOKclassreference)
+ return true;
+ if (e->op == TOKaddress && ((AddrExp *)e)->e1->op == TOKstructliteral)
+ return true;
+ if (e->op == TOKarrayliteral)
+ return arrayHasInvalidEnumInitializer(((ArrayLiteralExp *)e)->elements);
+ if (e->op == TOKstructliteral)
+ return arrayHasInvalidEnumInitializer(((StructLiteralExp *)e)->elements);
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+ return arrayHasInvalidEnumInitializer(ae->values) ||
+ arrayHasInvalidEnumInitializer(ae->keys);
+ }
+ return false;
+ }
+ };
+ if (EnumInitializer::hasInvalidEnumInitializer(ei->exp))
+ error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
+ }
+ }
+ else if (_init && isThreadlocal())
+ {
+ if ((type->ty == Tclass) && type->isMutable() && !type->isShared())
+ {
+ ExpInitializer *ei = _init->isExpInitializer();
+ if (ei && ei->exp->op == TOKclassreference)
+ error("is mutable. Only const or immutable class thread local variable are allowed, not %s", type->toChars());
+ }
+ else if (type->ty == Tpointer && type->nextOf()->ty == Tstruct && type->nextOf()->isMutable() &&!type->nextOf()->isShared())
+ {
+ ExpInitializer *ei = _init->isExpInitializer();
+ if (ei && ei->exp->op == TOKaddress && ((AddrExp *)ei->exp)->e1->op == TOKstructliteral)
+ {
+ error("is a pointer to mutable struct. Only pointers to const, immutable or shared struct thread local variable are allowed, not %s", type->toChars());
+ }
+ }
+ }
+ semanticRun = PASSsemantic2done;
+}
+
+void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+ //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars());
+
+ if (aliassym)
+ {
+ // If this variable was really a tuple, set the offsets for the tuple fields
+ TupleDeclaration *v2 = aliassym->isTupleDeclaration();
+ assert(v2);
+ for (size_t i = 0; i < v2->objects->dim; i++)
+ {
+ RootObject *o = (*v2->objects)[i];
+ assert(o->dyncast() == DYNCAST_EXPRESSION);
+ Expression *e = (Expression *)o;
+ assert(e->op == TOKdsymbol);
+ DsymbolExp *se = (DsymbolExp *)e;
+ se->s->setFieldOffset(ad, poffset, isunion);
+ }
+ return;
+ }
+
+ if (!isField())
+ return;
+ assert(!(storage_class & (STCstatic | STCextern | STCparameter | STCtls)));
+
+ //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars());
+
+ /* Fields that are tuples appear both as part of TupleDeclarations and
+ * as members. That means ignore them if they are already a field.
+ */
+ if (offset)
+ {
+ // already a field
+ *poffset = ad->structsize; // Bugzilla 13613
+ return;
+ }
+ for (size_t i = 0; i < ad->fields.dim; i++)
+ {
+ if (ad->fields[i] == this)
+ {
+ // already a field
+ *poffset = ad->structsize; // Bugzilla 13613
+ return;
+ }
+ }
+
+ // Check for forward referenced types which will fail the size() call
+ Type *t = type->toBasetype();
+ if (storage_class & STCref)
+ {
+ // References are the size of a pointer
+ t = Type::tvoidptr;
+ }
+ Type *tv = t->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)tv;
+ assert(ts->sym != ad); // already checked in ad->determineFields()
+ if (!ts->sym->determineSize(loc))
+ {
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ }
+
+ // List in ad->fields. Even if the type is error, it's necessary to avoid
+ // pointless error diagnostic "more initializers than fields" on struct literal.
+ ad->fields.push(this);
+
+ if (t->ty == Terror)
+ return;
+
+ const d_uns64 sz = t->size(loc);
+ assert(sz != SIZE_INVALID && sz < UINT32_MAX);
+ unsigned memsize = (unsigned)sz; // size of member
+ unsigned memalignsize = Target::fieldalign(t); // size of member for alignment purposes
+
+ offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, alignment,
+ &ad->structsize, &ad->alignsize, isunion);
+
+ //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+
+ //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad->toChars(), offset, memsize);
+}
+
+const char *VarDeclaration::kind()
+{
+ return "variable";
+}
+
+Dsymbol *VarDeclaration::toAlias()
+{
+ //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
+ if ((!type || !type->deco) && _scope)
+ semantic(_scope);
+
+ assert(this != aliassym);
+ Dsymbol *s = aliassym ? aliassym->toAlias() : this;
+ return s;
+}
+
+AggregateDeclaration *VarDeclaration::isThis()
+{
+ AggregateDeclaration *ad = NULL;
+
+ if (!(storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter |
+ STCtls | STCgshared | STCctfe)))
+ {
+ for (Dsymbol *s = this; s; s = s->parent)
+ {
+ ad = s->isMember();
+ if (ad)
+ break;
+ if (!s->parent || !s->parent->isTemplateMixin()) break;
+ }
+ }
+ return ad;
+}
+
+bool VarDeclaration::needThis()
+{
+ //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class);
+ return isField();
+}
+
+bool VarDeclaration::isExport() const
+{
+ return protection.kind == PROTexport;
+}
+
+bool VarDeclaration::isImportedSymbol() const
+{
+ if (protection.kind == PROTexport && !_init &&
+ (storage_class & STCstatic || parent->isModule()))
+ return true;
+ return false;
+}
+
+/*******************************************
+ * Helper function for the expansion of manifest constant.
+ */
+Expression *VarDeclaration::expandInitializer(Loc loc)
+{
+ assert((storage_class & STCmanifest) && _init);
+
+ Expression *e = getConstInitializer();
+ if (!e)
+ {
+ ::error(loc, "cannot make expression out of initializer for %s", toChars());
+ return new ErrorExp();
+ }
+
+ e = e->copy();
+ e->loc = loc; // for better error message
+ return e;
+}
+
+void VarDeclaration::checkCtorConstInit()
+{
+#if 0 /* doesn't work if more than one static ctor */
+ if (ctorinit == 0 && isCtorinit() && !isField())
+ error("missing initializer in static constructor for const variable");
+#endif
+}
+
+bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
+
+/************************************
+ * Check to see if this variable is actually in an enclosing function
+ * rather than the current one.
+ * Returns true if error occurs.
+ */
+bool VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
+{
+ //printf("VarDeclaration::checkNestedReference() %s\n", toChars());
+ if (sc->intypeof == 1 || (sc->flags & SCOPEctfe))
+ return false;
+ if (!parent || parent == sc->parent)
+ return false;
+ if (isDataseg() || (storage_class & STCmanifest))
+ return false;
+
+ // The current function
+ FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
+ if (!fdthis)
+ return false; // out of function scope
+
+ Dsymbol *p = toParent2();
+
+ // Function literals from fdthis to p must be delegates
+ checkNestedRef(fdthis, p);
+
+ // The function that this variable is in
+ FuncDeclaration *fdv = p->isFuncDeclaration();
+ if (!fdv || fdv == fdthis)
+ return false;
+
+ // Add fdthis to nestedrefs[] if not already there
+ for (size_t i = 0; 1; i++)
+ {
+ if (i == nestedrefs.dim)
+ {
+ nestedrefs.push(fdthis);
+ break;
+ }
+ if (nestedrefs[i] == fdthis)
+ break;
+ }
+
+ /* __require and __ensure will always get called directly,
+ * so they never make outer functions closure.
+ */
+ if (fdthis->ident == Id::require || fdthis->ident == Id::ensure)
+ return false;
+
+ //printf("\tfdv = %s\n", fdv->toChars());
+ //printf("\tfdthis = %s\n", fdthis->toChars());
+ if (loc.filename)
+ {
+ int lv = fdthis->getLevel(loc, sc, fdv);
+ if (lv == -2) // error
+ return true;
+ }
+
+ // Add this to fdv->closureVars[] if not already there
+ for (size_t i = 0; 1; i++)
+ {
+ if (i == fdv->closureVars.dim)
+ {
+ if (!sc->intypeof && !(sc->flags & SCOPEcompile))
+ fdv->closureVars.push(this);
+ break;
+ }
+ if (fdv->closureVars[i] == this)
+ break;
+ }
+
+ //printf("fdthis is %s\n", fdthis->toChars());
+ //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars());
+ // __dollar creates problems because it isn't a real variable Bugzilla 3326
+ if (ident == Id::dollar)
+ {
+ ::error(loc, "cannnot use $ inside a function literal");
+ return true;
+ }
+
+ if (ident == Id::withSym) // Bugzilla 1759
+ {
+ ExpInitializer *ez = _init->isExpInitializer();
+ assert(ez);
+ Expression *e = ez->exp;
+ if (e->op == TOKconstruct || e->op == TOKblit)
+ e = ((AssignExp *)e)->e2;
+ return lambdaCheckForNestedRef(e, sc);
+ }
+
+ return false;
+}
+
+/*******************************************
+ * If variable has a constant expression initializer, get it.
+ * Otherwise, return NULL.
+ */
+
+Expression *VarDeclaration::getConstInitializer(bool needFullType)
+{
+ assert(type && _init);
+
+ // Ungag errors when not speculative
+ unsigned oldgag = global.gag;
+ if (global.gag)
+ {
+ Dsymbol *sym = toParent()->isAggregateDeclaration();
+ if (sym && !sym->isSpeculative())
+ global.gag = 0;
+ }
+
+ if (_scope)
+ {
+ inuse++;
+ _init = ::semantic(_init, _scope, type, INITinterpret);
+ _scope = NULL;
+ inuse--;
+ }
+ Expression *e = initializerToExpression(_init, needFullType ? type : NULL);
+
+ global.gag = oldgag;
+ return e;
+}
+
+/*************************************
+ * Return true if we can take the address of this variable.
+ */
+
+bool VarDeclaration::canTakeAddressOf()
+{
+ return !(storage_class & STCmanifest);
+}
+
+
+/*******************************
+ * Does symbol go into data segment?
+ * Includes extern variables.
+ */
+
+bool VarDeclaration::isDataseg()
+{
+ if (isdataseg == 0) // the value is not cached
+ {
+ isdataseg = 2; // The Variables does not go into the datasegment
+
+ if (!canTakeAddressOf())
+ {
+ return false;
+ }
+
+ Dsymbol *parent = toParent();
+ if (!parent && !(storage_class & STCstatic))
+ {
+ error("forward referenced");
+ type = Type::terror;
+ }
+ else if (storage_class & (STCstatic | STCextern | STCtls | STCgshared) ||
+ parent->isModule() || parent->isTemplateInstance() || parent->isNspace())
+ {
+ isdataseg = 1; // It is in the DataSegment
+ }
+ }
+
+ return (isdataseg == 1);
+}
+
+/************************************
+ * Does symbol go into thread local storage?
+ */
+
+bool VarDeclaration::isThreadlocal()
+{
+ //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars());
+ /* Data defaults to being thread-local. It is not thread-local
+ * if it is immutable, const or shared.
+ */
+ bool i = isDataseg() &&
+ !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared));
+ //printf("\treturn %d\n", i);
+ return i;
+}
+
+/********************************************
+ * Can variable be read and written by CTFE?
+ */
+
+bool VarDeclaration::isCTFE()
+{
+ return (storage_class & STCctfe) != 0; // || !isDataseg();
+}
+
+bool VarDeclaration::isOverlappedWith(VarDeclaration *v)
+{
+ const d_uns64 vsz = v->type->size();
+ const d_uns64 tsz = type->size();
+ assert(vsz != SIZE_INVALID && tsz != SIZE_INVALID);
+ return offset < v->offset + vsz &&
+ v->offset < offset + tsz;
+}
+
+bool VarDeclaration::hasPointers()
+{
+ //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty);
+ return (!isDataseg() && type->hasPointers());
+}
+
+/******************************************
+ * Return true if variable needs to call the destructor.
+ */
+
+bool VarDeclaration::needsScopeDtor()
+{
+ //printf("VarDeclaration::needsScopeDtor() %s\n", toChars());
+ return edtor && !(storage_class & STCnodtor);
+}
+
+
+/******************************************
+ * If a variable has a scope destructor call, return call for it.
+ * Otherwise, return NULL.
+ */
+
+Expression *VarDeclaration::callScopeDtor(Scope *)
+{
+ //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
+
+ // Destruction of STCfield's is handled by buildDtor()
+ if (storage_class & (STCnodtor | STCref | STCout | STCfield))
+ {
+ return NULL;
+ }
+
+ Expression *e = NULL;
+
+ // Destructors for structs and arrays of structs
+ Type *tv = type->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+ if (!sd->dtor || sd->errors)
+ return NULL;
+
+ const d_uns64 sz = type->size();
+ assert(sz != SIZE_INVALID);
+ if (!sz)
+ return NULL;
+
+ if (type->toBasetype()->ty == Tstruct)
+ {
+ // v.__xdtor()
+ e = new VarExp(loc, this);
+
+ /* This is a hack so we can call destructors on const/immutable objects.
+ * Need to add things like "const ~this()" and "immutable ~this()" to
+ * fix properly.
+ */
+ e->type = e->type->mutableOf();
+
+ // Enable calling destructors on shared objects.
+ // The destructor is always a single, non-overloaded function,
+ // and must serve both shared and non-shared objects.
+ e->type = e->type->unSharedOf();
+
+ e = new DotVarExp(loc, e, sd->dtor, false);
+ e = new CallExp(loc, e);
+ }
+ else
+ {
+ // _ArrayDtor(v[0 .. n])
+ e = new VarExp(loc, this);
+
+ const d_uns64 sdsz = sd->type->size();
+ assert(sdsz != SIZE_INVALID && sdsz != 0);
+ const d_uns64 n = sz / sdsz;
+ e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type::tsize_t),
+ new IntegerExp(loc, n, Type::tsize_t));
+ // Prevent redundant bounds check
+ ((SliceExp *)e)->upperIsInBounds = true;
+ ((SliceExp *)e)->lowerIsLessThanUpper = true;
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ e->type = sd->type->arrayOf();
+
+ e = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), e);
+ }
+ return e;
+ }
+
+ // Destructors for classes
+ if (storage_class & (STCauto | STCscope) && !(storage_class & STCparameter))
+ {
+ for (ClassDeclaration *cd = type->isClassHandle();
+ cd;
+ cd = cd->baseClass)
+ {
+ /* We can do better if there's a way with onstack
+ * classes to determine if there's no way the monitor
+ * could be set.
+ */
+ //if (cd->isInterfaceDeclaration())
+ //error("interface %s cannot be scope", cd->toChars());
+
+ // Destroying C++ scope classes crashes currently. Since C++ class dtors are not currently supported, simply do not run dtors for them.
+ // See https://issues.dlang.org/show_bug.cgi?id=13182
+ if (cd->cpp)
+ {
+ break;
+ }
+ if (mynew || onstack) // if any destructors
+ {
+ // delete this;
+ Expression *ec;
+
+ ec = new VarExp(loc, this);
+ e = new DeleteExp(loc, ec, true);
+ e->type = Type::tvoid;
+ break;
+ }
+ }
+ }
+ return e;
+}
+
+/**********************************
+ * Determine if `this` has a lifetime that lasts past
+ * the destruction of `v`
+ * Params:
+ * v = variable to test against
+ * Returns:
+ * true if it does
+ */
+bool VarDeclaration::enclosesLifetimeOf(VarDeclaration *v) const
+{
+ return sequenceNumber < v->sequenceNumber;
+}
+
+/******************************************
+ */
+
+void ObjectNotFound(Identifier *id)
+{
+ Type::error(Loc(), "%s not found. object.d may be incorrectly installed or corrupt.", id->toChars());
+ fatal();
+}
+
+/******************************** SymbolDeclaration ********************************/
+
+SymbolDeclaration::SymbolDeclaration(Loc loc, StructDeclaration *dsym)
+ : Declaration(dsym->ident)
+{
+ this->loc = loc;
+ this->dsym = dsym;
+ storage_class |= STCconst;
+}
+
+/********************************* TypeInfoDeclaration ****************************/
+
+TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo)
+ : VarDeclaration(Loc(), Type::dtypeinfo->type, tinfo->getTypeInfoIdent(), NULL)
+{
+ this->tinfo = tinfo;
+ storage_class = STCstatic | STCgshared;
+ protection = Prot(PROTpublic);
+ linkage = LINKc;
+ alignment = Target::ptrsize;
+}
+
+TypeInfoDeclaration *TypeInfoDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoDeclaration(tinfo);
+}
+
+Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *)
+{
+ assert(0); // should never be produced by syntax
+ return NULL;
+}
+
+void TypeInfoDeclaration::semantic(Scope *)
+{
+ assert(linkage == LINKc);
+}
+
+const char *TypeInfoDeclaration::toChars()
+{
+ //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo->toChars());
+ OutBuffer buf;
+ buf.writestring("typeid(");
+ buf.writestring(tinfo->toChars());
+ buf.writeByte(')');
+ return buf.extractString();
+}
+
+/***************************** TypeInfoConstDeclaration **********************/
+
+TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfoconst)
+ {
+ ObjectNotFound(Id::TypeInfo_Const);
+ }
+ type = Type::typeinfoconst->type;
+}
+
+TypeInfoConstDeclaration *TypeInfoConstDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoConstDeclaration(tinfo);
+}
+
+/***************************** TypeInfoInvariantDeclaration **********************/
+
+TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfoinvariant)
+ {
+ ObjectNotFound(Id::TypeInfo_Invariant);
+ }
+ type = Type::typeinfoinvariant->type;
+}
+
+TypeInfoInvariantDeclaration *TypeInfoInvariantDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoInvariantDeclaration(tinfo);
+}
+
+/***************************** TypeInfoSharedDeclaration **********************/
+
+TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfoshared)
+ {
+ ObjectNotFound(Id::TypeInfo_Shared);
+ }
+ type = Type::typeinfoshared->type;
+}
+
+TypeInfoSharedDeclaration *TypeInfoSharedDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoSharedDeclaration(tinfo);
+}
+
+/***************************** TypeInfoWildDeclaration **********************/
+
+TypeInfoWildDeclaration::TypeInfoWildDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfowild)
+ {
+ ObjectNotFound(Id::TypeInfo_Wild);
+ }
+ type = Type::typeinfowild->type;
+}
+
+TypeInfoWildDeclaration *TypeInfoWildDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoWildDeclaration(tinfo);
+}
+
+/***************************** TypeInfoStructDeclaration **********************/
+
+TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfostruct)
+ {
+ ObjectNotFound(Id::TypeInfo_Struct);
+ }
+ type = Type::typeinfostruct->type;
+}
+
+TypeInfoStructDeclaration *TypeInfoStructDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoStructDeclaration(tinfo);
+}
+
+/***************************** TypeInfoClassDeclaration ***********************/
+
+TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfoclass)
+ {
+ ObjectNotFound(Id::TypeInfo_Class);
+ }
+ type = Type::typeinfoclass->type;
+}
+
+TypeInfoClassDeclaration *TypeInfoClassDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoClassDeclaration(tinfo);
+}
+
+/***************************** TypeInfoInterfaceDeclaration *******************/
+
+TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfointerface)
+ {
+ ObjectNotFound(Id::TypeInfo_Interface);
+ }
+ type = Type::typeinfointerface->type;
+}
+
+TypeInfoInterfaceDeclaration *TypeInfoInterfaceDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoInterfaceDeclaration(tinfo);
+}
+
+/***************************** TypeInfoPointerDeclaration *********************/
+
+TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfopointer)
+ {
+ ObjectNotFound(Id::TypeInfo_Pointer);
+ }
+ type = Type::typeinfopointer->type;
+}
+
+TypeInfoPointerDeclaration *TypeInfoPointerDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoPointerDeclaration(tinfo);
+}
+
+/***************************** TypeInfoArrayDeclaration ***********************/
+
+TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfoarray)
+ {
+ ObjectNotFound(Id::TypeInfo_Array);
+ }
+ type = Type::typeinfoarray->type;
+}
+
+TypeInfoArrayDeclaration *TypeInfoArrayDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoArrayDeclaration(tinfo);
+}
+
+/***************************** TypeInfoStaticArrayDeclaration *****************/
+
+TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfostaticarray)
+ {
+ ObjectNotFound(Id::TypeInfo_StaticArray);
+ }
+ type = Type::typeinfostaticarray->type;
+}
+
+TypeInfoStaticArrayDeclaration *TypeInfoStaticArrayDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoStaticArrayDeclaration(tinfo);
+}
+
+/***************************** TypeInfoAssociativeArrayDeclaration ************/
+
+TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfoassociativearray)
+ {
+ ObjectNotFound(Id::TypeInfo_AssociativeArray);
+ }
+ type = Type::typeinfoassociativearray->type;
+}
+
+TypeInfoAssociativeArrayDeclaration *TypeInfoAssociativeArrayDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoAssociativeArrayDeclaration(tinfo);
+}
+
+/***************************** TypeInfoVectorDeclaration ***********************/
+
+TypeInfoVectorDeclaration::TypeInfoVectorDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfovector)
+ {
+ ObjectNotFound(Id::TypeInfo_Vector);
+ }
+ type = Type::typeinfovector->type;
+}
+
+TypeInfoVectorDeclaration *TypeInfoVectorDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoVectorDeclaration(tinfo);
+}
+
+/***************************** TypeInfoEnumDeclaration ***********************/
+
+TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfoenum)
+ {
+ ObjectNotFound(Id::TypeInfo_Enum);
+ }
+ type = Type::typeinfoenum->type;
+}
+
+TypeInfoEnumDeclaration *TypeInfoEnumDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoEnumDeclaration(tinfo);
+}
+
+/***************************** TypeInfoFunctionDeclaration ********************/
+
+TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfofunction)
+ {
+ ObjectNotFound(Id::TypeInfo_Function);
+ }
+ type = Type::typeinfofunction->type;
+}
+
+TypeInfoFunctionDeclaration *TypeInfoFunctionDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoFunctionDeclaration(tinfo);
+}
+
+/***************************** TypeInfoDelegateDeclaration ********************/
+
+TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfodelegate)
+ {
+ ObjectNotFound(Id::TypeInfo_Delegate);
+ }
+ type = Type::typeinfodelegate->type;
+}
+
+TypeInfoDelegateDeclaration *TypeInfoDelegateDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoDelegateDeclaration(tinfo);
+}
+
+/***************************** TypeInfoTupleDeclaration **********************/
+
+TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo)
+ : TypeInfoDeclaration(tinfo)
+{
+ if (!Type::typeinfotypelist)
+ {
+ ObjectNotFound(Id::TypeInfo_Tuple);
+ }
+ type = Type::typeinfotypelist->type;
+}
+
+TypeInfoTupleDeclaration *TypeInfoTupleDeclaration::create(Type *tinfo)
+{
+ return new TypeInfoTupleDeclaration(tinfo);
+}
+
+/********************************* ThisDeclaration ****************************/
+
+// For the "this" parameter to member functions
+
+ThisDeclaration::ThisDeclaration(Loc loc, Type *t)
+ : VarDeclaration(loc, t, Id::This, NULL)
+{
+ storage_class |= STCnodtor;
+}
+
+Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *)
+{
+ assert(0); // should never be produced by syntax
+ return NULL;
+}
+
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
new file mode 100644
index 0000000..071ce2c
--- /dev/null
+++ b/gcc/d/dmd/declaration.h
@@ -0,0 +1,899 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/declaration.h
+ */
+
+#pragma once
+
+#include "dsymbol.h"
+#include "mtype.h"
+#include "objc.h"
+
+class Expression;
+class Statement;
+class LabelDsymbol;
+class Initializer;
+class Module;
+class ForeachStatement;
+class FuncDeclaration;
+class ExpInitializer;
+class StructDeclaration;
+struct InterState;
+struct CompiledCtfeFunction;
+struct ObjcSelector;
+struct IntRange;
+
+enum LINK;
+enum TOK;
+enum MATCH;
+enum PURE;
+enum PINLINE;
+
+#define STCundefined 0LL
+#define STCstatic 1LL
+#define STCextern 2LL
+#define STCconst 4LL
+#define STCfinal 8LL
+#define STCabstract 0x10LL
+#define STCparameter 0x20LL
+#define STCfield 0x40LL
+#define STCoverride 0x80LL
+#define STCauto 0x100LL
+#define STCsynchronized 0x200LL
+#define STCdeprecated 0x400LL
+#define STCin 0x800LL // in parameter
+#define STCout 0x1000LL // out parameter
+#define STClazy 0x2000LL // lazy parameter
+#define STCforeach 0x4000LL // variable for foreach loop
+#define STCvariadic 0x10000LL // the 'variadic' parameter in: T foo(T a, U b, V variadic...)
+#define STCctorinit 0x20000LL // can only be set inside constructor
+#define STCtemplateparameter 0x40000LL // template parameter
+#define STCscope 0x80000LL
+#define STCimmutable 0x100000LL
+#define STCref 0x200000LL
+#define STCinit 0x400000LL // has explicit initializer
+#define STCmanifest 0x800000LL // manifest constant
+#define STCnodtor 0x1000000LL // don't run destructor
+#define STCnothrow 0x2000000LL // never throws exceptions
+#define STCpure 0x4000000LL // pure function
+#define STCtls 0x8000000LL // thread local
+#define STCalias 0x10000000LL // alias parameter
+#define STCshared 0x20000000LL // accessible from multiple threads
+// accessible from multiple threads
+// but not typed as "shared"
+#define STCgshared 0x40000000LL
+#define STCwild 0x80000000LL // for "wild" type constructor
+#define STC_TYPECTOR (STCconst | STCimmutable | STCshared | STCwild)
+#define STC_FUNCATTR (STCref | STCnothrow | STCnogc | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem)
+
+#define STCproperty 0x100000000LL
+#define STCsafe 0x200000000LL
+#define STCtrusted 0x400000000LL
+#define STCsystem 0x800000000LL
+#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static
+#define STCdisable 0x2000000000LL // for functions that are not callable
+#define STCresult 0x4000000000LL // for result variables passed to out contracts
+#define STCnodefaultctor 0x8000000000LL // must be set inside constructor
+#define STCtemp 0x10000000000LL // temporary variable
+#define STCrvalue 0x20000000000LL // force rvalue for variables
+#define STCnogc 0x40000000000LL // @nogc
+#define STCvolatile 0x80000000000LL // destined for volatile in the back end
+#define STCreturn 0x100000000000LL // 'return ref' or 'return scope' for function parameters
+#define STCautoref 0x200000000000LL // Mark for the already deduced 'auto ref' parameter
+#define STCinference 0x400000000000LL // do attribute inference
+#define STCexptemp 0x800000000000LL // temporary variable that has lifetime restricted to an expression
+#define STCmaybescope 0x1000000000000LL // parameter might be 'scope'
+#define STCscopeinferred 0x2000000000000LL // 'scope' has been inferred and should not be part of mangling
+#define STCfuture 0x4000000000000LL // introducing new base class function
+#define STClocal 0x8000000000000LL // do not forward (see ddmd.dsymbol.ForwardingScopeDsymbol).
+
+const StorageClass STCStorageClass = (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal |
+ STCabstract | STCsynchronized | STCdeprecated | STCfuture | STCoverride | STClazy | STCalias |
+ STCout | STCin |
+ STCmanifest | STCimmutable | STCshared | STCwild | STCnothrow | STCnogc | STCpure | STCref | STCtls |
+ STCgshared | STCproperty | STCsafe | STCtrusted | STCsystem | STCdisable | STClocal);
+
+struct Match
+{
+ int count; // number of matches found
+ MATCH last; // match level of lastf
+ FuncDeclaration *lastf; // last matching function we found
+ FuncDeclaration *nextf; // current matching function
+ FuncDeclaration *anyf; // pick a func, any func, to use for error recovery
+};
+
+void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs);
+int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
+
+void ObjectNotFound(Identifier *id);
+
+/**************************************************************/
+
+class Declaration : public Dsymbol
+{
+public:
+ Type *type;
+ Type *originalType; // before semantic analysis
+ StorageClass storage_class;
+ Prot protection;
+ LINK linkage;
+ int inuse; // used to detect cycles
+ const char *mangleOverride; // overridden symbol with pragma(mangle, "...")
+
+ Declaration(Identifier *id);
+ void semantic(Scope *sc);
+ const char *kind();
+ d_uns64 size(Loc loc);
+ int checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag);
+
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+
+ bool isStatic() { return (storage_class & STCstatic) != 0; }
+ virtual bool isDelete();
+ virtual bool isDataseg();
+ virtual bool isThreadlocal();
+ virtual bool isCodeseg() const;
+ bool isCtorinit() { return (storage_class & STCctorinit) != 0; }
+ bool isFinal() { return (storage_class & STCfinal) != 0; }
+ bool isAbstract() { return (storage_class & STCabstract) != 0; }
+ bool isConst() { return (storage_class & STCconst) != 0; }
+ bool isImmutable() { return (storage_class & STCimmutable) != 0; }
+ bool isWild() { return (storage_class & STCwild) != 0; }
+ bool isAuto() { return (storage_class & STCauto) != 0; }
+ bool isScope() { return (storage_class & STCscope) != 0; }
+ bool isSynchronized() { return (storage_class & STCsynchronized) != 0; }
+ bool isParameter() { return (storage_class & STCparameter) != 0; }
+ bool isDeprecated() { return (storage_class & STCdeprecated) != 0; }
+ bool isOverride() { return (storage_class & STCoverride) != 0; }
+ bool isResult() { return (storage_class & STCresult) != 0; }
+ bool isField() { return (storage_class & STCfield) != 0; }
+
+ bool isIn() { return (storage_class & STCin) != 0; }
+ bool isOut() { return (storage_class & STCout) != 0; }
+ bool isRef() { return (storage_class & STCref) != 0; }
+
+ bool isFuture() { return (storage_class & STCfuture) != 0; }
+
+ Prot prot();
+
+ Declaration *isDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class TupleDeclaration : public Declaration
+{
+public:
+ Objects *objects;
+ bool isexp; // true: expression tuple
+
+ TypeTuple *tupletype; // !=NULL if this is a type tuple
+
+ TupleDeclaration(Loc loc, Identifier *ident, Objects *objects);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ const char *kind();
+ Type *getType();
+ Dsymbol *toAlias2();
+ bool needThis();
+
+ TupleDeclaration *isTupleDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class AliasDeclaration : public Declaration
+{
+public:
+ Dsymbol *aliassym;
+ Dsymbol *overnext; // next in overload list
+ Dsymbol *_import; // !=NULL if unresolved internal alias for selective import
+
+ AliasDeclaration(Loc loc, Identifier *ident, Type *type);
+ AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s);
+ static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ void aliasSemantic(Scope *sc);
+ bool overloadInsert(Dsymbol *s);
+ const char *kind();
+ Type *getType();
+ Dsymbol *toAlias();
+ Dsymbol *toAlias2();
+ bool isOverloadable();
+
+ AliasDeclaration *isAliasDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class OverDeclaration : public Declaration
+{
+public:
+ Dsymbol *overnext; // next in overload list
+ Dsymbol *aliassym;
+ bool hasOverloads;
+
+ OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads = true);
+ const char *kind();
+ void semantic(Scope *sc);
+ bool equals(RootObject *o);
+ bool overloadInsert(Dsymbol *s);
+
+ Dsymbol *toAlias();
+ Dsymbol *isUnique();
+ bool isOverloadable();
+
+ OverDeclaration *isOverDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class VarDeclaration : public Declaration
+{
+public:
+ Initializer *_init;
+ unsigned offset;
+ unsigned sequenceNumber; // order the variables are declared
+ FuncDeclarations nestedrefs; // referenced by these lexically nested functions
+ bool isargptr; // if parameter that _argptr points to
+ structalign_t alignment;
+ bool ctorinit; // it has been initialized in a ctor
+ bool onstack; // it is a class that was allocated on the stack
+ bool mynew; // it is a class new'd with custom operator new
+ int canassign; // it can be assigned to
+ bool overlapped; // if it is a field and has overlapping
+ bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
+ bool doNotInferScope; // do not infer 'scope' for this variable
+ unsigned char isdataseg; // private data for isDataseg
+ Dsymbol *aliassym; // if redone as alias to another symbol
+ VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection
+ unsigned endlinnum; // line number of end of scope that this var lives in
+
+ // When interpreting, these point to the value (NULL if value not determinable)
+ // The index of this variable on the CTFE stack, -1 if not allocated
+ int ctfeAdrOnStack;
+ Expression *edtor; // if !=NULL, does the destruction of the variable
+ IntRange *range; // if !NULL, the variable is known to be within the range
+
+ VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ void semantic2(Scope *sc);
+ const char *kind();
+ AggregateDeclaration *isThis();
+ bool needThis();
+ bool isExport() const;
+ bool isImportedSymbol() const;
+ bool isDataseg();
+ bool isThreadlocal();
+ bool isCTFE();
+ bool isOverlappedWith(VarDeclaration *v);
+ bool hasPointers();
+ bool canTakeAddressOf();
+ bool needsScopeDtor();
+ bool enclosesLifetimeOf(VarDeclaration *v) const;
+ Expression *callScopeDtor(Scope *sc);
+ Expression *getConstInitializer(bool needFullType = true);
+ Expression *expandInitializer(Loc loc);
+ void checkCtorConstInit();
+ bool checkNestedReference(Scope *sc, Loc loc);
+ Dsymbol *toAlias();
+ // Eliminate need for dynamic_cast
+ VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+// This is a shell around a back end symbol
+
+class SymbolDeclaration : public Declaration
+{
+public:
+ StructDeclaration *dsym;
+
+ SymbolDeclaration(Loc loc, StructDeclaration *dsym);
+
+ // Eliminate need for dynamic_cast
+ SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoDeclaration : public VarDeclaration
+{
+public:
+ Type *tinfo;
+
+ TypeInfoDeclaration(Type *tinfo);
+ static TypeInfoDeclaration *create(Type *tinfo);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ const char *toChars();
+
+ TypeInfoDeclaration *isTypeInfoDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoStructDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoStructDeclaration(Type *tinfo);
+ static TypeInfoStructDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoClassDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoClassDeclaration(Type *tinfo);
+ static TypeInfoClassDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoInterfaceDeclaration(Type *tinfo);
+ static TypeInfoInterfaceDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoPointerDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoPointerDeclaration(Type *tinfo);
+ static TypeInfoPointerDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoArrayDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoArrayDeclaration(Type *tinfo);
+ static TypeInfoArrayDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoStaticArrayDeclaration(Type *tinfo);
+ static TypeInfoStaticArrayDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoAssociativeArrayDeclaration(Type *tinfo);
+ static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoEnumDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoEnumDeclaration(Type *tinfo);
+ static TypeInfoEnumDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoFunctionDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoFunctionDeclaration(Type *tinfo);
+ static TypeInfoFunctionDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoDelegateDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoDelegateDeclaration(Type *tinfo);
+ static TypeInfoDelegateDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoTupleDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoTupleDeclaration(Type *tinfo);
+ static TypeInfoTupleDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoConstDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoConstDeclaration(Type *tinfo);
+ static TypeInfoConstDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoInvariantDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoInvariantDeclaration(Type *tinfo);
+ static TypeInfoInvariantDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoSharedDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoSharedDeclaration(Type *tinfo);
+ static TypeInfoSharedDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoWildDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoWildDeclaration(Type *tinfo);
+ static TypeInfoWildDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeInfoVectorDeclaration : public TypeInfoDeclaration
+{
+public:
+ TypeInfoVectorDeclaration(Type *tinfo);
+ static TypeInfoVectorDeclaration *create(Type *tinfo);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+class ThisDeclaration : public VarDeclaration
+{
+public:
+ ThisDeclaration(Loc loc, Type *t);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ ThisDeclaration *isThisDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+enum ILS
+{
+ ILSuninitialized, // not computed yet
+ ILSno, // cannot inline
+ ILSyes // can inline
+};
+
+/**************************************************************/
+
+enum BUILTIN
+{
+ BUILTINunknown = -1, // not known if this is a builtin
+ BUILTINno, // this is not a builtin
+ BUILTINyes // this is a builtin
+};
+
+Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments);
+BUILTIN isBuiltin(FuncDeclaration *fd);
+
+typedef Expression *(*builtin_fp)(Loc loc, FuncDeclaration *fd, Expressions *arguments);
+void add_builtin(const char *mangle, builtin_fp fp);
+void builtin_init();
+
+#define FUNCFLAGpurityInprocess 1 // working on determining purity
+#define FUNCFLAGsafetyInprocess 2 // working on determining safety
+#define FUNCFLAGnothrowInprocess 4 // working on determining nothrow
+#define FUNCFLAGnogcInprocess 8 // working on determining @nogc
+#define FUNCFLAGreturnInprocess 0x10 // working on inferring 'return' for parameters
+#define FUNCFLAGinlineScanned 0x20 // function has been scanned for inline possibilities
+#define FUNCFLAGinferScope 0x40 // infer 'scope' for parameters
+
+class FuncDeclaration : public Declaration
+{
+public:
+ Types *fthrows; // Array of Type's of exceptions (not used)
+ Statement *frequire;
+ Statement *fensure;
+ Statement *fbody;
+
+ FuncDeclarations foverrides; // functions this function overrides
+ FuncDeclaration *fdrequire; // function that does the in contract
+ FuncDeclaration *fdensure; // function that does the out contract
+
+ const char *mangleString; // mangled symbol created from mangleExact()
+
+ Identifier *outId; // identifier for out statement
+ VarDeclaration *vresult; // variable corresponding to outId
+ LabelDsymbol *returnLabel; // where the return goes
+
+ // used to prevent symbols in different
+ // scopes from having the same name
+ DsymbolTable *localsymtab;
+ VarDeclaration *vthis; // 'this' parameter (member and nested)
+ VarDeclaration *v_arguments; // '_arguments' parameter
+ ObjcSelector* selector; // Objective-C method selector (member function only)
+ VarDeclaration *v_argptr; // '_argptr' variable
+ VarDeclarations *parameters; // Array of VarDeclaration's for parameters
+ DsymbolTable *labtab; // statement label symbol table
+ Dsymbol *overnext; // next in overload list
+ FuncDeclaration *overnext0; // next in overload list (only used during IFTI)
+ Loc endloc; // location of closing curly bracket
+ int vtblIndex; // for member functions, index into vtbl[]
+ bool naked; // true if naked
+ bool generated; // true if function was generated by the compiler rather than
+ // supplied by the user
+ ILS inlineStatusStmt;
+ ILS inlineStatusExp;
+ PINLINE inlining;
+
+ CompiledCtfeFunction *ctfeCode; // Compiled code for interpreter
+ int inlineNest; // !=0 if nested inline
+ bool isArrayOp; // true if array operation
+ // true if errors in semantic3 this function's frame ptr
+ bool semantic3Errors;
+ ForeachStatement *fes; // if foreach body, this is the foreach
+ BaseClass* interfaceVirtual; // if virtual, but only appears in interface vtbl[]
+ bool introducing; // true if 'introducing' function
+ // if !=NULL, then this is the type
+ // of the 'introducing' function
+ // this one is overriding
+ Type *tintro;
+ bool inferRetType; // true if return type is to be inferred
+ StorageClass storage_class2; // storage class for template onemember's
+
+ // Things that should really go into Scope
+
+ // 1 if there's a return exp; statement
+ // 2 if there's a throw statement
+ // 4 if there's an assert(0)
+ // 8 if there's inline asm
+ // 16 if there are multiple return statements
+ int hasReturnExp;
+
+ // Support for NRVO (named return value optimization)
+ bool nrvo_can; // true means we can do it
+ VarDeclaration *nrvo_var; // variable to replace with shidden
+ Symbol *shidden; // hidden pointer passed to function
+
+ ReturnStatements *returns;
+
+ GotoStatements *gotos; // Gotos with forward references
+
+ // set if this is a known, builtin function we can evaluate at compile time
+ BUILTIN builtin;
+
+ // set if someone took the address of this function
+ int tookAddressOf;
+ bool requiresClosure; // this function needs a closure
+
+ // local variables in this function which are referenced by nested functions
+ VarDeclarations closureVars;
+ // Sibling nested functions which called this one
+ FuncDeclarations siblingCallers;
+
+ FuncDeclarations *inlinedNestedCallees;
+
+ unsigned flags; // FUNCFLAGxxxxx
+
+ FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
+ static FuncDeclaration *create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ void semantic3(Scope *sc);
+ bool functionSemantic();
+ bool functionSemantic3();
+ bool checkForwardRef(Loc loc);
+ // called from semantic3
+ VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad);
+ bool equals(RootObject *o);
+
+ int overrides(FuncDeclaration *fd);
+ int findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349 = true);
+ BaseClass *overrideInterface();
+ bool overloadInsert(Dsymbol *s);
+ FuncDeclaration *overloadExactMatch(Type *t);
+ FuncDeclaration *overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads);
+ TemplateDeclaration *findTemplateDeclRoot();
+ bool inUnittest();
+ MATCH leastAsSpecialized(FuncDeclaration *g);
+ LabelDsymbol *searchLabel(Identifier *ident);
+ int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference
+ const char *toPrettyChars(bool QualifyTypes = false);
+ const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure'
+ bool isMain();
+ bool isCMain();
+ bool isWinMain();
+ bool isDllMain();
+ bool isExport() const;
+ bool isImportedSymbol() const;
+ bool isCodeseg() const;
+ bool isOverloadable();
+ PURE isPure();
+ PURE isPureBypassingInference();
+ bool setImpure();
+ bool isSafe();
+ bool isSafeBypassingInference();
+ bool isTrusted();
+ bool setUnsafe();
+
+ bool isNogc();
+ bool isNogcBypassingInference();
+ bool setGC();
+
+ void printGCUsage(Loc loc, const char *warn);
+ bool isolateReturn();
+ bool parametersIntersect(Type *t);
+ virtual bool isNested();
+ AggregateDeclaration *isThis();
+ bool needThis();
+ bool isVirtualMethod();
+ virtual bool isVirtual();
+ virtual bool isFinalFunc();
+ virtual bool addPreInvariant();
+ virtual bool addPostInvariant();
+ const char *kind();
+ FuncDeclaration *isUnique();
+ bool checkNestedReference(Scope *sc, Loc loc);
+ bool needsClosure();
+ bool checkClosure();
+ bool hasNestedFrameRefs();
+ void buildResultVar(Scope *sc, Type *tret);
+ Statement *mergeFrequire(Statement *);
+ Statement *mergeFensure(Statement *, Identifier *oid);
+ Parameters *getParameters(int *pvarargs);
+
+ static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
+ static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
+ void checkDmain();
+
+ FuncDeclaration *isFuncDeclaration() { return this; }
+
+ virtual FuncDeclaration *toAliasFunc() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
+ Objects *tiargs,
+ Type *tthis,
+ Expressions *arguments,
+ int flags = 0);
+
+class FuncAliasDeclaration : public FuncDeclaration
+{
+public:
+ FuncDeclaration *funcalias;
+ bool hasOverloads;
+
+ FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads = true);
+
+ FuncAliasDeclaration *isFuncAliasDeclaration() { return this; }
+ const char *kind();
+
+ FuncDeclaration *toAliasFunc();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class FuncLiteralDeclaration : public FuncDeclaration
+{
+public:
+ TOK tok; // TOKfunction or TOKdelegate
+ Type *treq; // target of return type inference
+
+ // backend
+ bool deferToObj;
+
+ FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, TOK tok,
+ ForeachStatement *fes, Identifier *id = NULL);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ bool isNested();
+ AggregateDeclaration *isThis();
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+
+ void modifyReturns(Scope *sc, Type *tret);
+
+ FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; }
+ const char *kind();
+ const char *toPrettyChars(bool QualifyTypes = false);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CtorDeclaration : public FuncDeclaration
+{
+public:
+ CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ const char *kind();
+ const char *toChars();
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+
+ CtorDeclaration *isCtorDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PostBlitDeclaration : public FuncDeclaration
+{
+public:
+ PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+ bool overloadInsert(Dsymbol *s);
+
+ PostBlitDeclaration *isPostBlitDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DtorDeclaration : public FuncDeclaration
+{
+public:
+ DtorDeclaration(Loc loc, Loc endloc);
+ DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ const char *kind();
+ const char *toChars();
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+ bool overloadInsert(Dsymbol *s);
+
+ DtorDeclaration *isDtorDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticCtorDeclaration : public FuncDeclaration
+{
+public:
+ StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+ StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ AggregateDeclaration *isThis();
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+ bool hasStaticCtorOrDtor();
+
+ StaticCtorDeclaration *isStaticCtorDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SharedStaticCtorDeclaration : public StaticCtorDeclaration
+{
+public:
+ SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+ Dsymbol *syntaxCopy(Dsymbol *);
+
+ SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticDtorDeclaration : public FuncDeclaration
+{
+public:
+ VarDeclaration *vgate; // 'gate' variable
+
+ StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+ StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ AggregateDeclaration *isThis();
+ bool isVirtual();
+ bool hasStaticCtorOrDtor();
+ bool addPreInvariant();
+ bool addPostInvariant();
+
+ StaticDtorDeclaration *isStaticDtorDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SharedStaticDtorDeclaration : public StaticDtorDeclaration
+{
+public:
+ SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
+ Dsymbol *syntaxCopy(Dsymbol *);
+
+ SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class InvariantDeclaration : public FuncDeclaration
+{
+public:
+ InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id = NULL);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+
+ InvariantDeclaration *isInvariantDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class UnitTestDeclaration : public FuncDeclaration
+{
+public:
+ char *codedoc; /** For documented unittest. */
+
+ // toObjFile() these nested functions after this one
+ FuncDeclarations deferredNested;
+
+ UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ AggregateDeclaration *isThis();
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+
+ UnitTestDeclaration *isUnitTestDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class NewDeclaration : public FuncDeclaration
+{
+public:
+ Parameters *parameters;
+ int varargs;
+
+ NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, int varargs);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ const char *kind();
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+
+ NewDeclaration *isNewDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class DeleteDeclaration : public FuncDeclaration
+{
+public:
+ Parameters *parameters;
+
+ DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ const char *kind();
+ bool isDelete();
+ bool isVirtual();
+ bool addPreInvariant();
+ bool addPostInvariant();
+
+ DeleteDeclaration *isDeleteDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/delegatize.c b/gcc/d/dmd/delegatize.c
new file mode 100644
index 0000000..99fe938
--- /dev/null
+++ b/gcc/d/dmd/delegatize.c
@@ -0,0 +1,210 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/delegatize.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "expression.h"
+#include "statement.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "init.h"
+#include "tokens.h"
+
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+void lambdaSetParent(Expression *e, Scope *sc);
+bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+
+/********************************************
+ * Convert from expression to delegate that returns the expression,
+ * i.e. convert:
+ * expr
+ * to:
+ * typeof(expr) delegate() { return expr; }
+ */
+Expression *toDelegate(Expression *e, Type* t, Scope *sc)
+{
+ //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars());
+ Loc loc = e->loc;
+
+ TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd);
+ if (t->hasWild())
+ tf->mod = MODwild;
+ FuncLiteralDeclaration *fld =
+ new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
+
+ sc = sc->push();
+ sc->parent = fld; // set current function to be the delegate
+ lambdaSetParent(e, sc);
+ bool r = lambdaCheckForNestedRef(e, sc);
+ sc = sc->pop();
+
+ if (r)
+ return new ErrorExp();
+
+ Statement *s;
+ if (t->ty == Tvoid)
+ s = new ExpStatement(loc, e);
+ else
+ s = new ReturnStatement(loc, e);
+ fld->fbody = s;
+
+ e = new FuncExp(loc, fld);
+ e = semantic(e, sc);
+ return e;
+}
+
+/******************************************
+ * Patch the parent of declarations to be the new function literal.
+ */
+void lambdaSetParent(Expression *e, Scope *sc)
+{
+ class LambdaSetParent : public StoppableVisitor
+ {
+ Scope *sc;
+ public:
+ LambdaSetParent(Scope *sc) : sc(sc) {}
+
+ void visit(Expression *)
+ {
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ e->declaration->parent = sc->parent;
+ }
+
+ void visit(IndexExp *e)
+ {
+ if (e->lengthVar)
+ {
+ //printf("lengthVar\n");
+ e->lengthVar->parent = sc->parent;
+ }
+ }
+
+ void visit(SliceExp *e)
+ {
+ if (e->lengthVar)
+ {
+ //printf("lengthVar\n");
+ e->lengthVar->parent = sc->parent;
+ }
+ }
+ };
+
+ LambdaSetParent lsp(sc);
+ walkPostorder(e, &lsp);
+}
+
+/*******************************************
+ * Look for references to variables in a scope enclosing the new function literal.
+ * Returns true if error occurs.
+ */
+bool lambdaCheckForNestedRef(Expression *e, Scope *sc)
+{
+ class LambdaCheckForNestedRef : public StoppableVisitor
+ {
+ public:
+ Scope *sc;
+ bool result;
+
+ LambdaCheckForNestedRef(Scope *sc)
+ : sc(sc), result(false)
+ {
+ }
+
+ void visit(Expression *)
+ {
+ }
+
+ void visit(SymOffExp *e)
+ {
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (v)
+ result = v->checkNestedReference(sc, Loc());
+ }
+
+ void visit(VarExp *e)
+ {
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (v)
+ result = v->checkNestedReference(sc, Loc());
+ }
+
+ void visit(ThisExp *e)
+ {
+ if (e->var)
+ result = e->var->checkNestedReference(sc, Loc());
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ VarDeclaration *v = e->declaration->isVarDeclaration();
+ if (v)
+ {
+ result = v->checkNestedReference(sc, Loc());
+ if (result)
+ return;
+
+ /* Some expressions cause the frontend to create a temporary.
+ * For example, structs with cpctors replace the original
+ * expression e with:
+ * __cpcttmp = __cpcttmp.cpctor(e);
+ *
+ * In this instance, we need to ensure that the original
+ * expression e does not have any nested references by
+ * checking the declaration initializer too.
+ */
+ if (v->_init && v->_init->isExpInitializer())
+ {
+ Expression *ie = initializerToExpression(v->_init);
+ result = lambdaCheckForNestedRef(ie, sc);
+ }
+ }
+ }
+ };
+
+ LambdaCheckForNestedRef v(sc);
+ walkPostorder(e, &v);
+ return v.result;
+}
+
+bool checkNestedRef(Dsymbol *s, Dsymbol *p)
+{
+ while (s)
+ {
+ if (s == p) // hit!
+ return false;
+
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ if (!fd->isThis() && !fd->isNested())
+ break;
+
+ // Bugzilla 15332: change to delegate if fd is actually nested.
+ if (FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration())
+ fld->tok = TOKdelegate;
+ }
+ if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+ {
+ if (ad->storage_class & STCstatic)
+ break;
+ }
+ s = s->toParent2();
+ }
+ return true;
+}
diff --git a/gcc/d/dmd/denum.c b/gcc/d/dmd/denum.c
new file mode 100644
index 0000000..4107f11
--- /dev/null
+++ b/gcc/d/dmd/denum.c
@@ -0,0 +1,748 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/enum.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root/root.h"
+#include "errors.h"
+#include "enum.h"
+#include "mtype.h"
+#include "scope.h"
+#include "id.h"
+#include "expression.h"
+#include "module.h"
+#include "declaration.h"
+#include "init.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/********************************* EnumDeclaration ****************************/
+
+EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
+ : ScopeDsymbol(id)
+{
+ //printf("EnumDeclaration() %s\n", toChars());
+ this->loc = loc;
+ type = new TypeEnum(this);
+ this->memtype = memtype;
+ maxval = NULL;
+ minval = NULL;
+ defaultval = NULL;
+ sinit = NULL;
+ isdeprecated = false;
+ protection = Prot(PROTundefined);
+ parent = NULL;
+ added = false;
+ inuse = 0;
+}
+
+Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ EnumDeclaration *ed = new EnumDeclaration(loc, ident,
+ memtype ? memtype->syntaxCopy() : NULL);
+ return ScopeDsymbol::syntaxCopy(ed);
+}
+
+void EnumDeclaration::setScope(Scope *sc)
+{
+ if (semanticRun > PASSinit)
+ return;
+ ScopeDsymbol::setScope(sc);
+}
+
+void EnumDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+ /* Anonymous enum members get added to enclosing scope.
+ */
+ ScopeDsymbol *scopesym = isAnonymous() ? sds : this;
+
+ if (!isAnonymous())
+ {
+ ScopeDsymbol::addMember(sc, sds);
+
+ if (!symtab)
+ symtab = new DsymbolTable();
+ }
+
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ EnumMember *em = (*members)[i]->isEnumMember();
+ em->ed = this;
+ //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars());
+ em->addMember(sc, isAnonymous() ? scopesym : this);
+ }
+ }
+ added = true;
+}
+
+
+void EnumDeclaration::semantic(Scope *sc)
+{
+ //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars());
+ //printf("EnumDeclaration::semantic() %p %s\n", this, toChars());
+ if (semanticRun >= PASSsemanticdone)
+ return; // semantic() already completed
+ if (semanticRun == PASSsemantic)
+ {
+ assert(memtype);
+ ::error(loc, "circular reference to enum base type %s", memtype->toChars());
+ errors = true;
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ unsigned dprogress_save = Module::dprogress;
+
+ Scope *scx = NULL;
+ if (_scope)
+ {
+ sc = _scope;
+ scx = _scope; // save so we don't make redundant copies
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ type = type->semantic(loc, sc);
+
+ protection = sc->protection;
+ if (sc->stc & STCdeprecated)
+ isdeprecated = true;
+ userAttribDecl = sc->userAttribDecl;
+
+ semanticRun = PASSsemantic;
+
+ if (!members && !memtype) // enum ident;
+ {
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+
+ if (!symtab)
+ symtab = new DsymbolTable();
+
+ /* The separate, and distinct, cases are:
+ * 1. enum { ... }
+ * 2. enum : memtype { ... }
+ * 3. enum ident { ... }
+ * 4. enum ident : memtype { ... }
+ * 5. enum ident : memtype;
+ * 6. enum ident;
+ */
+
+ if (memtype)
+ {
+ memtype = memtype->semantic(loc, sc);
+
+ /* Check to see if memtype is forward referenced
+ */
+ if (memtype->ty == Tenum)
+ {
+ EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc);
+ if (!sym->memtype || !sym->members || !sym->symtab || sym->_scope)
+ {
+ // memtype is forward referenced, so try again later
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ _scope->_module->addDeferredSemantic(this);
+ Module::dprogress = dprogress_save;
+ //printf("\tdeferring %s\n", toChars());
+ semanticRun = PASSinit;
+ return;
+ }
+ }
+ if (memtype->ty == Tvoid)
+ {
+ error("base type must not be void");
+ memtype = Type::terror;
+ }
+ if (memtype->ty == Terror)
+ {
+ errors = true;
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->errors = true; // poison all the members
+ }
+ }
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ }
+
+ semanticRun = PASSsemanticdone;
+
+ if (!members) // enum ident : memtype;
+ return;
+
+ if (members->dim == 0)
+ {
+ error("enum %s must have at least one member", toChars());
+ errors = true;
+ return;
+ }
+
+ Module::dprogress++;
+
+ Scope *sce;
+ if (isAnonymous())
+ sce = sc;
+ else
+ {
+ sce = sc->push(this);
+ sce->parent = this;
+ }
+ sce = sce->startCTFE();
+ sce->setNoFree(); // needed for getMaxMinValue()
+
+ /* Each enum member gets the sce scope
+ */
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ EnumMember *em = (*members)[i]->isEnumMember();
+ if (em)
+ em->_scope = sce;
+ }
+
+ if (!added)
+ {
+ /* addMember() is not called when the EnumDeclaration appears as a function statement,
+ * so we have to do what addMember() does and install the enum members in the right symbol
+ * table
+ */
+ ScopeDsymbol *scopesym = NULL;
+ if (isAnonymous())
+ {
+ /* Anonymous enum members get added to enclosing scope.
+ */
+ for (Scope *sct = sce; 1; sct = sct->enclosing)
+ {
+ assert(sct);
+ if (sct->scopesym)
+ {
+ scopesym = sct->scopesym;
+ if (!sct->scopesym->symtab)
+ sct->scopesym->symtab = new DsymbolTable();
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Otherwise enum members are in the EnumDeclaration's symbol table
+ scopesym = this;
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ EnumMember *em = (*members)[i]->isEnumMember();
+ if (em)
+ {
+ em->ed = this;
+ em->addMember(sc, scopesym);
+ }
+ }
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ EnumMember *em = (*members)[i]->isEnumMember();
+ if (em)
+ em->semantic(em->_scope);
+ }
+ //printf("defaultval = %lld\n", defaultval);
+
+ //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
+ //printf("members = %s\n", members->toChars());
+}
+
+/******************************
+ * Get the value of the .max/.min property as an Expression
+ * Input:
+ * id Id::max or Id::min
+ */
+
+Expression *EnumDeclaration::getMaxMinValue(Loc loc, Identifier *id)
+{
+ //printf("EnumDeclaration::getMaxValue()\n");
+ bool first = true;
+
+ Expression **pval = (id == Id::max) ? &maxval : &minval;
+
+ if (inuse)
+ {
+ error(loc, "recursive definition of .%s property", id->toChars());
+ goto Lerrors;
+ }
+ if (*pval)
+ goto Ldone;
+
+ if (_scope)
+ semantic(_scope);
+ if (errors)
+ goto Lerrors;
+ if (semanticRun == PASSinit || !members)
+ {
+ if (isSpecial())
+ {
+ /* Allow these special enums to not need a member list
+ */
+ return memtype->getProperty(loc, id, 0);
+ }
+
+ error("is forward referenced looking for .%s", id->toChars());
+ goto Lerrors;
+ }
+ if (!(memtype && memtype->isintegral()))
+ {
+ error(loc, "has no .%s property because base type %s is not an integral type",
+ id->toChars(),
+ memtype ? memtype->toChars() : "");
+ goto Lerrors;
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ EnumMember *em = (*members)[i]->isEnumMember();
+ if (!em)
+ continue;
+ if (em->errors)
+ goto Lerrors;
+
+ Expression *e = em->value();
+ if (first)
+ {
+ *pval = e;
+ first = false;
+ }
+ else
+ {
+ /* In order to work successfully with UDTs,
+ * build expressions to do the comparisons,
+ * and let the semantic analyzer and constant
+ * folder give us the result.
+ */
+
+ /* Compute:
+ * if (e > maxval)
+ * maxval = e;
+ */
+ Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval);
+ inuse++;
+ ec = ::semantic(ec, em->_scope);
+ inuse--;
+ ec = ec->ctfeInterpret();
+ if (ec->toInteger())
+ *pval = e;
+ }
+ }
+Ldone:
+ {
+ Expression *e = *pval;
+ if (e->op != TOKerror)
+ {
+ e = e->copy();
+ e->loc = loc;
+ }
+ return e;
+ }
+
+Lerrors:
+ *pval = new ErrorExp();
+ return *pval;
+}
+
+/****************
+ * Determine if enum is a 'special' one.
+ * Returns:
+ * true if special
+ */
+bool EnumDeclaration::isSpecial() const
+{
+ return (ident == Id::__c_long ||
+ ident == Id::__c_ulong ||
+ ident == Id::__c_longlong ||
+ ident == Id::__c_ulonglong ||
+ ident == Id::__c_long_double) && memtype;
+}
+
+Expression *EnumDeclaration::getDefaultValue(Loc loc)
+{
+ //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
+ if (defaultval)
+ return defaultval;
+
+ if (_scope)
+ semantic(_scope);
+ if (errors)
+ goto Lerrors;
+ if (semanticRun == PASSinit || !members)
+ {
+ if (isSpecial())
+ {
+ /* Allow these special enums to not need a member list
+ */
+ return memtype->defaultInit(loc);
+ }
+
+ error(loc, "forward reference of %s.init", toChars());
+ goto Lerrors;
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ EnumMember *em = (*members)[i]->isEnumMember();
+ if (em)
+ {
+ defaultval = em->value();
+ return defaultval;
+ }
+ }
+
+Lerrors:
+ defaultval = new ErrorExp();
+ return defaultval;
+}
+
+Type *EnumDeclaration::getMemtype(Loc loc)
+{
+ if (loc.linnum == 0)
+ loc = this->loc;
+ if (_scope)
+ {
+ /* Enum is forward referenced. We don't need to resolve the whole thing,
+ * just the base type
+ */
+ if (memtype)
+ memtype = memtype->semantic(loc, _scope);
+ else
+ {
+ if (!isAnonymous() && members)
+ memtype = Type::tint32;
+ }
+ }
+ if (!memtype)
+ {
+ if (!isAnonymous() && members)
+ memtype = Type::tint32;
+ else
+ {
+ error(loc, "is forward referenced looking for base type");
+ return Type::terror;
+ }
+ }
+ return memtype;
+}
+
+bool EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
+{
+ if (isAnonymous())
+ return Dsymbol::oneMembers(members, ps, ident);
+ return Dsymbol::oneMember(ps, ident);
+}
+
+Type *EnumDeclaration::getType()
+{
+ return type;
+}
+
+const char *EnumDeclaration::kind()
+{
+ return "enum";
+}
+
+bool EnumDeclaration::isDeprecated()
+{
+ return isdeprecated;
+}
+
+Prot EnumDeclaration::prot()
+{
+ return protection;
+}
+
+Dsymbol *EnumDeclaration::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
+ if (_scope)
+ {
+ // Try one last time to resolve this enum
+ semantic(_scope);
+ }
+
+ if (!members || !symtab || _scope)
+ {
+ error("is forward referenced when looking for '%s'", ident->toChars());
+ //*(char*)0=0;
+ return NULL;
+ }
+
+ Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
+ return s;
+}
+
+/********************************* EnumMember ****************************/
+
+EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType)
+ : VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
+{
+ this->ed = NULL;
+ this->origValue = value;
+ this->origType = origType;
+}
+
+Expression *&EnumMember::value()
+{
+ return ((ExpInitializer*)_init)->exp;
+}
+
+Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new EnumMember(loc, ident,
+ value() ? value()->syntaxCopy() : NULL,
+ origType ? origType->syntaxCopy() : NULL);
+}
+
+const char *EnumMember::kind()
+{
+ return "enum member";
+}
+
+void EnumMember::semantic(Scope *sc)
+{
+ //printf("EnumMember::semantic() %s\n", toChars());
+ if (errors || semanticRun >= PASSsemanticdone)
+ return;
+ if (semanticRun == PASSsemantic)
+ {
+ error("circular reference to enum member");
+ Lerrors:
+ errors = true;
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ assert(ed);
+ ed->semantic(sc);
+ if (ed->errors)
+ goto Lerrors;
+
+ if (errors || semanticRun >= PASSsemanticdone)
+ return;
+
+ if (_scope)
+ sc = _scope;
+ if (!sc)
+ return;
+
+ semanticRun = PASSsemantic;
+
+ protection = ed->isAnonymous() ? ed->protection : Prot(PROTpublic);
+ linkage = LINKd;
+ storage_class = STCmanifest;
+ userAttribDecl = ed->isAnonymous() ? ed->userAttribDecl : NULL;
+
+ // The first enum member is special
+ bool first = (this == (*ed->members)[0]);
+
+ if (origType)
+ {
+ origType = origType->semantic(loc, sc);
+ type = origType;
+ assert(value()); // "type id;" is not a valid enum member declaration
+ }
+
+ if (value())
+ {
+ Expression *e = value();
+ assert(e->dyncast() == DYNCAST_EXPRESSION);
+ e = ::semantic(e, sc);
+ e = resolveProperties(sc, e);
+ e = e->ctfeInterpret();
+ if (e->op == TOKerror)
+ goto Lerrors;
+ if (first && !ed->memtype && !ed->isAnonymous())
+ {
+ ed->memtype = e->type;
+ if (ed->memtype->ty == Terror)
+ {
+ ed->errors = true;
+ goto Lerrors;
+ }
+ if (ed->memtype->ty != Terror)
+ {
+ /* Bugzilla 11746: All of named enum members should have same type
+ * with the first member. If the following members were referenced
+ * during the first member semantic, their types should be unified.
+ */
+ for (size_t i = 0; i < ed->members->dim; i++)
+ {
+ EnumMember *em = (*ed->members)[i]->isEnumMember();
+ if (!em || em == this || em->semanticRun < PASSsemanticdone || em->origType)
+ continue;
+
+ //printf("[%d] em = %s, em->semanticRun = %d\n", i, toChars(), em->semanticRun);
+ Expression *ev = em->value();
+ ev = ev->implicitCastTo(sc, ed->memtype);
+ ev = ev->ctfeInterpret();
+ ev = ev->castTo(sc, ed->type);
+ if (ev->op == TOKerror)
+ ed->errors = true;
+ em->value() = ev;
+ }
+ if (ed->errors)
+ {
+ ed->memtype = Type::terror;
+ goto Lerrors;
+ }
+ }
+ }
+
+ if (ed->memtype && !origType)
+ {
+ e = e->implicitCastTo(sc, ed->memtype);
+ e = e->ctfeInterpret();
+
+ // save origValue for better json output
+ origValue = e;
+
+ if (!ed->isAnonymous())
+ {
+ e = e->castTo(sc, ed->type);
+ e = e->ctfeInterpret();
+ }
+ }
+ else if (origType)
+ {
+ e = e->implicitCastTo(sc, origType);
+ e = e->ctfeInterpret();
+ assert(ed->isAnonymous());
+
+ // save origValue for better json output
+ origValue = e;
+ }
+ value() = e;
+ }
+ else if (first)
+ {
+ Type *t;
+ if (ed->memtype)
+ t = ed->memtype;
+ else
+ {
+ t = Type::tint32;
+ if (!ed->isAnonymous())
+ ed->memtype = t;
+ }
+ Expression *e = new IntegerExp(loc, 0, Type::tint32);
+ e = e->implicitCastTo(sc, t);
+ e = e->ctfeInterpret();
+
+ // save origValue for better json output
+ origValue = e;
+
+ if (!ed->isAnonymous())
+ {
+ e = e->castTo(sc, ed->type);
+ e = e->ctfeInterpret();
+ }
+ value() = e;
+ }
+ else
+ {
+ /* Find the previous enum member,
+ * and set this to be the previous value + 1
+ */
+ EnumMember *emprev = NULL;
+ for (size_t i = 0; i < ed->members->dim; i++)
+ {
+ EnumMember *em = (*ed->members)[i]->isEnumMember();
+ if (em)
+ {
+ if (em == this)
+ break;
+ emprev = em;
+ }
+ }
+ assert(emprev);
+ if (emprev->semanticRun < PASSsemanticdone) // if forward reference
+ emprev->semantic(emprev->_scope); // resolve it
+ if (emprev->errors)
+ goto Lerrors;
+
+ Expression *eprev = emprev->value();
+ Type *tprev = eprev->type->equals(ed->type) ? ed->memtype : eprev->type;
+
+ Expression *emax = tprev->getProperty(ed->loc, Id::max, 0);
+ emax = ::semantic(emax, sc);
+ emax = emax->ctfeInterpret();
+
+ // Set value to (eprev + 1).
+ // But first check that (eprev != emax)
+ assert(eprev);
+ Expression *e = new EqualExp(TOKequal, loc, eprev, emax);
+ e = ::semantic(e, sc);
+ e = e->ctfeInterpret();
+ if (e->toInteger())
+ {
+ error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev->ed->toChars(), emprev->toChars(), ed->type->toBasetype()->toChars());
+ goto Lerrors;
+ }
+
+ // Now set e to (eprev + 1)
+ e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type::tint32));
+ e = ::semantic(e, sc);
+ e = e->castTo(sc, eprev->type);
+ e = e->ctfeInterpret();
+
+ // save origValue (without cast) for better json output
+ if (e->op != TOKerror) // avoid duplicate diagnostics
+ {
+ assert(emprev->origValue);
+ origValue = new AddExp(loc, emprev->origValue, new IntegerExp(loc, 1, Type::tint32));
+ origValue = ::semantic(origValue, sc);
+ origValue = origValue->ctfeInterpret();
+ }
+
+ if (e->op == TOKerror)
+ goto Lerrors;
+ if (e->type->isfloating())
+ {
+ // Check that e != eprev (not always true for floats)
+ Expression *etest = new EqualExp(TOKequal, loc, e, eprev);
+ etest = ::semantic(etest, sc);
+ etest = etest->ctfeInterpret();
+ if (etest->toInteger())
+ {
+ error("has inexact value, due to loss of precision");
+ goto Lerrors;
+ }
+ }
+ value() = e;
+ }
+ if (!origType)
+ type = value()->type;
+
+ assert(origValue);
+ semanticRun = PASSsemanticdone;
+}
+
+Expression *EnumMember::getVarExp(Loc loc, Scope *sc)
+{
+ semantic(sc);
+ if (errors)
+ return new ErrorExp();
+ Expression *e = new VarExp(loc, this);
+ return ::semantic(e, sc);
+}
diff --git a/gcc/d/dmd/dimport.c b/gcc/d/dmd/dimport.c
new file mode 100644
index 0000000..03b3d1f
--- /dev/null
+++ b/gcc/d/dmd/dimport.c
@@ -0,0 +1,480 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/import.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root/root.h"
+#include "mars.h"
+#include "dsymbol.h"
+#include "import.h"
+#include "identifier.h"
+#include "module.h"
+#include "scope.h"
+#include "mtype.h"
+#include "declaration.h"
+#include "id.h"
+#include "attrib.h"
+#include "hdrgen.h"
+
+/********************************* Import ****************************/
+
+Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
+ int isstatic)
+ : Dsymbol(NULL)
+{
+ assert(id);
+ this->loc = loc;
+ this->packages = packages;
+ this->id = id;
+ this->aliasId = aliasId;
+ this->isstatic = isstatic;
+ this->protection = Prot(PROTprivate); // default to private
+ this->pkg = NULL;
+ this->mod = NULL;
+
+ // Set symbol name (bracketed)
+ if (aliasId)
+ {
+ // import [cstdio] = std.stdio;
+ this->ident = aliasId;
+ }
+ else if (packages && packages->dim)
+ {
+ // import [std].stdio;
+ this->ident = (*packages)[0];
+ }
+ else
+ {
+ // import [foo];
+ this->ident = id;
+ }
+}
+
+void Import::addAlias(Identifier *name, Identifier *alias)
+{
+ if (isstatic)
+ error("cannot have an import bind list");
+
+ if (!aliasId)
+ this->ident = NULL; // make it an anonymous import
+
+ names.push(name);
+ aliases.push(alias);
+}
+
+const char *Import::kind()
+{
+ return isstatic ? "static import" : "import";
+}
+
+Prot Import::prot()
+{
+ return protection;
+}
+
+Dsymbol *Import::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+
+ Import *si = new Import(loc, packages, id, aliasId, isstatic);
+
+ for (size_t i = 0; i < names.dim; i++)
+ {
+ si->addAlias(names[i], aliases[i]);
+ }
+
+ return si;
+}
+
+void Import::load(Scope *sc)
+{
+ //printf("Import::load('%s') %p\n", toPrettyChars(), this);
+
+ // See if existing module
+ DsymbolTable *dst = Package::resolve(packages, NULL, &pkg);
+ Dsymbol *s = dst->lookup(id);
+ if (s)
+ {
+ if (s->isModule())
+ mod = (Module *)s;
+ else
+ {
+ if (s->isAliasDeclaration())
+ {
+ ::error(loc, "%s %s conflicts with %s", s->kind(), s->toPrettyChars(), id->toChars());
+ }
+ else if (Package *p = s->isPackage())
+ {
+ if (p->isPkgMod == PKGunknown)
+ {
+ mod = Module::load(loc, packages, id);
+ if (!mod)
+ p->isPkgMod = PKGpackage;
+ else
+ {
+ // mod is a package.d, or a normal module which conflicts with the package name.
+ assert(mod->isPackageFile == (p->isPkgMod == PKGmodule));
+ if (mod->isPackageFile)
+ mod->tag = p->tag; // reuse the same package tag
+ }
+ }
+ else
+ {
+ mod = p->isPackageMod();
+ }
+ if (!mod)
+ {
+ ::error(loc, "can only import from a module, not from package %s.%s",
+ p->toPrettyChars(), id->toChars());
+ }
+ }
+ else if (pkg)
+ {
+ ::error(loc, "can only import from a module, not from package %s.%s",
+ pkg->toPrettyChars(), id->toChars());
+ }
+ else
+ {
+ ::error(loc, "can only import from a module, not from package %s",
+ id->toChars());
+ }
+ }
+ }
+
+ if (!mod)
+ {
+ // Load module
+ mod = Module::load(loc, packages, id);
+ if (mod)
+ {
+ dst->insert(id, mod); // id may be different from mod->ident,
+ // if so then insert alias
+ }
+ }
+ if (mod && !mod->importedFrom)
+ mod->importedFrom = sc ? sc->_module->importedFrom : Module::rootModule;
+ if (!pkg)
+ pkg = mod;
+
+ //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
+}
+
+void Import::importAll(Scope *sc)
+{
+ if (!mod)
+ {
+ load(sc);
+ if (mod) // if successfully loaded module
+ {
+ if (mod->md && mod->md->isdeprecated)
+ {
+ Expression *msg = mod->md->msg;
+ if (StringExp *se = msg ? msg->toStringExp() : NULL)
+ mod->deprecation(loc, "is deprecated - %s", se->string);
+ else
+ mod->deprecation(loc, "is deprecated");
+ }
+
+ mod->importAll(NULL);
+
+ if (sc->explicitProtection)
+ protection = sc->protection;
+ if (!isstatic && !aliasId && !names.dim)
+ {
+ sc->scopesym->importScope(mod, protection);
+ }
+ }
+ }
+}
+
+void Import::semantic(Scope *sc)
+{
+ //printf("Import::semantic('%s') %s\n", toPrettyChars(), id->toChars());
+
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ // Load if not already done so
+ if (!mod)
+ {
+ load(sc);
+ if (mod)
+ mod->importAll(NULL);
+ }
+
+ if (mod)
+ {
+ // Modules need a list of each imported module
+ //printf("%s imports %s\n", sc->_module->toChars(), mod->toChars());
+ sc->_module->aimports.push(mod);
+
+ if (sc->explicitProtection)
+ protection = sc->protection;
+
+ if (!aliasId && !names.dim) // neither a selective nor a renamed import
+ {
+ ScopeDsymbol *scopesym = NULL;
+ if (sc->explicitProtection)
+ protection = sc->protection.kind;
+ for (Scope *scd = sc; scd; scd = scd->enclosing)
+ {
+ if (!scd->scopesym)
+ continue;
+ scopesym = scd->scopesym;
+ break;
+ }
+
+ if (!isstatic)
+ {
+ scopesym->importScope(mod, protection);
+ }
+
+ // Mark the imported packages as accessible from the current
+ // scope. This access check is necessary when using FQN b/c
+ // we're using a single global package tree. See Bugzilla 313.
+ if (packages)
+ {
+ // import a.b.c.d;
+ Package *p = pkg; // a
+ scopesym->addAccessiblePackage(p, protection);
+ for (size_t i = 1; i < packages->dim; i++) // [b, c]
+ {
+ Identifier *id = (*packages)[i];
+ p = (Package *) p->symtab->lookup(id);
+ scopesym->addAccessiblePackage(p, protection);
+ }
+ }
+ scopesym->addAccessiblePackage(mod, protection); // d
+ }
+
+ mod->semantic(NULL);
+
+ if (mod->needmoduleinfo)
+ {
+ //printf("module4 %s because of %s\n", sc->_module->toChars(), mod->toChars());
+ sc->_module->needmoduleinfo = 1;
+ }
+
+ sc = sc->push(mod);
+ sc->protection = protection;
+ for (size_t i = 0; i < aliasdecls.dim; i++)
+ {
+ AliasDeclaration *ad = aliasdecls[i];
+ //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i]->toChars(), names[i]->toChars(), ad->_scope);
+ if (mod->search(loc, names[i]))
+ {
+ ad->semantic(sc);
+ // If the import declaration is in non-root module,
+ // analysis of the aliased symbol is deferred.
+ // Therefore, don't see the ad->aliassym or ad->type here.
+ }
+ else
+ {
+ Dsymbol *s = mod->search_correct(names[i]);
+ if (s)
+ mod->error(loc, "import '%s' not found, did you mean %s '%s'?", names[i]->toChars(), s->kind(), s->toChars());
+ else
+ mod->error(loc, "import '%s' not found", names[i]->toChars());
+ ad->type = Type::terror;
+ }
+ }
+ sc = sc->pop();
+ }
+
+ // object self-imports itself, so skip that (Bugzilla 7547)
+ // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164)
+ if (global.params.moduleDeps != NULL &&
+ !(id == Id::object && sc->_module->ident == Id::object) &&
+ sc->_module->ident != Id::entrypoint &&
+ strcmp(sc->_module->ident->toChars(), "__main") != 0)
+ {
+ /* The grammar of the file is:
+ * ImportDeclaration
+ * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
+ * ModuleAliasIdentifier ] "\n"
+ *
+ * BasicImportDeclaration
+ * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
+ * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
+ *
+ * FilePath
+ * - any string with '(', ')' and '\' escaped with the '\' character
+ */
+
+ OutBuffer *ob = global.params.moduleDeps;
+ Module* imod = sc->instantiatingModule();
+ if (!global.params.moduleDepsFile)
+ ob->writestring("depsImport ");
+ ob->writestring(imod->toPrettyChars());
+ ob->writestring(" (");
+ escapePath(ob, imod->srcfile->toChars());
+ ob->writestring(") : ");
+
+ // use protection instead of sc->protection because it couldn't be
+ // resolved yet, see the comment above
+ protectionToBuffer(ob, protection);
+ ob->writeByte(' ');
+ if (isstatic)
+ {
+ stcToBuffer(ob, STCstatic);
+ ob->writeByte(' ');
+ }
+ ob->writestring(": ");
+
+ if (packages)
+ {
+ for (size_t i = 0; i < packages->dim; i++)
+ {
+ Identifier *pid = (*packages)[i];
+ ob->printf("%s.", pid->toChars());
+ }
+ }
+
+ ob->writestring(id->toChars());
+ ob->writestring(" (");
+ if (mod)
+ escapePath(ob, mod->srcfile->toChars());
+ else
+ ob->writestring("???");
+ ob->writeByte(')');
+
+ for (size_t i = 0; i < names.dim; i++)
+ {
+ if (i == 0)
+ ob->writeByte(':');
+ else
+ ob->writeByte(',');
+
+ Identifier *name = names[i];
+ Identifier *alias = aliases[i];
+
+ if (!alias)
+ {
+ ob->printf("%s", name->toChars());
+ alias = name;
+ }
+ else
+ ob->printf("%s=%s", alias->toChars(), name->toChars());
+ }
+
+ if (aliasId)
+ ob->printf(" -> %s", aliasId->toChars());
+
+ ob->writenl();
+ }
+
+ //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
+}
+
+void Import::semantic2(Scope *sc)
+{
+ //printf("Import::semantic2('%s')\n", toChars());
+ if (mod)
+ {
+ mod->semantic2(NULL);
+ if (mod->needmoduleinfo)
+ {
+ //printf("module5 %s because of %s\n", sc->_module->toChars(), mod->toChars());
+ if (sc)
+ sc->_module->needmoduleinfo = 1;
+ }
+ }
+}
+
+Dsymbol *Import::toAlias()
+{
+ if (aliasId)
+ return mod;
+ return this;
+}
+
+/*****************************
+ * Add import to sd's symbol table.
+ */
+
+void Import::addMember(Scope *sc, ScopeDsymbol *sd)
+{
+ //printf("Import::addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd->toChars(), sc);
+ if (names.dim == 0)
+ return Dsymbol::addMember(sc, sd);
+
+ if (aliasId)
+ Dsymbol::addMember(sc, sd);
+
+ /* Instead of adding the import to sd's symbol table,
+ * add each of the alias=name pairs
+ */
+ for (size_t i = 0; i < names.dim; i++)
+ {
+ Identifier *name = names[i];
+ Identifier *alias = aliases[i];
+
+ if (!alias)
+ alias = name;
+
+ TypeIdentifier *tname = new TypeIdentifier(loc, name);
+ AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
+ ad->_import = this;
+ ad->addMember(sc, sd);
+
+ aliasdecls.push(ad);
+ }
+}
+
+void Import::setScope(Scope *sc)
+{
+ Dsymbol::setScope(sc);
+ if (aliasdecls.dim)
+ {
+ if (!mod)
+ importAll(sc);
+
+ sc = sc->push(mod);
+ sc->protection = protection;
+ for (size_t i = 0; i < aliasdecls.dim; i++)
+ {
+ AliasDeclaration *ad = aliasdecls[i];
+ ad->setScope(sc);
+ }
+ sc = sc->pop();
+ }
+}
+
+Dsymbol *Import::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
+
+ if (!pkg)
+ {
+ load(NULL);
+ mod->importAll(NULL);
+ mod->semantic(NULL);
+ }
+
+ // Forward it to the package/module
+ return pkg->search(loc, ident, flags);
+}
+
+bool Import::overloadInsert(Dsymbol *s)
+{
+ /* Allow multiple imports with the same package base, but disallow
+ * alias collisions (Bugzilla 5412).
+ */
+ assert(ident && ident == s->ident);
+ Import *imp;
+ if (!aliasId && (imp = s->isImport()) != NULL && !imp->aliasId)
+ return true;
+ else
+ return false;
+}
diff --git a/gcc/d/dmd/dinterpret.c b/gcc/d/dmd/dinterpret.c
new file mode 100644
index 0000000..54bf00d
--- /dev/null
+++ b/gcc/d/dmd/dinterpret.c
@@ -0,0 +1,6801 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/interpret.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h> // mem{cpy|set}()
+#include <new>
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "mtype.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "utf.h"
+#include "attrib.h" // for AttribDeclaration
+
+#include "template.h"
+#include "ctfe.h"
+
+/* Interpreter: what form of return value expression is required?
+ */
+enum CtfeGoal
+{
+ ctfeNeedRvalue, // Must return an Rvalue (== CTFE value)
+ ctfeNeedLvalue, // Must return an Lvalue (== CTFE reference)
+ ctfeNeedNothing // The return value is not required
+};
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+Expression *interpret(Statement *s, InterState *istate);
+Expression *interpret(Expression *e, InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
+Expression *semantic(Expression *e, Scope *sc);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+static Expression *interpret(UnionExp *pue, Expression *e, InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
+static Expression *interpret(UnionExp *pue, Statement *s, InterState *istate);
+
+#define SHOWPERFORMANCE 0
+
+// Maximum allowable recursive function calls in CTFE
+#define CTFE_RECURSION_LIMIT 1000
+
+/**
+ The values of all CTFE variables
+*/
+struct CtfeStack
+{
+private:
+ /* The stack. Every declaration we encounter is pushed here,
+ together with the VarDeclaration, and the previous
+ stack address of that variable, so that we can restore it
+ when we leave the stack frame.
+ Note that when a function is forward referenced, the interpreter must
+ run semantic3, and that may start CTFE again with a NULL istate. Thus
+ the stack might not be empty when CTFE begins.
+
+ Ctfe Stack addresses are just 0-based integers, but we save
+ them as 'void *' because Array can only do pointers.
+ */
+ Expressions values; // values on the stack
+ VarDeclarations vars; // corresponding variables
+ Array<void *> savedId; // id of the previous state of that var
+
+ Array<void *> frames; // all previous frame pointers
+ Expressions savedThis; // all previous values of localThis
+
+ /* Global constants get saved here after evaluation, so we never
+ * have to redo them. This saves a lot of time and memory.
+ */
+ Expressions globalValues; // values of global constants
+
+ size_t framepointer; // current frame pointer
+ size_t maxStackPointer; // most stack we've ever used
+ Expression *localThis; // value of 'this', or NULL if none
+public:
+ CtfeStack();
+
+ size_t stackPointer();
+
+ // The current value of 'this', or NULL if none
+ Expression *getThis();
+
+ // Largest number of stack positions we've used
+ size_t maxStackUsage();
+ // Start a new stack frame, using the provided 'this'.
+ void startFrame(Expression *thisexp);
+ void endFrame();
+ bool isInCurrentFrame(VarDeclaration *v);
+ Expression *getValue(VarDeclaration *v);
+ void setValue(VarDeclaration *v, Expression *e);
+ void push(VarDeclaration *v);
+ void pop(VarDeclaration *v);
+ void popAll(size_t stackpointer);
+ void saveGlobalConstant(VarDeclaration *v, Expression *e);
+};
+
+struct InterState
+{
+ InterState *caller; // calling function's InterState
+ FuncDeclaration *fd; // function being interpreted
+ Statement *start; // if !=NULL, start execution at this statement
+ /* target of CTFEExp result; also
+ * target of labelled CTFEExp or
+ * CTFEExp. (NULL if no label).
+ */
+ Statement *gotoTarget;
+
+ InterState();
+};
+
+/************** CtfeStack ********************************************/
+
+CtfeStack ctfeStack;
+
+CtfeStack::CtfeStack() : framepointer(0), maxStackPointer(0)
+{
+}
+
+size_t CtfeStack::stackPointer()
+{
+ return values.dim;
+}
+
+Expression *CtfeStack::getThis()
+{
+ return localThis;
+}
+
+// Largest number of stack positions we've used
+size_t CtfeStack::maxStackUsage()
+{
+ return maxStackPointer;
+}
+
+void CtfeStack::startFrame(Expression *thisexp)
+{
+ frames.push((void *)(size_t)(framepointer));
+ savedThis.push(localThis);
+ framepointer = stackPointer();
+ localThis = thisexp;
+}
+
+void CtfeStack::endFrame()
+{
+ size_t oldframe = (size_t)(frames[frames.dim-1]);
+ localThis = savedThis[savedThis.dim-1];
+ popAll(framepointer);
+ framepointer = oldframe;
+ frames.setDim(frames.dim - 1);
+ savedThis.setDim(savedThis.dim -1);
+}
+
+bool CtfeStack::isInCurrentFrame(VarDeclaration *v)
+{
+ if (v->isDataseg() && !v->isCTFE())
+ return false; // It's a global
+ return v->ctfeAdrOnStack >= (int)framepointer;
+}
+
+Expression *CtfeStack::getValue(VarDeclaration *v)
+{
+ if ((v->isDataseg() || v->storage_class & STCmanifest) && !v->isCTFE())
+ {
+ assert(v->ctfeAdrOnStack >= 0 &&
+ v->ctfeAdrOnStack < (int)globalValues.dim);
+ return globalValues[v->ctfeAdrOnStack];
+ }
+ assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < (int)stackPointer());
+ return values[v->ctfeAdrOnStack];
+}
+
+void CtfeStack::setValue(VarDeclaration *v, Expression *e)
+{
+ assert(!v->isDataseg() || v->isCTFE());
+ assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < (int)stackPointer());
+ values[v->ctfeAdrOnStack] = e;
+}
+
+void CtfeStack::push(VarDeclaration *v)
+{
+ assert(!v->isDataseg() || v->isCTFE());
+ if (v->ctfeAdrOnStack != -1 &&
+ v->ctfeAdrOnStack >= (int)framepointer)
+ {
+ // Already exists in this frame, reuse it.
+ values[v->ctfeAdrOnStack] = NULL;
+ return;
+ }
+ savedId.push((void *)(size_t)(v->ctfeAdrOnStack));
+ v->ctfeAdrOnStack = (int)values.dim;
+ vars.push(v);
+ values.push(NULL);
+}
+
+void CtfeStack::pop(VarDeclaration *v)
+{
+ assert(!v->isDataseg() || v->isCTFE());
+ assert(!(v->storage_class & (STCref | STCout)));
+ int oldid = v->ctfeAdrOnStack;
+ v->ctfeAdrOnStack = (int)(size_t)(savedId[oldid]);
+ if (v->ctfeAdrOnStack == (int)values.dim - 1)
+ {
+ values.pop();
+ vars.pop();
+ savedId.pop();
+ }
+}
+
+void CtfeStack::popAll(size_t stackpointer)
+{
+ if (stackPointer() > maxStackPointer)
+ maxStackPointer = stackPointer();
+ assert(values.dim >= stackpointer);
+ for (size_t i = stackpointer; i < values.dim; ++i)
+ {
+ VarDeclaration *v = vars[i];
+ v->ctfeAdrOnStack = (int)(size_t)(savedId[i]);
+ }
+ values.setDim(stackpointer);
+ vars.setDim(stackpointer);
+ savedId.setDim(stackpointer);
+}
+
+void CtfeStack::saveGlobalConstant(VarDeclaration *v, Expression *e)
+{
+ assert(v->_init && (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && !v->isCTFE());
+ v->ctfeAdrOnStack = (int)globalValues.dim;
+ globalValues.push(e);
+}
+
+/************** InterState ********************************************/
+
+InterState::InterState()
+{
+ memset(this, 0, sizeof(InterState));
+}
+
+/************** CtfeStatus ********************************************/
+
+int CtfeStatus::callDepth = 0;
+int CtfeStatus::stackTraceCallsToSuppress = 0;
+int CtfeStatus::maxCallDepth = 0;
+int CtfeStatus::numArrayAllocs = 0;
+int CtfeStatus::numAssignments = 0;
+
+// CTFE diagnostic information
+void printCtfePerformanceStats()
+{
+#if SHOWPERFORMANCE
+ printf(" ---- CTFE Performance ----\n");
+ printf("max call depth = %d\tmax stack = %d\n", CtfeStatus::maxCallDepth, ctfeStack.maxStackUsage());
+ printf("array allocs = %d\tassignments = %d\n\n", CtfeStatus::numArrayAllocs, CtfeStatus::numAssignments);
+#endif
+}
+
+VarDeclaration *findParentVar(Expression *e);
+Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
+ FuncDeclaration *fd, Expressions *arguments, Expression *pthis);
+Expression *evaluatePostblit(InterState *istate, Expression *e);
+Expression *evaluateDtor(InterState *istate, Expression *e);
+Expression *scrubReturnValue(Loc loc, Expression *e);
+
+Expression *scrubCacheValue(Loc loc, Expression *e);
+
+
+/*************************************
+ * CTFE-object code for a single function
+ *
+ * Currently only counts the number of local variables in the function
+ */
+struct CompiledCtfeFunction
+{
+ FuncDeclaration *func; // Function being compiled, NULL if global scope
+ int numVars; // Number of variables declared in this function
+ Loc callingloc;
+
+ CompiledCtfeFunction(FuncDeclaration *f)
+ {
+ func = f;
+ numVars = 0;
+ }
+
+ void onDeclaration(VarDeclaration *)
+ {
+ //printf("%s CTFE declare %s\n", v->loc.toChars(), v->toChars());
+ ++numVars;
+ }
+
+ void onExpression(Expression *e)
+ {
+ class VarWalker : public StoppableVisitor
+ {
+ public:
+ CompiledCtfeFunction *ccf;
+
+ VarWalker(CompiledCtfeFunction *ccf)
+ : ccf(ccf)
+ {
+ }
+
+ void visit(Expression *)
+ {
+ }
+
+ void visit(ErrorExp *e)
+ {
+ // Currently there's a front-end bug: silent errors
+ // can occur inside delegate literals inside is(typeof()).
+ // Suppress the check in this case.
+ if (global.gag && ccf->func)
+ {
+ stop = 1;
+ return;
+ }
+
+ ::error(e->loc, "CTFE internal error: ErrorExp in %s\n", ccf->func ? ccf->func->loc.toChars() : ccf->callingloc.toChars());
+ assert(0);
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ VarDeclaration *v = e->declaration->isVarDeclaration();
+ if (!v)
+ return;
+ TupleDeclaration *td = v->toAlias()->isTupleDeclaration();
+ if (td)
+ {
+ if (!td->objects)
+ return;
+ for (size_t i= 0; i < td->objects->dim; ++i)
+ {
+ RootObject *o = td->objects->tdata()[i];
+ Expression *ex = isExpression(o);
+ DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL;
+ assert(s);
+ VarDeclaration *v2 = s->s->isVarDeclaration();
+ assert(v2);
+ if (!v2->isDataseg() || v2->isCTFE())
+ ccf->onDeclaration(v2);
+ }
+ }
+ else if (!(v->isDataseg() || v->storage_class & STCmanifest) || v->isCTFE())
+ ccf->onDeclaration(v);
+ Dsymbol *s = v->toAlias();
+ if (s == v && !v->isStatic() && v->_init)
+ {
+ ExpInitializer *ie = v->_init->isExpInitializer();
+ if (ie)
+ ccf->onExpression(ie->exp);
+ }
+ }
+
+ void visit(IndexExp *e)
+ {
+ if (e->lengthVar)
+ ccf->onDeclaration(e->lengthVar);
+ }
+
+ void visit(SliceExp *e)
+ {
+ if (e->lengthVar)
+ ccf->onDeclaration(e->lengthVar);
+ }
+ };
+
+ VarWalker v(this);
+ walkPostorder(e, &v);
+ }
+};
+
+class CtfeCompiler : public Visitor
+{
+public:
+ CompiledCtfeFunction *ccf;
+
+ CtfeCompiler(CompiledCtfeFunction *ccf)
+ : ccf(ccf)
+ {
+ }
+
+ void visit(Statement *)
+ {
+ assert(0);
+ }
+
+ void visit(ExpStatement *s)
+ {
+ if (s->exp)
+ ccf->onExpression(s->exp);
+ }
+
+ void visit(CompoundStatement *s)
+ {
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ Statement *sx = (*s->statements)[i];
+ if (sx)
+ ctfeCompile(sx);
+ }
+ }
+
+ void visit(UnrolledLoopStatement *s)
+ {
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ Statement *sx = (*s->statements)[i];
+ if (sx)
+ ctfeCompile(sx);
+ }
+ }
+
+ void visit(IfStatement *s)
+ {
+ ccf->onExpression(s->condition);
+ if (s->ifbody)
+ ctfeCompile(s->ifbody);
+ if (s->elsebody)
+ ctfeCompile(s->elsebody);
+ }
+
+ void visit(ScopeStatement *s)
+ {
+ if (s->statement)
+ ctfeCompile(s->statement);
+ }
+
+ void visit(OnScopeStatement *)
+ {
+ // rewritten to try/catch/finally
+ assert(0);
+ }
+
+ void visit(DoStatement *s)
+ {
+ ccf->onExpression(s->condition);
+ if (s->_body)
+ ctfeCompile(s->_body);
+ }
+
+ void visit(WhileStatement *)
+ {
+ // rewritten to ForStatement
+ assert(0);
+ }
+
+ void visit(ForStatement *s)
+ {
+ if (s->_init)
+ ctfeCompile(s->_init);
+ if (s->condition)
+ ccf->onExpression(s->condition);
+ if (s->increment)
+ ccf->onExpression(s->increment);
+ if (s->_body)
+ ctfeCompile(s->_body);
+ }
+
+ void visit(ForeachStatement *)
+ {
+ // rewritten for ForStatement
+ assert(0);
+ }
+
+ void visit(SwitchStatement *s)
+ {
+ ccf->onExpression(s->condition);
+ // Note that the body contains the the Case and Default
+ // statements, so we only need to compile the expressions
+ for (size_t i = 0; i < s->cases->dim; i++)
+ {
+ ccf->onExpression((*s->cases)[i]->exp);
+ }
+ if (s->_body)
+ ctfeCompile(s->_body);
+ }
+
+ void visit(CaseStatement *s)
+ {
+ if (s->statement)
+ ctfeCompile(s->statement);
+ }
+
+ void visit(DefaultStatement *s)
+ {
+ if (s->statement)
+ ctfeCompile(s->statement);
+ }
+
+ void visit(GotoDefaultStatement *)
+ {
+ }
+
+ void visit(GotoCaseStatement *)
+ {
+ }
+
+ void visit(SwitchErrorStatement *)
+ {
+ }
+
+ void visit(ReturnStatement *s)
+ {
+ if (s->exp)
+ ccf->onExpression(s->exp);
+ }
+
+ void visit(BreakStatement *)
+ {
+ }
+
+ void visit(ContinueStatement *)
+ {
+ }
+
+ void visit(WithStatement *s)
+ {
+ // If it is with(Enum) {...}, just execute the body.
+ if (s->exp->op == TOKscope || s->exp->op == TOKtype)
+ {
+ }
+ else
+ {
+ ccf->onDeclaration(s->wthis);
+ ccf->onExpression(s->exp);
+ }
+ if (s->_body)
+ ctfeCompile(s->_body);
+ }
+
+ void visit(TryCatchStatement *s)
+ {
+ if (s->_body)
+ ctfeCompile(s->_body);
+ for (size_t i = 0; i < s->catches->dim; i++)
+ {
+ Catch *ca = (*s->catches)[i];
+ if (ca->var)
+ ccf->onDeclaration(ca->var);
+ if (ca->handler)
+ ctfeCompile(ca->handler);
+ }
+ }
+
+ void visit(TryFinallyStatement *s)
+ {
+ if (s->_body)
+ ctfeCompile(s->_body);
+ if (s->finalbody)
+ ctfeCompile(s->finalbody);
+ }
+
+ void visit(ThrowStatement *s)
+ {
+ ccf->onExpression(s->exp);
+ }
+
+ void visit(GotoStatement *)
+ {
+ }
+
+ void visit(LabelStatement *s)
+ {
+ if (s->statement)
+ ctfeCompile(s->statement);
+ }
+
+ void visit(ImportStatement *)
+ {
+ // Contains no variables or executable code
+ }
+
+ void visit(ForeachRangeStatement *)
+ {
+ // rewritten for ForStatement
+ assert(0);
+ }
+
+ void visit(AsmStatement *)
+ {
+ // we can't compile asm statements
+ }
+
+ void ctfeCompile(Statement *s)
+ {
+ s->accept(this);
+ }
+};
+
+/*************************************
+ * Compile this function for CTFE.
+ * At present, this merely allocates variables.
+ */
+void ctfeCompile(FuncDeclaration *fd)
+{
+ assert(!fd->ctfeCode);
+ assert(!fd->semantic3Errors);
+ assert(fd->semanticRun == PASSsemantic3done);
+
+ fd->ctfeCode = new CompiledCtfeFunction(fd);
+ if (fd->parameters)
+ {
+ Type *tb = fd->type->toBasetype();
+ assert(tb->ty == Tfunction);
+ for (size_t i = 0; i < fd->parameters->dim; i++)
+ {
+ VarDeclaration *v = (*fd->parameters)[i];
+ fd->ctfeCode->onDeclaration(v);
+ }
+ }
+ if (fd->vresult)
+ fd->ctfeCode->onDeclaration(fd->vresult);
+ CtfeCompiler v(fd->ctfeCode);
+ v.ctfeCompile(fd->fbody);
+}
+
+/*************************************
+ * Entry point for CTFE.
+ * A compile-time result is required. Give an error if not possible.
+ *
+ * `e` must be semantically valid expression. In other words, it should not
+ * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
+ * functions and may invoke a function that contains `ErrorStatement` in its body.
+ * If that, the "CTFE failed because of previous errors" error is raised.
+ */
+Expression *ctfeInterpret(Expression *e)
+{
+ if (e->op == TOKerror)
+ return e;
+ assert(e->type); // Bugzilla 14642
+ //assert(e->type->ty != Terror); // FIXME
+ if (e->type->ty == Terror)
+ return new ErrorExp();
+
+ // This code is outside a function, but still needs to be compiled
+ // (there are compiler-generated temporary variables such as __dollar).
+ // However, this will only be run once and can then be discarded.
+ CompiledCtfeFunction ctfeCodeGlobal(NULL);
+ ctfeCodeGlobal.callingloc = e->loc;
+ ctfeCodeGlobal.onExpression(e);
+
+ Expression *result = interpret(e, NULL);
+ if (!CTFEExp::isCantExp(result))
+ result = scrubReturnValue(e->loc, result);
+ if (CTFEExp::isCantExp(result))
+ result = new ErrorExp();
+ return result;
+}
+
+/* Run CTFE on the expression, but allow the expression to be a TypeExp
+ * or a tuple containing a TypeExp. (This is required by pragma(msg)).
+ */
+Expression *ctfeInterpretForPragmaMsg(Expression *e)
+{
+ if (e->op == TOKerror || e->op == TOKtype)
+ return e;
+
+ // It's also OK for it to be a function declaration (happens only with
+ // __traits(getOverloads))
+ if (e->op == TOKvar && ((VarExp *)e)->var->isFuncDeclaration())
+ {
+ return e;
+ }
+
+ if (e->op != TOKtuple)
+ return e->ctfeInterpret();
+
+ // Tuples need to be treated seperately, since they are
+ // allowed to contain a TypeExp in this case.
+
+ TupleExp *tup = (TupleExp *)e;
+ Expressions *expsx = NULL;
+ for (size_t i = 0; i < tup->exps->dim; ++i)
+ {
+ Expression *g = (*tup->exps)[i];
+ Expression *h = g;
+ h = ctfeInterpretForPragmaMsg(g);
+ if (h != g)
+ {
+ if (!expsx)
+ {
+ expsx = new Expressions();
+ expsx->setDim(tup->exps->dim);
+ for (size_t j = 0; j < tup->exps->dim; j++)
+ (*expsx)[j] = (*tup->exps)[j];
+ }
+ (*expsx)[i] = h;
+ }
+ }
+ if (expsx)
+ {
+ TupleExp *te = new TupleExp(e->loc, expsx);
+ expandTuples(te->exps);
+ te->type = new TypeTuple(te->exps);
+ return te;
+ }
+ return e;
+}
+
+/*************************************
+ * Attempt to interpret a function given the arguments.
+ * Input:
+ * istate state for calling function (NULL if none)
+ * arguments function arguments
+ * thisarg 'this', if a needThis() function, NULL if not.
+ *
+ * Return result expression if successful, TOKcantexp if not,
+ * or CTFEExp if function returned void.
+ */
+
+static Expression *interpretFunction(FuncDeclaration *fd, InterState *istate, Expressions *arguments, Expression *thisarg)
+{
+ if (fd->semanticRun == PASSsemantic3)
+ {
+ fd->error("circular dependency. Functions cannot be interpreted while being compiled");
+ return CTFEExp::cantexp;
+ }
+ if (!fd->functionSemantic3())
+ return CTFEExp::cantexp;
+ if (fd->semanticRun < PASSsemantic3done)
+ return CTFEExp::cantexp;
+
+ // CTFE-compile the function
+ if (!fd->ctfeCode)
+ ctfeCompile(fd);
+
+ Type *tb = fd->type->toBasetype();
+ assert(tb->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)tb;
+ if (tf->varargs && arguments &&
+ ((fd->parameters && arguments->dim != fd->parameters->dim) || (!fd->parameters && arguments->dim)))
+ {
+ fd->error("C-style variadic functions are not yet implemented in CTFE");
+ return CTFEExp::cantexp;
+ }
+
+ // Nested functions always inherit the 'this' pointer from the parent,
+ // except for delegates. (Note that the 'this' pointer may be null).
+ // Func literals report isNested() even if they are in global scope,
+ // so we need to check that the parent is a function.
+ if (fd->isNested() && fd->toParent2()->isFuncDeclaration() && !thisarg && istate)
+ thisarg = ctfeStack.getThis();
+
+ if (fd->needThis() && !thisarg)
+ {
+ // error, no this. Prevent segfault.
+ // Here should be unreachable by the strict 'this' check in front-end.
+ fd->error("need 'this' to access member %s", fd->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ // Place to hold all the arguments to the function while
+ // we are evaluating them.
+ Expressions eargs;
+ size_t dim = arguments ? arguments->dim : 0;
+ assert((fd->parameters ? fd->parameters->dim : 0) == dim);
+
+ /* Evaluate all the arguments to the function,
+ * store the results in eargs[]
+ */
+ eargs.setDim(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression *earg = (*arguments)[i];
+ Parameter *fparam = Parameter::getNth(tf->parameters, i);
+
+ if (fparam->storageClass & (STCout | STCref))
+ {
+ if (!istate && (fparam->storageClass & STCout))
+ {
+ // initializing an out parameter involves writing to it.
+ earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars());
+ return CTFEExp::cantexp;
+ }
+ // Convert all reference arguments into lvalue references
+ earg = interpret(earg, istate, ctfeNeedLvalue);
+ if (CTFEExp::isCantExp(earg))
+ return earg;
+ }
+ else if (fparam->storageClass & STClazy)
+ {
+ }
+ else
+ {
+ /* Value parameters
+ */
+ Type *ta = fparam->type->toBasetype();
+ if (ta->ty == Tsarray && earg->op == TOKaddress)
+ {
+ /* Static arrays are passed by a simple pointer.
+ * Skip past this to get at the actual arg.
+ */
+ earg = ((AddrExp *)earg)->e1;
+ }
+ earg = interpret(earg, istate);
+ if (CTFEExp::isCantExp(earg))
+ return earg;
+ /* Struct literals are passed by value, but we don't need to
+ * copy them if they are passed as const
+ */
+ if (earg->op == TOKstructliteral && !(fparam->storageClass & (STCconst | STCimmutable)))
+ earg = copyLiteral(earg).copy();
+ }
+ if (earg->op == TOKthrownexception)
+ {
+ if (istate)
+ return earg;
+ ((ThrownExceptionExp *)earg)->generateUncaughtError();
+ return CTFEExp::cantexp;
+ }
+ eargs[i] = earg;
+ }
+
+ // Now that we've evaluated all the arguments, we can start the frame
+ // (this is the moment when the 'call' actually takes place).
+ InterState istatex;
+ istatex.caller = istate;
+ istatex.fd = fd;
+ ctfeStack.startFrame(thisarg);
+ if (fd->vthis && thisarg)
+ {
+ ctfeStack.push(fd->vthis);
+ setValue(fd->vthis, thisarg);
+ }
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression *earg = eargs[i];
+ Parameter *fparam = Parameter::getNth(tf->parameters, i);
+ VarDeclaration *v = (*fd->parameters)[i];
+ ctfeStack.push(v);
+
+ if ((fparam->storageClass & (STCout | STCref)) &&
+ earg->op == TOKvar && ((VarExp *)earg)->var->toParent2() == fd)
+ {
+ VarDeclaration *vx = ((VarExp *)earg)->var->isVarDeclaration();
+ if (!vx)
+ {
+ fd->error("cannot interpret %s as a ref parameter", earg->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ /* vx is a variable that is declared in fd.
+ * It means that fd is recursively called. e.g.
+ *
+ * void fd(int n, ref int v = dummy) {
+ * int vx;
+ * if (n == 1) fd(2, vx);
+ * }
+ * fd(1);
+ *
+ * The old value of vx on the stack in fd(1)
+ * should be saved at the start of fd(2, vx) call.
+ */
+ int oldadr = vx->ctfeAdrOnStack;
+
+ ctfeStack.push(vx);
+ assert(!hasValue(vx)); // vx is made uninitialized
+
+ // Bugzilla 14299: v->ctfeAdrOnStack should be saved already
+ // in the stack before the overwrite.
+ v->ctfeAdrOnStack = oldadr;
+ assert(hasValue(v)); // ref parameter v should refer existing value.
+ }
+ else
+ {
+ // Value parameters and non-trivial references
+ setValueWithoutChecking(v, earg);
+ }
+ }
+
+ if (fd->vresult)
+ ctfeStack.push(fd->vresult);
+
+ // Enter the function
+ ++CtfeStatus::callDepth;
+ if (CtfeStatus::callDepth > CtfeStatus::maxCallDepth)
+ CtfeStatus::maxCallDepth = CtfeStatus::callDepth;
+
+ Expression *e = NULL;
+ while (1)
+ {
+ if (CtfeStatus::callDepth > CTFE_RECURSION_LIMIT)
+ {
+ // This is a compiler error. It must not be suppressed.
+ global.gag = 0;
+ fd->error("CTFE recursion limit exceeded");
+ e = CTFEExp::cantexp;
+ break;
+ }
+ e = interpret(fd->fbody, &istatex);
+
+ if (istatex.start)
+ {
+ fd->error("CTFE internal error: failed to resume at statement %s", istatex.start->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ /* This is how we deal with a recursive statement AST
+ * that has arbitrary goto statements in it.
+ * Bubble up a 'result' which is the target of the goto
+ * statement, then go recursively down the AST looking
+ * for that statement, then execute starting there.
+ */
+ if (CTFEExp::isGotoExp(e))
+ {
+ istatex.start = istatex.gotoTarget; // set starting statement
+ istatex.gotoTarget = NULL;
+ }
+ else
+ {
+ assert(!e || (e->op != TOKcontinue && e->op != TOKbreak));
+ break;
+ }
+ }
+ // If fell off the end of a void function, return void
+ if (!e && tf->next->ty == Tvoid)
+ e = CTFEExp::voidexp;
+ if (tf->isref && e->op == TOKvar && ((VarExp *)e)->var == fd->vthis)
+ e = thisarg;
+ assert(e != NULL);
+
+ // Leave the function
+ --CtfeStatus::callDepth;
+
+ ctfeStack.endFrame();
+
+ // If it generated an uncaught exception, report error.
+ if (!istate && e->op == TOKthrownexception)
+ {
+ ((ThrownExceptionExp *)e)->generateUncaughtError();
+ e = CTFEExp::cantexp;
+ }
+
+ return e;
+}
+
+class Interpreter : public Visitor
+{
+public:
+ InterState *istate;
+ CtfeGoal goal;
+
+ Expression *result;
+ UnionExp *pue; // storage for `result`
+
+ Interpreter(UnionExp *pue, InterState *istate, CtfeGoal goal)
+ : istate(istate), goal(goal), pue(pue)
+ {
+ result = NULL;
+ }
+
+ // If e is TOKthrowexception or TOKcantexp,
+ // set it to 'result' and returns true.
+ bool exceptionOrCant(Expression *e)
+ {
+ if (exceptionOrCantInterpret(e))
+ {
+ // Make sure e is not pointing to a stack temporary
+ result = (e->op == TOKcantexp) ? CTFEExp::cantexp : e;
+ return true;
+ }
+ return false;
+ }
+
+ static Expressions *copyArrayOnWrite(Expressions *exps, Expressions *original)
+ {
+ if (exps == original)
+ {
+ if (!original)
+ exps = new Expressions();
+ else
+ exps = original->copy();
+ ++CtfeStatus::numArrayAllocs;
+ }
+ return exps;
+ }
+
+ /******************************** Statement ***************************/
+
+ void visit(Statement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ s->error("statement %s cannot be interpreted at compile time", s->toChars());
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(ExpStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ Expression *e = interpret(pue, s->exp, istate, ctfeNeedNothing);
+ if (exceptionOrCant(e))
+ return;
+ }
+
+ void visit(CompoundStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ const size_t dim = s->statements ? s->statements->dim : 0;
+ for (size_t i = 0; i < dim; i++)
+ {
+ Statement *sx = (*s->statements)[i];
+ result = interpret(pue, sx, istate);
+ if (result)
+ break;
+ }
+ }
+
+ void visit(UnrolledLoopStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ const size_t dim = s->statements ? s->statements->dim : 0;
+ for (size_t i = 0; i < dim; i++)
+ {
+ Statement *sx = (*s->statements)[i];
+ Expression *e = interpret(pue, sx, istate);
+ if (!e) // suceeds to interpret, or goto target
+ continue; // was not fonnd when istate->start != NULL
+ if (exceptionOrCant(e))
+ return;
+ if (e->op == TOKbreak)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ result = NULL;
+ return;
+ }
+ if (e->op == TOKcontinue)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // continue at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ continue;
+ }
+
+ // expression from return statement, or thrown exception
+ result = e;
+ break;
+ }
+ }
+
+ void visit(IfStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+ if (istate->start)
+ {
+ Expression *e = NULL;
+ e = interpret(s->ifbody, istate);
+ if (!e && istate->start)
+ e = interpret(s->elsebody, istate);
+ result = e;
+ return;
+ }
+
+ UnionExp ue;
+ Expression *e = interpret(&ue, s->condition, istate);
+ assert(e);
+ if (exceptionOrCant(e))
+ return;
+
+ if (isTrueBool(e))
+ result = interpret(pue, s->ifbody, istate);
+ else if (e->isBool(false))
+ result = interpret(pue, s->elsebody, istate);
+ else
+ {
+ // no error, or assert(0)?
+ result = CTFEExp::cantexp;
+ }
+ }
+
+ void visit(ScopeStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ result = interpret(pue, s->statement, istate);
+ }
+
+ /**
+ Given an expression e which is about to be returned from the current
+ function, generate an error if it contains pointers to local variables.
+
+ Only checks expressions passed by value (pointers to local variables
+ may already be stored in members of classes, arrays, or AAs which
+ were passed as mutable function parameters).
+ Returns:
+ true if it is safe to return, false if an error was generated.
+ */
+
+ static bool stopPointersEscaping(Loc loc, Expression *e)
+ {
+ if (!e->type->hasPointers())
+ return true;
+ if (isPointer(e->type))
+ {
+ Expression *x = e;
+ if (e->op == TOKaddress)
+ x = ((AddrExp *)e)->e1;
+ VarDeclaration *v;
+ while (x->op == TOKvar &&
+ (v = ((VarExp *)x)->var->isVarDeclaration()) != NULL)
+ {
+ if (v->storage_class & STCref)
+ {
+ x = getValue(v);
+ if (e->op == TOKaddress)
+ ((AddrExp *)e)->e1 = x;
+ continue;
+ }
+ if (ctfeStack.isInCurrentFrame(v))
+ {
+ error(loc, "returning a pointer to a local stack variable");
+ return false;
+ }
+ else
+ break;
+ }
+ // TODO: If it is a TOKdotvar or TOKindex, we should check that it is not
+ // pointing to a local struct or static array.
+ }
+ if (e->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ return stopPointersEscapingFromArray(loc, se->elements);
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ return stopPointersEscapingFromArray(loc, ((ArrayLiteralExp *)e)->elements);
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+ if (!stopPointersEscapingFromArray(loc, aae->keys))
+ return false;
+ return stopPointersEscapingFromArray(loc, aae->values);
+ }
+ return true;
+ }
+
+ // Check all members of an array for escaping local variables. Return false if error
+ static bool stopPointersEscapingFromArray(Loc loc, Expressions *elems)
+ {
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ Expression *m = (*elems)[i];
+ if (!m)
+ continue;
+ if (!stopPointersEscaping(loc, m))
+ return false;
+ }
+ return true;
+ }
+
+ void visit(ReturnStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ if (!s->exp)
+ {
+ result = CTFEExp::voidexp;
+ return;
+ }
+
+ assert(istate && istate->fd && istate->fd->type && istate->fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)istate->fd->type;
+
+ /* If the function returns a ref AND it's been called from an assignment,
+ * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
+ */
+ if (tf->isref)
+ {
+ result = interpret(pue, s->exp, istate, ctfeNeedLvalue);
+ return;
+ }
+ if (tf->next && tf->next->ty == Tdelegate && istate->fd->closureVars.dim > 0)
+ {
+ // To support this, we need to copy all the closure vars
+ // into the delegate literal.
+ s->error("closures are not yet supported in CTFE");
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ // We need to treat pointers specially, because TOKsymoff can be used to
+ // return a value OR a pointer
+ Expression *e = interpret(pue, s->exp, istate);
+ if (exceptionOrCant(e))
+ return;
+
+ // Disallow returning pointers to stack-allocated variables (bug 7876)
+ if (!stopPointersEscaping(s->loc, e))
+ {
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (needToCopyLiteral(e))
+ e = copyLiteral(e).copy();
+ result = e;
+ }
+
+ static Statement *findGotoTarget(InterState *istate, Identifier *ident)
+ {
+ Statement *target = NULL;
+ if (ident)
+ {
+ LabelDsymbol *label = istate->fd->searchLabel(ident);
+ assert(label && label->statement);
+ LabelStatement *ls = label->statement;
+ target = ls->gotoTarget ? ls->gotoTarget : ls->statement;
+ }
+ return target;
+ }
+
+ void visit(BreakStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ istate->gotoTarget = findGotoTarget(istate, s->ident);
+ result = CTFEExp::breakexp;
+ }
+
+ void visit(ContinueStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ istate->gotoTarget = findGotoTarget(istate, s->ident);
+ result = CTFEExp::continueexp;
+ }
+
+ void visit(WhileStatement *)
+ {
+ assert(0); // rewritten to ForStatement
+ }
+
+ void visit(DoStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ while (1)
+ {
+ Expression *e = interpret(s->_body, istate);
+ if (!e && istate->start) // goto target was not found
+ return;
+ assert(!istate->start);
+
+ if (exceptionOrCant(e))
+ return;
+ if (e && e->op == TOKbreak)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ break;
+ }
+ if (e && e->op == TOKcontinue)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // continue at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ e = NULL;
+ }
+ if (e)
+ {
+ result = e; // bubbled up from ReturnStatement
+ return;
+ }
+
+ UnionExp ue;
+ e = interpret(&ue, s->condition, istate);
+ if (exceptionOrCant(e))
+ return;
+ if (!e->isConst())
+ {
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (e->isBool(false))
+ break;
+ assert(isTrueBool(e));
+ }
+ assert(result == NULL);
+ }
+
+ void visit(ForStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ UnionExp ueinit;
+ Expression *ei = interpret(&ueinit, s->_init, istate);
+ if (exceptionOrCant(ei))
+ return;
+ assert(!ei); // s->init never returns from function, or jumps out from it
+
+ while (1)
+ {
+ if (s->condition && !istate->start)
+ {
+ UnionExp ue;
+ Expression *e = interpret(&ue, s->condition, istate);
+ if (exceptionOrCant(e))
+ return;
+ if (e->isBool(false))
+ break;
+ assert(isTrueBool(e));
+ }
+
+ Expression *e = interpret(pue, s->_body, istate);
+ if (!e && istate->start) // goto target was not found
+ return;
+ assert(!istate->start);
+
+ if (exceptionOrCant(e))
+ return;
+ if (e && e->op == TOKbreak)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ break;
+ }
+ if (e && e->op == TOKcontinue)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // continue at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ e = NULL;
+ }
+ if (e)
+ {
+ result = e; // bubbled up from ReturnStatement
+ return;
+ }
+
+ UnionExp uei;
+ e = interpret(&uei, s->increment, istate, ctfeNeedNothing);
+ if (exceptionOrCant(e))
+ return;
+ }
+ assert(result == NULL);
+ }
+
+ void visit(ForeachStatement *)
+ {
+ assert(0); // rewritten to ForStatement
+ }
+
+ void visit(ForeachRangeStatement *)
+ {
+ assert(0); // rewritten to ForStatement
+ }
+
+ void visit(SwitchStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+ if (istate->start)
+ {
+ Expression *e = interpret(s->_body, istate);
+ if (istate->start) // goto target was not found
+ return;
+ if (exceptionOrCant(e))
+ return;
+ if (e && e->op == TOKbreak)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ e = NULL;
+ }
+ result = e;
+ return;
+ }
+
+ UnionExp uecond;
+ Expression *econdition = interpret(&uecond, s->condition, istate);
+ if (exceptionOrCant(econdition))
+ return;
+
+ Statement *scase = NULL;
+ size_t dim = s->cases ? s->cases->dim : 0;
+ for (size_t i = 0; i < dim; i++)
+ {
+ CaseStatement *cs = (*s->cases)[i];
+ UnionExp uecase;
+ Expression *ecase = interpret(&uecase, cs->exp, istate);
+ if (exceptionOrCant(ecase))
+ return;
+ if (ctfeEqual(cs->exp->loc, TOKequal, econdition, ecase))
+ {
+ scase = cs;
+ break;
+ }
+ }
+ if (!scase)
+ {
+ if (s->hasNoDefault)
+ s->error("no default or case for %s in switch statement", econdition->toChars());
+ scase = s->sdefault;
+ }
+
+ assert(scase);
+
+ /* Jump to scase
+ */
+ istate->start = scase;
+ Expression *e = interpret(pue, s->_body, istate);
+ assert(!istate->start); // jump must not fail
+ if (e && e->op == TOKbreak)
+ {
+ if (istate->gotoTarget && istate->gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate->gotoTarget = NULL;
+ e = NULL;
+ }
+ result = e;
+ }
+
+ void visit(CaseStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ result = interpret(pue, s->statement, istate);
+ }
+
+ void visit(DefaultStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ result = interpret(pue, s->statement, istate);
+ }
+
+ void visit(GotoStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ assert(s->label && s->label->statement);
+ istate->gotoTarget = s->label->statement;
+ result = CTFEExp::gotoexp;
+ }
+
+ void visit(GotoCaseStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ assert(s->cs);
+ istate->gotoTarget = s->cs;
+ result = CTFEExp::gotoexp;
+ }
+
+ void visit(GotoDefaultStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ assert(s->sw && s->sw->sdefault);
+ istate->gotoTarget = s->sw->sdefault;
+ result = CTFEExp::gotoexp;
+ }
+
+ void visit(LabelStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+
+ result = interpret(pue, s->statement, istate);
+ }
+
+ void visit(TryCatchStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+ if (istate->start)
+ {
+ Expression *e = NULL;
+ e = interpret(pue, s->_body, istate);
+ for (size_t i = 0; i < s->catches->dim; i++)
+ {
+ if (e || !istate->start) // goto target was found
+ break;
+ Catch *ca = (*s->catches)[i];
+ e = interpret(ca->handler, istate);
+ }
+ result = e;
+ return;
+ }
+
+ Expression *e = interpret(pue, s->_body, istate);
+
+ // An exception was thrown
+ if (e && e->op == TOKthrownexception)
+ {
+ ThrownExceptionExp *ex = (ThrownExceptionExp *)e;
+ Type *extype = ex->thrown->originalClass()->type;
+
+ // Search for an appropriate catch clause.
+ for (size_t i = 0; i < s->catches->dim; i++)
+ {
+ Catch *ca = (*s->catches)[i];
+ Type *catype = ca->type;
+ if (!catype->equals(extype) && !catype->isBaseOf(extype, NULL))
+ continue;
+
+ // Execute the handler
+ if (ca->var)
+ {
+ ctfeStack.push(ca->var);
+ setValue(ca->var, ex->thrown);
+ }
+ e = interpret(ca->handler, istate);
+ if (CTFEExp::isGotoExp(e))
+ {
+ /* This is an optimization that relies on the locality of the jump target.
+ * If the label is in the same catch handler, the following scan
+ * would find it quickly and can reduce jump cost.
+ * Otherwise, the catch block may be unnnecessary scanned again
+ * so it would make CTFE speed slower.
+ */
+ InterState istatex = *istate;
+ istatex.start = istate->gotoTarget; // set starting statement
+ istatex.gotoTarget = NULL;
+ Expression *eh = interpret(ca->handler, &istatex);
+ if (!istatex.start)
+ {
+ istate->gotoTarget = NULL;
+ e = eh;
+ }
+ }
+ break;
+ }
+ }
+ result = e;
+ }
+
+ static bool isAnErrorException(ClassDeclaration *cd)
+ {
+ return cd == ClassDeclaration::errorException || ClassDeclaration::errorException->isBaseOf(cd, NULL);
+ }
+
+ static ThrownExceptionExp *chainExceptions(ThrownExceptionExp *oldest, ThrownExceptionExp *newest)
+ {
+ // Little sanity check to make sure it's really a Throwable
+ ClassReferenceExp *boss = oldest->thrown;
+ assert((*boss->value->elements)[4]->type->ty == Tclass); // Throwable.next
+ ClassReferenceExp *collateral = newest->thrown;
+ if ( isAnErrorException(collateral->originalClass()) &&
+ !isAnErrorException(boss->originalClass()))
+ {
+ // The new exception bypass the existing chain
+ assert((*collateral->value->elements)[5]->type->ty == Tclass);
+ (*collateral->value->elements)[5] = boss;
+ return newest;
+ }
+ while ((*boss->value->elements)[4]->op == TOKclassreference)
+ {
+ boss = (ClassReferenceExp *)(*boss->value->elements)[4];
+ }
+ (*boss->value->elements)[4] = collateral;
+ return oldest;
+ }
+
+ void visit(TryFinallyStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+ if (istate->start)
+ {
+ Expression *e = NULL;
+ e = interpret(pue, s->_body, istate);
+ // Jump into/out from finalbody is disabled in semantic analysis.
+ // and jump inside will be handled by the ScopeStatement == finalbody.
+ result = e;
+ return;
+ }
+
+ Expression *ex = interpret(s->_body, istate);
+ if (CTFEExp::isCantExp(ex))
+ {
+ result = ex;
+ return;
+ }
+ while (CTFEExp::isGotoExp(ex))
+ {
+ // If the goto target is within the body, we must not interpret the finally statement,
+ // because that will call destructors for objects within the scope, which we should not do.
+ InterState istatex = *istate;
+ istatex.start = istate->gotoTarget; // set starting statement
+ istatex.gotoTarget = NULL;
+ Expression *bex = interpret(s->_body, &istatex);
+ if (istatex.start)
+ {
+ // The goto target is outside the current scope.
+ break;
+ }
+ // The goto target was within the body.
+ if (CTFEExp::isCantExp(bex))
+ {
+ result = bex;
+ return;
+ }
+ *istate = istatex;
+ ex = bex;
+ }
+ Expression *ey = interpret(s->finalbody, istate);
+ if (CTFEExp::isCantExp(ey))
+ {
+ result = ey;
+ return;
+ }
+ if (ey && ey->op == TOKthrownexception)
+ {
+ // Check for collided exceptions
+ if (ex && ex->op == TOKthrownexception)
+ ex = chainExceptions((ThrownExceptionExp *)ex, (ThrownExceptionExp *)ey);
+ else
+ ex = ey;
+ }
+ result = ex;
+ }
+
+ void visit(ThrowStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ Expression *e = interpret(s->exp, istate);
+ if (exceptionOrCant(e))
+ return;
+
+ assert(e->op == TOKclassreference);
+ result = new ThrownExceptionExp(s->loc, (ClassReferenceExp *)e);
+ }
+
+ void visit(OnScopeStatement *)
+ {
+ assert(0);
+ }
+
+ void visit(WithStatement *s)
+ {
+ if (istate->start == s)
+ istate->start = NULL;
+ if (istate->start)
+ {
+ result = s->_body ? interpret(s->_body, istate) : NULL;
+ return;
+ }
+
+ // If it is with(Enum) {...}, just execute the body.
+ if (s->exp->op == TOKscope || s->exp->op == TOKtype)
+ {
+ result = interpret(pue, s->_body, istate);
+ return;
+ }
+
+ Expression *e = interpret(s->exp, istate);
+ if (exceptionOrCant(e))
+ return;
+
+ if (s->wthis->type->ty == Tpointer && s->exp->type->ty != Tpointer)
+ {
+ e = new AddrExp(s->loc, e, s->wthis->type);
+ }
+ ctfeStack.push(s->wthis);
+ setValue(s->wthis, e);
+ e = interpret(s->_body, istate);
+ if (CTFEExp::isGotoExp(e))
+ {
+ /* This is an optimization that relies on the locality of the jump target.
+ * If the label is in the same WithStatement, the following scan
+ * would find it quickly and can reduce jump cost.
+ * Otherwise, the statement body may be unnnecessary scanned again
+ * so it would make CTFE speed slower.
+ */
+ InterState istatex = *istate;
+ istatex.start = istate->gotoTarget; // set starting statement
+ istatex.gotoTarget = NULL;
+ Expression *ex = interpret(s->_body, &istatex);
+ if (!istatex.start)
+ {
+ istate->gotoTarget = NULL;
+ e = ex;
+ }
+ }
+ ctfeStack.pop(s->wthis);
+ result = e;
+ }
+
+ void visit(AsmStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+
+ s->error("asm statements cannot be interpreted at compile time");
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(ImportStatement *s)
+ {
+ if (istate->start)
+ {
+ if (istate->start != s)
+ return;
+ istate->start = NULL;
+ }
+ }
+
+ /******************************** Expression ***************************/
+
+ void visit(Expression *e)
+ {
+ e->error("cannot interpret %s at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(ThisExp *e)
+ {
+ if (goal == ctfeNeedLvalue)
+ {
+ // We might end up here with istate being zero (see bugzilla 16382)
+ if (istate && istate->fd->vthis)
+ {
+ result = new VarExp(e->loc, istate->fd->vthis);
+ result->type = e->type;
+ }
+ else
+ result = e;
+ return;
+ }
+
+ result = ctfeStack.getThis();
+ if (result)
+ {
+ assert(result->op == TOKstructliteral ||
+ result->op == TOKclassreference);
+ return;
+ }
+ e->error("value of 'this' is not known at compile time");
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(NullExp *e)
+ {
+ result = e;
+ }
+
+ void visit(IntegerExp *e)
+ {
+ result = e;
+ }
+
+ void visit(RealExp *e)
+ {
+ result = e;
+ }
+
+ void visit(ComplexExp *e)
+ {
+ result = e;
+ }
+
+ void visit(StringExp *e)
+ {
+ /* Attempts to modify string literals are prevented
+ * in BinExp::interpretAssignCommon.
+ */
+ result = e;
+ }
+
+ void visit(FuncExp *e)
+ {
+ result = e;
+ }
+
+ void visit(SymOffExp *e)
+ {
+ if (e->var->isFuncDeclaration() && e->offset == 0)
+ {
+ result = e;
+ return;
+ }
+ if (isTypeInfo_Class(e->type) && e->offset == 0)
+ {
+ result = e;
+ return;
+ }
+ if (e->type->ty != Tpointer)
+ {
+ // Probably impossible
+ e->error("cannot interpret %s at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ Type *pointee = ((TypePointer *)e->type)->next;
+ if (e->var->isThreadlocal())
+ {
+ e->error("cannot take address of thread-local variable %s at compile time", e->var->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ // Check for taking an address of a shared variable.
+ // If the shared variable is an array, the offset might not be zero.
+ Type *fromType = NULL;
+ if (e->var->type->ty == Tarray || e->var->type->ty == Tsarray)
+ {
+ fromType = ((TypeArray *)(e->var->type))->next;
+ }
+ if (e->var->isDataseg() &&
+ ((e->offset == 0 && isSafePointerCast(e->var->type, pointee)) ||
+ (fromType && isSafePointerCast(fromType, pointee))))
+ {
+ result = e;
+ return;
+ }
+ Expression *val = getVarExp(e->loc, istate, e->var, goal);
+ if (exceptionOrCant(val))
+ return;
+ if (val->type->ty == Tarray || val->type->ty == Tsarray)
+ {
+ // Check for unsupported type painting operations
+ Type *elemtype = ((TypeArray *)(val->type))->next;
+ d_uns64 elemsize = elemtype->size();
+
+ // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]*
+ if (val->type->ty == Tsarray && pointee->ty == Tarray &&
+ elemsize == pointee->nextOf()->size())
+ {
+ new(pue) AddrExp(e->loc, val, e->type);
+ result = pue->exp();
+ return;
+ }
+
+ // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
+ if (val->type->ty == Tsarray && pointee->ty == Tsarray &&
+ elemsize == pointee->nextOf()->size())
+ {
+ size_t d = (size_t)((TypeSArray *)pointee)->dim->toInteger();
+ Expression *elwr = new IntegerExp(e->loc, e->offset / elemsize, Type::tsize_t);
+ Expression *eupr = new IntegerExp(e->loc, e->offset / elemsize + d, Type::tsize_t);
+
+ // Create a CTFE pointer &val[ofs..ofs+d]
+ SliceExp *se = new SliceExp(e->loc, val, elwr, eupr);
+ se->type = pointee;
+ new(pue) AddrExp(e->loc, se, e->type);
+ result = pue->exp();
+ return;
+ }
+
+ if (!isSafePointerCast(elemtype, pointee))
+ {
+ // It's also OK to cast from &string to string*.
+ if (e->offset == 0 && isSafePointerCast(e->var->type, pointee))
+ {
+ // Create a CTFE pointer &var
+ VarExp *ve = new VarExp(e->loc, e->var);
+ ve->type = elemtype;
+ new(pue) AddrExp(e->loc, ve, e->type);
+ result = pue->exp();
+ return;
+ }
+ e->error("reinterpreting cast from %s to %s is not supported in CTFE",
+ val->type->toChars(), e->type->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ const dinteger_t sz = pointee->size();
+ dinteger_t indx = e->offset / sz;
+ assert(sz * indx == e->offset);
+ Expression *aggregate = NULL;
+ if (val->op == TOKarrayliteral || val->op == TOKstring)
+ {
+ aggregate = val;
+ }
+ else if (val->op == TOKslice)
+ {
+ aggregate = ((SliceExp *)val)->e1;
+ UnionExp uelwr;
+ Expression *lwr = interpret(&uelwr, ((SliceExp *)val)->lwr, istate);
+ indx += lwr->toInteger();
+ }
+ if (aggregate)
+ {
+ // Create a CTFE pointer &aggregate[ofs]
+ IntegerExp *ofs = new IntegerExp(e->loc, indx, Type::tsize_t);
+ IndexExp *ei = new IndexExp(e->loc, aggregate, ofs);
+ ei->type = elemtype;
+ new(pue) AddrExp(e->loc, ei, e->type);
+ result = pue->exp();
+ return;
+ }
+ }
+ else if (e->offset == 0 && isSafePointerCast(e->var->type, pointee))
+ {
+ // Create a CTFE pointer &var
+ VarExp *ve = new VarExp(e->loc, e->var);
+ ve->type = e->var->type;
+ new(pue) AddrExp(e->loc, ve, e->type);
+ result = pue->exp();
+ return;
+ }
+
+ e->error("cannot convert &%s to %s at compile time", e->var->type->toChars(), e->type->toChars());
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(AddrExp *e)
+ {
+ if (e->e1->op == TOKvar && ((VarExp *)e->e1)->var->isDataseg())
+ {
+ // Normally this is already done by optimize()
+ // Do it here in case optimize(WANTvalue) wasn't run before CTFE
+ result = new SymOffExp(e->loc, ((VarExp *)e->e1)->var, 0);
+ result->type = e->type;
+ return;
+ }
+ Expression *er = interpret(e->e1, istate, ctfeNeedLvalue);
+ if (er->op == TOKvar && ((VarExp *)er)->var == istate->fd->vthis)
+ er = interpret(er, istate);
+ if (exceptionOrCant(er))
+ return;
+
+ // Return a simplified address expression
+ new(pue) AddrExp(e->loc, er, e->type);
+ result = pue->exp();
+ }
+
+ void visit(DelegateExp *e)
+ {
+ // TODO: Really we should create a CTFE-only delegate expression
+ // of a pointer and a funcptr.
+
+ // If it is &nestedfunc, just return it
+ // TODO: We should save the context pointer
+ if (e->e1->op == TOKvar && ((VarExp *)e->e1)->var == e->func)
+ {
+ result = e;
+ return;
+ }
+
+ Expression *er = interpret(e->e1, istate);
+ if (exceptionOrCant(er))
+ return;
+ if (er == e->e1)
+ {
+ // If it has already been CTFE'd, just return it
+ result = e;
+ }
+ else
+ {
+ new(pue) DelegateExp(e->loc, er, e->func, false);
+ result = pue->exp();
+ result->type = e->type;
+ }
+ }
+
+ static Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal)
+ {
+ Expression *e = CTFEExp::cantexp;
+ if (VarDeclaration *v = d->isVarDeclaration())
+ {
+ /* Magic variable __ctfe always returns true when interpreting
+ */
+ if (v->ident == Id::ctfe)
+ return new IntegerExp(loc, 1, Type::tbool);
+
+ if (!v->originalType && v->_scope) // semantic() not yet run
+ {
+ v->semantic (v->_scope);
+ if (v->type->ty == Terror)
+ return CTFEExp::cantexp;
+ }
+
+ if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) &&
+ !hasValue(v) &&
+ v->_init && !v->isCTFE())
+ {
+ if (v->inuse)
+ {
+ error(loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ return CTFEExp::cantexp;
+ }
+ if (v->_scope)
+ {
+ v->inuse++;
+ v->_init = ::semantic(v->_init, v->_scope, v->type, INITinterpret); // might not be run on aggregate members
+ v->inuse--;
+ }
+ e = initializerToExpression(v->_init, v->type);
+ if (!e)
+ return CTFEExp::cantexp;
+ assert(e->type);
+
+ if (e->op == TOKconstruct || e->op == TOKblit)
+ {
+ AssignExp *ae = (AssignExp *)e;
+ e = ae->e2;
+ }
+
+ if (e->op == TOKerror)
+ {
+ // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
+ }
+ else if (v->isDataseg() || (v->storage_class & STCmanifest))
+ {
+ /* Bugzilla 14304: e is a value that is not yet owned by CTFE.
+ * Mark as "cached", and use it directly during interpretation.
+ */
+ e = scrubCacheValue(v->loc, e);
+ ctfeStack.saveGlobalConstant(v, e);
+ }
+ else
+ {
+ v->inuse++;
+ e = interpret(e, istate);
+ v->inuse--;
+ if (CTFEExp::isCantExp(e) && !global.gag && !CtfeStatus::stackTraceCallsToSuppress)
+ errorSupplemental(loc, "while evaluating %s.init", v->toChars());
+ if (exceptionOrCantInterpret(e))
+ return e;
+ }
+ }
+ else if (v->isCTFE() && !hasValue(v))
+ {
+ if (v->_init && v->type->size() != 0)
+ {
+ if (v->_init->isVoidInitializer())
+ {
+ // var should have been initialized when it was created
+ error(loc, "CTFE internal error: trying to access uninitialized var");
+ assert(0);
+ return CTFEExp::cantexp;
+ }
+ e = initializerToExpression(v->_init);
+ }
+ else
+ e = v->type->defaultInitLiteral(e->loc);
+
+ e = interpret(e, istate);
+ }
+ else if (!(v->isDataseg() || v->storage_class & STCmanifest) && !v->isCTFE() && !istate)
+ {
+ error(loc, "variable %s cannot be read at compile time", v->toChars());
+ return CTFEExp::cantexp;
+ }
+ else
+ {
+ e = hasValue(v) ? getValue(v) : NULL;
+ if (!e && !v->isCTFE() && v->isDataseg())
+ {
+ error(loc, "static variable %s cannot be read at compile time", v->toChars());
+ return CTFEExp::cantexp;
+ }
+ if (!e)
+ {
+ assert(!(v->_init && v->_init->isVoidInitializer()));
+ // CTFE initiated from inside a function
+ error(loc, "variable %s cannot be read at compile time", v->toChars());
+ return CTFEExp::cantexp;
+ }
+ if (e->op == TOKvoid)
+ {
+ VoidInitExp *ve = (VoidInitExp *)e;
+ error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars());
+ errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars());
+ return CTFEExp::cantexp;
+ }
+ if (goal != ctfeNeedLvalue && (v->isRef() || v->isOut()))
+ e = interpret(e, istate, goal);
+ }
+ if (!e)
+ e = CTFEExp::cantexp;
+ }
+ else if (SymbolDeclaration *s = d->isSymbolDeclaration())
+ {
+ // Struct static initializers, for example
+ e = s->dsym->type->defaultInitLiteral(loc);
+ if (e->op == TOKerror)
+ error(loc, "CTFE failed because of previous errors in %s.init", s->toChars());
+ e = ::semantic(e, NULL);
+ if (e->op == TOKerror)
+ e = CTFEExp::cantexp;
+ else // Convert NULL to CTFEExp
+ e = interpret(e, istate, goal);
+ }
+ else
+ error(loc, "cannot interpret declaration %s at compile time", d->toChars());
+ return e;
+ }
+
+ void visit(VarExp *e)
+ {
+ if (e->var->isFuncDeclaration())
+ {
+ result = e;
+ return;
+ }
+
+ if (goal == ctfeNeedLvalue)
+ {
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (v && !v->isDataseg() && !v->isCTFE() && !istate)
+ {
+ e->error("variable %s cannot be read at compile time", v->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (v && !hasValue(v))
+ {
+ if (!v->isCTFE() && v->isDataseg())
+ e->error("static variable %s cannot be read at compile time", v->toChars());
+ else // CTFE initiated from inside a function
+ e->error("variable %s cannot be read at compile time", v->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (v && (v->storage_class & (STCout | STCref)) && hasValue(v))
+ {
+ // Strip off the nest of ref variables
+ Expression *ev = getValue(v);
+ if (ev->op == TOKvar || ev->op == TOKindex || ev->op == TOKdotvar)
+ {
+ result = interpret(pue, ev, istate, goal);
+ return;
+ }
+ }
+ result = e;
+ return;
+ }
+ result = getVarExp(e->loc, istate, e->var, goal);
+ if (exceptionOrCant(result))
+ return;
+ if ((e->var->storage_class & (STCref | STCout)) == 0 &&
+ e->type->baseElemOf()->ty != Tstruct)
+ {
+ /* Ultimately, STCref|STCout check should be enough to see the
+ * necessity of type repainting. But currently front-end paints
+ * non-ref struct variables by the const type.
+ *
+ * auto foo(ref const S cs);
+ * S s;
+ * foo(s); // VarExp('s') will have const(S)
+ */
+ // A VarExp may include an implicit cast. It must be done explicitly.
+ result = paintTypeOntoLiteral(e->type, result);
+ }
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ Dsymbol *s = e->declaration;
+ if (VarDeclaration *v = s->isVarDeclaration())
+ {
+ if (TupleDeclaration *td = v->toAlias()->isTupleDeclaration())
+ {
+ result = NULL;
+
+ // Reserve stack space for all tuple members
+ if (!td->objects)
+ return;
+ for (size_t i = 0; i < td->objects->dim; ++i)
+ {
+ RootObject * o = (*td->objects)[i];
+ Expression *ex = isExpression(o);
+ DsymbolExp *ds = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL;
+ VarDeclaration *v2 = ds ? ds->s->isVarDeclaration() : NULL;
+ assert(v2);
+ if (v2->isDataseg() && !v2->isCTFE())
+ continue;
+
+ ctfeStack.push(v2);
+ if (v2->_init)
+ {
+ Expression *einit;
+ if (ExpInitializer *ie = v2->_init->isExpInitializer())
+ {
+ einit = interpret(ie->exp, istate, goal);
+ if (exceptionOrCant(einit))
+ return;
+ }
+ else if (v2->_init->isVoidInitializer())
+ {
+ einit = voidInitLiteral(v2->type, v2).copy();
+ }
+ else
+ {
+ e->error("declaration %s is not yet implemented in CTFE", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ setValue(v2, einit);
+ }
+ }
+ return;
+ }
+ if (v->isStatic())
+ {
+ // Just ignore static variables which aren't read or written yet
+ result = NULL;
+ return;
+ }
+ if (!(v->isDataseg() || v->storage_class & STCmanifest) || v->isCTFE())
+ ctfeStack.push(v);
+ if (v->_init)
+ {
+ if (ExpInitializer *ie = v->_init->isExpInitializer())
+ {
+ result = interpret(ie->exp, istate, goal);
+ }
+ else if (v->_init->isVoidInitializer())
+ {
+ result = voidInitLiteral(v->type, v).copy();
+ // There is no AssignExp for void initializers,
+ // so set it here.
+ setValue(v, result);
+ }
+ else
+ {
+ e->error("declaration %s is not yet implemented in CTFE", e->toChars());
+ result = CTFEExp::cantexp;
+ }
+ }
+ else if (v->type->size() == 0)
+ {
+ // Zero-length arrays don't need an initializer
+ result = v->type->defaultInitLiteral(e->loc);
+ }
+ else
+ {
+ e->error("variable %s cannot be modified at compile time", v->toChars());
+ result = CTFEExp::cantexp;
+ }
+ return;
+ }
+ if (s->isAttribDeclaration() ||
+ s->isTemplateMixin() ||
+ s->isTupleDeclaration())
+ {
+ // Check for static struct declarations, which aren't executable
+ AttribDeclaration *ad = e->declaration->isAttribDeclaration();
+ if (ad && ad->decl && ad->decl->dim == 1)
+ {
+ Dsymbol *sparent = (*ad->decl)[0];
+ if (sparent->isAggregateDeclaration() ||
+ sparent->isTemplateDeclaration() ||
+ sparent->isAliasDeclaration())
+ {
+ result = NULL;
+ return; // static (template) struct declaration. Nothing to do.
+ }
+ }
+
+ // These can be made to work, too lazy now
+ e->error("declaration %s is not yet implemented in CTFE", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ // Others should not contain executable code, so are trivial to evaluate
+ result = NULL;
+ }
+
+ void visit(TypeidExp *e)
+ {
+ if (isType(e->obj))
+ {
+ result = e;
+ return;
+ }
+ if (Expression *ex = isExpression(e->obj))
+ {
+ result = interpret(ex, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ if (result->op == TOKnull)
+ {
+ e->error("null pointer dereference evaluating typeid. '%s' is null", ex->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (result->op != TOKclassreference)
+ {
+ e->error("CTFE internal error: determining classinfo");
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ ClassDeclaration *cd = ((ClassReferenceExp *)result)->originalClass();
+ assert(cd);
+
+ new(pue) TypeidExp(e->loc, cd->type);
+ result = pue->exp();
+ result->type = e->type;
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(TupleExp *e)
+ {
+ if (exceptionOrCant(interpret(e->e0, istate, ctfeNeedNothing)))
+ return;
+
+ Expressions *expsx = e->exps;
+ for (size_t i = 0; i < expsx->dim; i++)
+ {
+ Expression *exp = (*expsx)[i];
+ Expression *ex = interpret(exp, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ // A tuple of assignments can contain void (Bug 5676).
+ if (goal == ctfeNeedNothing)
+ continue;
+ if (ex->op == TOKvoidexp)
+ {
+ e->error("CTFE internal error: void element %s in tuple", exp->toChars());
+ assert(0);
+ }
+
+ /* If any changes, do Copy On Write
+ */
+ if (ex != exp)
+ {
+ expsx = copyArrayOnWrite(expsx, e->exps);
+ (*expsx)[i] = ex;
+ }
+ }
+ if (expsx != e->exps)
+ {
+ expandTuples(expsx);
+ new(pue) TupleExp(e->loc, expsx);
+ result = pue->exp();
+ result->type = new TypeTuple(expsx);
+ }
+ else
+ result = e;
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ if (e->ownedByCtfe >= OWNEDctfe) // We've already interpreted all the elements
+ {
+ result = e;
+ return;
+ }
+
+ Type *tn = e->type->toBasetype()->nextOf()->toBasetype();
+ bool wantCopy = (tn->ty == Tsarray || tn->ty == Tstruct);
+
+ Expression *basis = interpret(e->basis, istate);
+ if (exceptionOrCant(basis))
+ return;
+
+ Expressions *expsx = e->elements;
+ size_t dim = expsx ? expsx->dim : 0;
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression *exp = (*expsx)[i];
+ Expression *ex;
+ if (!exp)
+ {
+ ex = copyLiteral(basis).copy();
+ }
+ else
+ {
+ // segfault bug 6250
+ assert(exp->op != TOKindex || ((IndexExp *)exp)->e1 != e);
+
+ ex = interpret(exp, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ /* Each elements should have distinct CFE memory.
+ * int[1] z = 7;
+ * int[1][] pieces = [z,z]; // here
+ */
+ if (wantCopy)
+ ex = copyLiteral(ex).copy();
+ }
+
+ /* If any changes, do Copy On Write
+ */
+ if (ex != exp)
+ {
+ expsx = copyArrayOnWrite(expsx, e->elements);
+ (*expsx)[i] = ex;
+ }
+ }
+
+ if (expsx != e->elements)
+ {
+ // todo: all tuple expansions should go in semantic phase.
+ expandTuples(expsx);
+ if (expsx->dim != dim)
+ {
+ e->error("CTFE internal error: invalid array literal");
+ result = CTFEExp::cantexp;
+ return;
+ }
+ new(pue) ArrayLiteralExp(e->loc, basis, expsx);
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)pue->exp();
+ ale->type = e->type;
+ ale->ownedByCtfe = OWNEDctfe;
+ result = ale;
+ }
+ else if (((TypeNext *)e->type)->next->mod & (MODconst | MODimmutable))
+ {
+ // If it's immutable, we don't need to dup it
+ result = e;
+ }
+ else
+ result = copyLiteral(e).copy();
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ if (e->ownedByCtfe >= OWNEDctfe) // We've already interpreted all the elements
+ {
+ result = e;
+ return;
+ }
+
+ Expressions *keysx = e->keys;
+ Expressions *valuesx = e->values;
+ for (size_t i = 0; i < keysx->dim; i++)
+ {
+ Expression *ekey = (*keysx)[i];
+ Expression *evalue = (*valuesx)[i];
+
+ Expression *ek = interpret(ekey, istate);
+ if (exceptionOrCant(ek))
+ return;
+ Expression *ev = interpret(evalue, istate);
+ if (exceptionOrCant(ev))
+ return;
+
+ /* If any changes, do Copy On Write
+ */
+ if (ek != ekey ||
+ ev != evalue)
+ {
+ keysx = copyArrayOnWrite(keysx, e->keys);
+ valuesx = copyArrayOnWrite(valuesx, e->values);
+ (*keysx)[i] = ek;
+ (*valuesx)[i] = ev;
+ }
+ }
+ if (keysx != e->keys)
+ expandTuples(keysx);
+ if (valuesx != e->values)
+ expandTuples(valuesx);
+ if (keysx->dim != valuesx->dim)
+ {
+ e->error("CTFE internal error: invalid AA");
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ /* Remove duplicate keys
+ */
+ for (size_t i = 1; i < keysx->dim; i++)
+ {
+ Expression *ekey = (*keysx)[i - 1];
+ for (size_t j = i; j < keysx->dim; j++)
+ {
+ Expression *ekey2 = (*keysx)[j];
+ if (!ctfeEqual(e->loc, TOKequal, ekey, ekey2))
+ continue;
+
+ // Remove ekey
+ keysx = copyArrayOnWrite(keysx, e->keys);
+ valuesx = copyArrayOnWrite(valuesx, e->values);
+ keysx->remove(i - 1);
+ valuesx->remove(i - 1);
+
+ i -= 1; // redo the i'th iteration
+ break;
+ }
+ }
+
+ if (keysx != e->keys ||
+ valuesx != e->values)
+ {
+ assert(keysx != e->keys &&
+ valuesx != e->values);
+ AssocArrayLiteralExp *ae = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
+ ae->type = e->type;
+ ae->ownedByCtfe = OWNEDctfe;
+ result = ae;
+ }
+ else
+ result = copyLiteral(e).copy();
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ if (e->ownedByCtfe >= OWNEDctfe)
+ {
+ result = e;
+ return;
+ }
+
+ size_t dim = e->elements ? e->elements->dim : 0;
+ Expressions *expsx = e->elements;
+
+ if (dim != e->sd->fields.dim)
+ {
+ // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
+ assert(e->sd->isNested() && dim == e->sd->fields.dim - 1);
+
+ /* If a nested struct has no initialized hidden pointer,
+ * set it to null to match the runtime behaviour.
+ */
+ NullExp *ne = new NullExp(e->loc);
+ ne->type = e->sd->vthis->type;
+
+ expsx = copyArrayOnWrite(expsx, e->elements);
+ expsx->push(ne);
+ ++dim;
+ }
+ assert(dim == e->sd->fields.dim);
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ VarDeclaration *v = e->sd->fields[i];
+ Expression *exp = (*expsx)[i];
+ Expression *ex = NULL;
+ if (!exp)
+ {
+ ex = voidInitLiteral(v->type, v).copy();
+ }
+ else
+ {
+ ex = interpret(exp, istate);
+ if (exceptionOrCant(ex))
+ return;
+ if ((v->type->ty != ex->type->ty) && v->type->ty == Tsarray)
+ {
+ // Block assignment from inside struct literals
+ TypeSArray *tsa = (TypeSArray *)v->type;
+ size_t len = (size_t)tsa->dim->toInteger();
+ ex = createBlockDuplicatedArrayLiteral(ex->loc, v->type, ex, len);
+ }
+ }
+
+ /* If any changes, do Copy On Write
+ */
+ if (ex != exp)
+ {
+ expsx = copyArrayOnWrite(expsx, e->elements);
+ (*expsx)[i] = ex;
+ }
+ }
+
+ if (expsx != e->elements)
+ {
+ expandTuples(expsx);
+ if (expsx->dim != e->sd->fields.dim)
+ {
+ e->error("CTFE internal error: invalid struct literal");
+ result = CTFEExp::cantexp;
+ return;
+ }
+ new(pue) StructLiteralExp(e->loc, e->sd, expsx);
+ StructLiteralExp *sle = (StructLiteralExp *)pue->exp();
+ sle->type = e->type;
+ sle->ownedByCtfe = OWNEDctfe;
+ sle->origin = e->origin;
+ result = sle;
+ }
+ else
+ result = copyLiteral(e).copy();
+ }
+
+ // Create an array literal of type 'newtype' with dimensions given by
+ // 'arguments'[argnum..$]
+ static Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate,
+ Expressions *arguments, int argnum)
+ {
+ Expression *lenExpr = interpret((*arguments)[argnum], istate);
+ if (exceptionOrCantInterpret(lenExpr))
+ return lenExpr;
+ size_t len = (size_t)(lenExpr->toInteger());
+ Type *elemType = ((TypeArray *)newtype)->next;
+ if (elemType->ty == Tarray && argnum < (int)arguments->dim - 1)
+ {
+ Expression *elem = recursivelyCreateArrayLiteral(loc, elemType, istate,
+ arguments, argnum + 1);
+ if (exceptionOrCantInterpret(elem))
+ return elem;
+
+ Expressions *elements = new Expressions();
+ elements->setDim(len);
+ for (size_t i = 0; i < len; i++)
+ (*elements)[i] = copyLiteral(elem).copy();
+ ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements);
+ ae->type = newtype;
+ ae->ownedByCtfe = OWNEDctfe;
+ return ae;
+ }
+ assert(argnum == (int)arguments->dim - 1);
+ if (elemType->ty == Tchar || elemType->ty == Twchar || elemType->ty == Tdchar)
+ {
+ const unsigned ch = (unsigned)elemType->defaultInitLiteral(loc)->toInteger();
+ const unsigned char sz = (unsigned char)elemType->size();
+ return createBlockDuplicatedStringLiteral(loc, newtype, ch, len, sz);
+ }
+ else
+ {
+ Expression *el = interpret(elemType->defaultInitLiteral(loc), istate);
+ return createBlockDuplicatedArrayLiteral(loc, newtype, el, len);
+ }
+ }
+
+ void visit(NewExp *e)
+ {
+ if (e->allocator)
+ {
+ e->error("member allocators not supported by CTFE");
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ result = interpret(e->argprefix, istate, ctfeNeedNothing);
+ if (exceptionOrCant(result))
+ return;
+
+ if (e->newtype->ty == Tarray && e->arguments)
+ {
+ result = recursivelyCreateArrayLiteral(e->loc, e->newtype, istate, e->arguments, 0);
+ return;
+ }
+ if (e->newtype->toBasetype()->ty == Tstruct)
+ {
+ if (e->member)
+ {
+ Expression *se = e->newtype->defaultInitLiteral(e->loc);
+ se = interpret(se, istate);
+ if (exceptionOrCant(se))
+ return;
+ result = interpretFunction(e->member, istate, e->arguments, se);
+
+ // Repaint as same as CallExp::interpret() does.
+ result->loc = e->loc;
+ }
+ else
+ {
+ StructDeclaration *sd = ((TypeStruct *)e->newtype->toBasetype())->sym;
+ Expressions *exps = new Expressions();
+ exps->reserve(sd->fields.dim);
+ if (e->arguments)
+ {
+ exps->setDim(e->arguments->dim);
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *ex = (*e->arguments)[i];
+ ex = interpret(ex, istate);
+ if (exceptionOrCant(ex))
+ return;
+ (*exps)[i] = ex;
+ }
+ }
+ sd->fill(e->loc, exps, false);
+
+ StructLiteralExp *se = new StructLiteralExp(e->loc, sd, exps, e->newtype);
+ se->type = e->newtype;
+ se->ownedByCtfe = OWNEDctfe;
+ result = interpret(se, istate);
+ }
+ if (exceptionOrCant(result))
+ return;
+ new(pue) AddrExp(e->loc, result, e->type);
+ result = pue->exp();
+ return;
+ }
+ if (e->newtype->toBasetype()->ty == Tclass)
+ {
+ ClassDeclaration *cd = ((TypeClass *)e->newtype->toBasetype())->sym;
+ size_t totalFieldCount = 0;
+ for (ClassDeclaration *c = cd; c; c = c->baseClass)
+ totalFieldCount += c->fields.dim;
+ Expressions *elems = new Expressions;
+ elems->setDim(totalFieldCount);
+ size_t fieldsSoFar = totalFieldCount;
+ for (ClassDeclaration *c = cd; c; c = c->baseClass)
+ {
+ fieldsSoFar -= c->fields.dim;
+ for (size_t i = 0; i < c->fields.dim; i++)
+ {
+ VarDeclaration *v = c->fields[i];
+ if (v->inuse)
+ {
+ e->error("circular reference to '%s'", v->toPrettyChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ Expression *m;
+ if (v->_init)
+ {
+ if (v->_init->isVoidInitializer())
+ m = voidInitLiteral(v->type, v).copy();
+ else
+ m = v->getConstInitializer(true);
+ }
+ else
+ m = v->type->defaultInitLiteral(e->loc);
+ if (exceptionOrCant(m))
+ return;
+ (*elems)[fieldsSoFar+i] = copyLiteral(m).copy();
+ }
+ }
+ // Hack: we store a ClassDeclaration instead of a StructDeclaration.
+ // We probably won't get away with this.
+ StructLiteralExp *se = new StructLiteralExp(e->loc, (StructDeclaration *)cd, elems, e->newtype);
+ se->ownedByCtfe = OWNEDctfe;
+ Expression *eref = new ClassReferenceExp(e->loc, se, e->type);
+ if (e->member)
+ {
+ // Call constructor
+ if (!e->member->fbody)
+ {
+ Expression *ctorfail = evaluateIfBuiltin(istate, e->loc, e->member, e->arguments, eref);
+ if (ctorfail)
+ {
+ if (exceptionOrCant(ctorfail))
+ return;
+ result = eref;
+ return;
+ }
+ e->member->error("%s cannot be constructed at compile time, because the constructor has no available source code", e->newtype->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ Expression *ctorfail = interpretFunction(e->member, istate, e->arguments, eref);
+ if (exceptionOrCant(ctorfail))
+ return;
+
+ /* Bugzilla 14465: Repaint the loc, because a super() call
+ * in the constructor modifies the loc of ClassReferenceExp
+ * in CallExp::interpret().
+ */
+ eref->loc = e->loc;
+ }
+ result = eref;
+ return;
+ }
+ if (e->newtype->toBasetype()->isscalar())
+ {
+ Expression *newval;
+ if (e->arguments && e->arguments->dim)
+ newval = (*e->arguments)[0];
+ else
+ newval = e->newtype->defaultInitLiteral(e->loc);
+ newval = interpret(newval, istate);
+ if (exceptionOrCant(newval))
+ return;
+
+ // Create a CTFE pointer &[newval][0]
+ Expressions *elements = new Expressions();
+ elements->setDim(1);
+ (*elements)[0] = newval;
+ ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, elements);
+ ae->type = e->newtype->arrayOf();
+ ae->ownedByCtfe = OWNEDctfe;
+
+ IndexExp *ei = new IndexExp(e->loc, ae, new IntegerExp(Loc(), 0, Type::tsize_t));
+ ei->type = e->newtype;
+ new(pue) AddrExp(e->loc, ei, e->type);
+ result = pue->exp();
+ return;
+ }
+ e->error("cannot interpret %s at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(UnaExp *e)
+ {
+ UnionExp ue;
+ Expression *e1 = interpret(&ue, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ switch (e->op)
+ {
+ case TOKneg: *pue = Neg(e->type, e1); break;
+ case TOKtilde: *pue = Com(e->type, e1); break;
+ case TOKnot: *pue = Not(e->type, e1); break;
+ case TOKvector: result = e; return; // do nothing
+ default: assert(0);
+ }
+ result = (*pue).exp();
+ }
+
+ void visit(DotTypeExp *e)
+ {
+ UnionExp ue;
+ Expression *e1 = interpret(&ue, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+
+ if (e1 == e->e1)
+ result = e; // optimize: reuse this CTFE reference
+ else
+ {
+ DotTypeExp *edt = (DotTypeExp *)e->copy();
+ edt->e1 = (e1 == ue.exp()) ? e1->copy() : e1; // don't return pointer to ue
+ result = edt;
+ }
+ }
+
+ bool evalOperand(UnionExp *pue, Expression *e, Expression *ex, Expression *&er)
+ {
+ er = interpret(pue, ex, istate);
+ if (exceptionOrCant(er))
+ return false;
+ if (er->isConst() != 1)
+ {
+ if (er->op == TOKarrayliteral)
+ // Until we get it to work, issue a reasonable error message
+ e->error("cannot interpret array literal expression %s at compile time", e->toChars());
+ else
+ e->error("CTFE internal error: non-constant value %s", ex->toChars());
+ result = CTFEExp::cantexp;
+ return false;
+ }
+ return true;
+ }
+
+ void interpretCommon(BinExp *e, fp_t fp)
+ {
+ if (e->e1->type->ty == Tpointer && e->e2->type->ty == Tpointer && e->op == TOKmin)
+ {
+ UnionExp ue1;
+ Expression *e1 = interpret(&ue1, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ UnionExp ue2;
+ Expression *e2 = interpret(&ue2, e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ *pue = pointerDifference(e->loc, e->type, e1, e2);
+ result = (*pue).exp();
+ return;
+ }
+ if (e->e1->type->ty == Tpointer && e->e2->type->isintegral())
+ {
+ UnionExp ue1;
+ Expression *e1 = interpret(&ue1, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ UnionExp ue2;
+ Expression *e2 = interpret(&ue2, e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ *pue = pointerArithmetic(e->loc, e->op, e->type, e1, e2);
+ result = (*pue).exp();
+ return;
+ }
+ if (e->e2->type->ty == Tpointer && e->e1->type->isintegral() && e->op == TOKadd)
+ {
+ UnionExp ue1;
+ Expression *e1 = interpret(&ue1, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ UnionExp ue2;
+ Expression *e2 = interpret(&ue2, e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ *pue = pointerArithmetic(e->loc, e->op, e->type, e2, e1);
+ result = (*pue).exp();
+ return;
+ }
+ if (e->e1->type->ty == Tpointer || e->e2->type->ty == Tpointer)
+ {
+ e->error("pointer expression %s cannot be interpreted at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ UnionExp ue1;
+ Expression *e1;
+ if (!evalOperand(&ue1, e, e->e1, e1))
+ return;
+ UnionExp ue2;
+ Expression *e2;
+ if (!evalOperand(&ue2, e, e->e2, e2))
+ return;
+
+ if (e->op == TOKshr || e->op == TOKshl || e->op == TOKushr)
+ {
+ const sinteger_t i2 = e2->toInteger();
+ const d_uns64 sz = e1->type->size() * 8;
+ if (i2 < 0 || (d_uns64)i2 >= sz)
+ {
+ e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
+ result = CTFEExp::cantexp;
+ return;
+ }
+ }
+ *pue = (*fp)(e->loc, e->type, e1, e2);
+ result = (*pue).exp();
+ if (CTFEExp::isCantExp(result))
+ e->error("%s cannot be interpreted at compile time", e->toChars());
+ }
+
+ void interpretCompareCommon(BinExp *e, fp2_t fp)
+ {
+ UnionExp ue1;
+ UnionExp ue2;
+ if (e->e1->type->ty == Tpointer && e->e2->type->ty == Tpointer)
+ {
+ Expression *e1 = interpret(&ue1, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ Expression *e2 = interpret(&ue2, e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ //printf("e1 = %s %s, e2 = %s %s\n", e1->type->toChars(), e1->toChars(), e2->type->toChars(), e2->toChars());
+ dinteger_t ofs1, ofs2;
+ Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
+ //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1->toChars(), agg2, agg2->toChars());
+ const int cmp = comparePointers(e->op, agg1, ofs1, agg2, ofs2);
+ if (cmp == -1)
+ {
+ char dir = (e->op == TOKgt || e->op == TOKge) ? '<' : '>';
+ e->error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE."
+ " To check if they point to the same memory block, use both > and < inside && or ||, "
+ "eg (%s && %s %c= %s + 1)",
+ e->toChars(), e->e1->toChars(), dir, e->e2->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ new(pue) IntegerExp(e->loc, cmp, e->type);
+ result = (*pue).exp();
+ return;
+ }
+ Expression *e1 = interpret(&ue1, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (!isCtfeComparable(e1))
+ {
+ e->error("cannot compare %s at compile time", e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ Expression *e2 = interpret(&ue2, e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ if (!isCtfeComparable(e2))
+ {
+ e->error("cannot compare %s at compile time", e2->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ const int cmp = (*fp)(e->loc, e->op, e1, e2);
+ new(pue) IntegerExp(e->loc, cmp, e->type);
+ result = (*pue).exp();
+ }
+
+ void visit(BinExp *e)
+ {
+ switch (e->op)
+ {
+ case TOKadd: interpretCommon(e, &Add); return;
+ case TOKmin: interpretCommon(e, &Min); return;
+ case TOKmul: interpretCommon(e, &Mul); return;
+ case TOKdiv: interpretCommon(e, &Div); return;
+ case TOKmod: interpretCommon(e, &Mod); return;
+ case TOKshl: interpretCommon(e, &Shl); return;
+ case TOKshr: interpretCommon(e, &Shr); return;
+ case TOKushr: interpretCommon(e, &Ushr); return;
+ case TOKand: interpretCommon(e, &And); return;
+ case TOKor: interpretCommon(e, &Or); return;
+ case TOKxor: interpretCommon(e, &Xor); return;
+ case TOKpow: interpretCommon(e, &Pow); return;
+ case TOKequal:
+ case TOKnotequal:
+ interpretCompareCommon(e, &ctfeEqual);
+ return;
+ case TOKidentity:
+ case TOKnotidentity:
+ interpretCompareCommon(e, &ctfeIdentity);
+ return;
+ case TOKlt:
+ case TOKle:
+ case TOKgt:
+ case TOKge:
+ interpretCompareCommon(e, &ctfeCmp);
+ return;
+ default:
+ printf("be = '%s' %s at [%s]\n", Token::toChars(e->op), e->toChars(), e->loc.toChars());
+ assert(0);
+ return;
+ }
+ }
+
+ /* Helper functions for BinExp::interpretAssignCommon
+ */
+
+ // Returns the variable which is eventually modified, or NULL if an rvalue.
+ // thisval is the current value of 'this'.
+ static VarDeclaration *findParentVar(Expression *e)
+ {
+ for (;;)
+ {
+ if (e->op == TOKvar)
+ break;
+ if (e->op == TOKindex)
+ e = ((IndexExp *)e)->e1;
+ else if (e->op == TOKdotvar)
+ e = ((DotVarExp *)e)->e1;
+ else if (e->op == TOKdotti)
+ e = ((DotTemplateInstanceExp *)e)->e1;
+ else if (e->op == TOKslice)
+ e = ((SliceExp *)e)->e1;
+ else
+ return NULL;
+ }
+ VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+ assert(v);
+ return v;
+ }
+
+ void interpretAssignCommon(BinExp *e, fp_t fp, int post = 0)
+ {
+ result = CTFEExp::cantexp;
+ Expression *e1 = e->e1;
+ if (!istate)
+ {
+ e->error("value of %s is not known at compile time", e1->toChars());
+ return;
+ }
+
+ ++CtfeStatus::numAssignments;
+
+ /* Before we begin, we need to know if this is a reference assignment
+ * (dynamic array, AA, or class) or a value assignment.
+ * Determining this for slice assignments are tricky: we need to know
+ * if it is a block assignment (a[] = e) rather than a direct slice
+ * assignment (a[] = b[]). Note that initializers of multi-dimensional
+ * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
+ * So we need to recurse to determine if it is a block assignment.
+ */
+ bool isBlockAssignment = false;
+ if (e1->op == TOKslice)
+ {
+ // a[] = e can have const e. So we compare the naked types.
+ Type *tdst = e1->type->toBasetype();
+ Type *tsrc = e->e2->type->toBasetype();
+ while (tdst->ty == Tsarray || tdst->ty == Tarray)
+ {
+ tdst = ((TypeArray *)tdst)->next->toBasetype();
+ if (tsrc->equivalent(tdst))
+ {
+ isBlockAssignment = true;
+ break;
+ }
+ }
+ }
+
+ // ---------------------------------------
+ // Deal with reference assignment
+ // ---------------------------------------
+ // If it is a construction of a ref variable, it is a ref assignment
+ if ((e->op == TOKconstruct || e->op == TOKblit) &&
+ (((AssignExp *)e)->memset & referenceInit))
+ {
+ assert(!fp);
+
+ Expression *newval = interpret(e->e2, istate, ctfeNeedLvalue);
+ if (exceptionOrCant(newval))
+ return;
+
+ VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
+ setValue(v, newval);
+
+ // Get the value to return. Note that 'newval' is an Lvalue,
+ // so if we need an Rvalue, we have to interpret again.
+ if (goal == ctfeNeedRvalue)
+ result = interpret(newval, istate);
+ else
+ result = e1; // VarExp is a CTFE reference
+ return;
+ }
+
+ if (fp)
+ {
+ while (e1->op == TOKcast)
+ {
+ CastExp *ce = (CastExp *)e1;
+ e1 = ce->e1;
+ }
+ }
+
+ // ---------------------------------------
+ // Interpret left hand side
+ // ---------------------------------------
+ AssocArrayLiteralExp *existingAA = NULL;
+ Expression *lastIndex = NULL;
+ Expression *oldval = NULL;
+ if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
+ {
+ // ---------------------------------------
+ // Deal with AA index assignment
+ // ---------------------------------------
+ /* This needs special treatment if the AA doesn't exist yet.
+ * There are two special cases:
+ * (1) If the AA is itself an index of another AA, we may need to create
+ * multiple nested AA literals before we can insert the new value.
+ * (2) If the ultimate AA is null, no insertion happens at all. Instead,
+ * we create nested AA literals, and change it into a assignment.
+ */
+ IndexExp *ie = (IndexExp *)e1;
+ int depth = 0; // how many nested AA indices are there?
+ while (ie->e1->op == TOKindex &&
+ ((IndexExp *)ie->e1)->e1->type->toBasetype()->ty == Taarray)
+ {
+ assert(ie->modifiable);
+ ie = (IndexExp *)ie->e1;
+ ++depth;
+ }
+
+ // Get the AA value to be modified.
+ Expression *aggregate = interpret(ie->e1, istate);
+ if (exceptionOrCant(aggregate))
+ return;
+ if (aggregate->op == TOKassocarrayliteral)
+ {
+ existingAA = (AssocArrayLiteralExp *)aggregate;
+
+ // Normal case, ultimate parent AA already exists
+ // We need to walk from the deepest index up, checking that an AA literal
+ // already exists on each level.
+ lastIndex = interpret(((IndexExp *)e1)->e2, istate);
+ lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
+ if (exceptionOrCant(lastIndex))
+ return;
+
+ while (depth > 0)
+ {
+ // Walk the syntax tree to find the indexExp at this depth
+ IndexExp *xe = (IndexExp *)e1;
+ for (int d= 0; d < depth; ++d)
+ xe = (IndexExp *)xe->e1;
+
+ Expression *ekey = interpret(xe->e2, istate);
+ if (exceptionOrCant(ekey))
+ return;
+ UnionExp ekeyTmp;
+ ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
+
+ // Look up this index in it up in the existing AA, to get the next level of AA.
+ AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(e->loc, existingAA, ekey);
+ if (exceptionOrCant(newAA))
+ return;
+ if (!newAA)
+ {
+ // Doesn't exist yet, create an empty AA...
+ Expressions *keysx = new Expressions();
+ Expressions *valuesx = new Expressions();
+ newAA = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
+ newAA->type = xe->type;
+ newAA->ownedByCtfe = OWNEDctfe;
+ //... and insert it into the existing AA.
+ existingAA->keys->push(ekey);
+ existingAA->values->push(newAA);
+ }
+ existingAA = newAA;
+ --depth;
+ }
+
+ if (fp)
+ {
+ oldval = findKeyInAA(e->loc, existingAA, lastIndex);
+ if (!oldval)
+ oldval = copyLiteral(e->e1->type->defaultInitLiteral(e->loc)).copy();
+ }
+ }
+ else
+ {
+ /* The AA is currently null. 'aggregate' is actually a reference to
+ * whatever contains it. It could be anything: var, dotvarexp, ...
+ * We rewrite the assignment from:
+ * aa[i][j] op= newval;
+ * into:
+ * aa = [i:[j:T.init]];
+ * aa[j] op= newval;
+ */
+ oldval = copyLiteral(e->e1->type->defaultInitLiteral(e->loc)).copy();
+
+ Expression *newaae = oldval;
+ while (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
+ {
+ Expression *ekey = interpret(((IndexExp *)e1)->e2, istate);
+ if (exceptionOrCant(ekey))
+ return;
+ ekey = resolveSlice(ekey); // only happens with AA assignment
+ Expressions *keysx = new Expressions();
+ Expressions *valuesx = new Expressions();
+ keysx->push(ekey);
+ valuesx->push(newaae);
+ AssocArrayLiteralExp *aae = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
+ aae->type = ((IndexExp *)e1)->e1->type;
+ aae->ownedByCtfe = OWNEDctfe;
+ if (!existingAA)
+ {
+ existingAA = aae;
+ lastIndex = ekey;
+ }
+ newaae = aae;
+ e1 = ((IndexExp *)e1)->e1;
+ }
+
+ // We must set to aggregate with newaae
+ e1 = interpret(e1, istate, ctfeNeedLvalue);
+ if (exceptionOrCant(e1))
+ return;
+ e1 = assignToLvalue(e, e1, newaae);
+ if (exceptionOrCant(e1))
+ return;
+ }
+ assert(existingAA && lastIndex);
+ e1 = NULL; // stomp
+ }
+ else if (e1->op == TOKarraylength)
+ {
+ oldval = interpret(e1, istate);
+ if (exceptionOrCant(oldval))
+ return;
+ }
+ else if (e->op == TOKconstruct || e->op == TOKblit)
+ {
+ // Unless we have a simple var assignment, we're
+ // only modifying part of the variable. So we need to make sure
+ // that the parent variable exists.
+ VarDeclaration *ultimateVar = findParentVar(e1);
+ if (e1->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
+ assert(v);
+ if (v->storage_class & STCout)
+ goto L1;
+ }
+ else if (ultimateVar && !getValue(ultimateVar))
+ {
+ Expression *ex = interpret(ultimateVar->type->defaultInitLiteral(e->loc), istate);
+ if (exceptionOrCant(ex))
+ return;
+ setValue(ultimateVar, ex);
+ }
+ else
+ goto L1;
+ }
+ else
+ {
+ L1:
+ e1 = interpret(e1, istate, ctfeNeedLvalue);
+ if (exceptionOrCant(e1))
+ return;
+
+ if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
+ {
+ IndexExp *ie = (IndexExp *)e1;
+ assert(ie->e1->op == TOKassocarrayliteral);
+ existingAA = (AssocArrayLiteralExp *)ie->e1;
+ lastIndex = ie->e2;
+ }
+ }
+
+ // ---------------------------------------
+ // Interpret right hand side
+ // ---------------------------------------
+ Expression *newval = interpret(e->e2, istate);
+ if (exceptionOrCant(newval))
+ return;
+ if (e->op == TOKblit && newval->op == TOKint64)
+ {
+ Type *tbn = e->type->baseElemOf();
+ if (tbn->ty == Tstruct)
+ {
+ /* Look for special case of struct being initialized with 0.
+ */
+ newval = e->type->defaultInitLiteral(e->loc);
+ if (newval->op == TOKerror)
+ {
+ result = CTFEExp::cantexp;
+ return;
+ }
+ newval = interpret(newval, istate); // copy and set ownedByCtfe flag
+ if (exceptionOrCant(newval))
+ return;
+ }
+ }
+
+ // ----------------------------------------------------
+ // Deal with read-modify-write assignments.
+ // Set 'newval' to the final assignment value
+ // Also determine the return value (except for slice
+ // assignments, which are more complicated)
+ // ----------------------------------------------------
+ if (fp)
+ {
+ if (!oldval)
+ {
+ // Load the left hand side after interpreting the right hand side.
+ oldval = interpret(e1, istate);
+ if (exceptionOrCant(oldval))
+ return;
+ }
+
+ if (e->e1->type->ty != Tpointer)
+ {
+ // ~= can create new values (see bug 6052)
+ if (e->op == TOKcatass)
+ {
+ // We need to dup it and repaint the type. For a dynamic array
+ // we can skip duplication, because it gets copied later anyway.
+ if (newval->type->ty != Tarray)
+ {
+ newval = copyLiteral(newval).copy();
+ newval->type = e->e2->type; // repaint type
+ }
+ else
+ {
+ newval = paintTypeOntoLiteral(e->e2->type, newval);
+ newval = resolveSlice(newval);
+ }
+ }
+ oldval = resolveSlice(oldval);
+
+ newval = (*fp)(e->loc, e->type, oldval, newval).copy();
+ }
+ else if (e->e2->type->isintegral() &&
+ (e->op == TOKaddass ||
+ e->op == TOKminass ||
+ e->op == TOKplusplus ||
+ e->op == TOKminusminus))
+ {
+ newval = pointerArithmetic(e->loc, e->op, e->type, oldval, newval).copy();
+ }
+ else
+ {
+ e->error("pointer expression %s cannot be interpreted at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (exceptionOrCant(newval))
+ {
+ if (CTFEExp::isCantExp(newval))
+ e->error("cannot interpret %s at compile time", e->toChars());
+ return;
+ }
+ }
+
+ if (existingAA)
+ {
+ if (existingAA->ownedByCtfe != OWNEDctfe)
+ {
+ e->error("cannot modify read-only constant %s", existingAA->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
+ // __LINE__, existingAA->toChars(), lastIndex->toChars(), oldval ? oldval->toChars() : NULL, newval->toChars());
+ assignAssocArrayElement(e->loc, existingAA, lastIndex, newval);
+
+ // Determine the return value
+ result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+ return;
+ }
+ if (e1->op == TOKarraylength)
+ {
+ /* Change the assignment from:
+ * arr.length = n;
+ * into:
+ * arr = new_length_array; (result is n)
+ */
+
+ // Determine the return value
+ result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+ if (exceptionOrCant(result))
+ return;
+
+ size_t oldlen = (size_t)oldval->toInteger();
+ size_t newlen = (size_t)newval->toInteger();
+ if (oldlen == newlen) // no change required -- we're done!
+ return;
+
+ // We have changed it into a reference assignment
+ // Note that returnValue is still the new length.
+ e1 = ((ArrayLengthExp *)e1)->e1;
+ Type *t = e1->type->toBasetype();
+ if (t->ty != Tarray)
+ {
+ e->error("%s is not yet supported at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ e1 = interpret(e1, istate, ctfeNeedLvalue);
+ if (exceptionOrCant(e1))
+ return;
+
+ if (oldlen != 0) // Get the old array literal.
+ oldval = interpret(e1, istate);
+ newval = changeArrayLiteralLength(e->loc, (TypeArray *)t, oldval,
+ oldlen, newlen).copy();
+
+ e1 = assignToLvalue(e, e1, newval);
+ if (exceptionOrCant(e1))
+ return;
+
+ return;
+ }
+
+ if (!isBlockAssignment)
+ {
+ newval = ctfeCast(e->loc, e->type, e->type, newval);
+ if (exceptionOrCant(newval))
+ return;
+
+ // Determine the return value
+ if (goal == ctfeNeedLvalue) // Bugzilla 14371
+ result = e1;
+ else
+ result = ctfeCast(e->loc, e->type, e->type, fp && post ? oldval : newval);
+ if (exceptionOrCant(result))
+ return;
+ }
+ if (exceptionOrCant(newval))
+ return;
+
+ /* Block assignment or element-wise assignment.
+ */
+ if (e1->op == TOKslice ||
+ e1->op == TOKvector ||
+ e1->op == TOKarrayliteral ||
+ e1->op == TOKstring ||
+ (e1->op == TOKnull && e1->type->toBasetype()->ty == Tarray))
+ {
+ // Note that slice assignments don't support things like ++, so
+ // we don't need to remember 'returnValue'.
+ result = interpretAssignToSlice(e, e1, newval, isBlockAssignment);
+ if (exceptionOrCant(result))
+ return;
+ if (e->e1->op == TOKslice)
+ {
+ Expression *e1x = interpret(((SliceExp*)e->e1)->e1, istate, ctfeNeedLvalue);
+ if (e1x->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp*)e1x;
+ Expression *ex = dve->e1;
+ StructLiteralExp *sle = ex->op == TOKstructliteral ? ((StructLiteralExp *)ex)
+ : ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value
+ : NULL;
+ VarDeclaration *v = dve->var->isVarDeclaration();
+ if (!sle || !v)
+ {
+ e->error("CTFE internal error: dotvar slice assignment");
+ result = CTFEExp::cantexp;
+ return;
+ }
+ stompOverlappedFields(sle, v);
+ }
+ }
+ return;
+ }
+
+ assert(result);
+
+ /* Assignment to a CTFE reference.
+ */
+ if (Expression *ex = assignToLvalue(e, e1, newval))
+ result = ex;
+
+ return;
+ }
+
+ /* Set all sibling fields which overlap with v to VoidExp.
+ */
+ void stompOverlappedFields(StructLiteralExp *sle, VarDeclaration *v)
+ {
+ if (!v->overlapped)
+ return;
+
+ for (size_t i = 0; i < sle->sd->fields.dim; i++)
+ {
+ VarDeclaration *v2 = sle->sd->fields[i];
+ if (v == v2 || !v->isOverlappedWith(v2))
+ continue;
+ Expression *e = (*sle->elements)[i];
+ if (e->op != TOKvoid)
+ (*sle->elements)[i] = voidInitLiteral(e->type, v).copy();
+ }
+ }
+
+ Expression *assignToLvalue(BinExp *e, Expression *e1, Expression *newval)
+ {
+ VarDeclaration *vd = NULL;
+ Expression **payload = NULL; // dead-store to prevent spurious warning
+ Expression *oldval;
+
+ if (e1->op == TOKvar)
+ {
+ vd = ((VarExp *)e1)->var->isVarDeclaration();
+ oldval = getValue(vd);
+ }
+ else if (e1->op == TOKdotvar)
+ {
+ /* Assignment to member variable of the form:
+ * e.v = newval
+ */
+ Expression *ex = ((DotVarExp *)e1)->e1;
+ StructLiteralExp *sle =
+ ex->op == TOKstructliteral ? ((StructLiteralExp *)ex):
+ ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value
+ : NULL;
+ VarDeclaration *v = ((DotVarExp *)e1)->var->isVarDeclaration();
+ if (!sle || !v)
+ {
+ e->error("CTFE internal error: dotvar assignment");
+ return CTFEExp::cantexp;
+ }
+ if (sle->ownedByCtfe != OWNEDctfe)
+ {
+ e->error("cannot modify read-only constant %s", sle->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ int fieldi = ex->op == TOKstructliteral
+ ? findFieldIndexByName(sle->sd, v)
+ : ((ClassReferenceExp *)ex)->findFieldIndexByName(v);
+ if (fieldi == -1)
+ {
+ e->error("CTFE internal error: cannot find field %s in %s", v->toChars(), ex->toChars());
+ return CTFEExp::cantexp;
+ }
+ assert(0 <= fieldi && fieldi < (int)sle->elements->dim);
+
+ // If it's a union, set all other members of this union to void
+ stompOverlappedFields(sle, v);
+
+ payload = &(*sle->elements)[fieldi];
+ oldval = *payload;
+ }
+ else if (e1->op == TOKindex)
+ {
+ IndexExp *ie = (IndexExp *)e1;
+ assert(ie->e1->type->toBasetype()->ty != Taarray);
+
+ Expression *aggregate;
+ uinteger_t indexToModify;
+ if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
+ {
+ return CTFEExp::cantexp;
+ }
+ size_t index = (size_t)indexToModify;
+
+ if (aggregate->op == TOKstring)
+ {
+ StringExp *existingSE = (StringExp *)aggregate;
+ if (existingSE->ownedByCtfe != OWNEDctfe)
+ {
+ e->error("cannot modify read-only string literal %s", ie->e1->toChars());
+ return CTFEExp::cantexp;
+ }
+ void *s = existingSE->string;
+ dinteger_t value = newval->toInteger();
+ switch (existingSE->sz)
+ {
+ case 1: (( utf8_t *)s)[index] = ( utf8_t)value; break;
+ case 2: ((utf16_t *)s)[index] = (utf16_t)value; break;
+ case 4: ((utf32_t *)s)[index] = (utf32_t)value; break;
+ default: assert(0); break;
+ }
+ return NULL;
+ }
+ if (aggregate->op != TOKarrayliteral)
+ {
+ e->error("index assignment %s is not yet supported in CTFE ", e->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ ArrayLiteralExp *existingAE = (ArrayLiteralExp *)aggregate;
+ if (existingAE->ownedByCtfe != OWNEDctfe)
+ {
+ e->error("cannot modify read-only constant %s", existingAE->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ payload = &(*existingAE->elements)[index];
+ oldval = *payload;
+ }
+ else
+ {
+ e->error("%s cannot be evaluated at compile time", e->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ Type *t1b = e1->type->toBasetype();
+ bool wantCopy = t1b->baseElemOf()->ty == Tstruct;
+
+ if (newval->op == TOKstructliteral && oldval)
+ {
+ newval = copyLiteral(newval).copy();
+ assignInPlace(oldval, newval);
+ }
+ else if (wantCopy && e->op == TOKassign)
+ {
+ // Currently postblit/destructor calls on static array are done
+ // in the druntime internal functions so they don't appear in AST.
+ // Therefore interpreter should handle them specially.
+
+ assert(oldval);
+ #if 1 // todo: instead we can directly access to each elements of the slice
+ newval = resolveSlice(newval);
+ if (CTFEExp::isCantExp(newval))
+ {
+ e->error("CTFE internal error: assignment %s", e->toChars());
+ return CTFEExp::cantexp;
+ }
+ #endif
+ assert(oldval->op == TOKarrayliteral);
+ assert(newval->op == TOKarrayliteral);
+
+ Expressions *oldelems = ((ArrayLiteralExp *)oldval)->elements;
+ Expressions *newelems = ((ArrayLiteralExp *)newval)->elements;
+ assert(oldelems->dim == newelems->dim);
+
+ Type *elemtype = oldval->type->nextOf();
+ for (size_t i = 0; i < newelems->dim; i++)
+ {
+ Expression *oldelem = (*oldelems)[i];
+ Expression *newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
+ // Bugzilla 9245
+ if (e->e2->isLvalue())
+ {
+ if (Expression *ex = evaluatePostblit(istate, newelem))
+ return ex;
+ }
+ // Bugzilla 13661
+ if (Expression *ex = evaluateDtor(istate, oldelem))
+ return ex;
+ (*oldelems)[i] = newelem;
+ }
+ }
+ else
+ {
+ // e1 has its own payload, so we have to create a new literal.
+ if (wantCopy)
+ newval = copyLiteral(newval).copy();
+
+ if (t1b->ty == Tsarray && e->op == TOKconstruct && e->e2->isLvalue())
+ {
+ // Bugzilla 9245
+ if (Expression *ex = evaluatePostblit(istate, newval))
+ return ex;
+ }
+
+ oldval = newval;
+ }
+
+ if (vd)
+ setValue(vd, oldval);
+ else
+ *payload = oldval;
+
+ // Blit assignment should return the newly created value.
+ if (e->op == TOKblit)
+ return oldval;
+
+ return NULL;
+ }
+
+ /*************
+ * Deal with assignments of the form:
+ * dest[] = newval
+ * dest[low..upp] = newval
+ * where newval has already been interpreted
+ *
+ * This could be a slice assignment or a block assignment, and
+ * dest could be either an array literal, or a string.
+ *
+ * Returns TOKcantexp on failure. If there are no errors,
+ * it returns aggregate[low..upp], except that as an optimisation,
+ * if goal == ctfeNeedNothing, it will return NULL
+ */
+ Expression *interpretAssignToSlice(BinExp *e,
+ Expression *e1, Expression *newval, bool isBlockAssignment)
+ {
+ dinteger_t lowerbound;
+ dinteger_t upperbound;
+
+ Expression *aggregate;
+ dinteger_t firstIndex;
+
+ if (e1->op == TOKvector)
+ e1 = ((VectorExp *)e1)->e1;
+ if (e1->op == TOKslice)
+ {
+ // ------------------------------
+ // aggregate[] = newval
+ // aggregate[low..upp] = newval
+ // ------------------------------
+
+ SliceExp *se = (SliceExp *)e1;
+ #if 1 // should be move in interpretAssignCommon as the evaluation of e1
+ Expression *oldval = interpret(se->e1, istate);
+
+ // Set the $ variable
+ uinteger_t dollar = resolveArrayLength(oldval);
+ if (se->lengthVar)
+ {
+ Expression *dollarExp = new IntegerExp(e1->loc, dollar, Type::tsize_t);
+ ctfeStack.push(se->lengthVar);
+ setValue(se->lengthVar, dollarExp);
+ }
+ Expression *lwr = interpret(se->lwr, istate);
+ if (exceptionOrCantInterpret(lwr))
+ {
+ if (se->lengthVar)
+ ctfeStack.pop(se->lengthVar);
+ return lwr;
+ }
+ Expression *upr = interpret(se->upr, istate);
+ if (exceptionOrCantInterpret(upr))
+ {
+ if (se->lengthVar)
+ ctfeStack.pop(se->lengthVar);
+ return upr;
+ }
+ if (se->lengthVar)
+ ctfeStack.pop(se->lengthVar); // $ is defined only in [L..U]
+
+ unsigned dim = (unsigned)dollar;
+ lowerbound = (int)(lwr ? lwr->toInteger() : 0);
+ upperbound = (size_t)(upr ? upr->toInteger() : dim);
+
+ if ((int)lowerbound < 0 || dim < upperbound)
+ {
+ e->error("array bounds [0..%d] exceeded in slice [%d..%d]",
+ dim, lowerbound, upperbound);
+ return CTFEExp::cantexp;
+ }
+ #endif
+ aggregate = oldval;
+ firstIndex = lowerbound;
+
+ if (aggregate->op == TOKslice)
+ {
+ // Slice of a slice --> change the bounds
+ SliceExp *oldse = (SliceExp *)aggregate;
+ if (oldse->upr->toInteger() < upperbound + oldse->lwr->toInteger())
+ {
+ e->error("slice [%d..%d] exceeds array bounds [0..%lld]",
+ lowerbound, upperbound,
+ oldse->upr->toInteger() - oldse->lwr->toInteger());
+ return CTFEExp::cantexp;
+ }
+ aggregate = oldse->e1;
+ firstIndex = lowerbound + oldse->lwr->toInteger();
+ }
+ }
+ else
+ {
+ if (e1->op == TOKarrayliteral)
+ {
+ lowerbound = 0;
+ upperbound = ((ArrayLiteralExp *)e1)->elements->dim;
+ }
+ else if (e1->op == TOKstring)
+ {
+ lowerbound = 0;
+ upperbound = ((StringExp *)e1)->len;
+ }
+ else if (e1->op == TOKnull)
+ {
+ lowerbound = 0;
+ upperbound = 0;
+ }
+ else
+ assert(0);
+
+ aggregate = e1;
+ firstIndex = lowerbound;
+ }
+ if (upperbound == lowerbound)
+ return newval;
+
+ // For slice assignment, we check that the lengths match.
+ if (!isBlockAssignment)
+ {
+ size_t srclen = (size_t)resolveArrayLength(newval);
+ if (srclen != (upperbound - lowerbound))
+ {
+ e->error("array length mismatch assigning [0..%d] to [%d..%d]",
+ srclen, lowerbound, upperbound);
+ return CTFEExp::cantexp;
+ }
+ }
+
+ if (aggregate->op == TOKstring)
+ {
+ StringExp *existingSE = (StringExp *)aggregate;
+ if (existingSE->ownedByCtfe != OWNEDctfe)
+ {
+ e->error("cannot modify read-only string literal %s", existingSE->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ if (newval->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *)newval;
+ Expression *aggr2 = se->e1;
+ const dinteger_t srclower = se->lwr->toInteger();
+ const dinteger_t srcupper = se->upr->toInteger();
+
+ if (aggregate == aggr2 &&
+ lowerbound < srcupper && srclower < upperbound)
+ {
+ e->error("overlapping slice assignment [%d..%d] = [%llu..%llu]",
+ lowerbound, upperbound, srclower, srcupper);
+ return CTFEExp::cantexp;
+ }
+ #if 1 // todo: instead we can directly access to each elements of the slice
+ Expression *orignewval = newval;
+ newval = resolveSlice(newval);
+ if (CTFEExp::isCantExp(newval))
+ {
+ e->error("CTFE internal error: slice %s", orignewval->toChars());
+ return CTFEExp::cantexp;
+ }
+ #endif
+ assert(newval->op != TOKslice);
+ }
+ if (newval->op == TOKstring)
+ {
+ sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, (size_t)firstIndex);
+ return newval;
+ }
+ if (newval->op == TOKarrayliteral)
+ {
+ /* Mixed slice: it was initialized as a string literal.
+ * Now a slice of it is being set with an array literal.
+ */
+ sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, (size_t)firstIndex);
+ return newval;
+ }
+
+ // String literal block slice assign
+ dinteger_t value = newval->toInteger();
+ void *s = existingSE->string;
+ for (size_t i = 0; i < upperbound - lowerbound; i++)
+ {
+ switch (existingSE->sz)
+ {
+ case 1: (( utf8_t *)s)[(size_t)(i + firstIndex)] = ( utf8_t)value; break;
+ case 2: ((utf16_t *)s)[(size_t)(i + firstIndex)] = (utf16_t)value; break;
+ case 4: ((utf32_t *)s)[(size_t)(i + firstIndex)] = (utf32_t)value; break;
+ default: assert(0); break;
+ }
+ }
+ if (goal == ctfeNeedNothing)
+ return NULL; // avoid creating an unused literal
+ SliceExp *retslice = new SliceExp(e->loc, existingSE,
+ new IntegerExp(e->loc, firstIndex, Type::tsize_t),
+ new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
+ retslice->type = e->type;
+ return interpret(retslice, istate);
+ }
+ if (aggregate->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *existingAE = (ArrayLiteralExp *)aggregate;
+ if (existingAE->ownedByCtfe != OWNEDctfe)
+ {
+ e->error("cannot modify read-only constant %s", existingAE->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ if (newval->op == TOKslice && !isBlockAssignment)
+ {
+ SliceExp *se = (SliceExp *)newval;
+ Expression *aggr2 = se->e1;
+ const dinteger_t srclower = se->lwr->toInteger();
+ const dinteger_t srcupper = se->upr->toInteger();
+ const bool wantCopy = (newval->type->toBasetype()->nextOf()->baseElemOf()->ty == Tstruct);
+
+ //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
+ // aggregate, aggregate->toChars(), lowerbound, upperbound,
+ // aggr2, aggr2->toChars(), srclower, srcupper, wantCopy);
+ if (wantCopy)
+ {
+ // Currently overlapping for struct array is allowed.
+ // The order of elements processing depends on the overlapping.
+ // See bugzilla 14024.
+ assert(aggr2->op == TOKarrayliteral);
+ Expressions *oldelems = existingAE->elements;
+ Expressions *newelems = ((ArrayLiteralExp *)aggr2)->elements;
+
+ Type *elemtype = aggregate->type->nextOf();
+ bool needsPostblit = e->e2->isLvalue();
+
+ if (aggregate == aggr2 &&
+ srclower < lowerbound && lowerbound < srcupper)
+ {
+ // reverse order
+ for (size_t i = upperbound - lowerbound; 0 < i--; )
+ {
+ Expression *oldelem = (*oldelems)[(size_t)(i + firstIndex)];
+ Expression *newelem = (*newelems)[(size_t)(i + srclower)];
+ newelem = copyLiteral(newelem).copy();
+ newelem->type = elemtype;
+ if (needsPostblit)
+ {
+ if (Expression *x = evaluatePostblit(istate, newelem))
+ return x;
+ }
+ if (Expression *x = evaluateDtor(istate, oldelem))
+ return x;
+ (*oldelems)[lowerbound + i] = newelem;
+ }
+ }
+ else
+ {
+ // normal order
+ for (size_t i = 0; i < upperbound - lowerbound; i++)
+ {
+ Expression *oldelem = (*oldelems)[(size_t)(i + firstIndex)];
+ Expression *newelem = (*newelems)[(size_t)(i + srclower)];
+ newelem = copyLiteral(newelem).copy();
+ newelem->type = elemtype;
+ if (needsPostblit)
+ {
+ if (Expression *x = evaluatePostblit(istate, newelem))
+ return x;
+ }
+ if (Expression *x = evaluateDtor(istate, oldelem))
+ return x;
+ (*oldelems)[lowerbound + i] = newelem;
+ }
+ }
+
+ //assert(0);
+ return newval; // oldval?
+ }
+ if (aggregate == aggr2 &&
+ lowerbound < srcupper && srclower < upperbound)
+ {
+ e->error("overlapping slice assignment [%d..%d] = [%llu..%llu]",
+ lowerbound, upperbound, srclower, srcupper);
+ return CTFEExp::cantexp;
+ }
+ #if 1 // todo: instead we can directly access to each elements of the slice
+ Expression *orignewval = newval;
+ newval = resolveSlice(newval);
+ if (CTFEExp::isCantExp(newval))
+ {
+ e->error("CTFE internal error: slice %s", orignewval->toChars());
+ return CTFEExp::cantexp;
+ }
+ #endif
+ // no overlapping
+ //length?
+ assert(newval->op != TOKslice);
+ }
+ if (newval->op == TOKstring && !isBlockAssignment)
+ {
+ /* Mixed slice: it was initialized as an array literal of chars/integers.
+ * Now a slice of it is being set with a string.
+ */
+ sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, (size_t)firstIndex);
+ return newval;
+ }
+ if (newval->op == TOKarrayliteral && !isBlockAssignment)
+ {
+ Expressions *oldelems = existingAE->elements;
+ Expressions *newelems = ((ArrayLiteralExp *)newval)->elements;
+ Type *elemtype = existingAE->type->nextOf();
+ bool needsPostblit = e->op != TOKblit && e->e2->isLvalue();
+ for (size_t j = 0; j < newelems->dim; j++)
+ {
+ Expression *newelem = (*newelems)[j];
+ newelem = paintTypeOntoLiteral(elemtype, newelem);
+ if (needsPostblit)
+ {
+ Expression *x = evaluatePostblit(istate, newelem);
+ if (exceptionOrCantInterpret(x))
+ return x;
+ }
+ (*oldelems)[(size_t)(j + firstIndex)] = newelem;
+ }
+ return newval;
+ }
+
+ /* Block assignment, initialization of static arrays
+ * x[] = newval
+ * x may be a multidimensional static array. (Note that this
+ * only happens with array literals, never with strings).
+ */
+ struct RecursiveBlock
+ {
+ InterState *istate;
+ Expression *newval;
+ bool refCopy;
+ bool needsPostblit;
+ bool needsDtor;
+
+ Expression *assignTo(ArrayLiteralExp *ae)
+ {
+ return assignTo(ae, 0, ae->elements->dim);
+ }
+
+ Expression *assignTo(ArrayLiteralExp *ae, size_t lwr, size_t upr)
+ {
+ Expressions *w = ae->elements;
+
+ assert(ae->type->ty == Tsarray ||
+ ae->type->ty == Tarray);
+ bool directblk = ((TypeArray *)ae->type)->next->equivalent(newval->type);
+
+ for (size_t k = lwr; k < upr; k++)
+ {
+ if (!directblk && (*w)[k]->op == TOKarrayliteral)
+ {
+ // Multidimensional array block assign
+ if (Expression *ex = assignTo((ArrayLiteralExp *)(*w)[k]))
+ return ex;
+ }
+ else if (refCopy)
+ {
+ (*w)[k] = newval;
+ }
+ else if (!needsPostblit && !needsDtor)
+ {
+ assignInPlace((*w)[k], newval);
+ }
+ else
+ {
+ Expression *oldelem = (*w)[k];
+ Expression *tmpelem = needsDtor ? copyLiteral(oldelem).copy() : NULL;
+
+ assignInPlace(oldelem, newval);
+
+ if (needsPostblit)
+ {
+ if (Expression *ex = evaluatePostblit(istate, oldelem))
+ return ex;
+ }
+ if (needsDtor)
+ {
+ // Bugzilla 14860
+ if (Expression *ex = evaluateDtor(istate, tmpelem))
+ return ex;
+ }
+ }
+ }
+ return NULL;
+ }
+ };
+
+ Type *tn = newval->type->toBasetype();
+ bool wantRef = (tn->ty == Tarray || isAssocArray(tn) ||tn->ty == Tclass);
+ bool cow = newval->op != TOKstructliteral &&
+ newval->op != TOKarrayliteral &&
+ newval->op != TOKstring;
+ Type *tb = tn->baseElemOf();
+ StructDeclaration *sd = (tb->ty == Tstruct ? ((TypeStruct *)tb)->sym : NULL);
+
+ RecursiveBlock rb;
+ rb.istate = istate;
+ rb.newval = newval;
+ rb.refCopy = wantRef || cow;
+ rb.needsPostblit = sd && sd->postblit && e->op != TOKblit && e->e2->isLvalue();
+ rb.needsDtor = sd && sd->dtor && e->op == TOKassign;
+
+ if (Expression *ex = rb.assignTo(existingAE, lowerbound, upperbound))
+ return ex;
+
+ if (goal == ctfeNeedNothing)
+ return NULL; // avoid creating an unused literal
+ SliceExp *retslice = new SliceExp(e->loc, existingAE,
+ new IntegerExp(e->loc, firstIndex, Type::tsize_t),
+ new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
+ retslice->type = e->type;
+ return interpret(retslice, istate);
+ }
+
+ e->error("slice operation %s = %s cannot be evaluated at compile time",
+ e1->toChars(), newval->toChars());
+ return CTFEExp::cantexp;
+ }
+
+ void visit(AssignExp *e)
+ {
+ interpretAssignCommon(e, NULL);
+ }
+
+ void visit(BinAssignExp *e)
+ {
+ switch (e->op)
+ {
+ case TOKaddass: interpretAssignCommon(e, &Add); return;
+ case TOKminass: interpretAssignCommon(e, &Min); return;
+ case TOKcatass: interpretAssignCommon(e, &ctfeCat); return;
+ case TOKmulass: interpretAssignCommon(e, &Mul); return;
+ case TOKdivass: interpretAssignCommon(e, &Div); return;
+ case TOKmodass: interpretAssignCommon(e, &Mod); return;
+ case TOKshlass: interpretAssignCommon(e, &Shl); return;
+ case TOKshrass: interpretAssignCommon(e, &Shr); return;
+ case TOKushrass: interpretAssignCommon(e, &Ushr); return;
+ case TOKandass: interpretAssignCommon(e, &And); return;
+ case TOKorass: interpretAssignCommon(e, &Or); return;
+ case TOKxorass: interpretAssignCommon(e, &Xor); return;
+ case TOKpowass: interpretAssignCommon(e, &Pow); return;
+ default:
+ assert(0);
+ return;
+ }
+ }
+
+ void visit(PostExp *e)
+ {
+ if (e->op == TOKplusplus)
+ interpretAssignCommon(e, &Add, 1);
+ else
+ interpretAssignCommon(e, &Min, 1);
+ }
+
+ /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
+ * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
+ * 0 otherwise
+ */
+ static int isPointerCmpExp(Expression *e, Expression **p1, Expression **p2)
+ {
+ int ret = 1;
+ while (e->op == TOKnot)
+ {
+ ret *= -1;
+ e = ((NotExp *)e)->e1;
+ }
+ switch (e->op)
+ {
+ case TOKlt:
+ case TOKle:
+ ret *= -1;
+ /* fall through */
+ case TOKgt:
+ case TOKge:
+ *p1 = ((BinExp *)e)->e1;
+ *p2 = ((BinExp *)e)->e2;
+ if (!(isPointer((*p1)->type) && isPointer((*p2)->type)))
+ ret = 0;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+ }
+
+ /** Negate a relational operator, eg >= becomes <
+ */
+ static TOK reverseRelation(TOK op)
+ {
+ switch (op)
+ {
+ case TOKge: return TOKlt;
+ case TOKgt: return TOKle;
+ case TOKle: return TOKgt;
+ case TOKlt: return TOKge;
+ default:
+ return assert(0), TOKreserved;
+ }
+ }
+
+ /** If this is a four pointer relation, evaluate it, else return NULL.
+ *
+ * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
+ * where p1, p2 are expressions yielding pointers to memory block p,
+ * and q1, q2 are expressions yielding pointers to memory block q.
+ * This expression is valid even if p and q are independent memory
+ * blocks and are therefore not normally comparable; the && form returns true
+ * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
+ * true if [p1..p2] lies outside [q1..q2], and false otherwise.
+ *
+ * Within the expression, any ordering of p1, p2, q1, q2 is permissible;
+ * the comparison operators can be any of >, <, <=, >=, provided that
+ * both directions (p > q and p < q) are checked. Additionally the
+ * relational sub-expressions can be negated, eg
+ * (!(q1 < p1) && p2 <= q2) is valid.
+ */
+ void interpretFourPointerRelation(BinExp *e)
+ {
+ assert(e->op == TOKandand || e->op == TOKoror);
+
+ /* It can only be an isInside expression, if both e1 and e2 are
+ * directional pointer comparisons.
+ * Note that this check can be made statically; it does not depends on
+ * any runtime values. This allows a JIT implementation to compile a
+ * special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
+ */
+
+ // Save the pointer expressions and the comparison directions,
+ // so we can use them later.
+ Expression *p1 = NULL;
+ Expression *p2 = NULL;
+ Expression *p3 = NULL;
+ Expression *p4 = NULL;
+ int dir1 = isPointerCmpExp(e->e1, &p1, &p2);
+ int dir2 = isPointerCmpExp(e->e2, &p3, &p4);
+ if (dir1 == 0 || dir2 == 0)
+ {
+ result = NULL;
+ return;
+ }
+
+ //printf("FourPointerRelation %s\n", toChars());
+
+ // Evaluate the first two pointers
+ p1 = interpret(p1, istate);
+ if (exceptionOrCant(p1))
+ return;
+ p2 = interpret(p2, istate);
+ if (exceptionOrCant(p2))
+ return;
+ dinteger_t ofs1, ofs2;
+ Expression *agg1 = getAggregateFromPointer(p1, &ofs1);
+ Expression *agg2 = getAggregateFromPointer(p2, &ofs2);
+
+ if (!pointToSameMemoryBlock(agg1, agg2) &&
+ agg1->op != TOKnull &&
+ agg2->op != TOKnull)
+ {
+ // Here it is either CANT_INTERPRET,
+ // or an IsInside comparison returning false.
+ p3 = interpret(p3, istate);
+ if (CTFEExp::isCantExp(p3))
+ return;
+ // Note that it is NOT legal for it to throw an exception!
+ Expression *except = NULL;
+ if (exceptionOrCantInterpret(p3))
+ except = p3;
+ else
+ {
+ p4 = interpret(p4, istate);
+ if (CTFEExp::isCantExp(p4))
+ {
+ result = p4;
+ return;
+ }
+ if (exceptionOrCantInterpret(p4))
+ except = p4;
+ }
+ if (except)
+ {
+ e->error("comparison %s of pointers to unrelated memory blocks remains "
+ "indeterminate at compile time "
+ "because exception %s was thrown while evaluating %s",
+ e->e1->toChars(), except->toChars(), e->e2->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ dinteger_t ofs3, ofs4;
+ Expression *agg3 = getAggregateFromPointer(p3, &ofs3);
+ Expression *agg4 = getAggregateFromPointer(p4, &ofs4);
+ // The valid cases are:
+ // p1 > p2 && p3 > p4 (same direction, also for < && <)
+ // p1 > p2 && p3 < p4 (different direction, also < && >)
+ // Changing any > into >= doesnt affect the result
+ if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
+ (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
+ {
+ // it's a legal two-sided comparison
+ result = new IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type);
+ return;
+ }
+ // It's an invalid four-pointer comparison. Either the second
+ // comparison is in the same direction as the first, or else
+ // more than two memory blocks are involved (either two independent
+ // invalid comparisons are present, or else agg3 == agg4).
+ e->error("comparison %s of pointers to unrelated memory blocks is "
+ "indeterminate at compile time, even when combined with %s.",
+ e->e1->toChars(), e->e2->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ // The first pointer expression didn't need special treatment, so we
+ // we need to interpret the entire expression exactly as a normal && or ||.
+ // This is easy because we haven't evaluated e2 at all yet, and we already
+ // know it will return a bool.
+ // But we mustn't evaluate the pointer expressions in e1 again, in case
+ // they have side-effects.
+ bool nott = false;
+ Expression *ex = e->e1;
+ while (ex->op == TOKnot)
+ {
+ nott = !nott;
+ ex = ((NotExp *)ex)->e1;
+ }
+ TOK cmpop = ex->op;
+ if (nott)
+ cmpop = reverseRelation(cmpop);
+ int cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
+ // We already know this is a valid comparison.
+ assert(cmp >= 0);
+ if ((e->op == TOKandand && cmp == 1) ||
+ (e->op == TOKoror && cmp == 0))
+ {
+ result = interpret(e->e2, istate);
+ return;
+ }
+ result = new IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type);
+ }
+
+ void visit(AndAndExp *e)
+ {
+ // Check for an insidePointer expression, evaluate it if so
+ interpretFourPointerRelation(e);
+ if (result)
+ return;
+
+ result = interpret(e->e1, istate);
+ if (exceptionOrCant(result))
+ return;
+
+ int res;
+ if (result->isBool(false))
+ res = 0;
+ else if (isTrueBool(result))
+ {
+ UnionExp ue2;
+ result = interpret(&ue2, e->e2, istate);
+ if (exceptionOrCant(result))
+ return;
+ if (result->op == TOKvoidexp)
+ {
+ assert(e->type->ty == Tvoid);
+ result = NULL;
+ return;
+ }
+ if (result->isBool(false))
+ res = 0;
+ else if (isTrueBool(result))
+ res = 1;
+ else
+ {
+ result->error("%s does not evaluate to a boolean", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ }
+ else
+ {
+ result->error("%s cannot be interpreted as a boolean", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (goal != ctfeNeedNothing)
+ {
+ new(pue) IntegerExp(e->loc, res, e->type);
+ result = pue->exp();
+ }
+ }
+
+ void visit(OrOrExp *e)
+ {
+ // Check for an insidePointer expression, evaluate it if so
+ interpretFourPointerRelation(e);
+ if (result)
+ return;
+
+ result = interpret(e->e1, istate);
+ if (exceptionOrCant(result))
+ return;
+
+ int res;
+ if (isTrueBool(result))
+ res = 1;
+ else if (result->isBool(false))
+ {
+ UnionExp ue2;
+ result = interpret(&ue2, e->e2, istate);
+ if (exceptionOrCant(result))
+ return;
+ if (result->op == TOKvoidexp)
+ {
+ assert(e->type->ty == Tvoid);
+ result = NULL;
+ return;
+ }
+ if (result->isBool(false))
+ res = 0;
+ else if (isTrueBool(result))
+ res = 1;
+ else
+ {
+ result->error("%s cannot be interpreted as a boolean", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ }
+ else
+ {
+ result->error("%s cannot be interpreted as a boolean", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (goal != ctfeNeedNothing)
+ {
+ new(pue) IntegerExp(e->loc, res, e->type);
+ result = pue->exp();
+ }
+ }
+
+ // Print a stack trace, starting from callingExp which called fd.
+ // To shorten the stack trace, try to detect recursion.
+ void showCtfeBackTrace(CallExp * callingExp, FuncDeclaration *fd)
+ {
+ if (CtfeStatus::stackTraceCallsToSuppress > 0)
+ {
+ --CtfeStatus::stackTraceCallsToSuppress;
+ return;
+ }
+ errorSupplemental(callingExp->loc, "called from here: %s", callingExp->toChars());
+ // Quit if it's not worth trying to compress the stack trace
+ if (CtfeStatus::callDepth < 6 || global.params.verbose)
+ return;
+ // Recursion happens if the current function already exists in the call stack.
+ int numToSuppress = 0;
+ int recurseCount = 0;
+ int depthSoFar = 0;
+ InterState *lastRecurse = istate;
+ for (InterState * cur = istate; cur; cur = cur->caller)
+ {
+ if (cur->fd == fd)
+ {
+ ++recurseCount;
+ numToSuppress = depthSoFar;
+ lastRecurse = cur;
+ }
+ ++depthSoFar;
+ }
+ // We need at least three calls to the same function, to make compression worthwhile
+ if (recurseCount < 2)
+ return;
+ // We found a useful recursion. Print all the calls involved in the recursion
+ errorSupplemental(fd->loc, "%d recursive calls to function %s", recurseCount, fd->toChars());
+ for (InterState *cur = istate; cur->fd != fd; cur = cur->caller)
+ {
+ errorSupplemental(cur->fd->loc, "recursively called from function %s", cur->fd->toChars());
+ }
+ // We probably didn't enter the recursion in this function.
+ // Go deeper to find the real beginning.
+ InterState * cur = istate;
+ while (lastRecurse->caller && cur->fd == lastRecurse->caller->fd)
+ {
+ cur = cur->caller;
+ lastRecurse = lastRecurse->caller;
+ ++numToSuppress;
+ }
+ CtfeStatus::stackTraceCallsToSuppress = numToSuppress;
+ }
+
+ void visit(CallExp *e)
+ {
+ Expression *pthis = NULL;
+ FuncDeclaration *fd = NULL;
+
+ Expression *ecall = interpret(e->e1, istate);
+ if (exceptionOrCant(ecall))
+ return;
+
+ if (ecall->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp *)ecall;
+
+ // Calling a member function
+ pthis = dve->e1;
+ fd = dve->var->isFuncDeclaration();
+ assert(fd);
+
+ if (pthis->op == TOKdottype)
+ pthis = ((DotTypeExp *)dve->e1)->e1;
+ }
+ else if (ecall->op == TOKvar)
+ {
+ fd = ((VarExp *)ecall)->var->isFuncDeclaration();
+ assert(fd);
+
+ if (fd->ident == Id::_ArrayPostblit ||
+ fd->ident == Id::_ArrayDtor)
+ {
+ assert(e->arguments->dim == 1);
+ Expression *ea = (*e->arguments)[0];
+ //printf("1 ea = %s %s\n", ea->type->toChars(), ea->toChars());
+ if (ea->op == TOKslice)
+ ea = ((SliceExp *)ea)->e1;
+ if (ea->op == TOKcast)
+ ea = ((CastExp *)ea)->e1;
+
+ //printf("2 ea = %s, %s %s\n", ea->type->toChars(), Token::toChars(ea->op), ea->toChars());
+ if (ea->op == TOKvar || ea->op == TOKsymoff)
+ result = getVarExp(e->loc, istate, ((SymbolExp *)ea)->var, ctfeNeedRvalue);
+ else if (ea->op == TOKaddress)
+ result = interpret(((AddrExp *)ea)->e1, istate);
+ else
+ assert(0);
+ if (CTFEExp::isCantExp(result))
+ return;
+
+ if (fd->ident == Id::_ArrayPostblit)
+ result = evaluatePostblit(istate, result);
+ else
+ result = evaluateDtor(istate, result);
+ if (!result)
+ result = CTFEExp::voidexp;
+ return;
+ }
+ }
+ else if (ecall->op == TOKsymoff)
+ {
+ SymOffExp *soe = (SymOffExp *)ecall;
+ fd = soe->var->isFuncDeclaration();
+ assert(fd && soe->offset == 0);
+ }
+ else if (ecall->op == TOKdelegate)
+ {
+ // Calling a delegate
+ fd = ((DelegateExp *)ecall)->func;
+ pthis = ((DelegateExp *)ecall)->e1;
+
+ // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
+ if (pthis->op == TOKvar && ((VarExp *)pthis)->var == fd)
+ pthis = NULL; // context is not necessary for CTFE
+ }
+ else if (ecall->op == TOKfunction)
+ {
+ // Calling a delegate literal
+ fd = ((FuncExp *)ecall)->fd;
+ }
+ else
+ {
+ // delegate.funcptr()
+ // others
+ e->error("cannot call %s at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (!fd)
+ {
+ e->error("CTFE internal error: cannot evaluate %s at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (pthis)
+ {
+ // Member function call
+
+ // Currently this is satisfied because closure is not yet supported.
+ assert(!fd->isNested());
+
+ if (pthis->op == TOKtypeid)
+ {
+ pthis->error("static variable %s cannot be read at compile time", pthis->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ assert(pthis);
+
+ if (pthis->op == TOKnull)
+ {
+ assert(pthis->type->toBasetype()->ty == Tclass);
+ e->error("function call through null class reference %s", pthis->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ assert(pthis->op == TOKstructliteral || pthis->op == TOKclassreference);
+
+ if (fd->isVirtual() && !e->directcall)
+ {
+ // Make a virtual function call.
+ // Get the function from the vtable of the original class
+ assert(pthis->op == TOKclassreference);
+ ClassDeclaration *cd = ((ClassReferenceExp *)pthis)->originalClass();
+
+ // We can't just use the vtable index to look it up, because
+ // vtables for interfaces don't get populated until the glue layer.
+ fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type);
+ assert(fd);
+ }
+ }
+
+ if (fd && fd->semanticRun >= PASSsemantic3done && fd->semantic3Errors)
+ {
+ e->error("CTFE failed because of previous errors in %s", fd->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ // Check for built-in functions
+ result = evaluateIfBuiltin(istate, e->loc, fd, e->arguments, pthis);
+ if (result)
+ return;
+
+ if (!fd->fbody)
+ {
+ e->error("%s cannot be interpreted at compile time,"
+ " because it has no available source code", fd->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ result = interpretFunction(fd, istate, e->arguments, pthis);
+ if (result->op == TOKvoidexp)
+ return;
+ if (!exceptionOrCantInterpret(result))
+ {
+ if (goal != ctfeNeedLvalue) // Peel off CTFE reference if it's unnesessary
+ result = interpret(result, istate);
+ }
+ if (!exceptionOrCantInterpret(result))
+ {
+ result = paintTypeOntoLiteral(e->type, result);
+ result->loc = e->loc;
+ }
+ else if (CTFEExp::isCantExp(result) && !global.gag)
+ showCtfeBackTrace(e, fd); // Print a stack trace.
+ }
+
+ void endTempStackFrame(InterState *pistateComma)
+ {
+ // If we created a temporary stack frame, end it now.
+ if (istate == pistateComma)
+ ctfeStack.endFrame();
+ }
+
+ void visit(CommaExp *e)
+ {
+ CommaExp *firstComma = e;
+ while (firstComma->e1->op == TOKcomma)
+ firstComma = (CommaExp *)firstComma->e1;
+
+ // If it creates a variable, and there's no context for
+ // the variable to be created in, we need to create one now.
+ InterState istateComma;
+ if (!istate && firstComma->e1->op == TOKdeclaration)
+ {
+ ctfeStack.startFrame(NULL);
+ istate = &istateComma;
+ }
+
+ result = CTFEExp::cantexp;
+
+ // If the comma returns a temporary variable, it needs to be an lvalue
+ // (this is particularly important for struct constructors)
+ if (e->e1->op == TOKdeclaration && e->e2->op == TOKvar &&
+ ((DeclarationExp *)e->e1)->declaration == ((VarExp*)e->e2)->var &&
+ ((VarExp*)e->e2)->var->storage_class & STCctfe) // same as Expression::isTemp
+ {
+ VarExp *ve = (VarExp *)e->e2;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ ctfeStack.push(v);
+ if (!v->_init && !getValue(v))
+ {
+ setValue(v, copyLiteral(v->type->defaultInitLiteral(e->loc)).copy());
+ }
+ if (!getValue(v))
+ {
+ Expression *newval = initializerToExpression(v->_init);
+ // Bug 4027. Copy constructors are a weird case where the
+ // initializer is a void function (the variable is modified
+ // through a reference parameter instead).
+ newval = interpret(newval, istate);
+ if (exceptionOrCant(newval))
+ return endTempStackFrame(&istateComma);
+ if (newval->op != TOKvoidexp)
+ {
+ // v isn't necessarily null.
+ setValueWithoutChecking(v, copyLiteral(newval).copy());
+ }
+ }
+ }
+ else
+ {
+ UnionExp ue;
+ Expression *e1 = interpret(&ue, e->e1, istate, ctfeNeedNothing);
+ if (exceptionOrCant(e1))
+ return endTempStackFrame(&istateComma);
+ }
+ result = interpret(pue, e->e2, istate, goal);
+ return endTempStackFrame(&istateComma);
+ }
+
+ void visit(CondExp *e)
+ {
+ UnionExp uecond;
+ Expression *econd;
+ econd = interpret(&uecond, e->econd, istate);
+ if (exceptionOrCant(econd))
+ return;
+
+ if (isPointer(e->econd->type))
+ {
+ if (econd->op != TOKnull)
+ {
+ new(&uecond) IntegerExp(e->loc, 1, Type::tbool);
+ econd = uecond.exp();
+ }
+ }
+
+ if (isTrueBool(econd))
+ result = interpret(pue, e->e1, istate, goal);
+ else if (econd->isBool(false))
+ result = interpret(pue, e->e2, istate, goal);
+ else
+ {
+ e->error("%s does not evaluate to boolean result at compile time", e->econd->toChars());
+ result = CTFEExp::cantexp;
+ }
+ }
+
+ void visit(ArrayLengthExp *e)
+ {
+ UnionExp ue1;
+ Expression *e1 = interpret(&ue1, e->e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1->op != TOKstring &&
+ e1->op != TOKarrayliteral &&
+ e1->op != TOKslice &&
+ e1->op != TOKnull)
+ {
+ e->error("%s cannot be evaluated at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ new(pue) IntegerExp(e->loc, resolveArrayLength(e1), e->type);
+ result = pue->exp();
+ }
+
+ void visit(DelegatePtrExp *e)
+ {
+ Expression *e1 = interpret(pue, e->e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ e->error("%s cannot be evaluated at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(DelegateFuncptrExp *e)
+ {
+ Expression *e1 = interpret(pue, e->e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ e->error("%s cannot be evaluated at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ }
+
+ static bool resolveIndexing(IndexExp *e, InterState *istate, Expression **pagg, uinteger_t *pidx, bool modify)
+ {
+ assert(e->e1->type->toBasetype()->ty != Taarray);
+
+ if (e->e1->type->toBasetype()->ty == Tpointer)
+ {
+ // Indexing a pointer. Note that there is no $ in this case.
+ Expression *e1 = interpret(e->e1, istate);
+ if (exceptionOrCantInterpret(e1))
+ return false;
+
+ Expression *e2 = interpret(e->e2, istate);
+ if (exceptionOrCantInterpret(e2))
+ return false;
+ sinteger_t indx = e2->toInteger();
+
+ dinteger_t ofs;
+ Expression *agg = getAggregateFromPointer(e1, &ofs);
+
+ if (agg->op == TOKnull)
+ {
+ e->error("cannot index through null pointer %s", e->e1->toChars());
+ return false;
+ }
+ if (agg->op == TOKint64)
+ {
+ e->error("cannot index through invalid pointer %s of value %s",
+ e->e1->toChars(), e1->toChars());
+ return false;
+ }
+ // Pointer to a non-array variable
+ if (agg->op == TOKsymoff)
+ {
+ e->error("mutable variable %s cannot be %s at compile time, even through a pointer",
+ (modify ? "modified" : "read"), ((SymOffExp *)agg)->var->toChars());
+ return false;
+ }
+
+ if (agg->op == TOKarrayliteral || agg->op == TOKstring)
+ {
+ dinteger_t len = resolveArrayLength(agg);
+ if (ofs + indx >= len)
+ {
+ e->error("pointer index [%lld] exceeds allocated memory block [0..%lld]",
+ ofs + indx, len);
+ return false;
+ }
+ }
+ else
+ {
+ if (ofs + indx != 0)
+ {
+ e->error("pointer index [%lld] lies outside memory block [0..1]",
+ ofs + indx);
+ return false;
+ }
+ }
+ *pagg = agg;
+ *pidx = ofs + indx;
+ return true;
+ }
+
+ Expression *e1 = interpret(e->e1, istate);
+ if (exceptionOrCantInterpret(e1))
+ return false;
+ if (e1->op == TOKnull)
+ {
+ e->error("cannot index null array %s", e->e1->toChars());
+ return false;
+ }
+ if (e1->op == TOKvector)
+ e1 = ((VectorExp *)e1)->e1;
+
+ // Set the $ variable, and find the array literal to modify
+ if (e1->op != TOKarrayliteral &&
+ e1->op != TOKstring &&
+ e1->op != TOKslice)
+ {
+ e->error("cannot determine length of %s at compile time",
+ e->e1->toChars());
+ return false;
+ }
+
+ dinteger_t len = resolveArrayLength(e1);
+ if (e->lengthVar)
+ {
+ Expression *dollarExp = new IntegerExp(e->loc, len, Type::tsize_t);
+ ctfeStack.push(e->lengthVar);
+ setValue(e->lengthVar, dollarExp);
+ }
+ Expression *e2 = interpret(e->e2, istate);
+ if (e->lengthVar)
+ ctfeStack.pop(e->lengthVar); // $ is defined only inside []
+ if (exceptionOrCantInterpret(e2))
+ return false;
+ if (e2->op != TOKint64)
+ {
+ e->error("CTFE internal error: non-integral index [%s]", e->e2->toChars());
+ return false;
+ }
+
+ if (e1->op == TOKslice)
+ {
+ // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
+ uinteger_t index = e2->toInteger();
+ uinteger_t ilwr = ((SliceExp *)e1)->lwr->toInteger();
+ uinteger_t iupr = ((SliceExp *)e1)->upr->toInteger();
+
+ if (index > iupr - ilwr)
+ {
+ e->error("index %llu exceeds array length %llu", index, iupr - ilwr);
+ return false;
+ }
+ *pagg = ((SliceExp *)e1)->e1;
+ *pidx = index + ilwr;
+ }
+ else
+ {
+ *pagg = e1;
+ *pidx = e2->toInteger();
+ if (len <= *pidx)
+ {
+ e->error("array index %lld is out of bounds [0..%lld]",
+ *pidx, len);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void visit(IndexExp *e)
+ {
+ if (e->e1->type->toBasetype()->ty == Tpointer)
+ {
+ Expression *agg;
+ uinteger_t indexToAccess;
+ if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
+ {
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (agg->op == TOKarrayliteral || agg->op == TOKstring)
+ {
+ if (goal == ctfeNeedLvalue)
+ {
+ // if we need a reference, IndexExp shouldn't be interpreting
+ // the expression to a value, it should stay as a reference
+ new(pue) IndexExp(e->loc, agg, new IntegerExp(e->e2->loc, indexToAccess, e->e2->type));
+ result = pue->exp();
+ result->type = e->type;
+ return;
+ }
+ result = ctfeIndex(e->loc, e->type, agg, indexToAccess);
+ return;
+ }
+ else
+ {
+ assert(indexToAccess == 0);
+ result = interpret(agg, istate, goal);
+ if (exceptionOrCant(result))
+ return;
+ result = paintTypeOntoLiteral(e->type, result);
+ return;
+ }
+ }
+
+ if (e->e1->type->toBasetype()->ty == Taarray)
+ {
+ Expression *e1 = interpret(e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1->op == TOKnull)
+ {
+ if (goal == ctfeNeedLvalue && e1->type->ty == Taarray && e->modifiable)
+ {
+ assert(0); // does not reach here?
+ return;
+ }
+ e->error("cannot index null array %s", e->e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ Expression *e2 = interpret(e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+
+ if (goal == ctfeNeedLvalue)
+ {
+ // Pointer or reference of a scalar type
+ if (e1 == e->e1 && e2 == e->e2)
+ result = e;
+ else
+ {
+ new(pue) IndexExp(e->loc, e1, e2);
+ result = pue->exp();
+ result->type = e->type;
+ }
+ return;
+ }
+
+ assert(e1->op == TOKassocarrayliteral);
+ UnionExp e2tmp;
+ e2 = resolveSlice(e2, &e2tmp);
+ result = findKeyInAA(e->loc, (AssocArrayLiteralExp *)e1, e2);
+ if (!result)
+ {
+ e->error("key %s not found in associative array %s", e2->toChars(), e->e1->toChars());
+ result = CTFEExp::cantexp;
+ }
+ return;
+ }
+
+ Expression *agg;
+ uinteger_t indexToAccess;
+ if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
+ {
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (goal == ctfeNeedLvalue)
+ {
+ Expression *e2 = new IntegerExp(e->e2->loc, indexToAccess, Type::tsize_t);
+ new(pue) IndexExp(e->loc, agg, e2);
+ result = pue->exp();
+ result->type = e->type;
+ return;
+ }
+
+ result = ctfeIndex(e->loc, e->type, agg, indexToAccess);
+ if (exceptionOrCant(result))
+ return;
+ if (result->op == TOKvoid)
+ {
+ e->error("%s is used before initialized", e->toChars());
+ errorSupplemental(result->loc, "originally uninitialized here");
+ result = CTFEExp::cantexp;
+ return;
+ }
+ result = paintTypeOntoLiteral(e->type, result);
+ }
+
+ void visit(SliceExp *e)
+ {
+ if (e->e1->type->toBasetype()->ty == Tpointer)
+ {
+ // Slicing a pointer. Note that there is no $ in this case.
+ Expression *e1 = interpret(e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1->op == TOKint64)
+ {
+ e->error("cannot slice invalid pointer %s of value %s", e->e1->toChars(), e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ /* Evaluate lower and upper bounds of slice
+ */
+ Expression *lwr = interpret(e->lwr, istate);
+ if (exceptionOrCant(lwr))
+ return;
+ Expression *upr = interpret(e->upr, istate);
+ if (exceptionOrCant(upr))
+ return;
+ uinteger_t ilwr = lwr->toInteger();
+ uinteger_t iupr = upr->toInteger();
+
+ dinteger_t ofs;
+ Expression *agg = getAggregateFromPointer(e1, &ofs);
+ ilwr += ofs;
+ iupr += ofs;
+ if (agg->op == TOKnull)
+ {
+ if (iupr == ilwr)
+ {
+ result = new NullExp(e->loc);
+ result->type = e->type;
+ return;
+ }
+ e->error("cannot slice null pointer %s", e->e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (agg->op == TOKsymoff)
+ {
+ e->error("slicing pointers to static variables is not supported in CTFE");
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (agg->op != TOKarrayliteral && agg->op != TOKstring)
+ {
+ e->error("pointer %s cannot be sliced at compile time (it does not point to an array)", e->e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ assert(agg->op == TOKarrayliteral || agg->op == TOKstring);
+ dinteger_t len = ArrayLength(Type::tsize_t, agg).exp()->toInteger();
+ //Type *pointee = ((TypePointer *)agg->type)->next;
+ if (iupr > (len + 1) || iupr < ilwr)
+ {
+ e->error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]", ilwr, iupr, len);
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (ofs != 0)
+ {
+ lwr = new IntegerExp(e->loc, ilwr, lwr->type);
+ upr = new IntegerExp(e->loc, iupr, upr->type);
+ }
+ new(pue) SliceExp(e->loc, agg, lwr, upr);
+ result = pue->exp();
+ result->type = e->type;
+ return;
+ }
+
+ Expression *e1 = interpret(e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+
+ if (!e->lwr)
+ {
+ result = paintTypeOntoLiteral(e->type, e1);
+ return;
+ }
+
+ /* Set the $ variable
+ */
+ if (e1->op != TOKarrayliteral && e1->op != TOKstring && e1->op != TOKnull && e1->op != TOKslice)
+ {
+ e->error("cannot determine length of %s at compile time", e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ uinteger_t dollar = resolveArrayLength(e1);
+ if (e->lengthVar)
+ {
+ IntegerExp *dollarExp = new IntegerExp(e->loc, dollar, Type::tsize_t);
+ ctfeStack.push(e->lengthVar);
+ setValue(e->lengthVar, dollarExp);
+ }
+
+ /* Evaluate lower and upper bounds of slice
+ */
+ Expression *lwr = interpret(e->lwr, istate);
+ if (exceptionOrCant(lwr))
+ {
+ if (e->lengthVar)
+ ctfeStack.pop(e->lengthVar);
+ return;
+ }
+ Expression *upr = interpret(e->upr, istate);
+ if (exceptionOrCant(upr))
+ {
+ if (e->lengthVar)
+ ctfeStack.pop(e->lengthVar);
+ return;
+ }
+ if (e->lengthVar)
+ ctfeStack.pop(e->lengthVar); // $ is defined only inside [L..U]
+
+ uinteger_t ilwr = lwr->toInteger();
+ uinteger_t iupr = upr->toInteger();
+ if (e1->op == TOKnull)
+ {
+ if (ilwr == 0 && iupr == 0)
+ {
+ result = e1;
+ return;
+ }
+ e1->error("slice [%llu..%llu] is out of bounds", ilwr, iupr);
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (e1->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *)e1;
+ // Simplify slice of slice:
+ // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
+ uinteger_t lo1 = se->lwr->toInteger();
+ uinteger_t up1 = se->upr->toInteger();
+ if (ilwr > iupr || iupr > up1 - lo1)
+ {
+ e->error("slice[%llu..%llu] exceeds array bounds[%llu..%llu]", ilwr, iupr, lo1, up1);
+ result = CTFEExp::cantexp;
+ return;
+ }
+ ilwr += lo1;
+ iupr += lo1;
+ new(pue) SliceExp(e->loc, se->e1, new IntegerExp(e->loc, ilwr, lwr->type), new IntegerExp(e->loc, iupr, upr->type));
+ result = pue->exp();
+ result->type = e->type;
+ return;
+ }
+ if (e1->op == TOKarrayliteral || e1->op == TOKstring)
+ {
+ if (iupr < ilwr || dollar < iupr)
+ {
+ e->error("slice [%lld..%lld] exceeds array bounds [0..%lld]", ilwr, iupr, dollar);
+ result = CTFEExp::cantexp;
+ return;
+ }
+ }
+ new(pue) SliceExp(e->loc, e1, lwr, upr);
+ result = pue->exp();
+ result->type = e->type;
+ }
+
+ void visit(InExp *e)
+ {
+ Expression *e1 = interpret(e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ Expression *e2 = interpret(e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ if (e2->op == TOKnull)
+ {
+ new(pue) NullExp(e->loc, e->type);
+ result = pue->exp();
+ return;
+ }
+ if (e2->op != TOKassocarrayliteral)
+ {
+ e->error("%s cannot be interpreted at compile time", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ e1 = resolveSlice(e1);
+ result = findKeyInAA(e->loc, (AssocArrayLiteralExp *)e2, e1);
+ if (exceptionOrCant(result))
+ return;
+ if (!result)
+ {
+ new(pue) NullExp(e->loc, e->type);
+ result = pue->exp();
+ }
+ else
+ {
+ // Create a CTFE pointer &aa[index]
+ result = new IndexExp(e->loc, e2, e1);
+ result->type = e->type->nextOf();
+ new(pue) AddrExp(e->loc, result, e->type);
+ result = pue->exp();
+ }
+ }
+
+ void visit(CatExp *e)
+ {
+ Expression *e1 = interpret(e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ Expression *e2 = interpret(e->e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ UnionExp e1tmp;
+ e1 = resolveSlice(e1, &e1tmp);
+ UnionExp e2tmp;
+ e2 = resolveSlice(e2, &e2tmp);
+ result = ctfeCat(e->loc, e->type, e1, e2).copy();
+ if (CTFEExp::isCantExp(result))
+ {
+ e->error("%s cannot be interpreted at compile time", e->toChars());
+ return;
+ }
+ // We know we still own it, because we interpreted both e1 and e2
+ if (result->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)result;
+ ale->ownedByCtfe = OWNEDctfe;
+
+ // Bugzilla 14686
+ for (size_t i = 0; i < ale->elements->dim; i++)
+ {
+ Expression *ex = evaluatePostblit(istate, (*ale->elements)[i]);
+ if (exceptionOrCant(ex))
+ return;
+ }
+ }
+ if (result->op == TOKstring)
+ ((StringExp *)result)->ownedByCtfe = OWNEDctfe;
+ }
+
+ void visit(DeleteExp *e)
+ {
+ result = interpret(e->e1, istate);
+ if (exceptionOrCant(result))
+ return;
+
+ if (result->op == TOKnull)
+ {
+ result = CTFEExp::voidexp;
+ return;
+ }
+
+ Type *tb = e->e1->type->toBasetype();
+ switch (tb->ty)
+ {
+ case Tclass:
+ {
+ if (result->op != TOKclassreference)
+ {
+ e->error("delete on invalid class reference '%s'", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ ClassReferenceExp *cre = (ClassReferenceExp *)result;
+ ClassDeclaration *cd = cre->originalClass();
+ if (cd->aggDelete)
+ {
+ e->error("member deallocators not supported by CTFE");
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (cd->dtor)
+ {
+ result = interpretFunction(cd->dtor, istate, NULL, cre);
+ if (exceptionOrCant(result))
+ return;
+ }
+ break;
+ }
+
+ case Tpointer:
+ {
+ tb = ((TypePointer *)tb)->next->toBasetype();
+ if (tb->ty == Tstruct)
+ {
+ if (result->op != TOKaddress ||
+ ((AddrExp *)result)->e1->op != TOKstructliteral)
+ {
+ e->error("delete on invalid struct pointer '%s'", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ StructLiteralExp *sle = (StructLiteralExp *)((AddrExp *)result)->e1;
+ if (sd->aggDelete)
+ {
+ e->error("member deallocators not supported by CTFE");
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (sd->dtor)
+ {
+ result = interpretFunction(sd->dtor, istate, NULL, sle);
+ if (exceptionOrCant(result))
+ return;
+ }
+ }
+ break;
+ }
+
+ case Tarray:
+ {
+ Type *tv = tb->nextOf()->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ if (result->op != TOKarrayliteral)
+ {
+ e->error("delete on invalid struct array '%s'", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+ if (sd->aggDelete)
+ {
+ e->error("member deallocators not supported by CTFE");
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (sd->dtor)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)result;
+ for (size_t i = 0; i < ale->elements->dim; i++)
+ {
+ Expression *el = (*ale->elements)[i];
+ result = interpretFunction(sd->dtor, istate, NULL, el);
+ if (exceptionOrCant(result))
+ return;
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ assert(0);
+ }
+ result = CTFEExp::voidexp;
+ }
+
+ void visit(CastExp *e)
+ {
+ Expression *e1 = interpret(e->e1, istate, goal);
+ if (exceptionOrCant(e1))
+ return;
+ // If the expression has been cast to void, do nothing.
+ if (e->to->ty == Tvoid)
+ {
+ result = CTFEExp::voidexp;
+ return;
+ }
+ if (e->to->ty == Tpointer && e1->op != TOKnull)
+ {
+ Type *pointee = ((TypePointer *)e->type)->next;
+ // Implement special cases of normally-unsafe casts
+ if (e1->op == TOKint64)
+ {
+ // Happens with Windows HANDLEs, for example.
+ result = paintTypeOntoLiteral(e->to, e1);
+ return;
+ }
+ bool castToSarrayPointer = false;
+ bool castBackFromVoid = false;
+ if (e1->type->ty == Tarray || e1->type->ty == Tsarray || e1->type->ty == Tpointer)
+ {
+ // Check for unsupported type painting operations
+ // For slices, we need the type being sliced,
+ // since it may have already been type painted
+ Type *elemtype = e1->type->nextOf();
+ if (e1->op == TOKslice)
+ elemtype = ((SliceExp *)e1)->e1->type->nextOf();
+ // Allow casts from X* to void *, and X** to void** for any X.
+ // But don't allow cast from X* to void**.
+ // So, we strip all matching * from source and target to find X.
+ // Allow casts to X* from void* only if the 'void' was originally an X;
+ // we check this later on.
+ Type *ultimatePointee = pointee;
+ Type *ultimateSrc = elemtype;
+ while (ultimatePointee->ty == Tpointer && ultimateSrc->ty == Tpointer)
+ {
+ ultimatePointee = ultimatePointee->nextOf();
+ ultimateSrc = ultimateSrc->nextOf();
+ }
+ if (ultimatePointee->ty == Tsarray && ultimatePointee->nextOf()->equivalent(ultimateSrc))
+ {
+ castToSarrayPointer = true;
+ }
+ else if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid &&
+ !isSafePointerCast(elemtype, pointee))
+ {
+ e->error("reinterpreting cast from %s* to %s* is not supported in CTFE",
+ elemtype->toChars(), pointee->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (ultimateSrc->ty == Tvoid)
+ castBackFromVoid = true;
+ }
+
+ if (e1->op == TOKslice)
+ {
+ if (((SliceExp *)e1)->e1->op == TOKnull)
+ {
+ result = paintTypeOntoLiteral(e->type, ((SliceExp *)e1)->e1);
+ return;
+ }
+ // Create a CTFE pointer &aggregate[1..2]
+ IndexExp *ei = new IndexExp(e->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr);
+ ei->type = e->type->nextOf();
+ new(pue) AddrExp(e->loc, ei, e->type);
+ result = pue->exp();
+ return;
+ }
+ if (e1->op == TOKarrayliteral || e1->op == TOKstring)
+ {
+ // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
+ IndexExp *ei = new IndexExp(e->loc, e1, new IntegerExp(e->loc, 0, Type::tsize_t));
+ ei->type = e->type->nextOf();
+ new(pue) AddrExp(e->loc, ei, e->type);
+ result = pue->exp();
+ return;
+ }
+ if (e1->op == TOKindex && !((IndexExp *)e1)->e1->type->equals(e1->type))
+ {
+ // type painting operation
+ IndexExp *ie = (IndexExp *)e1;
+ result = new IndexExp(e1->loc, ie->e1, ie->e2);
+ if (castBackFromVoid)
+ {
+ // get the original type. For strings, it's just the type...
+ Type *origType = ie->e1->type->nextOf();
+ // ..but for arrays of type void*, it's the type of the element
+ if (ie->e1->op == TOKarrayliteral && ie->e2->op == TOKint64)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1;
+ size_t indx = (size_t)ie->e2->toInteger();
+ if (indx < ale->elements->dim)
+ {
+ Expression *xx = (*ale->elements)[indx];
+ if (xx)
+ {
+ if (xx->op == TOKindex)
+ origType = ((IndexExp *)xx)->e1->type->nextOf();
+ else if (xx->op == TOKaddress)
+ origType= ((AddrExp *)xx)->e1->type;
+ else if (xx->op == TOKvar)
+ origType = ((VarExp *)xx)->var->type;
+ }
+ }
+ }
+ if (!isSafePointerCast(origType, pointee))
+ {
+ e->error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", origType->toChars(), pointee->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ }
+ result->type = e->type;
+ return;
+ }
+ if (e1->op == TOKaddress)
+ {
+ Type *origType = ((AddrExp *)e1)->e1->type;
+ if (isSafePointerCast(origType, pointee))
+ {
+ new(pue) AddrExp(e->loc, ((AddrExp *)e1)->e1, e->type);
+ result = pue->exp();
+ return;
+ }
+ if (castToSarrayPointer && pointee->toBasetype()->ty == Tsarray && ((AddrExp *)e1)->e1->op == TOKindex)
+ {
+ // &val[idx]
+ dinteger_t dim = ((TypeSArray *)pointee->toBasetype())->dim->toInteger();
+ IndexExp *ie = (IndexExp *)((AddrExp *)e1)->e1;
+ Expression *lwr = ie->e2;
+ Expression *upr = new IntegerExp(ie->e2->loc, ie->e2->toInteger() + dim, Type::tsize_t);
+
+ // Create a CTFE pointer &val[idx..idx+dim]
+ SliceExp *er = new SliceExp(e->loc, ie->e1, lwr, upr);
+ er->type = pointee;
+ new(pue) AddrExp(e->loc, er, e->type);
+ result = pue->exp();
+ return;
+ }
+ }
+ if (e1->op == TOKvar || e1->op == TOKsymoff)
+ {
+ // type painting operation
+ Type *origType = ((SymbolExp *)e1)->var->type;
+ if (castBackFromVoid && !isSafePointerCast(origType, pointee))
+ {
+ e->error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", origType->toChars(), pointee->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (e1->op == TOKvar)
+ new(pue) VarExp(e->loc, ((VarExp *)e1)->var);
+ else
+ new(pue) SymOffExp(e->loc, ((SymOffExp *)e1)->var, ((SymOffExp *)e1)->offset);
+ result = pue->exp();
+ result->type = e->to;
+ return;
+ }
+
+ // Check if we have a null pointer (eg, inside a struct)
+ e1 = interpret(e1, istate);
+ if (e1->op != TOKnull)
+ {
+ e->error("pointer cast from %s to %s is not supported at compile time", e1->type->toChars(), e->to->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ }
+ if (e->to->ty == Tsarray && e->e1->type->ty == Tvector)
+ {
+ // Special handling for: cast(float[4])__vector([w, x, y, z])
+ e1 = interpret(e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ assert(e1->op == TOKvector);
+ e1 = ((VectorExp *)e1)->e1;
+ }
+ if (e->to->ty == Tarray && e1->op == TOKslice)
+ {
+ // Note that the slice may be void[], so when checking for dangerous
+ // casts, we need to use the original type, which is se->e1.
+ SliceExp *se = (SliceExp *)e1;
+ if (!isSafePointerCast(se->e1->type->nextOf(), e->to->nextOf()))
+ {
+ e->error("array cast from %s to %s is not supported at compile time", se->e1->type->toChars(), e->to->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ new(pue) SliceExp(e1->loc, se->e1, se->lwr, se->upr);
+ result = pue->exp();
+ result->type = e->to;
+ return;
+ }
+ // Disallow array type painting, except for conversions between built-in
+ // types of identical size.
+ if ((e->to->ty == Tsarray || e->to->ty == Tarray) && (e1->type->ty == Tsarray || e1->type->ty == Tarray) && !isSafePointerCast(e1->type->nextOf(), e->to->nextOf()))
+ {
+ e->error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), e->to->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (e->to->ty == Tsarray)
+ e1 = resolveSlice(e1);
+ if (e->to->toBasetype()->ty == Tbool && e1->type->ty == Tpointer)
+ {
+ new(pue) IntegerExp(e->loc, e1->op != TOKnull, e->to);
+ result = pue->exp();
+ return;
+ }
+ result = ctfeCast(e->loc, e->type, e->to, e1);
+ }
+
+ void visit(AssertExp *e)
+ {
+ Expression *e1 = interpret(pue, e->e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (isTrueBool(e1))
+ {
+ }
+ else if (e1->isBool(false))
+ {
+ if (e->msg)
+ {
+ UnionExp ue;
+ result = interpret(&ue, e->msg, istate);
+ if (exceptionOrCant(result))
+ return;
+ e->error("%s", result->toChars());
+ }
+ else
+ e->error("%s failed", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ else
+ {
+ e->error("%s is not a compile time boolean expression", e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ result = e1;
+ return;
+ }
+
+ void visit(PtrExp *e)
+ {
+ // Check for int<->float and long<->double casts.
+ if (e->e1->op == TOKsymoff && ((SymOffExp *)e->e1)->offset == 0 && ((SymOffExp *)e->e1)->var->isVarDeclaration() && isFloatIntPaint(e->type, ((SymOffExp *)e->e1)->var->type))
+ {
+ // *(cast(int*)&v), where v is a float variable
+ result = paintFloatInt(getVarExp(e->loc, istate, ((SymOffExp *)e->e1)->var, ctfeNeedRvalue), e->type);
+ return;
+ }
+ if (e->e1->op == TOKcast && ((CastExp *)e->e1)->e1->op == TOKaddress)
+ {
+ // *(cast(int*)&x), where x is a float expression
+ Expression *x = ((AddrExp *)(((CastExp *)e->e1)->e1))->e1;
+ if (isFloatIntPaint(e->type, x->type))
+ {
+ result = paintFloatInt(interpret(x, istate), e->type);
+ return;
+ }
+ }
+
+ // Constant fold *(&structliteral + offset)
+ if (e->e1->op == TOKadd)
+ {
+ AddExp *ae = (AddExp *)e->e1;
+ if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
+ {
+ AddrExp *ade = (AddrExp *)ae->e1;
+ Expression *ex = interpret(ade->e1, istate);
+ if (exceptionOrCant(ex))
+ return;
+ if (ex->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)ex;
+ dinteger_t offset = ae->e2->toInteger();
+ result = se->getField(e->type, (unsigned)offset);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ // It's possible we have an array bounds error. We need to make sure it
+ // errors with this line number, not the one where the pointer was set.
+ result = interpret(e->e1, istate);
+ if (exceptionOrCant(result))
+ return;
+
+ if (result->op == TOKfunction)
+ return;
+ if (result->op == TOKsymoff)
+ {
+ SymOffExp *soe = (SymOffExp *)result;
+ if (soe->offset == 0 && soe->var->isFuncDeclaration())
+ return;
+ e->error("cannot dereference pointer to static variable %s at compile time", soe->var->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (result->op != TOKaddress)
+ {
+ if (result->op == TOKnull)
+ e->error("dereference of null pointer '%s'", e->e1->toChars());
+ else
+ e->error("dereference of invalid pointer '%s'", result->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ // *(&x) ==> x
+ result = ((AddrExp *)result)->e1;
+
+ if (result->op == TOKslice && e->type->toBasetype()->ty == Tsarray)
+ {
+ /* aggr[lwr..upr]
+ * upr may exceed the upper boundary of aggr, but the check is deferred
+ * until those out-of-bounds elements will be touched.
+ */
+ return;
+ }
+ result = interpret(result, istate, goal);
+ if (exceptionOrCant(result))
+ return;
+ }
+
+ void visit(DotVarExp *e)
+ {
+ Expression *ex = interpret(e->e1, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ if (FuncDeclaration *f = e->var->isFuncDeclaration())
+ {
+ if (ex == e->e1)
+ result = e; // optimize: reuse this CTFE reference
+ else
+ {
+ new(pue) DotVarExp(e->loc, ex, f, false);
+ result = pue->exp();
+ result->type = e->type;
+ }
+ return;
+ }
+
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (!v)
+ {
+ e->error("CTFE internal error: %s", e->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (ex->op == TOKnull)
+ {
+ if (ex->type->toBasetype()->ty == Tclass)
+ e->error("class '%s' is null and cannot be dereferenced", e->e1->toChars());
+ else
+ e->error("CTFE internal error: null this '%s'", e->e1->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (ex->op != TOKstructliteral && ex->op != TOKclassreference)
+ {
+ e->error("%s.%s is not yet implemented at compile time", e->e1->toChars(), e->var->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ StructLiteralExp *se;
+ int i;
+
+ // We can't use getField, because it makes a copy
+ if (ex->op == TOKclassreference)
+ {
+ se = ((ClassReferenceExp *)ex)->value;
+ i = ((ClassReferenceExp *)ex)->findFieldIndexByName(v);
+ }
+ else
+ {
+ se = (StructLiteralExp *)ex;
+ i = findFieldIndexByName(se->sd, v);
+ }
+ if (i == -1)
+ {
+ e->error("couldn't find field %s of type %s in %s", v->toChars(), e->type->toChars(), se->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (goal == ctfeNeedLvalue)
+ {
+ Expression *ev = (*se->elements)[i];
+ if (!ev || ev->op == TOKvoid)
+ (*se->elements)[i] = voidInitLiteral(e->type, v).copy();
+ // just return the (simplified) dotvar expression as a CTFE reference
+ if (e->e1 == ex)
+ result = e;
+ else
+ {
+ new(pue) DotVarExp(e->loc, ex, v);
+ result = pue->exp();
+ result->type = e->type;
+ }
+ return;
+ }
+
+ result = (*se->elements)[i];
+ if (!result)
+ {
+ e->error("Internal Compiler Error: null field %s", v->toChars());
+ result = CTFEExp::cantexp;
+ return;
+ }
+ if (result->op == TOKvoid)
+ {
+ VoidInitExp *ve = (VoidInitExp *)result;
+ const char *s = ve->var->toChars();
+ if (v->overlapped)
+ {
+ e->error("reinterpretation through overlapped field %s is not allowed in CTFE", s);
+ result = CTFEExp::cantexp;
+ return;
+ }
+ e->error("cannot read uninitialized variable %s in CTFE", s);
+ result = CTFEExp::cantexp;
+ return;
+ }
+
+ if (v->type->ty != result->type->ty && v->type->ty == Tsarray)
+ {
+ // Block assignment from inside struct literals
+ TypeSArray *tsa = (TypeSArray *)v->type;
+ size_t len = (size_t)tsa->dim->toInteger();
+ result = createBlockDuplicatedArrayLiteral(ex->loc, v->type, ex, len);
+ (*se->elements)[i] = result;
+ }
+ }
+
+ void visit(RemoveExp *e)
+ {
+ Expression *agg = interpret(e->e1, istate);
+ if (exceptionOrCant(agg))
+ return;
+ Expression *index = interpret(e->e2, istate);
+ if (exceptionOrCant(index))
+ return;
+ if (agg->op == TOKnull)
+ {
+ result = CTFEExp::voidexp;
+ return;
+ }
+ assert(agg->op == TOKassocarrayliteral);
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)agg;
+ Expressions *keysx = aae->keys;
+ Expressions *valuesx = aae->values;
+ size_t removed = 0;
+ for (size_t j = 0; j < valuesx->dim; ++j)
+ {
+ Expression *ekey = (*keysx)[j];
+ int eq = ctfeEqual(e->loc, TOKequal, ekey, index);
+ if (eq)
+ ++removed;
+ else if (removed != 0)
+ {
+ (*keysx)[j - removed] = ekey;
+ (*valuesx)[j - removed] = (*valuesx)[j];
+ }
+ }
+ valuesx->dim = valuesx->dim - removed;
+ keysx->dim = keysx->dim - removed;
+ new(pue) IntegerExp(e->loc, removed ? 1 : 0, Type::tbool);
+ result = pue->exp();
+ }
+
+ void visit(ClassReferenceExp *e)
+ {
+ //printf("ClassReferenceExp::interpret() %s\n", e->value->toChars());
+ result = e;
+ }
+
+ void visit(VoidInitExp *e)
+ {
+ e->error("CTFE internal error: trying to read uninitialized variable");
+ assert(0);
+ result = CTFEExp::cantexp;
+ }
+
+ void visit(ThrownExceptionExp *e)
+ {
+ assert(0); // This should never be interpreted
+ result = e;
+ }
+
+};
+
+/********************************************
+ * Interpret the expression.
+ * Params:
+ * pue = non-null pointer to temporary storage that can be used to store the return value
+ * e = Expression to interpret
+ * istate = context
+ * goal = what the result will be used for
+ * Returns:
+ * resulting expression
+ */
+
+static Expression *interpret(UnionExp *pue, Expression *e, InterState *istate, CtfeGoal goal)
+{
+ if (!e)
+ return NULL;
+ Interpreter v(pue, istate, goal);
+ e->accept(&v);
+ Expression *ex = v.result;
+ assert(goal == ctfeNeedNothing || ex != NULL);
+ return ex;
+}
+
+///
+Expression *interpret(Expression *e, InterState *istate, CtfeGoal goal)
+{
+ UnionExp ue;
+ Expression *result = interpret(&ue, e, istate, goal);
+ if (result == ue.exp())
+ result = ue.copy();
+ return result;
+}
+
+/***********************************
+ * Interpret the statement.
+ * Params:
+ * pue = non-null pointer to temporary storage that can be used to store the return value
+ * s = Statement to interpret
+ * istate = context
+ * Returns:
+ * NULL continue to next statement
+ * TOKcantexp cannot interpret statement at compile time
+ * !NULL expression from return statement, or thrown exception
+ */
+
+static Expression *interpret(UnionExp *pue, Statement *s, InterState *istate)
+{
+ if (!s)
+ return NULL;
+ Interpreter v(pue, istate, ctfeNeedNothing);
+ s->accept(&v);
+ return v.result;
+}
+
+Expression *interpret(Statement *s, InterState *istate)
+{
+ UnionExp ue;
+ Expression *result = interpret(&ue, s, istate);
+ if (result == ue.exp())
+ result = ue.copy();
+ return result;
+}
+
+Expression *scrubArray(Loc loc, Expressions *elems, bool structlit = false);
+
+/* All results destined for use outside of CTFE need to have their CTFE-specific
+ * features removed.
+ * In particular, all slices must be resolved.
+ */
+Expression *scrubReturnValue(Loc loc, Expression *e)
+{
+ if (e->op == TOKclassreference)
+ {
+ StructLiteralExp *se = ((ClassReferenceExp*)e)->value;
+ se->ownedByCtfe = OWNEDcode;
+ if (!(se->stageflags & stageScrub))
+ {
+ int old = se->stageflags;
+ se->stageflags |= stageScrub;
+ if (Expression *ex = scrubArray(loc, se->elements, true))
+ return ex;
+ se->stageflags = old;
+ }
+ }
+ if (e->op == TOKvoid)
+ {
+ error(loc, "uninitialized variable '%s' cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
+ return new ErrorExp();
+ }
+ e = resolveSlice(e);
+ if (e->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ se->ownedByCtfe = OWNEDcode;
+ if (!(se->stageflags & stageScrub))
+ {
+ int old = se->stageflags;
+ se->stageflags |= stageScrub;
+ if (Expression *ex = scrubArray(loc, se->elements, true))
+ return ex;
+ se->stageflags = old;
+ }
+ }
+ if (e->op == TOKstring)
+ {
+ ((StringExp *)e)->ownedByCtfe = OWNEDcode;
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDcode;
+ if (Expression *ex = scrubArray(loc, ((ArrayLiteralExp *)e)->elements))
+ return ex;
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+ aae->ownedByCtfe = OWNEDcode;
+ if (Expression *ex = scrubArray(loc, aae->keys))
+ return ex;
+ if (Expression *ex = scrubArray(loc, aae->values))
+ return ex;
+ aae->type = toBuiltinAAType(aae->type);
+ }
+ return e;
+}
+
+// Return true if every element is either void,
+// or is an array literal or struct literal of void elements.
+bool isEntirelyVoid(Expressions *elems)
+{
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ Expression *m = (*elems)[i];
+ // It can be NULL for performance reasons,
+ // see StructLiteralExp::interpret().
+ if (!m)
+ continue;
+
+ if (!(m->op == TOKvoid) &&
+ !(m->op == TOKarrayliteral && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) &&
+ !(m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements)))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Scrub all members of an array. Return false if error
+Expression *scrubArray(Loc loc, Expressions *elems, bool structlit)
+{
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ Expression *m = (*elems)[i];
+ // It can be NULL for performance reasons,
+ // see StructLiteralExp::interpret().
+ if (!m)
+ continue;
+
+ // A struct .init may contain void members.
+ // Static array members are a weird special case (bug 10994).
+ if (structlit &&
+ ((m->op == TOKvoid) ||
+ (m->op == TOKarrayliteral && m->type->ty == Tsarray && isEntirelyVoid(((ArrayLiteralExp *)m)->elements)) ||
+ (m->op == TOKstructliteral && isEntirelyVoid(((StructLiteralExp *)m)->elements))))
+ {
+ m = NULL;
+ }
+ else
+ {
+ m = scrubReturnValue(loc, m);
+ if (CTFEExp::isCantExp(m) || m->op == TOKerror)
+ return m;
+ }
+ (*elems)[i] = m;
+ }
+ return NULL;
+}
+
+Expression *scrubArrayCache(Loc loc, Expressions *elems);
+
+Expression *scrubCacheValue(Loc loc, Expression *e)
+{
+ if (e->op == TOKclassreference)
+ {
+ StructLiteralExp *sle = ((ClassReferenceExp*)e)->value;
+ sle->ownedByCtfe = OWNEDcache;
+ if (!(sle->stageflags & stageScrub))
+ {
+ int old = sle->stageflags;
+ sle->stageflags |= stageScrub;
+ if (Expression *ex = scrubArrayCache(loc, sle->elements))
+ return ex;
+ sle->stageflags = old;
+ }
+ }
+ if (e->op == TOKstructliteral)
+ {
+ StructLiteralExp *sle = (StructLiteralExp *)e;
+ sle->ownedByCtfe = OWNEDcache;
+ if (!(sle->stageflags & stageScrub))
+ {
+ int old = sle->stageflags;
+ sle->stageflags |= stageScrub;
+ if (Expression *ex = scrubArrayCache(loc, sle->elements))
+ return ex;
+ sle->stageflags = old;
+ }
+ }
+ if (e->op == TOKstring)
+ {
+ ((StringExp *)e)->ownedByCtfe = OWNEDcache;
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDcache;
+ if (Expression *ex = scrubArrayCache(loc, ((ArrayLiteralExp *)e)->elements))
+ return ex;
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
+ aae->ownedByCtfe = OWNEDcache;
+ if (Expression *ex = scrubArrayCache(loc, aae->keys))
+ return ex;
+ if (Expression *ex = scrubArrayCache(loc, aae->values))
+ return ex;
+ }
+ return e;
+}
+
+Expression *scrubArrayCache(Loc loc, Expressions *elems)
+{
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ Expression *m = (*elems)[i];
+ if (!m)
+ continue;
+ (*elems)[i] = scrubCacheValue(loc, m);
+ }
+ return NULL;
+}
+
+/******************************* Special Functions ***************************/
+
+Expression *interpret_length(InterState *istate, Expression *earg)
+{
+ //printf("interpret_length()\n");
+ earg = interpret(earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ dinteger_t len = 0;
+ if (earg->op == TOKassocarrayliteral)
+ len = ((AssocArrayLiteralExp *)earg)->keys->dim;
+ else
+ assert(earg->op == TOKnull);
+ Expression *e = new IntegerExp(earg->loc, len, Type::tsize_t);
+ return e;
+}
+
+Expression *interpret_keys(InterState *istate, Expression *earg, Type *returnType)
+{
+ earg = interpret(earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ if (earg->op == TOKnull)
+ return new NullExp(earg->loc, returnType);
+ if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+ return NULL;
+ assert(earg->op == TOKassocarrayliteral);
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+ ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->keys);
+ ae->ownedByCtfe = aae->ownedByCtfe;
+ ae->type = returnType;
+ return copyLiteral(ae).copy();
+}
+
+Expression *interpret_values(InterState *istate, Expression *earg, Type *returnType)
+{
+ earg = interpret(earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ if (earg->op == TOKnull)
+ return new NullExp(earg->loc, returnType);
+ if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+ return NULL;
+ assert(earg->op == TOKassocarrayliteral);
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
+ ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->values);
+ ae->ownedByCtfe = aae->ownedByCtfe;
+ ae->type = returnType;
+ //printf("result is %s\n", e->toChars());
+ return copyLiteral(ae).copy();
+}
+
+Expression *interpret_dup(InterState *istate, Expression *earg)
+{
+ earg = interpret(earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ if (earg->op == TOKnull)
+ return new NullExp(earg->loc, earg->type);
+ if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
+ return NULL;
+ assert(earg->op == TOKassocarrayliteral);
+ AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)copyLiteral(earg).copy();
+ for (size_t i = 0; i < aae->keys->dim; i++)
+ {
+ if (Expression *e = evaluatePostblit(istate, (*aae->keys)[i]))
+ return e;
+ if (Expression *e = evaluatePostblit(istate, (*aae->values)[i]))
+ return e;
+ }
+ aae->type = earg->type->mutableOf(); // repaint type from const(int[int]) to const(int)[int]
+ //printf("result is %s\n", aae->toChars());
+ return aae;
+}
+
+// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
+Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *deleg)
+{
+ aa = interpret(aa, istate);
+ if (exceptionOrCantInterpret(aa))
+ return aa;
+ if (aa->op != TOKassocarrayliteral)
+ return new IntegerExp(deleg->loc, 0, Type::tsize_t);
+
+ FuncDeclaration *fd = NULL;
+ Expression *pthis = NULL;
+ if (deleg->op == TOKdelegate)
+ {
+ fd = ((DelegateExp *)deleg)->func;
+ pthis = ((DelegateExp *)deleg)->e1;
+ }
+ else if (deleg->op == TOKfunction)
+ fd = ((FuncExp*)deleg)->fd;
+
+ assert(fd && fd->fbody);
+ assert(fd->parameters);
+ size_t numParams = fd->parameters->dim;
+ assert(numParams == 1 || numParams == 2);
+
+ Parameter *fparam = Parameter::getNth(((TypeFunction *)fd->type)->parameters, numParams - 1);
+ bool wantRefValue = 0 != (fparam->storageClass & (STCout | STCref));
+
+ Expressions args;
+ args.setDim(numParams);
+
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)aa;
+ if (!ae->keys || ae->keys->dim == 0)
+ return new IntegerExp(deleg->loc, 0, Type::tsize_t);
+ Expression *eresult;
+
+ for (size_t i = 0; i < ae->keys->dim; ++i)
+ {
+ Expression *ekey = (*ae->keys)[i];
+ Expression *evalue = (*ae->values)[i];
+ if (wantRefValue)
+ {
+ Type *t = evalue->type;
+ evalue = new IndexExp(deleg->loc, ae, ekey);
+ evalue->type = t;
+ }
+ args[numParams - 1] = evalue;
+ if (numParams == 2) args[0] = ekey;
+
+ eresult = interpretFunction(fd, istate, &args, pthis);
+ if (exceptionOrCantInterpret(eresult))
+ return eresult;
+
+ assert(eresult->op == TOKint64);
+ if (((IntegerExp *)eresult)->getInteger() != 0)
+ return eresult;
+ }
+ return eresult;
+}
+
+// Helper function: given a function of type A[] f(...),
+// return A[].
+Type *returnedArrayType(FuncDeclaration *fd)
+{
+ assert(fd->type->ty == Tfunction);
+ assert(fd->type->nextOf()->ty == Tarray);
+ return ((TypeFunction *)fd->type)->nextOf();
+}
+
+/* Decoding UTF strings for foreach loops. Duplicates the functionality of
+ * the twelve _aApplyXXn functions in aApply.d in the runtime.
+ */
+Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *deleg, bool rvs)
+{
+ FuncDeclaration *fd = NULL;
+ Expression *pthis = NULL;
+ if (deleg->op == TOKdelegate)
+ {
+ fd = ((DelegateExp *)deleg)->func;
+ pthis = ((DelegateExp *)deleg)->e1;
+ }
+ else if (deleg->op == TOKfunction)
+ fd = ((FuncExp*)deleg)->fd;
+
+ assert(fd && fd->fbody);
+ assert(fd->parameters);
+ size_t numParams = fd->parameters->dim;
+ assert(numParams == 1 || numParams == 2);
+ Type *charType = (*fd->parameters)[numParams-1]->type;
+ Type *indexType = numParams == 2 ? (*fd->parameters)[0]->type
+ : Type::tsize_t;
+ size_t len = (size_t)resolveArrayLength(str);
+ if (len == 0)
+ return new IntegerExp(deleg->loc, 0, indexType);
+
+ str = resolveSlice(str);
+
+ StringExp *se = NULL;
+ ArrayLiteralExp *ale = NULL;
+ if (str->op == TOKstring)
+ se = (StringExp *) str;
+ else if (str->op == TOKarrayliteral)
+ ale = (ArrayLiteralExp *)str;
+ else
+ {
+ str->error("CTFE internal error: cannot foreach %s", str->toChars());
+ return CTFEExp::cantexp;
+ }
+ Expressions args;
+ args.setDim(numParams);
+
+ Expression *eresult = NULL; // ded-store to prevent spurious warning
+
+ // Buffers for encoding; also used for decoding array literals
+ utf8_t utf8buf[4];
+ unsigned short utf16buf[2];
+
+ size_t start = rvs ? len : 0;
+ size_t end = rvs ? 0: len;
+ for (size_t indx = start; indx != end;)
+ {
+ // Step 1: Decode the next dchar from the string.
+
+ const char *errmsg = NULL; // Used for reporting decoding errors
+ dchar_t rawvalue; // Holds the decoded dchar
+ size_t currentIndex = indx; // The index of the decoded character
+
+ if (ale)
+ {
+ // If it is an array literal, copy the code points into the buffer
+ size_t buflen = 1; // #code points in the buffer
+ size_t n = 1; // #code points in this char
+ size_t sz = (size_t)ale->type->nextOf()->size();
+
+ switch (sz)
+ {
+ case 1:
+ if (rvs)
+ {
+ // find the start of the string
+ --indx;
+ buflen = 1;
+ while (indx > 0 && buflen < 4)
+ {
+ Expression * r = (*ale->elements)[indx];
+ assert(r->op == TOKint64);
+ utf8_t x = (utf8_t)(((IntegerExp *)r)->getInteger());
+ if ((x & 0xC0) != 0x80)
+ break;
+ ++buflen;
+ }
+ }
+ else
+ buflen = (indx + 4 > len) ? len - indx : 4;
+ for (size_t i = 0; i < buflen; ++i)
+ {
+ Expression * r = (*ale->elements)[indx + i];
+ assert(r->op == TOKint64);
+ utf8buf[i] = (utf8_t)(((IntegerExp *)r)->getInteger());
+ }
+ n = 0;
+ errmsg = utf_decodeChar(&utf8buf[0], buflen, &n, &rawvalue);
+ break;
+ case 2:
+ if (rvs)
+ {
+ // find the start of the string
+ --indx;
+ buflen = 1;
+ Expression * r = (*ale->elements)[indx];
+ assert(r->op == TOKint64);
+ unsigned short x = (unsigned short)(((IntegerExp *)r)->getInteger());
+ if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
+ {
+ --indx;
+ ++buflen;
+ }
+ }
+ else
+ buflen = (indx + 2 > len) ? len - indx : 2;
+ for (size_t i=0; i < buflen; ++i)
+ {
+ Expression * r = (*ale->elements)[indx + i];
+ assert(r->op == TOKint64);
+ utf16buf[i] = (unsigned short)(((IntegerExp *)r)->getInteger());
+ }
+ n = 0;
+ errmsg = utf_decodeWchar(&utf16buf[0], buflen, &n, &rawvalue);
+ break;
+ case 4:
+ {
+ if (rvs)
+ --indx;
+
+ Expression * r = (*ale->elements)[indx];
+ assert(r->op == TOKint64);
+ rawvalue = (dchar_t)((IntegerExp *)r)->getInteger();
+ n = 1;
+ }
+ break;
+ default:
+ assert(0);
+ }
+ if (!rvs)
+ indx += n;
+ }
+ else
+ {
+ // String literals
+ size_t saveindx; // used for reverse iteration
+
+ switch (se->sz)
+ {
+ case 1:
+ if (rvs)
+ {
+ // find the start of the string
+ utf8_t *s = (utf8_t *)se->string;
+ --indx;
+ while (indx > 0 && ((s[indx]&0xC0) == 0x80))
+ --indx;
+ saveindx = indx;
+ }
+ errmsg = utf_decodeChar((utf8_t *)se->string, se->len, &indx, &rawvalue);
+ if (rvs)
+ indx = saveindx;
+ break;
+ case 2:
+ if (rvs)
+ {
+ // find the start
+ unsigned short *s = (unsigned short *)se->string;
+ --indx;
+ if (s[indx] >= 0xDC00 && s[indx]<= 0xDFFF)
+ --indx;
+ saveindx = indx;
+ }
+ errmsg = utf_decodeWchar((unsigned short *)se->string, se->len, &indx, &rawvalue);
+ if (rvs)
+ indx = saveindx;
+ break;
+ case 4:
+ if (rvs)
+ --indx;
+ rawvalue = ((unsigned *)(se->string))[indx];
+ if (!rvs)
+ ++indx;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ if (errmsg)
+ {
+ deleg->error("%s", errmsg);
+ return CTFEExp::cantexp;
+ }
+
+ // Step 2: encode the dchar in the target encoding
+
+ int charlen = 1; // How many codepoints are involved?
+ switch (charType->size())
+ {
+ case 1:
+ charlen = utf_codeLengthChar(rawvalue);
+ utf_encodeChar(&utf8buf[0], rawvalue);
+ break;
+ case 2:
+ charlen = utf_codeLengthWchar(rawvalue);
+ utf_encodeWchar(&utf16buf[0], rawvalue);
+ break;
+ case 4:
+ break;
+ default:
+ assert(0);
+ }
+ if (rvs)
+ currentIndex = indx;
+
+ // Step 3: call the delegate once for each code point
+
+ // The index only needs to be set once
+ if (numParams == 2)
+ args[0] = new IntegerExp(deleg->loc, currentIndex, indexType);
+
+ Expression *val = NULL;
+
+ for (int k= 0; k < charlen; ++k)
+ {
+ dchar_t codepoint;
+ switch (charType->size())
+ {
+ case 1:
+ codepoint = utf8buf[k];
+ break;
+ case 2:
+ codepoint = utf16buf[k];
+ break;
+ case 4:
+ codepoint = rawvalue;
+ break;
+ default:
+ assert(0);
+ }
+ val = new IntegerExp(str->loc, codepoint, charType);
+
+ args[numParams - 1] = val;
+
+ eresult = interpretFunction(fd, istate, &args, pthis);
+ if (exceptionOrCantInterpret(eresult))
+ return eresult;
+ assert(eresult->op == TOKint64);
+ if (((IntegerExp *)eresult)->getInteger() != 0)
+ return eresult;
+ }
+ }
+ return eresult;
+}
+
+/* If this is a built-in function, return the interpreted result,
+ * Otherwise, return NULL.
+ */
+Expression *evaluateIfBuiltin(InterState *istate, Loc loc,
+ FuncDeclaration *fd, Expressions *arguments, Expression *pthis)
+{
+ Expression *e = NULL;
+ size_t nargs = arguments ? arguments->dim : 0;
+ if (!pthis)
+ {
+ if (isBuiltin(fd) == BUILTINyes)
+ {
+ Expressions args;
+ args.setDim(nargs);
+ for (size_t i = 0; i < args.dim; i++)
+ {
+ Expression *earg = (*arguments)[i];
+ earg = interpret(earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ args[i] = earg;
+ }
+ e = eval_builtin(loc, fd, &args);
+ if (!e)
+ {
+ error(loc, "cannot evaluate unimplemented builtin %s at compile time", fd->toChars());
+ e = CTFEExp::cantexp;
+ }
+ }
+ }
+ if (!pthis)
+ {
+ Expression *firstarg = nargs > 0 ? (*arguments)[0] : NULL;
+ if (firstarg && firstarg->type->toBasetype()->ty == Taarray)
+ {
+ TypeAArray *firstAAtype = (TypeAArray *)firstarg->type;
+ const char *id = fd->ident->toChars();
+ if (nargs == 1 && fd->ident == Id::aaLen)
+ return interpret_length(istate, firstarg);
+ if (nargs == 3 && !strcmp(id, "_aaApply"))
+ return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2]));
+ if (nargs == 3 && !strcmp(id, "_aaApply2"))
+ return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2]));
+ if (nargs == 1 && !strcmp(id, "keys") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+ return interpret_keys(istate, firstarg, firstAAtype->index->arrayOf());
+ if (nargs == 1 && !strcmp(id, "values") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+ return interpret_values(istate, firstarg, firstAAtype->nextOf()->arrayOf());
+ if (nargs == 1 && !strcmp(id, "rehash") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+ return interpret(firstarg, istate);
+ if (nargs == 1 && !strcmp(id, "dup") && !strcmp(fd->toParent2()->ident->toChars(), "object"))
+ return interpret_dup(istate, firstarg);
+ }
+ }
+ if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object)
+ {
+ if (pthis->op == TOKclassreference && fd->parent->ident == Id::Throwable)
+ {
+ // At present, the constructors just copy their arguments into the struct.
+ // But we might need some magic if stack tracing gets added to druntime.
+ StructLiteralExp *se = ((ClassReferenceExp *)pthis)->value;
+ assert(arguments->dim <= se->elements->dim);
+ for (size_t i = 0; i < arguments->dim; ++i)
+ {
+ e = interpret((*arguments)[i], istate);
+ if (exceptionOrCantInterpret(e))
+ return e;
+ (*se->elements)[i] = e;
+ }
+ return CTFEExp::voidexp;
+ }
+ }
+ if (nargs == 1 && !pthis &&
+ (fd->ident == Id::criticalenter || fd->ident == Id::criticalexit))
+ {
+ // Support synchronized{} as a no-op
+ return CTFEExp::voidexp;
+ }
+ if (!pthis)
+ {
+ const char *id = fd->ident->toChars();
+ size_t idlen = strlen(id);
+ if (nargs == 2 && (idlen == 10 || idlen == 11) &&
+ !strncmp(id, "_aApply", 7))
+ {
+ // Functions from aApply.d and aApplyR.d in the runtime
+ bool rvs = (idlen == 11); // true if foreach_reverse
+ char c = id[idlen-3]; // char width: 'c', 'w', or 'd'
+ char s = id[idlen-2]; // string width: 'c', 'w', or 'd'
+ char n = id[idlen-1]; // numParams: 1 or 2.
+ // There are 12 combinations
+ if ((n == '1' || n == '2') &&
+ (c == 'c' || c == 'w' || c == 'd') &&
+ (s == 'c' || s == 'w' || s == 'd') && c != s)
+ {
+ Expression *str = (*arguments)[0];
+ str = interpret(str, istate);
+ if (exceptionOrCantInterpret(str))
+ return str;
+ return foreachApplyUtf(istate, str, (*arguments)[1], rvs);
+ }
+ }
+ }
+ return e;
+}
+
+Expression *evaluatePostblit(InterState *istate, Expression *e)
+{
+ Type *tb = e->type->baseElemOf();
+ if (tb->ty != Tstruct)
+ return NULL;
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ if (!sd->postblit)
+ return NULL;
+
+ if (e->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
+ for (size_t i = 0; i < ale->elements->dim; i++)
+ {
+ e = evaluatePostblit(istate, (*ale->elements)[i]);
+ if (e)
+ return e;
+ }
+ return NULL;
+ }
+ if (e->op == TOKstructliteral)
+ {
+ // e.__postblit()
+ e = interpretFunction(sd->postblit, istate, NULL, e);
+ if (exceptionOrCantInterpret(e))
+ return e;
+ return NULL;
+ }
+ assert(0);
+ return NULL;
+}
+
+Expression *evaluateDtor(InterState *istate, Expression *e)
+{
+ Type *tb = e->type->baseElemOf();
+ if (tb->ty != Tstruct)
+ return NULL;
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ if (!sd->dtor)
+ return NULL;
+
+ if (e->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *alex = (ArrayLiteralExp *)e;
+ for (size_t i = alex->elements->dim; 0 < i--; )
+ e = evaluateDtor(istate, (*alex->elements)[i]);
+ }
+ else if (e->op == TOKstructliteral)
+ {
+ // e.__dtor()
+ e = interpretFunction(sd->dtor, istate, NULL, e);
+ }
+ else
+ assert(0);
+ if (exceptionOrCantInterpret(e))
+ return e;
+ return NULL;
+}
+
+/*************************** CTFE Sanity Checks ***************************/
+
+/* Setter functions for CTFE variable values.
+ * These functions exist to check for compiler CTFE bugs.
+ */
+bool hasValue(VarDeclaration *vd)
+{
+ if (vd->ctfeAdrOnStack == -1)
+ return false;
+ return NULL != getValue(vd);
+}
+
+Expression *getValue(VarDeclaration *vd)
+{
+ return ctfeStack.getValue(vd);
+}
+
+void setValueNull(VarDeclaration *vd)
+{
+ ctfeStack.setValue(vd, NULL);
+}
+
+// Don't check for validity
+void setValueWithoutChecking(VarDeclaration *vd, Expression *newval)
+{
+ ctfeStack.setValue(vd, newval);
+}
+
+void setValue(VarDeclaration *vd, Expression *newval)
+{
+ assert((vd->storage_class & (STCout | STCref))
+ ? isCtfeReferenceValid(newval)
+ : isCtfeValueValid(newval));
+ ctfeStack.setValue(vd, newval);
+}
diff --git a/gcc/d/dmd/dmacro.c b/gcc/d/dmd/dmacro.c
new file mode 100644
index 0000000..a5d8da1
--- /dev/null
+++ b/gcc/d/dmd/dmacro.c
@@ -0,0 +1,463 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/macro.c
+ */
+
+/* Simple macro text processor.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "errors.h"
+#include "root/rmem.h"
+#include "root/root.h"
+
+#include "macro.h"
+
+bool isIdStart(const utf8_t *p);
+bool isIdTail(const utf8_t *p);
+int utfStride(const utf8_t *p);
+
+utf8_t *memdup(const utf8_t *p, size_t len)
+{
+ return (utf8_t *)memcpy(mem.xmalloc(len), p, len);
+}
+
+Macro::Macro(const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
+{
+ next = NULL;
+
+ this->name = name;
+ this->namelen = namelen;
+
+ this->text = text;
+ this->textlen = textlen;
+ inuse = 0;
+}
+
+
+Macro *Macro::search(const utf8_t *name, size_t namelen)
+{ Macro *table;
+
+ //printf("Macro::search(%.*s)\n", namelen, name);
+ for (table = this; table; table = table->next)
+ {
+ if (table->namelen == namelen &&
+ memcmp(table->name, name, namelen) == 0)
+ {
+ //printf("\tfound %d\n", table->textlen);
+ break;
+ }
+ }
+ return table;
+}
+
+Macro *Macro::define(Macro **ptable, const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
+{
+ //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text);
+
+ Macro *table;
+
+ //assert(ptable);
+ for (table = *ptable; table; table = table->next)
+ {
+ if (table->namelen == namelen &&
+ memcmp(table->name, name, namelen) == 0)
+ {
+ table->text = text;
+ table->textlen = textlen;
+ return table;
+ }
+ }
+ table = new Macro(name, namelen, text, textlen);
+ table->next = *ptable;
+ *ptable = table;
+ return table;
+}
+
+/**********************************************************
+ * Given buffer p[0..end], extract argument marg[0..marglen].
+ * Params:
+ * n 0: get entire argument
+ * 1..9: get nth argument
+ * -1: get 2nd through end
+ */
+
+size_t extractArgN(const utf8_t *p, size_t end, const utf8_t **pmarg, size_t *pmarglen, int n)
+{
+ /* Scan forward for matching right parenthesis.
+ * Nest parentheses.
+ * Skip over "..." and '...' strings inside HTML tags.
+ * Skip over <!-- ... --> comments.
+ * Skip over previous macro insertions
+ * Set marglen.
+ */
+ unsigned parens = 1;
+ unsigned char instring = 0;
+ unsigned incomment = 0;
+ unsigned intag = 0;
+ unsigned inexp = 0;
+ int argn = 0;
+
+ size_t v = 0;
+
+ Largstart:
+ // Skip first space, if any, to find the start of the macro argument
+ if (n != 1 && v < end && isspace(p[v]))
+ v++;
+ *pmarg = p + v;
+
+ for (; v < end; v++)
+ { utf8_t c = p[v];
+
+ switch (c)
+ {
+ case ',':
+ if (!inexp && !instring && !incomment && parens == 1)
+ {
+ argn++;
+ if (argn == 1 && n == -1)
+ { v++;
+ goto Largstart;
+ }
+ if (argn == n)
+ break;
+ if (argn + 1 == n)
+ { v++;
+ goto Largstart;
+ }
+ }
+ continue;
+
+ case '(':
+ if (!inexp && !instring && !incomment)
+ parens++;
+ continue;
+
+ case ')':
+ if (!inexp && !instring && !incomment && --parens == 0)
+ {
+ break;
+ }
+ continue;
+
+ case '"':
+ case '\'':
+ if (!inexp && !incomment && intag)
+ {
+ if (c == instring)
+ instring = 0;
+ else if (!instring)
+ instring = c;
+ }
+ continue;
+
+ case '<':
+ if (!inexp && !instring && !incomment)
+ {
+ if (v + 6 < end &&
+ p[v + 1] == '!' &&
+ p[v + 2] == '-' &&
+ p[v + 3] == '-')
+ {
+ incomment = 1;
+ v += 3;
+ }
+ else if (v + 2 < end &&
+ isalpha(p[v + 1]))
+ intag = 1;
+ }
+ continue;
+
+ case '>':
+ if (!inexp)
+ intag = 0;
+ continue;
+
+ case '-':
+ if (!inexp &&
+ !instring &&
+ incomment &&
+ v + 2 < end &&
+ p[v + 1] == '-' &&
+ p[v + 2] == '>')
+ {
+ incomment = 0;
+ v += 2;
+ }
+ continue;
+
+ case 0xFF:
+ if (v + 1 < end)
+ {
+ if (p[v + 1] == '{')
+ inexp++;
+ else if (p[v + 1] == '}')
+ inexp--;
+ }
+ continue;
+
+ default:
+ continue;
+ }
+ break;
+ }
+ if (argn == 0 && n == -1)
+ *pmarg = p + v;
+ *pmarglen = p + v - *pmarg;
+ //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg);
+ return v;
+}
+
+
+/*****************************************************
+ * Expand macro in place in buf.
+ * Only look at the text in buf from start to end.
+ */
+
+void Macro::expand(OutBuffer *buf, size_t start, size_t *pend,
+ const utf8_t *arg, size_t arglen)
+{
+ // limit recursive expansion
+ static int nest;
+ static const int nestLimit = 1000;
+ if (nest > nestLimit)
+ {
+ error(Loc(), "DDoc macro expansion limit exceeded; more than %d "
+ "expansions.", nestLimit);
+ return;
+ }
+ nest++;
+
+ size_t end = *pend;
+ assert(start <= end);
+ assert(end <= buf->offset);
+
+ /* First pass - replace $0
+ */
+ arg = memdup(arg, arglen);
+ for (size_t u = start; u + 1 < end; )
+ {
+ utf8_t *p = (utf8_t *)buf->data; // buf->data is not loop invariant
+
+ /* Look for $0, but not $$0, and replace it with arg.
+ */
+ if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
+ {
+ if (u > start && p[u - 1] == '$')
+ { // Don't expand $$0, but replace it with $0
+ buf->remove(u - 1, 1);
+ end--;
+ u += 1; // now u is one past the closing '1'
+ continue;
+ }
+
+ utf8_t c = p[u + 1];
+ int n = (c == '+') ? -1 : c - '0';
+
+ const utf8_t *marg;
+ size_t marglen;
+ if (n == 0)
+ {
+ marg = arg;
+ marglen = arglen;
+ }
+ else
+ extractArgN(arg, arglen, &marg, &marglen, n);
+ if (marglen == 0)
+ { // Just remove macro invocation
+ //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
+ buf->remove(u, 2);
+ end -= 2;
+ }
+ else if (c == '+')
+ {
+ // Replace '$+' with 'arg'
+ //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
+ buf->remove(u, 2);
+ buf->insert(u, marg, marglen);
+ end += marglen - 2;
+
+ // Scan replaced text for further expansion
+ size_t mend = u + marglen;
+ expand(buf, u, &mend, NULL, 0);
+ end += mend - (u + marglen);
+ u = mend;
+ }
+ else
+ {
+ // Replace '$1' with '\xFF{arg\xFF}'
+ //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg);
+ buf->data[u] = 0xFF;
+ buf->data[u + 1] = '{';
+ buf->insert(u + 2, marg, marglen);
+ buf->insert(u + 2 + marglen, (const char *)"\xFF}", 2);
+ end += -2 + 2 + marglen + 2;
+
+ // Scan replaced text for further expansion
+ size_t mend = u + 2 + marglen;
+ expand(buf, u + 2, &mend, NULL, 0);
+ end += mend - (u + 2 + marglen);
+ u = mend;
+ }
+ //printf("u = %d, end = %d\n", u, end);
+ //printf("#%.*s#\n", end, &buf->data[0]);
+ continue;
+ }
+
+ u++;
+ }
+
+ /* Second pass - replace other macros
+ */
+ for (size_t u = start; u + 4 < end; )
+ {
+ utf8_t *p = (utf8_t *)buf->data; // buf->data is not loop invariant
+
+ /* A valid start of macro expansion is $(c, where c is
+ * an id start character, and not $$(c.
+ */
+ if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p+u+2))
+ {
+ //printf("\tfound macro start '%c'\n", p[u + 2]);
+ utf8_t *name = p + u + 2;
+ size_t namelen = 0;
+
+ const utf8_t *marg;
+ size_t marglen;
+
+ size_t v;
+ /* Scan forward to find end of macro name and
+ * beginning of macro argument (marg).
+ */
+ for (v = u + 2; v < end; v+=utfStride(p+v))
+ {
+
+ if (!isIdTail(p+v))
+ { // We've gone past the end of the macro name.
+ namelen = v - (u + 2);
+ break;
+ }
+ }
+
+ v += extractArgN(p + v, end - v, &marg, &marglen, 0);
+ assert(v <= end);
+
+ if (v < end)
+ { // v is on the closing ')'
+ if (u > start && p[u - 1] == '$')
+ { // Don't expand $$(NAME), but replace it with $(NAME)
+ buf->remove(u - 1, 1);
+ end--;
+ u = v; // now u is one past the closing ')'
+ continue;
+ }
+
+ Macro *m = search(name, namelen);
+
+ if (!m)
+ {
+ static const char undef[] = "DDOC_UNDEFINED_MACRO";
+ m = search((const utf8_t *)undef, strlen(undef));
+ if (m)
+ {
+ // Macro was not defined, so this is an expansion of
+ // DDOC_UNDEFINED_MACRO. Prepend macro name to args.
+ // marg = name[ ] ~ "," ~ marg[ ];
+ if (marglen)
+ {
+ utf8_t *q = (utf8_t *)mem.xmalloc(namelen + 1 + marglen);
+ assert(q);
+ memcpy(q, name, namelen);
+ q[namelen] = ',';
+ memcpy(q + namelen + 1, marg, marglen);
+ marg = q;
+ marglen += namelen + 1;
+ }
+ else
+ {
+ marg = name;
+ marglen = namelen;
+ }
+ }
+ }
+
+ if (m)
+ {
+ if (m->inuse && marglen == 0)
+ { // Remove macro invocation
+ buf->remove(u, v + 1 - u);
+ end -= v + 1 - u;
+ }
+ else if (m->inuse &&
+ ((arglen == marglen && memcmp(arg, marg, arglen) == 0) ||
+ (arglen + 4 == marglen &&
+ marg[0] == 0xFF &&
+ marg[1] == '{' &&
+ memcmp(arg, marg + 2, arglen) == 0 &&
+ marg[marglen - 2] == 0xFF &&
+ marg[marglen - 1] == '}'
+ )
+ )
+ )
+ {
+ /* Recursive expansion:
+ * marg is same as arg (with blue paint added)
+ * Just leave in place.
+ */
+ }
+ else
+ {
+ //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text);
+ marg = memdup(marg, marglen);
+ // Insert replacement text
+ buf->spread(v + 1, 2 + m->textlen + 2);
+ buf->data[v + 1] = 0xFF;
+ buf->data[v + 2] = '{';
+ memcpy(buf->data + v + 3, m->text, m->textlen);
+ buf->data[v + 3 + m->textlen] = 0xFF;
+ buf->data[v + 3 + m->textlen + 1] = '}';
+
+ end += 2 + m->textlen + 2;
+
+ // Scan replaced text for further expansion
+ m->inuse++;
+ size_t mend = v + 1 + 2+m->textlen+2;
+ expand(buf, v + 1, &mend, marg, marglen);
+ end += mend - (v + 1 + 2+m->textlen+2);
+ m->inuse--;
+
+ buf->remove(u, v + 1 - u);
+ end -= v + 1 - u;
+ u += mend - (v + 1);
+ mem.xfree(const_cast<utf8_t *>(marg));
+ //printf("u = %d, end = %d\n", u, end);
+ //printf("#%.*s#\n", end - u, &buf->data[u]);
+ continue;
+ }
+ }
+ else
+ {
+ // Replace $(NAME) with nothing
+ buf->remove(u, v + 1 - u);
+ end -= (v + 1 - u);
+ continue;
+ }
+ }
+ }
+ u++;
+ }
+ mem.xfree(const_cast<utf8_t *>(arg));
+ *pend = end;
+ nest--;
+}
diff --git a/gcc/d/dmd/dmangle.c b/gcc/d/dmd/dmangle.c
new file mode 100644
index 0000000..9734624
--- /dev/null
+++ b/gcc/d/dmd/dmangle.c
@@ -0,0 +1,865 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/mangle.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "root/root.h"
+
+#include "mangle.h"
+#include "init.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "mtype.h"
+#include "attrib.h"
+#include "target.h"
+#include "template.h"
+#include "id.h"
+#include "module.h"
+#include "enum.h"
+#include "expression.h"
+#include "utf.h"
+
+typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
+
+static const char *mangleChar[TMAX];
+
+void initTypeMangle()
+{
+ mangleChar[Tarray] = "A";
+ mangleChar[Tsarray] = "G";
+ mangleChar[Taarray] = "H";
+ mangleChar[Tpointer] = "P";
+ mangleChar[Treference] = "R";
+ mangleChar[Tfunction] = "F";
+ mangleChar[Tident] = "I";
+ mangleChar[Tclass] = "C";
+ mangleChar[Tstruct] = "S";
+ mangleChar[Tenum] = "E";
+ mangleChar[Tdelegate] = "D";
+
+ mangleChar[Tnone] = "n";
+ mangleChar[Tvoid] = "v";
+ mangleChar[Tint8] = "g";
+ mangleChar[Tuns8] = "h";
+ mangleChar[Tint16] = "s";
+ mangleChar[Tuns16] = "t";
+ mangleChar[Tint32] = "i";
+ mangleChar[Tuns32] = "k";
+ mangleChar[Tint64] = "l";
+ mangleChar[Tuns64] = "m";
+ mangleChar[Tint128] = "zi";
+ mangleChar[Tuns128] = "zk";
+ mangleChar[Tfloat32] = "f";
+ mangleChar[Tfloat64] = "d";
+ mangleChar[Tfloat80] = "e";
+
+ mangleChar[Timaginary32] = "o";
+ mangleChar[Timaginary64] = "p";
+ mangleChar[Timaginary80] = "j";
+ mangleChar[Tcomplex32] = "q";
+ mangleChar[Tcomplex64] = "r";
+ mangleChar[Tcomplex80] = "c";
+
+ mangleChar[Tbool] = "b";
+ mangleChar[Tchar] = "a";
+ mangleChar[Twchar] = "u";
+ mangleChar[Tdchar] = "w";
+
+ // '@' shouldn't appear anywhere in the deco'd names
+ mangleChar[Tinstance] = "@";
+ mangleChar[Terror] = "@";
+ mangleChar[Ttypeof] = "@";
+ mangleChar[Ttuple] = "B";
+ mangleChar[Tslice] = "@";
+ mangleChar[Treturn] = "@";
+ mangleChar[Tvector] = "@";
+
+ mangleChar[Tnull] = "n"; // same as TypeNone
+
+ for (size_t i = 0; i < TMAX; i++)
+ {
+ if (!mangleChar[i])
+ fprintf(stderr, "ty = %llu\n", (ulonglong)i);
+ assert(mangleChar[i]);
+ }
+}
+
+/*********************************
+ * Mangling for mod.
+ */
+void MODtoDecoBuffer(OutBuffer *buf, MOD mod)
+{
+ switch (mod)
+ {
+ case 0:
+ break;
+ case MODconst:
+ buf->writeByte('x');
+ break;
+ case MODimmutable:
+ buf->writeByte('y');
+ break;
+ case MODshared:
+ buf->writeByte('O');
+ break;
+ case MODshared | MODconst:
+ buf->writestring("Ox");
+ break;
+ case MODwild:
+ buf->writestring("Ng");
+ break;
+ case MODwildconst:
+ buf->writestring("Ngx");
+ break;
+ case MODshared | MODwild:
+ buf->writestring("ONg");
+ break;
+ case MODshared | MODwildconst:
+ buf->writestring("ONgx");
+ break;
+ default:
+ assert(0);
+ }
+}
+
+class Mangler : public Visitor
+{
+public:
+ OutBuffer *buf;
+
+ Mangler(OutBuffer *buf)
+ {
+ this->buf = buf;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**************************************************
+ * Type mangling
+ */
+
+ void visitWithMask(Type *t, unsigned char modMask)
+ {
+ if (modMask != t->mod)
+ {
+ MODtoDecoBuffer(buf, t->mod);
+ }
+ t->accept(this);
+ }
+
+ void visit(Type *t)
+ {
+ buf->writestring(mangleChar[t->ty]);
+ }
+
+ void visit(TypeNext *t)
+ {
+ visit((Type *)t);
+ visitWithMask(t->next, t->mod);
+ }
+
+ void visit(TypeVector *t)
+ {
+ buf->writestring("Nh");
+ visitWithMask(t->basetype, t->mod);
+ }
+
+ void visit(TypeSArray *t)
+ {
+ visit((Type *)t);
+ if (t->dim)
+ buf->printf("%llu", t->dim->toInteger());
+ if (t->next)
+ visitWithMask(t->next, t->mod);
+ }
+
+ void visit(TypeDArray *t)
+ {
+ visit((Type *)t);
+ if (t->next)
+ visitWithMask(t->next, t->mod);
+ }
+
+ void visit(TypeAArray *t)
+ {
+ visit((Type *)t);
+ visitWithMask(t->index, 0);
+ visitWithMask(t->next, t->mod);
+ }
+
+ void visit(TypeFunction *t)
+ {
+ //printf("TypeFunction::toDecoBuffer() t = %p %s\n", t, t->toChars());
+ //static int nest; if (++nest == 50) *(char*)0=0;
+
+ mangleFuncType(t, t, t->mod, t->next);
+ }
+
+ void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char modMask, Type *tret)
+ {
+ //printf("mangleFuncType() %s\n", t->toChars());
+ if (t->inuse)
+ {
+ t->inuse = 2; // flag error to caller
+ return;
+ }
+ t->inuse++;
+
+ if (modMask != t->mod)
+ MODtoDecoBuffer(buf, t->mod);
+
+ unsigned char mc;
+ switch (t->linkage)
+ {
+ case LINKd: mc = 'F'; break;
+ case LINKc: mc = 'U'; break;
+ case LINKwindows: mc = 'W'; break;
+ case LINKpascal: mc = 'V'; break;
+ case LINKcpp: mc = 'R'; break;
+ case LINKobjc: mc = 'Y'; break;
+ default:
+ assert(0);
+ }
+ buf->writeByte(mc);
+
+ if (ta->purity || ta->isnothrow || ta->isnogc || ta->isproperty || ta->isref || ta->trust || ta->isreturn || ta->isscope)
+ {
+ if (ta->purity)
+ buf->writestring("Na");
+ if (ta->isnothrow)
+ buf->writestring("Nb");
+ if (ta->isref)
+ buf->writestring("Nc");
+ if (ta->isproperty)
+ buf->writestring("Nd");
+ if (ta->isnogc)
+ buf->writestring("Ni");
+ if (ta->isreturn)
+ buf->writestring("Nj");
+ if (ta->isscope && !ta->isreturn && !ta->isscopeinferred)
+ buf->writestring("Nl");
+ switch (ta->trust)
+ {
+ case TRUSTtrusted:
+ buf->writestring("Ne");
+ break;
+ case TRUSTsafe:
+ buf->writestring("Nf");
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Write argument types
+ paramsToDecoBuffer(t->parameters);
+ //if (buf->data[buf->offset - 1] == '@') halt();
+ buf->writeByte('Z' - t->varargs); // mark end of arg list
+ if (tret != NULL)
+ visitWithMask(tret, 0);
+
+ t->inuse--;
+ }
+
+ void visit(TypeIdentifier *t)
+ {
+ visit((Type *)t);
+ const char *name = t->ident->toChars();
+ size_t len = strlen(name);
+ buf->printf("%u%s", (unsigned)len, name);
+ }
+
+ void visit(TypeEnum *t)
+ {
+ visit((Type *)t);
+ t->sym->accept(this);
+ }
+
+ void visit(TypeStruct *t)
+ {
+ //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name);
+ visit((Type *)t);
+ t->sym->accept(this);
+ }
+
+ void visit(TypeClass *t)
+ {
+ //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name);
+ visit((Type *)t);
+ t->sym->accept(this);
+ }
+
+ void visit(TypeTuple *t)
+ {
+ //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars());
+ visit((Type *)t);
+
+ OutBuffer buf2;
+ buf2.reserve(32);
+ Mangler v(&buf2);
+ v.paramsToDecoBuffer(t->arguments);
+ int len = (int)buf2.offset;
+ buf->printf("%d%.*s", len, len, buf2.extractData());
+ }
+
+ void visit(TypeNull *t)
+ {
+ visit((Type *)t);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void mangleDecl(Declaration *sthis)
+ {
+ mangleParent(sthis);
+
+ assert(sthis->ident);
+ const char *id = sthis->ident->toChars();
+ toBuffer(id, sthis);
+
+ if (FuncDeclaration *fd = sthis->isFuncDeclaration())
+ {
+ mangleFunc(fd, false);
+ }
+ else if (sthis->type->deco)
+ {
+ buf->writestring(sthis->type->deco);
+ }
+ else
+ assert(0);
+ }
+
+ void mangleParent(Dsymbol *s)
+ {
+ Dsymbol *p;
+ if (TemplateInstance *ti = s->isTemplateInstance())
+ p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent;
+ else
+ p = s->parent;
+
+ if (p)
+ {
+ mangleParent(p);
+
+ if (p->getIdent())
+ {
+ const char *id = p->ident->toChars();
+ toBuffer(id, s);
+
+ if (FuncDeclaration *f = p->isFuncDeclaration())
+ mangleFunc(f, true);
+ }
+ else
+ buf->writeByte('0');
+ }
+ }
+
+ void mangleFunc(FuncDeclaration *fd, bool inParent)
+ {
+ //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null");
+ //printf("fd->type = %s\n", fd->type->toChars());
+ if (fd->needThis() || fd->isNested())
+ buf->writeByte('M');
+ if (inParent)
+ {
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ TypeFunction *tfo = (TypeFunction *)fd->originalType;
+ mangleFuncType(tf, tfo, 0, NULL);
+ }
+ else if (fd->type->deco)
+ {
+ buf->writestring(fd->type->deco);
+ }
+ else
+ {
+ printf("[%s] %s %s\n", fd->loc.toChars(), fd->toChars(), fd->type->toChars());
+ assert(0); // don't mangle function until semantic3 done.
+ }
+ }
+
+ /************************************************************
+ * Write length prefixed string to buf.
+ */
+ void toBuffer(const char *id, Dsymbol *s)
+ {
+ size_t len = strlen(id);
+ if (len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
+ s->error("excessive length %llu for symbol, possible recursive expansion?", len);
+ else
+ {
+ buf->printf("%llu", (ulonglong)len);
+ buf->write(id, len);
+ }
+ }
+
+ void visit(Declaration *d)
+ {
+ //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
+ // d, d->toChars(), d->parent ? d->parent->toChars() : "null", d->linkage);
+ if (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // if at global scope
+ {
+ switch (d->linkage)
+ {
+ case LINKd:
+ break;
+
+ case LINKc:
+ case LINKwindows:
+ case LINKpascal:
+ case LINKobjc:
+ buf->writestring(d->ident->toChars());
+ return;
+
+ case LINKcpp:
+ buf->writestring(Target::toCppMangle(d));
+ return;
+
+ case LINKdefault:
+ d->error("forward declaration");
+ buf->writestring(d->ident->toChars());
+ return;
+
+ default:
+ fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage);
+ assert(0);
+ return;
+ }
+ }
+
+ buf->writestring("_D");
+ mangleDecl(d);
+ }
+
+ /******************************************************************************
+ * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
+ * If and only if there is no overloads, mangle() could return
+ * exact mangled name.
+ *
+ * module test;
+ * void foo(long) {} // _D4test3fooFlZv
+ * void foo(string) {} // _D4test3fooFAyaZv
+ *
+ * // from FuncDeclaration::mangle().
+ * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
+ * // by calling Dsymbol::mangle()
+ *
+ * // from FuncAliasDeclaration::mangle()
+ * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
+ * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
+ *
+ * If a function has no overloads, .mangleof property still returns exact mangled name.
+ *
+ * void bar() {}
+ * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
+ * // by calling FuncDeclaration::mangleExact().
+ */
+ void visit(FuncDeclaration *fd)
+ {
+ if (fd->isUnique())
+ mangleExact(fd);
+ else
+ visit((Dsymbol *)fd);
+ }
+
+ // ditto
+ void visit(FuncAliasDeclaration *fd)
+ {
+ FuncDeclaration *f = fd->toAliasFunc();
+ FuncAliasDeclaration *fa = f->isFuncAliasDeclaration();
+ if (!fd->hasOverloads && !fa)
+ {
+ mangleExact(f);
+ return;
+ }
+ if (fa)
+ {
+ fa->accept(this);
+ return;
+ }
+ visit((Dsymbol *)fd);
+ }
+
+ void visit(OverDeclaration *od)
+ {
+ if (od->overnext)
+ {
+ visit((Dsymbol *)od);
+ return;
+ }
+
+ if (FuncDeclaration *fd = od->aliassym->isFuncDeclaration())
+ {
+ if (!od->hasOverloads || fd->isUnique())
+ {
+ mangleExact(fd);
+ return;
+ }
+ }
+ if (TemplateDeclaration *td = od->aliassym->isTemplateDeclaration())
+ {
+ if (!od->hasOverloads || td->overnext == NULL)
+ {
+ td->accept(this);
+ return;
+ }
+ }
+ visit((Dsymbol *)od);
+ }
+
+ void mangleExact(FuncDeclaration *fd)
+ {
+ assert(!fd->isFuncAliasDeclaration());
+
+ if (fd->mangleOverride)
+ {
+ buf->writestring(fd->mangleOverride);
+ return;
+ }
+
+ if (fd->isMain())
+ {
+ buf->writestring("_Dmain");
+ return;
+ }
+
+ if (fd->isWinMain() || fd->isDllMain() || fd->ident == Id::tls_get_addr)
+ {
+ buf->writestring(fd->ident->toChars());
+ return;
+ }
+
+ visit((Declaration *)fd);
+ }
+
+ void visit(VarDeclaration *vd)
+ {
+ if (vd->mangleOverride)
+ {
+ buf->writestring(vd->mangleOverride);
+ return;
+ }
+
+ visit((Declaration *)vd);
+ }
+
+ void visit(AggregateDeclaration *ad)
+ {
+ ClassDeclaration *cd = ad->isClassDeclaration();
+ Dsymbol *parentsave = ad->parent;
+ if (cd)
+ {
+ /* These are reserved to the compiler, so keep simple
+ * names for them.
+ */
+ if ((cd->ident == Id::Exception && cd->parent->ident == Id::object) ||
+ cd->ident == Id::TypeInfo ||
+ cd->ident == Id::TypeInfo_Struct ||
+ cd->ident == Id::TypeInfo_Class ||
+ cd->ident == Id::TypeInfo_Tuple ||
+ cd == ClassDeclaration::object ||
+ cd == Type::typeinfoclass ||
+ cd == Module::moduleinfo ||
+ strncmp(cd->ident->toChars(), "TypeInfo_", 9) == 0)
+ {
+ // Don't mangle parent
+ ad->parent = NULL;
+ }
+ }
+
+ visit((Dsymbol *)ad);
+
+ ad->parent = parentsave;
+ }
+
+ void visit(TemplateInstance *ti)
+ {
+ if (!ti->tempdecl)
+ ti->error("is not defined");
+ else
+ mangleParent(ti);
+
+ ti->getIdent();
+ const char *id = ti->ident ? ti->ident->toChars() : ti->toChars();
+ toBuffer(id, ti);
+
+ //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id);
+ }
+
+ void visit(Dsymbol *s)
+ {
+ mangleParent(s);
+
+ const char *id = s->ident ? s->ident->toChars() : s->toChars();
+ toBuffer(id, s);
+
+ //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void visit(Expression *e)
+ {
+ e->error("expression %s is not a valid template value argument", e->toChars());
+ }
+
+ void visit(IntegerExp *e)
+ {
+ if ((sinteger_t)e->value < 0)
+ buf->printf("N%lld", -e->value);
+ else
+ buf->printf("i%lld", e->value);
+ }
+
+ void visit(RealExp *e)
+ {
+ buf->writeByte('e');
+ realToMangleBuffer(e->value);
+ }
+
+ void realToMangleBuffer(real_t value)
+ {
+ /* Rely on %A to get portable mangling.
+ * Must munge result to get only identifier characters.
+ *
+ * Possible values from %A => mangled result
+ * NAN => NAN
+ * -INF => NINF
+ * INF => INF
+ * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
+ * 0X1.9P+2 => 19P2
+ */
+
+ if (CTFloat::isNaN(value))
+ buf->writestring("NAN"); // no -NAN bugs
+ else if (CTFloat::isInfinity(value))
+ buf->writestring(value < CTFloat::zero ? "NINF" : "INF");
+ else
+ {
+ const size_t BUFFER_LEN = 36;
+ char buffer[BUFFER_LEN];
+ size_t n = CTFloat::sprint(buffer, 'A', value);
+ assert(n < BUFFER_LEN);
+ for (size_t i = 0; i < n; i++)
+ {
+ char c = buffer[i];
+ switch (c)
+ {
+ case '-':
+ buf->writeByte('N');
+ break;
+
+ case '+':
+ case 'X':
+ case '.':
+ break;
+
+ case '0':
+ if (i < 2)
+ break; // skip leading 0X
+ /* fall through */
+ default:
+ buf->writeByte(c);
+ break;
+ }
+ }
+ }
+ }
+
+ void visit(ComplexExp *e)
+ {
+ buf->writeByte('c');
+ realToMangleBuffer(e->toReal());
+ buf->writeByte('c'); // separate the two
+ realToMangleBuffer(e->toImaginary());
+ }
+
+ void visit(NullExp *)
+ {
+ buf->writeByte('n');
+ }
+
+ void visit(StringExp *e)
+ {
+ char m;
+ OutBuffer tmp;
+ utf8_t *q;
+ size_t qlen;
+
+ /* Write string in UTF-8 format
+ */
+ switch (e->sz)
+ {
+ case 1:
+ m = 'a';
+ q = (utf8_t *)e->string;
+ qlen = e->len;
+ break;
+
+ case 2:
+ m = 'w';
+ for (size_t u = 0; u < e->len; )
+ {
+ unsigned c;
+ const char *p = utf_decodeWchar((unsigned short *)e->string, e->len, &u, &c);
+ if (p)
+ e->error("%s", p);
+ else
+ tmp.writeUTF8(c);
+ }
+ q = (utf8_t *)tmp.data;
+ qlen = tmp.offset;
+ break;
+
+ case 4:
+ m = 'd';
+ for (size_t u = 0; u < e->len; u++)
+ {
+ unsigned c = ((unsigned *)e->string)[u];
+ if (!utf_isValidDchar(c))
+ e->error("invalid UCS-32 char \\U%08x", c);
+ else
+ tmp.writeUTF8(c);
+ }
+ q = (utf8_t *)tmp.data;
+ qlen = tmp.offset;
+ break;
+
+ default:
+ assert(0);
+ }
+ buf->reserve(1 + 11 + 2 * qlen);
+ buf->writeByte(m);
+ buf->printf("%d_", (int)qlen); // nbytes <= 11
+
+ for (utf8_t *p = (utf8_t *)buf->data + buf->offset, *pend = p + 2 * qlen;
+ p < pend; p += 2, ++q)
+ {
+ utf8_t hi = *q >> 4 & 0xF;
+ p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a');
+ utf8_t lo = *q & 0xF;
+ p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a');
+ }
+ buf->offset += 2 * qlen;
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ size_t dim = e->elements ? e->elements->dim : 0;
+ buf->printf("A%u", dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ e->getElement(i)->accept(this);
+ }
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ size_t dim = e->keys->dim;
+ buf->printf("A%u", dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ (*e->keys)[i]->accept(this);
+ (*e->values)[i]->accept(this);
+ }
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ size_t dim = e->elements ? e->elements->dim : 0;
+ buf->printf("S%u", dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression *ex = (*e->elements)[i];
+ if (ex)
+ ex->accept(this);
+ else
+ buf->writeByte('v'); // 'v' for void
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void paramsToDecoBuffer(Parameters *parameters)
+ {
+ //printf("Parameter::paramsToDecoBuffer()\n");
+ Parameter_foreach(parameters, &paramsToDecoBufferDg, (void *)this);
+ }
+
+ static int paramsToDecoBufferDg(void *ctx, size_t, Parameter *p)
+ {
+ p->accept((Visitor *)ctx);
+ return 0;
+ }
+
+ void visit(Parameter *p)
+ {
+ if (p->storageClass & STCscope && !(p->storageClass & STCscopeinferred))
+ buf->writeByte('M');
+ // 'return inout ref' is the same as 'inout ref'
+ if ((p->storageClass & (STCreturn | STCwild)) == STCreturn)
+ buf->writestring("Nk");
+ switch (p->storageClass & (STCin | STCout | STCref | STClazy))
+ {
+ case 0:
+ case STCin:
+ break;
+ case STCout:
+ buf->writeByte('J');
+ break;
+ case STCref:
+ buf->writeByte('K');
+ break;
+ case STClazy:
+ buf->writeByte('L');
+ break;
+ default:
+ assert(0);
+ }
+ visitWithMask(p->type, 0);
+ }
+};
+
+/******************************************************************************
+ * Returns exact mangled name of function.
+ */
+const char *mangleExact(FuncDeclaration *fd)
+{
+ if (!fd->mangleString)
+ {
+ OutBuffer buf;
+ Mangler v(&buf);
+ v.mangleExact(fd);
+ fd->mangleString = buf.extractString();
+ }
+ return fd->mangleString;
+}
+
+void mangleToBuffer(Type *t, OutBuffer *buf)
+{
+ Mangler v(buf);
+ v.visitWithMask(t, 0);
+}
+
+void mangleToBuffer(Expression *e, OutBuffer *buf)
+{
+ Mangler v(buf);
+ e->accept(&v);
+}
+
+void mangleToBuffer(Dsymbol *s, OutBuffer *buf)
+{
+ Mangler v(buf);
+ s->accept(&v);
+}
diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c
new file mode 100644
index 0000000..a374aac
--- /dev/null
+++ b/gcc/d/dmd/dmodule.c
@@ -0,0 +1,1436 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/module.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "module.h"
+#include "parse.h"
+#include "scope.h"
+#include "identifier.h"
+#include "id.h"
+#include "import.h"
+#include "dsymbol.h"
+#include "expression.h"
+#include "lexer.h"
+#include "attrib.h"
+
+// For getcwd()
+#if _WIN32
+#include <direct.h>
+#endif
+#if POSIX
+#include <unistd.h>
+#endif
+
+AggregateDeclaration *Module::moduleinfo;
+
+Module *Module::rootModule;
+DsymbolTable *Module::modules;
+Modules Module::amodules;
+
+Dsymbols Module::deferred; // deferred Dsymbol's needing semantic() run on them
+Dsymbols Module::deferred2; // deferred Dsymbol's needing semantic2() run on them
+Dsymbols Module::deferred3; // deferred Dsymbol's needing semantic3() run on them
+unsigned Module::dprogress;
+
+const char *lookForSourceFile(const char **path, const char *filename);
+
+void Module::_init()
+{
+ modules = new DsymbolTable();
+}
+
+Module::Module(const char *filename, Identifier *ident, int doDocComment, int doHdrGen)
+ : Package(ident)
+{
+ const char *srcfilename;
+
+// printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
+ this->arg = filename;
+ md = NULL;
+ errors = 0;
+ numlines = 0;
+ members = NULL;
+ isDocFile = 0;
+ isPackageFile = false;
+ needmoduleinfo = 0;
+ selfimports = 0;
+ rootimports = 0;
+ insearch = 0;
+ searchCacheIdent = NULL;
+ searchCacheSymbol = NULL;
+ searchCacheFlags = 0;
+ decldefs = NULL;
+ sictor = NULL;
+ sctor = NULL;
+ sdtor = NULL;
+ ssharedctor = NULL;
+ sshareddtor = NULL;
+ stest = NULL;
+ sfilename = NULL;
+ importedFrom = NULL;
+ srcfile = NULL;
+ srcfilePath = NULL;
+ docfile = NULL;
+
+ debuglevel = 0;
+ debugids = NULL;
+ debugidsNot = NULL;
+ versionlevel = 0;
+ versionids = NULL;
+ versionidsNot = NULL;
+
+ macrotable = NULL;
+ escapetable = NULL;
+ doppelganger = 0;
+ cov = NULL;
+ covb = NULL;
+
+ nameoffset = 0;
+ namelen = 0;
+
+ srcfilename = FileName::defaultExt(filename, global.mars_ext);
+
+ if (global.run_noext && global.params.run &&
+ !FileName::ext(filename) &&
+ FileName::exists(srcfilename) == 0 &&
+ FileName::exists(filename) == 1)
+ {
+ FileName::free(srcfilename);
+ srcfilename = FileName::removeExt(filename); // just does a mem.strdup(filename)
+ }
+ else if (!FileName::equalsExt(srcfilename, global.mars_ext) &&
+ !FileName::equalsExt(srcfilename, global.hdr_ext) &&
+ !FileName::equalsExt(srcfilename, "dd"))
+ {
+ error("source file name '%s' must have .%s extension", srcfilename, global.mars_ext);
+ fatal();
+ }
+ srcfile = new File(srcfilename);
+ if (!FileName::absolute(srcfilename))
+ srcfilePath = getcwd(NULL, 0);
+
+ objfile = setOutfile(global.params.objname, global.params.objdir, filename, global.obj_ext);
+
+ if (doDocComment)
+ setDocfile();
+
+ if (doHdrGen)
+ hdrfile = setOutfile(global.params.hdrname, global.params.hdrdir, arg, global.hdr_ext);
+
+ //objfile = new File(objfilename);
+}
+
+Module *Module::create(const char *filename, Identifier *ident, int doDocComment, int doHdrGen)
+{
+ return new Module(filename, ident, doDocComment, doHdrGen);
+}
+
+void Module::setDocfile()
+{
+ docfile = setOutfile(global.params.docname, global.params.docdir, arg, global.doc_ext);
+}
+
+/*********************************************
+ * Combines things into output file name for .html and .di files.
+ * Input:
+ * name Command line name given for the file, NULL if none
+ * dir Command line directory given for the file, NULL if none
+ * arg Name of the source file
+ * ext File name extension to use if 'name' is NULL
+ * global.params.preservePaths get output path from arg
+ * srcfile Input file - output file name must not match input file
+ */
+
+File *Module::setOutfile(const char *name, const char *dir, const char *arg, const char *ext)
+{
+ const char *docfilename;
+
+ if (name)
+ {
+ docfilename = name;
+ }
+ else
+ {
+ const char *argdoc;
+ if (global.params.preservePaths)
+ argdoc = arg;
+ else
+ argdoc = FileName::name(arg);
+
+ // If argdoc doesn't have an absolute path, make it relative to dir
+ if (!FileName::absolute(argdoc))
+ { //FileName::ensurePathExists(dir);
+ argdoc = FileName::combine(dir, argdoc);
+ }
+ docfilename = FileName::forceExt(argdoc, ext);
+ }
+
+ if (FileName::equals(docfilename, srcfile->name->str))
+ {
+ error("source file and output file have same name '%s'", srcfile->name->str);
+ fatal();
+ }
+
+ return new File(docfilename);
+}
+
+void Module::deleteObjFile()
+{
+ if (global.params.obj)
+ objfile->remove();
+ if (docfile)
+ docfile->remove();
+}
+
+const char *Module::kind()
+{
+ return "module";
+}
+
+static void checkModFileAlias(OutBuffer *buf, OutBuffer *dotmods,
+ Array<const char *> *ms, size_t msdim, const char *p)
+{
+ /* Check and replace the contents of buf[] with
+ * an alias string from global.params.modFileAliasStrings[]
+ */
+ dotmods->writestring(p);
+ for (size_t j = msdim; j--;)
+ {
+ const char *m = (*ms)[j];
+ const char *q = strchr(m, '=');
+ assert(q);
+ if (dotmods->offset <= (size_t)(q - m) && memcmp(dotmods->peekString(), m, q - m) == 0)
+ {
+ buf->reset();
+ size_t qlen = strlen(q + 1);
+ if (qlen && (q[qlen] == '/' || q[qlen] == '\\'))
+ --qlen; // remove trailing separator
+ buf->write(q + 1, qlen);
+ break; // last matching entry in ms[] wins
+ }
+ }
+ dotmods->writeByte('.');
+}
+
+Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident)
+{
+ //printf("Module::load(ident = '%s')\n", ident->toChars());
+
+ // Build module filename by turning:
+ // foo.bar.baz
+ // into:
+ // foo\bar\baz
+ const char *filename = ident->toChars();
+ if (packages && packages->dim)
+ {
+ OutBuffer buf;
+ OutBuffer dotmods;
+ Array<const char *> *ms = global.params.modFileAliasStrings;
+ const size_t msdim = ms ? ms->dim : 0;
+
+ for (size_t i = 0; i < packages->dim; i++)
+ {
+ Identifier *pid = (*packages)[i];
+ const char *p = pid->toChars();
+ buf.writestring(p);
+ if (msdim)
+ checkModFileAlias(&buf, &dotmods, ms, msdim, p);
+#if _WIN32
+ buf.writeByte('\\');
+#else
+ buf.writeByte('/');
+#endif
+ }
+ buf.writestring(filename);
+ if (msdim)
+ checkModFileAlias(&buf, &dotmods, ms, msdim, filename);
+ buf.writeByte(0);
+ filename = (char *)buf.extractData();
+ }
+
+ Module *m = new Module(filename, ident, 0, 0);
+ m->loc = loc;
+
+ /* Look for the source file
+ */
+ const char *path;
+ const char *result = lookForSourceFile(&path, filename);
+ if (result)
+ {
+ m->srcfile = new File(result);
+ if (path)
+ m->srcfilePath = path;
+ else if (!FileName::absolute(result))
+ m->srcfilePath = getcwd(NULL, 0);
+ }
+
+ if (!m->read(loc))
+ return NULL;
+
+ if (global.params.verbose)
+ {
+ OutBuffer buf;
+ if (packages)
+ {
+ for (size_t i = 0; i < packages->dim; i++)
+ {
+ Identifier *pid = (*packages)[i];
+ buf.writestring(pid->toChars());
+ buf.writeByte('.');
+ }
+ }
+ buf.printf("%s\t(%s)", ident->toChars(), m->srcfile->toChars());
+ message("import %s", buf.peekString());
+ }
+
+ m = m->parse();
+
+ Compiler::loadModule(m);
+
+ return m;
+}
+
+bool Module::read(Loc loc)
+{
+ //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars());
+ if (srcfile->read())
+ {
+ if (!strcmp(srcfile->toChars(), "object.d"))
+ {
+ ::error(loc, "cannot find source code for runtime library file 'object.d'");
+ errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
+ errorSupplemental(loc, "config file: %s", FileName::canonicalName(global.inifilename));
+ }
+ else
+ {
+ // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
+ bool isPackageMod = (strcmp(toChars(), "package") != 0) &&
+ (strcmp(srcfile->name->name(), "package.d") == 0 || (strcmp(srcfile->name->name(), "package.di") == 0));
+
+ if (isPackageMod)
+ ::error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'",
+ toChars(), srcfile->toChars());
+ else
+ error(loc, "is in file '%s' which cannot be read", srcfile->toChars());
+ }
+
+ if (!global.gag)
+ {
+ /* Print path
+ */
+ if (global.path)
+ {
+ for (size_t i = 0; i < global.path->dim; i++)
+ {
+ const char *p = (*global.path)[i];
+ fprintf(stderr, "import path[%llu] = %s\n", (ulonglong)i, p);
+ }
+ }
+ else
+ fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile->toChars());
+ fatal();
+ }
+ return false;
+ }
+ return true;
+}
+
+Module *Module::parse()
+{
+ //printf("Module::parse(srcfile='%s') this=%p\n", srcfile->name->toChars(), this);
+
+ const char *srcname = srcfile->name->toChars();
+ //printf("Module::parse(srcname = '%s')\n", srcname);
+
+ isPackageFile = (strcmp(srcfile->name->name(), "package.d") == 0 ||
+ strcmp(srcfile->name->name(), "package.di") == 0);
+
+ utf8_t *buf = (utf8_t *)srcfile->buffer;
+ size_t buflen = srcfile->len;
+
+ if (buflen >= 2)
+ {
+ /* Convert all non-UTF-8 formats to UTF-8.
+ * BOM : http://www.unicode.org/faq/utf_bom.html
+ * 00 00 FE FF UTF-32BE, big-endian
+ * FF FE 00 00 UTF-32LE, little-endian
+ * FE FF UTF-16BE, big-endian
+ * FF FE UTF-16LE, little-endian
+ * EF BB BF UTF-8
+ */
+
+ unsigned le;
+ unsigned bom = 1; // assume there's a BOM
+ if (buf[0] == 0xFF && buf[1] == 0xFE)
+ {
+ if (buflen >= 4 && buf[2] == 0 && buf[3] == 0)
+ { // UTF-32LE
+ le = 1;
+
+ Lutf32:
+ OutBuffer dbuf;
+ unsigned *pu = (unsigned *)(buf);
+ unsigned *pumax = &pu[buflen / 4];
+
+ if (buflen & 3)
+ { error("odd length of UTF-32 char source %u", buflen);
+ fatal();
+ }
+
+ dbuf.reserve(buflen / 4);
+ for (pu += bom; pu < pumax; pu++)
+ { unsigned u;
+
+ u = le ? Port::readlongLE(pu) : Port::readlongBE(pu);
+ if (u & ~0x7F)
+ {
+ if (u > 0x10FFFF)
+ { error("UTF-32 value %08x greater than 0x10FFFF", u);
+ fatal();
+ }
+ dbuf.writeUTF8(u);
+ }
+ else
+ dbuf.writeByte(u);
+ }
+ dbuf.writeByte(0); // add 0 as sentinel for scanner
+ buflen = dbuf.offset - 1; // don't include sentinel in count
+ buf = (utf8_t *) dbuf.extractData();
+ }
+ else
+ { // UTF-16LE (X86)
+ // Convert it to UTF-8
+ le = 1;
+
+ Lutf16:
+ OutBuffer dbuf;
+ unsigned short *pu = (unsigned short *)(buf);
+ unsigned short *pumax = &pu[buflen / 2];
+
+ if (buflen & 1)
+ { error("odd length of UTF-16 char source %u", buflen);
+ fatal();
+ }
+
+ dbuf.reserve(buflen / 2);
+ for (pu += bom; pu < pumax; pu++)
+ { unsigned u;
+
+ u = le ? Port::readwordLE(pu) : Port::readwordBE(pu);
+ if (u & ~0x7F)
+ { if (u >= 0xD800 && u <= 0xDBFF)
+ { unsigned u2;
+
+ if (++pu > pumax)
+ { error("surrogate UTF-16 high value %04x at EOF", u);
+ fatal();
+ }
+ u2 = le ? Port::readwordLE(pu) : Port::readwordBE(pu);
+ if (u2 < 0xDC00 || u2 > 0xDFFF)
+ { error("surrogate UTF-16 low value %04x out of range", u2);
+ fatal();
+ }
+ u = (u - 0xD7C0) << 10;
+ u |= (u2 - 0xDC00);
+ }
+ else if (u >= 0xDC00 && u <= 0xDFFF)
+ { error("unpaired surrogate UTF-16 value %04x", u);
+ fatal();
+ }
+ else if (u == 0xFFFE || u == 0xFFFF)
+ { error("illegal UTF-16 value %04x", u);
+ fatal();
+ }
+ dbuf.writeUTF8(u);
+ }
+ else
+ dbuf.writeByte(u);
+ }
+ dbuf.writeByte(0); // add 0 as sentinel for scanner
+ buflen = dbuf.offset - 1; // don't include sentinel in count
+ buf = (utf8_t *) dbuf.extractData();
+ }
+ }
+ else if (buf[0] == 0xFE && buf[1] == 0xFF)
+ { // UTF-16BE
+ le = 0;
+ goto Lutf16;
+ }
+ else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
+ { // UTF-32BE
+ le = 0;
+ goto Lutf32;
+ }
+ else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
+ { // UTF-8
+
+ buf += 3;
+ buflen -= 3;
+ }
+ else
+ {
+ /* There is no BOM. Make use of Arcane Jill's insight that
+ * the first char of D source must be ASCII to
+ * figure out the encoding.
+ */
+
+ bom = 0;
+ if (buflen >= 4)
+ { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
+ { // UTF-32LE
+ le = 1;
+ goto Lutf32;
+ }
+ else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
+ { // UTF-32BE
+ le = 0;
+ goto Lutf32;
+ }
+ }
+ if (buflen >= 2)
+ {
+ if (buf[1] == 0)
+ { // UTF-16LE
+ le = 1;
+ goto Lutf16;
+ }
+ else if (buf[0] == 0)
+ { // UTF-16BE
+ le = 0;
+ goto Lutf16;
+ }
+ }
+
+ // It's UTF-8
+ if (buf[0] >= 0x80)
+ { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
+ fatal();
+ }
+ }
+ }
+
+ /* If it starts with the string "Ddoc", then it's a documentation
+ * source file.
+ */
+ if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0)
+ {
+ comment = buf + 4;
+ isDocFile = 1;
+ if (!docfile)
+ setDocfile();
+ return this;
+ }
+ {
+ Parser p(this, buf, buflen, docfile != NULL);
+ p.nextToken();
+ members = p.parseModule();
+ md = p.md;
+ numlines = p.scanloc.linnum;
+ if (p.errors)
+ ++global.errors;
+ }
+
+ if (srcfile->ref == 0)
+ ::free(srcfile->buffer);
+ srcfile->buffer = NULL;
+ srcfile->len = 0;
+
+ /* The symbol table into which the module is to be inserted.
+ */
+ DsymbolTable *dst;
+
+ if (md)
+ {
+ /* A ModuleDeclaration, md, was provided.
+ * The ModuleDeclaration sets the packages this module appears in, and
+ * the name of this module.
+ */
+ this->ident = md->id;
+ Package *ppack = NULL;
+ dst = Package::resolve(md->packages, &this->parent, &ppack);
+ assert(dst);
+
+ Module *m = ppack ? ppack->isModule() : NULL;
+ if (m && (strcmp(m->srcfile->name->name(), "package.d") != 0 &&
+ strcmp(m->srcfile->name->name(), "package.di") != 0))
+ {
+ ::error(md->loc, "package name '%s' conflicts with usage as a module name in file %s",
+ ppack->toPrettyChars(), m->srcfile->toChars());
+ }
+ }
+ else
+ {
+ /* The name of the module is set to the source file name.
+ * There are no packages.
+ */
+ dst = modules; // and so this module goes into global module symbol table
+
+ /* Check to see if module name is a valid identifier
+ */
+ if (!Identifier::isValidIdentifier(this->ident->toChars()))
+ error("has non-identifier characters in filename, use module declaration instead");
+ }
+
+ // Add internal used functions in 'object' module members.
+ if (!parent && ident == Id::object)
+ {
+ static const utf8_t code_ArrayEq[] =
+ "bool _ArrayEq(T1, T2)(T1[] a, T2[] b) {\n"
+ " if (a.length != b.length) return false;\n"
+ " foreach (size_t i; 0 .. a.length) { if (a[i] != b[i]) return false; }\n"
+ " return true; }\n";
+
+ static const utf8_t code_ArrayPostblit[] =
+ "void _ArrayPostblit(T)(T[] a) { foreach (ref T e; a) e.__xpostblit(); }\n";
+
+ static const utf8_t code_ArrayDtor[] =
+ "void _ArrayDtor(T)(T[] a) { foreach_reverse (ref T e; a) e.__xdtor(); }\n";
+
+ static const utf8_t code_xopEquals[] =
+ "bool _xopEquals(in void*, in void*) { throw new Error(\"TypeInfo.equals is not implemented\"); }\n";
+
+ static const utf8_t code_xopCmp[] =
+ "bool _xopCmp(in void*, in void*) { throw new Error(\"TypeInfo.compare is not implemented\"); }\n";
+
+ Identifier *arreq = Id::_ArrayEq;
+ Identifier *xopeq = Identifier::idPool("_xopEquals");
+ Identifier *xopcmp = Identifier::idPool("_xopCmp");
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *sx = (*members)[i];
+ if (!sx) continue;
+ if (arreq && sx->ident == arreq) arreq = NULL;
+ if (xopeq && sx->ident == xopeq) xopeq = NULL;
+ if (xopcmp && sx->ident == xopcmp) xopcmp = NULL;
+ }
+
+ if (arreq)
+ {
+ Parser p(loc, this, code_ArrayEq, strlen((const char *)code_ArrayEq), 0);
+ p.nextToken();
+ members->append(p.parseDeclDefs(0));
+ }
+ {
+ Parser p(loc, this, code_ArrayPostblit, strlen((const char *)code_ArrayPostblit), 0);
+ p.nextToken();
+ members->append(p.parseDeclDefs(0));
+ }
+ {
+ Parser p(loc, this, code_ArrayDtor, strlen((const char *)code_ArrayDtor), 0);
+ p.nextToken();
+ members->append(p.parseDeclDefs(0));
+ }
+ if (xopeq)
+ {
+ Parser p(loc, this, code_xopEquals, strlen((const char *)code_xopEquals), 0);
+ p.nextToken();
+ members->append(p.parseDeclDefs(0));
+ }
+ if (xopcmp)
+ {
+ Parser p(loc, this, code_xopCmp, strlen((const char *)code_xopCmp), 0);
+ p.nextToken();
+ members->append(p.parseDeclDefs(0));
+ }
+ }
+
+ // Insert module into the symbol table
+ Dsymbol *s = this;
+ if (isPackageFile)
+ {
+ /* If the source tree is as follows:
+ * pkg/
+ * +- package.d
+ * +- common.d
+ * the 'pkg' will be incorporated to the internal package tree in two ways:
+ * import pkg;
+ * and:
+ * import pkg.common;
+ *
+ * If both are used in one compilation, 'pkg' as a module (== pkg/package.d)
+ * and a package name 'pkg' will conflict each other.
+ *
+ * To avoid the conflict:
+ * 1. If preceding package name insertion had occurred by Package::resolve,
+ * later package.d loading will change Package::isPkgMod to PKGmodule and set Package::mod.
+ * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
+ */
+ Package *p = new Package(ident);
+ p->parent = this->parent;
+ p->isPkgMod = PKGmodule;
+ p->mod = this;
+ p->tag = this->tag; // reuse the same package tag
+ p->symtab = new DsymbolTable();
+ s = p;
+ }
+ if (!dst->insert(s))
+ {
+ /* It conflicts with a name that is already in the symbol table.
+ * Figure out what went wrong, and issue error message.
+ */
+ Dsymbol *prev = dst->lookup(ident);
+ assert(prev);
+ if (Module *mprev = prev->isModule())
+ {
+ if (FileName::compare(srcname, mprev->srcfile->toChars()) != 0)
+ error(loc, "from file %s conflicts with another module %s from file %s",
+ srcname, mprev->toChars(), mprev->srcfile->toChars());
+ else if (isRoot() && mprev->isRoot())
+ error(loc, "from file %s is specified twice on the command line",
+ srcname);
+ else
+ error(loc, "from file %s must be imported with 'import %s;'",
+ srcname, toPrettyChars());
+
+ // Bugzilla 14446: Return previously parsed module to avoid AST duplication ICE.
+ return mprev;
+ }
+ else if (Package *pkg = prev->isPackage())
+ {
+ if (pkg->isPkgMod == PKGunknown && isPackageFile)
+ {
+ /* If the previous inserted Package is not yet determined as package.d,
+ * link it to the actual module.
+ */
+ pkg->isPkgMod = PKGmodule;
+ pkg->mod = this;
+ pkg->tag = this->tag; // reuse the same package tag
+ }
+ else
+ error(md ? md->loc : loc, "from file %s conflicts with package name %s",
+ srcname, pkg->toChars());
+ }
+ else
+ assert(global.errors);
+ }
+ else
+ {
+ // Add to global array of all modules
+ amodules.push(this);
+ }
+ return this;
+}
+
+void Module::importAll(Scope *)
+{
+ //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+
+ if (_scope)
+ return; // already done
+
+ if (isDocFile)
+ {
+ error("is a Ddoc file, cannot import it");
+ return;
+ }
+
+ if (md && md->msg)
+ {
+ if (StringExp *se = md->msg->toStringExp())
+ md->msg = se;
+ else
+ md->msg->error("string expected, not '%s'", md->msg->toChars());
+ }
+
+ /* Note that modules get their own scope, from scratch.
+ * This is so regardless of where in the syntax a module
+ * gets imported, it is unaffected by context.
+ * Ignore prevsc.
+ */
+ Scope *sc = Scope::createGlobal(this); // create root scope
+
+ // Add import of "object", even for the "object" module.
+ // If it isn't there, some compiler rewrites, like
+ // classinst == classinst -> .object.opEquals(classinst, classinst)
+ // would fail inside object.d.
+ if (members->dim == 0 || ((*members)[0])->ident != Id::object)
+ {
+ Import *im = new Import(Loc(), NULL, Id::object, NULL, 0);
+ members->shift(im);
+ }
+
+ if (!symtab)
+ {
+ // Add all symbols into module's symbol table
+ symtab = new DsymbolTable();
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->addMember(sc, sc->scopesym);
+ }
+ }
+ // anything else should be run after addMember, so version/debug symbols are defined
+
+ /* Set scope for the symbols so that if we forward reference
+ * a symbol, it can possibly be resolved on the spot.
+ * If this works out well, it can be extended to all modules
+ * before any semantic() on any of them.
+ */
+ setScope(sc); // remember module scope for semantic
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->setScope(sc);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->importAll(sc);
+ }
+
+ sc = sc->pop();
+ sc->pop(); // 2 pops because Scope::createGlobal() created 2
+}
+
+void Module::semantic(Scope *)
+{
+ if (semanticRun != PASSinit)
+ return;
+
+ //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+ semanticRun = PASSsemantic;
+
+ // Note that modules get their own scope, from scratch.
+ // This is so regardless of where in the syntax a module
+ // gets imported, it is unaffected by context.
+ Scope *sc = _scope; // see if already got one from importAll()
+ if (!sc)
+ {
+ Scope::createGlobal(this); // create root scope
+ }
+
+ //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
+
+ // Pass 1 semantic routines: do public side of the definition
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+
+ //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars());
+ s->semantic(sc);
+ runDeferredSemantic();
+ }
+
+ if (userAttribDecl)
+ {
+ userAttribDecl->semantic(sc);
+ }
+
+ if (!_scope)
+ {
+ sc = sc->pop();
+ sc->pop(); // 2 pops because Scope::createGlobal() created 2
+ }
+ semanticRun = PASSsemanticdone;
+ //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+}
+
+void Module::semantic2(Scope*)
+{
+ //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+ if (semanticRun != PASSsemanticdone) // semantic() not completed yet - could be recursive call
+ return;
+ semanticRun = PASSsemantic2;
+
+ // Note that modules get their own scope, from scratch.
+ // This is so regardless of where in the syntax a module
+ // gets imported, it is unaffected by context.
+ Scope *sc = Scope::createGlobal(this); // create root scope
+ //printf("Module = %p\n", sc.scopesym);
+
+ // Pass 2 semantic routines: do initializers and function bodies
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic2(sc);
+ }
+
+ if (userAttribDecl)
+ {
+ userAttribDecl->semantic2(sc);
+ }
+
+ sc = sc->pop();
+ sc->pop();
+ semanticRun = PASSsemantic2done;
+ //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+}
+
+void Module::semantic3(Scope*)
+{
+ //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
+ if (semanticRun != PASSsemantic2done)
+ return;
+ semanticRun = PASSsemantic3;
+
+ // Note that modules get their own scope, from scratch.
+ // This is so regardless of where in the syntax a module
+ // gets imported, it is unaffected by context.
+ Scope *sc = Scope::createGlobal(this); // create root scope
+ //printf("Module = %p\n", sc.scopesym);
+
+ // Pass 3 semantic routines: do initializers and function bodies
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars());
+ s->semantic3(sc);
+
+ runDeferredSemantic2();
+ }
+
+ if (userAttribDecl)
+ {
+ userAttribDecl->semantic3(sc);
+ }
+
+ sc = sc->pop();
+ sc->pop();
+ semanticRun = PASSsemantic3done;
+}
+
+/**********************************
+ * Determine if we need to generate an instance of ModuleInfo
+ * for this Module.
+ */
+
+int Module::needModuleInfo()
+{
+ //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov);
+ return needmoduleinfo || global.params.cov;
+}
+
+Dsymbol *Module::search(const Loc &loc, Identifier *ident, int flags)
+{
+ /* Since modules can be circularly referenced,
+ * need to stop infinite recursive searches.
+ * This is done with the cache.
+ */
+
+ //printf("%s Module::search('%s', flags = x%x) insearch = %d\n", toChars(), ident->toChars(), flags, insearch);
+ if (insearch)
+ return NULL;
+
+ /* Qualified module searches always search their imports,
+ * even if SearchLocalsOnly
+ */
+ if (!(flags & SearchUnqualifiedModule))
+ flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
+
+ if (searchCacheIdent == ident && searchCacheFlags == flags)
+ {
+ //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
+ // toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null");
+ return searchCacheSymbol;
+ }
+
+ unsigned int errors = global.errors;
+
+ insearch = 1;
+ Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
+ insearch = 0;
+
+ if (errors == global.errors)
+ {
+ // Bugzilla 10752: We can cache the result only when it does not cause
+ // access error so the side-effect should be reproduced in later search.
+ searchCacheIdent = ident;
+ searchCacheSymbol = s;
+ searchCacheFlags = flags;
+ }
+ return s;
+}
+
+bool Module::isPackageAccessible(Package *p, Prot protection, int flags)
+{
+ if (insearch) // don't follow import cycles
+ return false;
+ if (flags & IgnorePrivateImports)
+ protection = Prot(PROTpublic); // only consider public imports
+ insearch = true;
+ bool r = ScopeDsymbol::isPackageAccessible(p, protection);
+ insearch = false;
+ return r;
+}
+
+Dsymbol *Module::symtabInsert(Dsymbol *s)
+{
+ searchCacheIdent = NULL; // symbol is inserted, so invalidate cache
+ return Package::symtabInsert(s);
+}
+
+void Module::clearCache()
+{
+ for (size_t i = 0; i < amodules.dim; i++)
+ {
+ Module *m = amodules[i];
+ m->searchCacheIdent = NULL;
+ }
+}
+
+/*******************************************
+ * Can't run semantic on s now, try again later.
+ */
+
+void Module::addDeferredSemantic(Dsymbol *s)
+{
+ // Don't add it if it is already there
+ for (size_t i = 0; i < deferred.dim; i++)
+ {
+ Dsymbol *sd = deferred[i];
+
+ if (sd == s)
+ return;
+ }
+
+ //printf("Module::addDeferredSemantic('%s')\n", s->toChars());
+ deferred.push(s);
+}
+
+void Module::addDeferredSemantic2(Dsymbol *s)
+{
+ //printf("Module::addDeferredSemantic2('%s')\n", s->toChars());
+ deferred2.push(s);
+}
+
+void Module::addDeferredSemantic3(Dsymbol *s)
+{
+ //printf("Module::addDeferredSemantic3('%s')\n", s->toChars());
+ deferred3.push(s);
+}
+
+/******************************************
+ * Run semantic() on deferred symbols.
+ */
+
+void Module::runDeferredSemantic()
+{
+ if (dprogress == 0)
+ return;
+
+ static int nested;
+ if (nested)
+ return;
+ //if (deferred.dim) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.dim);
+ nested++;
+
+ size_t len;
+ do
+ {
+ dprogress = 0;
+ len = deferred.dim;
+ if (!len)
+ break;
+
+ Dsymbol **todo;
+ Dsymbol **todoalloc = NULL;
+ Dsymbol *tmp;
+ if (len == 1)
+ {
+ todo = &tmp;
+ }
+ else
+ {
+ todo = (Dsymbol **)malloc(len * sizeof(Dsymbol *));
+ assert(todo);
+ todoalloc = todo;
+ }
+ memcpy(todo, deferred.tdata(), len * sizeof(Dsymbol *));
+ deferred.setDim(0);
+
+ for (size_t i = 0; i < len; i++)
+ {
+ Dsymbol *s = todo[i];
+
+ s->semantic(NULL);
+ //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
+ }
+ //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress);
+ if (todoalloc)
+ free(todoalloc);
+ } while (deferred.dim < len || dprogress); // while making progress
+ nested--;
+ //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim);
+}
+
+void Module::runDeferredSemantic2()
+{
+ Module::runDeferredSemantic();
+
+ Dsymbols *a = &Module::deferred2;
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ Dsymbol *s = (*a)[i];
+ //printf("[%d] %s semantic2a\n", i, s->toPrettyChars());
+ s->semantic2(NULL);
+
+ if (global.errors)
+ break;
+ }
+ a->setDim(0);
+}
+
+void Module::runDeferredSemantic3()
+{
+ Module::runDeferredSemantic2();
+
+ Dsymbols *a = &Module::deferred3;
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ Dsymbol *s = (*a)[i];
+ //printf("[%d] %s semantic3a\n", i, s->toPrettyChars());
+
+ s->semantic3(NULL);
+
+ if (global.errors)
+ break;
+ }
+ a->setDim(0);
+}
+
+/************************************
+ * Recursively look at every module this module imports,
+ * return true if it imports m.
+ * Can be used to detect circular imports.
+ */
+
+int Module::imports(Module *m)
+{
+ //printf("%s Module::imports(%s)\n", toChars(), m->toChars());
+ for (size_t i = 0; i < aimports.dim; i++)
+ {
+ Module *mi = aimports[i];
+ if (mi == m)
+ return true;
+ if (!mi->insearch)
+ {
+ mi->insearch = 1;
+ int r = mi->imports(m);
+ if (r)
+ return r;
+ }
+ }
+ return false;
+}
+
+/*************************************
+ * Return true if module imports itself.
+ */
+
+bool Module::selfImports()
+{
+ //printf("Module::selfImports() %s\n", toChars());
+ if (selfimports == 0)
+ {
+ for (size_t i = 0; i < amodules.dim; i++)
+ amodules[i]->insearch = 0;
+
+ selfimports = imports(this) + 1;
+
+ for (size_t i = 0; i < amodules.dim; i++)
+ amodules[i]->insearch = 0;
+ }
+ return selfimports == 2;
+}
+
+/*************************************
+ * Return true if module imports root module.
+ */
+
+bool Module::rootImports()
+{
+ //printf("Module::rootImports() %s\n", toChars());
+ if (rootimports == 0)
+ {
+ for (size_t i = 0; i < amodules.dim; i++)
+ amodules[i]->insearch = 0;
+
+ rootimports = 1;
+ for (size_t i = 0; i < amodules.dim; ++i)
+ {
+ Module *m = amodules[i];
+ if (m->isRoot() && imports(m))
+ {
+ rootimports = 2;
+ break;
+ }
+ }
+
+ for (size_t i = 0; i < amodules.dim; i++)
+ amodules[i]->insearch = 0;
+ }
+ return rootimports == 2;
+}
+
+bool Module::isCoreModule(Identifier *ident)
+{
+ return this->ident == ident && parent && parent->ident == Id::core && !parent->parent;
+}
+
+/* =========================== ModuleDeclaration ===================== */
+
+ModuleDeclaration::ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id)
+{
+ this->loc = loc;
+ this->packages = packages;
+ this->id = id;
+ this->isdeprecated = false;
+ this->msg = NULL;
+}
+
+const char *ModuleDeclaration::toChars()
+{
+ OutBuffer buf;
+
+ if (packages && packages->dim)
+ {
+ for (size_t i = 0; i < packages->dim; i++)
+ {
+ Identifier *pid = (*packages)[i];
+ buf.writestring(pid->toChars());
+ buf.writeByte('.');
+ }
+ }
+ buf.writestring(id->toChars());
+ return buf.extractString();
+}
+
+/* =========================== Package ===================== */
+
+Package::Package(Identifier *ident)
+ : ScopeDsymbol(ident)
+{
+ this->isPkgMod = PKGunknown;
+ this->mod = NULL;
+ static unsigned packageTag = 0;
+ this->tag = packageTag++;
+}
+
+
+const char *Package::kind()
+{
+ return "package";
+}
+
+Module *Package::isPackageMod()
+{
+ if (isPkgMod == PKGmodule)
+ {
+ return mod;
+ }
+ return NULL;
+}
+
+/**
+ * Checks if pkg is a sub-package of this
+ *
+ * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3',
+ * this function returns 'true'. If it is other way around or qualified
+ * package paths conflict function returns 'false'.
+ *
+ * Params:
+ * pkg = possible subpackage
+ *
+ * Returns:
+ * see description
+ */
+bool Package::isAncestorPackageOf(const Package * const pkg) const
+{
+ if (this == pkg)
+ return true;
+ if (!pkg || !pkg->parent)
+ return false;
+ return isAncestorPackageOf(pkg->parent->isPackage());
+}
+
+void Package::semantic(Scope *)
+{
+ if (semanticRun < PASSsemanticdone)
+ semanticRun = PASSsemanticdone;
+}
+
+/****************************************************
+ * Input:
+ * packages[] the pkg1.pkg2 of pkg1.pkg2.mod
+ * Returns:
+ * the symbol table that mod should be inserted into
+ * Output:
+ * *pparent the rightmost package, i.e. pkg2, or NULL if no packages
+ * *ppkg the leftmost package, i.e. pkg1, or NULL if no packages
+ */
+
+DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg)
+{
+ DsymbolTable *dst = Module::modules;
+ Dsymbol *parent = NULL;
+
+ //printf("Package::resolve()\n");
+ if (ppkg)
+ *ppkg = NULL;
+
+ if (packages)
+ {
+ for (size_t i = 0; i < packages->dim; i++)
+ {
+ Identifier *pid = (*packages)[i];
+ Package *pkg;
+ Dsymbol *p = dst->lookup(pid);
+ if (!p)
+ {
+ pkg = new Package(pid);
+ dst->insert(pkg);
+ pkg->parent = parent;
+ pkg->symtab = new DsymbolTable();
+ }
+ else
+ {
+ pkg = p->isPackage();
+ assert(pkg);
+ // It might already be a module, not a package, but that needs
+ // to be checked at a higher level, where a nice error message
+ // can be generated.
+ // dot net needs modules and packages with same name
+
+ // But we still need a symbol table for it
+ if (!pkg->symtab)
+ pkg->symtab = new DsymbolTable();
+ }
+ parent = pkg;
+ dst = pkg->symtab;
+ if (ppkg && !*ppkg)
+ *ppkg = pkg;
+ if (pkg->isModule())
+ {
+ // Return the module so that a nice error message can be generated
+ if (ppkg)
+ *ppkg = (Package *)p;
+ break;
+ }
+ }
+ }
+ if (pparent)
+ *pparent = parent;
+ return dst;
+}
+
+Dsymbol *Package::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("%s Package::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
+ flags &= ~SearchLocalsOnly; // searching an import is always transitive
+ if (!isModule() && mod)
+ {
+ // Prefer full package name.
+ Dsymbol *s = symtab ? symtab->lookup(ident) : NULL;
+ if (s)
+ return s;
+ //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
+ return mod->search(loc, ident, flags);
+ }
+
+ return ScopeDsymbol::search(loc, ident, flags);
+}
+
+/* =========================== ===================== */
+
+/********************************************
+ * Look for the source file if it's different from filename.
+ * Look for .di, .d, directory, and along global.path.
+ * Does not open the file.
+ * Output:
+ * path the path where the file was found if it was not the current directory
+ * Input:
+ * filename as supplied by the user
+ * global.path
+ * Returns:
+ * NULL if it's not different from filename.
+ */
+
+const char *lookForSourceFile(const char **path, const char *filename)
+{
+ /* Search along global.path for .di file, then .d file.
+ */
+ *path = NULL;
+
+ const char *sdi = FileName::forceExt(filename, global.hdr_ext);
+ if (FileName::exists(sdi) == 1)
+ return sdi;
+
+ const char *sd = FileName::forceExt(filename, global.mars_ext);
+ if (FileName::exists(sd) == 1)
+ return sd;
+
+ if (FileName::exists(filename) == 2)
+ {
+ /* The filename exists and it's a directory.
+ * Therefore, the result should be: filename/package.d
+ * iff filename/package.d is a file
+ */
+ const char *ni = FileName::combine(filename, "package.di");
+ if (FileName::exists(ni) == 1)
+ return ni;
+ FileName::free(ni);
+ const char *n = FileName::combine(filename, "package.d");
+ if (FileName::exists(n) == 1)
+ return n;
+ FileName::free(n);
+ }
+
+ if (FileName::absolute(filename))
+ return NULL;
+
+ if (!global.path)
+ return NULL;
+
+ for (size_t i = 0; i < global.path->dim; i++)
+ {
+ const char *p = (*global.path)[i];
+
+ const char *n = FileName::combine(p, sdi);
+ if (FileName::exists(n) == 1)
+ {
+ *path = p;
+ return n;
+ }
+ FileName::free(n);
+
+ n = FileName::combine(p, sd);
+ if (FileName::exists(n) == 1)
+ {
+ *path = p;
+ return n;
+ }
+ FileName::free(n);
+
+ const char *b = FileName::removeExt(filename);
+ n = FileName::combine(p, b);
+ FileName::free(b);
+ if (FileName::exists(n) == 2)
+ {
+ const char *n2i = FileName::combine(n, "package.di");
+ if (FileName::exists(n2i) == 1)
+ return n2i;
+ FileName::free(n2i);
+ const char *n2 = FileName::combine(n, "package.d");
+ if (FileName::exists(n2) == 1)
+ {
+ *path = p;
+ return n2;
+ }
+ FileName::free(n2);
+ }
+ FileName::free(n);
+ }
+ return NULL;
+}
diff --git a/gcc/d/dmd/doc.c b/gcc/d/dmd/doc.c
new file mode 100644
index 0000000..92ce33c
--- /dev/null
+++ b/gcc/d/dmd/doc.c
@@ -0,0 +1,2741 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/doc.c
+ */
+
+// This implements the Ddoc capability.
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "root/rmem.h"
+#include "root/root.h"
+#include "root/port.h"
+#include "root/aav.h"
+
+#include "attrib.h"
+#include "cond.h"
+#include "mars.h"
+#include "dsymbol.h"
+#include "macro.h"
+#include "template.h"
+#include "lexer.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "statement.h"
+#include "enum.h"
+#include "id.h"
+#include "module.h"
+#include "scope.h"
+#include "hdrgen.h"
+#include "doc.h"
+#include "mtype.h"
+#include "utf.h"
+
+void emitMemberComments(ScopeDsymbol *sds, OutBuffer *buf, Scope *sc);
+void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc);
+void emitComment(Dsymbol *s, OutBuffer *buf, Scope *sc);
+
+struct Escape
+{
+ const char *strings[256];
+
+ const char *escapeChar(unsigned c);
+};
+
+class Section
+{
+public:
+ const utf8_t *name;
+ size_t namelen;
+
+ const utf8_t *body;
+ size_t bodylen;
+
+ int nooutput;
+
+ virtual void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+class ParamSection : public Section
+{
+public:
+ void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+class MacroSection : public Section
+{
+public:
+ void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+typedef Array<Section *> Sections;
+
+struct DocComment
+{
+ Sections sections; // Section*[]
+
+ Section *summary;
+ Section *copyright;
+ Section *macros;
+ Macro **pmacrotable;
+ Escape **pescapetable;
+
+ Dsymbols a;
+
+ DocComment() :
+ summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL)
+ { }
+
+ static DocComment *parse(Dsymbol *s, const utf8_t *comment);
+ static void parseMacros(Escape **pescapetable, Macro **pmacrotable, const utf8_t *m, size_t mlen);
+ static void parseEscapes(Escape **pescapetable, const utf8_t *textstart, size_t textlen);
+
+ void parseSections(const utf8_t *comment);
+ void writeSections(Scope *sc, Dsymbols *a, OutBuffer *buf);
+};
+
+
+int cmp(const char *stringz, const void *s, size_t slen);
+int icmp(const char *stringz, const void *s, size_t slen);
+bool isDitto(const utf8_t *comment);
+const utf8_t *skipwhitespace(const utf8_t *p);
+size_t skiptoident(OutBuffer *buf, size_t i);
+size_t skippastident(OutBuffer *buf, size_t i);
+size_t skippastURL(OutBuffer *buf, size_t i);
+void highlightText(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
+void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset);
+void highlightCode(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
+void highlightCode2(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
+void highlightCode3(Scope *sc, OutBuffer *buf, const utf8_t *p, const utf8_t *pend);
+TypeFunction *isTypeFunction(Dsymbol *s);
+Parameter *isFunctionParameter(Dsymbols *a, const utf8_t *p, size_t len);
+TemplateParameter *isTemplateParameter(Dsymbols *a, const utf8_t *p, size_t len);
+
+bool isIdStart(const utf8_t *p);
+bool isCVariadicArg(const utf8_t *p, size_t len);
+bool isIdTail(const utf8_t *p);
+bool isIndentWS(const utf8_t *p);
+int utfStride(const utf8_t *p);
+
+// Workaround for missing Parameter instance for variadic params. (it's unnecessary to instantiate one).
+bool isCVariadicParameter(Dsymbols *a, const utf8_t *p, size_t len)
+{
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ TypeFunction *tf = isTypeFunction((*a)[i]);
+ if (tf && tf->varargs == 1 && cmp("...", p, len) == 0)
+ return true;
+ }
+ return false;
+}
+
+static Dsymbol *getEponymousMember(TemplateDeclaration *td)
+{
+ if (!td->onemember)
+ return NULL;
+
+ if (AggregateDeclaration *ad = td->onemember->isAggregateDeclaration())
+ return ad;
+ if (FuncDeclaration *fd = td->onemember->isFuncDeclaration())
+ return fd;
+ if (td->onemember->isEnumMember())
+ return NULL; // Keep backward compatibility. See compilable/ddoc9.d
+ if (VarDeclaration *vd = td->onemember->isVarDeclaration())
+ return td->constraint ? NULL : vd;
+
+ return NULL;
+}
+
+static TemplateDeclaration *getEponymousParent(Dsymbol *s)
+{
+ if (!s->parent)
+ return NULL;
+ TemplateDeclaration *td = s->parent->isTemplateDeclaration();
+ return (td && getEponymousMember(td)) ? td : NULL;
+}
+
+static const char ddoc_default[] = "\
+DDOC = <html><head>\n\
+ <META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\
+ <title>$(TITLE)</title>\n\
+ </head><body>\n\
+ <h1>$(TITLE)</h1>\n\
+ $(BODY)\n\
+ <hr>$(SMALL Page generated by $(LINK2 http://dlang.org/ddoc.html, Ddoc). $(COPYRIGHT))\n\
+ </body></html>\n\
+\n\
+B = <b>$0</b>\n\
+I = <i>$0</i>\n\
+U = <u>$0</u>\n\
+P = <p>$0</p>\n\
+DL = <dl>$0</dl>\n\
+DT = <dt>$0</dt>\n\
+DD = <dd>$0</dd>\n\
+TABLE = <table>$0</table>\n\
+TR = <tr>$0</tr>\n\
+TH = <th>$0</th>\n\
+TD = <td>$0</td>\n\
+OL = <ol>$0</ol>\n\
+UL = <ul>$0</ul>\n\
+LI = <li>$0</li>\n\
+BIG = <big>$0</big>\n\
+SMALL = <small>$0</small>\n\
+BR = <br>\n\
+LINK = <a href=\"$0\">$0</a>\n\
+LINK2 = <a href=\"$1\">$+</a>\n\
+LPAREN= (\n\
+RPAREN= )\n\
+BACKTICK= `\n\
+DOLLAR= $\n\
+DEPRECATED= $0\n\
+\n\
+RED = <font color=red>$0</font>\n\
+BLUE = <font color=blue>$0</font>\n\
+GREEN = <font color=green>$0</font>\n\
+YELLOW =<font color=yellow>$0</font>\n\
+BLACK = <font color=black>$0</font>\n\
+WHITE = <font color=white>$0</font>\n\
+\n\
+D_CODE = <pre class=\"d_code\">$0</pre>\n\
+DDOC_BACKQUOTED = $(D_INLINECODE $0)\n\
+D_INLINECODE = <pre style=\"display:inline;\" class=\"d_inline_code\">$0</pre>\n\
+D_COMMENT = $(GREEN $0)\n\
+D_STRING = $(RED $0)\n\
+D_KEYWORD = $(BLUE $0)\n\
+D_PSYMBOL = $(U $0)\n\
+D_PARAM = $(I $0)\n\
+\n\
+DDOC_COMMENT = <!-- $0 -->\n\
+DDOC_DECL = $(DT $(BIG $0))\n\
+DDOC_DECL_DD = $(DD $0)\n\
+DDOC_DITTO = $(BR)$0\n\
+DDOC_SECTIONS = $0\n\
+DDOC_SUMMARY = $0$(BR)$(BR)\n\
+DDOC_DESCRIPTION = $0$(BR)$(BR)\n\
+DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\
+DDOC_SECTION_H = $(B $0)$(BR)\n\
+DDOC_SECTION = $0$(BR)$(BR)\n\
+DDOC_MEMBERS = $(DL $0)\n\
+DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\
+DDOC_ENUM_BASETYPE = $0\n\
+DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\
+DDOC_PARAM_ROW = $(TR $0)\n\
+DDOC_PARAM_ID = $(TD $0)\n\
+DDOC_PARAM_DESC = $(TD $0)\n\
+DDOC_BLANKLINE = $(BR)$(BR)\n\
+\n\
+DDOC_ANCHOR = <a name=\"$1\"></a>\n\
+DDOC_PSYMBOL = $(U $0)\n\
+DDOC_PSUPER_SYMBOL = $(U $0)\n\
+DDOC_KEYWORD = $(B $0)\n\
+DDOC_PARAM = $(I $0)\n\
+\n\
+ESCAPES = /</&lt;/\n\
+ />/&gt;/\n\
+ /&/&amp;/\n\
+";
+
+static const char ddoc_decl_s[] = "$(DDOC_DECL ";
+static const char ddoc_decl_e[] = ")\n";
+
+static const char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD ";
+static const char ddoc_decl_dd_e[] = ")\n";
+
+
+/****************************************************
+ */
+
+void gendocfile(Module *m)
+{
+ static OutBuffer mbuf;
+ static int mbuf_done;
+
+ OutBuffer buf;
+
+ //printf("Module::gendocfile()\n");
+
+ if (!mbuf_done) // if not already read the ddoc files
+ {
+ mbuf_done = 1;
+
+ // Use our internal default
+ mbuf.write(ddoc_default, strlen(ddoc_default));
+
+ // Override with DDOCFILE specified in the sc.ini file
+ char *p = getenv("DDOCFILE");
+ if (p)
+ global.params.ddocfiles->shift(p);
+
+ // Override with the ddoc macro files from the command line
+ for (size_t i = 0; i < global.params.ddocfiles->dim; i++)
+ {
+ FileName f((*global.params.ddocfiles)[i]);
+ File file(&f);
+ readFile(m->loc, &file);
+ // BUG: convert file contents to UTF-8 before use
+
+ //printf("file: '%.*s'\n", file.len, file.buffer);
+ mbuf.write(file.buffer, file.len);
+ }
+ }
+ DocComment::parseMacros(&m->escapetable, &m->macrotable, (utf8_t *)mbuf.data, mbuf.offset);
+
+ Scope *sc = Scope::createGlobal(m); // create root scope
+
+ DocComment *dc = DocComment::parse(m, m->comment);
+ dc->pmacrotable = &m->macrotable;
+ dc->pescapetable = &m->escapetable;
+ sc->lastdc = dc;
+
+ // Generate predefined macros
+
+ // Set the title to be the name of the module
+ {
+ const char *p = m->toPrettyChars();
+ Macro::define(&m->macrotable, (const utf8_t *)"TITLE", 5, (const utf8_t *)p, strlen(p));
+ }
+
+ // Set time macros
+ {
+ time_t t;
+ time(&t);
+ char *p = ctime(&t);
+ p = mem.xstrdup(p);
+ Macro::define(&m->macrotable, (const utf8_t *)"DATETIME", 8, (const utf8_t *)p, strlen(p));
+ Macro::define(&m->macrotable, (const utf8_t *)"YEAR", 4, (const utf8_t *)p + 20, 4);
+ }
+
+ const char *srcfilename = m->srcfile->toChars();
+ Macro::define(&m->macrotable, (const utf8_t *)"SRCFILENAME", 11, (const utf8_t *)srcfilename, strlen(srcfilename));
+
+ const char *docfilename = m->docfile->toChars();
+ Macro::define(&m->macrotable, (const utf8_t *)"DOCFILENAME", 11, (const utf8_t *)docfilename, strlen(docfilename));
+
+ if (dc->copyright)
+ {
+ dc->copyright->nooutput = 1;
+ Macro::define(&m->macrotable, (const utf8_t *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen);
+ }
+
+ buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", m->srcfile->toChars());
+ if (m->isDocFile)
+ {
+ Loc loc = m->md ? m->md->loc : m->loc;
+ size_t commentlen = strlen((const char *)m->comment);
+ Dsymbols a;
+ // Bugzilla 9764: Don't push m in a, to prevent emphasize ddoc file name.
+ if (dc->macros)
+ {
+ commentlen = dc->macros->name - m->comment;
+ dc->macros->write(loc, dc, sc, &a, &buf);
+ }
+ buf.write(m->comment, commentlen);
+ highlightText(sc, &a, &buf, 0);
+ }
+ else
+ {
+ Dsymbols a;
+ a.push(m);
+ dc->writeSections(sc, &a, &buf);
+ emitMemberComments(m, &buf, sc);
+ }
+
+ //printf("BODY= '%.*s'\n", buf.offset, buf.data);
+ Macro::define(&m->macrotable, (const utf8_t *)"BODY", 4, (const utf8_t *)buf.data, buf.offset);
+
+ OutBuffer buf2;
+ buf2.writestring("$(DDOC)\n");
+ size_t end = buf2.offset;
+ m->macrotable->expand(&buf2, 0, &end, NULL, 0);
+
+ /* Remove all the escape sequences from buf2,
+ * and make CR-LF the newline.
+ */
+ {
+ buf.setsize(0);
+ buf.reserve(buf2.offset);
+ utf8_t *p = (utf8_t *)buf2.data;
+ for (size_t j = 0; j < buf2.offset; j++)
+ {
+ utf8_t c = p[j];
+ if (c == 0xFF && j + 1 < buf2.offset)
+ {
+ j++;
+ continue;
+ }
+ if (c == '\n')
+ buf.writeByte('\r');
+ else if (c == '\r')
+ {
+ buf.writestring("\r\n");
+ if (j + 1 < buf2.offset && p[j + 1] == '\n')
+ {
+ j++;
+ }
+ continue;
+ }
+ buf.writeByte(c);
+ }
+ }
+
+ // Transfer image to file
+ assert(m->docfile);
+ m->docfile->setbuffer(buf.data, buf.offset);
+ m->docfile->ref = 1;
+ ensurePathToNameExists(Loc(), m->docfile->toChars());
+ writeFile(m->loc, m->docfile);
+}
+
+/****************************************************
+ * Having unmatched parentheses can hose the output of Ddoc,
+ * as the macros depend on properly nested parentheses.
+ * This function replaces all ( with $(LPAREN) and ) with $(RPAREN)
+ * to preserve text literally. This also means macros in the
+ * text won't be expanded.
+ */
+void escapeDdocString(OutBuffer *buf, size_t start)
+{
+ for (size_t u = start; u < buf->offset; u++)
+ {
+ utf8_t c = buf->data[u];
+ switch(c)
+ {
+ case '$':
+ buf->remove(u, 1);
+ buf->insert(u, (const char *)"$(DOLLAR)", 9);
+ u += 8;
+ break;
+
+ case '(':
+ buf->remove(u, 1); //remove the (
+ buf->insert(u, (const char *)"$(LPAREN)", 9); //insert this instead
+ u += 8; //skip over newly inserted macro
+ break;
+
+ case ')':
+ buf->remove(u, 1); //remove the )
+ buf->insert(u, (const char *)"$(RPAREN)", 9); //insert this instead
+ u += 8; //skip over newly inserted macro
+ break;
+ }
+ }
+}
+
+/****************************************************
+ * Having unmatched parentheses can hose the output of Ddoc,
+ * as the macros depend on properly nested parentheses.
+
+ * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN).
+ */
+void escapeStrayParenthesis(Loc loc, OutBuffer *buf, size_t start)
+{
+ unsigned par_open = 0;
+
+ for (size_t u = start; u < buf->offset; u++)
+ {
+ utf8_t c = buf->data[u];
+ switch(c)
+ {
+ case '(':
+ par_open++;
+ break;
+
+ case ')':
+ if (par_open == 0)
+ {
+ //stray ')'
+ warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output."
+ " Use $(RPAREN) instead for unpaired right parentheses.");
+ buf->remove(u, 1); //remove the )
+ buf->insert(u, (const char *)"$(RPAREN)", 9); //insert this instead
+ u += 8; //skip over newly inserted macro
+ }
+ else
+ par_open--;
+ break;
+ }
+ }
+
+ if (par_open) // if any unmatched lparens
+ {
+ par_open = 0;
+ for (size_t u = buf->offset; u > start;)
+ {
+ u--;
+ utf8_t c = buf->data[u];
+ switch(c)
+ {
+ case ')':
+ par_open++;
+ break;
+
+ case '(':
+ if (par_open == 0)
+ {
+ //stray '('
+ warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output."
+ " Use $(LPAREN) instead for unpaired left parentheses.");
+ buf->remove(u, 1); //remove the (
+ buf->insert(u, (const char *)"$(LPAREN)", 9); //insert this instead
+ }
+ else
+ par_open--;
+ break;
+ }
+ }
+ }
+}
+
+// Basically, this is to skip over things like private{} blocks in a struct or
+// class definition that don't add any components to the qualified name.
+static Scope *skipNonQualScopes(Scope *sc)
+{
+ while (sc && !sc->scopesym)
+ sc = sc->enclosing;
+ return sc;
+}
+
+static bool emitAnchorName(OutBuffer *buf, Dsymbol *s, Scope *sc)
+{
+ if (!s || s->isPackage() || s->isModule())
+ return false;
+
+ // Add parent names first
+ bool dot = false;
+ if (s->parent)
+ dot = emitAnchorName(buf, s->parent, sc);
+ else if (sc)
+ dot = emitAnchorName(buf, sc->scopesym, skipNonQualScopes(sc->enclosing));
+
+ // Eponymous template members can share the parent anchor name
+ if (getEponymousParent(s))
+ return dot;
+ if (dot)
+ buf->writeByte('.');
+
+ // Use "this" not "__ctor"
+ TemplateDeclaration *td;
+ if (s->isCtorDeclaration() || ((td = s->isTemplateDeclaration()) != NULL &&
+ td->onemember && td->onemember->isCtorDeclaration()))
+ {
+ buf->writestring("this");
+ }
+ else
+ {
+ /* We just want the identifier, not overloads like TemplateDeclaration::toChars.
+ * We don't want the template parameter list and constraints. */
+ buf->writestring(s->Dsymbol::toChars());
+ }
+ return true;
+}
+
+static void emitAnchor(OutBuffer *buf, Dsymbol *s, Scope *sc)
+{
+ Identifier *ident;
+ {
+ OutBuffer anc;
+ emitAnchorName(&anc, s, skipNonQualScopes(sc));
+ ident = Identifier::idPool(anc.peekString());
+ }
+ size_t *count = (size_t*)dmd_aaGet(&sc->anchorCounts, (void *)ident);
+ TemplateDeclaration *td = getEponymousParent(s);
+ // don't write an anchor for matching consecutive ditto symbols
+ if (*count > 0 && sc->prevAnchor == ident &&
+ sc->lastdc && (isDitto(s->comment) || (td && isDitto(td->comment))))
+ return;
+
+ (*count)++;
+ // cache anchor name
+ sc->prevAnchor = ident;
+
+ buf->writestring("$(DDOC_ANCHOR ");
+ buf->writestring(ident->toChars());
+ // only append count once there's a duplicate
+ if (*count != 1)
+ buf->printf(".%u", *count);
+ buf->writeByte(')');
+}
+
+/******************************* emitComment **********************************/
+
+/** Get leading indentation from 'src' which represents lines of code. */
+static size_t getCodeIndent(const char *src)
+{
+ while (src && (*src == '\r' || *src == '\n'))
+ ++src; // skip until we find the first non-empty line
+
+ size_t codeIndent = 0;
+ while (src && (*src == ' ' || *src == '\t'))
+ {
+ codeIndent++;
+ src++;
+ }
+ return codeIndent;
+}
+
+/** Recursively expand template mixin member docs into the scope. */
+static void expandTemplateMixinComments(TemplateMixin *tm, OutBuffer *buf, Scope *sc)
+{
+ if (!tm->semanticRun) tm->semantic(sc);
+ TemplateDeclaration *td = (tm && tm->tempdecl) ?
+ tm->tempdecl->isTemplateDeclaration() : NULL;
+ if (td && td->members)
+ {
+ for (size_t i = 0; i < td->members->dim; i++)
+ {
+ Dsymbol *sm = (*td->members)[i];
+ TemplateMixin *tmc = sm->isTemplateMixin();
+ if (tmc && tmc->comment)
+ expandTemplateMixinComments(tmc, buf, sc);
+ else
+ emitComment(sm, buf, sc);
+ }
+ }
+}
+
+void emitMemberComments(ScopeDsymbol *sds, OutBuffer *buf, Scope *sc)
+{
+ if (!sds->members)
+ return;
+
+ //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars());
+
+ const char *m = "$(DDOC_MEMBERS ";
+ if (sds->isTemplateDeclaration())
+ m = "$(DDOC_TEMPLATE_MEMBERS ";
+ else if (sds->isClassDeclaration())
+ m = "$(DDOC_CLASS_MEMBERS ";
+ else if (sds->isStructDeclaration())
+ m = "$(DDOC_STRUCT_MEMBERS ";
+ else if (sds->isEnumDeclaration())
+ m = "$(DDOC_ENUM_MEMBERS ";
+ else if (sds->isModule())
+ m = "$(DDOC_MODULE_MEMBERS ";
+
+ size_t offset1 = buf->offset; // save starting offset
+ buf->writestring(m);
+ size_t offset2 = buf->offset; // to see if we write anything
+
+ sc = sc->push(sds);
+
+ for (size_t i = 0; i < sds->members->dim; i++)
+ {
+ Dsymbol *s = (*sds->members)[i];
+ //printf("\ts = '%s'\n", s->toChars());
+
+ // only expand if parent is a non-template (semantic won't work)
+ if (s->comment && s->isTemplateMixin() && s->parent && !s->parent->isTemplateDeclaration())
+ expandTemplateMixinComments((TemplateMixin *)s, buf, sc);
+
+ emitComment(s, buf, sc);
+ }
+ emitComment(NULL, buf, sc);
+
+ sc->pop();
+
+ if (buf->offset == offset2)
+ {
+ /* Didn't write out any members, so back out last write
+ */
+ buf->offset = offset1;
+ }
+ else
+ buf->writestring(")\n");
+}
+
+void emitProtection(OutBuffer *buf, Prot prot)
+{
+ if (prot.kind != PROTundefined && prot.kind != PROTpublic)
+ {
+ protectionToBuffer(buf, prot);
+ buf->writeByte(' ');
+ }
+}
+
+void emitComment(Dsymbol *s, OutBuffer *buf, Scope *sc)
+{
+ class EmitComment : public Visitor
+ {
+ public:
+ OutBuffer *buf;
+ Scope *sc;
+
+ EmitComment(OutBuffer *buf, Scope *sc)
+ : buf(buf), sc(sc)
+ {
+ }
+
+ void visit(Dsymbol *) {}
+ void visit(InvariantDeclaration *) {}
+ void visit(UnitTestDeclaration *) {}
+ void visit(PostBlitDeclaration *) {}
+ void visit(DtorDeclaration *) {}
+ void visit(StaticCtorDeclaration *) {}
+ void visit(StaticDtorDeclaration *) {}
+ void visit(TypeInfoDeclaration *) {}
+
+ void emit(Scope *sc, Dsymbol *s, const utf8_t *com)
+ {
+ if (s && sc->lastdc && isDitto(com))
+ {
+ sc->lastdc->a.push(s);
+ return;
+ }
+
+ // Put previous doc comment if exists
+ if (DocComment *dc = sc->lastdc)
+ {
+ // Put the declaration signatures as the document 'title'
+ buf->writestring(ddoc_decl_s);
+ for (size_t i = 0; i < dc->a.dim; i++)
+ {
+ Dsymbol *sx = dc->a[i];
+
+ if (i == 0)
+ {
+ size_t o = buf->offset;
+ toDocBuffer(sx, buf, sc);
+ highlightCode(sc, sx, buf, o);
+ continue;
+ }
+
+ buf->writestring("$(DDOC_DITTO ");
+ {
+ size_t o = buf->offset;
+ toDocBuffer(sx, buf, sc);
+ highlightCode(sc, sx, buf, o);
+ }
+ buf->writeByte(')');
+ }
+ buf->writestring(ddoc_decl_e);
+
+ // Put the ddoc comment as the document 'description'
+ buf->writestring(ddoc_decl_dd_s);
+ {
+ dc->writeSections(sc, &dc->a, buf);
+ if (ScopeDsymbol *sds = dc->a[0]->isScopeDsymbol())
+ emitMemberComments(sds, buf, sc);
+ }
+ buf->writestring(ddoc_decl_dd_e);
+ //printf("buf.2 = [[%.*s]]\n", buf->offset - o0, buf->data + o0);
+ }
+
+ if (s)
+ {
+ DocComment *dc = DocComment::parse(s, com);
+ dc->pmacrotable = &sc->_module->macrotable;
+ sc->lastdc = dc;
+ }
+ }
+
+ void visit(Declaration *d)
+ {
+ //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", d, d->toChars(), d->comment);
+ //printf("type = %p\n", d->type);
+ const utf8_t *com = d->comment;
+ if (TemplateDeclaration *td = getEponymousParent(d))
+ {
+ if (isDitto(td->comment))
+ com = td->comment;
+ else
+ com = Lexer::combineComments(td->comment, com);
+ }
+ else
+ {
+ if (!d->ident)
+ return;
+ if (!d->type && !d->isCtorDeclaration() && !d->isAliasDeclaration())
+ return;
+ if (d->protection.kind == PROTprivate || sc->protection.kind == PROTprivate)
+ return;
+ }
+ if (!com)
+ return;
+
+ emit(sc, d, com);
+ }
+
+ void visit(AggregateDeclaration *ad)
+ {
+ //printf("AggregateDeclaration::emitComment() '%s'\n", ad->toChars());
+ const utf8_t *com = ad->comment;
+ if (TemplateDeclaration *td = getEponymousParent(ad))
+ {
+ if (isDitto(td->comment))
+ com = td->comment;
+ else
+ com = Lexer::combineComments(td->comment, com);
+ }
+ else
+ {
+ if (ad->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+ return;
+ if (!ad->comment)
+ return;
+ }
+ if (!com)
+ return;
+
+ emit(sc, ad, com);
+ }
+
+ void visit(TemplateDeclaration *td)
+ {
+ //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", td->toChars(), td->kind());
+ if (td->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+ return;
+ if (!td->comment)
+ return;
+
+ if (Dsymbol *ss = getEponymousMember(td))
+ {
+ ss->accept(this);
+ return;
+ }
+ emit(sc, td, td->comment);
+ }
+
+ void visit(EnumDeclaration *ed)
+ {
+ if (ed->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+ return;
+ if (ed->isAnonymous() && ed->members)
+ {
+ for (size_t i = 0; i < ed->members->dim; i++)
+ {
+ Dsymbol *s = (*ed->members)[i];
+ emitComment(s, buf, sc);
+ }
+ return;
+ }
+ if (!ed->comment)
+ return;
+ if (ed->isAnonymous())
+ return;
+
+ emit(sc, ed, ed->comment);
+ }
+
+ void visit(EnumMember *em)
+ {
+ //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", em, em->toChars(), em->comment);
+ if (em->prot().kind == PROTprivate || sc->protection.kind == PROTprivate)
+ return;
+ if (!em->comment)
+ return;
+
+ emit(sc, em, em->comment);
+ }
+
+ void visit(AttribDeclaration *ad)
+ {
+ //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
+
+ /* A general problem with this, illustrated by BUGZILLA 2516,
+ * is that attributes are not transmitted through to the underlying
+ * member declarations for template bodies, because semantic analysis
+ * is not done for template declaration bodies
+ * (only template instantiations).
+ * Hence, Ddoc omits attributes from template members.
+ */
+
+ Dsymbols *d = ad->include(NULL, NULL);
+
+ if (d)
+ {
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ //printf("AttribDeclaration::emitComment %s\n", s->toChars());
+ emitComment(s, buf, sc);
+ }
+ }
+ }
+
+ void visit(ProtDeclaration *pd)
+ {
+ if (pd->decl)
+ {
+ Scope *scx = sc;
+ sc = sc->copy();
+ sc->protection = pd->protection;
+ visit((AttribDeclaration *)pd);
+ scx->lastdc = sc->lastdc;
+ sc = sc->pop();
+ }
+ }
+
+ void visit(ConditionalDeclaration *cd)
+ {
+ //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
+ if (cd->condition->inc)
+ {
+ visit((AttribDeclaration *)cd);
+ return;
+ }
+
+ /* If generating doc comment, be careful because if we're inside
+ * a template, then include(NULL, NULL) will fail.
+ */
+ Dsymbols *d = cd->decl ? cd->decl : cd->elsedecl;
+ for (size_t i = 0; i < d->dim; i++)
+ {
+ Dsymbol *s = (*d)[i];
+ emitComment(s, buf, sc);
+ }
+ }
+ };
+
+ EmitComment v(buf, sc);
+
+ if (!s)
+ v.emit(sc, NULL, NULL);
+ else
+ s->accept(&v);
+}
+
+/******************************* toDocBuffer **********************************/
+
+void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc)
+{
+ class ToDocBuffer : public Visitor
+ {
+ public:
+ OutBuffer *buf;
+ Scope *sc;
+
+ ToDocBuffer(OutBuffer *buf, Scope *sc)
+ : buf(buf), sc(sc)
+ {
+ }
+
+ void visit(Dsymbol *s)
+ {
+ //printf("Dsymbol::toDocbuffer() %s\n", s->toChars());
+ HdrGenState hgs;
+ hgs.ddoc = true;
+ ::toCBuffer(s, buf, &hgs);
+ }
+
+ void prefix(Dsymbol *s)
+ {
+ if (s->isDeprecated())
+ buf->writestring("deprecated ");
+
+ if (Declaration *d = s->isDeclaration())
+ {
+ emitProtection(buf, d->protection);
+
+ if (d->isStatic())
+ buf->writestring("static ");
+ else if (d->isFinal())
+ buf->writestring("final ");
+ else if (d->isAbstract())
+ buf->writestring("abstract ");
+
+ if (!d->isFuncDeclaration()) // functionToBufferFull handles this
+ {
+ if (d->isConst())
+ buf->writestring("const ");
+ if (d->isImmutable())
+ buf->writestring("immutable ");
+ if (d->isSynchronized())
+ buf->writestring("synchronized ");
+
+ if (d->storage_class & STCmanifest)
+ buf->writestring("enum ");
+ }
+ }
+ }
+
+ void visit(Declaration *d)
+ {
+ if (!d->ident)
+ return;
+
+ TemplateDeclaration *td = getEponymousParent(d);
+ //printf("Declaration::toDocbuffer() %s, originalType = %s, td = %s\n", d->toChars(), d->originalType ? d->originalType->toChars() : "--", td ? td->toChars() : "--");
+
+ HdrGenState hgs;
+ hgs.ddoc = true;
+
+ if (d->isDeprecated())
+ buf->writestring("$(DEPRECATED ");
+
+ prefix(d);
+
+ if (d->type)
+ {
+ Type *origType = d->originalType ? d->originalType : d->type;
+ if (origType->ty == Tfunction)
+ {
+ functionToBufferFull((TypeFunction *)origType, buf, d->ident, &hgs, td);
+ }
+ else
+ ::toCBuffer(origType, buf, d->ident, &hgs);
+ }
+ else
+ buf->writestring(d->ident->toChars());
+
+ if (d->isVarDeclaration() && td)
+ {
+ buf->writeByte('(');
+ if (td->origParameters && td->origParameters->dim)
+ {
+ for (size_t i = 0; i < td->origParameters->dim; i++)
+ {
+ if (i)
+ buf->writestring(", ");
+ toCBuffer((*td->origParameters)[i], buf, &hgs);
+ }
+ }
+ buf->writeByte(')');
+ }
+
+ // emit constraints if declaration is a templated declaration
+ if (td && td->constraint)
+ {
+ buf->writestring(" if (");
+ ::toCBuffer(td->constraint, buf, &hgs);
+ buf->writeByte(')');
+ }
+
+ if (d->isDeprecated())
+ buf->writestring(")");
+
+ buf->writestring(";\n");
+ }
+
+ void visit(AliasDeclaration *ad)
+ {
+ //printf("AliasDeclaration::toDocbuffer() %s\n", ad->toChars());
+ if (!ad->ident)
+ return;
+
+ if (ad->isDeprecated())
+ buf->writestring("deprecated ");
+
+ emitProtection(buf, ad->protection);
+ buf->printf("alias %s = ", ad->toChars());
+
+ if (Dsymbol *s = ad->aliassym) // ident alias
+ {
+ prettyPrintDsymbol(s, ad->parent);
+ }
+ else if (Type *type = ad->getType()) // type alias
+ {
+ if (type->ty == Tclass || type->ty == Tstruct || type->ty == Tenum)
+ {
+ if (Dsymbol *s = type->toDsymbol(NULL)) // elaborate type
+ prettyPrintDsymbol(s, ad->parent);
+ else
+ buf->writestring(type->toChars());
+ }
+ else
+ {
+ // simple type
+ buf->writestring(type->toChars());
+ }
+ }
+
+ buf->writestring(";\n");
+ }
+
+ void parentToBuffer(Dsymbol *s)
+ {
+ if (s && !s->isPackage() && !s->isModule())
+ {
+ parentToBuffer(s->parent);
+ buf->writestring(s->toChars());
+ buf->writestring(".");
+ }
+ }
+
+ static bool inSameModule(Dsymbol *s, Dsymbol *p)
+ {
+ for ( ; s ; s = s->parent)
+ {
+ if (s->isModule())
+ break;
+ }
+
+ for ( ; p ; p = p->parent)
+ {
+ if (p->isModule())
+ break;
+ }
+
+ return s == p;
+ }
+
+ void prettyPrintDsymbol(Dsymbol *s, Dsymbol *parent)
+ {
+ if (s->parent && (s->parent == parent)) // in current scope -> naked name
+ {
+ buf->writestring(s->toChars());
+ }
+ else if (!inSameModule(s, parent)) // in another module -> full name
+ {
+ buf->writestring(s->toPrettyChars());
+ }
+ else // nested in a type in this module -> full name w/o module name
+ {
+ // if alias is nested in a user-type use module-scope lookup
+ if (!parent->isModule() && !parent->isPackage())
+ buf->writestring(".");
+
+ parentToBuffer(s->parent);
+ buf->writestring(s->toChars());
+ }
+ }
+
+ void visit(AggregateDeclaration *ad)
+ {
+ if (!ad->ident)
+ return;
+
+ buf->printf("%s %s", ad->kind(), ad->toChars());
+ buf->writestring(";\n");
+ }
+
+ void visit(StructDeclaration *sd)
+ {
+ //printf("StructDeclaration::toDocbuffer() %s\n", sd->toChars());
+ if (!sd->ident)
+ return;
+
+ if (TemplateDeclaration *td = getEponymousParent(sd))
+ {
+ toDocBuffer(td, buf, sc);
+ }
+ else
+ {
+ buf->printf("%s %s", sd->kind(), sd->toChars());
+ }
+ buf->writestring(";\n");
+ }
+
+ void visit(ClassDeclaration *cd)
+ {
+ //printf("ClassDeclaration::toDocbuffer() %s\n", cd->toChars());
+ if (!cd->ident)
+ return;
+
+ if (TemplateDeclaration *td = getEponymousParent(cd))
+ {
+ toDocBuffer(td, buf, sc);
+ }
+ else
+ {
+ if (!cd->isInterfaceDeclaration() && cd->isAbstract())
+ buf->writestring("abstract ");
+ buf->printf("%s %s", cd->kind(), cd->toChars());
+ }
+ int any = 0;
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ BaseClass *bc = (*cd->baseclasses)[i];
+
+ if (bc->sym && bc->sym->ident == Id::Object)
+ continue;
+
+ if (any)
+ buf->writestring(", ");
+ else
+ {
+ buf->writestring(": ");
+ any = 1;
+ }
+ emitProtection(buf, Prot(PROTpublic));
+ if (bc->sym)
+ {
+ buf->printf("$(DDOC_PSUPER_SYMBOL %s)", bc->sym->toPrettyChars());
+ }
+ else
+ {
+ HdrGenState hgs;
+ ::toCBuffer(bc->type, buf, NULL, &hgs);
+ }
+ }
+ buf->writestring(";\n");
+ }
+
+ void visit(EnumDeclaration *ed)
+ {
+ if (!ed->ident)
+ return;
+
+ buf->printf("%s %s", ed->kind(), ed->toChars());
+ if (ed->memtype)
+ {
+ buf->writestring(": $(DDOC_ENUM_BASETYPE ");
+ HdrGenState hgs;
+ ::toCBuffer(ed->memtype, buf, NULL, &hgs);
+ buf->writestring(")");
+ }
+ buf->writestring(";\n");
+ }
+
+ void visit(EnumMember *em)
+ {
+ if (!em->ident)
+ return;
+
+ buf->writestring(em->toChars());
+ }
+ };
+
+ ToDocBuffer v(buf, sc);
+ s->accept(&v);
+}
+
+/********************************* DocComment *********************************/
+
+DocComment *DocComment::parse(Dsymbol *s, const utf8_t *comment)
+{
+ //printf("parse(%s): '%s'\n", s->toChars(), comment);
+ DocComment *dc = new DocComment();
+ dc->a.push(s);
+ if (!comment)
+ return dc;
+
+ dc->parseSections(comment);
+
+ for (size_t i = 0; i < dc->sections.dim; i++)
+ {
+ Section *sec = dc->sections[i];
+
+ if (icmp("copyright", sec->name, sec->namelen) == 0)
+ {
+ dc->copyright = sec;
+ }
+ if (icmp("macros", sec->name, sec->namelen) == 0)
+ {
+ dc->macros = sec;
+ }
+ }
+
+ return dc;
+}
+
+/*****************************************
+ * Parse next paragraph out of *pcomment.
+ * Update *pcomment to point past paragraph.
+ * Returns NULL if no more paragraphs.
+ * If paragraph ends in 'identifier:',
+ * then (*pcomment)[0 .. idlen] is the identifier.
+ */
+
+void DocComment::parseSections(const utf8_t *comment)
+{
+ const utf8_t *p;
+ const utf8_t *pstart;
+ const utf8_t *pend;
+ const utf8_t *idstart = NULL; // dead-store to prevent spurious warning
+ size_t idlen;
+
+ const utf8_t *name = NULL;
+ size_t namelen = 0;
+
+ //printf("parseSections('%s')\n", comment);
+ p = comment;
+ while (*p)
+ {
+ const utf8_t *pstart0 = p;
+ p = skipwhitespace(p);
+ pstart = p;
+ pend = p;
+
+ /* Find end of section, which is ended by one of:
+ * 'identifier:' (but not inside a code section)
+ * '\0'
+ */
+ idlen = 0;
+ int inCode = 0;
+ while (1)
+ {
+ // Check for start/end of a code section
+ if (*p == '-')
+ {
+ if (!inCode)
+ {
+ // restore leading indentation
+ while (pstart0 < pstart && isIndentWS(pstart-1)) --pstart;
+ }
+
+ int numdash = 0;
+ while (*p == '-')
+ {
+ ++numdash;
+ p++;
+ }
+ // BUG: handle UTF PS and LS too
+ if ((!*p || *p == '\r' || *p == '\n') && numdash >= 3)
+ inCode ^= 1;
+ pend = p;
+ }
+
+ if (!inCode && isIdStart(p))
+ {
+ const utf8_t *q = p + utfStride(p);
+ while (isIdTail(q))
+ q += utfStride(q);
+ // Detected tag ends it
+ if (*q == ':' && isupper(*p)
+ && (isspace(q[1]) || q[1] == 0))
+ {
+ idlen = q - p;
+ idstart = p;
+ for (pend = p; pend > pstart; pend--)
+ {
+ if (pend[-1] == '\n')
+ break;
+ }
+ p = q + 1;
+ break;
+ }
+ }
+ while (1)
+ {
+ if (!*p)
+ goto L1;
+ if (*p == '\n')
+ {
+ p++;
+ if (*p == '\n' && !summary && !namelen && !inCode)
+ {
+ pend = p;
+ p++;
+ goto L1;
+ }
+ break;
+ }
+ p++;
+ pend = p;
+ }
+ p = skipwhitespace(p);
+ }
+ L1:
+
+ if (namelen || pstart < pend)
+ {
+ Section *s;
+ if (icmp("Params", name, namelen) == 0)
+ s = new ParamSection();
+ else if (icmp("Macros", name, namelen) == 0)
+ s = new MacroSection();
+ else
+ s = new Section();
+ s->name = name;
+ s->namelen = namelen;
+ s->body = pstart;
+ s->bodylen = pend - pstart;
+ s->nooutput = 0;
+
+ //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body);
+
+ sections.push(s);
+
+ if (!summary && !namelen)
+ summary = s;
+ }
+
+ if (idlen)
+ {
+ name = idstart;
+ namelen = idlen;
+ }
+ else
+ {
+ name = NULL;
+ namelen = 0;
+ if (!*p)
+ break;
+ }
+ }
+}
+
+void DocComment::writeSections(Scope *sc, Dsymbols *a, OutBuffer *buf)
+{
+ assert(a->dim);
+
+ //printf("DocComment::writeSections()\n");
+ Loc loc = (*a)[0]->loc;
+ if (Module *m = (*a)[0]->isModule())
+ {
+ if (m->md)
+ loc = m->md->loc;
+ }
+
+ size_t offset1 = buf->offset;
+ buf->writestring("$(DDOC_SECTIONS ");
+ size_t offset2 = buf->offset;
+
+ for (size_t i = 0; i < sections.dim; i++)
+ {
+ Section *sec = sections[i];
+ if (sec->nooutput)
+ continue;
+
+ //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body);
+ if (!sec->namelen && i == 0)
+ {
+ buf->writestring("$(DDOC_SUMMARY ");
+ size_t o = buf->offset;
+ buf->write(sec->body, sec->bodylen);
+ escapeStrayParenthesis(loc, buf, o);
+ highlightText(sc, a, buf, o);
+ buf->writestring(")\n");
+ }
+ else
+ sec->write(loc, this, sc, a, buf);
+ }
+
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ Dsymbol *s = (*a)[i];
+ if (Dsymbol *td = getEponymousParent(s))
+ s = td;
+
+ for (UnitTestDeclaration *utd = s->ddocUnittest; utd; utd = utd->ddocUnittest)
+ {
+ if (utd->protection.kind == PROTprivate || !utd->comment || !utd->fbody)
+ continue;
+
+ // Strip whitespaces to avoid showing empty summary
+ const utf8_t *c = utd->comment;
+ while (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r') ++c;
+
+ buf->writestring("$(DDOC_EXAMPLES ");
+
+ size_t o = buf->offset;
+ buf->writestring((const char *)c);
+
+ if (utd->codedoc)
+ {
+ size_t n = getCodeIndent(utd->codedoc);
+ while (n--) buf->writeByte(' ');
+ buf->writestring("----\n");
+ buf->writestring(utd->codedoc);
+ buf->writestring("----\n");
+ highlightText(sc, a, buf, o);
+ }
+
+ buf->writestring(")");
+ }
+ }
+
+ if (buf->offset == offset2)
+ {
+ /* Didn't write out any sections, so back out last write
+ */
+ buf->offset = offset1;
+ buf->writestring("$(DDOC_BLANKLINE)\n");
+ }
+ else
+ buf->writestring(")\n");
+}
+
+/***************************************************
+ */
+
+void Section::write(Loc loc, DocComment *, Scope *sc, Dsymbols *a, OutBuffer *buf)
+{
+ assert(a->dim);
+
+ if (namelen)
+ {
+ static const char *table[] =
+ {
+ "AUTHORS", "BUGS", "COPYRIGHT", "DATE",
+ "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE",
+ "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS",
+ "VERSION", NULL
+ };
+
+ for (size_t i = 0; table[i]; i++)
+ {
+ if (icmp(table[i], name, namelen) == 0)
+ {
+ buf->printf("$(DDOC_%s ", table[i]);
+ goto L1;
+ }
+ }
+
+ buf->writestring("$(DDOC_SECTION ");
+
+ // Replace _ characters with spaces
+ buf->writestring("$(DDOC_SECTION_H ");
+ size_t o = buf->offset;
+ for (size_t u = 0; u < namelen; u++)
+ {
+ utf8_t c = name[u];
+ buf->writeByte((c == '_') ? ' ' : c);
+ }
+ escapeStrayParenthesis(loc, buf, o);
+ buf->writestring(":)\n");
+ }
+ else
+ {
+ buf->writestring("$(DDOC_DESCRIPTION ");
+ }
+ L1:
+ size_t o = buf->offset;
+ buf->write(body, bodylen);
+ escapeStrayParenthesis(loc, buf, o);
+ highlightText(sc, a, buf, o);
+ buf->writestring(")\n");
+}
+
+/***************************************************
+ */
+
+void ParamSection::write(Loc loc, DocComment *, Scope *sc, Dsymbols *a, OutBuffer *buf)
+{
+ assert(a->dim);
+ Dsymbol *s = (*a)[0]; // test
+
+ const utf8_t *p = body;
+ size_t len = bodylen;
+ const utf8_t *pend = p + len;
+
+ const utf8_t *tempstart = NULL;
+ size_t templen = 0;
+
+ const utf8_t *namestart = NULL;
+ size_t namelen = 0; // !=0 if line continuation
+
+ const utf8_t *textstart = NULL;
+ size_t textlen = 0;
+
+ size_t paramcount = 0;
+
+ buf->writestring("$(DDOC_PARAMS ");
+ while (p < pend)
+ {
+ // Skip to start of macro
+ while (1)
+ {
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ p++;
+ continue;
+
+ case '\n':
+ p++;
+ goto Lcont;
+
+ default:
+ if (isIdStart(p) || isCVariadicArg(p, pend - p))
+ break;
+ if (namelen)
+ goto Ltext; // continuation of prev macro
+ goto Lskipline;
+ }
+ break;
+ }
+ tempstart = p;
+
+ while (isIdTail(p))
+ p += utfStride(p);
+ if (isCVariadicArg(p, pend - p))
+ p += 3;
+
+ templen = p - tempstart;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ if (*p != '=')
+ {
+ if (namelen)
+ goto Ltext; // continuation of prev macro
+ goto Lskipline;
+ }
+ p++;
+
+ if (namelen)
+ {
+ // Output existing param
+
+ L1:
+ //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
+ ++paramcount;
+ HdrGenState hgs;
+ buf->writestring("$(DDOC_PARAM_ROW ");
+ {
+ buf->writestring("$(DDOC_PARAM_ID ");
+ {
+ size_t o = buf->offset;
+ Parameter *fparam = isFunctionParameter(a, namestart, namelen);
+ bool isCVariadic = isCVariadicParameter(a, namestart, namelen);
+ if (isCVariadic)
+ {
+ buf->writestring("...");
+ }
+ else if (fparam && fparam->type && fparam->ident)
+ {
+ ::toCBuffer(fparam->type, buf, fparam->ident, &hgs);
+ }
+ else
+ {
+ if (isTemplateParameter(a, namestart, namelen))
+ {
+ // 10236: Don't count template parameters for params check
+ --paramcount;
+ }
+ else if (!fparam)
+ {
+ warning(s->loc, "Ddoc: function declaration has no parameter '%.*s'", (int)namelen, namestart);
+ }
+ buf->write(namestart, namelen);
+ }
+ escapeStrayParenthesis(loc, buf, o);
+ highlightCode(sc, a, buf, o);
+ }
+ buf->writestring(")\n");
+
+ buf->writestring("$(DDOC_PARAM_DESC ");
+ {
+ size_t o = buf->offset;
+ buf->write(textstart, textlen);
+ escapeStrayParenthesis(loc, buf, o);
+ highlightText(sc, a, buf, o);
+ }
+ buf->writestring(")");
+ }
+ buf->writestring(")\n");
+ namelen = 0;
+ if (p >= pend)
+ break;
+ }
+
+ namestart = tempstart;
+ namelen = templen;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+ textstart = p;
+
+ Ltext:
+ while (*p != '\n')
+ p++;
+ textlen = p - textstart;
+ p++;
+
+ Lcont:
+ continue;
+
+ Lskipline:
+ // Ignore this line
+ while (*p++ != '\n')
+ ;
+ }
+ if (namelen)
+ goto L1; // write out last one
+ buf->writestring(")\n");
+
+ TypeFunction *tf = a->dim == 1 ? isTypeFunction(s) : NULL;
+ if (tf)
+ {
+ size_t pcount = (tf->parameters ? tf->parameters->dim : 0) + (int)(tf->varargs == 1);
+ if (pcount != paramcount)
+ {
+ warning(s->loc, "Ddoc: parameter count mismatch");
+ }
+ }
+}
+
+/***************************************************
+ */
+
+void MacroSection::write(Loc, DocComment *dc, Scope *, Dsymbols *, OutBuffer *)
+{
+ //printf("MacroSection::write()\n");
+ DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen);
+}
+
+/************************************************
+ * Parse macros out of Macros: section.
+ * Macros are of the form:
+ * name1 = value1
+ *
+ * name2 = value2
+ */
+
+void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, const utf8_t *m, size_t mlen)
+{
+ const utf8_t *p = m;
+ size_t len = mlen;
+ const utf8_t *pend = p + len;
+
+ const utf8_t *tempstart = NULL;
+ size_t templen = 0;
+
+ const utf8_t *namestart = NULL;
+ size_t namelen = 0; // !=0 if line continuation
+
+ const utf8_t *textstart = NULL;
+ size_t textlen = 0;
+
+ while (p < pend)
+ {
+ // Skip to start of macro
+ while (1)
+ {
+ if (p >= pend)
+ goto Ldone;
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ p++;
+ continue;
+
+ case '\r':
+ case '\n':
+ p++;
+ goto Lcont;
+
+ default:
+ if (isIdStart(p))
+ break;
+ if (namelen)
+ goto Ltext; // continuation of prev macro
+ goto Lskipline;
+ }
+ break;
+ }
+ tempstart = p;
+
+ while (1)
+ {
+ if (p >= pend)
+ goto Ldone;
+ if (!isIdTail(p))
+ break;
+ p += utfStride(p);
+ }
+ templen = p - tempstart;
+
+ while (1)
+ {
+ if (p >= pend)
+ goto Ldone;
+ if (!(*p == ' ' || *p == '\t'))
+ break;
+ p++;
+ }
+
+ if (*p != '=')
+ {
+ if (namelen)
+ goto Ltext; // continuation of prev macro
+ goto Lskipline;
+ }
+ p++;
+ if (p >= pend)
+ goto Ldone;
+
+ if (namelen)
+ {
+ // Output existing macro
+ L1:
+ //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
+ if (icmp("ESCAPES", namestart, namelen) == 0)
+ parseEscapes(pescapetable, textstart, textlen);
+ else
+ Macro::define(pmacrotable, namestart, namelen, textstart, textlen);
+ namelen = 0;
+ if (p >= pend)
+ break;
+ }
+
+ namestart = tempstart;
+ namelen = templen;
+
+ while (p < pend && (*p == ' ' || *p == '\t'))
+ p++;
+ textstart = p;
+
+ Ltext:
+ while (p < pend && *p != '\r' && *p != '\n')
+ p++;
+ textlen = p - textstart;
+
+ p++;
+ //printf("p = %p, pend = %p\n", p, pend);
+
+ Lcont:
+ continue;
+
+ Lskipline:
+ // Ignore this line
+ while (p < pend && *p != '\r' && *p != '\n')
+ p++;
+ }
+Ldone:
+ if (namelen)
+ goto L1; // write out last one
+}
+
+/**************************************
+ * Parse escapes of the form:
+ * /c/string/
+ * where c is a single character.
+ * Multiple escapes can be separated
+ * by whitespace and/or commas.
+ */
+
+void DocComment::parseEscapes(Escape **pescapetable, const utf8_t *textstart, size_t textlen)
+{
+ Escape *escapetable = *pescapetable;
+
+ if (!escapetable)
+ {
+ escapetable = new Escape;
+ memset(escapetable, 0, sizeof(Escape));
+ *pescapetable = escapetable;
+ }
+ //printf("parseEscapes('%.*s') pescapetable = %p\n", textlen, textstart, pescapetable);
+ const utf8_t *p = textstart;
+ const utf8_t *pend = p + textlen;
+
+ while (1)
+ {
+ while (1)
+ {
+ if (p + 4 >= pend)
+ return;
+ if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ','))
+ break;
+ p++;
+ }
+ if (p[0] != '/' || p[2] != '/')
+ return;
+ utf8_t c = p[1];
+ p += 3;
+ const utf8_t *start = p;
+ while (1)
+ {
+ if (p >= pend)
+ return;
+ if (*p == '/')
+ break;
+ p++;
+ }
+ size_t len = p - start;
+ char *s = (char *)memcpy(mem.xmalloc(len + 1), start, len);
+ s[len] = 0;
+ escapetable->strings[c] = s;
+ //printf("\t%c = '%s'\n", c, s);
+ p++;
+ }
+}
+
+
+/******************************************
+ * Compare 0-terminated string with length terminated string.
+ * Return < 0, ==0, > 0
+ */
+
+int cmp(const char *stringz, const void *s, size_t slen)
+{
+ size_t len1 = strlen(stringz);
+
+ if (len1 != slen)
+ return (int)(len1 - slen);
+ return memcmp(stringz, s, slen);
+}
+
+int icmp(const char *stringz, const void *s, size_t slen)
+{
+ size_t len1 = strlen(stringz);
+
+ if (len1 != slen)
+ return (int)(len1 - slen);
+ return Port::memicmp(stringz, (const char *)s, slen);
+}
+
+/*****************************************
+ * Return true if comment consists entirely of "ditto".
+ */
+
+bool isDitto(const utf8_t *comment)
+{
+ if (comment)
+ {
+ const utf8_t *p = skipwhitespace(comment);
+
+ if (Port::memicmp((const char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0)
+ return true;
+ }
+ return false;
+}
+
+/**********************************************
+ * Skip white space.
+ */
+
+const utf8_t *skipwhitespace(const utf8_t *p)
+{
+ for (; 1; p++)
+ {
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ case '\n':
+ continue;
+ }
+ break;
+ }
+ return p;
+}
+
+
+/************************************************
+ * Scan forward to one of:
+ * start of identifier
+ * beginning of next line
+ * end of buf
+ */
+
+size_t skiptoident(OutBuffer *buf, size_t i)
+{
+ while (i < buf->offset)
+ {
+ dchar_t c;
+
+ size_t oi = i;
+ if (utf_decodeChar((utf8_t *)buf->data, buf->offset, &i, &c))
+ {
+ /* Ignore UTF errors, but still consume input
+ */
+ break;
+ }
+ if (c >= 0x80)
+ {
+ if (!isUniAlpha(c))
+ continue;
+ }
+ else if (!(isalpha(c) || c == '_' || c == '\n'))
+ continue;
+ i = oi;
+ break;
+ }
+ return i;
+}
+
+/************************************************
+ * Scan forward past end of identifier.
+ */
+
+size_t skippastident(OutBuffer *buf, size_t i)
+{
+ while (i < buf->offset)
+ {
+ dchar_t c;
+
+ size_t oi = i;
+ if (utf_decodeChar((utf8_t *)buf->data, buf->offset, &i, &c))
+ {
+ /* Ignore UTF errors, but still consume input
+ */
+ break;
+ }
+ if (c >= 0x80)
+ {
+ if (isUniAlpha(c))
+ continue;
+ }
+ else if (isalnum(c) || c == '_')
+ continue;
+ i = oi;
+ break;
+ }
+ return i;
+}
+
+
+/************************************************
+ * Scan forward past URL starting at i.
+ * We don't want to highlight parts of a URL.
+ * Returns:
+ * i if not a URL
+ * index just past it if it is a URL
+ */
+
+size_t skippastURL(OutBuffer *buf, size_t i)
+{
+ size_t length = buf->offset - i;
+ utf8_t *p = (utf8_t *)&buf->data[i];
+ size_t j;
+ unsigned sawdot = 0;
+
+ if (length > 7 && Port::memicmp((char *)p, "http://", 7) == 0)
+ {
+ j = 7;
+ }
+ else if (length > 8 && Port::memicmp((char *)p, "https://", 8) == 0)
+ {
+ j = 8;
+ }
+ else
+ goto Lno;
+
+ for (; j < length; j++)
+ {
+ utf8_t c = p[j];
+ if (isalnum(c))
+ continue;
+ if (c == '-' || c == '_' || c == '?' ||
+ c == '=' || c == '%' || c == '&' ||
+ c == '/' || c == '+' || c == '#' ||
+ c == '~')
+ continue;
+ if (c == '.')
+ {
+ sawdot = 1;
+ continue;
+ }
+ break;
+ }
+ if (sawdot)
+ return i + j;
+
+Lno:
+ return i;
+}
+
+
+/****************************************************
+ */
+
+bool isIdentifier(Dsymbols *a, const utf8_t *p, size_t len)
+{
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ const char *s = (*a)[i]->ident->toChars();
+ if (cmp(s, p, len) == 0)
+ return true;
+ }
+ return false;
+}
+
+/****************************************************
+ */
+
+bool isKeyword(utf8_t *p, size_t len)
+{
+ static const char *table[] = { "true", "false", "null", NULL };
+
+ for (int i = 0; table[i]; i++)
+ {
+ if (cmp(table[i], p, len) == 0)
+ return true;
+ }
+ return false;
+}
+
+/****************************************************
+ */
+
+TypeFunction *isTypeFunction(Dsymbol *s)
+{
+ FuncDeclaration *f = s->isFuncDeclaration();
+
+ /* f->type may be NULL for template members.
+ */
+ if (f && f->type)
+ {
+ Type *t = f->originalType ? f->originalType : f->type;
+ if (t->ty == Tfunction)
+ return (TypeFunction *)t;
+ }
+ return NULL;
+}
+
+/****************************************************
+ */
+
+Parameter *isFunctionParameter(Dsymbols *a, const utf8_t *p, size_t len)
+{
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ TypeFunction *tf = isTypeFunction((*a)[i]);
+ if (tf && tf->parameters)
+ {
+ for (size_t k = 0; k < tf->parameters->dim; k++)
+ {
+ Parameter *fparam = (*tf->parameters)[k];
+ if (fparam->ident && cmp(fparam->ident->toChars(), p, len) == 0)
+ {
+ return fparam;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/****************************************************
+ */
+
+TemplateParameter *isTemplateParameter(Dsymbols *a, const utf8_t *p, size_t len)
+{
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ TemplateDeclaration *td = getEponymousParent((*a)[i]);
+ if (td && td->origParameters)
+ {
+ for (size_t k = 0; k < td->origParameters->dim; k++)
+ {
+ TemplateParameter *tp = (*td->origParameters)[k];
+ if (tp->ident && cmp(tp->ident->toChars(), p, len) == 0)
+ {
+ return tp;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/****************************************************
+ * Return true if str is a reserved symbol name
+ * that starts with a double underscore.
+ */
+
+bool isReservedName(utf8_t *str, size_t len)
+{
+ static const char *table[] = {
+ "__ctor", "__dtor", "__postblit", "__invariant", "__unitTest",
+ "__require", "__ensure", "__dollar", "__ctfe", "__withSym", "__result",
+ "__returnLabel", "__vptr", "__monitor", "__gate", "__xopEquals", "__xopCmp",
+ "__LINE__", "__FILE__", "__MODULE__", "__FUNCTION__", "__PRETTY_FUNCTION__",
+ "__DATE__", "__TIME__", "__TIMESTAMP__", "__VENDOR__", "__VERSION__",
+ "__EOF__", "__LOCAL_SIZE", "___tls_get_addr", "__entrypoint", NULL };
+
+ for (int i = 0; table[i]; i++)
+ {
+ if (cmp(table[i], str, len) == 0)
+ return true;
+ }
+ return false;
+}
+
+/**************************************************
+ * Highlight text section.
+ */
+
+void highlightText(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
+{
+ Dsymbol *s = a->dim ? (*a)[0] : NULL; // test
+
+ //printf("highlightText()\n");
+
+ int leadingBlank = 1;
+ int inCode = 0;
+ int inBacktick = 0;
+ //int inComment = 0; // in <!-- ... --> comment
+ size_t iCodeStart = 0; // start of code section
+ size_t codeIndent = 0;
+
+ size_t iLineStart = offset;
+
+ for (size_t i = offset; i < buf->offset; i++)
+ {
+ utf8_t c = buf->data[i];
+
+ Lcont:
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ break;
+
+ case '\n':
+ if (inBacktick)
+ {
+ // `inline code` is only valid if contained on a single line
+ // otherwise, the backticks should be output literally.
+ //
+ // This lets things like `output from the linker' display
+ // unmolested while keeping the feature consistent with GitHub.
+
+ inBacktick = false;
+ inCode = false; // the backtick also assumes we're in code
+
+ // Nothing else is necessary since the DDOC_BACKQUOTED macro is
+ // inserted lazily at the close quote, meaning the rest of the
+ // text is already OK.
+ }
+
+ if (!sc->_module->isDocFile &&
+ !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n"
+ {
+ static const char blankline[] = "$(DDOC_BLANKLINE)\n";
+
+ i = buf->insert(i, blankline, strlen(blankline));
+ }
+ leadingBlank = 1;
+ iLineStart = i + 1;
+ break;
+
+ case '<':
+ {
+ leadingBlank = 0;
+ if (inCode)
+ break;
+ utf8_t *p = (utf8_t *)&buf->data[i];
+ const char *se = sc->_module->escapetable->escapeChar('<');
+ if (se && strcmp(se, "&lt;") == 0)
+ {
+ // Generating HTML
+ // Skip over comments
+ if (p[1] == '!' && p[2] == '-' && p[3] == '-')
+ {
+ size_t j = i + 4;
+ p += 4;
+ while (1)
+ {
+ if (j == buf->offset)
+ goto L1;
+ if (p[0] == '-' && p[1] == '-' && p[2] == '>')
+ {
+ i = j + 2; // place on closing '>'
+ break;
+ }
+ j++;
+ p++;
+ }
+ break;
+ }
+
+ // Skip over HTML tag
+ if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2])))
+ {
+ size_t j = i + 2;
+ p += 2;
+ while (1)
+ {
+ if (j == buf->offset)
+ break;
+ if (p[0] == '>')
+ {
+ i = j; // place on closing '>'
+ break;
+ }
+ j++;
+ p++;
+ }
+ break;
+ }
+ }
+ L1:
+ // Replace '<' with '&lt;' character entity
+ if (se)
+ {
+ size_t len = strlen(se);
+ buf->remove(i, 1);
+ i = buf->insert(i, se, len);
+ i--; // point to ';'
+ }
+ break;
+ }
+ case '>':
+ {
+ leadingBlank = 0;
+ if (inCode)
+ break;
+ // Replace '>' with '&gt;' character entity
+ const char *se = sc->_module->escapetable->escapeChar('>');
+ if (se)
+ {
+ size_t len = strlen(se);
+ buf->remove(i, 1);
+ i = buf->insert(i, se, len);
+ i--; // point to ';'
+ }
+ break;
+ }
+ case '&':
+ {
+ leadingBlank = 0;
+ if (inCode)
+ break;
+ utf8_t *p = (utf8_t *)&buf->data[i];
+ if (p[1] == '#' || isalpha(p[1]))
+ break; // already a character entity
+ // Replace '&' with '&amp;' character entity
+ const char *se = sc->_module->escapetable->escapeChar('&');
+ if (se)
+ {
+ size_t len = strlen(se);
+ buf->remove(i, 1);
+ i = buf->insert(i, se, len);
+ i--; // point to ';'
+ }
+ break;
+ }
+ case '`':
+ {
+ if (inBacktick)
+ {
+ inBacktick = 0;
+ inCode = 0;
+
+ OutBuffer codebuf;
+
+ codebuf.write(buf->data + iCodeStart + 1, i - (iCodeStart + 1));
+
+ // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL
+ highlightCode(sc, a, &codebuf, 0);
+
+ buf->remove(iCodeStart, i - iCodeStart + 1); // also trimming off the current `
+
+ static const char pre[] = "$(DDOC_BACKQUOTED ";
+ i = buf->insert(iCodeStart, pre, strlen(pre));
+ i = buf->insert(i, (char *)codebuf.data, codebuf.offset);
+ i = buf->insert(i, ")", 1);
+
+ i--; // point to the ending ) so when the for loop does i++, it will see the next character
+
+ break;
+ }
+
+ if (inCode)
+ break;
+
+ inCode = 1;
+ inBacktick = 1;
+ codeIndent = 0; // inline code is not indented
+
+ // All we do here is set the code flags and record
+ // the location. The macro will be inserted lazily
+ // so we can easily cancel the inBacktick if we come
+ // across a newline character.
+ iCodeStart = i;
+
+ break;
+ }
+ case '-':
+ /* A line beginning with --- delimits a code section.
+ * inCode tells us if it is start or end of a code section.
+ */
+ if (leadingBlank)
+ {
+ size_t istart = i;
+ size_t eollen = 0;
+
+ leadingBlank = 0;
+ while (1)
+ {
+ ++i;
+ if (i >= buf->offset)
+ break;
+ c = buf->data[i];
+ if (c == '\n')
+ {
+ eollen = 1;
+ break;
+ }
+ if (c == '\r')
+ {
+ eollen = 1;
+ if (i + 1 >= buf->offset)
+ break;
+ if (buf->data[i + 1] == '\n')
+ {
+ eollen = 2;
+ break;
+ }
+ }
+ // BUG: handle UTF PS and LS too
+ if (c != '-')
+ goto Lcont;
+ }
+ if (i - istart < 3)
+ goto Lcont;
+
+ // We have the start/end of a code section
+
+ // Remove the entire --- line, including blanks and \n
+ buf->remove(iLineStart, i - iLineStart + eollen);
+ i = iLineStart;
+
+ if (inCode && (i <= iCodeStart))
+ {
+ // Empty code section, just remove it completely.
+ inCode = 0;
+ break;
+ }
+
+ if (inCode)
+ {
+ inCode = 0;
+ // The code section is from iCodeStart to i
+ OutBuffer codebuf;
+
+ codebuf.write(buf->data + iCodeStart, i - iCodeStart);
+ codebuf.writeByte(0);
+
+ // Remove leading indentations from all lines
+ bool lineStart = true;
+ utf8_t *endp = (utf8_t *)codebuf.data + codebuf.offset;
+ for (utf8_t *p = (utf8_t *)codebuf.data; p < endp; )
+ {
+ if (lineStart)
+ {
+ size_t j = codeIndent;
+ utf8_t *q = p;
+ while (j-- > 0 && q < endp && isIndentWS(q))
+ ++q;
+ codebuf.remove(p - (utf8_t *)codebuf.data, q - p);
+ assert((utf8_t *)codebuf.data <= p);
+ assert(p < (utf8_t *)codebuf.data + codebuf.offset);
+ lineStart = false;
+ endp = (utf8_t *)codebuf.data + codebuf.offset; // update
+ continue;
+ }
+ if (*p == '\n')
+ lineStart = true;
+ ++p;
+ }
+
+ highlightCode2(sc, a, &codebuf, 0);
+ buf->remove(iCodeStart, i - iCodeStart);
+ i = buf->insert(iCodeStart, codebuf.data, codebuf.offset);
+ i = buf->insert(i, (const char *)")\n", 2);
+ i -= 2; // in next loop, c should be '\n'
+ }
+ else
+ {
+ static const char d_code[] = "$(D_CODE ";
+
+ inCode = 1;
+ codeIndent = istart - iLineStart; // save indent count
+ i = buf->insert(i, d_code, strlen(d_code));
+ iCodeStart = i;
+ i--; // place i on >
+ leadingBlank = true;
+ }
+ }
+ break;
+
+ default:
+ leadingBlank = 0;
+ if (sc->_module->isDocFile || inCode)
+ break;
+
+ utf8_t *start = (utf8_t *)buf->data + i;
+ if (isIdStart(start))
+ {
+ size_t j = skippastident(buf, i);
+ if (i < j)
+ {
+ size_t k = skippastURL(buf, i);
+ if (i < k)
+ {
+ i = k - 1;
+ break;
+ }
+ }
+ else
+ break;
+ size_t len = j - i;
+
+ // leading '_' means no highlight unless it's a reserved symbol name
+ if (c == '_' &&
+ (i == 0 || !isdigit(*(start - 1))) &&
+ (i == buf->offset - 1 || !isReservedName(start, len)))
+ {
+ buf->remove(i, 1);
+ i = j - 1;
+ break;
+ }
+ if (isIdentifier(a, start, len))
+ {
+ i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+ break;
+ }
+ if (isKeyword(start, len))
+ {
+ i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1;
+ break;
+ }
+ if (isFunctionParameter(a, start, len))
+ {
+ //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+ i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
+ break;
+ }
+
+ i = j - 1;
+ }
+ break;
+ }
+ }
+ if (inCode)
+ error(s ? s->loc : Loc(), "unmatched --- in DDoc comment");
+}
+
+/**************************************************
+ * Highlight code for DDOC section.
+ */
+
+void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset)
+{
+ //printf("highlightCode(s = %s '%s')\n", s->kind(), s->toChars());
+ OutBuffer ancbuf;
+ emitAnchor(&ancbuf, s, sc);
+ buf->insert(offset, (char *)ancbuf.data, ancbuf.offset);
+ offset += ancbuf.offset;
+
+ Dsymbols a;
+ a.push(s);
+ highlightCode(sc, &a, buf, offset);
+}
+
+/****************************************************
+ */
+
+void highlightCode(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
+{
+ //printf("highlightCode(a = '%s')\n", a->toChars());
+
+ for (size_t i = offset; i < buf->offset; i++)
+ {
+ utf8_t c = buf->data[i];
+ const char *se = sc->_module->escapetable->escapeChar(c);
+ if (se)
+ {
+ size_t len = strlen(se);
+ buf->remove(i, 1);
+ i = buf->insert(i, se, len);
+ i--; // point to ';'
+ continue;
+ }
+
+ utf8_t *start = (utf8_t *)buf->data + i;
+ if (isIdStart(start))
+ {
+ size_t j = skippastident(buf, i);
+ if (i < j)
+ {
+ size_t len = j - i;
+ if (isIdentifier(a, start, len))
+ {
+ i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+ continue;
+ }
+ if (isFunctionParameter(a, start, len))
+ {
+ //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+ i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
+ continue;
+ }
+ i = j - 1;
+ }
+ }
+ }
+}
+
+/****************************************
+ */
+
+void highlightCode3(Scope *sc, OutBuffer *buf, const utf8_t *p, const utf8_t *pend)
+{
+ for (; p < pend; p++)
+ {
+ const char *s = sc->_module->escapetable->escapeChar(*p);
+ if (s)
+ buf->writestring(s);
+ else
+ buf->writeByte(*p);
+ }
+}
+
+/**************************************************
+ * Highlight code for CODE section.
+ */
+
+void highlightCode2(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
+{
+ unsigned errorsave = global.errors;
+ Lexer lex(NULL, (utf8_t *)buf->data, 0, buf->offset - 1, 0, 1);
+ OutBuffer res;
+ const utf8_t *lastp = (utf8_t *)buf->data;
+
+ //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data);
+ res.reserve(buf->offset);
+ while (1)
+ {
+ Token tok;
+ lex.scan(&tok);
+ highlightCode3(sc, &res, lastp, tok.ptr);
+
+ const char *highlight = NULL;
+ switch (tok.value)
+ {
+ case TOKidentifier:
+ {
+ if (!sc)
+ break;
+ size_t len = lex.p - tok.ptr;
+ if (isIdentifier(a, tok.ptr, len))
+ {
+ highlight = "$(D_PSYMBOL ";
+ break;
+ }
+ if (isFunctionParameter(a, tok.ptr, len))
+ {
+ //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
+ highlight = "$(D_PARAM ";
+ break;
+ }
+ break;
+ }
+ case TOKcomment:
+ highlight = "$(D_COMMENT ";
+ break;
+
+ case TOKstring:
+ highlight = "$(D_STRING ";
+ break;
+
+ default:
+ if (tok.isKeyword())
+ highlight = "$(D_KEYWORD ";
+ break;
+ }
+ if (highlight)
+ {
+ res.writestring(highlight);
+ size_t o = res.offset;
+ highlightCode3(sc, &res, tok.ptr, lex.p);
+ if (tok.value == TOKcomment || tok.value == TOKstring)
+ escapeDdocString(&res, o); // Bugzilla 7656, 7715, and 10519
+ res.writeByte(')');
+ }
+ else
+ highlightCode3(sc, &res, tok.ptr, lex.p);
+ if (tok.value == TOKeof)
+ break;
+ lastp = lex.p;
+ }
+ buf->setsize(offset);
+ buf->write(&res);
+ global.errors = errorsave;
+}
+
+/***************************************
+ * Find character string to replace c with.
+ */
+
+const char *Escape::escapeChar(unsigned c)
+{
+ assert(c < 256);
+ //printf("escapeChar('%c') => %p, %p\n", c, strings, strings[c]);
+ return strings[c];
+}
+
+/****************************************
+ * Determine if p points to the start of a "..." parameter identifier.
+ */
+
+bool isCVariadicArg(const utf8_t *p, size_t len)
+{
+ return len >= 3 && cmp("...", p, 3) == 0;
+}
+
+/****************************************
+ * Determine if p points to the start of an identifier.
+ */
+
+bool isIdStart(const utf8_t *p)
+{
+ unsigned c = *p;
+ if (isalpha(c) || c == '_')
+ return true;
+ if (c >= 0x80)
+ {
+ size_t i = 0;
+ if (utf_decodeChar(p, 4, &i, &c))
+ return false; // ignore errors
+ if (isUniAlpha(c))
+ return true;
+ }
+ return false;
+}
+
+/****************************************
+ * Determine if p points to the rest of an identifier.
+ */
+
+bool isIdTail(const utf8_t *p)
+{
+ unsigned c = *p;
+ if (isalnum(c) || c == '_')
+ return true;
+ if (c >= 0x80)
+ {
+ size_t i = 0;
+ if (utf_decodeChar(p, 4, &i, &c))
+ return false; // ignore errors
+ if (isUniAlpha(c))
+ return true;
+ }
+ return false;
+}
+
+/****************************************
+ * Determine if p points to the indentation space.
+ */
+
+bool isIndentWS(const utf8_t *p)
+{
+ return (*p == ' ') || (*p == '\t');
+}
+
+/*****************************************
+ * Return number of bytes in UTF character.
+ */
+
+int utfStride(const utf8_t *p)
+{
+ unsigned c = *p;
+ if (c < 0x80)
+ return 1;
+ size_t i = 0;
+ utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input
+ return (int)i;
+}
diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h
new file mode 100644
index 0000000..7f3ef51
--- /dev/null
+++ b/gcc/d/dmd/doc.h
@@ -0,0 +1,14 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/doc.h
+ */
+
+#pragma once
+
+void escapeDdocString(OutBuffer *buf, size_t start);
+void gendocfile(Module *m);
diff --git a/gcc/d/dmd/dscope.c b/gcc/d/dmd/dscope.c
new file mode 100644
index 0000000..924a376
--- /dev/null
+++ b/gcc/d/dmd/dscope.c
@@ -0,0 +1,702 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/scope.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h> // strlen()
+
+#include "root/root.h"
+#include "root/rmem.h"
+#include "root/speller.h"
+
+#include "mars.h"
+#include "init.h"
+#include "identifier.h"
+#include "scope.h"
+#include "attrib.h"
+#include "dsymbol.h"
+#include "declaration.h"
+#include "statement.h"
+#include "aggregate.h"
+#include "module.h"
+#include "id.h"
+#include "template.h"
+
+Scope *Scope::freelist = NULL;
+
+void allocFieldinit(Scope *sc, size_t dim)
+{
+ sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
+ sc->fieldinit_dim = dim;
+}
+
+void freeFieldinit(Scope *sc)
+{
+ if (sc->fieldinit)
+ mem.xfree(sc->fieldinit);
+ sc->fieldinit = NULL;
+ sc->fieldinit_dim = 0;
+}
+
+Scope *Scope::alloc()
+{
+ if (freelist)
+ {
+ Scope *s = freelist;
+ freelist = s->enclosing;
+ //printf("freelist %p\n", s);
+ assert(s->flags & SCOPEfree);
+ s->flags &= ~SCOPEfree;
+ return s;
+ }
+
+ return new Scope();
+}
+
+Scope::Scope()
+{
+ // Create root scope
+
+ //printf("Scope::Scope() %p\n", this);
+ this->_module = NULL;
+ this->scopesym = NULL;
+ this->sds = NULL;
+ this->enclosing = NULL;
+ this->parent = NULL;
+ this->sw = NULL;
+ this->tf = NULL;
+ this->os = NULL;
+ this->tinst = NULL;
+ this->minst = NULL;
+ this->sbreak = NULL;
+ this->scontinue = NULL;
+ this->fes = NULL;
+ this->callsc = NULL;
+ this->aligndecl = NULL;
+ this->func = NULL;
+ this->slabel = NULL;
+ this->linkage = LINKd;
+ this->cppmangle = CPPMANGLEdefault;
+ this->inlining = PINLINEdefault;
+ this->protection = Prot(PROTpublic);
+ this->explicitProtection = 0;
+ this->stc = 0;
+ this->depdecl = NULL;
+ this->inunion = 0;
+ this->nofree = 0;
+ this->noctor = 0;
+ this->intypeof = 0;
+ this->lastVar = NULL;
+ this->callSuper = 0;
+ this->fieldinit = NULL;
+ this->fieldinit_dim = 0;
+ this->flags = 0;
+ this->lastdc = NULL;
+ this->anchorCounts = NULL;
+ this->prevAnchor = NULL;
+ this->userAttribDecl = NULL;
+}
+
+Scope *Scope::copy()
+{
+ Scope *sc = Scope::alloc();
+ *sc = *this; // memcpy
+
+ /* Bugzilla 11777: The copied scope should not inherit fieldinit.
+ */
+ sc->fieldinit = NULL;
+
+ return sc;
+}
+
+Scope *Scope::createGlobal(Module *_module)
+{
+ Scope *sc = Scope::alloc();
+ *sc = Scope(); // memset
+
+ sc->aligndecl = NULL;
+ sc->linkage = LINKd;
+ sc->inlining = PINLINEdefault;
+ sc->protection = Prot(PROTpublic);
+
+ sc->_module = _module;
+
+ sc->tinst = NULL;
+ sc->minst = _module;
+
+ sc->scopesym = new ScopeDsymbol();
+ sc->scopesym->symtab = new DsymbolTable();
+
+ // Add top level package as member of this global scope
+ Dsymbol *m = _module;
+ while (m->parent)
+ m = m->parent;
+ m->addMember(NULL, sc->scopesym);
+ m->parent = NULL; // got changed by addMember()
+
+ // Create the module scope underneath the global scope
+ sc = sc->push(_module);
+ sc->parent = _module;
+ return sc;
+}
+
+Scope *Scope::push()
+{
+ Scope *s = copy();
+
+ //printf("Scope::push(this = %p) new = %p\n", this, s);
+ assert(!(flags & SCOPEfree));
+ s->scopesym = NULL;
+ s->sds = NULL;
+ s->enclosing = this;
+ s->slabel = NULL;
+ s->nofree = 0;
+ s->fieldinit = saveFieldInit();
+ s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
+ SCOPEnoaccesscheck | SCOPEignoresymbolvisibility));
+ s->lastdc = NULL;
+
+ assert(this != s);
+ return s;
+}
+
+Scope *Scope::push(ScopeDsymbol *ss)
+{
+ //printf("Scope::push(%s)\n", ss->toChars());
+ Scope *s = push();
+ s->scopesym = ss;
+ return s;
+}
+
+Scope *Scope::pop()
+{
+ //printf("Scope::pop() %p nofree = %d\n", this, nofree);
+ Scope *enc = enclosing;
+
+ if (enclosing)
+ {
+ enclosing->callSuper |= callSuper;
+ if (fieldinit)
+ {
+ if (enclosing->fieldinit)
+ {
+ assert(fieldinit != enclosing->fieldinit);
+ size_t dim = fieldinit_dim;
+ for (size_t i = 0; i < dim; i++)
+ enclosing->fieldinit[i] |= fieldinit[i];
+ }
+ freeFieldinit(this);
+ }
+ }
+
+ if (!nofree)
+ {
+ enclosing = freelist;
+ freelist = this;
+ flags |= SCOPEfree;
+ }
+
+ return enc;
+}
+
+Scope *Scope::startCTFE()
+{
+ Scope *sc = this->push();
+ sc->flags = this->flags | SCOPEctfe;
+ return sc;
+}
+
+Scope *Scope::endCTFE()
+{
+ assert(flags & SCOPEctfe);
+ return pop();
+}
+
+void Scope::mergeCallSuper(Loc loc, unsigned cs)
+{
+ // This does a primitive flow analysis to support the restrictions
+ // regarding when and how constructors can appear.
+ // It merges the results of two paths.
+ // The two paths are callSuper and cs; the result is merged into callSuper.
+
+ if (cs != callSuper)
+ {
+ // Have ALL branches called a constructor?
+ int aAll = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0;
+ int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
+
+ // Have ANY branches called a constructor?
+ bool aAny = (cs & CSXany_ctor) != 0;
+ bool bAny = (callSuper & CSXany_ctor) != 0;
+
+ // Have any branches returned?
+ bool aRet = (cs & CSXreturn) != 0;
+ bool bRet = (callSuper & CSXreturn) != 0;
+
+ // Have any branches halted?
+ bool aHalt = (cs & CSXhalt) != 0;
+ bool bHalt = (callSuper & CSXhalt) != 0;
+
+ bool ok = true;
+
+ if (aHalt && bHalt)
+ {
+ callSuper = CSXhalt;
+ }
+ else if ((!aHalt && aRet && !aAny && bAny) ||
+ (!bHalt && bRet && !bAny && aAny))
+ {
+ // If one has returned without a constructor call, there must be never
+ // have been ctor calls in the other.
+ ok = false;
+ }
+ else if (aHalt || (aRet && aAll))
+ {
+ // If one branch has called a ctor and then exited, anything the
+ // other branch has done is OK (except returning without a
+ // ctor call, but we already checked that).
+ callSuper |= cs & (CSXany_ctor | CSXlabel);
+ }
+ else if (bHalt || (bRet && bAll))
+ {
+ callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
+ }
+ else
+ {
+ // Both branches must have called ctors, or both not.
+ ok = (aAll == bAll);
+ // If one returned without a ctor, we must remember that
+ // (Don't bother if we've already found an error)
+ if (ok && aRet && !aAny)
+ callSuper |= CSXreturn;
+ callSuper |= cs & (CSXany_ctor | CSXlabel);
+ }
+ if (!ok)
+ error(loc, "one path skips constructor");
+ }
+}
+
+unsigned *Scope::saveFieldInit()
+{
+ unsigned *fi = NULL;
+ if (fieldinit) // copy
+ {
+ size_t dim = fieldinit_dim;
+ fi = (unsigned *)mem.xmalloc(sizeof(unsigned) * dim);
+ for (size_t i = 0; i < dim; i++)
+ fi[i] = fieldinit[i];
+ }
+ return fi;
+}
+
+static bool mergeFieldInit(unsigned &fieldInit, unsigned fi, bool mustInit)
+{
+ if (fi != fieldInit)
+ {
+ // Have any branches returned?
+ bool aRet = (fi & CSXreturn) != 0;
+ bool bRet = (fieldInit & CSXreturn) != 0;
+
+ // Have any branches halted?
+ bool aHalt = (fi & CSXhalt) != 0;
+ bool bHalt = (fieldInit & CSXhalt) != 0;
+
+ bool ok;
+
+ if (aHalt && bHalt)
+ {
+ ok = true;
+ fieldInit = CSXhalt;
+ }
+ else if (!aHalt && aRet)
+ {
+ ok = !mustInit || (fi & CSXthis_ctor);
+ fieldInit = fieldInit;
+ }
+ else if (!bHalt && bRet)
+ {
+ ok = !mustInit || (fieldInit & CSXthis_ctor);
+ fieldInit = fi;
+ }
+ else if (aHalt)
+ {
+ ok = !mustInit || (fieldInit & CSXthis_ctor);
+ fieldInit = fieldInit;
+ }
+ else if (bHalt)
+ {
+ ok = !mustInit || (fi & CSXthis_ctor);
+ fieldInit = fi;
+ }
+ else
+ {
+ ok = !mustInit || !((fieldInit ^ fi) & CSXthis_ctor);
+ fieldInit |= fi;
+ }
+
+ return ok;
+ }
+ return true;
+}
+
+void Scope::mergeFieldInit(Loc loc, unsigned *fies)
+{
+ if (fieldinit && fies)
+ {
+ FuncDeclaration *f = func;
+ if (fes) f = fes->func;
+ AggregateDeclaration *ad = f->isMember2();
+ assert(ad);
+
+ for (size_t i = 0; i < ad->fields.dim; i++)
+ {
+ VarDeclaration *v = ad->fields[i];
+ bool mustInit = (v->storage_class & STCnodefaultctor ||
+ v->type->needsNested());
+
+ if (!::mergeFieldInit(fieldinit[i], fies[i], mustInit))
+ {
+ ::error(loc, "one path skips field %s", ad->fields[i]->toChars());
+ }
+ }
+ }
+}
+
+Module *Scope::instantiatingModule()
+{
+ // TODO: in speculative context, returning 'module' is correct?
+ return minst ? minst : _module;
+}
+
+static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
+{
+ for (Scope *sc = scope; sc; sc = sc->enclosing)
+ {
+ assert(sc != sc->enclosing);
+ if (!sc->scopesym)
+ continue;
+ //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
+
+ if (sc->scopesym->isModule())
+ flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+
+ if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
+ {
+ if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
+ ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
+ sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
+ {
+ warning(s->loc, "array 'length' hides other 'length' name in outer scope");
+ }
+ if (pscopesym)
+ *pscopesym = sc->scopesym;
+ return s;
+ }
+ // Stop when we hit a module, but keep going if that is not just under the global scope
+ if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
+ break;
+ }
+ return NULL;
+}
+
+/************************************
+ * Perform unqualified name lookup by following the chain of scopes up
+ * until found.
+ *
+ * Params:
+ * loc = location to use for error messages
+ * ident = name to look up
+ * pscopesym = if supplied and name is found, set to scope that ident was found in
+ * flags = modify search based on flags
+ *
+ * Returns:
+ * symbol if found, null if not
+ */
+Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
+{
+ // This function is called only for unqualified lookup
+ assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
+
+ /* If ident is "start at module scope", only look at module scope
+ */
+ if (ident == Id::empty)
+ {
+ // Look for module scope
+ for (Scope *sc = this; sc; sc = sc->enclosing)
+ {
+ assert(sc != sc->enclosing);
+ if (!sc->scopesym)
+ continue;
+
+ if (Dsymbol *s = sc->scopesym->isModule())
+ {
+ if (pscopesym)
+ *pscopesym = sc->scopesym;
+ return s;
+ }
+ }
+ return NULL;
+ }
+
+ if (this->flags & SCOPEignoresymbolvisibility)
+ flags |= IgnoreSymbolVisibility;
+
+ Dsymbol *sold = NULL;
+ if (global.params.bug10378 || global.params.check10378)
+ {
+ sold = searchScopes(this, loc, ident, pscopesym, flags | IgnoreSymbolVisibility);
+ if (!global.params.check10378)
+ return sold;
+
+ if (ident == Id::dollar) // Bugzilla 15825
+ return sold;
+
+ // Search both ways
+ }
+
+ // First look in local scopes
+ Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
+ if (!s)
+ {
+ // Second look in imported modules
+ s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
+ /** Still find private symbols, so that symbols that weren't access
+ * checked by the compiler remain usable. Once the deprecation is over,
+ * this should be moved to search_correct instead.
+ */
+ if (!s && !(flags & IgnoreSymbolVisibility))
+ {
+ s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
+ if (!s)
+ s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly | IgnoreSymbolVisibility);
+
+ if (s && !(flags & IgnoreErrors))
+ ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), _module->toChars());
+ }
+ }
+
+ if (global.params.check10378)
+ {
+ Dsymbol *snew = s;
+ if (sold != snew)
+ deprecation10378(loc, sold, snew);
+ if (global.params.bug10378)
+ s = sold;
+ }
+ return s;
+}
+
+Dsymbol *Scope::insert(Dsymbol *s)
+{
+ if (VarDeclaration *vd = s->isVarDeclaration())
+ {
+ if (lastVar)
+ vd->lastVar = lastVar;
+ lastVar = vd;
+ }
+ else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
+ {
+ if (VarDeclaration *vd = ss->withstate->wthis)
+ {
+ if (lastVar)
+ vd->lastVar = lastVar;
+ lastVar = vd;
+ }
+ return NULL;
+ }
+ for (Scope *sc = this; sc; sc = sc->enclosing)
+ {
+ //printf("\tsc = %p\n", sc);
+ if (sc->scopesym)
+ {
+ //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
+ if (!sc->scopesym->symtab)
+ sc->scopesym->symtab = new DsymbolTable();
+ return sc->scopesym->symtabInsert(s);
+ }
+ }
+ assert(0);
+ return NULL;
+}
+
+/********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+
+ClassDeclaration *Scope::getClassScope()
+{
+ for (Scope *sc = this; sc; sc = sc->enclosing)
+ {
+ if (!sc->scopesym)
+ continue;
+
+ ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
+ if (cd)
+ return cd;
+ }
+ return NULL;
+}
+
+/********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+
+AggregateDeclaration *Scope::getStructClassScope()
+{
+ for (Scope *sc = this; sc; sc = sc->enclosing)
+ {
+ if (!sc->scopesym)
+ continue;
+
+ AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
+ if (ad)
+ return ad;
+ ad = sc->scopesym->isStructDeclaration();
+ if (ad)
+ return ad;
+ }
+ return NULL;
+}
+
+/*******************************************
+ * For TemplateDeclarations, we need to remember the Scope
+ * where it was declared. So mark the Scope as not
+ * to be free'd.
+ */
+
+void Scope::setNoFree()
+{
+ //int i = 0;
+
+ //printf("Scope::setNoFree(this = %p)\n", this);
+ for (Scope *sc = this; sc; sc = sc->enclosing)
+ {
+ //printf("\tsc = %p\n", sc);
+ sc->nofree = 1;
+
+ assert(!(flags & SCOPEfree));
+ //assert(sc != sc->enclosing);
+ //assert(!sc->enclosing || sc != sc->enclosing->enclosing);
+ //if (++i == 10)
+ //assert(0);
+ }
+}
+
+structalign_t Scope::alignment()
+{
+ if (aligndecl)
+ return aligndecl->getAlignment(this);
+ else
+ return STRUCTALIGN_DEFAULT;
+}
+
+/************************************************
+ * Given the failed search attempt, try to find
+ * one with a close spelling.
+ */
+
+void *scope_search_fp(void *arg, const char *seed, int* cost)
+{
+ //printf("scope_search_fp('%s')\n", seed);
+
+ /* If not in the lexer's string table, it certainly isn't in the symbol table.
+ * Doing this first is a lot faster.
+ */
+ size_t len = strlen(seed);
+ if (!len)
+ return NULL;
+ Identifier *id = Identifier::lookup(seed, len);
+ if (!id)
+ return NULL;
+
+ Scope *sc = (Scope *)arg;
+ Module::clearCache();
+ Dsymbol *scopesym = NULL;
+ Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
+ if (s)
+ {
+ for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
+ if (sc->scopesym == scopesym)
+ break;
+ if (scopesym != s->parent)
+ {
+ (*cost)++; // got to the symbol through an import
+ if (s->prot().kind == PROTprivate)
+ return NULL;
+ }
+ }
+ return (void*)s;
+}
+
+void Scope::deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew)
+{
+ // Bugzilla 15857
+ //
+ // The overloadset found via the new lookup rules is either
+ // equal or a subset of the overloadset found via the old
+ // lookup rules, so it suffices to compare the dimension to
+ // check for equality.
+ OverloadSet *osold = NULL;
+ OverloadSet *osnew = NULL;
+ if (sold && (osold = sold->isOverloadSet()) != NULL &&
+ snew && (osnew = snew->isOverloadSet()) != NULL &&
+ osold->a.dim == osnew->a.dim)
+ return;
+
+ OutBuffer buf;
+ buf.writestring("local import search method found ");
+ if (osold)
+ buf.printf("%s %s (%d overloads)", sold->kind(), sold->toPrettyChars(), (int)osold->a.dim);
+ else if (sold)
+ buf.printf("%s %s", sold->kind(), sold->toPrettyChars());
+ else
+ buf.writestring("nothing");
+ buf.writestring(" instead of ");
+ if (osnew)
+ buf.printf("%s %s (%d overloads)", snew->kind(), snew->toPrettyChars(), (int)osnew->a.dim);
+ else if (snew)
+ buf.printf("%s %s", snew->kind(), snew->toPrettyChars());
+ else
+ buf.writestring("nothing");
+
+ deprecation(loc, "%s", buf.peekString());
+}
+
+Dsymbol *Scope::search_correct(Identifier *ident)
+{
+ if (global.gag)
+ return NULL; // don't do it for speculative compiles; too time consuming
+
+ return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
+}
+
+/************************************
+ * Maybe `ident` was a C or C++ name. Check for that,
+ * and suggest the D equivalent.
+ * Params:
+ * ident = unknown identifier
+ * Returns:
+ * D identifier string if found, null if not
+ */
+const char *Scope::search_correct_C(Identifier *ident)
+{
+ TOK tok;
+ if (ident == Id::_NULL)
+ tok = TOKnull;
+ else if (ident == Id::_TRUE)
+ tok = TOKtrue;
+ else if (ident == Id::_FALSE)
+ tok = TOKfalse;
+ else if (ident == Id::_unsigned)
+ tok = TOKuns32;
+ else
+ return NULL;
+ return Token::toChars(tok);
+}
diff --git a/gcc/d/dmd/dstruct.c b/gcc/d/dmd/dstruct.c
new file mode 100644
index 0000000..c99abce
--- /dev/null
+++ b/gcc/d/dmd/dstruct.c
@@ -0,0 +1,1463 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/struct.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root/root.h"
+#include "errors.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "init.h"
+#include "declaration.h"
+#include "module.h"
+#include "id.h"
+#include "statement.h"
+#include "template.h"
+#include "tokens.h"
+
+Type *getTypeInfoType(Type *t, Scope *sc);
+TypeTuple *toArgTypes(Type *t);
+void unSpeculative(Scope *sc, RootObject *o);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+
+FuncDeclaration *StructDeclaration::xerreq; // object.xopEquals
+FuncDeclaration *StructDeclaration::xerrcmp; // object.xopCmp
+
+/***************************************
+ * Search toString member function for TypeInfo_Struct.
+ * string toString();
+ */
+FuncDeclaration *search_toString(StructDeclaration *sd)
+{
+ Dsymbol *s = search_function(sd, Id::tostring);
+ FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
+ if (fd)
+ {
+ static TypeFunction *tftostring;
+ if (!tftostring)
+ {
+ tftostring = new TypeFunction(NULL, Type::tstring, 0, LINKd);
+ tftostring = (TypeFunction *)tftostring->merge();
+ }
+
+ fd = fd->overloadExactMatch(tftostring);
+ }
+ return fd;
+}
+
+/***************************************
+ * Request additonal semantic analysis for TypeInfo generation.
+ */
+void semanticTypeInfo(Scope *sc, Type *t)
+{
+ class FullTypeInfoVisitor : public Visitor
+ {
+ public:
+ Scope *sc;
+
+ void visit(Type *t)
+ {
+ Type *tb = t->toBasetype();
+ if (tb != t)
+ tb->accept(this);
+ }
+ void visit(TypeNext *t)
+ {
+ if (t->next)
+ t->next->accept(this);
+ }
+ void visit(TypeBasic *) { }
+ void visit(TypeVector *t)
+ {
+ t->basetype->accept(this);
+ }
+ void visit(TypeAArray *t)
+ {
+ t->index->accept(this);
+ visit((TypeNext *)t);
+ }
+ void visit(TypeFunction *t)
+ {
+ visit((TypeNext *)t);
+ // Currently TypeInfo_Function doesn't store parameter types.
+ }
+ void visit(TypeStruct *t)
+ {
+ StructDeclaration *sd = t->sym;
+
+ /* Step 1: create TypeInfoDeclaration
+ */
+ if (!sc) // inline may request TypeInfo.
+ {
+ Scope scx;
+ scx._module = sd->getModule();
+ getTypeInfoType(t, &scx);
+ sd->requestTypeInfo = true;
+ }
+ else if (!sc->minst)
+ {
+ // don't yet have to generate TypeInfo instance if
+ // the typeid(T) expression exists in speculative scope.
+ }
+ else
+ {
+ getTypeInfoType(t, sc);
+ sd->requestTypeInfo = true;
+
+ // Bugzilla 15149, if the typeid operand type comes from a
+ // result of auto function, it may be yet speculative.
+ unSpeculative(sc, sd);
+ }
+
+ /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
+ * This should be done even if typeid(T) exists in speculative scope.
+ * Because it may appear later in non-speculative scope.
+ */
+ if (!sd->members)
+ return; // opaque struct
+ if (!sd->xeq && !sd->xcmp && !sd->postblit &&
+ !sd->dtor && !sd->xhash && !search_toString(sd))
+ return; // none of TypeInfo-specific members
+
+ // If the struct is in a non-root module, run semantic3 to get
+ // correct symbols for the member function.
+ if (sd->semanticRun >= PASSsemantic3)
+ {
+ // semantic3 is already done
+ }
+ else if (TemplateInstance *ti = sd->isInstantiated())
+ {
+ if (ti->minst && !ti->minst->isRoot())
+ Module::addDeferredSemantic3(sd);
+ }
+ else
+ {
+ if (sd->inNonRoot())
+ {
+ //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), sd->inNonRoot());
+ Module::addDeferredSemantic3(sd);
+ }
+ }
+ }
+ void visit(TypeClass *) { }
+ void visit(TypeTuple *t)
+ {
+ if (t->arguments)
+ {
+ for (size_t i = 0; i < t->arguments->dim; i++)
+ {
+ Type *tprm = (*t->arguments)[i]->type;
+ if (tprm)
+ tprm->accept(this);
+ }
+ }
+ }
+ };
+
+ if (sc)
+ {
+ if (!sc->func)
+ return;
+ if (sc->intypeof)
+ return;
+ if (sc->flags & (SCOPEctfe | SCOPEcompile))
+ return;
+ }
+
+ FullTypeInfoVisitor v;
+ v.sc = sc;
+ t->accept(&v);
+}
+
+/********************************* AggregateDeclaration ****************************/
+
+AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
+ : ScopeDsymbol(id)
+{
+ this->loc = loc;
+
+ storage_class = 0;
+ protection = Prot(PROTpublic);
+ type = NULL;
+ structsize = 0; // size of struct
+ alignsize = 0; // size of struct for alignment purposes
+ sizeok = SIZEOKnone; // size not determined yet
+ deferred = NULL;
+ isdeprecated = false;
+ inv = NULL;
+ aggNew = NULL;
+ aggDelete = NULL;
+
+ stag = NULL;
+ sinit = NULL;
+ enclosing = NULL;
+ vthis = NULL;
+
+ ctor = NULL;
+ defaultCtor = NULL;
+ aliasthis = NULL;
+ noDefaultCtor = false;
+ dtor = NULL;
+ getRTInfo = NULL;
+}
+
+Prot AggregateDeclaration::prot()
+{
+ return protection;
+}
+
+/***************************************
+ * Create a new scope from sc.
+ * semantic, semantic2 and semantic3 will use this for aggregate members.
+ */
+Scope *AggregateDeclaration::newScope(Scope *sc)
+{
+ Scope *sc2 = sc->push(this);
+ sc2->stc &= STCsafe | STCtrusted | STCsystem;
+ sc2->parent = this;
+ if (isUnionDeclaration())
+ sc2->inunion = 1;
+ sc2->protection = Prot(PROTpublic);
+ sc2->explicitProtection = 0;
+ sc2->aligndecl = NULL;
+ sc2->userAttribDecl = NULL;
+ return sc2;
+}
+
+void AggregateDeclaration::setScope(Scope *sc)
+{
+ // Might need a scope to resolve forward references. The check for
+ // semanticRun prevents unnecessary setting of _scope during deferred
+ // setScope phases for aggregates which already finished semantic().
+ // Also see https://issues.dlang.org/show_bug.cgi?id=16607
+ if (semanticRun < PASSsemanticdone)
+ ScopeDsymbol::setScope(sc);
+}
+
+void AggregateDeclaration::semantic2(Scope *sc)
+{
+ //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
+ if (!members)
+ return;
+
+ if (_scope)
+ {
+ error("has forward references");
+ return;
+ }
+
+ Scope *sc2 = newScope(sc);
+
+ determineSize(loc);
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("\t[%d] %s\n", i, s->toChars());
+ s->semantic2(sc2);
+ }
+
+ sc2->pop();
+}
+
+void AggregateDeclaration::semantic3(Scope *sc)
+{
+ //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
+ if (!members)
+ return;
+
+ StructDeclaration *sd = isStructDeclaration();
+ if (!sc) // from runDeferredSemantic3 for TypeInfo generation
+ {
+ assert(sd);
+ sd->semanticTypeInfoMembers();
+ return;
+ }
+
+ Scope *sc2 = newScope(sc);
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic3(sc2);
+ }
+
+ sc2->pop();
+
+ // don't do it for unused deprecated types
+ // or error types
+ if (!getRTInfo && Type::rtinfo &&
+ (!isDeprecated() || global.params.useDeprecated != DIAGNOSTICerror) &&
+ (type && type->ty != Terror))
+ {
+ // Evaluate: RTinfo!type
+ Objects *tiargs = new Objects();
+ tiargs->push(type);
+ TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs);
+
+ Scope *sc3 = ti->tempdecl->_scope->startCTFE();
+ sc3->tinst = sc->tinst;
+ sc3->minst = sc->minst;
+ if (isDeprecated())
+ sc3->stc |= STCdeprecated;
+
+ ti->semantic(sc3);
+ ti->semantic2(sc3);
+ ti->semantic3(sc3);
+ Expression *e = resolve(Loc(), sc3, ti->toAlias(), false);
+
+ sc3->endCTFE();
+
+ e = e->ctfeInterpret();
+ getRTInfo = e;
+ }
+
+ if (sd)
+ sd->semanticTypeInfoMembers();
+}
+
+/***************************************
+ * Find all instance fields, then push them into `fields`.
+ *
+ * Runs semantic() for all instance field variables, but also
+ * the field types can reamin yet not resolved forward references,
+ * except direct recursive definitions.
+ * After the process sizeok is set to SIZEOKfwd.
+ *
+ * Returns:
+ * false if any errors occur.
+ */
+bool AggregateDeclaration::determineFields()
+{
+ if (sizeok != SIZEOKnone)
+ return true;
+
+ //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
+ fields.setDim(0);
+
+ struct SV
+ {
+ AggregateDeclaration *agg;
+
+ static int func(Dsymbol *s, void *param)
+ {
+ VarDeclaration *v = s->isVarDeclaration();
+ if (!v)
+ return 0;
+ if (v->storage_class & STCmanifest)
+ return 0;
+
+ AggregateDeclaration *ad = ((SV *)param)->agg;
+
+ if (v->_scope)
+ v->semantic(NULL);
+ // Note: Aggregate fields or size could have determined during v->semantic.
+ if (ad->sizeok != SIZEOKnone)
+ return 1;
+
+ if (v->aliassym)
+ return 0; // If this variable was really a tuple, skip it.
+
+ if (v->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter))
+ return 0;
+ if (!v->isField() || v->semanticRun < PASSsemanticdone)
+ return 1; // unresolvable forward reference
+
+ ad->fields.push(v);
+
+ if (v->storage_class & STCref)
+ return 0;
+ Type *tv = v->type->baseElemOf();
+ if (tv->ty != Tstruct)
+ return 0;
+ if (ad == ((TypeStruct *)tv)->sym)
+ {
+ const char *psz = (v->type->toBasetype()->ty == Tsarray) ? "static array of " : "";
+ ad->error("cannot have field %s with %ssame struct type", v->toChars(), psz);
+ ad->type = Type::terror;
+ ad->errors = true;
+ return 1;
+ }
+ return 0;
+ }
+ };
+ SV sv;
+ sv.agg = this;
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ if (s->apply(&SV::func, &sv))
+ {
+ if (sizeok != SIZEOKnone)
+ return true;
+ return false;
+ }
+ }
+
+ if (sizeok != SIZEOKdone)
+ sizeok = SIZEOKfwd;
+
+ return true;
+}
+
+/***************************************
+ * Collect all instance fields, then determine instance size.
+ * Returns:
+ * false if failed to determine the size.
+ */
+bool AggregateDeclaration::determineSize(Loc loc)
+{
+ //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
+
+ // The previous instance size finalizing had:
+ if (type->ty == Terror)
+ return false; // failed already
+ if (sizeok == SIZEOKdone)
+ return true; // succeeded
+
+ if (!members)
+ {
+ error(loc, "unknown size");
+ return false;
+ }
+
+ if (_scope)
+ semantic(NULL);
+
+ // Determine the instance size of base class first.
+ if (ClassDeclaration *cd = isClassDeclaration())
+ {
+ cd = cd->baseClass;
+ if (cd && !cd->determineSize(loc))
+ goto Lfail;
+ }
+
+ // Determine instance fields when sizeok == SIZEOKnone
+ if (!determineFields())
+ goto Lfail;
+ if (sizeok != SIZEOKdone)
+ finalizeSize();
+
+ // this aggregate type has:
+ if (type->ty == Terror)
+ return false; // marked as invalid during the finalizing.
+ if (sizeok == SIZEOKdone)
+ return true; // succeeded to calculate instance size.
+
+Lfail:
+ // There's unresolvable forward reference.
+ if (type != Type::terror)
+ error(loc, "no size because of forward reference");
+ // Don't cache errors from speculative semantic, might be resolvable later.
+ // https://issues.dlang.org/show_bug.cgi?id=16574
+ if (!global.gag)
+ {
+ type = Type::terror;
+ errors = true;
+ }
+ return false;
+}
+
+void StructDeclaration::semanticTypeInfoMembers()
+{
+ if (xeq &&
+ xeq->_scope &&
+ xeq->semanticRun < PASSsemantic3done)
+ {
+ unsigned errors = global.startGagging();
+ xeq->semantic3(xeq->_scope);
+ if (global.endGagging(errors))
+ xeq = xerreq;
+ }
+
+ if (xcmp &&
+ xcmp->_scope &&
+ xcmp->semanticRun < PASSsemantic3done)
+ {
+ unsigned errors = global.startGagging();
+ xcmp->semantic3(xcmp->_scope);
+ if (global.endGagging(errors))
+ xcmp = xerrcmp;
+ }
+
+ FuncDeclaration *ftostr = search_toString(this);
+ if (ftostr &&
+ ftostr->_scope &&
+ ftostr->semanticRun < PASSsemantic3done)
+ {
+ ftostr->semantic3(ftostr->_scope);
+ }
+
+ if (xhash &&
+ xhash->_scope &&
+ xhash->semanticRun < PASSsemantic3done)
+ {
+ xhash->semantic3(xhash->_scope);
+ }
+
+ if (postblit &&
+ postblit->_scope &&
+ postblit->semanticRun < PASSsemantic3done)
+ {
+ postblit->semantic3(postblit->_scope);
+ }
+
+ if (dtor &&
+ dtor->_scope &&
+ dtor->semanticRun < PASSsemantic3done)
+ {
+ dtor->semantic3(dtor->_scope);
+ }
+}
+
+d_uns64 AggregateDeclaration::size(Loc loc)
+{
+ //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
+ bool ok = determineSize(loc);
+ //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
+ return ok ? structsize : SIZE_INVALID;
+}
+
+Type *AggregateDeclaration::getType()
+{
+ return type;
+}
+
+bool AggregateDeclaration::isDeprecated()
+{
+ return isdeprecated;
+}
+
+bool AggregateDeclaration::isExport() const
+{
+ return protection.kind == PROTexport;
+}
+
+/***************************************
+ * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
+ * field initializers have unique memory space on instance.
+ * Returns:
+ * true if any errors happen.
+ */
+
+bool AggregateDeclaration::checkOverlappedFields()
+{
+ //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
+ assert(sizeok == SIZEOKdone);
+ size_t nfields = fields.dim;
+ if (isNested())
+ {
+ ClassDeclaration *cd = isClassDeclaration();
+ if (!cd || !cd->baseClass || !cd->baseClass->isNested())
+ nfields--;
+ }
+ bool errors = false;
+
+ // Fill in missing any elements with default initializers
+ for (size_t i = 0; i < nfields; i++)
+ {
+ VarDeclaration *vd = fields[i];
+ if (vd->errors)
+ {
+ errors = true;
+ continue;
+ }
+
+ VarDeclaration *vx = vd;
+ if (vd->_init && vd->_init->isVoidInitializer())
+ vx = NULL;
+
+ // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
+ for (size_t j = 0; j < nfields; j++)
+ {
+ if (i == j)
+ continue;
+ VarDeclaration *v2 = fields[j];
+ if (v2->errors)
+ {
+ errors = true;
+ continue;
+ }
+ if (!vd->isOverlappedWith(v2))
+ continue;
+
+ // vd and v2 are overlapping.
+ vd->overlapped = true;
+ v2->overlapped = true;
+
+ if (!MODimplicitConv(vd->type->mod, v2->type->mod))
+ v2->overlapUnsafe = true;
+ if (!MODimplicitConv(v2->type->mod, vd->type->mod))
+ vd->overlapUnsafe = true;
+
+ if (!vx)
+ continue;
+ if (v2->_init && v2->_init->isVoidInitializer())
+ continue;
+
+ if (vx->_init && v2->_init)
+ {
+ ::error(loc, "overlapping default initialization for field %s and %s", v2->toChars(), vd->toChars());
+ errors = true;
+ }
+ }
+ }
+ return errors;
+}
+
+/***************************************
+ * Fill out remainder of elements[] with default initializers for fields[].
+ * Input:
+ * loc: location
+ * elements: explicit arguments which given to construct object.
+ * ctorinit: true if the elements will be used for default initialization.
+ * Returns:
+ * false if any errors occur.
+ * Otherwise, returns true and the missing arguments will be pushed in elements[].
+ */
+bool AggregateDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit)
+{
+ //printf("AggregateDeclaration::fill() %s\n", toChars());
+ assert(sizeok == SIZEOKdone);
+ assert(elements);
+ size_t nfields = fields.dim - isNested();
+ bool errors = false;
+
+ size_t dim = elements->dim;
+ elements->setDim(nfields);
+ for (size_t i = dim; i < nfields; i++)
+ (*elements)[i] = NULL;
+
+ // Fill in missing any elements with default initializers
+ for (size_t i = 0; i < nfields; i++)
+ {
+ if ((*elements)[i])
+ continue;
+
+ VarDeclaration *vd = fields[i];
+ VarDeclaration *vx = vd;
+ if (vd->_init && vd->_init->isVoidInitializer())
+ vx = NULL;
+
+ // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
+ size_t fieldi = i;
+ for (size_t j = 0; j < nfields; j++)
+ {
+ if (i == j)
+ continue;
+ VarDeclaration *v2 = fields[j];
+ if (!vd->isOverlappedWith(v2))
+ continue;
+
+ if ((*elements)[j])
+ {
+ vx = NULL;
+ break;
+ }
+ if (v2->_init && v2->_init->isVoidInitializer())
+ continue;
+
+ if (1)
+ {
+ /* Prefer first found non-void-initialized field
+ * union U { int a; int b = 2; }
+ * U u; // Error: overlapping initialization for field a and b
+ */
+ if (!vx)
+ {
+ vx = v2;
+ fieldi = j;
+ }
+ else if (v2->_init)
+ {
+ ::error(loc, "overlapping initialization for field %s and %s",
+ v2->toChars(), vd->toChars());
+ errors = true;
+ }
+ }
+ else
+ {
+ // Will fix Bugzilla 1432 by enabling this path always
+
+ /* Prefer explicitly initialized field
+ * union U { int a; int b = 2; }
+ * U u; // OK (u.b == 2)
+ */
+ if (!vx || (!vx->_init && v2->_init))
+ {
+ vx = v2;
+ fieldi = j;
+ }
+ else if (vx != vd && !vx->isOverlappedWith(v2))
+ {
+ // Both vx and v2 fills vd, but vx and v2 does not overlap
+ }
+ else if (vx->_init && v2->_init)
+ {
+ ::error(loc, "overlapping default initialization for field %s and %s",
+ v2->toChars(), vd->toChars());
+ errors = true;
+ }
+ else
+ assert(vx->_init || (!vx->_init && !v2->_init));
+ }
+ }
+ if (vx)
+ {
+ Expression *e;
+ if (vx->type->size() == 0)
+ {
+ e = NULL;
+ }
+ else if (vx->_init)
+ {
+ assert(!vx->_init->isVoidInitializer());
+ e = vx->getConstInitializer(false);
+ }
+ else
+ {
+ if ((vx->storage_class & STCnodefaultctor) && !ctorinit)
+ {
+ ::error(loc, "field %s.%s must be initialized because it has no default constructor",
+ type->toChars(), vx->toChars());
+ errors = true;
+ }
+
+ /* Bugzilla 12509: Get the element of static array type.
+ */
+ Type *telem = vx->type;
+ if (telem->ty == Tsarray)
+ {
+ /* We cannot use Type::baseElemOf() here.
+ * If the bottom of the Tsarray is an enum type, baseElemOf()
+ * will return the base of the enum, and its default initializer
+ * would be different from the enum's.
+ */
+ while (telem->toBasetype()->ty == Tsarray)
+ telem = ((TypeSArray *)telem->toBasetype())->next;
+
+ if (telem->ty == Tvoid)
+ telem = Type::tuns8->addMod(telem->mod);
+ }
+ if (telem->needsNested() && ctorinit)
+ e = telem->defaultInit(loc);
+ else
+ e = telem->defaultInitLiteral(loc);
+ }
+ (*elements)[fieldi] = e;
+ }
+ }
+
+ for (size_t i = 0; i < elements->dim; i++)
+ {
+ Expression *e = (*elements)[i];
+ if (e && e->op == TOKerror)
+ return false;
+ }
+
+ return !errors;
+}
+
+/****************************
+ * Do byte or word alignment as necessary.
+ * Align sizes of 0, as we may not know array sizes yet.
+ *
+ * alignment: struct alignment that is in effect
+ * size: alignment requirement of field
+ */
+
+void AggregateDeclaration::alignmember(
+ structalign_t alignment,
+ unsigned size,
+ unsigned *poffset)
+{
+ //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
+ switch (alignment)
+ {
+ case (structalign_t) 1:
+ // No alignment
+ break;
+
+ case (structalign_t) STRUCTALIGN_DEFAULT:
+ // Alignment in Target::fieldalignsize must match what the
+ // corresponding C compiler's default alignment behavior is.
+ assert(size > 0 && !(size & (size - 1)));
+ *poffset = (*poffset + size - 1) & ~(size - 1);
+ break;
+
+ default:
+ // Align on alignment boundary, which must be a positive power of 2
+ assert(alignment > 0 && !(alignment & (alignment - 1)));
+ *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
+ break;
+ }
+}
+
+/****************************************
+ * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
+ * Returns:
+ * offset to place field at
+ *
+ * nextoffset: next location in aggregate
+ * memsize: size of member
+ * memalignsize: natural alignment of member
+ * alignment: alignment in effect for this member
+ * paggsize: size of aggregate (updated)
+ * paggalignsize: alignment of aggregate (updated)
+ * isunion: the aggregate is a union
+ */
+unsigned AggregateDeclaration::placeField(
+ unsigned *nextoffset,
+ unsigned memsize,
+ unsigned memalignsize,
+ structalign_t alignment,
+ unsigned *paggsize,
+ unsigned *paggalignsize,
+ bool isunion
+ )
+{
+ unsigned ofs = *nextoffset;
+
+ const unsigned actualAlignment =
+ alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
+
+ alignmember(alignment, memalignsize, &ofs);
+ unsigned memoffset = ofs;
+ ofs += memsize;
+ if (ofs > *paggsize)
+ *paggsize = ofs;
+ if (!isunion)
+ *nextoffset = ofs;
+
+ if (*paggalignsize < actualAlignment)
+ *paggalignsize = actualAlignment;
+
+ return memoffset;
+}
+
+
+/****************************************
+ * Returns true if there's an extra member which is the 'this'
+ * pointer to the enclosing context (enclosing aggregate or function)
+ */
+
+bool AggregateDeclaration::isNested()
+{
+ return enclosing != NULL;
+}
+
+/* Append vthis field (this->tupleof[$-1]) to make this aggregate type nested.
+ */
+void AggregateDeclaration::makeNested()
+{
+ if (enclosing) // if already nested
+ return;
+ if (sizeok == SIZEOKdone)
+ return;
+ if (isUnionDeclaration() || isInterfaceDeclaration())
+ return;
+ if (storage_class & STCstatic)
+ return;
+
+ // If nested struct, add in hidden 'this' pointer to outer scope
+ Dsymbol *s = toParent2();
+ if (!s)
+ return;
+ Type *t = NULL;
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ enclosing = fd;
+
+ /* Bugzilla 14422: If a nested class parent is a function, its
+ * context pointer (== `outer`) should be void* always.
+ */
+ t = Type::tvoidptr;
+ }
+ else if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+ {
+ if (isClassDeclaration() && ad->isClassDeclaration())
+ {
+ enclosing = ad;
+ }
+ else if (isStructDeclaration())
+ {
+ if (TemplateInstance *ti = ad->parent->isTemplateInstance())
+ {
+ enclosing = ti->enclosing;
+ }
+ }
+
+ t = ad->handleType();
+ }
+ if (enclosing)
+ {
+ //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars());
+ assert(t);
+ if (t->ty == Tstruct)
+ t = Type::tvoidptr; // t should not be a ref type
+ assert(!vthis);
+ vthis = new ThisDeclaration(loc, t);
+ //vthis->storage_class |= STCref;
+
+ // Emulate vthis->addMember()
+ members->push(vthis);
+
+ // Emulate vthis->semantic()
+ vthis->storage_class |= STCfield;
+ vthis->parent = this;
+ vthis->protection = Prot(PROTpublic);
+ vthis->alignment = t->alignment();
+ vthis->semanticRun = PASSsemanticdone;
+
+ if (sizeok == SIZEOKfwd)
+ fields.push(vthis);
+ }
+}
+
+/*******************************************
+ * Look for constructor declaration.
+ */
+Dsymbol *AggregateDeclaration::searchCtor()
+{
+ Dsymbol *s = search(Loc(), Id::ctor);
+ if (s)
+ {
+ if (!(s->isCtorDeclaration() ||
+ s->isTemplateDeclaration() ||
+ s->isOverloadSet()))
+ {
+ s->error("is not a constructor; identifiers starting with __ are reserved for the implementation");
+ errors = true;
+ s = NULL;
+ }
+ }
+ if (s && s->toParent() != this)
+ s = NULL; // search() looks through ancestor classes
+ if (s)
+ {
+ // Finish all constructors semantics to determine this->noDefaultCtor.
+ struct SearchCtor
+ {
+ static int fp(Dsymbol *s, void *)
+ {
+ CtorDeclaration *f = s->isCtorDeclaration();
+ if (f && f->semanticRun == PASSinit)
+ f->semantic(NULL);
+ return 0;
+ }
+ };
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *sm = (*members)[i];
+ sm->apply(&SearchCtor::fp, NULL);
+ }
+ }
+ return s;
+}
+
+/********************************* StructDeclaration ****************************/
+
+StructDeclaration::StructDeclaration(Loc loc, Identifier *id, bool inObject)
+ : AggregateDeclaration(loc, id)
+{
+ zeroInit = 0; // assume false until we do semantic processing
+ hasIdentityAssign = false;
+ hasIdentityEquals = false;
+ postblit = NULL;
+
+ xeq = NULL;
+ xcmp = NULL;
+ xhash = NULL;
+ alignment = 0;
+ ispod = ISPODfwd;
+ arg1type = NULL;
+ arg2type = NULL;
+ requestTypeInfo = false;
+
+ // For forward references
+ type = new TypeStruct(this);
+
+ if (inObject)
+ {
+ if (id == Id::ModuleInfo && !Module::moduleinfo)
+ Module::moduleinfo = this;
+ }
+}
+
+StructDeclaration *StructDeclaration::create(Loc loc, Identifier *id, bool inObject)
+{
+ return new StructDeclaration(loc, id, inObject);
+}
+
+Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
+{
+ StructDeclaration *sd =
+ s ? (StructDeclaration *)s
+ : new StructDeclaration(loc, ident, false);
+ return ScopeDsymbol::syntaxCopy(sd);
+}
+
+void StructDeclaration::semantic(Scope *sc)
+{
+ //printf("StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
+
+ //static int count; if (++count == 20) halt();
+
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ unsigned errors = global.errors;
+
+ //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
+ Scope *scx = NULL;
+ if (_scope)
+ {
+ sc = _scope;
+ scx = _scope; // save so we don't make redundant copies
+ _scope = NULL;
+ }
+
+ if (!parent)
+ {
+ assert(sc->parent && sc->func);
+ parent = sc->parent;
+ }
+ assert(parent && !isAnonymous());
+
+ if (this->errors)
+ type = Type::terror;
+ if (semanticRun == PASSinit)
+ type = type->addSTC(sc->stc | storage_class);
+ type = type->semantic(loc, sc);
+
+ if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
+ {
+ TemplateInstance *ti = ((TypeStruct *)type)->sym->isInstantiated();
+ if (ti && isError(ti))
+ ((TypeStruct *)type)->sym = this;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = ungagSpeculative();
+
+ if (semanticRun == PASSinit)
+ {
+ protection = sc->protection;
+
+ alignment = sc->alignment();
+
+ storage_class |= sc->stc;
+ if (storage_class & STCdeprecated)
+ isdeprecated = true;
+ if (storage_class & STCabstract)
+ error("structs, unions cannot be abstract");
+ userAttribDecl = sc->userAttribDecl;
+ }
+ else if (symtab && !scx)
+ {
+ return;
+ }
+ semanticRun = PASSsemantic;
+
+ if (!members) // if opaque declaration
+ {
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+ if (!symtab)
+ {
+ symtab = new DsymbolTable();
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
+ s->addMember(sc, this);
+ }
+ }
+
+ Scope *sc2 = newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("struct: setScope %s %s\n", s->kind(), s->toChars());
+ s->setScope(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->importAll(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic(sc2);
+ }
+
+ if (!determineFields())
+ {
+ assert(type->ty == Terror);
+ sc2->pop();
+ semanticRun = PASSsemanticdone;
+ return;
+ }
+
+ /* Following special member functions creation needs semantic analysis
+ * completion of sub-structs in each field types. For example, buildDtor
+ * needs to check existence of elaborate dtor in type of each fields.
+ * See the case in compilable/test14838.d
+ */
+ for (size_t i = 0; i < fields.dim; i++)
+ {
+ VarDeclaration *v = fields[i];
+ Type *tb = v->type->baseElemOf();
+ if (tb->ty != Tstruct)
+ continue;
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ if (sd->semanticRun >= PASSsemanticdone)
+ continue;
+
+ sc2->pop();
+
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ _scope->_module->addDeferredSemantic(this);
+
+ //printf("\tdeferring %s\n", toChars());
+ return;
+ }
+
+ /* Look for special member functions.
+ */
+ aggNew = (NewDeclaration *)search(Loc(), Id::classNew);
+ aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);
+
+ // Look for the constructor
+ ctor = searchCtor();
+
+ dtor = buildDtor(this, sc2);
+ postblit = buildPostBlit(this, sc2);
+
+ buildOpAssign(this, sc2);
+ buildOpEquals(this, sc2);
+
+ xeq = buildXopEquals(this, sc2);
+ xcmp = buildXopCmp(this, sc2);
+ xhash = buildXtoHash(this, sc2);
+
+ inv = buildInv(this, sc2);
+
+ Module::dprogress++;
+ semanticRun = PASSsemanticdone;
+ //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());
+
+ sc2->pop();
+
+ if (ctor)
+ {
+ Dsymbol *scall = search(Loc(), Id::call);
+ if (scall)
+ {
+ unsigned xerrors = global.startGagging();
+ sc = sc->push();
+ sc->tinst = NULL;
+ sc->minst = NULL;
+ FuncDeclaration *fcall = resolveFuncCall(loc, sc, scall, NULL, NULL, NULL, 1);
+ sc = sc->pop();
+ global.endGagging(xerrors);
+
+ if (fcall && fcall->isStatic())
+ {
+ error(fcall->loc, "static opCall is hidden by constructors and can never be called");
+ errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with static opCall.");
+ }
+ }
+ }
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ type = Type::terror;
+ this->errors = true;
+ if (deferred)
+ deferred->errors = true;
+ }
+
+ if (deferred && !global.gag)
+ {
+ deferred->semantic2(sc);
+ deferred->semantic3(sc);
+ }
+
+ assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this);
+}
+
+Dsymbol *StructDeclaration::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
+
+ if (_scope && !symtab)
+ semantic(_scope);
+
+ if (!members || !symtab) // opaque or semantic() is not yet called
+ {
+ error("is forward referenced when looking for '%s'", ident->toChars());
+ return NULL;
+ }
+
+ return ScopeDsymbol::search(loc, ident, flags);
+}
+
+void StructDeclaration::finalizeSize()
+{
+ //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
+ assert(sizeok != SIZEOKdone);
+
+ //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);
+
+ fields.setDim(0); // workaround
+
+ // Set the offsets of the fields and determine the size of the struct
+ unsigned offset = 0;
+ bool isunion = isUnionDeclaration() != NULL;
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->setFieldOffset(this, &offset, isunion);
+ }
+ if (type->ty == Terror)
+ return;
+
+ // 0 sized struct's are set to 1 byte
+ if (structsize == 0)
+ {
+ structsize = 1;
+ alignsize = 1;
+ }
+
+ // Round struct size up to next alignsize boundary.
+ // This will ensure that arrays of structs will get their internals
+ // aligned properly.
+ if (alignment == STRUCTALIGN_DEFAULT)
+ structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+ else
+ structsize = (structsize + alignment - 1) & ~(alignment - 1);
+
+ sizeok = SIZEOKdone;
+
+ //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);
+
+ if (errors)
+ return;
+
+ // Calculate fields[i]->overlapped
+ if (checkOverlappedFields())
+ {
+ errors = true;
+ return;
+ }
+
+ // Determine if struct is all zeros or not
+ zeroInit = 1;
+ for (size_t i = 0; i < fields.dim; i++)
+ {
+ VarDeclaration *vd = fields[i];
+ if (vd->_init)
+ {
+ // Should examine init to see if it is really all 0's
+ zeroInit = 0;
+ break;
+ }
+ else if (!vd->type->isZeroInit(loc))
+ {
+ zeroInit = 0;
+ break;
+ }
+ }
+
+ TypeTuple *tt = toArgTypes(type);
+ size_t dim = tt->arguments->dim;
+ if (dim >= 1)
+ {
+ assert(dim <= 2);
+ arg1type = (*tt->arguments)[0]->type;
+ if (dim == 2)
+ arg2type = (*tt->arguments)[1]->type;
+ }
+}
+
+/***************************************
+ * Fit elements[] to the corresponding type of field[].
+ * Input:
+ * loc
+ * sc
+ * elements The explicit arguments that given to construct object.
+ * stype The constructed object type.
+ * Returns false if any errors occur.
+ * Otherwise, returns true and elements[] are rewritten for the output.
+ */
+bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype)
+{
+ if (!elements)
+ return true;
+
+ size_t nfields = fields.dim - isNested();
+ size_t offset = 0;
+ for (size_t i = 0; i < elements->dim; i++)
+ {
+ Expression *e = (*elements)[i];
+ if (!e)
+ continue;
+
+ e = resolveProperties(sc, e);
+ if (i >= nfields)
+ {
+ if (i == fields.dim - 1 && isNested() && e->op == TOKnull)
+ {
+ // CTFE sometimes creates null as hidden pointer; we'll allow this.
+ continue;
+ }
+ ::error(loc, "more initializers than fields (%d) of %s", (int)nfields, toChars());
+ return false;
+ }
+ VarDeclaration *v = fields[i];
+ if (v->offset < offset)
+ {
+ ::error(loc, "overlapping initialization for %s", v->toChars());
+ return false;
+ }
+ offset = (unsigned)(v->offset + v->type->size());
+
+ Type *t = v->type;
+ if (stype)
+ t = t->addMod(stype->mod);
+ Type *origType = t;
+ Type *tb = t->toBasetype();
+
+ /* Look for case of initializing a static array with a too-short
+ * string literal, such as:
+ * char[5] foo = "abc";
+ * Allow this by doing an explicit cast, which will lengthen the string
+ * literal.
+ */
+ if (e->op == TOKstring && tb->ty == Tsarray)
+ {
+ StringExp *se = (StringExp *)e;
+ Type *typeb = se->type->toBasetype();
+ TY tynto = tb->nextOf()->ty;
+ if (!se->committed &&
+ (typeb->ty == Tarray || typeb->ty == Tsarray) &&
+ (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
+ se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
+ {
+ e = se->castTo(sc, t);
+ goto L1;
+ }
+ }
+
+ while (!e->implicitConvTo(t) && tb->ty == Tsarray)
+ {
+ /* Static array initialization, as in:
+ * T[3][5] = e;
+ */
+ t = tb->nextOf();
+ tb = t->toBasetype();
+ }
+ if (!e->implicitConvTo(t))
+ t = origType; // restore type for better diagnostic
+
+ e = e->implicitCastTo(sc, t);
+ L1:
+ if (e->op == TOKerror)
+ return false;
+
+ (*elements)[i] = doCopyOrMove(sc, e);
+ }
+ return true;
+}
+
+/***************************************
+ * Return true if struct is POD (Plain Old Data).
+ * This is defined as:
+ * not nested
+ * no postblits, destructors, or assignment operators
+ * no 'ref' fields or fields that are themselves non-POD
+ * The idea being these are compatible with C structs.
+ */
+bool StructDeclaration::isPOD()
+{
+ // If we've already determined whether this struct is POD.
+ if (ispod != ISPODfwd)
+ return (ispod == ISPODyes);
+
+ ispod = ISPODyes;
+
+ if (enclosing || postblit || dtor)
+ ispod = ISPODno;
+
+ // Recursively check all fields are POD.
+ for (size_t i = 0; i < fields.dim; i++)
+ {
+ VarDeclaration *v = fields[i];
+ if (v->storage_class & STCref)
+ {
+ ispod = ISPODno;
+ break;
+ }
+
+ Type *tv = v->type->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)tv;
+ StructDeclaration *sd = ts->sym;
+ if (!sd->isPOD())
+ {
+ ispod = ISPODno;
+ break;
+ }
+ }
+ }
+
+ return (ispod == ISPODyes);
+}
+
+const char *StructDeclaration::kind()
+{
+ return "struct";
+}
+
+/********************************* UnionDeclaration ****************************/
+
+UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
+ : StructDeclaration(loc, id, false)
+{
+}
+
+Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ UnionDeclaration *ud = new UnionDeclaration(loc, ident);
+ return StructDeclaration::syntaxCopy(ud);
+}
+
+const char *UnionDeclaration::kind()
+{
+ return "union";
+}
diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c
new file mode 100644
index 0000000..0f0a0dc
--- /dev/null
+++ b/gcc/d/dmd/dsymbol.c
@@ -0,0 +1,1781 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/dsymbol.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <limits.h>
+
+#include "root/rmem.h"
+#include "root/speller.h"
+#include "root/aav.h"
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "identifier.h"
+#include "module.h"
+#include "mtype.h"
+#include "expression.h"
+#include "statement.h"
+#include "declaration.h"
+#include "id.h"
+#include "scope.h"
+#include "init.h"
+#include "import.h"
+#include "template.h"
+#include "attrib.h"
+#include "enum.h"
+#include "lexer.h"
+
+bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
+typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
+int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
+Expression *semantic(Expression *e, Scope *sc);
+
+
+/****************************** Dsymbol ******************************/
+
+Dsymbol::Dsymbol()
+{
+ //printf("Dsymbol::Dsymbol(%p)\n", this);
+ this->ident = NULL;
+ this->parent = NULL;
+ this->csym = NULL;
+ this->isym = NULL;
+ this->loc = Loc();
+ this->comment = NULL;
+ this->_scope = NULL;
+ this->prettystring = NULL;
+ this->semanticRun = PASSinit;
+ this->errors = false;
+ this->depdecl = NULL;
+ this->userAttribDecl = NULL;
+ this->ddocUnittest = NULL;
+}
+
+Dsymbol::Dsymbol(Identifier *ident)
+{
+ //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
+ this->ident = ident;
+ this->parent = NULL;
+ this->csym = NULL;
+ this->isym = NULL;
+ this->loc = Loc();
+ this->comment = NULL;
+ this->_scope = NULL;
+ this->prettystring = NULL;
+ this->semanticRun = PASSinit;
+ this->errors = false;
+ this->depdecl = NULL;
+ this->userAttribDecl = NULL;
+ this->ddocUnittest = NULL;
+}
+
+Dsymbol *Dsymbol::create(Identifier *ident)
+{
+ return new Dsymbol(ident);
+}
+
+bool Dsymbol::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ Dsymbol *s = (Dsymbol *)(o);
+ // Overload sets don't have an ident
+ if (s && ident && s->ident && ident->equals(s->ident))
+ return true;
+ return false;
+}
+
+/**************************************
+ * Copy the syntax.
+ * Used for template instantiations.
+ * If s is NULL, allocate the new object, otherwise fill it in.
+ */
+
+Dsymbol *Dsymbol::syntaxCopy(Dsymbol *)
+{
+ print();
+ printf("%s %s\n", kind(), toChars());
+ assert(0);
+ return NULL;
+}
+
+/**************************************
+ * Determine if this symbol is only one.
+ * Returns:
+ * false, *ps = NULL: There are 2 or more symbols
+ * true, *ps = NULL: There are zero symbols
+ * true, *ps = symbol: The one and only one symbol
+ */
+
+bool Dsymbol::oneMember(Dsymbol **ps, Identifier *)
+{
+ //printf("Dsymbol::oneMember()\n");
+ *ps = this;
+ return true;
+}
+
+/*****************************************
+ * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
+ */
+
+bool Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident)
+{
+ //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0);
+ Dsymbol *s = NULL;
+
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *sx = (*members)[i];
+ bool x = sx->oneMember(ps, ident);
+ //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps);
+ if (!x)
+ {
+ //printf("\tfalse 1\n");
+ assert(*ps == NULL);
+ return false;
+ }
+ if (*ps)
+ {
+ assert(ident);
+ if (!(*ps)->ident || !(*ps)->ident->equals(ident))
+ continue;
+ if (!s)
+ s = *ps;
+ else if (s->isOverloadable() && (*ps)->isOverloadable())
+ {
+ // keep head of overload set
+ FuncDeclaration *f1 = s->isFuncDeclaration();
+ FuncDeclaration *f2 = (*ps)->isFuncDeclaration();
+ if (f1 && f2)
+ {
+ assert(!f1->isFuncAliasDeclaration());
+ assert(!f2->isFuncAliasDeclaration());
+ for (; f1 != f2; f1 = f1->overnext0)
+ {
+ if (f1->overnext0 == NULL)
+ {
+ f1->overnext0 = f2;
+ break;
+ }
+ }
+ }
+ }
+ else // more than one symbol
+ {
+ *ps = NULL;
+ //printf("\tfalse 2\n");
+ return false;
+ }
+ }
+ }
+ }
+ *ps = s; // s is the one symbol, NULL if none
+ //printf("\ttrue\n");
+ return true;
+}
+
+/*****************************************
+ * Is Dsymbol a variable that contains pointers?
+ */
+
+bool Dsymbol::hasPointers()
+{
+ //printf("Dsymbol::hasPointers() %s\n", toChars());
+ return false;
+}
+
+bool Dsymbol::hasStaticCtorOrDtor()
+{
+ //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
+ return false;
+}
+
+void Dsymbol::setFieldOffset(AggregateDeclaration *, unsigned *, bool)
+{
+}
+
+Identifier *Dsymbol::getIdent()
+{
+ return ident;
+}
+
+const char *Dsymbol::toChars()
+{
+ return ident ? ident->toChars() : "__anonymous";
+}
+
+const char *Dsymbol::toPrettyCharsHelper()
+{
+ return toChars();
+}
+
+const char *Dsymbol::toPrettyChars(bool QualifyTypes)
+{
+ if (prettystring && !QualifyTypes)
+ return (const char *)prettystring;
+
+ //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
+ if (!parent)
+ {
+ const char *s = toChars();
+ if (!QualifyTypes)
+ prettystring = (const utf8_t *)s;
+ return s;
+ }
+
+ // Computer number of components
+ size_t complength = 0;
+ for (Dsymbol *p = this; p; p = p->parent)
+ ++complength;
+
+ // Allocate temporary array comp[]
+ const char **comp = (const char **)malloc(complength * sizeof(char**));
+ if (!comp)
+ Mem::error();
+
+ // Fill in comp[] and compute length of final result
+ size_t length = 0;
+ int i = 0;
+ for (Dsymbol *p = this; p; p = p->parent)
+ {
+ const char *s = QualifyTypes ? p->toPrettyCharsHelper() : p->toChars();
+ const size_t len = strlen(s);
+ comp[i] = s;
+ ++i;
+ length += len + 1;
+ }
+
+ char *s = (char *)mem.xmalloc(length);
+ char *q = s + length - 1;
+ *q = 0;
+ for (size_t j = 0; j < complength; j++)
+ {
+ const char *t = comp[j];
+ const size_t len = strlen(t);
+ q -= len;
+ memcpy(q, t, len);
+ if (q == s)
+ break;
+ *--q = '.';
+ }
+ free(comp);
+ if (!QualifyTypes)
+ prettystring = (utf8_t *)s;
+ return s;
+}
+
+Loc& Dsymbol::getLoc()
+{
+ if (!loc.filename) // avoid bug 5861.
+ {
+ Module *m = getModule();
+
+ if (m && m->srcfile)
+ loc.filename = m->srcfile->toChars();
+ }
+ return loc;
+}
+
+const char *Dsymbol::locToChars()
+{
+ return getLoc().toChars();
+}
+
+const char *Dsymbol::kind()
+{
+ return "symbol";
+}
+
+/*********************************
+ * If this symbol is really an alias for another,
+ * return that other.
+ * If needed, semantic() is invoked due to resolve forward reference.
+ */
+Dsymbol *Dsymbol::toAlias()
+{
+ return this;
+}
+
+/*********************************
+ * Resolve recursive tuple expansion in eponymous template.
+ */
+Dsymbol *Dsymbol::toAlias2()
+{
+ return toAlias();
+}
+
+Dsymbol *Dsymbol::pastMixin()
+{
+ Dsymbol *s = this;
+
+ //printf("Dsymbol::pastMixin() %s\n", toChars());
+ while (s && s->isTemplateMixin())
+ s = s->parent;
+ return s;
+}
+
+/**********************************
+ * `parent` field returns a lexically enclosing scope symbol this is a member of.
+ *
+ * `toParent()` returns a logically enclosing scope symbol this is a member of.
+ * It skips over TemplateMixin's.
+ *
+ * `toParent2()` returns an enclosing scope symbol this is living at runtime.
+ * It skips over both TemplateInstance's and TemplateMixin's.
+ * It's used when looking for the 'this' pointer of the enclosing function/class.
+ *
+ * Examples:
+ * module mod;
+ * template Foo(alias a) { mixin Bar!(); }
+ * mixin template Bar() {
+ * public { // ProtDeclaration
+ * void baz() { a = 2; }
+ * }
+ * }
+ * void test() {
+ * int v = 1;
+ * alias foo = Foo!(v);
+ * foo.baz();
+ * assert(v == 2);
+ * }
+ *
+ * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
+ * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
+ * // s.toParent() == TemplateInstance('mod.test.Foo!()')
+ * // s.toParent2() == FuncDeclaration('mod.test')
+ */
+Dsymbol *Dsymbol::toParent()
+{
+ return parent ? parent->pastMixin() : NULL;
+}
+
+/// ditto
+Dsymbol *Dsymbol::toParent2()
+{
+ Dsymbol *s = parent;
+ while (s && s->isTemplateInstance())
+ s = s->parent;
+ return s;
+}
+
+TemplateInstance *Dsymbol::isInstantiated()
+{
+ for (Dsymbol *s = parent; s; s = s->parent)
+ {
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti && !ti->isTemplateMixin())
+ return ti;
+ }
+ return NULL;
+}
+
+// Check if this function is a member of a template which has only been
+// instantiated speculatively, eg from inside is(typeof()).
+// Return the speculative template instance it is part of,
+// or NULL if not speculative.
+TemplateInstance *Dsymbol::isSpeculative()
+{
+ Dsymbol *par = parent;
+ while (par)
+ {
+ TemplateInstance *ti = par->isTemplateInstance();
+ if (ti && ti->gagged)
+ return ti;
+ par = par->toParent();
+ }
+ return NULL;
+}
+
+Ungag Dsymbol::ungagSpeculative()
+{
+ unsigned oldgag = global.gag;
+
+ if (global.gag && !isSpeculative() && !toParent2()->isFuncDeclaration())
+ global.gag = 0;
+
+ return Ungag(oldgag);
+}
+
+bool Dsymbol::isAnonymous()
+{
+ return ident == NULL;
+}
+
+/*************************************
+ * Set scope for future semantic analysis so we can
+ * deal better with forward references.
+ */
+
+void Dsymbol::setScope(Scope *sc)
+{
+ //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc);
+ if (!sc->nofree)
+ sc->setNoFree(); // may need it even after semantic() finishes
+ _scope = sc;
+ if (sc->depdecl)
+ depdecl = sc->depdecl;
+
+ if (!userAttribDecl)
+ userAttribDecl = sc->userAttribDecl;
+}
+
+void Dsymbol::importAll(Scope *)
+{
+}
+
+/*************************************
+ * Does semantic analysis on the public face of declarations.
+ */
+
+void Dsymbol::semantic(Scope *)
+{
+ error("%p has no semantic routine", this);
+}
+
+/*************************************
+ * Does semantic analysis on initializers and members of aggregates.
+ */
+
+void Dsymbol::semantic2(Scope *)
+{
+ // Most Dsymbols have no further semantic analysis needed
+}
+
+/*************************************
+ * Does semantic analysis on function bodies.
+ */
+
+void Dsymbol::semantic3(Scope *)
+{
+ // Most Dsymbols have no further semantic analysis needed
+}
+
+/*********************************************
+ * Search for ident as member of s.
+ * Params:
+ * loc = location to print for error messages
+ * ident = identifier to search for
+ * flags = IgnoreXXXX
+ * Returns:
+ * NULL if not found
+ */
+
+Dsymbol *Dsymbol::search(const Loc &, Identifier *, int)
+{
+ //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
+ return NULL;
+}
+
+/***************************************************
+ * Search for symbol with correct spelling.
+ */
+
+void *symbol_search_fp(void *arg, const char *seed, int *cost)
+{
+ /* If not in the lexer's string table, it certainly isn't in the symbol table.
+ * Doing this first is a lot faster.
+ */
+ size_t len = strlen(seed);
+ if (!len)
+ return NULL;
+ Identifier *id = Identifier::lookup(seed, len);
+ if (!id)
+ return NULL;
+
+ *cost = 0;
+ Dsymbol *s = (Dsymbol *)arg;
+ Module::clearCache();
+ return (void *)s->search(Loc(), id, IgnoreErrors);
+}
+
+Dsymbol *Dsymbol::search_correct(Identifier *ident)
+{
+ if (global.gag)
+ return NULL; // don't do it for speculative compiles; too time consuming
+
+ return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, (void *)this, idchars);
+}
+
+/***************************************
+ * Search for identifier id as a member of 'this'.
+ * id may be a template instance.
+ * Returns:
+ * symbol found, NULL if not
+ */
+Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
+{
+ //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
+ Dsymbol *s = toAlias();
+ Dsymbol *sm;
+
+ if (Declaration *d = s->isDeclaration())
+ {
+ if (d->inuse)
+ {
+ ::error(loc, "circular reference to '%s'", d->toPrettyChars());
+ return NULL;
+ }
+ }
+
+ switch (id->dyncast())
+ {
+ case DYNCAST_IDENTIFIER:
+ sm = s->search(loc, (Identifier *)id);
+ break;
+
+ case DYNCAST_DSYMBOL:
+ {
+ // It's a template instance
+ //printf("\ttemplate instance id\n");
+ Dsymbol *st = (Dsymbol *)id;
+ TemplateInstance *ti = st->isTemplateInstance();
+ sm = s->search(loc, ti->name);
+ if (!sm)
+ {
+ sm = s->search_correct(ti->name);
+ if (sm)
+ ::error(loc, "template identifier '%s' is not a member of %s '%s', did you mean %s '%s'?",
+ ti->name->toChars(), s->kind(), s->toPrettyChars(), sm->kind(), sm->toChars());
+ else
+ ::error(loc, "template identifier '%s' is not a member of %s '%s'",
+ ti->name->toChars(), s->kind(), s->toPrettyChars());
+ return NULL;
+ }
+ sm = sm->toAlias();
+ TemplateDeclaration *td = sm->isTemplateDeclaration();
+ if (!td)
+ {
+ ::error(loc, "%s.%s is not a template, it is a %s", s->toPrettyChars(), ti->name->toChars(), sm->kind());
+ return NULL;
+ }
+ ti->tempdecl = td;
+ if (!ti->semanticRun)
+ ti->semantic(sc);
+ sm = ti->toAlias();
+ break;
+ }
+
+ case DYNCAST_TYPE:
+ case DYNCAST_EXPRESSION:
+ default:
+ assert(0);
+ }
+ return sm;
+}
+
+bool Dsymbol::overloadInsert(Dsymbol *)
+{
+ //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
+ return false;
+}
+
+d_uns64 Dsymbol::size(Loc)
+{
+ error("Dsymbol '%s' has no size", toChars());
+ return SIZE_INVALID;
+}
+
+bool Dsymbol::isforwardRef()
+{
+ return false;
+}
+
+AggregateDeclaration *Dsymbol::isThis()
+{
+ return NULL;
+}
+
+bool Dsymbol::isExport() const
+{
+ return false;
+}
+
+bool Dsymbol::isImportedSymbol() const
+{
+ return false;
+}
+
+bool Dsymbol::isDeprecated()
+{
+ return false;
+}
+
+bool Dsymbol::isOverloadable()
+{
+ return false;
+}
+
+LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()?
+{
+ return NULL;
+}
+
+/// Returns an AggregateDeclaration when toParent() is that.
+AggregateDeclaration *Dsymbol::isMember()
+{
+ //printf("Dsymbol::isMember() %s\n", toChars());
+ Dsymbol *parent = toParent();
+ //printf("parent is %s %s\n", parent->kind(), parent->toChars());
+ return parent ? parent->isAggregateDeclaration() : NULL;
+}
+
+/// Returns an AggregateDeclaration when toParent2() is that.
+AggregateDeclaration *Dsymbol::isMember2()
+{
+ //printf("Dsymbol::isMember2() %s\n", toChars());
+ Dsymbol *parent = toParent2();
+ //printf("parent is %s %s\n", parent->kind(), parent->toChars());
+ return parent ? parent->isAggregateDeclaration() : NULL;
+}
+
+// is this a member of a ClassDeclaration?
+ClassDeclaration *Dsymbol::isClassMember()
+{
+ AggregateDeclaration *ad = isMember();
+ return ad ? ad->isClassDeclaration() : NULL;
+}
+
+Type *Dsymbol::getType()
+{
+ return NULL;
+}
+
+bool Dsymbol::needThis()
+{
+ return false;
+}
+
+/*********************************
+ * Iterate this dsymbol or members of this scoped dsymbol, then
+ * call `fp` with the found symbol and `param`.
+ * Params:
+ * fp = function pointer to process the iterated symbol.
+ * If it returns nonzero, the iteration will be aborted.
+ * param = a parameter passed to fp.
+ * Returns:
+ * nonzero if the iteration is aborted by the return value of fp,
+ * or 0 if it's completed.
+ */
+int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+ return (*fp)(this, param);
+}
+
+void Dsymbol::addMember(Scope *, ScopeDsymbol *sds)
+{
+ //printf("Dsymbol::addMember('%s')\n", toChars());
+ //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds->toChars());
+ //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds->symtab = %p)\n", this, toChars(), sds, sds->symtab);
+ parent = sds;
+ if (!isAnonymous()) // no name, so can't add it to symbol table
+ {
+ if (!sds->symtabInsert(this)) // if name is already defined
+ {
+ Dsymbol *s2 = sds->symtabLookup(this, ident);
+ if (!s2->overloadInsert(this))
+ {
+ sds->multiplyDefined(Loc(), this, s2);
+ errors = true;
+ }
+ }
+ if (sds->isAggregateDeclaration() || sds->isEnumDeclaration())
+ {
+ if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof)
+ {
+ error(".%s property cannot be redefined", ident->toChars());
+ errors = true;
+ }
+ }
+ }
+}
+
+void Dsymbol::error(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::verror(getLoc(), format, ap, kind(), toPrettyChars());
+ va_end(ap);
+}
+
+void Dsymbol::error(Loc loc, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::verror(loc, format, ap, kind(), toPrettyChars());
+ va_end(ap);
+}
+
+void Dsymbol::deprecation(Loc loc, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::vdeprecation(loc, format, ap, kind(), toPrettyChars());
+ va_end(ap);
+}
+
+void Dsymbol::deprecation(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::vdeprecation(getLoc(), format, ap, kind(), toPrettyChars());
+ va_end(ap);
+}
+
+void Dsymbol::checkDeprecated(Loc loc, Scope *sc)
+{
+ if (global.params.useDeprecated != DIAGNOSTICoff && isDeprecated())
+ {
+ // Don't complain if we're inside a deprecated symbol's scope
+ for (Dsymbol *sp = sc->parent; sp; sp = sp->parent)
+ {
+ if (sp->isDeprecated())
+ goto L1;
+ }
+
+ for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing)
+ {
+ if (sc2->scopesym && sc2->scopesym->isDeprecated())
+ goto L1;
+
+ // If inside a StorageClassDeclaration that is deprecated
+ if (sc2->stc & STCdeprecated)
+ goto L1;
+ }
+
+ const char *message = NULL;
+ for (Dsymbol *p = this; p; p = p->parent)
+ {
+ message = p->depdecl ? p->depdecl->getMessage() : NULL;
+ if (message)
+ break;
+ }
+
+ if (message)
+ deprecation(loc, "is deprecated - %s", message);
+ else
+ deprecation(loc, "is deprecated");
+ }
+
+ L1:
+ Declaration *d = isDeclaration();
+ if (d && d->storage_class & STCdisable)
+ {
+ if (!(sc->func && sc->func->storage_class & STCdisable))
+ {
+ if (d->toParent() && d->isPostBlitDeclaration())
+ d->toParent()->error(loc, "is not copyable because it is annotated with @disable");
+ else
+ error(loc, "is not callable because it is annotated with @disable");
+ }
+ }
+}
+
+/**********************************
+ * Determine which Module a Dsymbol is in.
+ */
+
+Module *Dsymbol::getModule()
+{
+ //printf("Dsymbol::getModule()\n");
+ if (TemplateInstance *ti = isInstantiated())
+ return ti->tempdecl->getModule();
+
+ Dsymbol *s = this;
+ while (s)
+ {
+ //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
+ Module *m = s->isModule();
+ if (m)
+ return m;
+ s = s->parent;
+ }
+ return NULL;
+}
+
+/**********************************
+ * Determine which Module a Dsymbol is in, as far as access rights go.
+ */
+
+Module *Dsymbol::getAccessModule()
+{
+ //printf("Dsymbol::getAccessModule()\n");
+ if (TemplateInstance *ti = isInstantiated())
+ return ti->tempdecl->getAccessModule();
+
+ Dsymbol *s = this;
+ while (s)
+ {
+ //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
+ Module *m = s->isModule();
+ if (m)
+ return m;
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti && ti->enclosing)
+ {
+ /* Because of local template instantiation, the parent isn't where the access
+ * rights come from - it's the template declaration
+ */
+ s = ti->tempdecl;
+ }
+ else
+ s = s->parent;
+ }
+ return NULL;
+}
+
+/*************************************
+ */
+
+Prot Dsymbol::prot()
+{
+ return Prot(PROTpublic);
+}
+
+/*************************************
+ * Do syntax copy of an array of Dsymbol's.
+ */
+
+Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a)
+{
+
+ Dsymbols *b = NULL;
+ if (a)
+ {
+ b = a->copy();
+ for (size_t i = 0; i < b->dim; i++)
+ {
+ (*b)[i] = (*b)[i]->syntaxCopy(NULL);
+ }
+ }
+ return b;
+}
+
+/****************************************
+ * Add documentation comment to Dsymbol.
+ * Ignore NULL comments.
+ */
+
+void Dsymbol::addComment(const utf8_t *comment)
+{
+ //if (comment)
+ //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
+
+ if (!this->comment)
+ this->comment = comment;
+ else if (comment && strcmp((const char *)comment, (const char *)this->comment) != 0)
+ { // Concatenate the two
+ this->comment = Lexer::combineComments(this->comment, comment);
+ }
+}
+
+/****************************************
+ * Returns true if this symbol is defined in a non-root module without instantiation.
+ */
+bool Dsymbol::inNonRoot()
+{
+ Dsymbol *s = parent;
+ for (; s; s = s->toParent())
+ {
+ if (s->isTemplateInstance())
+ {
+ return false;
+ }
+ if (Module *m = s->isModule())
+ {
+ if (!m->isRoot())
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
+/********************************* OverloadSet ****************************/
+
+OverloadSet::OverloadSet(Identifier *ident, OverloadSet *os)
+ : Dsymbol(ident)
+{
+ if (os)
+ {
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ a.push(os->a[i]);
+ }
+ }
+}
+
+void OverloadSet::push(Dsymbol *s)
+{
+ a.push(s);
+}
+
+const char *OverloadSet::kind()
+{
+ return "overloadset";
+}
+
+
+/********************************* ScopeDsymbol ****************************/
+
+ScopeDsymbol::ScopeDsymbol()
+ : Dsymbol()
+{
+ members = NULL;
+ symtab = NULL;
+ endlinnum = 0;
+ importedScopes = NULL;
+ prots = NULL;
+}
+
+ScopeDsymbol::ScopeDsymbol(Identifier *id)
+ : Dsymbol(id)
+{
+ members = NULL;
+ symtab = NULL;
+ endlinnum = 0;
+ importedScopes = NULL;
+ prots = NULL;
+}
+
+Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
+{
+ //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
+ ScopeDsymbol *sds = s ? (ScopeDsymbol *)s : new ScopeDsymbol(ident);
+ sds->members = arraySyntaxCopy(members);
+ sds->endlinnum = endlinnum;
+ return sds;
+}
+
+void ScopeDsymbol::semantic(Scope *)
+{
+}
+
+/*****************************************
+ * This function is #1 on the list of functions that eat cpu time.
+ * Be very, very careful about slowing it down.
+ */
+
+Dsymbol *ScopeDsymbol::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
+ //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0;
+
+ // Look in symbols declared in this module
+ if (symtab && !(flags & SearchImportsOnly))
+ {
+ //printf(" look in locals\n");
+ Dsymbol *s1 = symtab->lookup(ident);
+ if (s1)
+ {
+ //printf("\tfound in locals = '%s.%s'\n",toChars(),s1->toChars());
+ return s1;
+ }
+ }
+ //printf(" not found in locals\n");
+
+ // Look in imported scopes
+ if (importedScopes)
+ {
+ //printf(" look in imports\n");
+ Dsymbol *s = NULL;
+ OverloadSet *a = NULL;
+
+ // Look in imported modules
+ for (size_t i = 0; i < importedScopes->dim; i++)
+ {
+ // If private import, don't search it
+ if ((flags & IgnorePrivateImports) && prots[i] == PROTprivate)
+ continue;
+
+ int sflags = flags & (IgnoreErrors | IgnoreAmbiguous | IgnoreSymbolVisibility); // remember these in recursive searches
+ Dsymbol *ss = (*importedScopes)[i];
+
+ //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
+
+ if (ss->isModule())
+ {
+ if (flags & SearchLocalsOnly)
+ continue;
+ }
+ else // mixin template
+ {
+ if (flags & SearchImportsOnly)
+ continue;
+ // compatibility with -transition=import (Bugzilla 15925)
+ // SearchLocalsOnly should always get set for new lookup rules
+ sflags |= (flags & SearchLocalsOnly);
+ }
+
+ /* Don't find private members if ss is a module
+ */
+ Dsymbol *s2 = ss->search(loc, ident, sflags | (ss->isModule() ? IgnorePrivateImports : IgnoreNone));
+ if (!s2 || (!(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2)))
+ continue;
+ if (!s)
+ {
+ s = s2;
+ if (s && s->isOverloadSet())
+ a = mergeOverloadSet(ident, a, s);
+ }
+ else if (s2 && s != s2)
+ {
+ if (s->toAlias() == s2->toAlias() ||
+ (s->getType() == s2->getType() && s->getType()))
+ {
+ /* After following aliases, we found the same
+ * symbol, so it's not an ambiguity. But if one
+ * alias is deprecated or less accessible, prefer
+ * the other.
+ */
+ if (s->isDeprecated() ||
+ (s->prot().isMoreRestrictiveThan(s2->prot()) && s2->prot().kind != PROTnone))
+ s = s2;
+ }
+ else
+ {
+ /* Two imports of the same module should be regarded as
+ * the same.
+ */
+ Import *i1 = s->isImport();
+ Import *i2 = s2->isImport();
+ if (!(i1 && i2 &&
+ (i1->mod == i2->mod ||
+ (!i1->parent->isImport() && !i2->parent->isImport() &&
+ i1->ident->equals(i2->ident))
+ )
+ )
+ )
+ {
+ /* Bugzilla 8668:
+ * Public selective import adds AliasDeclaration in module.
+ * To make an overload set, resolve aliases in here and
+ * get actual overload roots which accessible via s and s2.
+ */
+ s = s->toAlias();
+ s2 = s2->toAlias();
+
+ /* If both s2 and s are overloadable (though we only
+ * need to check s once)
+ */
+ if ((s2->isOverloadSet() || s2->isOverloadable()) &&
+ (a || s->isOverloadable()))
+ {
+ a = mergeOverloadSet(ident, a, s2);
+ continue;
+ }
+ if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
+ return NULL;
+ if (!(flags & IgnoreErrors))
+ ScopeDsymbol::multiplyDefined(loc, s, s2);
+ break;
+ }
+ }
+ }
+ }
+
+ if (s)
+ {
+ /* Build special symbol if we had multiple finds
+ */
+ if (a)
+ {
+ if (!s->isOverloadSet())
+ a = mergeOverloadSet(ident, a, s);
+ s = a;
+ }
+
+ // TODO: remove once private symbol visibility has been deprecated
+ if (!(flags & IgnoreErrors) && s->prot().kind == PROTprivate &&
+ !s->isOverloadable() && !s->parent->isTemplateMixin() && !s->parent->isNspace())
+ {
+ AliasDeclaration *ad;
+ // accessing private selective and renamed imports is
+ // deprecated by restricting the symbol visibility
+ if (s->isImport() || ((ad = s->isAliasDeclaration()) != NULL && ad->_import != NULL))
+ {}
+ else
+ error(loc, "%s %s is private", s->kind(), s->toPrettyChars());
+ }
+ //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
+ return s;
+ }
+ //printf(" not found in imports\n");
+ }
+
+ return NULL;
+}
+
+OverloadSet *ScopeDsymbol::mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s)
+{
+ if (!os)
+ {
+ os = new OverloadSet(ident);
+ os->parent = this;
+ }
+ if (OverloadSet *os2 = s->isOverloadSet())
+ {
+ // Merge the cross-module overload set 'os2' into 'os'
+ if (os->a.dim == 0)
+ {
+ os->a.setDim(os2->a.dim);
+ memcpy(os->a.tdata(), os2->a.tdata(), sizeof(os->a[0]) * os2->a.dim);
+ }
+ else
+ {
+ for (size_t i = 0; i < os2->a.dim; i++)
+ {
+ os = mergeOverloadSet(ident, os, os2->a[i]);
+ }
+ }
+ }
+ else
+ {
+ assert(s->isOverloadable());
+
+ /* Don't add to os[] if s is alias of previous sym
+ */
+ for (size_t j = 0; j < os->a.dim; j++)
+ {
+ Dsymbol *s2 = os->a[j];
+ if (s->toAlias() == s2->toAlias())
+ {
+ if (s2->isDeprecated() ||
+ (s2->prot().isMoreRestrictiveThan(s->prot()) &&
+ s->prot().kind != PROTnone))
+ {
+ os->a[j] = s;
+ }
+ goto Lcontinue;
+ }
+ }
+ os->push(s);
+ Lcontinue:
+ ;
+ }
+ return os;
+}
+
+void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
+{
+ //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);
+
+ // No circular or redundant import's
+ if (s != this)
+ {
+ if (!importedScopes)
+ importedScopes = new Dsymbols();
+ else
+ {
+ for (size_t i = 0; i < importedScopes->dim; i++)
+ {
+ Dsymbol *ss = (*importedScopes)[i];
+ if (ss == s) // if already imported
+ {
+ if (protection.kind > prots[i])
+ prots[i] = protection.kind; // upgrade access
+ return;
+ }
+ }
+ }
+ importedScopes->push(s);
+ prots = (PROTKIND *)mem.xrealloc(prots, importedScopes->dim * sizeof(prots[0]));
+ prots[importedScopes->dim - 1] = protection.kind;
+ }
+}
+
+static void bitArraySet(BitArray *array, size_t idx)
+{
+ array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] |= 1 << (idx & (sizeof(size_t) * CHAR_BIT - 1));
+}
+
+static bool bitArrayGet(BitArray *array, size_t idx)
+{
+ return (array->ptr[idx / (sizeof(size_t) * CHAR_BIT)] & (1 << (idx & (sizeof(size_t) * CHAR_BIT - 1)))) != 0;
+}
+
+static void bitArrayLength(BitArray *array, size_t len)
+{
+ size_t obytes = (array->len + CHAR_BIT - 1) / CHAR_BIT;
+ size_t nbytes = (len + CHAR_BIT - 1) / CHAR_BIT;
+
+ if (obytes < nbytes)
+ {
+ if (!array->ptr)
+ array->ptr = (size_t *)mem.xmalloc(nbytes * sizeof(size_t));
+ else
+ array->ptr = (size_t *)mem.xrealloc(array->ptr, nbytes * sizeof(size_t));
+
+ for (size_t i = obytes; i < nbytes; i++)
+ array->ptr[i] = 0;
+ }
+ array->len = len;
+}
+
+void ScopeDsymbol::addAccessiblePackage(Package *p, Prot protection)
+{
+ BitArray *pary = protection.kind == PROTprivate ? &privateAccessiblePackages : &accessiblePackages;
+ if (pary->len <= p->tag)
+ bitArrayLength(pary, p->tag + 1);
+ bitArraySet(pary, p->tag);
+}
+
+bool ScopeDsymbol::isPackageAccessible(Package *p, Prot protection, int)
+{
+ if ((p->tag < accessiblePackages.len && bitArrayGet(&accessiblePackages, p->tag)) ||
+ (protection.kind == PROTprivate && p->tag < privateAccessiblePackages.len && bitArrayGet(&privateAccessiblePackages, p->tag)))
+ return true;
+ if (importedScopes)
+ {
+ for (size_t i = 0; i < importedScopes->dim; i++)
+ {
+ // only search visible scopes && imported modules should ignore private imports
+ Dsymbol *ss = (*importedScopes)[i];
+ if (protection.kind <= prots[i] &&
+ ss->isScopeDsymbol()->isPackageAccessible(p, protection, IgnorePrivateImports))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ScopeDsymbol::isforwardRef()
+{
+ return (members == NULL);
+}
+
+void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2)
+{
+ if (loc.filename)
+ { ::error(loc, "%s at %s conflicts with %s at %s",
+ s1->toPrettyChars(),
+ s1->locToChars(),
+ s2->toPrettyChars(),
+ s2->locToChars());
+ }
+ else
+ {
+ s1->error(s1->loc, "conflicts with %s %s at %s",
+ s2->kind(),
+ s2->toPrettyChars(),
+ s2->locToChars());
+ }
+}
+
+const char *ScopeDsymbol::kind()
+{
+ return "ScopeDsymbol";
+}
+
+Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s)
+{
+ return symtab->insert(s);
+}
+
+/****************************************
+ * Look up identifier in symbol table.
+ */
+
+Dsymbol *ScopeDsymbol::symtabLookup(Dsymbol *, Identifier *id)
+{
+ return symtab->lookup(id);
+}
+
+/****************************************
+ * Return true if any of the members are static ctors or static dtors, or if
+ * any members have members that are.
+ */
+
+bool ScopeDsymbol::hasStaticCtorOrDtor()
+{
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ { Dsymbol *member = (*members)[i];
+
+ if (member->hasStaticCtorOrDtor())
+ return true;
+ }
+ }
+ return false;
+}
+
+/***************************************
+ * Determine number of Dsymbols, folding in AttribDeclaration members.
+ */
+
+static int dimDg(void *ctx, size_t, Dsymbol *)
+{
+ ++*(size_t *)ctx;
+ return 0;
+}
+
+size_t ScopeDsymbol::dim(Dsymbols *members)
+{
+ size_t n = 0;
+ ScopeDsymbol_foreach(NULL, members, &dimDg, &n);
+ return n;
+}
+
+/***************************************
+ * Get nth Dsymbol, folding in AttribDeclaration members.
+ * Returns:
+ * Dsymbol* nth Dsymbol
+ * NULL not found, *pn gets incremented by the number
+ * of Dsymbols
+ */
+
+struct GetNthSymbolCtx
+{
+ size_t nth;
+ Dsymbol *sym;
+};
+
+static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym)
+{
+ GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx;
+ if (n == p->nth)
+ { p->sym = sym;
+ return 1;
+ }
+ return 0;
+}
+
+Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *)
+{
+ GetNthSymbolCtx ctx = { nth, NULL };
+ int res = ScopeDsymbol_foreach(NULL, members, &getNthSymbolDg, &ctx);
+ return res ? ctx.sym : NULL;
+}
+
+/***************************************
+ * Expands attribute declarations in members in depth first
+ * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each
+ * member.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ */
+
+int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn)
+{
+ assert(dg);
+ if (!members)
+ return 0;
+
+ size_t n = pn ? *pn : 0; // take over index
+ int result = 0;
+ for (size_t i = 0; i < members->dim; i++)
+ { Dsymbol *s = (*members)[i];
+
+ if (AttribDeclaration *a = s->isAttribDeclaration())
+ result = ScopeDsymbol_foreach(sc, a->include(sc, NULL), dg, ctx, &n);
+ else if (TemplateMixin *tm = s->isTemplateMixin())
+ result = ScopeDsymbol_foreach(sc, tm->members, dg, ctx, &n);
+ else if (s->isTemplateInstance())
+ ;
+ else if (s->isUnitTestDeclaration())
+ ;
+ else
+ result = dg(ctx, n++, s);
+
+ if (result)
+ break;
+ }
+
+ if (pn)
+ *pn = n; // update index
+ return result;
+}
+
+/*******************************************
+ * Look for member of the form:
+ * const(MemberInfo)[] getMembers(string);
+ * Returns NULL if not found
+ */
+
+FuncDeclaration *ScopeDsymbol::findGetMembers()
+{
+ Dsymbol *s = search_function(this, Id::getmembers);
+ FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
+
+ if (fdx && fdx->isVirtual())
+ fdx = NULL;
+
+ return fdx;
+}
+
+
+/****************************** WithScopeSymbol ******************************/
+
+WithScopeSymbol::WithScopeSymbol(WithStatement *withstate)
+ : ScopeDsymbol()
+{
+ this->withstate = withstate;
+}
+
+Dsymbol *WithScopeSymbol::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("WithScopeSymbol::search(%s)\n", ident->toChars());
+ if (flags & SearchImportsOnly)
+ return NULL;
+
+ // Acts as proxy to the with class declaration
+ Dsymbol *s = NULL;
+ Expression *eold = NULL;
+ for (Expression *e = withstate->exp; e != eold; e = resolveAliasThis(_scope, e))
+ {
+ if (e->op == TOKscope)
+ {
+ s = ((ScopeExp *)e)->sds;
+ }
+ else if (e->op == TOKtype)
+ {
+ s = e->type->toDsymbol(NULL);
+ }
+ else
+ {
+ Type *t = e->type->toBasetype();
+ s = t->toDsymbol(NULL);
+ }
+ if (s)
+ {
+ s = s->search(loc, ident, flags);
+ if (s)
+ return s;
+ }
+ eold = e;
+ }
+ return NULL;
+}
+
+/****************************** ArrayScopeSymbol ******************************/
+
+ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e)
+ : ScopeDsymbol()
+{
+ assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray);
+ exp = e;
+ type = NULL;
+ td = NULL;
+ this->sc = sc;
+}
+
+ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t)
+ : ScopeDsymbol()
+{
+ exp = NULL;
+ type = t;
+ td = NULL;
+ this->sc = sc;
+}
+
+ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s)
+ : ScopeDsymbol()
+{
+ exp = NULL;
+ type = NULL;
+ td = s;
+ this->sc = sc;
+}
+
+Dsymbol *ArrayScopeSymbol::search(const Loc &loc, Identifier *ident, int)
+{
+ //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
+ if (ident == Id::dollar)
+ {
+ VarDeclaration **pvar;
+ Expression *ce;
+
+ L1:
+ if (td)
+ {
+ /* $ gives the number of elements in the tuple
+ */
+ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
+ Expression *e = new IntegerExp(Loc(), td->objects->dim, Type::tsize_t);
+ v->_init = new ExpInitializer(Loc(), e);
+ v->storage_class |= STCtemp | STCstatic | STCconst;
+ v->semantic(sc);
+ return v;
+ }
+
+ if (type)
+ {
+ /* $ gives the number of type entries in the type tuple
+ */
+ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
+ Expression *e = new IntegerExp(Loc(), type->arguments->dim, Type::tsize_t);
+ v->_init = new ExpInitializer(Loc(), e);
+ v->storage_class |= STCtemp | STCstatic | STCconst;
+ v->semantic(sc);
+ return v;
+ }
+
+ if (exp->op == TOKindex)
+ {
+ /* array[index] where index is some function of $
+ */
+ IndexExp *ie = (IndexExp *)exp;
+ pvar = &ie->lengthVar;
+ ce = ie->e1;
+ }
+ else if (exp->op == TOKslice)
+ {
+ /* array[lwr .. upr] where lwr or upr is some function of $
+ */
+ SliceExp *se = (SliceExp *)exp;
+ pvar = &se->lengthVar;
+ ce = se->e1;
+ }
+ else if (exp->op == TOKarray)
+ {
+ /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
+ * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
+ */
+ ArrayExp *ae = (ArrayExp *)exp;
+ pvar = &ae->lengthVar;
+ ce = ae->e1;
+ }
+ else
+ {
+ /* Didn't find $, look in enclosing scope(s).
+ */
+ return NULL;
+ }
+
+ while (ce->op == TOKcomma)
+ ce = ((CommaExp *)ce)->e2;
+
+ /* If we are indexing into an array that is really a type
+ * tuple, rewrite this as an index into a type tuple and
+ * try again.
+ */
+ if (ce->op == TOKtype)
+ {
+ Type *t = ((TypeExp *)ce)->type;
+ if (t->ty == Ttuple)
+ {
+ type = (TypeTuple *)t;
+ goto L1;
+ }
+ }
+
+ /* *pvar is lazily initialized, so if we refer to $
+ * multiple times, it gets set only once.
+ */
+ if (!*pvar) // if not already initialized
+ {
+ /* Create variable v and set it to the value of $
+ */
+ VarDeclaration *v;
+ Type *t;
+ if (ce->op == TOKtuple)
+ {
+ /* It is for an expression tuple, so the
+ * length will be a const.
+ */
+ Expression *e = new IntegerExp(Loc(), ((TupleExp *)ce)->exps->dim, Type::tsize_t);
+ v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(Loc(), e));
+ v->storage_class |= STCtemp | STCstatic | STCconst;
+ }
+ else if (ce->type && (t = ce->type->toBasetype()) != NULL &&
+ (t->ty == Tstruct || t->ty == Tclass))
+ {
+ // Look for opDollar
+ assert(exp->op == TOKarray || exp->op == TOKslice);
+ AggregateDeclaration *ad = isAggregate(t);
+ assert(ad);
+
+ Dsymbol *s = ad->search(loc, Id::opDollar);
+ if (!s) // no dollar exists -- search in higher scope
+ return NULL;
+ s = s->toAlias();
+
+ Expression *e = NULL;
+ // Check for multi-dimensional opDollar(dim) template.
+ if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ {
+ dinteger_t dim = 0;
+ if (exp->op == TOKarray)
+ {
+ dim = ((ArrayExp *)exp)->currentDimension;
+ }
+ else if (exp->op == TOKslice)
+ {
+ dim = 0; // slices are currently always one-dimensional
+ }
+ else
+ {
+ assert(0);
+ }
+
+ Objects *tiargs = new Objects();
+ Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t);
+ edim = ::semantic(edim, sc);
+ tiargs->push(edim);
+ e = new DotTemplateInstanceExp(loc, ce, td->ident, tiargs);
+ }
+ else
+ {
+ /* opDollar exists, but it's not a template.
+ * This is acceptable ONLY for single-dimension indexing.
+ * Note that it's impossible to have both template & function opDollar,
+ * because both take no arguments.
+ */
+ if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->dim != 1)
+ {
+ exp->error("%s only defines opDollar for one dimension", ad->toChars());
+ return NULL;
+ }
+ Declaration *d = s->isDeclaration();
+ assert(d);
+ e = new DotVarExp(loc, ce, d);
+ }
+ e = ::semantic(e, sc);
+ if (!e->type)
+ exp->error("%s has no value", e->toChars());
+ t = e->type->toBasetype();
+ if (t && t->ty == Tfunction)
+ e = new CallExp(e->loc, e);
+ v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e));
+ v->storage_class |= STCtemp | STCctfe | STCrvalue;
+ }
+ else
+ {
+ /* For arrays, $ will either be a compile-time constant
+ * (in which case its value in set during constant-folding),
+ * or a variable (in which case an expression is created in
+ * toir.c).
+ */
+ VoidInitializer *e = new VoidInitializer(Loc());
+ e->type = Type::tsize_t;
+ v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e);
+ v->storage_class |= STCtemp | STCctfe; // it's never a true static variable
+ }
+ *pvar = v;
+ }
+ (*pvar)->semantic(sc);
+ return (*pvar);
+ }
+ return NULL;
+}
+
+
+/****************************** DsymbolTable ******************************/
+
+DsymbolTable::DsymbolTable()
+{
+ tab = NULL;
+}
+
+Dsymbol *DsymbolTable::lookup(Identifier const * const ident)
+{
+ //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string);
+ return (Dsymbol *)dmd_aaGetRvalue(tab, const_cast<void *>((const void *)ident));
+}
+
+Dsymbol *DsymbolTable::insert(Dsymbol *s)
+{
+ //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars());
+ Identifier *ident = s->ident;
+ Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
+ if (*ps)
+ return NULL; // already in table
+ *ps = s;
+ return s;
+}
+
+Dsymbol *DsymbolTable::insert(Identifier const * const ident, Dsymbol *s)
+{
+ //printf("DsymbolTable::insert()\n");
+ Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, const_cast<void *>((const void *)ident));
+ if (*ps)
+ return NULL; // already in table
+ *ps = s;
+ return s;
+}
+
+Dsymbol *DsymbolTable::update(Dsymbol *s)
+{
+ Identifier *ident = s->ident;
+ Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
+ *ps = s;
+ return s;
+}
+
+/****************************** Prot ******************************/
+
+Prot::Prot()
+{
+ this->kind = PROTundefined;
+ this->pkg = NULL;
+}
+
+Prot::Prot(PROTKIND kind)
+{
+ this->kind = kind;
+ this->pkg = NULL;
+}
+
+/**
+ * Checks if `this` is superset of `other` restrictions.
+ * For example, "protected" is more restrictive than "public".
+ */
+bool Prot::isMoreRestrictiveThan(const Prot other) const
+{
+ return this->kind < other.kind;
+}
+
+/**
+ * Checks if `this` is absolutely identical protection attribute to `other`
+ */
+bool Prot::operator==(const Prot& other) const
+{
+ if (this->kind == other.kind)
+ {
+ if (this->kind == PROTpackage)
+ return this->pkg == other.pkg;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Checks if parent defines different access restrictions than this one.
+ *
+ * Params:
+ * parent = protection attribute for scope that hosts this one
+ *
+ * Returns:
+ * 'true' if parent is already more restrictive than this one and thus
+ * no differentiation is needed.
+ */
+bool Prot::isSubsetOf(const Prot& parent) const
+{
+ if (this->kind != parent.kind)
+ return false;
+
+ if (this->kind == PROTpackage)
+ {
+ if (!this->pkg)
+ return true;
+ if (!parent.pkg)
+ return false;
+ if (parent.pkg->isAncestorPackageOf(this->pkg))
+ return true;
+ }
+
+ return true;
+}
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
new file mode 100644
index 0000000..0f2f03d
--- /dev/null
+++ b/gcc/d/dmd/dsymbol.h
@@ -0,0 +1,406 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "root/stringtable.h"
+
+#include "globals.h"
+#include "arraytypes.h"
+#include "visitor.h"
+
+class Identifier;
+struct Scope;
+class DsymbolTable;
+class Declaration;
+class ThisDeclaration;
+class TypeInfoDeclaration;
+class TupleDeclaration;
+class AliasDeclaration;
+class AggregateDeclaration;
+class EnumDeclaration;
+class ClassDeclaration;
+class InterfaceDeclaration;
+class StructDeclaration;
+class UnionDeclaration;
+class FuncDeclaration;
+class FuncAliasDeclaration;
+class OverDeclaration;
+class FuncLiteralDeclaration;
+class CtorDeclaration;
+class PostBlitDeclaration;
+class DtorDeclaration;
+class StaticCtorDeclaration;
+class StaticDtorDeclaration;
+class SharedStaticCtorDeclaration;
+class SharedStaticDtorDeclaration;
+class InvariantDeclaration;
+class UnitTestDeclaration;
+class NewDeclaration;
+class VarDeclaration;
+class AttribDeclaration;
+class Package;
+class Module;
+class Import;
+class Type;
+class TypeTuple;
+class WithStatement;
+class LabelDsymbol;
+class ScopeDsymbol;
+class ForwardingScopeDsymbol;
+class TemplateDeclaration;
+class TemplateInstance;
+class TemplateMixin;
+class ForwardingAttribDeclaration;
+class Nspace;
+class EnumMember;
+class WithScopeSymbol;
+class ArrayScopeSymbol;
+class SymbolDeclaration;
+class Expression;
+class DeleteDeclaration;
+class OverloadSet;
+struct AA;
+#ifdef IN_GCC
+typedef union tree_node Symbol;
+#else
+struct Symbol;
+#endif
+
+struct Ungag
+{
+ unsigned oldgag;
+
+ Ungag(unsigned old) : oldgag(old) {}
+ ~Ungag() { global.gag = oldgag; }
+};
+
+enum PROTKIND
+{
+ PROTundefined,
+ PROTnone, // no access
+ PROTprivate,
+ PROTpackage,
+ PROTprotected,
+ PROTpublic,
+ PROTexport
+};
+
+struct Prot
+{
+ PROTKIND kind;
+ Package *pkg;
+
+ Prot();
+ Prot(PROTKIND kind);
+
+ bool isMoreRestrictiveThan(const Prot other) const;
+ bool operator==(const Prot& other) const;
+ bool isSubsetOf(const Prot& other) const;
+};
+
+// in hdrgen.c
+void protectionToBuffer(OutBuffer *buf, Prot prot);
+const char *protectionToChars(PROTKIND kind);
+
+/* State of symbol in winding its way through the passes of the compiler
+ */
+enum PASS
+{
+ PASSinit, // initial state
+ PASSsemantic, // semantic() started
+ PASSsemanticdone, // semantic() done
+ PASSsemantic2, // semantic2() started
+ PASSsemantic2done, // semantic2() done
+ PASSsemantic3, // semantic3() started
+ PASSsemantic3done, // semantic3() done
+ PASSinline, // inline started
+ PASSinlinedone, // inline done
+ PASSobj // toObjFile() run
+};
+
+/* Flags for symbol search
+ */
+enum
+{
+ IgnoreNone = 0x00, // default
+ IgnorePrivateImports = 0x01, // don't search private imports
+ IgnoreErrors = 0x02, // don't give error messages
+ IgnoreAmbiguous = 0x04, // return NULL if ambiguous
+ SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
+ SearchImportsOnly = 0x10, // only look in imports
+ SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
+ // meaning don't search imports in that scope,
+ // because qualified module searches search
+ // their imports
+ IgnoreSymbolVisibility = 0x80 // also find private and package protected symbols
+};
+
+typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *);
+
+class Dsymbol : public RootObject
+{
+public:
+ Identifier *ident;
+ Dsymbol *parent;
+ Symbol *csym; // symbol for code generator
+ Symbol *isym; // import version of csym
+ const utf8_t *comment; // documentation comment for this Dsymbol
+ Loc loc; // where defined
+ Scope *_scope; // !=NULL means context to use for semantic()
+ const utf8_t *prettystring;
+ bool errors; // this symbol failed to pass semantic()
+ PASS semanticRun;
+ DeprecatedDeclaration *depdecl; // customized deprecation message
+ UserAttributeDeclaration *userAttribDecl; // user defined attributes
+ UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc)
+
+ Dsymbol();
+ Dsymbol(Identifier *);
+ static Dsymbol *create(Identifier *);
+ const char *toChars();
+ virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments
+ Loc& getLoc();
+ const char *locToChars();
+ bool equals(RootObject *o);
+ bool isAnonymous();
+ void error(Loc loc, const char *format, ...);
+ void error(const char *format, ...);
+ void deprecation(Loc loc, const char *format, ...);
+ void deprecation(const char *format, ...);
+ void checkDeprecated(Loc loc, Scope *sc);
+ Module *getModule();
+ Module *getAccessModule();
+ Dsymbol *pastMixin();
+ Dsymbol *toParent();
+ Dsymbol *toParent2();
+ TemplateInstance *isInstantiated();
+ TemplateInstance *isSpeculative();
+ Ungag ungagSpeculative();
+
+ // kludge for template.isSymbol()
+ int dyncast() const { return DYNCAST_DSYMBOL; }
+
+ static Dsymbols *arraySyntaxCopy(Dsymbols *a);
+
+ virtual Identifier *getIdent();
+ virtual const char *toPrettyChars(bool QualifyTypes = false);
+ virtual const char *kind();
+ virtual Dsymbol *toAlias(); // resolve real symbol
+ virtual Dsymbol *toAlias2();
+ virtual int apply(Dsymbol_apply_ft_t fp, void *param);
+ virtual void addMember(Scope *sc, ScopeDsymbol *sds);
+ virtual void setScope(Scope *sc);
+ virtual void importAll(Scope *sc);
+ virtual void semantic(Scope *sc);
+ virtual void semantic2(Scope *sc);
+ virtual void semantic3(Scope *sc);
+ virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
+ Dsymbol *search_correct(Identifier *id);
+ Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id);
+ virtual bool overloadInsert(Dsymbol *s);
+ virtual d_uns64 size(Loc loc);
+ virtual bool isforwardRef();
+ virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
+ virtual bool isExport() const; // is Dsymbol exported?
+ virtual bool isImportedSymbol() const; // is Dsymbol imported?
+ virtual bool isDeprecated(); // is Dsymbol deprecated?
+ virtual bool isOverloadable();
+ virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol?
+ AggregateDeclaration *isMember(); // is this a member of an AggregateDeclaration?
+ AggregateDeclaration *isMember2(); // is this a member of an AggregateDeclaration?
+ ClassDeclaration *isClassMember(); // is this a member of a ClassDeclaration?
+ virtual Type *getType(); // is this a type?
+ virtual bool needThis(); // need a 'this' pointer?
+ virtual Prot prot();
+ virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
+ virtual bool oneMember(Dsymbol **ps, Identifier *ident);
+ static bool oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident);
+ virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ virtual bool hasPointers();
+ virtual bool hasStaticCtorOrDtor();
+ virtual void addLocalClass(ClassDeclarations *) { }
+ virtual void checkCtorConstInit() { }
+
+ virtual void addComment(const utf8_t *comment);
+
+ bool inNonRoot();
+
+ // Eliminate need for dynamic_cast
+ virtual Package *isPackage() { return NULL; }
+ virtual Module *isModule() { return NULL; }
+ virtual EnumMember *isEnumMember() { return NULL; }
+ virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; }
+ virtual TemplateInstance *isTemplateInstance() { return NULL; }
+ virtual TemplateMixin *isTemplateMixin() { return NULL; }
+ virtual ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return NULL; }
+ virtual Nspace *isNspace() { return NULL; }
+ virtual Declaration *isDeclaration() { return NULL; }
+ virtual StorageClassDeclaration *isStorageClassDeclaration(){ return NULL; }
+ virtual ThisDeclaration *isThisDeclaration() { return NULL; }
+ virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; }
+ virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
+ virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
+ virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; }
+ virtual FuncDeclaration *isFuncDeclaration() { return NULL; }
+ virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; }
+ virtual OverDeclaration *isOverDeclaration() { return NULL; }
+ virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; }
+ virtual CtorDeclaration *isCtorDeclaration() { return NULL; }
+ virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; }
+ virtual DtorDeclaration *isDtorDeclaration() { return NULL; }
+ virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; }
+ virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; }
+ virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; }
+ virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; }
+ virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; }
+ virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; }
+ virtual NewDeclaration *isNewDeclaration() { return NULL; }
+ virtual VarDeclaration *isVarDeclaration() { return NULL; }
+ virtual ClassDeclaration *isClassDeclaration() { return NULL; }
+ virtual StructDeclaration *isStructDeclaration() { return NULL; }
+ virtual UnionDeclaration *isUnionDeclaration() { return NULL; }
+ virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; }
+ virtual ScopeDsymbol *isScopeDsymbol() { return NULL; }
+ virtual ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return NULL; }
+ virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; }
+ virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
+ virtual Import *isImport() { return NULL; }
+ virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
+ virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; }
+ virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; }
+ virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
+ virtual AnonDeclaration *isAnonDeclaration() { return NULL; }
+ virtual OverloadSet *isOverloadSet() { return NULL; }
+ virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+// Dsymbol that generates a scope
+
+class ScopeDsymbol : public Dsymbol
+{
+public:
+ Dsymbols *members; // all Dsymbol's in this scope
+ DsymbolTable *symtab; // members[] sorted into table
+ unsigned endlinnum; // the linnumber of the statement after the scope (0 if unknown)
+
+private:
+ Dsymbols *importedScopes; // imported Dsymbol's
+ PROTKIND *prots; // array of PROTKIND, one for each import
+
+ BitArray accessiblePackages, privateAccessiblePackages;
+
+public:
+ ScopeDsymbol();
+ ScopeDsymbol(Identifier *id);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ OverloadSet *mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s);
+ virtual void importScope(Dsymbol *s, Prot protection);
+ void addAccessiblePackage(Package *p, Prot protection);
+ virtual bool isPackageAccessible(Package *p, Prot protection, int flags = 0);
+ bool isforwardRef();
+ static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
+ const char *kind();
+ FuncDeclaration *findGetMembers();
+ virtual Dsymbol *symtabInsert(Dsymbol *s);
+ virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
+ bool hasStaticCtorOrDtor();
+
+ static size_t dim(Dsymbols *members);
+ static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL);
+
+ ScopeDsymbol *isScopeDsymbol() { return this; }
+ void semantic(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// With statement scope
+
+class WithScopeSymbol : public ScopeDsymbol
+{
+public:
+ WithStatement *withstate;
+
+ WithScopeSymbol(WithStatement *withstate);
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+
+ WithScopeSymbol *isWithScopeSymbol() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Array Index/Slice scope
+
+class ArrayScopeSymbol : public ScopeDsymbol
+{
+public:
+ Expression *exp; // IndexExp or SliceExp
+ TypeTuple *type; // for tuple[length]
+ TupleDeclaration *td; // for tuples of objects
+ Scope *sc;
+
+ ArrayScopeSymbol(Scope *sc, Expression *e);
+ ArrayScopeSymbol(Scope *sc, TypeTuple *t);
+ ArrayScopeSymbol(Scope *sc, TupleDeclaration *td);
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
+
+ ArrayScopeSymbol *isArrayScopeSymbol() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Overload Sets
+
+class OverloadSet : public Dsymbol
+{
+public:
+ Dsymbols a; // array of Dsymbols
+
+ OverloadSet(Identifier *ident, OverloadSet *os = NULL);
+ void push(Dsymbol *s);
+ OverloadSet *isOverloadSet() { return this; }
+ const char *kind();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Forwarding ScopeDsymbol
+
+class ForwardingScopeDsymbol : public ScopeDsymbol
+{
+ ScopeDsymbol *forward;
+
+ Dsymbol *symtabInsert(Dsymbol *s);
+ Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
+ void importScope(Dsymbol *s, Prot protection);
+ void semantic(Scope *sc);
+ const char *kind();
+
+ ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; }
+};
+
+// Table of Dsymbol's
+
+class DsymbolTable : public RootObject
+{
+public:
+ AA *tab;
+
+ DsymbolTable();
+
+ // Look up Identifier. Return Dsymbol if found, NULL if not.
+ Dsymbol *lookup(Identifier const * const ident);
+
+ // Insert Dsymbol in table. Return NULL if already there.
+ Dsymbol *insert(Dsymbol *s);
+
+ // Look for Dsymbol in table. If there, return it. If not, insert s and return that.
+ Dsymbol *update(Dsymbol *s);
+ Dsymbol *insert(Identifier const * const ident, Dsymbol *s); // when ident and s are not the same
+};
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c
new file mode 100644
index 0000000..f2b3b2f
--- /dev/null
+++ b/gcc/d/dmd/dtemplate.c
@@ -0,0 +1,8602 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/template.c
+ */
+
+// Handle template implementation
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root/root.h"
+#include "root/aav.h"
+#include "root/rmem.h"
+#include "root/stringtable.h"
+#include "root/hash.h"
+
+#include "mangle.h"
+#include "mtype.h"
+#include "template.h"
+#include "init.h"
+#include "expression.h"
+#include "scope.h"
+#include "module.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "dsymbol.h"
+#include "mars.h"
+#include "dsymbol.h"
+#include "identifier.h"
+#include "hdrgen.h"
+#include "id.h"
+#include "attrib.h"
+#include "tokens.h"
+
+#define IDX_NOTFOUND (0x12345678) // index is not found
+
+Type *rawTypeMerge(Type *t1, Type *t2);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+MATCH MODmethodConv(MOD modfrom, MOD modto);
+MOD MODmerge(MOD mod1, MOD mod2);
+
+static size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters);
+static int arrayObjectMatch(Objects *oa1, Objects *oa2);
+static unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam);
+static MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam);
+static bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
+Expression *semantic(Expression *e, Scope *sc);
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
+
+/********************************************
+ * These functions substitute for dynamic_cast. dynamic_cast does not work
+ * on earlier versions of gcc.
+ */
+
+Expression *isExpression(RootObject *o)
+{
+ //return dynamic_cast<Expression *>(o);
+ if (!o || o->dyncast() != DYNCAST_EXPRESSION)
+ return NULL;
+ return (Expression *)o;
+}
+
+Dsymbol *isDsymbol(RootObject *o)
+{
+ //return dynamic_cast<Dsymbol *>(o);
+ if (!o || o->dyncast() != DYNCAST_DSYMBOL)
+ return NULL;
+ return (Dsymbol *)o;
+}
+
+Type *isType(RootObject *o)
+{
+ //return dynamic_cast<Type *>(o);
+ if (!o || o->dyncast() != DYNCAST_TYPE)
+ return NULL;
+ return (Type *)o;
+}
+
+Tuple *isTuple(RootObject *o)
+{
+ //return dynamic_cast<Tuple *>(o);
+ if (!o || o->dyncast() != DYNCAST_TUPLE)
+ return NULL;
+ return (Tuple *)o;
+}
+
+Parameter *isParameter(RootObject *o)
+{
+ //return dynamic_cast<Parameter *>(o);
+ if (!o || o->dyncast() != DYNCAST_PARAMETER)
+ return NULL;
+ return (Parameter *)o;
+}
+
+/**************************************
+ * Is this Object an error?
+ */
+bool isError(RootObject *o)
+{
+ Type *t = isType(o);
+ if (t)
+ return (t->ty == Terror);
+ Expression *e = isExpression(o);
+ if (e)
+ return (e->op == TOKerror || !e->type || e->type->ty == Terror);
+ Tuple *v = isTuple(o);
+ if (v)
+ return arrayObjectIsError(&v->objects);
+ Dsymbol *s = isDsymbol(o);
+ assert(s);
+ if (s->errors)
+ return true;
+ return s->parent ? isError(s->parent) : false;
+}
+
+/**************************************
+ * Are any of the Objects an error?
+ */
+bool arrayObjectIsError(Objects *args)
+{
+ for (size_t i = 0; i < args->dim; i++)
+ {
+ RootObject *o = (*args)[i];
+ if (isError(o))
+ return true;
+ }
+ return false;
+}
+
+/***********************
+ * Try to get arg as a type.
+ */
+
+Type *getType(RootObject *o)
+{
+ Type *t = isType(o);
+ if (!t)
+ {
+ Expression *e = isExpression(o);
+ if (e)
+ t = e->type;
+ }
+ return t;
+}
+
+Dsymbol *getDsymbol(RootObject *oarg)
+{
+ //printf("getDsymbol()\n");
+ //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
+
+ Dsymbol *sa;
+ Expression *ea = isExpression(oarg);
+ if (ea)
+ {
+ // Try to convert Expression to symbol
+ if (ea->op == TOKvar)
+ sa = ((VarExp *)ea)->var;
+ else if (ea->op == TOKfunction)
+ {
+ if (((FuncExp *)ea)->td)
+ sa = ((FuncExp *)ea)->td;
+ else
+ sa = ((FuncExp *)ea)->fd;
+ }
+ else if (ea->op == TOKtemplate)
+ sa = ((TemplateExp *)ea)->td;
+ else
+ sa = NULL;
+ }
+ else
+ {
+ // Try to convert Type to symbol
+ Type *ta = isType(oarg);
+ if (ta)
+ sa = ta->toDsymbol(NULL);
+ else
+ sa = isDsymbol(oarg); // if already a symbol
+ }
+ return sa;
+}
+
+/***********************
+ * Try to get value from manifest constant
+ */
+
+static Expression *getValue(Expression *e)
+{
+ if (e && e->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+ if (v && v->storage_class & STCmanifest)
+ {
+ e = v->getConstInitializer();
+ }
+ }
+ return e;
+}
+
+static Expression *getValue(Dsymbol *&s)
+{
+ Expression *e = NULL;
+ if (s)
+ {
+ VarDeclaration *v = s->isVarDeclaration();
+ if (v && v->storage_class & STCmanifest)
+ {
+ e = v->getConstInitializer();
+ }
+ }
+ return e;
+}
+
+/**********************************
+ * Return true if e could be valid only as a template value parameter.
+ * Return false if it might be an alias or tuple.
+ * (Note that even in this case, it could still turn out to be a value).
+ */
+bool definitelyValueParameter(Expression *e)
+{
+ // None of these can be value parameters
+ if (e->op == TOKtuple || e->op == TOKscope ||
+ e->op == TOKtype || e->op == TOKdottype ||
+ e->op == TOKtemplate || e->op == TOKdottd ||
+ e->op == TOKfunction || e->op == TOKerror ||
+ e->op == TOKthis || e->op == TOKsuper)
+ return false;
+
+ if (e->op != TOKdotvar)
+ return true;
+
+ /* Template instantiations involving a DotVar expression are difficult.
+ * In most cases, they should be treated as a value parameter, and interpreted.
+ * But they might also just be a fully qualified name, which should be treated
+ * as an alias.
+ */
+
+ // x.y.f cannot be a value
+ FuncDeclaration *f = ((DotVarExp *)e)->var->isFuncDeclaration();
+ if (f)
+ return false;
+
+ while (e->op == TOKdotvar)
+ {
+ e = ((DotVarExp *)e)->e1;
+ }
+ // this.x.y and super.x.y couldn't possibly be valid values.
+ if (e->op == TOKthis || e->op == TOKsuper)
+ return false;
+
+ // e.type.x could be an alias
+ if (e->op == TOKdottype)
+ return false;
+
+ // var.x.y is the only other possible form of alias
+ if (e->op != TOKvar)
+ return true;
+
+ VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+
+ // func.x.y is not an alias
+ if (!v)
+ return true;
+
+ // TODO: Should we force CTFE if it is a global constant?
+
+ return false;
+}
+
+static Expression *getExpression(RootObject *o)
+{
+ Dsymbol *s = isDsymbol(o);
+ return s ? getValue(s) : getValue(isExpression(o));
+}
+
+/******************************
+ * If o1 matches o2, return true.
+ * Else, return false.
+ */
+
+static bool match(RootObject *o1, RootObject *o2)
+{
+ //printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
+ // o1, o1->toChars(), o1->dyncast(), o2, o2->toChars(), o2->dyncast());
+
+ /* A proper implementation of the various equals() overrides
+ * should make it possible to just do o1->equals(o2), but
+ * we'll do that another day.
+ */
+
+ /* Manifest constants should be compared by their values,
+ * at least in template arguments.
+ */
+
+ if (Type *t1 = isType(o1))
+ {
+ Type *t2 = isType(o2);
+ if (!t2)
+ goto Lnomatch;
+
+ //printf("\tt1 = %s\n", t1->toChars());
+ //printf("\tt2 = %s\n", t2->toChars());
+ if (!t1->equals(t2))
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+ if (Expression *e1 = getExpression(o1))
+ {
+ Expression *e2 = getExpression(o2);
+ if (!e2)
+ goto Lnomatch;
+
+ //printf("\te1 = %s %s %s\n", e1->type->toChars(), Token::toChars(e1->op), e1->toChars());
+ //printf("\te2 = %s %s %s\n", e2->type->toChars(), Token::toChars(e2->op), e2->toChars());
+
+ // two expressions can be equal although they do not have the same
+ // type; that happens when they have the same value. So check type
+ // as well as expression equality to ensure templates are properly
+ // matched.
+ if (!e1->type->equals(e2->type) || !e1->equals(e2))
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+ if (Dsymbol *s1 = isDsymbol(o1))
+ {
+ Dsymbol *s2 = isDsymbol(o2);
+ if (!s2)
+ goto Lnomatch;
+
+ //printf("\ts1 = %s\n", s1->toChars());
+ //printf("\ts2 = %s\n", s2->toChars());
+ if (!s1->equals(s2))
+ goto Lnomatch;
+ if (s1->parent != s2->parent && !s1->isFuncDeclaration() && !s2->isFuncDeclaration())
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+ if (Tuple *u1 = isTuple(o1))
+ {
+ Tuple *u2 = isTuple(o2);
+ if (!u2)
+ goto Lnomatch;
+
+ //printf("\tu1 = %s\n", u1->toChars());
+ //printf("\tu2 = %s\n", u2->toChars());
+ if (!arrayObjectMatch(&u1->objects, &u2->objects))
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+Lmatch:
+ //printf("\t-> match\n");
+ return true;
+
+Lnomatch:
+ //printf("\t-> nomatch\n");
+ return false;
+}
+
+
+/************************************
+ * Match an array of them.
+ */
+int arrayObjectMatch(Objects *oa1, Objects *oa2)
+{
+ if (oa1 == oa2)
+ return 1;
+ if (oa1->dim != oa2->dim)
+ return 0;
+ for (size_t j = 0; j < oa1->dim; j++)
+ {
+ RootObject *o1 = (*oa1)[j];
+ RootObject *o2 = (*oa2)[j];
+ if (!match(o1, o2))
+ {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/************************************
+ * Computes hash of expression.
+ * Handles all Expression classes and MUST match their equals method,
+ * i.e. e1->equals(e2) implies expressionHash(e1) == expressionHash(e2).
+ */
+static hash_t expressionHash(Expression *e)
+{
+ switch (e->op)
+ {
+ case TOKint64:
+ return (size_t) ((IntegerExp *)e)->getInteger();
+
+ case TOKfloat64:
+ return CTFloat::hash(((RealExp *)e)->value);
+
+ case TOKcomplex80:
+ {
+ ComplexExp *ce = (ComplexExp *)e;
+ return mixHash(CTFloat::hash(ce->toReal()), CTFloat::hash(ce->toImaginary()));
+ }
+
+ case TOKidentifier:
+ return (size_t)(void *) ((IdentifierExp *)e)->ident;
+
+ case TOKnull:
+ return (size_t)(void *) ((NullExp *)e)->type;
+
+ case TOKstring:
+ {
+ StringExp *se = (StringExp *)e;
+ return calcHash((const char *)se->string, se->len * se->sz);
+ }
+
+ case TOKtuple:
+ {
+ TupleExp *te = (TupleExp *)e;
+ size_t hash = 0;
+ hash += te->e0 ? expressionHash(te->e0) : 0;
+ for (size_t i = 0; i < te->exps->dim; i++)
+ {
+ Expression *elem = (*te->exps)[i];
+ hash = mixHash(hash, expressionHash(elem));
+ }
+ return hash;
+ }
+
+ case TOKarrayliteral:
+ {
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
+ size_t hash = 0;
+ for (size_t i = 0; i < ae->elements->dim; i++)
+ hash = mixHash(hash, expressionHash(ae->getElement(i)));
+ return hash;
+ }
+
+ case TOKassocarrayliteral:
+ {
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+ size_t hash = 0;
+ for (size_t i = 0; i < ae->keys->dim; i++)
+ // reduction needs associative op as keys are unsorted (use XOR)
+ hash ^= mixHash(expressionHash((*ae->keys)[i]), expressionHash((*ae->values)[i]));
+ return hash;
+ }
+
+ case TOKstructliteral:
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ size_t hash = 0;
+ for (size_t i = 0; i < se->elements->dim; i++)
+ {
+ Expression *elem = (*se->elements)[i];
+ hash = mixHash(hash, elem ? expressionHash(elem) : 0);
+ }
+ return hash;
+ }
+
+ case TOKvar:
+ return (size_t)(void *) ((VarExp *)e)->var;
+
+ case TOKfunction:
+ return (size_t)(void *) ((FuncExp *)e)->fd;
+
+ default:
+ // no custom equals for this expression
+ // equals based on identity
+ return (size_t)(void *) e;
+ }
+}
+
+
+/************************************
+ * Return hash of Objects.
+ */
+static hash_t arrayObjectHash(Objects *oa1)
+{
+ hash_t hash = 0;
+ for (size_t j = 0; j < oa1->dim; j++)
+ {
+ /* Must follow the logic of match()
+ */
+ RootObject *o1 = (*oa1)[j];
+ if (Type *t1 = isType(o1))
+ hash = mixHash(hash, (size_t)t1->deco);
+ else if (Expression *e1 = getExpression(o1))
+ hash = mixHash(hash, expressionHash(e1));
+ else if (Dsymbol *s1 = isDsymbol(o1))
+ {
+ FuncAliasDeclaration *fa1 = s1->isFuncAliasDeclaration();
+ if (fa1)
+ s1 = fa1->toAliasFunc();
+ hash = mixHash(hash, mixHash((size_t)(void *)s1->getIdent(), (size_t)(void *)s1->parent));
+ }
+ else if (Tuple *u1 = isTuple(o1))
+ hash = mixHash(hash, arrayObjectHash(&u1->objects));
+ }
+ return hash;
+}
+
+RootObject *objectSyntaxCopy(RootObject *o)
+{
+ if (!o)
+ return NULL;
+ if (Type *t = isType(o))
+ return t->syntaxCopy();
+ if (Expression *e = isExpression(o))
+ return e->syntaxCopy();
+ return o;
+}
+
+
+/* ======================== TemplateDeclaration ============================= */
+
+TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
+ TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, bool ismixin, bool literal)
+ : ScopeDsymbol(id)
+{
+ this->loc = loc;
+ this->parameters = parameters;
+ this->origParameters = parameters;
+ this->constraint = constraint;
+ this->members = decldefs;
+ this->overnext = NULL;
+ this->overroot = NULL;
+ this->funcroot = NULL;
+ this->onemember = NULL;
+ this->literal = literal;
+ this->ismixin = ismixin;
+ this->isstatic = true;
+ this->previous = NULL;
+ this->protection = Prot(PROTundefined);
+ this->instances = NULL;
+
+ // Compute in advance for Ddoc's use
+ // Bugzilla 11153: ident could be NULL if parsing fails.
+ if (members && ident)
+ {
+ Dsymbol *s;
+ if (Dsymbol::oneMembers(members, &s, ident) && s)
+ {
+ onemember = s;
+ s->parent = this;
+ }
+ }
+}
+
+Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
+{
+ //printf("TemplateDeclaration::syntaxCopy()\n");
+ TemplateParameters *p = NULL;
+ if (parameters)
+ {
+ p = new TemplateParameters();
+ p->setDim(parameters->dim);
+ for (size_t i = 0; i < p->dim; i++)
+ (*p)[i] = (*parameters)[i]->syntaxCopy();
+ }
+ return new TemplateDeclaration(loc, ident, p,
+ constraint ? constraint->syntaxCopy() : NULL,
+ Dsymbol::arraySyntaxCopy(members), ismixin, literal);
+}
+
+void TemplateDeclaration::semantic(Scope *sc)
+{
+ if (semanticRun != PASSinit)
+ return; // semantic() already run
+
+ // Remember templates defined in module object that we need to know about
+ if (sc->_module && sc->_module->ident == Id::object)
+ {
+ if (ident == Id::RTInfo)
+ Type::rtinfo = this;
+ }
+
+ /* Remember Scope for later instantiations, but make
+ * a copy since attributes can change.
+ */
+ if (!this->_scope)
+ {
+ this->_scope = sc->copy();
+ this->_scope->setNoFree();
+ }
+
+ semanticRun = PASSsemantic;
+
+ parent = sc->parent;
+ protection = sc->protection;
+ isstatic = toParent()->isModule() || (_scope->stc & STCstatic);
+
+ if (!isstatic)
+ {
+ if (AggregateDeclaration *ad = parent->pastMixin()->isAggregateDeclaration())
+ ad->makeNested();
+ }
+
+ // Set up scope for parameters
+ ScopeDsymbol *paramsym = new ScopeDsymbol();
+ paramsym->parent = parent;
+ Scope *paramscope = sc->push(paramsym);
+ paramscope->stc = 0;
+
+ if (global.params.doDocComments)
+ {
+ origParameters = new TemplateParameters();
+ origParameters->setDim(parameters->dim);
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*parameters)[i];
+ (*origParameters)[i] = tp->syntaxCopy();
+ }
+ }
+
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*parameters)[i];
+
+ if (!tp->declareParameter(paramscope))
+ {
+ error(tp->loc, "parameter '%s' multiply defined", tp->ident->toChars());
+ errors = true;
+ }
+ if (!tp->semantic(paramscope, parameters))
+ {
+ errors = true;
+ }
+ if (i + 1 != parameters->dim && tp->isTemplateTupleParameter())
+ {
+ error("template tuple parameter must be last one");
+ errors = true;
+ }
+ }
+
+ /* Calculate TemplateParameter::dependent
+ */
+ TemplateParameters tparams;
+ tparams.setDim(1);
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*parameters)[i];
+ tparams[0] = tp;
+
+ for (size_t j = 0; j < parameters->dim; j++)
+ {
+ // Skip cases like: X(T : T)
+ if (i == j)
+ continue;
+
+ if (TemplateTypeParameter *ttp = (*parameters)[j]->isTemplateTypeParameter())
+ {
+ if (reliesOnTident(ttp->specType, &tparams))
+ tp->dependent = true;
+ }
+ else if (TemplateAliasParameter *tap = (*parameters)[j]->isTemplateAliasParameter())
+ {
+ if (reliesOnTident(tap->specType, &tparams) ||
+ reliesOnTident(isType(tap->specAlias), &tparams))
+ {
+ tp->dependent = true;
+ }
+ }
+ }
+ }
+
+ paramscope->pop();
+
+ // Compute again
+ onemember = NULL;
+ if (members)
+ {
+ Dsymbol *s;
+ if (Dsymbol::oneMembers(members, &s, ident) && s)
+ {
+ onemember = s;
+ s->parent = this;
+ }
+ }
+
+ /* BUG: should check:
+ * o no virtual functions or non-static data members of classes
+ */
+}
+
+const char *TemplateDeclaration::kind()
+{
+ return (onemember && onemember->isAggregateDeclaration())
+ ? onemember->kind()
+ : "template";
+}
+
+/**********************************
+ * Overload existing TemplateDeclaration 'this' with the new one 's'.
+ * Return true if successful; i.e. no conflict.
+ */
+
+bool TemplateDeclaration::overloadInsert(Dsymbol *s)
+{
+ FuncDeclaration *fd = s->isFuncDeclaration();
+ if (fd)
+ {
+ if (funcroot)
+ return funcroot->overloadInsert(fd);
+ funcroot = fd;
+ return funcroot->overloadInsert(this);
+ }
+
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (!td)
+ return false;
+
+ TemplateDeclaration *pthis = this;
+ TemplateDeclaration **ptd;
+ for (ptd = &pthis; *ptd; ptd = &(*ptd)->overnext)
+ {
+ }
+
+ td->overroot = this;
+ *ptd = td;
+ return true;
+}
+
+/****************************
+ * Check to see if constraint is satisfied.
+ */
+bool TemplateDeclaration::evaluateConstraint(
+ TemplateInstance *ti, Scope *sc, Scope *paramscope,
+ Objects *dedargs, FuncDeclaration *fd)
+{
+ /* Detect recursive attempts to instantiate this template declaration,
+ * Bugzilla 4072
+ * void foo(T)(T x) if (is(typeof(foo(x)))) { }
+ * static assert(!is(typeof(foo(7))));
+ * Recursive attempts are regarded as a constraint failure.
+ */
+ /* There's a chicken-and-egg problem here. We don't know yet if this template
+ * instantiation will be a local one (enclosing is set), and we won't know until
+ * after selecting the correct template. Thus, function we're nesting inside
+ * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel().
+ * Workaround the problem by setting a flag to relax the checking on frame errors.
+ */
+
+ for (TemplatePrevious *p = previous; p; p = p->prev)
+ {
+ if (arrayObjectMatch(p->dedargs, dedargs))
+ {
+ //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars());
+ /* It must be a subscope of p->sc, other scope chains are not recursive
+ * instantiations.
+ */
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (scx == p->sc)
+ return false;
+ }
+ }
+ /* BUG: should also check for ref param differences
+ */
+ }
+
+ TemplatePrevious pr;
+ pr.prev = previous;
+ pr.sc = paramscope;
+ pr.dedargs = dedargs;
+ previous = &pr; // add this to threaded list
+
+ Scope *scx = paramscope->push(ti);
+ scx->parent = ti;
+ scx->tinst = NULL;
+ scx->minst = NULL;
+
+ assert(!ti->symtab);
+ if (fd)
+ {
+ /* Declare all the function parameters as variables and add them to the scope
+ * Making parameters is similar to FuncDeclaration::semantic3
+ */
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ assert(tf->ty == Tfunction);
+
+ scx->parent = fd;
+
+ Parameters *fparameters = tf->parameters;
+ int fvarargs = tf->varargs;
+
+ size_t nfparams = Parameter::dim(fparameters);
+ for (size_t i = 0; i < nfparams; i++)
+ {
+ Parameter *fparam = Parameter::getNth(fparameters, i);
+ fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
+ fparam->storageClass |= STCparameter;
+ if (fvarargs == 2 && i + 1 == nfparams)
+ fparam->storageClass |= STCvariadic;
+ }
+ for (size_t i = 0; i < fparameters->dim; i++)
+ {
+ Parameter *fparam = (*fparameters)[i];
+ if (!fparam->ident)
+ continue; // don't add it, if it has no name
+ VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL);
+ v->storage_class = fparam->storageClass;
+ v->semantic(scx);
+ if (!ti->symtab)
+ ti->symtab = new DsymbolTable();
+ if (!scx->insert(v))
+ error("parameter %s.%s is already defined", toChars(), v->toChars());
+ else
+ v->parent = fd;
+ }
+ if (isstatic)
+ fd->storage_class |= STCstatic;
+
+ fd->vthis = fd->declareThis(scx, fd->isThis());
+ }
+
+ Expression *e = constraint->syntaxCopy();
+
+ assert(ti->inst == NULL);
+ ti->inst = ti; // temporary instantiation to enable genIdent()
+
+ scx->flags |= SCOPEconstraint;
+ bool errors = false;
+ bool result = evalStaticCondition(scx, constraint, e, errors);
+ ti->inst = NULL;
+ ti->symtab = NULL;
+ scx = scx->pop();
+ previous = pr.prev; // unlink from threaded list
+ if (errors)
+ return false;
+ return result;
+}
+
+/***************************************
+ * Given that ti is an instance of this TemplateDeclaration,
+ * deduce the types of the parameters to this, and store
+ * those deduced types in dedtypes[].
+ * Input:
+ * flag 1: don't do semantic() because of dummy types
+ * 2: don't change types in matchArg()
+ * Output:
+ * dedtypes deduced arguments
+ * Return match level.
+ */
+
+MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti,
+ Objects *dedtypes, Expressions *fargs, int flag)
+{
+ MATCH m;
+ size_t dedtypes_dim = dedtypes->dim;
+
+ dedtypes->zero();
+
+ if (errors)
+ return MATCHnomatch;
+
+ size_t parameters_dim = parameters->dim;
+ int variadic = isVariadic() != NULL;
+
+ // If more arguments than parameters, no match
+ if (ti->tiargs->dim > parameters_dim && !variadic)
+ {
+ return MATCHnomatch;
+ }
+
+ assert(dedtypes_dim == parameters_dim);
+ assert(dedtypes_dim >= ti->tiargs->dim || variadic);
+
+ assert(_scope);
+
+ // Set up scope for template parameters
+ ScopeDsymbol *paramsym = new ScopeDsymbol();
+ paramsym->parent = _scope->parent;
+ Scope *paramscope = _scope->push(paramsym);
+ paramscope->tinst = ti;
+ paramscope->minst = sc->minst;
+ paramscope->callsc = sc;
+ paramscope->stc = 0;
+
+ // Attempt type deduction
+ m = MATCHexact;
+ for (size_t i = 0; i < dedtypes_dim; i++)
+ {
+ MATCH m2;
+ TemplateParameter *tp = (*parameters)[i];
+ Declaration *sparam;
+
+ //printf("\targument [%d]\n", i);
+ m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+ //printf("\tm2 = %d\n", m2);
+
+ if (m2 == MATCHnomatch)
+ {
+ goto Lnomatch;
+ }
+
+ if (m2 < m)
+ m = m2;
+
+ if (!flag)
+ sparam->semantic(paramscope);
+ if (!paramscope->insert(sparam)) // TODO: This check can make more early
+ goto Lnomatch; // in TemplateDeclaration::semantic, and
+ // then we don't need to make sparam if flags == 0
+ }
+
+ if (!flag)
+ {
+ /* Any parameter left without a type gets the type of
+ * its corresponding arg
+ */
+ for (size_t i = 0; i < dedtypes_dim; i++)
+ {
+ if (!(*dedtypes)[i])
+ {
+ assert(i < ti->tiargs->dim);
+ (*dedtypes)[i] = (Type *)(*ti->tiargs)[i];
+ }
+ }
+ }
+
+ if (m > MATCHnomatch && constraint && !flag)
+ {
+ if (ti->hasNestedArgs(ti->tiargs, this->isstatic)) // TODO: should gag error
+ ti->parent = ti->enclosing;
+ else
+ ti->parent = this->parent;
+
+ // Similar to doHeaderInstantiation
+ FuncDeclaration *fd = onemember ? onemember->isFuncDeclaration() : NULL;
+ if (fd)
+ {
+ assert(fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy();
+
+ fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, tf);
+ fd->parent = ti;
+ fd->inferRetType = true;
+
+ // Shouldn't run semantic on default arguments and return type.
+ for (size_t i = 0; i < tf->parameters->dim; i++)
+ (*tf->parameters)[i]->defaultArg = NULL;
+ tf->next = NULL;
+
+ // Resolve parameter types and 'auto ref's.
+ tf->fargs = fargs;
+ unsigned olderrors = global.startGagging();
+ fd->type = tf->semantic(loc, paramscope);
+ if (global.endGagging(olderrors))
+ {
+ assert(fd->type->ty != Tfunction);
+ goto Lnomatch;
+ }
+ assert(fd->type->ty == Tfunction);
+ fd->originalType = fd->type; // for mangling
+ }
+
+ // TODO: dedtypes => ti->tiargs ?
+ if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
+ goto Lnomatch;
+ }
+
+ goto Lret;
+
+Lnomatch:
+ m = MATCHnomatch;
+
+Lret:
+ paramscope->pop();
+ return m;
+}
+
+/********************************************
+ * Determine partial specialization order of 'this' vs td2.
+ * Returns:
+ * match this is at least as specialized as td2
+ * 0 td2 is more specialized than this
+ */
+
+MATCH TemplateDeclaration::leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs)
+{
+ /* This works by taking the template parameters to this template
+ * declaration and feeding them to td2 as if it were a template
+ * instance.
+ * If it works, then this template is at least as specialized
+ * as td2.
+ */
+
+ TemplateInstance ti(Loc(), ident); // create dummy template instance
+ // Set type arguments to dummy template instance to be types
+ // generated from the parameters to this template declaration
+ ti.tiargs = new Objects();
+ ti.tiargs->reserve(parameters->dim);
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*parameters)[i];
+ if (tp->dependent)
+ break;
+ RootObject *p = (RootObject *)tp->dummyArg();
+ if (!p)
+ break;
+
+ ti.tiargs->push(p);
+ }
+
+ // Temporary Array to hold deduced types
+ Objects dedtypes;
+ dedtypes.setDim(td2->parameters->dim);
+
+ // Attempt a type deduction
+ MATCH m = td2->matchWithInstance(sc, &ti, &dedtypes, fargs, 1);
+ if (m > MATCHnomatch)
+ {
+ /* A non-variadic template is more specialized than a
+ * variadic one.
+ */
+ TemplateTupleParameter *tp = isVariadic();
+ if (tp && !tp->dependent && !td2->isVariadic())
+ goto L1;
+
+ return m;
+ }
+ L1:
+ return MATCHnomatch;
+}
+
+static Expression *emptyArrayElement = NULL;
+
+class TypeDeduced : public Type
+{
+public:
+ Type *tded;
+ Expressions argexps; // corresponding expressions
+ Types tparams; // tparams[i]->mod
+
+ TypeDeduced(Type *tt, Expression *e, Type *tparam)
+ : Type(Tnone)
+ {
+ tded = tt;
+ argexps.push(e);
+ tparams.push(tparam);
+ }
+
+ virtual ~TypeDeduced()
+ {
+ }
+
+ void update(Expression *e, Type *tparam)
+ {
+ argexps.push(e);
+ tparams.push(tparam);
+ }
+ void update(Type *tt, Expression *e, Type *tparam)
+ {
+ tded = tt;
+ argexps.push(e);
+ tparams.push(tparam);
+ }
+ MATCH matchAll(Type *tt)
+ {
+ MATCH match = MATCHexact;
+ for (size_t j = 0; j < argexps.dim; j++)
+ {
+ Expression *e = argexps[j];
+ assert(e);
+ if (e == emptyArrayElement)
+ continue;
+
+ Type *t = tt->addMod(tparams[j]->mod)->substWildTo(MODconst);
+
+ MATCH m = e->implicitConvTo(t);
+ if (match > m)
+ match = m;
+ if (match <= MATCHnomatch)
+ break;
+ }
+ return match;
+ }
+};
+
+/*************************************************
+ * Match function arguments against a specific template function.
+ * Input:
+ * ti
+ * sc instantiation scope
+ * fd
+ * tthis 'this' argument if !NULL
+ * fargs arguments to function
+ * Output:
+ * fd Partially instantiated function declaration
+ * ti->tdtypes Expression/Type deduced template arguments
+ * Returns:
+ * match level
+ * bit 0-3 Match template parameters by inferred template arguments
+ * bit 4-7 Match template parameters by initial template arguments
+ */
+
+MATCH TemplateDeclaration::deduceFunctionTemplateMatch(
+ TemplateInstance *ti, Scope *sc,
+ FuncDeclaration *&fd, Type *tthis, Expressions *fargs)
+{
+ size_t nfparams;
+ size_t nfargs;
+ size_t ntargs; // array size of tiargs
+ size_t fptupindex = IDX_NOTFOUND;
+ MATCH match = MATCHexact;
+ MATCH matchTiargs = MATCHexact;
+ Parameters *fparameters; // function parameter list
+ int fvarargs; // function varargs
+ unsigned wildmatch = 0;
+ size_t inferStart = 0;
+
+ Loc instLoc = ti->loc;
+ Objects *tiargs = ti->tiargs;
+ Objects *dedargs = new Objects();
+ Objects* dedtypes = &ti->tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
+
+ assert(_scope);
+
+ dedargs->setDim(parameters->dim);
+ dedargs->zero();
+
+ dedtypes->setDim(parameters->dim);
+ dedtypes->zero();
+
+ if (errors || fd->errors)
+ return MATCHnomatch;
+
+ // Set up scope for parameters
+ ScopeDsymbol *paramsym = new ScopeDsymbol();
+ paramsym->parent = _scope->parent; // should use hasnestedArgs and enclosing?
+ Scope *paramscope = _scope->push(paramsym);
+ paramscope->tinst = ti;
+ paramscope->minst = sc->minst;
+ paramscope->callsc = sc;
+ paramscope->stc = 0;
+
+ TemplateTupleParameter *tp = isVariadic();
+ Tuple *declaredTuple = NULL;
+
+ ntargs = 0;
+ if (tiargs)
+ {
+ // Set initial template arguments
+ ntargs = tiargs->dim;
+ size_t n = parameters->dim;
+ if (tp)
+ n--;
+ if (ntargs > n)
+ {
+ if (!tp)
+ goto Lnomatch;
+
+ /* The extra initial template arguments
+ * now form the tuple argument.
+ */
+ Tuple *t = new Tuple();
+ assert(parameters->dim);
+ (*dedargs)[parameters->dim - 1] = t;
+
+ t->objects.setDim(ntargs - n);
+ for (size_t i = 0; i < t->objects.dim; i++)
+ {
+ t->objects[i] = (*tiargs)[n + i];
+ }
+ declareParameter(paramscope, tp, t);
+ declaredTuple = t;
+ }
+ else
+ n = ntargs;
+
+ memcpy(dedargs->tdata(), tiargs->tdata(), n * sizeof(*dedargs->tdata()));
+
+ for (size_t i = 0; i < n; i++)
+ {
+ assert(i < parameters->dim);
+ Declaration *sparam = NULL;
+ MATCH m = (*parameters)[i]->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
+ //printf("\tdeduceType m = %d\n", m);
+ if (m <= MATCHnomatch)
+ goto Lnomatch;
+ if (m < matchTiargs)
+ matchTiargs = m;
+
+ sparam->semantic(paramscope);
+ if (!paramscope->insert(sparam))
+ goto Lnomatch;
+ }
+ if (n < parameters->dim && !declaredTuple)
+ {
+ inferStart = n;
+ }
+ else
+ inferStart = parameters->dim;
+ //printf("tiargs matchTiargs = %d\n", matchTiargs);
+ }
+
+ fparameters = fd->getParameters(&fvarargs);
+ nfparams = Parameter::dim(fparameters); // number of function parameters
+ nfargs = fargs ? fargs->dim : 0; // number of function arguments
+
+ /* Check for match of function arguments with variadic template
+ * parameter, such as:
+ *
+ * void foo(T, A...)(T t, A a);
+ * void main() { foo(1,2,3); }
+ */
+ if (tp) // if variadic
+ {
+ // TemplateTupleParameter always makes most lesser matching.
+ matchTiargs = MATCHconvert;
+
+ if (nfparams == 0 && nfargs != 0) // if no function parameters
+ {
+ if (!declaredTuple)
+ {
+ Tuple *t = new Tuple();
+ //printf("t = %p\n", t);
+ (*dedargs)[parameters->dim - 1] = t;
+ declareParameter(paramscope, tp, t);
+ declaredTuple = t;
+ }
+ }
+ else
+ {
+ /* Figure out which of the function parameters matches
+ * the tuple template parameter. Do this by matching
+ * type identifiers.
+ * Set the index of this function parameter to fptupindex.
+ */
+ for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
+ {
+ Parameter *fparam = (*fparameters)[fptupindex];
+ if (fparam->type->ty != Tident)
+ continue;
+ TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+ if (!tp->ident->equals(tid->ident) || tid->idents.dim)
+ continue;
+
+ if (fvarargs) // variadic function doesn't
+ goto Lnomatch; // go with variadic template
+
+ goto L1;
+ }
+ fptupindex = IDX_NOTFOUND;
+ L1:
+ ;
+ }
+ }
+
+ if (toParent()->isModule() || (_scope->stc & STCstatic))
+ tthis = NULL;
+ if (tthis)
+ {
+ bool hasttp = false;
+
+ // Match 'tthis' to any TemplateThisParameter's
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateThisParameter *ttp = (*parameters)[i]->isTemplateThisParameter();
+ if (ttp)
+ {
+ hasttp = true;
+
+ Type *t = new TypeIdentifier(Loc(), ttp->ident);
+ MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
+ if (m <= MATCHnomatch)
+ goto Lnomatch;
+ if (m < match)
+ match = m; // pick worst match
+ }
+ }
+
+ // Match attributes of tthis against attributes of fd
+ if (fd->type && !fd->isCtorDeclaration())
+ {
+ StorageClass stc = _scope->stc | fd->storage_class2;
+ // Propagate parent storage class (see bug 5504)
+ Dsymbol *p = parent;
+ while (p->isTemplateDeclaration() || p->isTemplateInstance())
+ p = p->parent;
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (ad)
+ stc |= ad->storage_class;
+
+ unsigned char mod = fd->type->mod;
+ if (stc & STCimmutable)
+ mod = MODimmutable;
+ else
+ {
+ if (stc & (STCshared | STCsynchronized))
+ mod |= MODshared;
+ if (stc & STCconst)
+ mod |= MODconst;
+ if (stc & STCwild)
+ mod |= MODwild;
+ }
+
+ unsigned char thismod = tthis->mod;
+ if (hasttp)
+ mod = MODmerge(thismod, mod);
+ MATCH m = MODmethodConv(thismod, mod);
+ if (m <= MATCHnomatch)
+ goto Lnomatch;
+ if (m < match)
+ match = m;
+ }
+ }
+
+ // Loop through the function parameters
+ {
+ //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple->objects.dim : 0);
+ //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple->toChars() : NULL);
+ size_t argi = 0;
+ size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
+ for (size_t parami = 0; parami < nfparams; parami++)
+ {
+ Parameter *fparam = Parameter::getNth(fparameters, parami);
+
+ // Apply function parameter storage classes to parameter types
+ Type *prmtype = fparam->type->addStorageClass(fparam->storageClass);
+
+ Expression *farg;
+
+ /* See function parameters which wound up
+ * as part of a template tuple parameter.
+ */
+ if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
+ {
+ assert(prmtype->ty == Tident);
+ TypeIdentifier *tid = (TypeIdentifier *)prmtype;
+ if (!declaredTuple)
+ {
+ /* The types of the function arguments
+ * now form the tuple argument.
+ */
+ declaredTuple = new Tuple();
+ (*dedargs)[parameters->dim - 1] = declaredTuple;
+
+ /* Count function parameters following a tuple parameter.
+ * void foo(U, T...)(int y, T, U, int) {} // rem == 2 (U, int)
+ */
+ size_t rem = 0;
+ for (size_t j = parami + 1; j < nfparams; j++)
+ {
+ Parameter *p = Parameter::getNth(fparameters, j);
+ if (!reliesOnTident(p->type, parameters, inferStart))
+ {
+ Type *pt = p->type->syntaxCopy()->semantic(fd->loc, paramscope);
+ rem += pt->ty == Ttuple ? ((TypeTuple *)pt)->arguments->dim : 1;
+ }
+ else
+ {
+ ++rem;
+ }
+ }
+
+ if (nfargs2 - argi < rem)
+ goto Lnomatch;
+ declaredTuple->objects.setDim(nfargs2 - argi - rem);
+ for (size_t i = 0; i < declaredTuple->objects.dim; i++)
+ {
+ farg = (*fargs)[argi + i];
+
+ // Check invalid arguments to detect errors early.
+ if (farg->op == TOKerror || farg->type->ty == Terror)
+ goto Lnomatch;
+
+ if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid)
+ goto Lnomatch;
+
+ Type *tt;
+ MATCH m;
+ if (unsigned char wm = deduceWildHelper(farg->type, &tt, tid))
+ {
+ wildmatch |= wm;
+ m = MATCHconst;
+ }
+ else
+ {
+ m = deduceTypeHelper(farg->type, &tt, tid);
+ }
+ if (m <= MATCHnomatch)
+ goto Lnomatch;
+ if (m < match)
+ match = m;
+
+ /* Remove top const for dynamic array types and pointer types
+ */
+ if ((tt->ty == Tarray || tt->ty == Tpointer) &&
+ !tt->isMutable() &&
+ (!(fparam->storageClass & STCref) ||
+ ((fparam->storageClass & STCauto) && !farg->isLvalue())))
+ {
+ tt = tt->mutableOf();
+ }
+ declaredTuple->objects[i] = tt;
+ }
+ declareParameter(paramscope, tp, declaredTuple);
+ }
+ else
+ {
+ // Bugzilla 6810: If declared tuple is not a type tuple,
+ // it cannot be function parameter types.
+ for (size_t i = 0; i < declaredTuple->objects.dim; i++)
+ {
+ if (!isType(declaredTuple->objects[i]))
+ goto Lnomatch;
+ }
+ }
+ assert(declaredTuple);
+ argi += declaredTuple->objects.dim;
+ continue;
+ }
+
+ // If parameter type doesn't depend on inferred template parameters,
+ // semantic it to get actual type.
+ if (!reliesOnTident(prmtype, parameters, inferStart))
+ {
+ // should copy prmtype to avoid affecting semantic result
+ prmtype = prmtype->syntaxCopy()->semantic(fd->loc, paramscope);
+
+ if (prmtype->ty == Ttuple)
+ {
+ TypeTuple *tt = (TypeTuple *)prmtype;
+ size_t tt_dim = tt->arguments->dim;
+ for (size_t j = 0; j < tt_dim; j++, ++argi)
+ {
+ Parameter *p = (*tt->arguments)[j];
+ if (j == tt_dim - 1 && fvarargs == 2 && parami + 1 == nfparams && argi < nfargs)
+ {
+ prmtype = p->type;
+ goto Lvarargs;
+ }
+ if (argi >= nfargs)
+ {
+ if (p->defaultArg)
+ continue;
+ goto Lnomatch;
+ }
+ farg = (*fargs)[argi];
+ if (!farg->implicitConvTo(p->type))
+ goto Lnomatch;
+ }
+ continue;
+ }
+ }
+
+ if (argi >= nfargs) // if not enough arguments
+ {
+ if (!fparam->defaultArg)
+ goto Lvarargs;
+
+ /* Bugzilla 2803: Before the starting of type deduction from the function
+ * default arguments, set the already deduced parameters into paramscope.
+ * It's necessary to avoid breaking existing acceptable code. Cases:
+ *
+ * 1. Already deduced template parameters can appear in fparam->defaultArg:
+ * auto foo(A, B)(A a, B b = A.stringof);
+ * foo(1);
+ * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
+ *
+ * 2. If prmtype depends on default-specified template parameter, the
+ * default type should be preferred.
+ * auto foo(N = size_t, R)(R r, N start = 0)
+ * foo([1,2,3]);
+ * // at fparam `N start = 0`, N should be 'size_t' before
+ * // the deduction result from fparam->defaultArg.
+ */
+ if (argi == nfargs)
+ {
+ for (size_t i = 0; i < dedtypes->dim; i++)
+ {
+ Type *at = isType((*dedtypes)[i]);
+ if (at && at->ty == Tnone)
+ {
+ TypeDeduced *xt = (TypeDeduced *)at;
+ (*dedtypes)[i] = xt->tded; // 'unbox'
+ delete xt;
+ }
+ }
+ for (size_t i = ntargs; i < dedargs->dim; i++)
+ {
+ TemplateParameter *tparam = (*parameters)[i];
+
+ RootObject *oarg = (*dedargs)[i];
+ RootObject *oded = (*dedtypes)[i];
+ if (!oarg)
+ {
+ if (oded)
+ {
+ if (tparam->specialization() || !tparam->isTemplateTypeParameter())
+ {
+ /* The specialization can work as long as afterwards
+ * the oded == oarg
+ */
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
+ //printf("m2 = %d\n", m2);
+ if (m2 <= MATCHnomatch)
+ goto Lnomatch;
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i]->equals(oded))
+ error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
+ }
+ else
+ {
+ if (MATCHconvert < matchTiargs)
+ matchTiargs = MATCHconvert;
+ }
+ (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
+ }
+ else
+ {
+ oded = tparam->defaultArg(instLoc, paramscope);
+ if (oded)
+ (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
+ }
+ }
+ }
+ }
+ nfargs2 = argi + 1;
+
+ /* If prmtype does not depend on any template parameters:
+ *
+ * auto foo(T)(T v, double x = 0);
+ * foo("str");
+ * // at fparam == 'double x = 0'
+ *
+ * or, if all template parameters in the prmtype are already deduced:
+ *
+ * auto foo(R)(R range, ElementType!R sum = 0);
+ * foo([1,2,3]);
+ * // at fparam == 'ElementType!R sum = 0'
+ *
+ * Deducing prmtype from fparam->defaultArg is not necessary.
+ */
+ if (prmtype->deco ||
+ prmtype->syntaxCopy()->trySemantic(loc, paramscope))
+ {
+ ++argi;
+ continue;
+ }
+
+ // Deduce prmtype from the defaultArg.
+ farg = fparam->defaultArg->syntaxCopy();
+ farg = ::semantic(farg, paramscope);
+ farg = resolveProperties(paramscope, farg);
+ }
+ else
+ {
+ farg = (*fargs)[argi];
+ }
+ {
+ // Check invalid arguments to detect errors early.
+ if (farg->op == TOKerror || farg->type->ty == Terror)
+ goto Lnomatch;
+
+ Type *att = NULL;
+ Lretry:
+ Type *argtype = farg->type;
+
+ if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid && farg->op != TOKfunction)
+ goto Lnomatch;
+
+ // Bugzilla 12876: optimize arugument to allow CT-known length matching
+ farg = farg->optimize(WANTvalue, (fparam->storageClass & (STCref | STCout)) != 0);
+ //printf("farg = %s %s\n", farg->type->toChars(), farg->toChars());
+
+ RootObject *oarg = farg;
+ if ((fparam->storageClass & STCref) &&
+ (!(fparam->storageClass & STCauto) || farg->isLvalue()))
+ {
+ /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
+ */
+ Type *taai;
+ if (argtype->ty == Tarray &&
+ (prmtype->ty == Tsarray ||
+ (prmtype->ty == Taarray && (taai = ((TypeAArray *)prmtype)->index)->ty == Tident &&
+ ((TypeIdentifier *)taai)->idents.dim == 0)))
+ {
+ if (farg->op == TOKstring)
+ {
+ StringExp *se = (StringExp *)farg;
+ argtype = se->type->nextOf()->sarrayOf(se->len);
+ }
+ else if (farg->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)farg;
+ argtype = ae->type->nextOf()->sarrayOf(ae->elements->dim);
+ }
+ else if (farg->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *)farg;
+ if (Type *tsa = toStaticArrayType(se))
+ argtype = tsa;
+ }
+ }
+
+ oarg = argtype;
+ }
+ else if ((fparam->storageClass & STCout) == 0 &&
+ (argtype->ty == Tarray || argtype->ty == Tpointer) &&
+ templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND &&
+ ((TypeIdentifier *)prmtype)->idents.dim == 0)
+ {
+ /* The farg passing to the prmtype always make a copy. Therefore,
+ * we can shrink the set of the deduced type arguments for prmtype
+ * by adjusting top-qualifier of the argtype.
+ *
+ * prmtype argtype ta
+ * T <- const(E)[] const(E)[]
+ * T <- const(E[]) const(E)[]
+ * qualifier(T) <- const(E)[] const(E[])
+ * qualifier(T) <- const(E[]) const(E[])
+ */
+ Type *ta = argtype->castMod(prmtype->mod ? argtype->nextOf()->mod : 0);
+ if (ta != argtype)
+ {
+ Expression *ea = farg->copy();
+ ea->type = ta;
+ oarg = ea;
+ }
+ }
+
+ if (fvarargs == 2 && parami + 1 == nfparams && argi + 1 < nfargs)
+ goto Lvarargs;
+
+ unsigned wm = 0;
+ MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart);
+ //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch);
+ wildmatch |= wm;
+
+ /* If no match, see if the argument can be matched by using
+ * implicit conversions.
+ */
+ if (m == MATCHnomatch && prmtype->deco)
+ m = farg->implicitConvTo(prmtype);
+
+ if (m == MATCHnomatch)
+ {
+ AggregateDeclaration *ad = isAggregate(farg->type);
+ if (ad && ad->aliasthis && argtype != att)
+ {
+ if (!att && argtype->checkAliasThisRec()) // Bugzilla 12537
+ att = argtype;
+
+ /* If a semantic error occurs while doing alias this,
+ * eg purity(bug 7295), just regard it as not a match.
+ */
+ if (Expression *e = resolveAliasThis(sc, farg, true))
+ {
+ farg = e;
+ goto Lretry;
+ }
+ }
+ }
+
+ if (m > MATCHnomatch && (fparam->storageClass & (STCref | STCauto)) == STCref)
+ {
+ if (!farg->isLvalue())
+ {
+ if ((farg->op == TOKstring || farg->op == TOKslice) &&
+ (prmtype->ty == Tsarray || prmtype->ty == Taarray))
+ {
+ // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+ }
+ else
+ goto Lnomatch;
+ }
+ }
+ if (m > MATCHnomatch && (fparam->storageClass & STCout))
+ {
+ if (!farg->isLvalue())
+ goto Lnomatch;
+ if (!farg->type->isMutable()) // Bugzilla 11916
+ goto Lnomatch;
+ }
+ if (m == MATCHnomatch && (fparam->storageClass & STClazy) && prmtype->ty == Tvoid &&
+ farg->type->ty != Tvoid)
+ m = MATCHconvert;
+
+ if (m != MATCHnomatch)
+ {
+ if (m < match)
+ match = m; // pick worst match
+ argi++;
+ continue;
+ }
+ }
+
+ Lvarargs:
+ /* The following code for variadic arguments closely
+ * matches TypeFunction::callMatch()
+ */
+ if (!(fvarargs == 2 && parami + 1 == nfparams))
+ goto Lnomatch;
+
+ /* Check for match with function parameter T...
+ */
+ Type *tb = prmtype->toBasetype();
+ switch (tb->ty)
+ {
+ // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
+ case Tsarray:
+ case Taarray:
+ // Perhaps we can do better with this, see TypeFunction::callMatch()
+ if (tb->ty == Tsarray)
+ {
+ TypeSArray *tsa = (TypeSArray *)tb;
+ dinteger_t sz = tsa->dim->toInteger();
+ if (sz != nfargs - argi)
+ goto Lnomatch;
+ }
+ else if (tb->ty == Taarray)
+ {
+ TypeAArray *taa = (TypeAArray *)tb;
+ Expression *dim = new IntegerExp(instLoc, nfargs - argi, Type::tsize_t);
+
+ size_t i = templateParameterLookup(taa->index, parameters);
+ if (i == IDX_NOTFOUND)
+ {
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ Scope *sco;
+
+ unsigned errors = global.startGagging();
+ /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
+ * The parameter isn't part of the template
+ * ones, let's try to find it in the
+ * instantiation scope 'sc' and the one
+ * belonging to the template itself. */
+ sco = sc;
+ taa->index->resolve(instLoc, sco, &e, &t, &s);
+ if (!e)
+ {
+ sco = paramscope;
+ taa->index->resolve(instLoc, sco, &e, &t, &s);
+ }
+ global.endGagging(errors);
+
+ if (!e)
+ {
+ goto Lnomatch;
+ }
+
+ e = e->ctfeInterpret();
+ e = e->implicitCastTo(sco, Type::tsize_t);
+ e = e->optimize(WANTvalue);
+ if (!dim->equals(e))
+ goto Lnomatch;
+ }
+ else
+ {
+ // This code matches code in TypeInstance::deduceType()
+ TemplateParameter *tprm = (*parameters)[i];
+ TemplateValueParameter *tvp = tprm->isTemplateValueParameter();
+ if (!tvp)
+ goto Lnomatch;
+ Expression *e = (Expression *)(*dedtypes)[i];
+ if (e)
+ {
+ if (!dim->equals(e))
+ goto Lnomatch;
+ }
+ else
+ {
+ Type *vt = tvp->valType->semantic(Loc(), sc);
+ MATCH m = (MATCH)dim->implicitConvTo(vt);
+ if (m <= MATCHnomatch)
+ goto Lnomatch;
+ (*dedtypes)[i] = dim;
+ }
+ }
+ }
+ /* fall through */
+ case Tarray:
+ {
+ TypeArray *ta = (TypeArray *)tb;
+ Type *tret = fparam->isLazyArray();
+ for (; argi < nfargs; argi++)
+ {
+ Expression *arg = (*fargs)[argi];
+ assert(arg);
+
+ MATCH m;
+ /* If lazy array of delegates,
+ * convert arg(s) to delegate(s)
+ */
+ if (tret)
+ {
+ if (ta->next->equals(arg->type))
+ {
+ m = MATCHexact;
+ }
+ else
+ {
+ m = arg->implicitConvTo(tret);
+ if (m == MATCHnomatch)
+ {
+ if (tret->toBasetype()->ty == Tvoid)
+ m = MATCHconvert;
+ }
+ }
+ }
+ else
+ {
+ unsigned wm = 0;
+ m = deduceType(arg, paramscope, ta->next, parameters, dedtypes, &wm, inferStart);
+ wildmatch |= wm;
+ }
+ if (m == MATCHnomatch)
+ goto Lnomatch;
+ if (m < match)
+ match = m;
+ }
+ goto Lmatch;
+ }
+ case Tclass:
+ case Tident:
+ goto Lmatch;
+
+ default:
+ goto Lnomatch;
+ }
+ ++argi;
+ }
+ //printf("-> argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
+ if (argi != nfargs2 && !fvarargs)
+ goto Lnomatch;
+ }
+
+Lmatch:
+
+ for (size_t i = 0; i < dedtypes->dim; i++)
+ {
+ Type *at = isType((*dedtypes)[i]);
+ if (at)
+ {
+ if (at->ty == Tnone)
+ {
+ TypeDeduced *xt = (TypeDeduced *)at;
+ at = xt->tded; // 'unbox'
+ delete xt;
+ }
+ (*dedtypes)[i] = at->merge2();
+ }
+ }
+ for (size_t i = ntargs; i < dedargs->dim; i++)
+ {
+ TemplateParameter *tparam = (*parameters)[i];
+ //printf("tparam[%d] = %s\n", i, tparam->ident->toChars());
+ /* For T:T*, the dedargs is the T*, dedtypes is the T
+ * But for function templates, we really need them to match
+ */
+ RootObject *oarg = (*dedargs)[i];
+ RootObject *oded = (*dedtypes)[i];
+ //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
+ //if (oarg) printf("oarg: %s\n", oarg->toChars());
+ //if (oded) printf("oded: %s\n", oded->toChars());
+ if (!oarg)
+ {
+ if (oded)
+ {
+ if (tparam->specialization() || !tparam->isTemplateTypeParameter())
+ {
+ /* The specialization can work as long as afterwards
+ * the oded == oarg
+ */
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
+ //printf("m2 = %d\n", m2);
+ if (m2 <= MATCHnomatch)
+ goto Lnomatch;
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i]->equals(oded))
+ error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
+ }
+ else
+ {
+ if (MATCHconvert < matchTiargs)
+ matchTiargs = MATCHconvert;
+ }
+ }
+ else
+ {
+ oded = tparam->defaultArg(instLoc, paramscope);
+ if (!oded)
+ {
+ // if tuple parameter and
+ // tuple parameter was not in function parameter list and
+ // we're one or more arguments short (i.e. no tuple argument)
+ if (tparam == tp &&
+ fptupindex == IDX_NOTFOUND &&
+ ntargs <= dedargs->dim - 1)
+ {
+ // make tuple argument an empty tuple
+ oded = (RootObject *)new Tuple();
+ }
+ else
+ goto Lnomatch;
+ }
+ if (isError(oded))
+ goto Lerror;
+ ntargs++;
+
+ /* At the template parameter T, the picked default template argument
+ * X!int should be matched to T in order to deduce dependent
+ * template parameter A.
+ * auto foo(T : X!A = X!int, A...)() { ... }
+ * foo(); // T <-- X!int, A <-- (int)
+ */
+ if (tparam->specialization())
+ {
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
+ //printf("m2 = %d\n", m2);
+ if (m2 <= MATCHnomatch)
+ goto Lnomatch;
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i]->equals(oded))
+ error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
+ }
+ }
+ oded = declareParameter(paramscope, tparam, oded);
+ (*dedargs)[i] = oded;
+ }
+ }
+
+ /* Bugzilla 7469: As same as the code for 7469 in findBestMatch,
+ * expand a Tuple in dedargs to normalize template arguments.
+ */
+ if (size_t d = dedargs->dim)
+ {
+ if (Tuple *va = isTuple((*dedargs)[d - 1]))
+ {
+ if (va->objects.dim)
+ {
+ dedargs->setDim(d - 1);
+ dedargs->insert(d - 1, &va->objects);
+ }
+ }
+ }
+ ti->tiargs = dedargs; // update to the normalized template arguments.
+
+ // Partially instantiate function for constraint and fd->leastAsSpecialized()
+ {
+ assert(paramsym);
+ Scope *sc2 = _scope;
+ sc2 = sc2->push(paramsym);
+ sc2 = sc2->push(ti);
+ sc2->parent = ti;
+ sc2->tinst = ti;
+ sc2->minst = sc->minst;
+
+ fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
+
+ sc2 = sc2->pop();
+ sc2 = sc2->pop();
+
+ if (!fd)
+ goto Lnomatch;
+ }
+
+ if (constraint)
+ {
+ if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
+ goto Lnomatch;
+ }
+
+ paramscope->pop();
+ //printf("\tmatch %d\n", match);
+ return (MATCH)(match | (matchTiargs<<4));
+
+Lnomatch:
+ paramscope->pop();
+ //printf("\tnomatch\n");
+ return MATCHnomatch;
+
+Lerror: // todo: for the future improvement
+ paramscope->pop();
+ //printf("\terror\n");
+ return MATCHnomatch;
+}
+
+/**************************************************
+ * Declare template parameter tp with value o, and install it in the scope sc.
+ */
+
+RootObject *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o)
+{
+ //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o);
+
+ Type *ta = isType(o);
+ Expression *ea = isExpression(o);
+ Dsymbol *sa = isDsymbol(o);
+ Tuple *va = isTuple(o);
+
+ Declaration *d;
+ VarDeclaration *v = NULL;
+
+ if (ea && ea->op == TOKtype)
+ ta = ea->type;
+ else if (ea && ea->op == TOKscope)
+ sa = ((ScopeExp *)ea)->sds;
+ else if (ea && (ea->op == TOKthis || ea->op == TOKsuper))
+ sa = ((ThisExp *)ea)->var;
+ else if (ea && ea->op == TOKfunction)
+ {
+ if (((FuncExp *)ea)->td)
+ sa = ((FuncExp *)ea)->td;
+ else
+ sa = ((FuncExp *)ea)->fd;
+ }
+
+ if (ta)
+ {
+ //printf("type %s\n", ta->toChars());
+ d = new AliasDeclaration(Loc(), tp->ident, ta);
+ }
+ else if (sa)
+ {
+ //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars());
+ d = new AliasDeclaration(Loc(), tp->ident, sa);
+ }
+ else if (ea)
+ {
+ // tdtypes.data[i] always matches ea here
+ Initializer *init = new ExpInitializer(loc, ea);
+ TemplateValueParameter *tvp = tp->isTemplateValueParameter();
+
+ Type *t = tvp ? tvp->valType : NULL;
+
+ v = new VarDeclaration(loc, t, tp->ident, init);
+ v->storage_class = STCmanifest | STCtemplateparameter;
+ d = v;
+ }
+ else if (va)
+ {
+ //printf("\ttuple\n");
+ d = new TupleDeclaration(loc, tp->ident, &va->objects);
+ }
+ else
+ {
+ assert(0);
+ }
+
+ d->storage_class |= STCtemplateparameter;
+ if (ta)
+ {
+ Type *t = ta;
+ // consistent with Type::checkDeprecated()
+ while (t->ty != Tenum)
+ {
+ if (!t->nextOf()) break;
+ t = ((TypeNext *)t)->next;
+ }
+ if (Dsymbol *s = t->toDsymbol(sc))
+ {
+ if (s->isDeprecated())
+ d->storage_class |= STCdeprecated;
+ }
+ }
+ else if (sa)
+ {
+ if (sa->isDeprecated())
+ d->storage_class |= STCdeprecated;
+ }
+
+ if (!sc->insert(d))
+ error("declaration %s is already defined", tp->ident->toChars());
+ d->semantic(sc);
+
+ /* So the caller's o gets updated with the result of semantic() being run on o
+ */
+ if (v)
+ o = initializerToExpression(v->_init);
+ return o;
+}
+
+/**************************************
+ * Determine if TemplateDeclaration is variadic.
+ */
+
+TemplateTupleParameter *isVariadic(TemplateParameters *parameters)
+{
+ size_t dim = parameters->dim;
+ TemplateTupleParameter *tp = NULL;
+
+ if (dim)
+ tp = ((*parameters)[dim - 1])->isTemplateTupleParameter();
+ return tp;
+}
+
+TemplateTupleParameter *TemplateDeclaration::isVariadic()
+{
+ return ::isVariadic(parameters);
+}
+
+/***********************************
+ * We can overload templates.
+ */
+
+bool TemplateDeclaration::isOverloadable()
+{
+ return true;
+}
+
+/*************************************************
+ * Given function arguments, figure out which template function
+ * to expand, and return matching result.
+ * Input:
+ * m matching result
+ * dstart the root of overloaded function templates
+ * loc instantiation location
+ * sc instantiation scope
+ * tiargs initial list of template arguments
+ * tthis if !NULL, the 'this' pointer argument
+ * fargs arguments to function
+ */
+
+void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
+ Objects *tiargs, Type *tthis, Expressions *fargs)
+{
+ struct ParamDeduce
+ {
+ // context
+ Loc loc;
+ Scope *sc;
+ Type *tthis;
+ Objects *tiargs;
+ Expressions *fargs;
+ // result
+ Match *m;
+ int property; // 0: unintialized
+ // 1: seen @property
+ // 2: not @property
+ size_t ov_index;
+ TemplateDeclaration *td_best;
+ TemplateInstance *ti_best;
+ MATCH ta_last;
+ Type *tthis_best;
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ if (s->errors)
+ return 0;
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ return ((ParamDeduce *)param)->applyFunction(fd);
+ if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ return ((ParamDeduce *)param)->applyTemplate(td);
+ return 0;
+ }
+
+ int applyFunction(FuncDeclaration *fd)
+ {
+ // skip duplicates
+ if (fd == m->lastf)
+ return 0;
+ // explicitly specified tiargs never match to non template function
+ if (tiargs && tiargs->dim > 0)
+ return 0;
+
+ if (fd->semanticRun == PASSinit && fd->_scope)
+ {
+ Ungag ungag = fd->ungagSpeculative();
+ fd->semantic(fd->_scope);
+ }
+ if (fd->semanticRun == PASSinit)
+ {
+ ::error(loc, "forward reference to template %s", fd->toChars());
+ return 1;
+ }
+ //printf("fd = %s %s, fargs = %s\n", fd->toChars(), fd->type->toChars(), fargs->toChars());
+ m->anyf = fd;
+ TypeFunction *tf = (TypeFunction *)fd->type;
+
+ int prop = (tf->isproperty) ? 1 : 2;
+ if (property == 0)
+ property = prop;
+ else if (property != prop)
+ error(fd->loc, "cannot overload both property and non-property functions");
+
+ /* For constructors, qualifier check will be opposite direction.
+ * Qualified constructor always makes qualified object, then will be checked
+ * that it is implicitly convertible to tthis.
+ */
+ Type *tthis_fd = fd->needThis() ? tthis : NULL;
+ bool isCtorCall = tthis_fd && fd->isCtorDeclaration();
+ if (isCtorCall)
+ {
+ //printf("%s tf->mod = x%x tthis_fd->mod = x%x %d\n", tf->toChars(),
+ // tf->mod, tthis_fd->mod, fd->isolateReturn());
+ if (MODimplicitConv(tf->mod, tthis_fd->mod) ||
+ (tf->isWild() && tf->isShared() == tthis_fd->isShared()) ||
+ fd->isolateReturn())
+ {
+ /* && tf->isShared() == tthis_fd->isShared()*/
+ // Uniquely constructed object can ignore shared qualifier.
+ // TODO: Is this appropriate?
+ tthis_fd = NULL;
+ }
+ else
+ return 0; // MATCHnomatch
+ }
+ MATCH mfa = tf->callMatch(tthis_fd, fargs);
+ //printf("test1: mfa = %d\n", mfa);
+ if (mfa > MATCHnomatch)
+ {
+ if (mfa > m->last) goto LfIsBetter;
+ if (mfa < m->last) goto LlastIsBetter;
+
+ /* See if one of the matches overrides the other.
+ */
+ assert(m->lastf);
+ if (m->lastf->overrides(fd)) goto LlastIsBetter;
+ if (fd->overrides(m->lastf)) goto LfIsBetter;
+
+ /* Try to disambiguate using template-style partial ordering rules.
+ * In essence, if f() and g() are ambiguous, if f() can call g(),
+ * but g() cannot call f(), then pick f().
+ * This is because f() is "more specialized."
+ */
+ {
+ MATCH c1 = fd->leastAsSpecialized(m->lastf);
+ MATCH c2 = m->lastf->leastAsSpecialized(fd);
+ //printf("c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto LfIsBetter;
+ if (c1 < c2) goto LlastIsBetter;
+ }
+
+ /* The 'overrides' check above does covariant checking only
+ * for virtual member functions. It should do it for all functions,
+ * but in order to not risk breaking code we put it after
+ * the 'leastAsSpecialized' check.
+ * In the future try moving it before.
+ * I.e. a not-the-same-but-covariant match is preferred,
+ * as it is more restrictive.
+ */
+ if (!m->lastf->type->equals(fd->type))
+ {
+ //printf("cov: %d %d\n", m->lastf->type->covariant(fd->type), fd->type->covariant(m->lastf->type));
+ if (m->lastf->type->covariant(fd->type) == 1) goto LlastIsBetter;
+ if (fd->type->covariant(m->lastf->type) == 1) goto LfIsBetter;
+ }
+
+ /* If the two functions are the same function, like:
+ * int foo(int);
+ * int foo(int x) { ... }
+ * then pick the one with the body.
+ */
+ if (tf->equals(m->lastf->type) &&
+ fd->storage_class == m->lastf->storage_class &&
+ fd->parent == m->lastf->parent &&
+ fd->protection == m->lastf->protection &&
+ fd->linkage == m->lastf->linkage)
+ {
+ if ( fd->fbody && !m->lastf->fbody) goto LfIsBetter;
+ if (!fd->fbody && m->lastf->fbody) goto LlastIsBetter;
+ }
+
+ // Bugzilla 14450: Prefer exact qualified constructor for the creating object type
+ if (isCtorCall && tf->mod != m->lastf->type->mod)
+ {
+ if (tthis->mod == tf->mod) goto LfIsBetter;
+ if (tthis->mod == m->lastf->type->mod) goto LlastIsBetter;
+ }
+
+ m->nextf = fd;
+ m->count++;
+ return 0;
+
+ LlastIsBetter:
+ return 0;
+
+ LfIsBetter:
+ td_best = NULL;
+ ti_best = NULL;
+ ta_last = MATCHexact;
+ m->last = mfa;
+ m->lastf = fd;
+ tthis_best = tthis_fd;
+ ov_index = 0;
+ m->count = 1;
+ return 0;
+ }
+ return 0;
+ }
+
+ int applyTemplate(TemplateDeclaration *td)
+ {
+ //printf("applyTemplate()\n");
+ // skip duplicates
+ if (td == td_best)
+ return 0;
+
+ if (!sc)
+ sc = td->_scope; // workaround for Type::aliasthisOf
+
+ if (td->semanticRun == PASSinit && td->_scope)
+ {
+ // Try to fix forward reference. Ungag errors while doing so.
+ Ungag ungag = td->ungagSpeculative();
+ td->semantic(td->_scope);
+ }
+ if (td->semanticRun == PASSinit)
+ {
+ ::error(loc, "forward reference to template %s", td->toChars());
+ Lerror:
+ m->lastf = NULL;
+ m->count = 0;
+ m->last = MATCHnomatch;
+ return 1;
+ }
+ //printf("td = %s\n", td->toChars());
+
+ FuncDeclaration *f;
+ f = td->onemember ? td->onemember->isFuncDeclaration() : NULL;
+ if (!f)
+ {
+ if (!tiargs)
+ tiargs = new Objects();
+ TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
+ Objects dedtypes;
+ dedtypes.setDim(td->parameters->dim);
+ assert(td->semanticRun != PASSinit);
+ MATCH mta = td->matchWithInstance(sc, ti, &dedtypes, fargs, 0);
+ //printf("matchWithInstance = %d\n", mta);
+ if (mta <= MATCHnomatch || mta < ta_last) // no match or less match
+ return 0;
+
+ ti->semantic(sc, fargs);
+ if (!ti->inst) // if template failed to expand
+ return 0;
+
+ Dsymbol *s = ti->inst->toAlias();
+ FuncDeclaration *fd;
+ if (TemplateDeclaration *tdx = s->isTemplateDeclaration())
+ {
+ Objects dedtypesX; // empty tiargs
+
+ // Bugzilla 11553: Check for recursive instantiation of tdx.
+ for (TemplatePrevious *p = tdx->previous; p; p = p->prev)
+ {
+ if (arrayObjectMatch(p->dedargs, &dedtypesX))
+ {
+ //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars());
+ /* It must be a subscope of p->sc, other scope chains are not recursive
+ * instantiations.
+ */
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (scx == p->sc)
+ {
+ error(loc, "recursive template expansion while looking for %s.%s", ti->toChars(), tdx->toChars());
+ goto Lerror;
+ }
+ }
+ }
+ /* BUG: should also check for ref param differences
+ */
+ }
+
+ TemplatePrevious pr;
+ pr.prev = tdx->previous;
+ pr.sc = sc;
+ pr.dedargs = &dedtypesX;
+ tdx->previous = &pr; // add this to threaded list
+
+ fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1);
+
+ tdx->previous = pr.prev; // unlink from threaded list
+ }
+ else if (s->isFuncDeclaration())
+ {
+ fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1);
+ }
+ else
+ goto Lerror;
+
+ if (!fd)
+ return 0;
+
+ if (fd->type->ty != Tfunction)
+ {
+ m->lastf = fd; // to propagate "error match"
+ m->count = 1;
+ m->last = MATCHnomatch;
+ return 1;
+ }
+
+ Type *tthis_fd = fd->needThis() && !fd->isCtorDeclaration() ? tthis : NULL;
+
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ MATCH mfa = tf->callMatch(tthis_fd, fargs);
+ if (mfa < m->last)
+ return 0;
+
+ if (mta < ta_last) goto Ltd_best2;
+ if (mta > ta_last) goto Ltd2;
+
+ if (mfa < m->last) goto Ltd_best2;
+ if (mfa > m->last) goto Ltd2;
+
+ //printf("Lambig2\n");
+ m->nextf = fd;
+ m->count++;
+ return 0;
+
+ Ltd_best2:
+ return 0;
+
+ Ltd2:
+ // td is the new best match
+ assert(td->_scope);
+ td_best = td;
+ ti_best = NULL;
+ property = 0; // (backward compatibility)
+ ta_last = mta;
+ m->last = mfa;
+ m->lastf = fd;
+ tthis_best = tthis_fd;
+ ov_index = 0;
+ m->nextf = NULL;
+ m->count = 1;
+ return 0;
+ }
+
+ //printf("td = %s\n", td->toChars());
+ for (size_t ovi = 0; f; f = f->overnext0, ovi++)
+ {
+ if (f->type->ty != Tfunction || f->errors)
+ goto Lerror;
+
+ /* This is a 'dummy' instance to evaluate constraint properly.
+ */
+ TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
+ ti->parent = td->parent; // Maybe calculating valid 'enclosing' is unnecessary.
+
+ FuncDeclaration *fd = f;
+ int x = td->deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs);
+ MATCH mta = (MATCH)(x >> 4);
+ MATCH mfa = (MATCH)(x & 0xF);
+ //printf("match:t/f = %d/%d\n", mta, mfa);
+ if (!fd || mfa == MATCHnomatch)
+ continue;
+
+ Type *tthis_fd = fd->needThis() ? tthis : NULL;
+
+ bool isCtorCall = tthis_fd && fd->isCtorDeclaration();
+ if (isCtorCall)
+ {
+ // Constructor call requires additional check.
+
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ assert(tf->next);
+ if (MODimplicitConv(tf->mod, tthis_fd->mod) ||
+ (tf->isWild() && tf->isShared() == tthis_fd->isShared()) ||
+ fd->isolateReturn())
+ {
+ tthis_fd = NULL;
+ }
+ else
+ continue; // MATCHnomatch
+ }
+
+ if (mta < ta_last) goto Ltd_best;
+ if (mta > ta_last) goto Ltd;
+
+ if (mfa < m->last) goto Ltd_best;
+ if (mfa > m->last) goto Ltd;
+
+ if (td_best)
+ {
+ // Disambiguate by picking the most specialized TemplateDeclaration
+ MATCH c1 = td->leastAsSpecialized(sc, td_best, fargs);
+ MATCH c2 = td_best->leastAsSpecialized(sc, td, fargs);
+ //printf("1: c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+ assert(fd && m->lastf);
+ {
+ // Disambiguate by tf->callMatch
+ TypeFunction *tf1 = (TypeFunction *)fd->type;
+ assert(tf1->ty == Tfunction);
+ TypeFunction *tf2 = (TypeFunction *)m->lastf->type;
+ assert(tf2->ty == Tfunction);
+ MATCH c1 = tf1->callMatch(tthis_fd, fargs);
+ MATCH c2 = tf2->callMatch(tthis_best, fargs);
+ //printf("2: c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+ {
+ // Disambiguate by picking the most specialized FunctionDeclaration
+ MATCH c1 = fd->leastAsSpecialized(m->lastf);
+ MATCH c2 = m->lastf->leastAsSpecialized(fd);
+ //printf("3: c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+
+ // Bugzilla 14450: Prefer exact qualified constructor for the creating object type
+ if (isCtorCall && fd->type->mod != m->lastf->type->mod)
+ {
+ if (tthis->mod == fd->type->mod) goto Ltd;
+ if (tthis->mod == m->lastf->type->mod) goto Ltd_best;
+ }
+
+ m->nextf = fd;
+ m->count++;
+ continue;
+
+ Ltd_best: // td_best is the best match so far
+ //printf("Ltd_best\n");
+ continue;
+
+ Ltd: // td is the new best match
+ //printf("Ltd\n");
+ assert(td->_scope);
+ td_best = td;
+ ti_best = ti;
+ property = 0; // (backward compatibility)
+ ta_last = mta;
+ m->last = mfa;
+ m->lastf = fd;
+ tthis_best = tthis_fd;
+ ov_index = ovi;
+ m->nextf = NULL;
+ m->count = 1;
+ continue;
+ }
+ return 0;
+ }
+ };
+ ParamDeduce p;
+ // context
+ p.loc = loc;
+ p.sc = sc;
+ p.tthis = tthis;
+ p.tiargs = tiargs;
+ p.fargs = fargs;
+
+ // result
+ p.m = m;
+ p.property = 0;
+ p.ov_index = 0;
+ p.td_best = NULL;
+ p.ti_best = NULL;
+ p.ta_last = m->last != MATCHnomatch ? MATCHexact : MATCHnomatch;
+ p.tthis_best = NULL;
+
+ TemplateDeclaration *td = dstart->isTemplateDeclaration();
+ if (td && td->funcroot)
+ dstart = td->funcroot;
+
+ overloadApply(dstart, &p, &ParamDeduce::fp);
+
+ //printf("td_best = %p, m->lastf = %p\n", p.td_best, m->lastf);
+ if (p.td_best && p.ti_best && m->count == 1)
+ {
+ // Matches to template function
+ assert(p.td_best->onemember && p.td_best->onemember->isFuncDeclaration());
+
+ /* The best match is td_best with arguments tdargs.
+ * Now instantiate the template.
+ */
+ assert(p.td_best->_scope);
+ if (!sc)
+ sc = p.td_best->_scope; // workaround for Type::aliasthisOf
+
+ TemplateInstance *ti = new TemplateInstance(loc, p.td_best, p.ti_best->tiargs);
+ ti->semantic(sc, fargs);
+
+ m->lastf = ti->toAlias()->isFuncDeclaration();
+ if (!m->lastf)
+ goto Lnomatch;
+ if (ti->errors)
+ {
+ Lerror:
+ m->count = 1;
+ assert(m->lastf);
+ m->last = MATCHnomatch;
+ return;
+ }
+
+ // look forward instantiated overload function
+ // Dsymbol::oneMembers is alredy called in TemplateInstance::semantic.
+ // it has filled overnext0d
+ while (p.ov_index--)
+ {
+ m->lastf = m->lastf->overnext0;
+ assert(m->lastf);
+ }
+
+ p.tthis_best = m->lastf->needThis() && !m->lastf->isCtorDeclaration() ? tthis : NULL;
+
+ TypeFunction *tf = (TypeFunction *)m->lastf->type;
+ if (tf->ty == Terror)
+ goto Lerror;
+ assert(tf->ty == Tfunction);
+ if (!tf->callMatch(p.tthis_best, fargs))
+ goto Lnomatch;
+
+ /* As Bugzilla 3682 shows, a template instance can be matched while instantiating
+ * that same template. Thus, the function type can be incomplete. Complete it.
+ *
+ * Bugzilla 9208: For auto function, completion should be deferred to the end of
+ * its semantic3. Should not complete it in here.
+ */
+ if (tf->next && !m->lastf->inferRetType)
+ {
+ m->lastf->type = tf->semantic(loc, sc);
+ }
+ }
+ else if (m->lastf)
+ {
+ // Matches to non template function,
+ // or found matches were ambiguous.
+ assert(m->count >= 1);
+ }
+ else
+ {
+ Lnomatch:
+ m->count = 0;
+ m->lastf = NULL;
+ m->last = MATCHnomatch;
+ }
+}
+
+/*************************************************
+ * Limited function template instantiation for using fd->leastAsSpecialized()
+ */
+FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(
+ TemplateInstance *ti, Scope *sc2,
+ FuncDeclaration *fd, Type *tthis, Expressions *fargs)
+{
+ assert(fd);
+
+ // function body and contracts are not need
+ if (fd->isCtorDeclaration())
+ fd = new CtorDeclaration(fd->loc, fd->endloc, fd->storage_class, fd->type->syntaxCopy());
+ else
+ fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy());
+ fd->parent = ti;
+
+ assert(fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ tf->fargs = fargs;
+
+ if (tthis)
+ {
+ // Match 'tthis' to any TemplateThisParameter's
+ bool hasttp = false;
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*parameters)[i];
+ TemplateThisParameter *ttp = tp->isTemplateThisParameter();
+ if (ttp)
+ hasttp = true;
+ }
+ if (hasttp)
+ {
+ tf = (TypeFunction *)tf->addSTC(ModToStc(tthis->mod));
+ assert(!tf->deco);
+ }
+ }
+
+ Scope *scx = sc2->push();
+
+ // Shouldn't run semantic on default arguments and return type.
+ for (size_t i = 0; i < tf->parameters->dim; i++)
+ (*tf->parameters)[i]->defaultArg = NULL;
+ if (fd->isCtorDeclaration())
+ {
+ // For constructors, emitting return type is necessary for
+ // isolateReturn() in functionResolve.
+ scx->flags |= SCOPEctor;
+
+ Dsymbol *parent = toParent2();
+ Type *tret;
+ AggregateDeclaration *ad = parent->isAggregateDeclaration();
+ if (!ad || parent->isUnionDeclaration())
+ {
+ tret = Type::tvoid;
+ }
+ else
+ {
+ tret = ad->handleType();
+ assert(tret);
+ tret = tret->addStorageClass(fd->storage_class | scx->stc);
+ tret = tret->addMod(tf->mod);
+ }
+ tf->next = tret;
+ if (ad && ad->isStructDeclaration())
+ tf->isref = 1;
+ //printf("tf = %s\n", tf->toChars());
+ }
+ else
+ tf->next = NULL;
+ fd->type = tf;
+ fd->type = fd->type->addSTC(scx->stc);
+ fd->type = fd->type->semantic(fd->loc, scx);
+ scx = scx->pop();
+
+ if (fd->type->ty != Tfunction)
+ return NULL;
+
+ fd->originalType = fd->type; // for mangling
+ //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod);
+ //printf("fd->needThis() = %d\n", fd->needThis());
+
+ return fd;
+}
+
+bool TemplateDeclaration::hasStaticCtorOrDtor()
+{
+ return false; // don't scan uninstantiated templates
+}
+
+const char *TemplateDeclaration::toChars()
+{
+ if (literal)
+ return Dsymbol::toChars();
+
+ OutBuffer buf;
+ HdrGenState hgs;
+
+ buf.writestring(ident->toChars());
+ buf.writeByte('(');
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*parameters)[i];
+ if (i)
+ buf.writestring(", ");
+ ::toCBuffer(tp, &buf, &hgs);
+ }
+ buf.writeByte(')');
+
+ if (onemember)
+ {
+ FuncDeclaration *fd = onemember->isFuncDeclaration();
+ if (fd && fd->type)
+ {
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ buf.writestring(parametersTypeToChars(tf->parameters, tf->varargs));
+ }
+ }
+
+ if (constraint)
+ {
+ buf.writestring(" if (");
+ ::toCBuffer(constraint, &buf, &hgs);
+ buf.writeByte(')');
+ }
+ return buf.extractString();
+}
+
+Prot TemplateDeclaration::prot()
+{
+ return protection;
+}
+
+/****************************************************
+ * Given a new instance tithis of this TemplateDeclaration,
+ * see if there already exists an instance.
+ * If so, return that existing instance.
+ */
+
+TemplateInstance *TemplateDeclaration::findExistingInstance(TemplateInstance *tithis, Expressions *fargs)
+{
+ //printf("findExistingInstance(%p)\n", tithis);
+ tithis->fargs = fargs;
+ TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)tithis->toHash());
+ if (tinstances)
+ {
+ for (size_t i = 0; i < tinstances->dim; i++)
+ {
+ TemplateInstance *ti = (*tinstances)[i];
+ if (tithis->compare(ti) == 0)
+ return ti;
+ }
+ }
+ return NULL;
+}
+
+/********************************************
+ * Add instance ti to TemplateDeclaration's table of instances.
+ * Return a handle we can use to later remove it if it fails instantiation.
+ */
+
+TemplateInstance *TemplateDeclaration::addInstance(TemplateInstance *ti)
+{
+ //printf("addInstance() %p %p\n", instances, ti);
+ TemplateInstances **ptinstances = (TemplateInstances **)dmd_aaGet((AA **)&instances, (void *)ti->toHash());
+ if (!*ptinstances)
+ *ptinstances = new TemplateInstances();
+ (*ptinstances)->push(ti);
+ return ti;
+}
+
+/*******************************************
+ * Remove TemplateInstance from table of instances.
+ * Input:
+ * handle returned by addInstance()
+ */
+
+void TemplateDeclaration::removeInstance(TemplateInstance *handle)
+{
+ //printf("removeInstance()\n");
+ TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)handle->toHash());
+ if (tinstances)
+ {
+ for (size_t i = 0; i < tinstances->dim; i++)
+ {
+ TemplateInstance *ti = (*tinstances)[i];
+ if (handle == ti)
+ {
+ tinstances->remove(i);
+ break;
+ }
+ }
+ }
+}
+
+/* ======================== Type ============================================ */
+
+/****
+ * Given an identifier, figure out which TemplateParameter it is.
+ * Return IDX_NOTFOUND if not found.
+ */
+
+static size_t templateIdentifierLookup(Identifier *id, TemplateParameters *parameters)
+{
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*parameters)[i];
+ if (tp->ident->equals(id))
+ return i;
+ }
+ return IDX_NOTFOUND;
+}
+
+size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters)
+{
+ if (tparam->ty == Tident)
+ {
+ TypeIdentifier *tident = (TypeIdentifier *)tparam;
+ //printf("\ttident = '%s'\n", tident->toChars());
+ return templateIdentifierLookup(tident->ident, parameters);
+ }
+ return IDX_NOTFOUND;
+}
+
+unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam)
+{
+ if ((tparam->mod & MODwild) == 0)
+ return 0;
+
+ *at = NULL;
+
+ #define X(U,T) ((U) << 4) | (T)
+ switch (X(tparam->mod, t->mod))
+ {
+ case X(MODwild, 0):
+ case X(MODwild, MODconst):
+ case X(MODwild, MODshared):
+ case X(MODwild, MODshared | MODconst):
+ case X(MODwild, MODimmutable):
+ case X(MODwildconst, 0):
+ case X(MODwildconst, MODconst):
+ case X(MODwildconst, MODshared):
+ case X(MODwildconst, MODshared | MODconst):
+ case X(MODwildconst, MODimmutable):
+ case X(MODshared | MODwild, MODshared):
+ case X(MODshared | MODwild, MODshared | MODconst):
+ case X(MODshared | MODwild, MODimmutable):
+ case X(MODshared | MODwildconst, MODshared):
+ case X(MODshared | MODwildconst, MODshared | MODconst):
+ case X(MODshared | MODwildconst, MODimmutable):
+ {
+ unsigned char wm = (t->mod & ~MODshared);
+ if (wm == 0)
+ wm = MODmutable;
+ unsigned char m = (t->mod & (MODconst | MODimmutable)) | (tparam->mod & t->mod & MODshared);
+ *at = t->unqualify(m);
+ return wm;
+ }
+
+ case X(MODwild, MODwild):
+ case X(MODwild, MODwildconst):
+ case X(MODwild, MODshared | MODwild):
+ case X(MODwild, MODshared | MODwildconst):
+ case X(MODwildconst, MODwild):
+ case X(MODwildconst, MODwildconst):
+ case X(MODwildconst, MODshared | MODwild):
+ case X(MODwildconst, MODshared | MODwildconst):
+ case X(MODshared | MODwild, MODshared | MODwild):
+ case X(MODshared | MODwild, MODshared | MODwildconst):
+ case X(MODshared | MODwildconst, MODshared | MODwild):
+ case X(MODshared | MODwildconst, MODshared | MODwildconst):
+ {
+ *at = t->unqualify(tparam->mod & t->mod);
+ return MODwild;
+ }
+
+ default:
+ return 0;
+ }
+ #undef X
+}
+
+MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam)
+{
+ // 9*9 == 81 cases
+
+ #define X(U,T) ((U) << 4) | (T)
+ switch (X(tparam->mod, t->mod))
+ {
+ case X(0, 0):
+ case X(0, MODconst):
+ case X(0, MODwild):
+ case X(0, MODwildconst):
+ case X(0, MODshared):
+ case X(0, MODshared | MODconst):
+ case X(0, MODshared | MODwild):
+ case X(0, MODshared | MODwildconst):
+ case X(0, MODimmutable):
+ // foo(U) T => T
+ // foo(U) const(T) => const(T)
+ // foo(U) inout(T) => inout(T)
+ // foo(U) inout(const(T)) => inout(const(T))
+ // foo(U) shared(T) => shared(T)
+ // foo(U) shared(const(T)) => shared(const(T))
+ // foo(U) shared(inout(T)) => shared(inout(T))
+ // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
+ // foo(U) immutable(T) => immutable(T)
+ {
+ *at = t;
+ return MATCHexact;
+ }
+
+ case X(MODconst, MODconst):
+ case X(MODwild, MODwild):
+ case X(MODwildconst, MODwildconst):
+ case X(MODshared, MODshared):
+ case X(MODshared | MODconst, MODshared | MODconst):
+ case X(MODshared | MODwild, MODshared | MODwild):
+ case X(MODshared | MODwildconst, MODshared | MODwildconst):
+ case X(MODimmutable, MODimmutable):
+ // foo(const(U)) const(T) => T
+ // foo(inout(U)) inout(T) => T
+ // foo(inout(const(U))) inout(const(T)) => T
+ // foo(shared(U)) shared(T) => T
+ // foo(shared(const(U))) shared(const(T)) => T
+ // foo(shared(inout(U))) shared(inout(T)) => T
+ // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
+ // foo(immutable(U)) immutable(T) => T
+ {
+ *at = t->mutableOf()->unSharedOf();
+ return MATCHexact;
+ }
+
+ case X(MODconst, 0):
+ case X(MODconst, MODwild):
+ case X(MODconst, MODwildconst):
+ case X(MODconst, MODshared | MODconst):
+ case X(MODconst, MODshared | MODwild):
+ case X(MODconst, MODshared | MODwildconst):
+ case X(MODconst, MODimmutable):
+ case X(MODwild, MODshared | MODwild):
+ case X(MODwildconst, MODshared | MODwildconst):
+ case X(MODshared | MODconst, MODimmutable):
+ // foo(const(U)) T => T
+ // foo(const(U)) inout(T) => T
+ // foo(const(U)) inout(const(T)) => T
+ // foo(const(U)) shared(const(T)) => shared(T)
+ // foo(const(U)) shared(inout(T)) => shared(T)
+ // foo(const(U)) shared(inout(const(T))) => shared(T)
+ // foo(const(U)) immutable(T) => T
+ // foo(inout(U)) shared(inout(T)) => shared(T)
+ // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
+ // foo(shared(const(U))) immutable(T) => T
+ {
+ *at = t->mutableOf();
+ return MATCHconst;
+ }
+
+ case X(MODconst, MODshared):
+ // foo(const(U)) shared(T) => shared(T)
+ {
+ *at = t;
+ return MATCHconst;
+ }
+
+ case X(MODshared, MODshared | MODconst):
+ case X(MODshared, MODshared | MODwild):
+ case X(MODshared, MODshared | MODwildconst):
+ case X(MODshared | MODconst, MODshared):
+ // foo(shared(U)) shared(const(T)) => const(T)
+ // foo(shared(U)) shared(inout(T)) => inout(T)
+ // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
+ // foo(shared(const(U))) shared(T) => T
+ {
+ *at = t->unSharedOf();
+ return MATCHconst;
+ }
+
+ case X(MODwildconst, MODimmutable):
+ case X(MODshared | MODconst, MODshared | MODwildconst):
+ case X(MODshared | MODwildconst, MODimmutable):
+ case X(MODshared | MODwildconst, MODshared | MODwild):
+ // foo(inout(const(U))) immutable(T) => T
+ // foo(shared(const(U))) shared(inout(const(T))) => T
+ // foo(shared(inout(const(U)))) immutable(T) => T
+ // foo(shared(inout(const(U)))) shared(inout(T)) => T
+ {
+ *at = t->unSharedOf()->mutableOf();
+ return MATCHconst;
+ }
+
+ case X(MODshared | MODconst, MODshared | MODwild):
+ // foo(shared(const(U))) shared(inout(T)) => T
+ {
+ *at = t->unSharedOf()->mutableOf();
+ return MATCHconst;
+ }
+
+ case X(MODwild, 0):
+ case X(MODwild, MODconst):
+ case X(MODwild, MODwildconst):
+ case X(MODwild, MODimmutable):
+ case X(MODwild, MODshared):
+ case X(MODwild, MODshared | MODconst):
+ case X(MODwild, MODshared | MODwildconst):
+ case X(MODwildconst, 0):
+ case X(MODwildconst, MODconst):
+ case X(MODwildconst, MODwild):
+ case X(MODwildconst, MODshared):
+ case X(MODwildconst, MODshared | MODconst):
+ case X(MODwildconst, MODshared | MODwild):
+ case X(MODshared, 0):
+ case X(MODshared, MODconst):
+ case X(MODshared, MODwild):
+ case X(MODshared, MODwildconst):
+ case X(MODshared, MODimmutable):
+ case X(MODshared | MODconst, 0):
+ case X(MODshared | MODconst, MODconst):
+ case X(MODshared | MODconst, MODwild):
+ case X(MODshared | MODconst, MODwildconst):
+ case X(MODshared | MODwild, 0):
+ case X(MODshared | MODwild, MODconst):
+ case X(MODshared | MODwild, MODwild):
+ case X(MODshared | MODwild, MODwildconst):
+ case X(MODshared | MODwild, MODimmutable):
+ case X(MODshared | MODwild, MODshared):
+ case X(MODshared | MODwild, MODshared | MODconst):
+ case X(MODshared | MODwild, MODshared | MODwildconst):
+ case X(MODshared | MODwildconst, 0):
+ case X(MODshared | MODwildconst, MODconst):
+ case X(MODshared | MODwildconst, MODwild):
+ case X(MODshared | MODwildconst, MODwildconst):
+ case X(MODshared | MODwildconst, MODshared):
+ case X(MODshared | MODwildconst, MODshared | MODconst):
+ case X(MODimmutable, 0):
+ case X(MODimmutable, MODconst):
+ case X(MODimmutable, MODwild):
+ case X(MODimmutable, MODwildconst):
+ case X(MODimmutable, MODshared):
+ case X(MODimmutable, MODshared | MODconst):
+ case X(MODimmutable, MODshared | MODwild):
+ case X(MODimmutable, MODshared | MODwildconst):
+ // foo(inout(U)) T => nomatch
+ // foo(inout(U)) const(T) => nomatch
+ // foo(inout(U)) inout(const(T)) => nomatch
+ // foo(inout(U)) immutable(T) => nomatch
+ // foo(inout(U)) shared(T) => nomatch
+ // foo(inout(U)) shared(const(T)) => nomatch
+ // foo(inout(U)) shared(inout(const(T))) => nomatch
+ // foo(inout(const(U))) T => nomatch
+ // foo(inout(const(U))) const(T) => nomatch
+ // foo(inout(const(U))) inout(T) => nomatch
+ // foo(inout(const(U))) shared(T) => nomatch
+ // foo(inout(const(U))) shared(const(T)) => nomatch
+ // foo(inout(const(U))) shared(inout(T)) => nomatch
+ // foo(shared(U)) T => nomatch
+ // foo(shared(U)) const(T) => nomatch
+ // foo(shared(U)) inout(T) => nomatch
+ // foo(shared(U)) inout(const(T)) => nomatch
+ // foo(shared(U)) immutable(T) => nomatch
+ // foo(shared(const(U))) T => nomatch
+ // foo(shared(const(U))) const(T) => nomatch
+ // foo(shared(const(U))) inout(T) => nomatch
+ // foo(shared(const(U))) inout(const(T)) => nomatch
+ // foo(shared(inout(U))) T => nomatch
+ // foo(shared(inout(U))) const(T) => nomatch
+ // foo(shared(inout(U))) inout(T) => nomatch
+ // foo(shared(inout(U))) inout(const(T)) => nomatch
+ // foo(shared(inout(U))) immutable(T) => nomatch
+ // foo(shared(inout(U))) shared(T) => nomatch
+ // foo(shared(inout(U))) shared(const(T)) => nomatch
+ // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
+ // foo(shared(inout(const(U)))) T => nomatch
+ // foo(shared(inout(const(U)))) const(T) => nomatch
+ // foo(shared(inout(const(U)))) inout(T) => nomatch
+ // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
+ // foo(shared(inout(const(U)))) shared(T) => nomatch
+ // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
+ // foo(immutable(U)) T => nomatch
+ // foo(immutable(U)) const(T) => nomatch
+ // foo(immutable(U)) inout(T) => nomatch
+ // foo(immutable(U)) inout(const(T)) => nomatch
+ // foo(immutable(U)) shared(T) => nomatch
+ // foo(immutable(U)) shared(const(T)) => nomatch
+ // foo(immutable(U)) shared(inout(T)) => nomatch
+ // foo(immutable(U)) shared(inout(const(T))) => nomatch
+ return MATCHnomatch;
+
+ default:
+ assert(0);
+ return MATCHnomatch; // silence compiler warning about missing return
+ }
+ #undef X
+}
+
+/* These form the heart of template argument deduction.
+ * Given 'this' being the type argument to the template instance,
+ * it is matched against the template declaration parameter specialization
+ * 'tparam' to determine the type to be used for the parameter.
+ * Example:
+ * template Foo(T:T*) // template declaration
+ * Foo!(int*) // template instantiation
+ * Input:
+ * this = int*
+ * tparam = T*
+ * parameters = [ T:T* ] // Array of TemplateParameter's
+ * Output:
+ * dedtypes = [ int ] // Array of Expression/Type's
+ */
+MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters,
+ Objects *dedtypes, unsigned *wm, size_t inferStart)
+{
+ class DeduceType : public Visitor
+ {
+ public:
+ Scope *sc;
+ Type *tparam;
+ TemplateParameters *parameters;
+ Objects *dedtypes;
+ unsigned *wm;
+ size_t inferStart;
+ MATCH result;
+
+ DeduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm, size_t inferStart)
+ : sc(sc), tparam(tparam), parameters(parameters), dedtypes(dedtypes), wm(wm), inferStart(inferStart)
+ {
+ result = MATCHnomatch;
+ }
+
+ void visit(Type *t)
+ {
+ if (!tparam)
+ goto Lnomatch;
+
+ if (t == tparam)
+ goto Lexact;
+
+ if (tparam->ty == Tident)
+ {
+ // Determine which parameter tparam is
+ size_t i = templateParameterLookup(tparam, parameters);
+ if (i == IDX_NOTFOUND)
+ {
+ if (!sc)
+ goto Lnomatch;
+
+ /* Need a loc to go with the semantic routine.
+ */
+ Loc loc;
+ if (parameters->dim)
+ {
+ TemplateParameter *tp = (*parameters)[0];
+ loc = tp->loc;
+ }
+
+ /* BUG: what if tparam is a template instance, that
+ * has as an argument another Tident?
+ */
+ tparam = tparam->semantic(loc, sc);
+ assert(tparam->ty != Tident);
+ result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
+ return;
+ }
+
+ TemplateParameter *tp = (*parameters)[i];
+
+ TypeIdentifier *tident = (TypeIdentifier *)tparam;
+ if (tident->idents.dim > 0)
+ {
+ //printf("matching %s to %s\n", tparam->toChars(), t->toChars());
+ Dsymbol *s = t->toDsymbol(sc);
+ for (size_t j = tident->idents.dim; j-- > 0; )
+ {
+ RootObject *id = tident->idents[j];
+ if (id->dyncast() == DYNCAST_IDENTIFIER)
+ {
+ if (!s || !s->parent)
+ goto Lnomatch;
+ Dsymbol *s2 = s->parent->search(Loc(), (Identifier *)id);
+ if (!s2)
+ goto Lnomatch;
+ s2 = s2->toAlias();
+ //printf("[%d] s = %s %s, s2 = %s %s\n", j, s->kind(), s->toChars(), s2->kind(), s2->toChars());
+ if (s != s2)
+ {
+ if (Type *tx = s2->getType())
+ {
+ if (s != tx->toDsymbol(sc))
+ goto Lnomatch;
+ }
+ else
+ goto Lnomatch;
+ }
+ s = s->parent;
+ }
+ else
+ goto Lnomatch;
+ }
+ //printf("[e] s = %s\n", s?s->toChars():"(null)");
+ if (tp->isTemplateTypeParameter())
+ {
+ Type *tt = s->getType();
+ if (!tt)
+ goto Lnomatch;
+ Type *at = (Type *)(*dedtypes)[i];
+ if (at && at->ty == Tnone)
+ at = ((TypeDeduced *)at)->tded;
+ if (!at || tt->equals(at))
+ {
+ (*dedtypes)[i] = tt;
+ goto Lexact;
+ }
+ }
+ if (tp->isTemplateAliasParameter())
+ {
+ Dsymbol *s2 = (Dsymbol *)(*dedtypes)[i];
+ if (!s2 || s == s2)
+ {
+ (*dedtypes)[i] = s;
+ goto Lexact;
+ }
+ }
+ goto Lnomatch;
+ }
+
+ // Found the corresponding parameter tp
+ if (!tp->isTemplateTypeParameter())
+ goto Lnomatch;
+
+ Type *at = (Type *)(*dedtypes)[i];
+ Type *tt;
+ if (unsigned char wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
+ {
+ // type vs (none)
+ if (!at)
+ {
+ (*dedtypes)[i] = tt;
+ *wm |= wx;
+ result = MATCHconst;
+ return;
+ }
+
+ // type vs expressions
+ if (at->ty == Tnone)
+ {
+ TypeDeduced *xt = (TypeDeduced *)at;
+ result = xt->matchAll(tt);
+ if (result > MATCHnomatch)
+ {
+ (*dedtypes)[i] = tt;
+ if (result > MATCHconst)
+ result = MATCHconst; // limit level for inout matches
+ delete xt;
+ }
+ return;
+ }
+
+ // type vs type
+ if (tt->equals(at))
+ {
+ (*dedtypes)[i] = tt; // Prefer current type match
+ goto Lconst;
+ }
+ if (tt->implicitConvTo(at->constOf()))
+ {
+ (*dedtypes)[i] = at->constOf()->mutableOf();
+ *wm |= MODconst;
+ goto Lconst;
+ }
+ if (at->implicitConvTo(tt->constOf()))
+ {
+ (*dedtypes)[i] = tt->constOf()->mutableOf();
+ *wm |= MODconst;
+ goto Lconst;
+ }
+ goto Lnomatch;
+ }
+ else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
+ {
+ // type vs (none)
+ if (!at)
+ {
+ (*dedtypes)[i] = tt;
+ result = m;
+ return;
+ }
+
+ // type vs expressions
+ if (at->ty == Tnone)
+ {
+ TypeDeduced *xt = (TypeDeduced *)at;
+ result = xt->matchAll(tt);
+ if (result > MATCHnomatch)
+ {
+ (*dedtypes)[i] = tt;
+ delete xt;
+ }
+ return;
+ }
+
+ // type vs type
+ if (tt->equals(at))
+ {
+ goto Lexact;
+ }
+ if (tt->ty == Tclass && at->ty == Tclass)
+ {
+ result = tt->implicitConvTo(at);
+ return;
+ }
+ if (tt->ty == Tsarray && at->ty == Tarray &&
+ tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst)
+ {
+ goto Lexact;
+ }
+ }
+ goto Lnomatch;
+ }
+
+ if (tparam->ty == Ttypeof)
+ {
+ /* Need a loc to go with the semantic routine.
+ */
+ Loc loc;
+ if (parameters->dim)
+ {
+ TemplateParameter *tp = (*parameters)[0];
+ loc = tp->loc;
+ }
+
+ tparam = tparam->semantic(loc, sc);
+ }
+ if (t->ty != tparam->ty)
+ {
+ if (Dsymbol *sym = t->toDsymbol(sc))
+ {
+ if (sym->isforwardRef() && !tparam->deco)
+ goto Lnomatch;
+ }
+
+ MATCH m = t->implicitConvTo(tparam);
+ if (m == MATCHnomatch)
+ {
+ if (t->ty == Tclass)
+ {
+ TypeClass *tc = (TypeClass *)t;
+ if (tc->sym->aliasthis && !(tc->att & RECtracingDT))
+ {
+ tc->att = (AliasThisRec)(tc->att | RECtracingDT);
+ m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm);
+ tc->att = (AliasThisRec)(tc->att & ~RECtracingDT);
+ }
+ }
+ else if (t->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)t;
+ if (ts->sym->aliasthis && !(ts->att & RECtracingDT))
+ {
+ ts->att = (AliasThisRec)(ts->att | RECtracingDT);
+ m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm);
+ ts->att = (AliasThisRec)(ts->att & ~RECtracingDT);
+ }
+ }
+ }
+ result = m;
+ return;
+ }
+
+ if (t->nextOf())
+ {
+ if (tparam->deco && !tparam->hasWild())
+ {
+ result = t->implicitConvTo(tparam);
+ return;
+ }
+
+ Type *tpn = tparam->nextOf();
+ if (wm && t->ty == Taarray && tparam->isWild())
+ {
+ // Bugzilla 12403: In IFTI, stop inout matching on transitive part of AA types.
+ tpn = tpn->substWildTo(MODmutable);
+ }
+
+ result = deduceType(t->nextOf(), sc, tpn, parameters, dedtypes, wm);
+ return;
+ }
+
+ Lexact:
+ result = MATCHexact;
+ return;
+
+ Lnomatch:
+ result = MATCHnomatch;
+ return;
+
+ Lconst:
+ result = MATCHconst;
+ }
+
+ void visit(TypeVector *t)
+ {
+ if (tparam->ty == Tvector)
+ {
+ TypeVector *tp = (TypeVector *)tparam;
+ result = deduceType(t->basetype, sc, tp->basetype, parameters, dedtypes, wm);
+ return;
+ }
+ visit((Type *)t);
+ }
+
+ void visit(TypeDArray *t)
+ {
+ visit((Type *)t);
+ }
+
+ void visit(TypeSArray *t)
+ {
+ // Extra check that array dimensions must match
+ if (tparam)
+ {
+ if (tparam->ty == Tarray)
+ {
+ MATCH m = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm);
+ result = (m >= MATCHconst) ? MATCHconvert : MATCHnomatch;
+ return;
+ }
+
+ TemplateParameter *tp = NULL;
+ Expression *edim = NULL;
+ size_t i;
+ if (tparam->ty == Tsarray)
+ {
+ TypeSArray *tsa = (TypeSArray *)tparam;
+ if (tsa->dim->op == TOKvar &&
+ ((VarExp *)tsa->dim)->var->storage_class & STCtemplateparameter)
+ {
+ Identifier *id = ((VarExp *)tsa->dim)->var->ident;
+ i = templateIdentifierLookup(id, parameters);
+ assert(i != IDX_NOTFOUND);
+ tp = (*parameters)[i];
+ }
+ else
+ edim = tsa->dim;
+ }
+ else if (tparam->ty == Taarray)
+ {
+ TypeAArray *taa = (TypeAArray *)tparam;
+ i = templateParameterLookup(taa->index, parameters);
+ if (i != IDX_NOTFOUND)
+ tp = (*parameters)[i];
+ else
+ {
+ Expression *e;
+ Type *tx;
+ Dsymbol *s;
+ taa->index->resolve(Loc(), sc, &e, &tx, &s);
+ edim = s ? getValue(s) : getValue(e);
+ }
+ }
+ if ((tp && tp->matchArg(sc, t->dim, i, parameters, dedtypes, NULL)) ||
+ (edim && edim->toInteger() == t->dim->toInteger()))
+ {
+ result = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm);
+ return;
+ }
+ }
+ visit((Type *)t);
+ return;
+
+ result = MATCHnomatch;
+ }
+
+ void visit(TypeAArray *t)
+ {
+ // Extra check that index type must match
+ if (tparam && tparam->ty == Taarray)
+ {
+ TypeAArray *tp = (TypeAArray *)tparam;
+ if (!deduceType(t->index, sc, tp->index, parameters, dedtypes))
+ {
+ result = MATCHnomatch;
+ return;
+ }
+ }
+ visit((Type *)t);
+ }
+
+ void visit(TypeFunction *t)
+ {
+ //printf("TypeFunction::deduceType()\n");
+ //printf("\tthis = %d, ", t->ty); t->print();
+ //printf("\ttparam = %d, ", tparam->ty); tparam->print();
+
+ // Extra check that function characteristics must match
+ if (tparam && tparam->ty == Tfunction)
+ {
+ TypeFunction *tp = (TypeFunction *)tparam;
+ if (t->varargs != tp->varargs ||
+ t->linkage != tp->linkage)
+ {
+ result = MATCHnomatch;
+ return;
+ }
+
+ size_t nfargs = Parameter::dim(t->parameters);
+ size_t nfparams = Parameter::dim(tp->parameters);
+
+ // bug 2579 fix: Apply function parameter storage classes to parameter types
+ for (size_t i = 0; i < nfparams; i++)
+ {
+ Parameter *fparam = Parameter::getNth(tp->parameters, i);
+ fparam->type = fparam->type->addStorageClass(fparam->storageClass);
+ fparam->storageClass &= ~(STC_TYPECTOR | STCin);
+ }
+ //printf("\t-> this = %d, ", t->ty); t->print();
+ //printf("\t-> tparam = %d, ", tparam->ty); tparam->print();
+
+ /* See if tuple match
+ */
+ if (nfparams > 0 && nfargs >= nfparams - 1)
+ {
+ /* See if 'A' of the template parameter matches 'A'
+ * of the type of the last function parameter.
+ */
+ Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1);
+ assert(fparam);
+ assert(fparam->type);
+ if (fparam->type->ty != Tident)
+ goto L1;
+ TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
+ if (tid->idents.dim)
+ goto L1;
+
+ /* Look through parameters to find tuple matching tid->ident
+ */
+ size_t tupi = 0;
+ for (; 1; tupi++)
+ {
+ if (tupi == parameters->dim)
+ goto L1;
+ TemplateParameter *tx = (*parameters)[tupi];
+ TemplateTupleParameter *tup = tx->isTemplateTupleParameter();
+ if (tup && tup->ident->equals(tid->ident))
+ break;
+ }
+
+ /* The types of the function arguments [nfparams - 1 .. nfargs]
+ * now form the tuple argument.
+ */
+ size_t tuple_dim = nfargs - (nfparams - 1);
+
+ /* See if existing tuple, and whether it matches or not
+ */
+ RootObject *o = (*dedtypes)[tupi];
+ if (o)
+ {
+ // Existing deduced argument must be a tuple, and must match
+ Tuple *tup = isTuple(o);
+ if (!tup || tup->objects.dim != tuple_dim)
+ {
+ result = MATCHnomatch;
+ return;
+ }
+ for (size_t i = 0; i < tuple_dim; i++)
+ {
+ Parameter *arg = Parameter::getNth(t->parameters, nfparams - 1 + i);
+ if (!arg->type->equals(tup->objects[i]))
+ {
+ result = MATCHnomatch;
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Create new tuple
+ Tuple *tup = new Tuple();
+ tup->objects.setDim(tuple_dim);
+ for (size_t i = 0; i < tuple_dim; i++)
+ {
+ Parameter *arg = Parameter::getNth(t->parameters, nfparams - 1 + i);
+ tup->objects[i] = arg->type;
+ }
+ (*dedtypes)[tupi] = tup;
+ }
+ nfparams--; // don't consider the last parameter for type deduction
+ goto L2;
+ }
+
+ L1:
+ if (nfargs != nfparams)
+ {
+ result = MATCHnomatch;
+ return;
+ }
+ L2:
+ for (size_t i = 0; i < nfparams; i++)
+ {
+ Parameter *a = Parameter::getNth(t->parameters, i);
+ Parameter *ap = Parameter::getNth(tp->parameters, i);
+
+ if (!a->isCovariant(t->isref, ap) ||
+ !deduceType(a->type, sc, ap->type, parameters, dedtypes))
+ {
+ result = MATCHnomatch;
+ return;
+ }
+ }
+ }
+ visit((Type *)t);
+ }
+
+ void visit(TypeIdentifier *t)
+ {
+ // Extra check
+ if (tparam && tparam->ty == Tident)
+ {
+ TypeIdentifier *tp = (TypeIdentifier *)tparam;
+
+ for (size_t i = 0; i < t->idents.dim; i++)
+ {
+ RootObject *id1 = t->idents[i];
+ RootObject *id2 = tp->idents[i];
+
+ if (!id1->equals(id2))
+ {
+ result = MATCHnomatch;
+ return;
+ }
+ }
+ }
+ visit((Type *)t);
+ }
+
+ void visit(TypeInstance *t)
+ {
+ // Extra check
+ if (tparam && tparam->ty == Tinstance && t->tempinst->tempdecl)
+ {
+ TemplateDeclaration *tempdecl = t->tempinst->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ TypeInstance *tp = (TypeInstance *)tparam;
+
+ //printf("tempinst->tempdecl = %p\n", tempdecl);
+ //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
+ if (!tp->tempinst->tempdecl)
+ {
+ //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars());
+
+ /* Handle case of:
+ * template Foo(T : sa!(T), alias sa)
+ */
+ size_t i = templateIdentifierLookup(tp->tempinst->name, parameters);
+ if (i == IDX_NOTFOUND)
+ {
+ /* Didn't find it as a parameter identifier. Try looking
+ * it up and seeing if is an alias. See Bugzilla 1454
+ */
+ TypeIdentifier *tid = new TypeIdentifier(tp->loc, tp->tempinst->name);
+ Type *tx;
+ Expression *e;
+ Dsymbol *s;
+ tid->resolve(tp->loc, sc, &e, &tx, &s);
+ if (tx)
+ {
+ s = tx->toDsymbol(sc);
+ if (TemplateInstance *ti = s ? s->parent->isTemplateInstance() : NULL)
+ {
+ // Bugzilla 14290: Try to match with ti->tempecl,
+ // only when ti is an enclosing instance.
+ Dsymbol *p = sc->parent;
+ while (p && p != ti)
+ p = p->parent;
+ if (p)
+ s = ti->tempdecl;
+ }
+ }
+ if (s)
+ {
+ s = s->toAlias();
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (td)
+ {
+ if (td->overroot)
+ td = td->overroot;
+ for (; td; td = td->overnext)
+ {
+ if (td == tempdecl)
+ goto L2;
+ }
+ }
+ }
+ goto Lnomatch;
+ }
+ TemplateParameter *tpx = (*parameters)[i];
+ if (!tpx->matchArg(sc, tempdecl, i, parameters, dedtypes, NULL))
+ goto Lnomatch;
+ }
+ else if (tempdecl != tp->tempinst->tempdecl)
+ goto Lnomatch;
+
+ L2:
+
+ for (size_t i = 0; 1; i++)
+ {
+ //printf("\ttest: tempinst->tiargs[%d]\n", i);
+ RootObject *o1 = NULL;
+ if (i < t->tempinst->tiargs->dim)
+ o1 = (*t->tempinst->tiargs)[i];
+ else if (i < t->tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim)
+ {
+ // Pick up default arg
+ o1 = t->tempinst->tdtypes[i];
+ }
+ else if (i >= tp->tempinst->tiargs->dim)
+ break;
+
+ if (i >= tp->tempinst->tiargs->dim)
+ {
+ size_t dim = tempdecl->parameters->dim - (tempdecl->isVariadic() ? 1 : 0);
+ while (i < dim && ((*tempdecl->parameters)[i]->dependent ||
+ (*tempdecl->parameters)[i]->hasDefaultArg()))
+ {
+ i++;
+ }
+ if (i >= dim)
+ break; // match if all remained parameters are dependent
+ goto Lnomatch;
+ }
+
+ RootObject *o2 = (*tp->tempinst->tiargs)[i];
+ Type *t2 = isType(o2);
+
+ size_t j = (t2 && t2->ty == Tident && i == tp->tempinst->tiargs->dim - 1)
+ ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
+ if (j != IDX_NOTFOUND && j == parameters->dim - 1 &&
+ (*parameters)[j]->isTemplateTupleParameter())
+ {
+ /* Given:
+ * struct A(B...) {}
+ * alias A!(int, float) X;
+ * static if (is(X Y == A!(Z), Z...)) {}
+ * deduce that Z is a tuple(int, float)
+ */
+
+ /* Create tuple from remaining args
+ */
+ Tuple *vt = new Tuple();
+ size_t vtdim = (tempdecl->isVariadic()
+ ? t->tempinst->tiargs->dim : t->tempinst->tdtypes.dim) - i;
+ vt->objects.setDim(vtdim);
+ for (size_t k = 0; k < vtdim; k++)
+ {
+ RootObject *o;
+ if (k < t->tempinst->tiargs->dim)
+ o = (*t->tempinst->tiargs)[i + k];
+ else // Pick up default arg
+ o = t->tempinst->tdtypes[i + k];
+ vt->objects[k] = o;
+ }
+
+ Tuple *v = (Tuple *)(*dedtypes)[j];
+ if (v)
+ {
+ if (!match(v, vt))
+ goto Lnomatch;
+ }
+ else
+ (*dedtypes)[j] = vt;
+ break;
+ }
+ else if (!o1)
+ break;
+
+ Type *t1 = isType(o1);
+ Dsymbol *s1 = isDsymbol(o1);
+ Dsymbol *s2 = isDsymbol(o2);
+ Expression *e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
+ Expression *e2 = isExpression(o2);
+
+ if (t1 && t2)
+ {
+ if (!deduceType(t1, sc, t2, parameters, dedtypes))
+ goto Lnomatch;
+ }
+ else if (e1 && e2)
+ {
+ Le:
+ e1 = e1->ctfeInterpret();
+
+ /* If it is one of the template parameters for this template,
+ * we should not attempt to interpret it. It already has a value.
+ */
+ if (e2->op == TOKvar &&
+ (((VarExp *)e2)->var->storage_class & STCtemplateparameter))
+ {
+ /*
+ * (T:Number!(e2), int e2)
+ */
+ j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters);
+ if (j != IDX_NOTFOUND)
+ goto L1;
+ // The template parameter was not from this template
+ // (it may be from a parent template, for example)
+ }
+
+ e2 = ::semantic(e2, sc); // Bugzilla 13417
+ e2 = e2->ctfeInterpret();
+
+ //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty);
+ //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty);
+ if (!e1->equals(e2))
+ {
+ if (!e2->implicitConvTo(e1->type))
+ goto Lnomatch;
+
+ e2 = e2->implicitCastTo(sc, e1->type);
+ e2 = e2->ctfeInterpret();
+ if (!e1->equals(e2))
+ goto Lnomatch;
+ }
+ }
+ else if (e1 && t2 && t2->ty == Tident)
+ {
+ j = templateParameterLookup(t2, parameters);
+ L1:
+ if (j == IDX_NOTFOUND)
+ {
+ t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2);
+ if (e2)
+ goto Le;
+ goto Lnomatch;
+ }
+ if (!(*parameters)[j]->matchArg(sc, e1, j, parameters, dedtypes, NULL))
+ goto Lnomatch;
+ }
+ else if (s1 && s2)
+ {
+ Ls:
+ if (!s1->equals(s2))
+ goto Lnomatch;
+ }
+ else if (s1 && t2 && t2->ty == Tident)
+ {
+ j = templateParameterLookup(t2, parameters);
+ if (j == IDX_NOTFOUND)
+ {
+ t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2);
+ if (s2)
+ goto Ls;
+ goto Lnomatch;
+ }
+ if (!(*parameters)[j]->matchArg(sc, s1, j, parameters, dedtypes, NULL))
+ goto Lnomatch;
+ }
+ else
+ goto Lnomatch;
+ }
+ }
+ visit((Type *)t);
+ return;
+
+ Lnomatch:
+ //printf("no match\n");
+ result = MATCHnomatch;
+ }
+
+ void visit(TypeStruct *t)
+ {
+ /* If this struct is a template struct, and we're matching
+ * it against a template instance, convert the struct type
+ * to a template instance, too, and try again.
+ */
+ TemplateInstance *ti = t->sym->parent->isTemplateInstance();
+
+ if (tparam && tparam->ty == Tinstance)
+ {
+ if (ti && ti->toAlias() == t->sym)
+ {
+ TypeInstance *tx = new TypeInstance(Loc(), ti);
+ result = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
+ return;
+ }
+
+ /* Match things like:
+ * S!(T).foo
+ */
+ TypeInstance *tpi = (TypeInstance *)tparam;
+ if (tpi->idents.dim)
+ {
+ RootObject *id = tpi->idents[tpi->idents.dim - 1];
+ if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id))
+ {
+ Type *tparent = t->sym->parent->getType();
+ if (tparent)
+ {
+ /* Slice off the .foo in S!(T).foo
+ */
+ tpi->idents.dim--;
+ result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
+ tpi->idents.dim++;
+ return;
+ }
+ }
+ }
+ }
+
+ // Extra check
+ if (tparam && tparam->ty == Tstruct)
+ {
+ TypeStruct *tp = (TypeStruct *)tparam;
+
+ //printf("\t%d\n", (MATCH) t->implicitConvTo(tp));
+ if (wm && t->deduceWild(tparam, false))
+ {
+ result = MATCHconst;
+ return;
+ }
+ result = t->implicitConvTo(tp);
+ return;
+ }
+ visit((Type *)t);
+ }
+
+ void visit(TypeEnum *t)
+ {
+ // Extra check
+ if (tparam && tparam->ty == Tenum)
+ {
+ TypeEnum *tp = (TypeEnum *)tparam;
+ if (t->sym == tp->sym)
+ visit((Type *)t);
+ else
+ result = MATCHnomatch;
+ return;
+ }
+ Type *tb = t->toBasetype();
+ if (tb->ty == tparam->ty ||
+ (tb->ty == Tsarray && tparam->ty == Taarray))
+ {
+ result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
+ return;
+ }
+ visit((Type *)t);
+ }
+
+ /* Helper for TypeClass::deduceType().
+ * Classes can match with implicit conversion to a base class or interface.
+ * This is complicated, because there may be more than one base class which
+ * matches. In such cases, one or more parameters remain ambiguous.
+ * For example,
+ *
+ * interface I(X, Y) {}
+ * class C : I(uint, double), I(char, double) {}
+ * C x;
+ * foo(T, U)( I!(T, U) x)
+ *
+ * deduces that U is double, but T remains ambiguous (could be char or uint).
+ *
+ * Given a baseclass b, and initial deduced types 'dedtypes', this function
+ * tries to match tparam with b, and also tries all base interfaces of b.
+ * If a match occurs, numBaseClassMatches is incremented, and the new deduced
+ * types are ANDed with the current 'best' estimate for dedtypes.
+ */
+ static void deduceBaseClassParameters(BaseClass *b,
+ Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes,
+ Objects *best, int &numBaseClassMatches)
+ {
+ TemplateInstance *parti = b->sym ? b->sym->parent->isTemplateInstance() : NULL;
+ if (parti)
+ {
+ // Make a temporary copy of dedtypes so we don't destroy it
+ Objects *tmpdedtypes = new Objects();
+ tmpdedtypes->setDim(dedtypes->dim);
+ memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->dim * sizeof(void *));
+
+ TypeInstance *t = new TypeInstance(Loc(), parti);
+ MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
+ if (m > MATCHnomatch)
+ {
+ // If this is the first ever match, it becomes our best estimate
+ if (numBaseClassMatches==0)
+ memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->dim * sizeof(void *));
+ else for (size_t k = 0; k < tmpdedtypes->dim; ++k)
+ {
+ // If we've found more than one possible type for a parameter,
+ // mark it as unknown.
+ if ((*tmpdedtypes)[k] != (*best)[k])
+ (*best)[k] = (*dedtypes)[k];
+ }
+ ++numBaseClassMatches;
+ }
+ }
+ // Now recursively test the inherited interfaces
+ for (size_t j = 0; j < b->baseInterfaces.length; ++j)
+ {
+ BaseClass *bi = &b->baseInterfaces.ptr[j];
+ deduceBaseClassParameters(bi,
+ sc, tparam, parameters, dedtypes,
+ best, numBaseClassMatches);
+ }
+
+ }
+
+ void visit(TypeClass *t)
+ {
+ //printf("TypeClass::deduceType(this = %s)\n", t->toChars());
+
+ /* If this class is a template class, and we're matching
+ * it against a template instance, convert the class type
+ * to a template instance, too, and try again.
+ */
+ TemplateInstance *ti = t->sym->parent->isTemplateInstance();
+
+ if (tparam && tparam->ty == Tinstance)
+ {
+ if (ti && ti->toAlias() == t->sym)
+ {
+ TypeInstance *tx = new TypeInstance(Loc(), ti);
+ MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
+ // Even if the match fails, there is still a chance it could match
+ // a base class.
+ if (m != MATCHnomatch)
+ {
+ result = m;
+ return;
+ }
+ }
+
+ /* Match things like:
+ * S!(T).foo
+ */
+ TypeInstance *tpi = (TypeInstance *)tparam;
+ if (tpi->idents.dim)
+ {
+ RootObject *id = tpi->idents[tpi->idents.dim - 1];
+ if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id))
+ {
+ Type *tparent = t->sym->parent->getType();
+ if (tparent)
+ {
+ /* Slice off the .foo in S!(T).foo
+ */
+ tpi->idents.dim--;
+ result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
+ tpi->idents.dim++;
+ return;
+ }
+ }
+ }
+
+ // If it matches exactly or via implicit conversion, we're done
+ visit((Type *)t);
+ if (result != MATCHnomatch)
+ return;
+
+ /* There is still a chance to match via implicit conversion to
+ * a base class or interface. Because there could be more than one such
+ * match, we need to check them all.
+ */
+
+ int numBaseClassMatches = 0; // Have we found an interface match?
+
+ // Our best guess at dedtypes
+ Objects *best = new Objects();
+ best->setDim(dedtypes->dim);
+
+ ClassDeclaration *s = t->sym;
+ while (s && s->baseclasses->dim > 0)
+ {
+ // Test the base class
+ deduceBaseClassParameters((*s->baseclasses)[0],
+ sc, tparam, parameters, dedtypes,
+ best, numBaseClassMatches);
+
+ // Test the interfaces inherited by the base class
+ for (size_t i = 0; i < s->interfaces.length; ++i)
+ {
+ BaseClass *b = s->interfaces.ptr[i];
+ deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes,
+ best, numBaseClassMatches);
+ }
+ s = (*s->baseclasses)[0]->sym;
+ }
+
+ if (numBaseClassMatches == 0)
+ {
+ result = MATCHnomatch;
+ return;
+ }
+
+ // If we got at least one match, copy the known types into dedtypes
+ memcpy(dedtypes->tdata(), best->tdata(), best->dim * sizeof(void *));
+ result = MATCHconvert;
+ return;
+ }
+
+ // Extra check
+ if (tparam && tparam->ty == Tclass)
+ {
+ TypeClass *tp = (TypeClass *)tparam;
+
+ //printf("\t%d\n", (MATCH) t->implicitConvTo(tp));
+ if (wm && t->deduceWild(tparam, false))
+ {
+ result = MATCHconst;
+ return;
+ }
+ result = t->implicitConvTo(tp);
+ return;
+ }
+ visit((Type *)t);
+ }
+
+ void visit(Expression *e)
+ {
+ //printf("Expression::deduceType(e = %s)\n", e->toChars());
+ size_t i = templateParameterLookup(tparam, parameters);
+ if (i == IDX_NOTFOUND || ((TypeIdentifier *)tparam)->idents.dim > 0)
+ {
+ if (e == emptyArrayElement && tparam->ty == Tarray)
+ {
+ Type *tn = ((TypeNext *)tparam)->next;
+ result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
+ return;
+ }
+ e->type->accept(this);
+ return;
+ }
+
+ TemplateTypeParameter *tp = (*parameters)[i]->isTemplateTypeParameter();
+ if (!tp)
+ return; // nomatch
+
+ if (e == emptyArrayElement)
+ {
+ if ((*dedtypes)[i])
+ {
+ result = MATCHexact;
+ return;
+ }
+ if (tp->defaultType)
+ {
+ tp->defaultType->accept(this);
+ return;
+ }
+ }
+
+ Type *at = (Type *)(*dedtypes)[i];
+ Type *tt;
+ if (unsigned char wx = deduceWildHelper(e->type, &tt, tparam))
+ {
+ *wm |= wx;
+ result = MATCHconst;
+ }
+ else if (MATCH m = deduceTypeHelper(e->type, &tt, tparam))
+ {
+ result = m;
+ }
+ else
+ return; // nomatch
+
+ // expression vs (none)
+ if (!at)
+ {
+ (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
+ return;
+ }
+
+ TypeDeduced *xt = NULL;
+ if (at->ty == Tnone)
+ {
+ xt = (TypeDeduced *)at;
+ at = xt->tded;
+ }
+
+ // From previous matched expressions to current deduced type
+ MATCH match1 = xt ? xt->matchAll(tt) : MATCHnomatch;
+
+ // From current expresssion to previous deduced type
+ Type *pt = at->addMod(tparam->mod);
+ if (*wm)
+ pt = pt->substWildTo(*wm);
+ MATCH match2 = e->implicitConvTo(pt);
+
+ if (match1 > MATCHnomatch && match2 > MATCHnomatch)
+ {
+ if (at->implicitConvTo(tt) <= MATCHnomatch)
+ match1 = MATCHnomatch; // Prefer at
+ else if (tt->implicitConvTo(at) <= MATCHnomatch)
+ match2 = MATCHnomatch; // Prefer tt
+ else if (tt->isTypeBasic() && tt->ty == at->ty && tt->mod != at->mod)
+ {
+ if (!tt->isMutable() && !at->isMutable())
+ tt = tt->mutableOf()->addMod(MODmerge(tt->mod, at->mod));
+ else if (tt->isMutable())
+ {
+ if (at->mod == 0) // Prefer unshared
+ match1 = MATCHnomatch;
+ else
+ match2 = MATCHnomatch;
+ }
+ else if (at->isMutable())
+ {
+ if (tt->mod == 0) // Prefer unshared
+ match2 = MATCHnomatch;
+ else
+ match1 = MATCHnomatch;
+ }
+ //printf("tt = %s, at = %s\n", tt->toChars(), at->toChars());
+ }
+ else
+ {
+ match1 = MATCHnomatch;
+ match2 = MATCHnomatch;
+ }
+ }
+ if (match1 > MATCHnomatch)
+ {
+ // Prefer current match: tt
+ if (xt)
+ xt->update(tt, e, tparam);
+ else
+ (*dedtypes)[i] = tt;
+ result = match1;
+ return;
+ }
+ if (match2 > MATCHnomatch)
+ {
+ // Prefer previous match: (*dedtypes)[i]
+ if (xt)
+ xt->update(e, tparam);
+ result = match2;
+ return;
+ }
+
+ /* Deduce common type
+ */
+ if (Type *t = rawTypeMerge(at, tt))
+ {
+ if (xt)
+ xt->update(t, e, tparam);
+ else
+ (*dedtypes)[i] = t;
+
+ pt = tt->addMod(tparam->mod);
+ if (*wm)
+ pt = pt->substWildTo(*wm);
+ result = e->implicitConvTo(pt);
+ return;
+ }
+
+ result = MATCHnomatch;
+ }
+
+ MATCH deduceEmptyArrayElement()
+ {
+ if (!emptyArrayElement)
+ {
+ emptyArrayElement = new IdentifierExp(Loc(), Id::p); // dummy
+ emptyArrayElement->type = Type::tvoid;
+ }
+ assert(tparam->ty == Tarray);
+
+ Type *tn = ((TypeNext *)tparam)->next;
+ return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
+ }
+
+ void visit(NullExp *e)
+ {
+ if (tparam->ty == Tarray && e->type->ty == Tnull)
+ {
+ // tparam:T[] <- e:null (void[])
+ result = deduceEmptyArrayElement();
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(StringExp *e)
+ {
+ Type *taai;
+ if (e->type->ty == Tarray &&
+ (tparam->ty == Tsarray ||
+ (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
+ ((TypeIdentifier *)taai)->idents.dim == 0)))
+ {
+ // Consider compile-time known boundaries
+ e->type->nextOf()->sarrayOf(e->len)->accept(this);
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ if ((!e->elements || !e->elements->dim) &&
+ e->type->toBasetype()->nextOf()->ty == Tvoid &&
+ tparam->ty == Tarray)
+ {
+ // tparam:T[] <- e:[] (void[])
+ result = deduceEmptyArrayElement();
+ return;
+ }
+
+ if (tparam->ty == Tarray && e->elements && e->elements->dim)
+ {
+ Type *tn = ((TypeDArray *)tparam)->next;
+ result = MATCHexact;
+ if (e->basis)
+ {
+ MATCH m = deduceType(e->basis, sc, tn, parameters, dedtypes, wm);
+ if (m < result)
+ result = m;
+ }
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ if (result <= MATCHnomatch)
+ break;
+ Expression *el = (*e->elements)[i];
+ if (!el)
+ continue;
+ MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
+ if (m < result)
+ result = m;
+ }
+ return;
+ }
+
+ Type *taai;
+ if (e->type->ty == Tarray &&
+ (tparam->ty == Tsarray ||
+ (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
+ ((TypeIdentifier *)taai)->idents.dim == 0)))
+ {
+ // Consider compile-time known boundaries
+ e->type->nextOf()->sarrayOf(e->elements->dim)->accept(this);
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ if (tparam->ty == Taarray && e->keys && e->keys->dim)
+ {
+ TypeAArray *taa = (TypeAArray *)tparam;
+ result = MATCHexact;
+ for (size_t i = 0; i < e->keys->dim; i++)
+ {
+ MATCH m1 = deduceType((*e->keys)[i], sc, taa->index, parameters, dedtypes, wm);
+ if (m1 < result)
+ result = m1;
+ if (result <= MATCHnomatch)
+ break;
+ MATCH m2 = deduceType((*e->values)[i], sc, taa->next, parameters, dedtypes, wm);
+ if (m2 < result)
+ result = m2;
+ if (result <= MATCHnomatch)
+ break;
+ }
+ return;
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(FuncExp *e)
+ {
+ //printf("e->type = %s, tparam = %s\n", e->type->toChars(), tparam->toChars());
+ if (e->td)
+ {
+ Type *to = tparam;
+ if (!to->nextOf() || to->nextOf()->ty != Tfunction)
+ return;
+ TypeFunction *tof = (TypeFunction *)to->nextOf();
+
+ // Parameter types inference from 'tof'
+ assert(e->td->_scope);
+ TypeFunction *tf = (TypeFunction *)e->fd->type;
+ //printf("\ttof = %s\n", tof->toChars());
+ //printf("\ttf = %s\n", tf->toChars());
+ size_t dim = Parameter::dim(tf->parameters);
+
+ if (Parameter::dim(tof->parameters) != dim ||
+ tof->varargs != tf->varargs)
+ return;
+
+ Objects *tiargs = new Objects();
+ tiargs->reserve(e->td->parameters->dim);
+
+ for (size_t i = 0; i < e->td->parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*e->td->parameters)[i];
+ size_t u = 0;
+ for (; u < dim; u++)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, u);
+ if (p->type->ty == Tident &&
+ ((TypeIdentifier *)p->type)->ident == tp->ident)
+ {
+ break;
+ }
+ }
+ assert(u < dim);
+ Parameter *pto = Parameter::getNth(tof->parameters, u);
+ if (!pto)
+ break;
+ Type *t = pto->type->syntaxCopy(); // Bugzilla 11774
+ if (reliesOnTident(t, parameters, inferStart))
+ return;
+ t = t->semantic(e->loc, sc);
+ if (t->ty == Terror)
+ return;
+ tiargs->push(t);
+ }
+
+ // Set target of return type inference
+ if (!tf->next && tof->next)
+ e->fd->treq = tparam;
+
+ TemplateInstance *ti = new TemplateInstance(e->loc, e->td, tiargs);
+ Expression *ex = new ScopeExp(e->loc, ti);
+ ex = ::semantic(ex, e->td->_scope);
+
+ // Reset inference target for the later re-semantic
+ e->fd->treq = NULL;
+
+ if (ex->op == TOKerror)
+ return;
+ if (ex->op != TOKfunction)
+ return;
+ visit(ex->type);
+ return;
+ }
+
+ Type *t = e->type;
+
+ if (t->ty == Tdelegate && tparam->ty == Tpointer)
+ return;
+
+ // Allow conversion from implicit function pointer to delegate
+ if (e->tok == TOKreserved &&
+ t->ty == Tpointer && tparam->ty == Tdelegate)
+ {
+ TypeFunction *tf = (TypeFunction *)t->nextOf();
+ t = (new TypeDelegate(tf))->merge();
+ }
+ //printf("tparam = %s <= e->type = %s, t = %s\n", tparam->toChars(), e->type->toChars(), t->toChars());
+ visit(t);
+ }
+
+ void visit(SliceExp *e)
+ {
+ Type *taai;
+ if (e->type->ty == Tarray &&
+ (tparam->ty == Tsarray ||
+ (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
+ ((TypeIdentifier *)taai)->idents.dim == 0)))
+ {
+ // Consider compile-time known boundaries
+ if (Type *tsa = toStaticArrayType(e))
+ {
+ tsa->accept(this);
+ return;
+ }
+ }
+ visit((Expression *)e);
+ }
+
+ void visit(CommaExp *e)
+ {
+ ((CommaExp *)e)->e2->accept(this);
+ }
+ };
+
+ DeduceType v(sc, tparam, parameters, dedtypes, wm, inferStart);
+ if (Type *t = isType(o))
+ t->accept(&v);
+ else
+ {
+ assert(isExpression(o) && wm);
+ ((Expression *)o)->accept(&v);
+ }
+ return v.result;
+}
+
+/*******************************
+ * Input:
+ * t Tested type, if NULL, returns NULL.
+ * tparams Optional template parameters.
+ * == NULL:
+ * If one of the subtypes of this type is a TypeIdentifier,
+ * i.e. it's an unresolved type, return that type.
+ * != NULL:
+ * Only when the TypeIdentifier is one of template parameters,
+ * return that type.
+ */
+
+bool reliesOnTident(Type *t, TemplateParameters *tparams, size_t iStart)
+{
+ class ReliesOnTident : public Visitor
+ {
+ public:
+ TemplateParameters *tparams;
+ size_t iStart;
+ bool result;
+
+ ReliesOnTident(TemplateParameters *tparams, size_t iStart)
+ : tparams(tparams), iStart(iStart)
+ {
+ result = false;
+ }
+
+ void visit(Type *)
+ {
+ }
+
+ void visit(TypeNext *t)
+ {
+ t->next->accept(this);
+ }
+
+ void visit(TypeVector *t)
+ {
+ t->basetype->accept(this);
+ }
+
+ void visit(TypeAArray *t)
+ {
+ visit((TypeNext *)t);
+ if (!result)
+ t->index->accept(this);
+ }
+
+ void visit(TypeFunction *t)
+ {
+ size_t dim = Parameter::dim(t->parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam = Parameter::getNth(t->parameters, i);
+ fparam->type->accept(this);
+ if (result)
+ return;
+ }
+ if (t->next)
+ t->next->accept(this);
+ }
+
+ void visit(TypeIdentifier *t)
+ {
+ if (!tparams)
+ {
+ result = true;
+ return;
+ }
+
+ for (size_t i = iStart; i < tparams->dim; i++)
+ {
+ TemplateParameter *tp = (*tparams)[i];
+ if (tp->ident->equals(t->ident))
+ {
+ result = true;
+ return;
+ }
+ }
+ }
+
+ void visit(TypeInstance *t)
+ {
+ if (!tparams)
+ return;
+
+ for (size_t i = iStart; i < tparams->dim; i++)
+ {
+ TemplateParameter *tp = (*tparams)[i];
+ if (t->tempinst->name == tp->ident)
+ {
+ result = true;
+ return;
+ }
+ }
+ if (!t->tempinst->tiargs)
+ return;
+ for (size_t i = 0; i < t->tempinst->tiargs->dim; i++)
+ {
+ Type *ta = isType((*t->tempinst->tiargs)[i]);
+ if (ta)
+ {
+ ta->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(TypeTypeof *t)
+ {
+ //printf("TypeTypeof::reliesOnTident('%s')\n", t->toChars());
+ t->exp->accept(this);
+ }
+
+ void visit(TypeTuple *t)
+ {
+ if (t->arguments)
+ {
+ for (size_t i = 0; i < t->arguments->dim; i++)
+ {
+ Parameter *arg = (*t->arguments)[i];
+ arg->type->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(Expression *)
+ {
+ //printf("Expression::reliesOnTident('%s')\n", e->toChars());
+ }
+
+ void visit(IdentifierExp *e)
+ {
+ //printf("IdentifierExp::reliesOnTident('%s')\n", e->toChars());
+ for (size_t i = iStart; i < tparams->dim; i++)
+ {
+ TemplateParameter *tp = (*tparams)[i];
+ if (e->ident == tp->ident)
+ {
+ result = true;
+ return;
+ }
+ }
+ }
+
+ void visit(TupleExp *e)
+ {
+ //printf("TupleExp::reliesOnTident('%s')\n", e->toChars());
+ if (e->exps)
+ {
+ for (size_t i = 0; i < e->exps->dim; i++)
+ {
+ Expression *ea = (*e->exps)[i];
+ ea->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ //printf("ArrayLiteralExp::reliesOnTident('%s')\n", e->toChars());
+ if (e->elements)
+ {
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *el = (*e->elements)[i];
+ el->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ //printf("AssocArrayLiteralExp::reliesOnTident('%s')\n", e->toChars());
+ for (size_t i = 0; i < e->keys->dim; i++)
+ {
+ Expression *ek = (*e->keys)[i];
+ ek->accept(this);
+ if (result)
+ return;
+ }
+ for (size_t i = 0; i < e->values->dim; i++)
+ {
+ Expression *ev = (*e->values)[i];
+ ev->accept(this);
+ if (result)
+ return;
+ }
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ //printf("StructLiteralExp::reliesOnTident('%s')\n", e->toChars());
+ if (e->elements)
+ {
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *ea = (*e->elements)[i];
+ ea->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(TypeExp *e)
+ {
+ //printf("TypeExp::reliesOnTident('%s')\n", e->toChars());
+ e->type->accept(this);
+ }
+
+ void visit(NewExp *e)
+ {
+ //printf("NewExp::reliesOnTident('%s')\n", e->toChars());
+ if (e->thisexp)
+ e->thisexp->accept(this);
+ if (!result && e->newargs)
+ {
+ for (size_t i = 0; i < e->newargs->dim; i++)
+ {
+ Expression *ea = (*e->newargs)[i];
+ ea->accept(this);
+ if (result)
+ return;
+ }
+ }
+ e->newtype->accept(this);
+ if (!result && e->arguments)
+ {
+ for (size_t i = 0; i < e->arguments->dim; i++)
+ {
+ Expression *ea = (*e->arguments)[i];
+ ea->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(NewAnonClassExp *)
+ {
+ //printf("NewAnonClassExp::reliesOnTident('%s')\n", e->toChars());
+ result = true;
+ }
+
+ void visit(FuncExp *)
+ {
+ //printf("FuncExp::reliesOnTident('%s')\n", e->toChars());
+ result = true;
+ }
+
+ void visit(TypeidExp *e)
+ {
+ //printf("TypeidExp::reliesOnTident('%s')\n", e->toChars());
+ if (Expression *ea = isExpression(e->obj))
+ ea->accept(this);
+ else if (Type *ta = isType(e->obj))
+ ta->accept(this);
+ }
+
+ void visit(TraitsExp *e)
+ {
+ //printf("TraitsExp::reliesOnTident('%s')\n", e->toChars());
+ if (e->args)
+ {
+ for (size_t i = 0; i < e->args->dim; i++)
+ {
+ RootObject *oa = (*e->args)[i];
+ if (Expression *ea = isExpression(oa))
+ ea->accept(this);
+ else if (Type *ta = isType(oa))
+ ta->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(IsExp *e)
+ {
+ //printf("IsExp::reliesOnTident('%s')\n", e->toChars());
+ e->targ->accept(this);
+ }
+
+ void visit(UnaExp *e)
+ {
+ //printf("UnaExp::reliesOnTident('%s')\n", e->toChars());
+ e->e1->accept(this);
+ }
+
+ void visit(DotTemplateInstanceExp *e)
+ {
+ //printf("DotTemplateInstanceExp::reliesOnTident('%s')\n", e->toChars());
+ visit((UnaExp *)e);
+ if (!result && e->ti->tiargs)
+ {
+ for (size_t i = 0; i < e->ti->tiargs->dim; i++)
+ {
+ RootObject *oa = (*e->ti->tiargs)[i];
+ if (Expression *ea = isExpression(oa))
+ ea->accept(this);
+ else if (Type *ta = isType(oa))
+ ta->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(CallExp *e)
+ {
+ //printf("CallExp::reliesOnTident('%s')\n", e->toChars());
+ visit((UnaExp *)e);
+ if (!result && e->arguments)
+ {
+ for (size_t i = 0; i < e->arguments->dim; i++)
+ {
+ Expression *ea = (*e->arguments)[i];
+ ea->accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ void visit(CastExp *e)
+ {
+ //printf("CastExp::reliesOnTident('%s')\n", e->toChars());
+ visit((UnaExp *)e);
+ // e.to can be null for cast() with no type
+ if (!result && e->to)
+ e->to->accept(this);
+ }
+
+ void visit(SliceExp *e)
+ {
+ //printf("SliceExp::reliesOnTident('%s')\n", e->toChars());
+ visit((UnaExp *)e);
+ if (!result && e->lwr)
+ e->lwr->accept(this);
+ if (!result && e->upr)
+ e->upr->accept(this);
+ }
+
+ void visit(IntervalExp *e)
+ {
+ //printf("IntervalExp::reliesOnTident('%s')\n", e->toChars());
+ e->lwr->accept(this);
+ if (!result)
+ e->upr->accept(this);
+ }
+
+ void visit(ArrayExp *e)
+ {
+ //printf("ArrayExp::reliesOnTident('%s')\n", e->toChars());
+ visit((UnaExp *)e);
+ if (!result && e->arguments)
+ {
+ for (size_t i = 0; i < e->arguments->dim; i++)
+ {
+ Expression *ea = (*e->arguments)[i];
+ ea->accept(this);
+ }
+ }
+ }
+
+ void visit(BinExp *e)
+ {
+ //printf("BinExp::reliesOnTident('%s')\n", e->toChars());
+ e->e1->accept(this);
+ if (!result)
+ e->e2->accept(this);
+ }
+
+ void visit(CondExp *e)
+ {
+ //printf("BinExp::reliesOnTident('%s')\n", e->toChars());
+ e->econd->accept(this);
+ if (!result)
+ visit((BinExp *)e);
+ }
+ };
+
+ if (!t)
+ return false;
+
+ ReliesOnTident v(tparams, iStart);
+ t->accept(&v);
+ return v.result;
+}
+
+/* ======================== TemplateParameter =============================== */
+
+TemplateParameter::TemplateParameter(Loc loc, Identifier *ident)
+{
+ this->loc = loc;
+ this->ident = ident;
+ this->dependent = false;
+}
+
+TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter()
+{
+ return NULL;
+}
+
+TemplateValueParameter *TemplateParameter::isTemplateValueParameter()
+{
+ return NULL;
+}
+
+TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter()
+{
+ return NULL;
+}
+
+TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter()
+{
+ return NULL;
+}
+
+TemplateThisParameter *TemplateParameter::isTemplateThisParameter()
+{
+ return NULL;
+}
+
+/*******************************************
+ * Match to a particular TemplateParameter.
+ * Input:
+ * instLoc location that the template is instantiated.
+ * tiargs[] actual arguments to template instance
+ * i i'th argument
+ * parameters[] template parameters
+ * dedtypes[] deduced arguments to template instance
+ * *psparam set to symbol declared and initialized to dedtypes[i]
+ */
+MATCH TemplateParameter::matchArg(Loc instLoc, Scope *sc, Objects *tiargs,
+ size_t i, TemplateParameters *parameters, Objects *dedtypes,
+ Declaration **psparam)
+{
+ RootObject *oarg;
+
+ if (i < tiargs->dim)
+ oarg = (*tiargs)[i];
+ else
+ {
+ // Get default argument instead
+ oarg = defaultArg(instLoc, sc);
+ if (!oarg)
+ {
+ assert(i < dedtypes->dim);
+ // It might have already been deduced
+ oarg = (*dedtypes)[i];
+ if (!oarg)
+ goto Lnomatch;
+ }
+ }
+ return matchArg(sc, oarg, i, parameters, dedtypes, psparam);
+
+Lnomatch:
+ if (psparam)
+ *psparam = NULL;
+ return MATCHnomatch;
+}
+
+/* ======================== TemplateTypeParameter =========================== */
+
+// type-parameter
+
+Type *TemplateTypeParameter::tdummy = NULL;
+
+TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType,
+ Type *defaultType)
+ : TemplateParameter(loc, ident)
+{
+ this->ident = ident;
+ this->specType = specType;
+ this->defaultType = defaultType;
+}
+
+TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter()
+{
+ return this;
+}
+
+TemplateParameter *TemplateTypeParameter::syntaxCopy()
+{
+ return new TemplateTypeParameter(loc, ident,
+ specType ? specType->syntaxCopy() : NULL,
+ defaultType ? defaultType->syntaxCopy() : NULL);
+}
+
+bool TemplateTypeParameter::declareParameter(Scope *sc)
+{
+ //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars());
+ TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+ Declaration *ad = new AliasDeclaration(loc, ident, ti);
+ return sc->insert(ad) != NULL;
+}
+
+bool TemplateTypeParameter::semantic(Scope *sc, TemplateParameters *parameters)
+{
+ //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
+ if (specType && !reliesOnTident(specType, parameters))
+ {
+ specType = specType->semantic(loc, sc);
+ }
+ return !(specType && isError(specType));
+}
+
+MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg,
+ size_t i, TemplateParameters *parameters, Objects *dedtypes,
+ Declaration **psparam)
+{
+ //printf("TemplateTypeParameter::matchArg('%s')\n", ident->toChars());
+ MATCH m = MATCHexact;
+ Type *ta = isType(oarg);
+ if (!ta)
+ {
+ //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
+ goto Lnomatch;
+ }
+ //printf("ta is %s\n", ta->toChars());
+
+ if (specType)
+ {
+ if (!ta || ta == tdummy)
+ goto Lnomatch;
+
+ //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars());
+ MATCH m2 = deduceType(ta, sc, specType, parameters, dedtypes);
+ if (m2 <= MATCHnomatch)
+ {
+ //printf("\tfailed deduceType\n");
+ goto Lnomatch;
+ }
+
+ if (m2 < m)
+ m = m2;
+ if ((*dedtypes)[i])
+ {
+ Type *t = (Type *)(*dedtypes)[i];
+
+ if (dependent && !t->equals(ta)) // Bugzilla 14357
+ goto Lnomatch;
+
+ /* This is a self-dependent parameter. For example:
+ * template X(T : T*) {}
+ * template X(T : S!T, alias S) {}
+ */
+ //printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
+ ta = t;
+ }
+ }
+ else
+ {
+ if ((*dedtypes)[i])
+ {
+ // Must match already deduced type
+ Type *t = (Type *)(*dedtypes)[i];
+
+ if (!t->equals(ta))
+ {
+ //printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
+ goto Lnomatch;
+ }
+ }
+ else
+ {
+ // So that matches with specializations are better
+ m = MATCHconvert;
+ }
+ }
+ (*dedtypes)[i] = ta;
+
+ if (psparam)
+ *psparam = new AliasDeclaration(loc, ident, ta);
+ //printf("\tm = %d\n", m);
+ return dependent ? MATCHexact : m;
+
+Lnomatch:
+ if (psparam)
+ *psparam = NULL;
+ //printf("\tm = %d\n", MATCHnomatch);
+ return MATCHnomatch;
+}
+
+
+void TemplateTypeParameter::print(RootObject *oarg, RootObject *oded)
+{
+ printf(" %s\n", ident->toChars());
+
+ Type *t = isType(oarg);
+ Type *ta = isType(oded);
+
+ assert(ta);
+
+ if (specType)
+ printf("\tSpecialization: %s\n", specType->toChars());
+ if (defaultType)
+ printf("\tDefault: %s\n", defaultType->toChars());
+ printf("\tParameter: %s\n", t ? t->toChars() : "NULL");
+ printf("\tDeduced Type: %s\n", ta->toChars());
+}
+
+void *TemplateTypeParameter::dummyArg()
+{
+ Type *t = specType;
+ if (!t)
+ {
+ // Use this for alias-parameter's too (?)
+ if (!tdummy)
+ tdummy = new TypeIdentifier(loc, ident);
+ t = tdummy;
+ }
+ return (void *)t;
+}
+
+
+RootObject *TemplateTypeParameter::specialization()
+{
+ return specType;
+}
+
+RootObject *TemplateTypeParameter::defaultArg(Loc, Scope *sc)
+{
+ Type *t = defaultType;
+ if (t)
+ {
+ t = t->syntaxCopy();
+ t = t->semantic(loc, sc); // use the parameter loc
+ }
+ return t;
+}
+
+bool TemplateTypeParameter::hasDefaultArg()
+{
+ return defaultType != NULL;
+}
+
+/* ======================== TemplateThisParameter =========================== */
+
+// this-parameter
+
+TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident,
+ Type *specType,
+ Type *defaultType)
+ : TemplateTypeParameter(loc, ident, specType, defaultType)
+{
+}
+
+TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter()
+{
+ return this;
+}
+
+TemplateParameter *TemplateThisParameter::syntaxCopy()
+{
+ return new TemplateThisParameter(loc, ident,
+ specType ? specType->syntaxCopy() : NULL,
+ defaultType ? defaultType->syntaxCopy() : NULL);
+}
+
+/* ======================== TemplateAliasParameter ========================== */
+
+// alias-parameter
+
+Dsymbol *TemplateAliasParameter::sdummy = NULL;
+
+TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident,
+ Type *specType, RootObject *specAlias, RootObject *defaultAlias)
+ : TemplateParameter(loc, ident)
+{
+ this->ident = ident;
+ this->specType = specType;
+ this->specAlias = specAlias;
+ this->defaultAlias = defaultAlias;
+}
+
+TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter()
+{
+ return this;
+}
+
+TemplateParameter *TemplateAliasParameter::syntaxCopy()
+{
+ return new TemplateAliasParameter(loc, ident,
+ specType ? specType->syntaxCopy() : NULL,
+ objectSyntaxCopy(specAlias),
+ objectSyntaxCopy(defaultAlias));
+}
+
+bool TemplateAliasParameter::declareParameter(Scope *sc)
+{
+ TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+ Declaration *ad = new AliasDeclaration(loc, ident, ti);
+ return sc->insert(ad) != NULL;
+}
+
+static RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters)
+{
+ if (o)
+ {
+ Expression *ea = isExpression(o);
+ Type *ta = isType(o);
+ if (ta && (!parameters || !reliesOnTident(ta, parameters)))
+ {
+ Dsymbol *s = ta->toDsymbol(sc);
+ if (s)
+ o = s;
+ else
+ o = ta->semantic(loc, sc);
+ }
+ else if (ea)
+ {
+ sc = sc->startCTFE();
+ ea = ::semantic(ea, sc);
+ sc = sc->endCTFE();
+ o = ea->ctfeInterpret();
+ }
+ }
+ return o;
+}
+
+bool TemplateAliasParameter::semantic(Scope *sc, TemplateParameters *parameters)
+{
+ if (specType && !reliesOnTident(specType, parameters))
+ {
+ specType = specType->semantic(loc, sc);
+ }
+ specAlias = aliasParameterSemantic(loc, sc, specAlias, parameters);
+ return !(specType && isError(specType)) &&
+ !(specAlias && isError(specAlias));
+}
+
+MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg,
+ size_t i, TemplateParameters *parameters, Objects *dedtypes,
+ Declaration **psparam)
+{
+ //printf("TemplateAliasParameter::matchArg('%s')\n", ident->toChars());
+ MATCH m = MATCHexact;
+ Type *ta = isType(oarg);
+ RootObject *sa = ta && !ta->deco ? NULL : getDsymbol(oarg);
+ Expression *ea = isExpression(oarg);
+ if (ea && (ea->op == TOKthis || ea->op == TOKsuper))
+ sa = ((ThisExp *)ea)->var;
+ else if (ea && ea->op == TOKscope)
+ sa = ((ScopeExp *)ea)->sds;
+ if (sa)
+ {
+ if (((Dsymbol *)sa)->isAggregateDeclaration())
+ m = MATCHconvert;
+
+ /* specType means the alias must be a declaration with a type
+ * that matches specType.
+ */
+ if (specType)
+ {
+ Declaration *d = ((Dsymbol *)sa)->isDeclaration();
+ if (!d)
+ goto Lnomatch;
+ if (!d->type->equals(specType))
+ goto Lnomatch;
+ }
+ }
+ else
+ {
+ sa = oarg;
+ if (ea)
+ {
+ if (specType)
+ {
+ if (!ea->type->equals(specType))
+ goto Lnomatch;
+ }
+ }
+ else if (ta && ta->ty == Tinstance && !specAlias)
+ {
+ /* Bugzilla xxxxx: Specialized parameter should be prefeerd
+ * match to the template type parameter.
+ * template X(alias a) {} // a == this
+ * template X(alias a : B!A, alias B, A...) {} // B!A => ta
+ */
+ }
+ else if (sa && sa == TemplateTypeParameter::tdummy)
+ {
+ /* Bugzilla 2025: Aggregate Types should preferentially
+ * match to the template type parameter.
+ * template X(alias a) {} // a == this
+ * template X(T) {} // T => sa
+ */
+ }
+ else
+ goto Lnomatch;
+ }
+
+ if (specAlias)
+ {
+ if (sa == sdummy)
+ goto Lnomatch;
+ Dsymbol *sx = isDsymbol(sa);
+ if (sa != specAlias && sx)
+ {
+ Type *talias = isType(specAlias);
+ if (!talias)
+ goto Lnomatch;
+
+ TemplateInstance *ti = sx->isTemplateInstance();
+ if (!ti && sx->parent)
+ {
+ ti = sx->parent->isTemplateInstance();
+ if (ti && ti->name != sx->ident)
+ goto Lnomatch;
+ }
+ if (!ti)
+ goto Lnomatch;
+
+ Type *t = new TypeInstance(Loc(), ti);
+ MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
+ if (m2 <= MATCHnomatch)
+ goto Lnomatch;
+ }
+ }
+ else if ((*dedtypes)[i])
+ {
+ // Must match already deduced symbol
+ RootObject *si = (*dedtypes)[i];
+ if (!sa || si != sa)
+ goto Lnomatch;
+ }
+ (*dedtypes)[i] = sa;
+
+ if (psparam)
+ {
+ if (Dsymbol *s = isDsymbol(sa))
+ {
+ *psparam = new AliasDeclaration(loc, ident, s);
+ }
+ else if (Type *t = isType(sa))
+ {
+ *psparam = new AliasDeclaration(loc, ident, t);
+ }
+ else
+ {
+ assert(ea);
+
+ // Declare manifest constant
+ Initializer *init = new ExpInitializer(loc, ea);
+ VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+ v->storage_class = STCmanifest;
+ v->semantic(sc);
+ *psparam = v;
+ }
+ }
+ return dependent ? MATCHexact : m;
+
+Lnomatch:
+ if (psparam)
+ *psparam = NULL;
+ //printf("\tm = %d\n", MATCHnomatch);
+ return MATCHnomatch;
+}
+
+
+void TemplateAliasParameter::print(RootObject *, RootObject *oded)
+{
+ printf(" %s\n", ident->toChars());
+
+ Dsymbol *sa = isDsymbol(oded);
+ assert(sa);
+
+ printf("\tParameter alias: %s\n", sa->toChars());
+}
+
+void *TemplateAliasParameter::dummyArg()
+{
+ RootObject *s = specAlias;
+ if (!s)
+ {
+ if (!sdummy)
+ sdummy = new Dsymbol();
+ s = sdummy;
+ }
+ return (void*)s;
+}
+
+
+RootObject *TemplateAliasParameter::specialization()
+{
+ return specAlias;
+}
+
+RootObject *TemplateAliasParameter::defaultArg(Loc, Scope *sc)
+{
+ RootObject *da = defaultAlias;
+ Type *ta = isType(defaultAlias);
+ if (ta)
+ {
+ if (ta->ty == Tinstance)
+ {
+ // If the default arg is a template, instantiate for each type
+ da = ta->syntaxCopy();
+ }
+ }
+
+ RootObject *o = aliasParameterSemantic(loc, sc, da, NULL); // use the parameter loc
+ return o;
+}
+
+bool TemplateAliasParameter::hasDefaultArg()
+{
+ return defaultAlias != NULL;
+}
+
+/* ======================== TemplateValueParameter ========================== */
+
+// value-parameter
+
+AA *TemplateValueParameter::edummies = NULL;
+
+TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType,
+ Expression *specValue, Expression *defaultValue)
+ : TemplateParameter(loc, ident)
+{
+ this->ident = ident;
+ this->valType = valType;
+ this->specValue = specValue;
+ this->defaultValue = defaultValue;
+}
+
+TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter()
+{
+ return this;
+}
+
+TemplateParameter *TemplateValueParameter::syntaxCopy()
+{
+ return new TemplateValueParameter(loc, ident,
+ valType->syntaxCopy(),
+ specValue ? specValue->syntaxCopy() : NULL,
+ defaultValue ? defaultValue->syntaxCopy() : NULL);
+}
+
+bool TemplateValueParameter::declareParameter(Scope *sc)
+{
+ VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL);
+ v->storage_class = STCtemplateparameter;
+ return sc->insert(v) != NULL;
+}
+
+bool TemplateValueParameter::semantic(Scope *sc, TemplateParameters *)
+{
+ valType = valType->semantic(loc, sc);
+
+ return !isError(valType);
+}
+
+MATCH TemplateValueParameter::matchArg(Scope *sc, RootObject *oarg,
+ size_t i, TemplateParameters *, Objects *dedtypes, Declaration **psparam)
+{
+ //printf("TemplateValueParameter::matchArg('%s')\n", ident->toChars());
+
+ MATCH m = MATCHexact;
+
+ Expression *ei = isExpression(oarg);
+ Type *vt;
+
+ if (!ei && oarg)
+ {
+ Dsymbol *si = isDsymbol(oarg);
+ FuncDeclaration *f = si ? si->isFuncDeclaration() : NULL;
+ if (!f || !f->fbody || f->needThis())
+ goto Lnomatch;
+
+ ei = new VarExp(loc, f);
+ ei = ::semantic(ei, sc);
+
+ /* If a function is really property-like, and then
+ * it's CTFEable, ei will be a literal expression.
+ */
+ unsigned int olderrors = global.startGagging();
+ ei = resolveProperties(sc, ei);
+ ei = ei->ctfeInterpret();
+ if (global.endGagging(olderrors) || ei->op == TOKerror)
+ goto Lnomatch;
+
+ /* Bugzilla 14520: A property-like function can match to both
+ * TemplateAlias and ValueParameter. But for template overloads,
+ * it should always prefer alias parameter to be consistent
+ * template match result.
+ *
+ * template X(alias f) { enum X = 1; }
+ * template X(int val) { enum X = 2; }
+ * int f1() { return 0; } // CTFEable
+ * int f2(); // body-less function is not CTFEable
+ * enum x1 = X!f1; // should be 1
+ * enum x2 = X!f2; // should be 1
+ *
+ * e.g. The x1 value must be same even if the f1 definition will be moved
+ * into di while stripping body code.
+ */
+ m = MATCHconvert;
+ }
+
+ if (ei && ei->op == TOKvar)
+ {
+ // Resolve const variables that we had skipped earlier
+ ei = ei->ctfeInterpret();
+ }
+
+ //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty);
+ vt = valType->semantic(loc, sc);
+ //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars());
+ //printf("vt = %s\n", vt->toChars());
+
+ if (ei->type)
+ {
+ MATCH m2 = ei->implicitConvTo(vt);
+ //printf("m: %d\n", m);
+ if (m2 < m)
+ m = m2;
+ if (m <= MATCHnomatch)
+ goto Lnomatch;
+ ei = ei->implicitCastTo(sc, vt);
+ ei = ei->ctfeInterpret();
+ }
+
+ if (specValue)
+ {
+ if (!ei || (Expression *)dmd_aaGetRvalue(edummies, (void *)ei->type) == ei)
+ goto Lnomatch;
+
+ Expression *e = specValue;
+
+ sc = sc->startCTFE();
+ e = ::semantic(e, sc);
+ e = resolveProperties(sc, e);
+ sc = sc->endCTFE();
+ e = e->implicitCastTo(sc, vt);
+ e = e->ctfeInterpret();
+
+ ei = ei->syntaxCopy();
+ sc = sc->startCTFE();
+ ei = ::semantic(ei, sc);
+ sc = sc->endCTFE();
+ ei = ei->implicitCastTo(sc, vt);
+ ei = ei->ctfeInterpret();
+ //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars());
+ //printf("\te : %s, %s\n", e->toChars(), e->type->toChars());
+ if (!ei->equals(e))
+ goto Lnomatch;
+ }
+ else
+ {
+ if ((*dedtypes)[i])
+ {
+ // Must match already deduced value
+ Expression *e = (Expression *)(*dedtypes)[i];
+
+ if (!ei || !ei->equals(e))
+ goto Lnomatch;
+ }
+ }
+ (*dedtypes)[i] = ei;
+
+ if (psparam)
+ {
+ Initializer *init = new ExpInitializer(loc, ei);
+ Declaration *sparam = new VarDeclaration(loc, vt, ident, init);
+ sparam->storage_class = STCmanifest;
+ *psparam = sparam;
+ }
+ return dependent ? MATCHexact : m;
+
+Lnomatch:
+ //printf("\tno match\n");
+ if (psparam)
+ *psparam = NULL;
+ return MATCHnomatch;
+}
+
+
+void TemplateValueParameter::print(RootObject *, RootObject *oded)
+{
+ printf(" %s\n", ident->toChars());
+
+ Expression *ea = isExpression(oded);
+
+ if (specValue)
+ printf("\tSpecialization: %s\n", specValue->toChars());
+ printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL");
+}
+
+void *TemplateValueParameter::dummyArg()
+{
+ Expression *e = specValue;
+ if (!e)
+ {
+ // Create a dummy value
+ Expression **pe = (Expression **)dmd_aaGet(&edummies, (void *)valType);
+ if (!*pe)
+ *pe = valType->defaultInit();
+ e = *pe;
+ }
+ return (void *)e;
+}
+
+
+RootObject *TemplateValueParameter::specialization()
+{
+ return specValue;
+}
+
+RootObject *TemplateValueParameter::defaultArg(Loc instLoc, Scope *sc)
+{
+ Expression *e = defaultValue;
+ if (e)
+ {
+ e = e->syntaxCopy();
+ if ((e = ::semantic(e, sc)) == NULL)
+ return NULL;
+ if ((e = resolveProperties(sc, e)) == NULL)
+ return NULL;
+ e = e->resolveLoc(instLoc, sc); // use the instantiated loc
+ e = e->optimize(WANTvalue);
+ }
+ return e;
+}
+
+bool TemplateValueParameter::hasDefaultArg()
+{
+ return defaultValue != NULL;
+}
+
+/* ======================== TemplateTupleParameter ========================== */
+
+// variadic-parameter
+
+TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident)
+ : TemplateParameter(loc, ident)
+{
+ this->ident = ident;
+}
+
+TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter()
+{
+ return this;
+}
+
+TemplateParameter *TemplateTupleParameter::syntaxCopy()
+{
+ return new TemplateTupleParameter(loc, ident);
+}
+
+bool TemplateTupleParameter::declareParameter(Scope *sc)
+{
+ TypeIdentifier *ti = new TypeIdentifier(loc, ident);
+ Declaration *ad = new AliasDeclaration(loc, ident, ti);
+ return sc->insert(ad) != NULL;
+}
+
+bool TemplateTupleParameter::semantic(Scope *, TemplateParameters *)
+{
+ return true;
+}
+
+MATCH TemplateTupleParameter::matchArg(Loc, Scope *sc, Objects *tiargs,
+ size_t i, TemplateParameters *parameters, Objects *dedtypes,
+ Declaration **psparam)
+{
+ /* The rest of the actual arguments (tiargs[]) form the match
+ * for the variadic parameter.
+ */
+ assert(i + 1 == dedtypes->dim); // must be the last one
+ Tuple *ovar;
+
+ if (Tuple *u = isTuple((*dedtypes)[i]))
+ {
+ // It has already been deduced
+ ovar = u;
+ }
+ else if (i + 1 == tiargs->dim && isTuple((*tiargs)[i]))
+ ovar = isTuple((*tiargs)[i]);
+ else
+ {
+ ovar = new Tuple();
+ //printf("ovar = %p\n", ovar);
+ if (i < tiargs->dim)
+ {
+ //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim);
+ ovar->objects.setDim(tiargs->dim - i);
+ for (size_t j = 0; j < ovar->objects.dim; j++)
+ ovar->objects[j] = (*tiargs)[i + j];
+ }
+ }
+ return matchArg(sc, ovar, i, parameters, dedtypes, psparam);
+}
+
+MATCH TemplateTupleParameter::matchArg(Scope *, RootObject *oarg,
+ size_t i, TemplateParameters *, Objects *dedtypes, Declaration **psparam)
+{
+ //printf("TemplateTupleParameter::matchArg('%s')\n", ident->toChars());
+ Tuple *ovar = isTuple(oarg);
+ if (!ovar)
+ return MATCHnomatch;
+ if ((*dedtypes)[i])
+ {
+ Tuple *tup = isTuple((*dedtypes)[i]);
+ if (!tup)
+ return MATCHnomatch;
+ if (!match(tup, ovar))
+ return MATCHnomatch;
+ }
+ (*dedtypes)[i] = ovar;
+
+ if (psparam)
+ *psparam = new TupleDeclaration(loc, ident, &ovar->objects);
+ return dependent ? MATCHexact : MATCHconvert;
+}
+
+
+void TemplateTupleParameter::print(RootObject *, RootObject *oded)
+{
+ printf(" %s... [", ident->toChars());
+ Tuple *v = isTuple(oded);
+ assert(v);
+
+ //printf("|%d| ", v->objects.dim);
+ for (size_t i = 0; i < v->objects.dim; i++)
+ {
+ if (i)
+ printf(", ");
+
+ RootObject *o = v->objects[i];
+
+ Dsymbol *sa = isDsymbol(o);
+ if (sa)
+ printf("alias: %s", sa->toChars());
+
+ Type *ta = isType(o);
+ if (ta)
+ printf("type: %s", ta->toChars());
+
+ Expression *ea = isExpression(o);
+ if (ea)
+ printf("exp: %s", ea->toChars());
+
+ assert(!isTuple(o)); // no nested Tuple arguments
+ }
+
+ printf("]\n");
+}
+
+void *TemplateTupleParameter::dummyArg()
+{
+ return NULL;
+}
+
+
+RootObject *TemplateTupleParameter::specialization()
+{
+ return NULL;
+}
+
+RootObject *TemplateTupleParameter::defaultArg(Loc, Scope *)
+{
+ return NULL;
+}
+
+bool TemplateTupleParameter::hasDefaultArg()
+{
+ return false;
+}
+
+/* ======================== TemplateInstance ================================ */
+
+TemplateInstance::TemplateInstance(Loc loc, Identifier *ident)
+ : ScopeDsymbol(NULL)
+{
+ this->loc = loc;
+ this->name = ident;
+ this->tiargs = NULL;
+ this->tempdecl = NULL;
+ this->inst = NULL;
+ this->tinst = NULL;
+ this->tnext = NULL;
+ this->minst = NULL;
+ this->deferred = NULL;
+ this->memberOf = NULL;
+ this->argsym = NULL;
+ this->aliasdecl = NULL;
+ this->semantictiargsdone = false;
+ this->inuse = 0;
+ this->nest = 0;
+ this->havetempdecl = false;
+ this->enclosing = NULL;
+ this->gagged = false;
+ this->hash = 0;
+ this->fargs = NULL;
+}
+
+/*****************
+ * This constructor is only called when we figured out which function
+ * template to instantiate.
+ */
+
+TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs)
+ : ScopeDsymbol(NULL)
+{
+ this->loc = loc;
+ this->name = td->ident;
+ this->tiargs = tiargs;
+ this->tempdecl = td;
+ this->inst = NULL;
+ this->tinst = NULL;
+ this->tnext = NULL;
+ this->minst = NULL;
+ this->deferred = NULL;
+ this->memberOf = NULL;
+ this->argsym = NULL;
+ this->aliasdecl = NULL;
+ this->semantictiargsdone = true;
+ this->inuse = 0;
+ this->nest = 0;
+ this->havetempdecl = true;
+ this->enclosing = NULL;
+ this->gagged = false;
+ this->hash = 0;
+ this->fargs = NULL;
+
+ assert(tempdecl->_scope);
+}
+
+
+Objects *TemplateInstance::arraySyntaxCopy(Objects *objs)
+{
+ Objects *a = NULL;
+ if (objs)
+ {
+ a = new Objects();
+ a->setDim(objs->dim);
+ for (size_t i = 0; i < objs->dim; i++)
+ (*a)[i] = objectSyntaxCopy((*objs)[i]);
+ }
+ return a;
+}
+
+Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
+{
+ TemplateInstance *ti =
+ s ? (TemplateInstance *)s
+ : new TemplateInstance(loc, name);
+ ti->tiargs = arraySyntaxCopy(tiargs);
+ TemplateDeclaration *td;
+ if (inst && tempdecl && (td = tempdecl->isTemplateDeclaration()) != NULL)
+ td->ScopeDsymbol::syntaxCopy(ti);
+ else
+ ScopeDsymbol::syntaxCopy(ti);
+ return ti;
+}
+
+void TemplateInstance::semantic(Scope *sc)
+{
+ semantic(sc, NULL);
+}
+
+void TemplateInstance::expandMembers(Scope *sc2)
+{
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->setScope(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->importAll(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
+ //printf("test: enclosing = %d, sc2->parent = %s\n", enclosing, sc2->parent->toChars());
+// if (enclosing)
+// s->parent = sc->parent;
+ //printf("test3: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
+ s->semantic(sc2);
+ //printf("test4: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
+ Module::runDeferredSemantic();
+ }
+}
+
+void TemplateInstance::tryExpandMembers(Scope *sc2)
+{
+ static int nest;
+ // extracted to a function to allow windows SEH to work without destructors in the same function
+ //printf("%d\n", nest);
+ if (++nest > 500)
+ {
+ global.gag = 0; // ensure error message gets printed
+ error("recursive expansion");
+ fatal();
+ }
+
+ expandMembers(sc2);
+
+ nest--;
+}
+
+void TemplateInstance::trySemantic3(Scope *sc2)
+{
+ // extracted to a function to allow windows SEH to work without destructors in the same function
+ static int nest;
+ //printf("%d\n", nest);
+ if (++nest > 300)
+ {
+ global.gag = 0; // ensure error message gets printed
+ error("recursive expansion");
+ fatal();
+ }
+ semantic3(sc2);
+
+ --nest;
+}
+
+void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
+{
+ //printf("[%s] TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", loc.toChars(), toChars(), this, global.gag, sc);
+ if (inst) // if semantic() was already run
+ {
+ return;
+ }
+ if (semanticRun != PASSinit)
+ {
+ Ungag ungag(global.gag);
+ if (!gagged)
+ global.gag = 0;
+ error(loc, "recursive template expansion");
+ if (gagged)
+ semanticRun = PASSinit;
+ else
+ inst = this;
+ errors = true;
+ return;
+ }
+
+ // Get the enclosing template instance from the scope tinst
+ tinst = sc->tinst;
+
+ // Get the instantiating module from the scope minst
+ minst = sc->minst;
+ // Bugzilla 10920: If the enclosing function is non-root symbol,
+ // this instance should be speculative.
+ if (!tinst && sc->func && sc->func->inNonRoot())
+ {
+ minst = NULL;
+ }
+
+ gagged = (global.gag > 0);
+
+ semanticRun = PASSsemantic;
+
+ /* Find template declaration first,
+ * then run semantic on each argument (place results in tiargs[]),
+ * last find most specialized template from overload list/set.
+ */
+ if (!findTempDecl(sc, NULL) ||
+ !semanticTiargs(sc) ||
+ !findBestMatch(sc, fargs))
+ {
+Lerror:
+ if (gagged)
+ {
+ // Bugzilla 13220: Rollback status for later semantic re-running.
+ semanticRun = PASSinit;
+ }
+ else
+ inst = this;
+ errors = true;
+ return;
+ }
+ TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ // If tempdecl is a mixin, disallow it
+ if (tempdecl->ismixin)
+ {
+ error("mixin templates are not regular templates");
+ goto Lerror;
+ }
+
+ hasNestedArgs(tiargs, tempdecl->isstatic);
+ if (errors)
+ goto Lerror;
+
+ /* See if there is an existing TemplateInstantiation that already
+ * implements the typeargs. If so, just refer to that one instead.
+ */
+ inst = tempdecl->findExistingInstance(this, fargs);
+ TemplateInstance *errinst = NULL;
+ if (!inst)
+ {
+ // So, we need to implement 'this' instance.
+ }
+ else if (inst->gagged && !gagged && inst->errors)
+ {
+ // If the first instantiation had failed, re-run semantic,
+ // so that error messages are shown.
+ errinst = inst;
+ }
+ else
+ {
+ // It's a match
+ parent = inst->parent;
+ errors = inst->errors;
+
+ // If both this and the previous instantiation were gagged,
+ // use the number of errors that happened last time.
+ global.errors += errors;
+ global.gaggedErrors += errors;
+
+ // If the first instantiation was gagged, but this is not:
+ if (inst->gagged)
+ {
+ // It had succeeded, mark it is a non-gagged instantiation,
+ // and reuse it.
+ inst->gagged = gagged;
+ }
+
+ this->tnext = inst->tnext;
+ inst->tnext = this;
+
+ /* A module can have explicit template instance and its alias
+ * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`).
+ * If the first instantiation 'inst' had happened in non-root module,
+ * compiler can assume that its instantiated code would be included
+ * in the separately compiled obj/lib file (e.g. phobos.lib).
+ *
+ * However, if 'this' second instantiation happened in root module,
+ * compiler might need to invoke its codegen (Bugzilla 2500 & 2644).
+ * But whole import graph is not determined until all semantic pass finished,
+ * so 'inst' should conservatively finish the semantic3 pass for the codegen.
+ */
+ if (minst && minst->isRoot() && !(inst->minst && inst->minst->isRoot()))
+ {
+ /* Swap the position of 'inst' and 'this' in the instantiation graph.
+ * Then, the primary instance `inst` will be changed to a root instance.
+ *
+ * Before:
+ * non-root -> A!() -> B!()[inst] -> C!()
+ * |
+ * root -> D!() -> B!()[this]
+ *
+ * After:
+ * non-root -> A!() -> B!()[this]
+ * |
+ * root -> D!() -> B!()[inst] -> C!()
+ */
+ Module *mi = minst;
+ TemplateInstance *ti = tinst;
+ minst = inst->minst;
+ tinst = inst->tinst;
+ inst->minst = mi;
+ inst->tinst = ti;
+
+ if (minst) // if inst was not speculative
+ {
+ /* Add 'inst' once again to the root module members[], then the
+ * instance members will get codegen chances.
+ */
+ inst->appendToModuleMember();
+ }
+ }
+
+ return;
+ }
+ unsigned errorsave = global.errors;
+
+ inst = this;
+ parent = enclosing ? enclosing : tempdecl->parent;
+ //printf("parent = '%s'\n", parent->kind());
+
+ TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this);
+
+ //getIdent();
+
+ // Store the place we added it to in target_symbol_list(_idx) so we can
+ // remove it later if we encounter an error.
+ Dsymbols *target_symbol_list = appendToModuleMember();
+ size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list->dim - 1 : 0;
+
+ // Copy the syntax trees from the TemplateDeclaration
+ members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+
+ // resolve TemplateThisParameter
+ for (size_t i = 0; i < tempdecl->parameters->dim; i++)
+ {
+ if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL)
+ continue;
+ Type *t = isType((*tiargs)[i]);
+ assert(t);
+ if (StorageClass stc = ModToStc(t->mod))
+ {
+ //printf("t = %s, stc = x%llx\n", t->toChars(), stc);
+ Dsymbols *s = new Dsymbols();
+ s->push(new StorageClassDeclaration(stc, members));
+ members = s;
+ }
+ break;
+ }
+
+ // Create our own scope for the template parameters
+ Scope *scope = tempdecl->_scope;
+ if (tempdecl->semanticRun == PASSinit)
+ {
+ error("template instantiation %s forward references template declaration %s", toChars(), tempdecl->toChars());
+ return;
+ }
+
+ argsym = new ScopeDsymbol();
+ argsym->parent = scope->parent;
+ scope = scope->push(argsym);
+ scope->tinst = this;
+ scope->minst = minst;
+ //scope->stc = 0;
+
+ // Declare each template parameter as an alias for the argument type
+ Scope *paramscope = scope->push();
+ paramscope->stc = 0;
+ paramscope->protection = Prot(PROTpublic); // Bugzilla 14169: template parameters should be public
+ declareParameters(paramscope);
+ paramscope->pop();
+
+ // Add members of template instance to template instance symbol table
+// parent = scope->scopesym;
+ symtab = new DsymbolTable();
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->addMember(scope, this);
+ }
+
+ /* See if there is only one member of template instance, and that
+ * member has the same name as the template instance.
+ * If so, this template instance becomes an alias for that member.
+ */
+ //printf("members->dim = %d\n", members->dim);
+ if (members->dim)
+ {
+ Dsymbol *s;
+ if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s)
+ {
+ //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
+ //printf("setting aliasdecl\n");
+ aliasdecl = s;
+ }
+ }
+
+ /* If function template declaration
+ */
+ if (fargs && aliasdecl)
+ {
+ FuncDeclaration *fd = aliasdecl->isFuncDeclaration();
+ if (fd)
+ {
+ /* Transmit fargs to type so that TypeFunction::semantic() can
+ * resolve any "auto ref" storage classes.
+ */
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (tf && tf->ty == Tfunction)
+ tf->fargs = fargs;
+ }
+ }
+
+ // Do semantic() analysis on template instance members
+ Scope *sc2;
+ sc2 = scope->push(this);
+ //printf("enclosing = %d, sc->parent = %s\n", enclosing, sc->parent->toChars());
+ sc2->parent = this;
+ sc2->tinst = this;
+ sc2->minst = minst;
+
+ tryExpandMembers(sc2);
+
+ semanticRun = PASSsemanticdone;
+
+ /* ConditionalDeclaration may introduce eponymous declaration,
+ * so we should find it once again after semantic.
+ */
+ if (members->dim)
+ {
+ Dsymbol *s;
+ if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s)
+ {
+ if (!aliasdecl || aliasdecl != s)
+ {
+ //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
+ //printf("setting aliasdecl 2\n");
+ aliasdecl = s;
+ }
+ }
+ }
+
+ if (global.errors != errorsave)
+ goto Laftersemantic;
+
+ /* If any of the instantiation members didn't get semantic() run
+ * on them due to forward references, we cannot run semantic2()
+ * or semantic3() yet.
+ */
+ {
+ bool found_deferred_ad = false;
+ for (size_t i = 0; i < Module::deferred.dim; i++)
+ {
+ Dsymbol *sd = Module::deferred[i];
+ AggregateDeclaration *ad = sd->isAggregateDeclaration();
+ if (ad && ad->parent && ad->parent->isTemplateInstance())
+ {
+ //printf("deferred template aggregate: %s %s\n",
+ // sd->parent->toChars(), sd->toChars());
+ found_deferred_ad = true;
+ if (ad->parent == this)
+ {
+ ad->deferred = this;
+ break;
+ }
+ }
+ }
+ if (found_deferred_ad || Module::deferred.dim)
+ goto Laftersemantic;
+ }
+
+ /* The problem is when to parse the initializer for a variable.
+ * Perhaps VarDeclaration::semantic() should do it like it does
+ * for initializers inside a function.
+ */
+ //if (sc->parent->isFuncDeclaration())
+ {
+ /* BUG 782: this has problems if the classes this depends on
+ * are forward referenced. Find a way to defer semantic()
+ * on this template.
+ */
+ semantic2(sc2);
+ }
+ if (global.errors != errorsave)
+ goto Laftersemantic;
+
+ if ((sc->func || (sc->flags & SCOPEfullinst)) && !tinst)
+ {
+ /* If a template is instantiated inside function, the whole instantiation
+ * should be done at that position. But, immediate running semantic3 of
+ * dependent templates may cause unresolved forward reference (Bugzilla 9050).
+ * To avoid the issue, don't run semantic3 until semantic and semantic2 done.
+ */
+ TemplateInstances deferred;
+ this->deferred = &deferred;
+
+ //printf("Run semantic3 on %s\n", toChars());
+ trySemantic3(sc2);
+
+ for (size_t i = 0; i < deferred.dim; i++)
+ {
+ //printf("+ run deferred semantic3 on %s\n", deferred[i]->toChars());
+ deferred[i]->semantic3(NULL);
+ }
+
+ this->deferred = NULL;
+ }
+ else if (tinst)
+ {
+ bool doSemantic3 = false;
+ if (sc->func && aliasdecl && aliasdecl->toAlias()->isFuncDeclaration())
+ {
+ /* Template function instantiation should run semantic3 immediately
+ * for attribute inference.
+ */
+ trySemantic3(sc2);
+ }
+ else if (sc->func)
+ {
+ /* A lambda function in template arguments might capture the
+ * instantiated scope context. For the correct context inference,
+ * all instantiated functions should run the semantic3 immediately.
+ * See also compilable/test14973.d
+ */
+ for (size_t i = 0; i < tdtypes.dim; i++)
+ {
+ RootObject *oarg = tdtypes[i];
+ Dsymbol *s = getDsymbol(oarg);
+ if (!s)
+ continue;
+
+ if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ {
+ if (!td->literal)
+ continue;
+ assert(td->members && td->members->dim == 1);
+ s = (*td->members)[0];
+ }
+ if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
+ {
+ if (fld->tok == TOKreserved)
+ {
+ doSemantic3 = true;
+ break;
+ }
+ }
+ }
+ //printf("[%s] %s doSemantic3 = %d\n", loc.toChars(), toChars(), doSemantic3);
+ }
+ if (doSemantic3)
+ trySemantic3(sc2);
+
+ TemplateInstance *ti = tinst;
+ int nest = 0;
+ while (ti && !ti->deferred && ti->tinst)
+ {
+ ti = ti->tinst;
+ if (++nest > 500)
+ {
+ global.gag = 0; // ensure error message gets printed
+ error("recursive expansion");
+ fatal();
+ }
+ }
+ if (ti && ti->deferred)
+ {
+ //printf("deferred semantic3 of %p %s, ti = %s, ti->deferred = %p\n", this, toChars(), ti->toChars());
+ for (size_t i = 0; ; i++)
+ {
+ if (i == ti->deferred->dim)
+ {
+ ti->deferred->push(this);
+ break;
+ }
+ if ((*ti->deferred)[i] == this)
+ break;
+ }
+ }
+ }
+
+ if (aliasdecl)
+ {
+ /* Bugzilla 13816: AliasDeclaration tries to resolve forward reference
+ * twice (See inuse check in AliasDeclaration::toAlias()). It's
+ * necessary to resolve mutual references of instantiated symbols, but
+ * it will left a true recursive alias in tuple declaration - an
+ * AliasDeclaration A refers TupleDeclaration B, and B contains A
+ * in its elements. To correctly make it an error, we strictly need to
+ * resolve the alias of eponymous member.
+ */
+ aliasdecl = aliasdecl->toAlias2();
+ }
+
+ Laftersemantic:
+ sc2->pop();
+
+ scope->pop();
+
+ // Give additional context info if error occurred during instantiation
+ if (global.errors != errorsave)
+ {
+ if (!errors)
+ {
+ if (!tempdecl->literal)
+ error(loc, "error instantiating");
+ if (tinst)
+ tinst->printInstantiationTrace();
+ }
+ errors = true;
+ if (gagged)
+ {
+ // Errors are gagged, so remove the template instance from the
+ // instance/symbol lists we added it to and reset our state to
+ // finish clean and so we can try to instantiate it again later
+ // (see bugzilla 4302 and 6602).
+ tempdecl->removeInstance(tempdecl_instance_idx);
+ if (target_symbol_list)
+ {
+ // Because we added 'this' in the last position above, we
+ // should be able to remove it without messing other indices up.
+ assert((*target_symbol_list)[target_symbol_list_idx] == this);
+ target_symbol_list->remove(target_symbol_list_idx);
+ memberOf = NULL; // no longer a member
+ }
+ semanticRun = PASSinit;
+ inst = NULL;
+ symtab = NULL;
+ }
+ }
+ else if (errinst)
+ {
+ /* Bugzilla 14541: If the previous gagged instance had failed by
+ * circular references, currrent "error reproduction instantiation"
+ * might succeed, because of the difference of instantiated context.
+ * On such case, the cached error instance needs to be overridden by the
+ * succeeded instance.
+ */
+ //printf("replaceInstance()\n");
+ TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)tempdecl->instances, (void *)hash);
+ assert(tinstances);
+ for (size_t i = 0; i < tinstances->dim; i++)
+ {
+ TemplateInstance *ti = (*tinstances)[i];
+ if (ti == errinst)
+ {
+ (*tinstances)[i] = this; // override
+ break;
+ }
+ }
+ }
+}
+
+
+/**********************************************
+ * Find template declaration corresponding to template instance.
+ *
+ * Returns:
+ * false if finding fails.
+ * Note:
+ * This function is reentrant against error occurrence. If returns false,
+ * any members of this object won't be modified, and repetition call will
+ * reproduce same error.
+ */
+
+bool TemplateInstance::findTempDecl(Scope *sc, WithScopeSymbol **pwithsym)
+{
+ if (pwithsym)
+ *pwithsym = NULL;
+
+ if (havetempdecl)
+ return true;
+
+ //printf("TemplateInstance::findTempDecl() %s\n", toChars());
+ if (!tempdecl)
+ {
+ /* Given:
+ * foo!( ... )
+ * figure out which TemplateDeclaration foo refers to.
+ */
+ Identifier *id = name;
+ Dsymbol *scopesym;
+ Dsymbol *s = sc->search(loc, id, &scopesym);
+ if (!s)
+ {
+ s = sc->search_correct(id);
+ if (s)
+ error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars());
+ else
+ error("template '%s' is not defined", id->toChars());
+ return false;
+ }
+
+ if (pwithsym)
+ *pwithsym = scopesym->isWithScopeSymbol();
+
+ /* We might have found an alias within a template when
+ * we really want the template.
+ */
+ TemplateInstance *ti;
+ if (s->parent &&
+ (ti = s->parent->isTemplateInstance()) != NULL)
+ {
+ if (ti->tempdecl && ti->tempdecl->ident == id)
+ {
+ /* This is so that one can refer to the enclosing
+ * template, even if it has the same name as a member
+ * of the template, if it has a !(arguments)
+ */
+ TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
+ assert(td);
+ if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td->overroot; // then get the start
+ s = td;
+ }
+ }
+
+ if (!updateTempDecl(sc, s))
+ {
+ return false;
+ }
+ }
+ assert(tempdecl);
+
+ struct ParamFwdTi
+ {
+ static int fp(void *param, Dsymbol *s)
+ {
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (!td)
+ return 0;
+
+ TemplateInstance *ti = (TemplateInstance *)param;
+ if (td->semanticRun == PASSinit)
+ {
+ if (td->_scope)
+ {
+ // Try to fix forward reference. Ungag errors while doing so.
+ Ungag ungag = td->ungagSpeculative();
+ td->semantic(td->_scope);
+ }
+ if (td->semanticRun == PASSinit)
+ {
+ ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars());
+ return 1;
+ }
+ }
+ return 0;
+ }
+ };
+ // Look for forward references
+ OverloadSet *tovers = tempdecl->isOverloadSet();
+ size_t overs_dim = tovers ? tovers->a.dim : 1;
+ for (size_t oi = 0; oi < overs_dim; oi++)
+ {
+ if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdTi::fp))
+ return false;
+ }
+ return true;
+}
+
+/**********************************************
+ * Confirm s is a valid template, then store it.
+ * Input:
+ * sc
+ * s candidate symbol of template. It may be:
+ * TemplateDeclaration
+ * FuncDeclaration with findTemplateDeclRoot() != NULL
+ * OverloadSet which contains candidates
+ * Returns:
+ * true if updating succeeds.
+ */
+
+bool TemplateInstance::updateTempDecl(Scope *sc, Dsymbol *s)
+{
+ if (s)
+ {
+ Identifier *id = name;
+ s = s->toAlias();
+
+ /* If an OverloadSet, look for a unique member that is a template declaration
+ */
+ OverloadSet *os = s->isOverloadSet();
+ if (os)
+ {
+ s = NULL;
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ Dsymbol *s2 = os->a[i];
+ if (FuncDeclaration *f = s2->isFuncDeclaration())
+ s2 = f->findTemplateDeclRoot();
+ else
+ s2 = s2->isTemplateDeclaration();
+ if (s2)
+ {
+ if (s)
+ {
+ tempdecl = os;
+ return true;
+ }
+ s = s2;
+ }
+ }
+ if (!s)
+ {
+ error("template '%s' is not defined", id->toChars());
+ return false;
+ }
+ }
+
+ OverDeclaration *od = s->isOverDeclaration();
+ if (od)
+ {
+ tempdecl = od; // TODO: more strict check
+ return true;
+ }
+
+ /* It should be a TemplateDeclaration, not some other symbol
+ */
+ if (FuncDeclaration *f = s->isFuncDeclaration())
+ tempdecl = f->findTemplateDeclRoot();
+ else
+ tempdecl = s->isTemplateDeclaration();
+ if (!tempdecl)
+ {
+ if (!s->parent && global.errors)
+ return false;
+ if (!s->parent && s->getType())
+ {
+ Dsymbol *s2 = s->getType()->toDsymbol(sc);
+ if (!s2)
+ {
+ error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+ return false;
+ }
+ s = s2;
+ }
+ //assert(s->parent);
+ TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL;
+ if (ti &&
+ (ti->name == s->ident ||
+ ti->toAlias()->ident == s->ident)
+ &&
+ ti->tempdecl)
+ {
+ /* This is so that one can refer to the enclosing
+ * template, even if it has the same name as a member
+ * of the template, if it has a !(arguments)
+ */
+ TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
+ assert(td);
+ if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td->overroot; // then get the start
+ tempdecl = td;
+ }
+ else
+ {
+ error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
+ return false;
+ }
+ }
+ }
+ return (tempdecl != NULL);
+}
+
+/**********************************
+ * Run semantic on the elements of tiargs.
+ * Input:
+ * sc
+ * Returns:
+ * false if one or more arguments have errors.
+ * Note:
+ * This function is reentrant against error occurrence. If returns false,
+ * all elements of tiargs won't be modified.
+ */
+
+bool TemplateInstance::semanticTiargs(Scope *sc)
+{
+ //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
+ if (semantictiargsdone)
+ return true;
+ if (semanticTiargs(loc, sc, tiargs, 0))
+ {
+ // cache the result iff semantic analysis succeeded entirely
+ semantictiargsdone = 1;
+ return true;
+ }
+ return false;
+}
+
+/**********************************
+ * Run semantic of tiargs as arguments of template.
+ * Input:
+ * loc
+ * sc
+ * tiargs array of template arguments
+ * flags 1: replace const variables with their initializers
+ * 2: don't devolve Parameter to Type
+ * Returns:
+ * false if one or more arguments have errors.
+ */
+
+bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags)
+{
+ // Run semantic on each argument, place results in tiargs[]
+ //printf("+TemplateInstance::semanticTiargs()\n");
+ if (!tiargs)
+ return true;
+ bool err = false;
+ for (size_t j = 0; j < tiargs->dim; j++)
+ {
+ RootObject *o = (*tiargs)[j];
+ Type *ta = isType(o);
+ Expression *ea = isExpression(o);
+ Dsymbol *sa = isDsymbol(o);
+
+ //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
+ if (ta)
+ {
+ //printf("type %s\n", ta->toChars());
+ // It might really be an Expression or an Alias
+ ta->resolve(loc, sc, &ea, &ta, &sa);
+ if (ea) goto Lexpr;
+ if (sa) goto Ldsym;
+ if (ta == NULL)
+ {
+ assert(global.errors);
+ ta = Type::terror;
+ }
+
+ Ltype:
+ if (ta->ty == Ttuple)
+ {
+ // Expand tuple
+ TypeTuple *tt = (TypeTuple *)ta;
+ size_t dim = tt->arguments->dim;
+ tiargs->remove(j);
+ if (dim)
+ {
+ tiargs->reserve(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *arg = (*tt->arguments)[i];
+ if (flags & 2 && arg->ident)
+ tiargs->insert(j + i, arg);
+ else
+ tiargs->insert(j + i, arg->type);
+ }
+ }
+ j--;
+ continue;
+ }
+ if (ta->ty == Terror)
+ {
+ err = true;
+ continue;
+ }
+ (*tiargs)[j] = ta->merge2();
+ }
+ else if (ea)
+ {
+ Lexpr:
+ //printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
+ if (flags & 1) // only used by __traits
+ {
+ ea = ::semantic(ea, sc);
+
+ // must not interpret the args, excepting template parameters
+ if (ea->op != TOKvar ||
+ (((VarExp *)ea)->var->storage_class & STCtemplateparameter))
+ {
+ ea = ea->optimize(WANTvalue);
+ }
+ }
+ else
+ {
+ sc = sc->startCTFE();
+ ea = ::semantic(ea, sc);
+ sc = sc->endCTFE();
+
+ if (ea->op == TOKvar)
+ {
+ /* This test is to skip substituting a const var with
+ * its initializer. The problem is the initializer won't
+ * match with an 'alias' parameter. Instead, do the
+ * const substitution in TemplateValueParameter::matchArg().
+ */
+ }
+ else if (definitelyValueParameter(ea))
+ {
+ if (ea->checkValue()) // check void expression
+ ea = new ErrorExp();
+ unsigned int olderrs = global.errors;
+ ea = ea->ctfeInterpret();
+ if (global.errors != olderrs)
+ ea = new ErrorExp();
+ }
+ }
+ //printf("-[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
+ if (ea->op == TOKtuple)
+ {
+ // Expand tuple
+ TupleExp *te = (TupleExp *)ea;
+ size_t dim = te->exps->dim;
+ tiargs->remove(j);
+ if (dim)
+ {
+ tiargs->reserve(dim);
+ for (size_t i = 0; i < dim; i++)
+ tiargs->insert(j + i, (*te->exps)[i]);
+ }
+ j--;
+ continue;
+ }
+ if (ea->op == TOKerror)
+ {
+ err = true;
+ continue;
+ }
+ (*tiargs)[j] = ea;
+
+ if (ea->op == TOKtype)
+ {
+ ta = ea->type;
+ goto Ltype;
+ }
+ if (ea->op == TOKscope)
+ {
+ sa = ((ScopeExp *)ea)->sds;
+ goto Ldsym;
+ }
+ if (ea->op == TOKfunction)
+ {
+ FuncExp *fe = (FuncExp *)ea;
+ /* A function literal, that is passed to template and
+ * already semanticed as function pointer, never requires
+ * outer frame. So convert it to global function is valid.
+ */
+ if (fe->fd->tok == TOKreserved && fe->type->ty == Tpointer)
+ {
+ // change to non-nested
+ fe->fd->tok = TOKfunction;
+ fe->fd->vthis = NULL;
+ }
+ else if (fe->td)
+ {
+ /* If template argument is a template lambda,
+ * get template declaration itself. */
+ //sa = fe->td;
+ //goto Ldsym;
+ }
+ }
+ if (ea->op == TOKdotvar)
+ {
+ // translate expression to dsymbol.
+ sa = ((DotVarExp *)ea)->var;
+ goto Ldsym;
+ }
+ if (ea->op == TOKtemplate)
+ {
+ sa = ((TemplateExp *)ea)->td;
+ goto Ldsym;
+ }
+ if (ea->op == TOKdottd)
+ {
+ // translate expression to dsymbol.
+ sa = ((DotTemplateExp *)ea)->td;
+ goto Ldsym;
+ }
+ }
+ else if (sa)
+ {
+ Ldsym:
+ //printf("dsym %s %s\n", sa->kind(), sa->toChars());
+ if (sa->errors)
+ {
+ err = true;
+ continue;
+ }
+
+ TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
+ if (d)
+ {
+ // Expand tuple
+ tiargs->remove(j);
+ tiargs->insert(j, d->objects);
+ j--;
+ continue;
+ }
+ if (FuncAliasDeclaration *fa = sa->isFuncAliasDeclaration())
+ {
+ FuncDeclaration *f = fa->toAliasFunc();
+ if (!fa->hasOverloads && f->isUnique())
+ {
+ // Strip FuncAlias only when the aliased function
+ // does not have any overloads.
+ sa = f;
+ }
+ }
+ (*tiargs)[j] = sa;
+
+ TemplateDeclaration *td = sa->isTemplateDeclaration();
+ if (td && td->semanticRun == PASSinit && td->literal)
+ {
+ td->semantic(sc);
+ }
+ FuncDeclaration *fd = sa->isFuncDeclaration();
+ if (fd)
+ fd->functionSemantic();
+ }
+ else if (isParameter(o))
+ {
+ }
+ else
+ {
+ assert(0);
+ }
+ //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
+ }
+ return !err;
+}
+
+bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
+{
+ if (havetempdecl)
+ {
+ TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+ assert(tempdecl->_scope);
+ // Deduce tdtypes
+ tdtypes.setDim(tempdecl->parameters->dim);
+ if (!tempdecl->matchWithInstance(sc, this, &tdtypes, fargs, 2))
+ {
+ error("incompatible arguments for template instantiation");
+ return false;
+ }
+ // TODO: Normalizing tiargs for bugzilla 7469 is necessary?
+ return true;
+ }
+
+ unsigned errs = global.errors;
+
+ struct ParamBest
+ {
+ // context
+ Scope *sc;
+ TemplateInstance *ti;
+ Objects dedtypes;
+ // result
+ TemplateDeclaration *td_best;
+ TemplateDeclaration *td_ambig;
+ MATCH m_best;
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ return ((ParamBest *)param)->fp(s);
+ }
+ int fp(Dsymbol *s)
+ {
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (!td)
+ return 0;
+
+ if (td == td_best) // skip duplicates
+ return 0;
+
+ //printf("td = %s\n", td->toPrettyChars());
+
+ // If more arguments than parameters,
+ // then this is no match.
+ if (td->parameters->dim < ti->tiargs->dim)
+ {
+ if (!td->isVariadic())
+ return 0;
+ }
+
+ dedtypes.setDim(td->parameters->dim);
+ dedtypes.zero();
+ assert(td->semanticRun != PASSinit);
+ MATCH m = td->matchWithInstance(sc, ti, &dedtypes, ti->fargs, 0);
+ //printf("matchWithInstance = %d\n", m);
+ if (m <= MATCHnomatch) // no match at all
+ return 0;
+
+ if (m < m_best) goto Ltd_best;
+ if (m > m_best) goto Ltd;
+
+ {
+ // Disambiguate by picking the most specialized TemplateDeclaration
+ MATCH c1 = td->leastAsSpecialized(sc, td_best, ti->fargs);
+ MATCH c2 = td_best->leastAsSpecialized(sc, td, ti->fargs);
+ //printf("c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+
+ td_ambig = td;
+ return 0;
+
+ Ltd_best: // td_best is the best match so far
+ td_ambig = NULL;
+ return 0;
+
+ Ltd: // td is the new best match
+ td_ambig = NULL;
+ td_best = td;
+ m_best = m;
+ ti->tdtypes.setDim(dedtypes.dim);
+ memcpy(ti->tdtypes.tdata(), dedtypes.tdata(), ti->tdtypes.dim * sizeof(void *));
+ return 0;
+ }
+ };
+ ParamBest p;
+ // context
+ p.ti = this;
+ p.sc = sc;
+
+ /* Since there can be multiple TemplateDeclaration's with the same
+ * name, look for the best match.
+ */
+ TemplateDeclaration *td_last = NULL;
+
+ OverloadSet *tovers = tempdecl->isOverloadSet();
+ size_t overs_dim = tovers ? tovers->a.dim : 1;
+ for (size_t oi = 0; oi < overs_dim; oi++)
+ {
+ // result
+ p.td_best = NULL;
+ p.td_ambig = NULL;
+ p.m_best = MATCHnomatch;
+ overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamBest::fp);
+
+ if (p.td_ambig)
+ {
+ ::error(loc, "%s %s.%s matches more than one template declaration:\n%s: %s\nand\n%s: %s",
+ p.td_best->kind(), p.td_best->parent->toPrettyChars(), p.td_best->ident->toChars(),
+ p.td_best->loc.toChars() , p.td_best->toChars(),
+ p.td_ambig->loc.toChars(), p.td_ambig->toChars());
+ return false;
+ }
+ if (p.td_best)
+ {
+ if (!td_last)
+ td_last = p.td_best;
+ else if (td_last != p.td_best)
+ {
+ ScopeDsymbol::multiplyDefined(loc, td_last, p.td_best);
+ return false;
+ }
+ }
+ }
+
+ if (td_last)
+ {
+ /* Bugzilla 7469: Normalize tiargs by using corresponding deduced
+ * template value parameters and tuples for the correct mangling.
+ *
+ * By doing this before hasNestedArgs, CTFEable local variable will be
+ * accepted as a value parameter. For example:
+ *
+ * void foo() {
+ * struct S(int n) {} // non-global template
+ * const int num = 1; // CTFEable local variable
+ * S!num s; // S!1 is instantiated, not S!num
+ * }
+ */
+ size_t dim = td_last->parameters->dim - (td_last->isVariadic() ? 1 : 0);
+ for (size_t i = 0; i < dim; i++)
+ {
+ if (tiargs->dim <= i)
+ tiargs->push(tdtypes[i]);
+ assert(i < tiargs->dim);
+
+ TemplateValueParameter *tvp = (*td_last->parameters)[i]->isTemplateValueParameter();
+ if (!tvp)
+ continue;
+ assert(tdtypes[i]);
+ // tdtypes[i] is already normalized to the required type in matchArg
+
+ (*tiargs)[i] = tdtypes[i];
+ }
+ if (td_last->isVariadic() && tiargs->dim == dim && tdtypes[dim])
+ {
+ Tuple *va = isTuple(tdtypes[dim]);
+ assert(va);
+ for (size_t i = 0; i < va->objects.dim; i++)
+ tiargs->push(va->objects[i]);
+ }
+ }
+ else if (errors && inst)
+ {
+ // instantiation was failed with error reporting
+ assert(global.errors);
+ return false;
+ }
+ else
+ {
+ TemplateDeclaration *tdecl = tempdecl->isTemplateDeclaration();
+
+ if (errs != global.errors)
+ errorSupplemental(loc, "while looking for match for %s", toChars());
+ else if (tdecl && !tdecl->overnext)
+ {
+ // Only one template, so we can give better error message
+ error("does not match template declaration %s", tdecl->toChars());
+ }
+ else
+ ::error(loc, "%s %s.%s does not match any template declaration",
+ tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars());
+ return false;
+ }
+
+ /* The best match is td_last
+ */
+ tempdecl = td_last;
+
+ return (errs == global.errors);
+}
+
+/*****************************************************
+ * Determine if template instance is really a template function,
+ * and that template function needs to infer types from the function
+ * arguments.
+ *
+ * Like findBestMatch, iterate possible template candidates,
+ * but just looks only the necessity of type inference.
+ */
+
+bool TemplateInstance::needsTypeInference(Scope *sc, int flag)
+{
+ //printf("TemplateInstance::needsTypeInference() %s\n", toChars());
+ if (semanticRun != PASSinit)
+ return false;
+
+ struct ParamNeedsInf
+ {
+ // context
+ Scope *sc;
+ TemplateInstance *ti;
+ int flag;
+ // result
+ Objects dedtypes;
+ size_t count;
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ return ((ParamNeedsInf *)param)->fp(s);
+ }
+ int fp(Dsymbol *s)
+ {
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (!td)
+ {
+ return 0;
+ }
+
+ /* If any of the overloaded template declarations need inference,
+ * then return true
+ */
+ FuncDeclaration *fd;
+ if (!td->onemember)
+ return 0;
+ if (TemplateDeclaration *td2 = td->onemember->isTemplateDeclaration())
+ {
+ if (!td2->onemember || !td2->onemember->isFuncDeclaration())
+ return 0;
+ if (ti->tiargs->dim >= td->parameters->dim - (td->isVariadic() ? 1 : 0))
+ return 0;
+ return 1;
+ }
+ if ((fd = td->onemember->isFuncDeclaration()) == NULL ||
+ fd->type->ty != Tfunction)
+ {
+ return 0;
+ }
+
+ for (size_t i = 0; i < td->parameters->dim; i++)
+ {
+ if ((*td->parameters)[i]->isTemplateThisParameter())
+ return 1;
+ }
+
+ /* Determine if the instance arguments, tiargs, are all that is necessary
+ * to instantiate the template.
+ */
+ //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, ti->tiargs->dim);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (size_t dim = Parameter::dim(tf->parameters))
+ {
+ TemplateParameter *tp = td->isVariadic();
+ if (tp && td->parameters->dim > 1)
+ return 1;
+
+ if (!tp && ti->tiargs->dim < td->parameters->dim)
+ {
+ // Can remain tiargs be filled by default arguments?
+ for (size_t i = ti->tiargs->dim; i < td->parameters->dim; i++)
+ {
+ if (!(*td->parameters)[i]->hasDefaultArg())
+ return 1;
+ }
+ }
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ // 'auto ref' needs inference.
+ if (Parameter::getNth(tf->parameters, i)->storageClass & STCauto)
+ return 1;
+ }
+ }
+
+ if (!flag)
+ {
+ /* Calculate the need for overload resolution.
+ * When only one template can match with tiargs, inference is not necessary.
+ */
+ dedtypes.setDim(td->parameters->dim);
+ dedtypes.zero();
+ if (td->semanticRun == PASSinit)
+ {
+ if (td->_scope)
+ {
+ // Try to fix forward reference. Ungag errors while doing so.
+ Ungag ungag = td->ungagSpeculative();
+ td->semantic(td->_scope);
+ }
+ if (td->semanticRun == PASSinit)
+ {
+ ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars());
+ return 1;
+ }
+ }
+ assert(td->semanticRun != PASSinit);
+ MATCH m = td->matchWithInstance(sc, ti, &dedtypes, NULL, 0);
+ if (m <= MATCHnomatch)
+ return 0;
+ }
+
+ /* If there is more than one function template which matches, we may
+ * need type inference (see Bugzilla 4430)
+ */
+ if (++count > 1)
+ return 1;
+
+ return 0;
+ }
+ };
+ ParamNeedsInf p;
+ // context
+ p.ti = this;
+ p.sc = sc;
+ p.flag = flag;
+ // result
+ p.count = 0;
+
+ OverloadSet *tovers = tempdecl->isOverloadSet();
+ size_t overs_dim = tovers ? tovers->a.dim : 1;
+ unsigned olderrs = global.errors;
+ for (size_t oi = 0; oi < overs_dim; oi++)
+ {
+ if (overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamNeedsInf::fp))
+ return true;
+ }
+ if (olderrs != global.errors)
+ {
+ if (!global.gag)
+ {
+ errorSupplemental(loc, "while looking for match for %s", toChars());
+ semanticRun = PASSsemanticdone;
+ inst = this;
+ }
+ errors = true;
+ }
+ //printf("false\n");
+ return false;
+}
+
+
+/*****************************************
+ * Determines if a TemplateInstance will need a nested
+ * generation of the TemplateDeclaration.
+ * Sets enclosing property if so, and returns != 0;
+ */
+
+bool TemplateInstance::hasNestedArgs(Objects *args, bool isstatic)
+{
+ int nested = 0;
+ //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars());
+
+ /* A nested instance happens when an argument references a local
+ * symbol that is on the stack.
+ */
+ for (size_t i = 0; i < args->dim; i++)
+ {
+ RootObject *o = (*args)[i];
+ Expression *ea = isExpression(o);
+ Dsymbol *sa = isDsymbol(o);
+ Tuple *va = isTuple(o);
+ if (ea)
+ {
+ if (ea->op == TOKvar)
+ {
+ sa = ((VarExp *)ea)->var;
+ goto Lsa;
+ }
+ if (ea->op == TOKthis)
+ {
+ sa = ((ThisExp *)ea)->var;
+ goto Lsa;
+ }
+ if (ea->op == TOKfunction)
+ {
+ if (((FuncExp *)ea)->td)
+ sa = ((FuncExp *)ea)->td;
+ else
+ sa = ((FuncExp *)ea)->fd;
+ goto Lsa;
+ }
+ // Emulate Expression::toMangleBuffer call that had exist in TemplateInstance::genIdent.
+ if (ea->op != TOKint64 &&
+ ea->op != TOKfloat64 &&
+ ea->op != TOKcomplex80 &&
+ ea->op != TOKnull &&
+ ea->op != TOKstring &&
+ ea->op != TOKarrayliteral &&
+ ea->op != TOKassocarrayliteral &&
+ ea->op != TOKstructliteral)
+ {
+ ea->error("expression %s is not a valid template value argument", ea->toChars());
+ errors = true;
+ }
+ }
+ else if (sa)
+ {
+ Lsa:
+ sa = sa->toAlias();
+ TemplateDeclaration *td = sa->isTemplateDeclaration();
+ if (td)
+ {
+ TemplateInstance *ti = sa->toParent()->isTemplateInstance();
+ if (ti && ti->enclosing)
+ sa = ti;
+ }
+ TemplateInstance *ti = sa->isTemplateInstance();
+ Declaration *d = sa->isDeclaration();
+ if ((td && td->literal) ||
+ (ti && ti->enclosing) ||
+ (d && !d->isDataseg() &&
+ !(d->storage_class & STCmanifest) &&
+ (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) &&
+ !isTemplateMixin()
+ ))
+ {
+ // if module level template
+ if (isstatic)
+ {
+ Dsymbol *dparent = sa->toParent2();
+ if (!enclosing)
+ enclosing = dparent;
+ else if (enclosing != dparent)
+ {
+ /* Select the more deeply nested of the two.
+ * Error if one is not nested inside the other.
+ */
+ for (Dsymbol *p = enclosing; p; p = p->parent)
+ {
+ if (p == dparent)
+ goto L1; // enclosing is most nested
+ }
+ for (Dsymbol *p = dparent; p; p = p->parent)
+ {
+ if (p == enclosing)
+ {
+ enclosing = dparent;
+ goto L1; // dparent is most nested
+ }
+ }
+ error("%s is nested in both %s and %s",
+ toChars(), enclosing->toChars(), dparent->toChars());
+ errors = true;
+ }
+ L1:
+ //printf("\tnested inside %s\n", enclosing->toChars());
+ nested |= 1;
+ }
+ else
+ {
+ error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars());
+ errors = true;
+ }
+ }
+ }
+ else if (va)
+ {
+ nested |= (int)hasNestedArgs(&va->objects, isstatic);
+ }
+ }
+ //printf("-TemplateInstance::hasNestedArgs('%s') = %d\n", tempdecl->ident->toChars(), nested);
+ return nested != 0;
+}
+
+/*****************************************
+ * Append 'this' to the specific module members[]
+ */
+Dsymbols *TemplateInstance::appendToModuleMember()
+{
+ Module *mi = minst; // instantiated -> inserted module
+
+ if (global.params.useUnitTests ||
+ global.params.debuglevel)
+ {
+ // Turn all non-root instances to speculative
+ if (mi && !mi->isRoot())
+ mi = NULL;
+ }
+
+ //printf("%s->appendToModuleMember() enclosing = %s mi = %s\n",
+ // toPrettyChars(),
+ // enclosing ? enclosing->toPrettyChars() : NULL,
+ // mi ? mi->toPrettyChars() : NULL);
+ if (!mi || mi->isRoot())
+ {
+ /* If the instantiated module is speculative or root, insert to the
+ * member of a root module. Then:
+ * - semantic3 pass will get called on the instance members.
+ * - codegen pass will get a selection chance to do/skip it.
+ */
+
+ struct N
+ {
+ static Dsymbol *getStrictEnclosing(TemplateInstance *ti)
+ {
+ do
+ {
+ if (ti->enclosing)
+ return ti->enclosing;
+ ti = ti->tempdecl->isInstantiated();
+ }
+ while (ti);
+ return NULL;
+ }
+ };
+ Dsymbol *enc = N::getStrictEnclosing(this);
+
+ // insert target is made stable by using the module
+ // where tempdecl is declared.
+ mi = (enc ? enc : tempdecl)->getModule();
+ if (!mi->isRoot())
+ mi = mi->importedFrom;
+ assert(mi->isRoot());
+ }
+ else
+ {
+ /* If the instantiated module is non-root, insert to the member of the
+ * non-root module. Then:
+ * - semantic3 pass won't be called on the instance.
+ * - codegen pass won't reach to the instance.
+ */
+ }
+ //printf("\t--> mi = %s\n", mi->toPrettyChars());
+
+ if (memberOf == mi) // already a member
+ {
+ return NULL;
+ }
+
+ Dsymbols *a = mi->members;
+ a->push(this);
+ memberOf = mi;
+ if (mi->semanticRun >= PASSsemantic2done && mi->isRoot())
+ Module::addDeferredSemantic2(this);
+ if (mi->semanticRun >= PASSsemantic3done && mi->isRoot())
+ Module::addDeferredSemantic3(this);
+ return a;
+}
+
+/****************************************
+ * This instance needs an identifier for name mangling purposes.
+ * Create one by taking the template declaration name and adding
+ * the type signature for it.
+ */
+
+Identifier *TemplateInstance::genIdent(Objects *args)
+{
+ TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
+ OutBuffer buf;
+ const char *id = tempdecl->ident->toChars();
+ if (!members)
+ {
+ // Use "__U" for the symbols declared inside template constraint.
+ buf.printf("__U%llu%s", (ulonglong)strlen(id), id);
+ }
+ else
+ buf.printf("__T%llu%s", (ulonglong)strlen(id), id);
+ size_t nparams = tempdecl->parameters->dim - (tempdecl->isVariadic() ? 1 : 0);
+ for (size_t i = 0; i < args->dim; i++)
+ {
+ RootObject *o = (*args)[i];
+ Type *ta = isType(o);
+ Expression *ea = isExpression(o);
+ Dsymbol *sa = isDsymbol(o);
+ Tuple *va = isTuple(o);
+ //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
+ if (i < nparams && (*tempdecl->parameters)[i]->specialization())
+ buf.writeByte('H'); // Bugzilla 6574
+ if (ta)
+ {
+ buf.writeByte('T');
+ if (ta->deco)
+ buf.writestring(ta->deco);
+ else
+ {
+ assert(global.errors);
+ }
+ }
+ else if (ea)
+ {
+ // Don't interpret it yet, it might actually be an alias template parameter.
+ // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
+ const bool keepLvalue = true;
+ ea = ea->optimize(WANTvalue, keepLvalue);
+ if (ea->op == TOKvar)
+ {
+ sa = ((VarExp *)ea)->var;
+ ea = NULL;
+ goto Lsa;
+ }
+ if (ea->op == TOKthis)
+ {
+ sa = ((ThisExp *)ea)->var;
+ ea = NULL;
+ goto Lsa;
+ }
+ if (ea->op == TOKfunction)
+ {
+ if (((FuncExp *)ea)->td)
+ sa = ((FuncExp *)ea)->td;
+ else
+ sa = ((FuncExp *)ea)->fd;
+ ea = NULL;
+ goto Lsa;
+ }
+ buf.writeByte('V');
+ if (ea->op == TOKtuple)
+ {
+ ea->error("tuple is not a valid template value argument");
+ continue;
+ }
+ // Now that we know it is not an alias, we MUST obtain a value
+ unsigned olderr = global.errors;
+ ea = ea->ctfeInterpret();
+ if (ea->op == TOKerror || olderr != global.errors)
+ continue;
+
+ /* Use deco that matches what it would be for a function parameter
+ */
+ buf.writestring(ea->type->deco);
+ mangleToBuffer(ea, &buf);
+ }
+ else if (sa)
+ {
+ Lsa:
+ buf.writeByte('S');
+ sa = sa->toAlias();
+ Declaration *d = sa->isDeclaration();
+ if (d && (!d->type || !d->type->deco))
+ {
+ error("forward reference of %s %s", d->kind(), d->toChars());
+ continue;
+ }
+
+ OutBuffer bufsa;
+ mangleToBuffer(sa, &bufsa);
+ const char *s = bufsa.extractString();
+
+ /* Bugzilla 3043: if the first character of s is a digit this
+ * causes ambiguity issues because the digits of the two numbers are adjacent.
+ * Current demanglers resolve this by trying various places to separate the
+ * numbers until one gets a successful demangle.
+ * Unfortunately, fixing this ambiguity will break existing binary
+ * compatibility and the demanglers, so we'll leave it as is.
+ */
+ buf.printf("%u%s", (unsigned)strlen(s), s);
+ }
+ else if (va)
+ {
+ assert(i + 1 == args->dim); // must be last one
+ args = &va->objects;
+ i = -(size_t)1;
+ }
+ else
+ assert(0);
+ }
+ buf.writeByte('Z');
+ id = buf.peekString();
+ //printf("\tgenIdent = %s\n", id);
+ return Identifier::idPool(id);
+}
+
+/*************************************
+ * Lazily generate identifier for template instance.
+ * This is because 75% of the ident's are never needed.
+ */
+
+Identifier *TemplateInstance::getIdent()
+{
+ if (!ident && inst && !errors)
+ ident = genIdent(tiargs); // need an identifier for name mangling purposes.
+ return ident;
+}
+
+/****************************************************
+ * Declare parameters of template instance, initialize them with the
+ * template instance arguments.
+ */
+
+void TemplateInstance::declareParameters(Scope *sc)
+{
+ TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ //printf("TemplateInstance::declareParameters()\n");
+ for (size_t i = 0; i < tdtypes.dim; i++)
+ {
+ TemplateParameter *tp = (*tempdecl->parameters)[i];
+ //RootObject *o = (*tiargs)[i];
+ RootObject *o = tdtypes[i]; // initializer for tp
+
+ //printf("\ttdtypes[%d] = %p\n", i, o);
+ tempdecl->declareParameter(sc, tp, o);
+ }
+}
+
+void TemplateInstance::semantic2(Scope *sc)
+{
+ if (semanticRun >= PASSsemantic2)
+ return;
+ semanticRun = PASSsemantic2;
+ if (!errors && members)
+ {
+ TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ sc = tempdecl->_scope;
+ assert(sc);
+ sc = sc->push(argsym);
+ sc = sc->push(this);
+ sc->tinst = this;
+ sc->minst = minst;
+
+ int needGagging = (gagged && !global.gag);
+ unsigned int olderrors = global.errors;
+ int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+ if (needGagging)
+ oldGaggedErrors = global.startGagging();
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic2(sc);
+ if (gagged && global.errors != olderrors)
+ break;
+ }
+
+ if (global.errors != olderrors)
+ {
+ if (!errors)
+ {
+ if (!tempdecl->literal)
+ error(loc, "error instantiating");
+ if (tinst)
+ tinst->printInstantiationTrace();
+ }
+ errors = true;
+ }
+ if (needGagging)
+ global.endGagging(oldGaggedErrors);
+
+ sc = sc->pop();
+ sc->pop();
+ }
+}
+
+void TemplateInstance::semantic3(Scope *sc)
+{
+//if (toChars()[0] == 'D') *(char*)0=0;
+ if (semanticRun >= PASSsemantic3)
+ return;
+ semanticRun = PASSsemantic3;
+ if (!errors && members)
+ {
+ TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ sc = tempdecl->_scope;
+ sc = sc->push(argsym);
+ sc = sc->push(this);
+ sc->tinst = this;
+ sc->minst = minst;
+
+ int needGagging = (gagged && !global.gag);
+ unsigned int olderrors = global.errors;
+ int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+ /* If this is a gagged instantiation, gag errors.
+ * Future optimisation: If the results are actually needed, errors
+ * would already be gagged, so we don't really need to run semantic
+ * on the members.
+ */
+ if (needGagging)
+ oldGaggedErrors = global.startGagging();
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic3(sc);
+ if (gagged && global.errors != olderrors)
+ break;
+ }
+
+ if (global.errors != olderrors)
+ {
+ if (!errors)
+ {
+ if (!tempdecl->literal)
+ error(loc, "error instantiating");
+ if (tinst)
+ tinst->printInstantiationTrace();
+ }
+ errors = true;
+ }
+ if (needGagging)
+ global.endGagging(oldGaggedErrors);
+
+ sc = sc->pop();
+ sc->pop();
+ }
+}
+
+/**************************************
+ * Given an error instantiating the TemplateInstance,
+ * give the nested TemplateInstance instantiations that got
+ * us here. Those are a list threaded into the nested scopes.
+ */
+void TemplateInstance::printInstantiationTrace()
+{
+ if (global.gag)
+ return;
+
+ const unsigned max_shown = 6;
+ const char format[] = "instantiated from here: %s";
+
+ // determine instantiation depth and number of recursive instantiations
+ unsigned n_instantiations = 1;
+ unsigned n_totalrecursions = 0;
+ for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+ {
+ ++n_instantiations;
+ // If two instantiations use the same declaration, they are recursive.
+ // (this works even if they are instantiated from different places in the
+ // same template).
+ // In principle, we could also check for multiple-template recursion, but it's
+ // probably not worthwhile.
+ if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl
+ && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc))
+ ++n_totalrecursions;
+ }
+
+ // show full trace only if it's short or verbose is on
+ if (n_instantiations <= max_shown || global.params.verbose)
+ {
+ for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+ {
+ cur->errors = true;
+ errorSupplemental(cur->loc, format, cur->toChars());
+ }
+ }
+ else if (n_instantiations - n_totalrecursions <= max_shown)
+ {
+ // By collapsing recursive instantiations into a single line,
+ // we can stay under the limit.
+ int recursionDepth=0;
+ for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+ {
+ cur->errors = true;
+ if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl
+ && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc))
+ {
+ ++recursionDepth;
+ }
+ else
+ {
+ if (recursionDepth)
+ errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars());
+ else
+ errorSupplemental(cur->loc, format, cur->toChars());
+ recursionDepth = 0;
+ }
+ }
+ }
+ else
+ {
+ // Even after collapsing the recursions, the depth is too deep.
+ // Just display the first few and last few instantiations.
+ unsigned i = 0;
+ for (TemplateInstance *cur = this; cur; cur = cur->tinst)
+ {
+ cur->errors = true;
+
+ if (i == max_shown / 2)
+ errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
+
+ if (i < max_shown / 2 ||
+ i >= n_instantiations - max_shown + max_shown / 2)
+ errorSupplemental(cur->loc, format, cur->toChars());
+ ++i;
+ }
+ }
+}
+
+Dsymbol *TemplateInstance::toAlias()
+{
+ if (!inst)
+ {
+ // Maybe we can resolve it
+ if (_scope)
+ {
+ semantic(_scope);
+ }
+ if (!inst)
+ {
+ error("cannot resolve forward reference");
+ errors = true;
+ return this;
+ }
+ }
+
+ if (inst != this)
+ return inst->toAlias();
+
+ if (aliasdecl)
+ {
+ return aliasdecl->toAlias();
+ }
+
+ return inst;
+}
+
+const char *TemplateInstance::kind()
+{
+ return "template instance";
+}
+
+bool TemplateInstance::oneMember(Dsymbol **ps, Identifier *)
+{
+ *ps = NULL;
+ return true;
+}
+
+const char *TemplateInstance::toChars()
+{
+ OutBuffer buf;
+ toCBufferInstance(this, &buf);
+ return buf.extractString();
+}
+
+const char *TemplateInstance::toPrettyCharsHelper()
+{
+ OutBuffer buf;
+ toCBufferInstance(this, &buf, true);
+ return buf.extractString();
+}
+
+/*************************************
+ * Compare proposed template instantiation with existing template instantiation.
+ * Note that this is not commutative because of the auto ref check.
+ * Params:
+ * this = proposed template instantiation
+ * o = existing template instantiation
+ * Returns:
+ * 0 for match, 1 for no match
+ */
+int TemplateInstance::compare(RootObject *o)
+{
+ TemplateInstance *ti = (TemplateInstance *)o;
+
+ //printf("this = %p, ti = %p\n", this, ti);
+ assert(tdtypes.dim == ti->tdtypes.dim);
+
+ // Nesting must match
+ if (enclosing != ti->enclosing)
+ {
+ //printf("test2 enclosing %s ti->enclosing %s\n", enclosing ? enclosing->toChars() : "", ti->enclosing ? ti->enclosing->toChars() : "");
+ goto Lnotequals;
+ }
+ //printf("parent = %s, ti->parent = %s\n", parent->toPrettyChars(), ti->parent->toPrettyChars());
+
+ if (!arrayObjectMatch(&tdtypes, &ti->tdtypes))
+ goto Lnotequals;
+
+ /* Template functions may have different instantiations based on
+ * "auto ref" parameters.
+ */
+ if (FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration())
+ {
+ if (!fd->errors)
+ {
+ Parameters *fparameters = fd->getParameters(NULL);
+ size_t nfparams = Parameter::dim(fparameters); // Num function parameters
+ for (size_t j = 0; j < nfparams; j++)
+ {
+ Parameter *fparam = Parameter::getNth(fparameters, j);
+ if (fparam->storageClass & STCautoref) // if "auto ref"
+ {
+ if (!fargs)
+ goto Lnotequals;
+ if (fargs->dim <= j)
+ break;
+ Expression *farg = (*fargs)[j];
+ if (farg->isLvalue())
+ {
+ if (!(fparam->storageClass & STCref))
+ goto Lnotequals; // auto ref's don't match
+ }
+ else
+ {
+ if (fparam->storageClass & STCref)
+ goto Lnotequals; // auto ref's don't match
+ }
+ }
+ }
+ }
+ }
+ return 0;
+
+ Lnotequals:
+ return 1;
+}
+
+hash_t TemplateInstance::toHash()
+{
+ if (!hash)
+ {
+ hash = (size_t)(void *)enclosing;
+ hash += arrayObjectHash(&tdtypes);
+ hash += hash == 0;
+ }
+ return hash;
+}
+
+/**************************************
+ * IsExpression can evaluate the specified type speculatively, and even if
+ * it instantiates any symbols, they are normally unnecessary for the
+ * final executable.
+ * However, if those symbols leak to the actual code, compiler should remark
+ * them as non-speculative to generate their code and link to the final executable.
+ */
+void unSpeculative(Scope *sc, RootObject *o)
+{
+ if (!o)
+ return;
+
+ if (Tuple *tup = isTuple(o))
+ {
+ for (size_t i = 0; i < tup->objects.dim; i++)
+ {
+ unSpeculative(sc, tup->objects[i]);
+ }
+ return;
+ }
+
+ Dsymbol *s = getDsymbol(o);
+ if (!s)
+ return;
+
+ if (Declaration *d = s->isDeclaration())
+ {
+ if (VarDeclaration *vd = d->isVarDeclaration())
+ o = vd->type;
+ else if (AliasDeclaration *ad = d->isAliasDeclaration())
+ {
+ o = ad->getType();
+ if (!o)
+ o = ad->toAlias();
+ }
+ else
+ o = d->toAlias();
+
+ s = getDsymbol(o);
+ if (!s)
+ return;
+ }
+
+ if (TemplateInstance *ti = s->isTemplateInstance())
+ {
+ // If the instance is already non-speculative,
+ // or it is leaked to the speculative scope.
+ if (ti->minst != NULL || sc->minst == NULL)
+ return;
+
+ // Remark as non-speculative instance.
+ ti->minst = sc->minst;
+ if (!ti->tinst)
+ ti->tinst = sc->tinst;
+
+ unSpeculative(sc, ti->tempdecl);
+ }
+
+ if (TemplateInstance *ti = s->isInstantiated())
+ unSpeculative(sc, ti);
+}
+
+/***********************************************
+ * Returns true if this is not instantiated in non-root module, and
+ * is a part of non-speculative instantiatiation.
+ *
+ * Note: minst does not stabilize until semantic analysis is completed,
+ * so don't call this function during semantic analysis to return precise result.
+ */
+bool TemplateInstance::needsCodegen()
+{
+ // Now -allInst is just for the backward compatibility.
+ if (global.params.allInst)
+ {
+ //printf("%s minst = %s, enclosing (%s)->isNonRoot = %d\n",
+ // toPrettyChars(), minst ? minst->toChars() : NULL,
+ // enclosing ? enclosing->toPrettyChars() : NULL, enclosing && enclosing->inNonRoot());
+ if (enclosing)
+ {
+ // Bugzilla 14588: If the captured context is not a function
+ // (e.g. class), the instance layout determination is guaranteed,
+ // because the semantic/semantic2 pass will be executed
+ // even for non-root instances.
+ if (!enclosing->isFuncDeclaration())
+ return true;
+
+ // Bugzilla 14834: If the captured context is a function,
+ // this excessive instantiation may cause ODR violation, because
+ // -allInst and others doesn't guarantee the semantic3 execution
+ // for that function.
+
+ // If the enclosing is also an instantiated function,
+ // we have to rely on the ancestor's needsCodegen() result.
+ if (TemplateInstance *ti = enclosing->isInstantiated())
+ return ti->needsCodegen();
+
+ // Bugzilla 13415: If and only if the enclosing scope needs codegen,
+ // this nested templates would also need code generation.
+ return !enclosing->inNonRoot();
+ }
+ return true;
+ }
+
+ if (!minst)
+ {
+ // If this is a speculative instantiation,
+ // 1. do codegen if ancestors really needs codegen.
+ // 2. become non-speculative if siblings are not speculative
+
+ TemplateInstance *tnext = this->tnext;
+ TemplateInstance *tinst = this->tinst;
+ // At first, disconnect chain first to prevent infinite recursion.
+ this->tnext = NULL;
+ this->tinst = NULL;
+
+ // Determine necessity of tinst before tnext.
+ if (tinst && tinst->needsCodegen())
+ {
+ minst = tinst->minst; // cache result
+ assert(minst);
+ assert(minst->isRoot() || minst->rootImports());
+ return true;
+ }
+ if (tnext && (tnext->needsCodegen() || tnext->minst))
+ {
+ minst = tnext->minst; // cache result
+ assert(minst);
+ return minst->isRoot() || minst->rootImports();
+ }
+
+ // Elide codegen because this is really speculative.
+ return false;
+ }
+
+ /* Even when this is reached to the codegen pass,
+ * a non-root nested template should not generate code,
+ * due to avoid ODR violation.
+ */
+ if (enclosing && enclosing->inNonRoot())
+ {
+ if (tinst)
+ {
+ bool r = tinst->needsCodegen();
+ minst = tinst->minst; // cache result
+ return r;
+ }
+ if (tnext)
+ {
+ bool r = tnext->needsCodegen();
+ minst = tnext->minst; // cache result
+ return r;
+ }
+ return false;
+ }
+
+ /* The issue is that if the importee is compiled with a different -debug
+ * setting than the importer, the importer may believe it exists
+ * in the compiled importee when it does not, when the instantiation
+ * is behind a conditional debug declaration.
+ */
+ // workaround for Bugzilla 11239
+ if (global.params.useUnitTests ||
+ global.params.debuglevel)
+ {
+ // Prefer instantiations from root modules, to maximize link-ability.
+ if (minst->isRoot())
+ return true;
+
+ TemplateInstance *tnext = this->tnext;
+ TemplateInstance *tinst = this->tinst;
+ this->tnext = NULL;
+ this->tinst = NULL;
+
+ if (tinst && tinst->needsCodegen())
+ {
+ minst = tinst->minst; // cache result
+ assert(minst);
+ assert(minst->isRoot() || minst->rootImports());
+ return true;
+ }
+ if (tnext && tnext->needsCodegen())
+ {
+ minst = tnext->minst; // cache result
+ assert(minst);
+ assert(minst->isRoot() || minst->rootImports());
+ return true;
+ }
+
+ // Bugzilla 2500 case
+ if (minst->rootImports())
+ return true;
+
+ // Elide codegen because this is not included in root instances.
+ return false;
+ }
+ else
+ {
+ // Prefer instantiations from non-root module, to minimize object code size.
+
+ /* If a TemplateInstance is ever instantiated by non-root modules,
+ * we do not have to generate code for it,
+ * because it will be generated when the non-root module is compiled.
+ *
+ * But, if the non-root 'minst' imports any root modules, it might still need codegen.
+ *
+ * The problem is if A imports B, and B imports A, and both A
+ * and B instantiate the same template, does the compilation of A
+ * or the compilation of B do the actual instantiation?
+ *
+ * See Bugzilla 2500.
+ */
+ if (!minst->isRoot() && !minst->rootImports())
+ return false;
+
+ TemplateInstance *tnext = this->tnext;
+ this->tnext = NULL;
+
+ if (tnext && !tnext->needsCodegen() && tnext->minst)
+ {
+ minst = tnext->minst; // cache result
+ assert(!minst->isRoot());
+ return false;
+ }
+
+ // Do codegen because this is not included in non-root instances.
+ return true;
+ }
+}
+
+/* ======================== TemplateMixin ================================ */
+
+TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs)
+ : TemplateInstance(loc, tqual->idents.dim ? (Identifier *)tqual->idents[tqual->idents.dim - 1]
+ : ((TypeIdentifier *)tqual)->ident)
+{
+ //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : "");
+ this->ident = ident;
+ this->tqual = tqual;
+ this->tiargs = tiargs ? tiargs : new Objects();
+}
+
+Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *)
+{
+ TemplateMixin *tm = new TemplateMixin(loc, ident,
+ (TypeQualified *)tqual->syntaxCopy(), tiargs);
+ return TemplateInstance::syntaxCopy(tm);
+}
+
+bool TemplateMixin::findTempDecl(Scope *sc)
+{
+ // Follow qualifications to find the TemplateDeclaration
+ if (!tempdecl)
+ {
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ tqual->resolve(loc, sc, &e, &t, &s);
+ if (!s)
+ {
+ error("is not defined");
+ return false;
+ }
+ s = s->toAlias();
+ tempdecl = s->isTemplateDeclaration();
+ OverloadSet *os = s->isOverloadSet();
+
+ /* If an OverloadSet, look for a unique member that is a template declaration
+ */
+ if (os)
+ {
+ Dsymbol *ds = NULL;
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ Dsymbol *s2 = os->a[i]->isTemplateDeclaration();
+ if (s2)
+ {
+ if (ds)
+ {
+ tempdecl = os;
+ break;
+ }
+ ds = s2;
+ }
+ }
+ }
+ if (!tempdecl)
+ {
+ error("%s isn't a template", s->toChars());
+ return false;
+ }
+ }
+ assert(tempdecl);
+
+ struct ParamFwdResTm
+ {
+ static int fp(void *param, Dsymbol *s)
+ {
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (!td)
+ return 0;
+
+ TemplateMixin *tm = (TemplateMixin *)param;
+ if (td->semanticRun == PASSinit)
+ {
+ if (td->_scope)
+ td->semantic(td->_scope);
+ else
+ {
+ tm->semanticRun = PASSinit;
+ return 1;
+ }
+ }
+ return 0;
+ }
+ };
+ // Look for forward references
+ OverloadSet *tovers = tempdecl->isOverloadSet();
+ size_t overs_dim = tovers ? tovers->a.dim : 1;
+ for (size_t oi = 0; oi < overs_dim; oi++)
+ {
+ if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdResTm::fp))
+ return false;
+ }
+ return true;
+}
+
+void TemplateMixin::semantic(Scope *sc)
+{
+ if (semanticRun != PASSinit)
+ {
+ // When a class/struct contains mixin members, and is done over
+ // because of forward references, never reach here so semanticRun
+ // has been reset to PASSinit.
+ return;
+ }
+ semanticRun = PASSsemantic;
+
+ Scope *scx = NULL;
+ if (_scope)
+ {
+ sc = _scope;
+ scx = _scope; // save so we don't make redundant copies
+ _scope = NULL;
+ }
+
+ /* Run semantic on each argument, place results in tiargs[],
+ * then find best match template with tiargs
+ */
+ if (!findTempDecl(sc) ||
+ !semanticTiargs(sc) ||
+ !findBestMatch(sc, NULL))
+ {
+ if (semanticRun == PASSinit) // forward reference had occured
+ {
+ //printf("forward reference - deferring\n");
+ _scope = scx ? scx : sc->copy();
+ _scope->setNoFree();
+ _scope->_module->addDeferredSemantic(this);
+ return;
+ }
+
+ inst = this;
+ errors = true;
+ return; // error recovery
+ }
+ TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
+ assert(tempdecl);
+
+ if (!ident)
+ {
+ /* Assign scope local unique identifier, as same as lambdas.
+ */
+ const char *s = "__mixin";
+
+ DsymbolTable *symtab;
+ if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
+ {
+ symtab = func->localsymtab;
+ if (symtab)
+ {
+ // Inside template constraint, symtab is not set yet.
+ goto L1;
+ }
+ }
+ else
+ {
+ symtab = sc->parent->isScopeDsymbol()->symtab;
+ L1:
+ assert(symtab);
+ int num = (int)dmd_aaLen(symtab->tab) + 1;
+ ident = Identifier::generateId(s, num);
+ symtab->insert(this);
+ }
+ }
+
+ inst = this;
+ parent = sc->parent;
+
+ /* Detect recursive mixin instantiations.
+ */
+ for (Dsymbol *s = parent; s; s = s->parent)
+ {
+ //printf("\ts = '%s'\n", s->toChars());
+ TemplateMixin *tm = s->isTemplateMixin();
+ if (!tm || tempdecl != tm->tempdecl)
+ continue;
+
+ /* Different argument list lengths happen with variadic args
+ */
+ if (tiargs->dim != tm->tiargs->dim)
+ continue;
+
+ for (size_t i = 0; i < tiargs->dim; i++)
+ {
+ RootObject *o = (*tiargs)[i];
+ Type *ta = isType(o);
+ Expression *ea = isExpression(o);
+ Dsymbol *sa = isDsymbol(o);
+ RootObject *tmo = (*tm->tiargs)[i];
+ if (ta)
+ {
+ Type *tmta = isType(tmo);
+ if (!tmta)
+ goto Lcontinue;
+ if (!ta->equals(tmta))
+ goto Lcontinue;
+ }
+ else if (ea)
+ {
+ Expression *tme = isExpression(tmo);
+ if (!tme || !ea->equals(tme))
+ goto Lcontinue;
+ }
+ else if (sa)
+ {
+ Dsymbol *tmsa = isDsymbol(tmo);
+ if (sa != tmsa)
+ goto Lcontinue;
+ }
+ else
+ assert(0);
+ }
+ error("recursive mixin instantiation");
+ return;
+
+ Lcontinue:
+ continue;
+ }
+
+ // Copy the syntax trees from the TemplateDeclaration
+ members = Dsymbol::arraySyntaxCopy(tempdecl->members);
+ if (!members)
+ return;
+
+ symtab = new DsymbolTable();
+
+ for (Scope *sce = sc; 1; sce = sce->enclosing)
+ {
+ ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
+ if (sds)
+ {
+ sds->importScope(this, Prot(PROTpublic));
+ break;
+ }
+ }
+
+ Scope *scy = sc->push(this);
+ scy->parent = this;
+
+ argsym = new ScopeDsymbol();
+ argsym->parent = scy->parent;
+ Scope *argscope = scy->push(argsym);
+
+ unsigned errorsave = global.errors;
+
+ // Declare each template parameter as an alias for the argument type
+ declareParameters(argscope);
+
+ // Add members to enclosing scope, as well as this scope
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->addMember(argscope, this);
+ //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym);
+ //printf("s->parent = %s\n", s->parent->toChars());
+ }
+
+ // Do semantic() analysis on template instance members
+ Scope *sc2 = argscope->push(this);
+ //size_t deferred_dim = Module::deferred.dim;
+
+ static int nest;
+ //printf("%d\n", nest);
+ if (++nest > 500)
+ {
+ global.gag = 0; // ensure error message gets printed
+ error("recursive expansion");
+ fatal();
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->setScope(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->importAll(sc2);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic(sc2);
+ }
+
+ nest--;
+
+ /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols.
+ * Because the members would already call Module::addDeferredSemantic() for themselves.
+ * See Struct, Class, Interface, and EnumDeclaration::semantic().
+ */
+ //if (!sc->func && Module::deferred.dim > deferred_dim) {}
+
+ AggregateDeclaration *ad = toParent()->isAggregateDeclaration();
+ if (sc->func && !ad)
+ {
+ semantic2(sc2);
+ semantic3(sc2);
+ }
+
+ // Give additional context info if error occurred during instantiation
+ if (global.errors != errorsave)
+ {
+ error("error instantiating");
+ errors = true;
+ }
+
+ sc2->pop();
+ argscope->pop();
+ scy->pop();
+}
+
+void TemplateMixin::semantic2(Scope *sc)
+{
+ if (semanticRun >= PASSsemantic2)
+ return;
+ semanticRun = PASSsemantic2;
+ if (members)
+ {
+ assert(sc);
+ sc = sc->push(argsym);
+ sc = sc->push(this);
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic2(sc);
+ }
+ sc = sc->pop();
+ sc->pop();
+ }
+}
+
+void TemplateMixin::semantic3(Scope *sc)
+{
+ if (semanticRun >= PASSsemantic3)
+ return;
+ semanticRun = PASSsemantic3;
+ if (members)
+ {
+ sc = sc->push(argsym);
+ sc = sc->push(this);
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic3(sc);
+ }
+ sc = sc->pop();
+ sc->pop();
+ }
+}
+
+const char *TemplateMixin::kind()
+{
+ return "mixin";
+}
+
+bool TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident)
+{
+ return Dsymbol::oneMember(ps, ident);
+}
+
+int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+ if (_scope) // if fwd reference
+ semantic(NULL); // try to resolve it
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ if (s)
+ {
+ if (s->apply(fp, param))
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+bool TemplateMixin::hasPointers()
+{
+ //printf("TemplateMixin::hasPointers() %s\n", toChars());
+
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf(" s = %s %s\n", s->kind(), s->toChars());
+ if (s->hasPointers())
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+ //printf("TemplateMixin::setFieldOffset() %s\n", toChars());
+ if (_scope) // if fwd reference
+ semantic(NULL); // try to resolve it
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("\t%s\n", s->toChars());
+ s->setFieldOffset(ad, poffset, isunion);
+ }
+ }
+}
+
+const char *TemplateMixin::toChars()
+{
+ OutBuffer buf;
+ toCBufferInstance(this, &buf);
+ return buf.extractString();
+}
diff --git a/gcc/d/dmd/dversion.c b/gcc/d/dmd/dversion.c
new file mode 100644
index 0000000..4737486
--- /dev/null
+++ b/gcc/d/dmd/dversion.c
@@ -0,0 +1,202 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/version.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "root/root.h"
+
+#include "identifier.h"
+#include "dsymbol.h"
+#include "cond.h"
+#include "version.h"
+#include "module.h"
+
+void checkReserved(Loc loc, const char *ident);
+
+/* ================================================== */
+
+/* DebugSymbol's happen for statements like:
+ * debug = identifier;
+ * debug = integer;
+ */
+
+DebugSymbol::DebugSymbol(Loc loc, Identifier *ident)
+ : Dsymbol(ident)
+{
+ this->loc = loc;
+}
+
+DebugSymbol::DebugSymbol(Loc loc, unsigned level)
+ : Dsymbol()
+{
+ this->level = level;
+ this->loc = loc;
+}
+
+const char *DebugSymbol::toChars()
+{
+ if (ident)
+ return ident->toChars();
+ else
+ {
+ OutBuffer buf;
+ buf.printf("%d", level);
+ return buf.extractString();
+ }
+}
+
+Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ DebugSymbol *ds = new DebugSymbol(loc, ident);
+ ds->level = level;
+ return ds;
+}
+
+void DebugSymbol::addMember(Scope *, ScopeDsymbol *sds)
+{
+ //printf("DebugSymbol::addMember('%s') %s\n", sds->toChars(), toChars());
+ Module *m = sds->isModule();
+
+ // Do not add the member to the symbol table,
+ // just make sure subsequent debug declarations work.
+ if (ident)
+ {
+ if (!m)
+ {
+ error("declaration must be at module level");
+ errors = true;
+ }
+ else
+ {
+ if (findCondition(m->debugidsNot, ident))
+ {
+ error("defined after use");
+ errors = true;
+ }
+ if (!m->debugids)
+ m->debugids = new Strings();
+ m->debugids->push(ident->toChars());
+ }
+ }
+ else
+ {
+ if (!m)
+ {
+ error("level declaration must be at module level");
+ errors = true;
+ }
+ else
+ m->debuglevel = level;
+ }
+}
+
+void DebugSymbol::semantic(Scope *)
+{
+ //printf("DebugSymbol::semantic() %s\n", toChars());
+ if (semanticRun < PASSsemanticdone)
+ semanticRun = PASSsemanticdone;
+}
+
+const char *DebugSymbol::kind()
+{
+ return "debug";
+}
+
+/* ================================================== */
+
+/* VersionSymbol's happen for statements like:
+ * version = identifier;
+ * version = integer;
+ */
+
+VersionSymbol::VersionSymbol(Loc loc, Identifier *ident)
+ : Dsymbol(ident)
+{
+ this->loc = loc;
+}
+
+VersionSymbol::VersionSymbol(Loc loc, unsigned level)
+ : Dsymbol()
+{
+ this->level = level;
+ this->loc = loc;
+}
+
+const char *VersionSymbol::toChars()
+{
+ if (ident)
+ return ident->toChars();
+ else
+ {
+ OutBuffer buf;
+ buf.printf("%d", level);
+ return buf.extractString();
+ }
+}
+
+Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ VersionSymbol *ds = ident ? new VersionSymbol(loc, ident)
+ : new VersionSymbol(loc, level);
+ return ds;
+}
+
+void VersionSymbol::addMember(Scope *, ScopeDsymbol *sds)
+{
+ //printf("VersionSymbol::addMember('%s') %s\n", sds->toChars(), toChars());
+ Module *m = sds->isModule();
+
+ // Do not add the member to the symbol table,
+ // just make sure subsequent debug declarations work.
+ if (ident)
+ {
+ checkReserved(loc, ident->toChars());
+ if (!m)
+ {
+ error("declaration must be at module level");
+ errors = true;
+ }
+ else
+ {
+ if (findCondition(m->versionidsNot, ident))
+ {
+ error("defined after use");
+ errors = true;
+ }
+ if (!m->versionids)
+ m->versionids = new Strings();
+ m->versionids->push(ident->toChars());
+ }
+ }
+ else
+ {
+ if (!m)
+ {
+ error("level declaration must be at module level");
+ errors = true;
+ }
+ else
+ m->versionlevel = level;
+ }
+}
+
+void VersionSymbol::semantic(Scope *)
+{
+ if (semanticRun < PASSsemanticdone)
+ semanticRun = PASSsemanticdone;
+}
+
+const char *VersionSymbol::kind()
+{
+ return "version";
+}
diff --git a/gcc/d/dmd/entity.c b/gcc/d/dmd/entity.c
new file mode 100644
index 0000000..38fd2d8
--- /dev/null
+++ b/gcc/d/dmd/entity.c
@@ -0,0 +1,2392 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/entity.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "root/port.h"
+
+/*********************************************
+ * Convert from named entity to its encoding.
+ * For reference:
+ * http://www.htmlhelp.com/reference/html40/entities/
+ * http://www.w3.org/2003/entities/2007/w3centities-f.ent
+ */
+
+struct NameId
+{
+ const char *name;
+ unsigned value;
+};
+
+static NameId namesA[]={
+ {"Aacgr", 0x00386}, // GREEK CAPITAL LETTER ALPHA WITH TONOS
+ {"aacgr", 0x003AC}, // GREEK SMALL LETTER ALPHA WITH TONOS
+ {"Aacute", 0x000C1}, // LATIN CAPITAL LETTER A WITH ACUTE
+ {"aacute", 0x000E1}, // LATIN SMALL LETTER A WITH ACUTE
+ {"Abreve", 0x00102}, // LATIN CAPITAL LETTER A WITH BREVE
+ {"abreve", 0x00103}, // LATIN SMALL LETTER A WITH BREVE
+ {"ac", 0x0223E}, // INVERTED LAZY S
+ {"acd", 0x0223F}, // SINE WAVE
+// {"acE", 0x0223E;0x00333}, // INVERTED LAZY S with double underline
+ {"Acirc", 0x000C2}, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ {"acirc", 0x000E2}, // LATIN SMALL LETTER A WITH CIRCUMFLEX
+ {"acute", 0x000B4}, // ACUTE ACCENT
+ {"Acy", 0x00410}, // CYRILLIC CAPITAL LETTER A
+ {"acy", 0x00430}, // CYRILLIC SMALL LETTER A
+ {"AElig", 0x000C6}, // LATIN CAPITAL LETTER AE
+ {"aelig", 0x000E6}, // LATIN SMALL LETTER AE
+ {"af", 0x02061}, // FUNCTION APPLICATION
+ {"Afr", 0x1D504}, // MATHEMATICAL FRAKTUR CAPITAL A
+ {"afr", 0x1D51E}, // MATHEMATICAL FRAKTUR SMALL A
+ {"Agr", 0x00391}, // GREEK CAPITAL LETTER ALPHA
+ {"agr", 0x003B1}, // GREEK SMALL LETTER ALPHA
+ {"Agrave", 0x000C0}, // LATIN CAPITAL LETTER A WITH GRAVE
+ {"agrave", 0x000E0}, // LATIN SMALL LETTER A WITH GRAVE
+ {"alefsym", 0x02135}, // ALEF SYMBOL
+ {"aleph", 0x02135}, // ALEF SYMBOL
+ {"Alpha", 0x00391}, // GREEK CAPITAL LETTER ALPHA
+ {"alpha", 0x003B1}, // GREEK SMALL LETTER ALPHA
+ {"Amacr", 0x00100}, // LATIN CAPITAL LETTER A WITH MACRON
+ {"amacr", 0x00101}, // LATIN SMALL LETTER A WITH MACRON
+ {"amalg", 0x02A3F}, // AMALGAMATION OR COPRODUCT
+ {"amp", 0x00026}, // AMPERSAND
+ {"AMP", 0x00026}, // AMPERSAND
+ {"and", 0x02227}, // LOGICAL AND
+ {"And", 0x02A53}, // DOUBLE LOGICAL AND
+ {"andand", 0x02A55}, // TWO INTERSECTING LOGICAL AND
+ {"andd", 0x02A5C}, // LOGICAL AND WITH HORIZONTAL DASH
+ {"andslope", 0x02A58}, // SLOPING LARGE AND
+ {"andv", 0x02A5A}, // LOGICAL AND WITH MIDDLE STEM
+ {"ang", 0x02220}, // ANGLE
+ {"ange", 0x029A4}, // ANGLE WITH UNDERBAR
+ {"angle", 0x02220}, // ANGLE
+ {"angmsd", 0x02221}, // MEASURED ANGLE
+ {"angmsdaa", 0x029A8}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT
+ {"angmsdab", 0x029A9}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT
+ {"angmsdac", 0x029AA}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT
+ {"angmsdad", 0x029AB}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT
+ {"angmsdae", 0x029AC}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP
+ {"angmsdaf", 0x029AD}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP
+ {"angmsdag", 0x029AE}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN
+ {"angmsdah", 0x029AF}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN
+ {"angrt", 0x0221F}, // RIGHT ANGLE
+ {"angrtvb", 0x022BE}, // RIGHT ANGLE WITH ARC
+ {"angrtvbd", 0x0299D}, // MEASURED RIGHT ANGLE WITH DOT
+ {"angsph", 0x02222}, // SPHERICAL ANGLE
+ {"angst", 0x000C5}, // LATIN CAPITAL LETTER A WITH RING ABOVE
+ {"angzarr", 0x0237C}, // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+ {"Aogon", 0x00104}, // LATIN CAPITAL LETTER A WITH OGONEK
+ {"aogon", 0x00105}, // LATIN SMALL LETTER A WITH OGONEK
+ {"Aopf", 0x1D538}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL A
+ {"aopf", 0x1D552}, // MATHEMATICAL DOUBLE-STRUCK SMALL A
+ {"ap", 0x02248}, // ALMOST EQUAL TO
+ {"apacir", 0x02A6F}, // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT
+ {"ape", 0x0224A}, // ALMOST EQUAL OR EQUAL TO
+ {"apE", 0x02A70}, // APPROXIMATELY EQUAL OR EQUAL TO
+ {"apid", 0x0224B}, // TRIPLE TILDE
+ {"apos", 0x00027}, // APOSTROPHE
+ {"ApplyFunction", 0x02061}, // FUNCTION APPLICATION
+ {"approx", 0x02248}, // ALMOST EQUAL TO
+ {"approxeq", 0x0224A}, // ALMOST EQUAL OR EQUAL TO
+ {"Aring", 0x000C5}, // LATIN CAPITAL LETTER A WITH RING ABOVE
+ {"aring", 0x000E5}, // LATIN SMALL LETTER A WITH RING ABOVE
+ {"Ascr", 0x1D49C}, // MATHEMATICAL SCRIPT CAPITAL A
+ {"ascr", 0x1D4B6}, // MATHEMATICAL SCRIPT SMALL A
+ {"Assign", 0x02254}, // COLON EQUALS
+ {"ast", 0x0002A}, // ASTERISK
+ {"asymp", 0x02248}, // ALMOST EQUAL TO
+ {"asympeq", 0x0224D}, // EQUIVALENT TO
+ {"Atilde", 0x000C3}, // LATIN CAPITAL LETTER A WITH TILDE
+ {"atilde", 0x000E3}, // LATIN SMALL LETTER A WITH TILDE
+ {"Auml", 0x000C4}, // LATIN CAPITAL LETTER A WITH DIAERESIS
+ {"auml", 0x000E4}, // LATIN SMALL LETTER A WITH DIAERESIS
+ {"awconint", 0x02233}, // ANTICLOCKWISE CONTOUR INTEGRAL
+ {"awint", 0x02A11}, // ANTICLOCKWISE INTEGRATION
+ {NULL, 0}
+};
+
+static NameId namesB[]={
+ {"backcong", 0x0224C}, // ALL EQUAL TO
+ {"backepsilon", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL
+ {"backprime", 0x02035}, // REVERSED PRIME
+ {"backsim", 0x0223D}, // REVERSED TILDE
+ {"backsimeq", 0x022CD}, // REVERSED TILDE EQUALS
+ {"Backslash", 0x02216}, // SET MINUS
+// "b.alpha", 0x1D6C2}, // MATHEMATICAL BOLD SMALL ALPHA
+ {"Barv", 0x02AE7}, // SHORT DOWN TACK WITH OVERBAR
+ {"barvee", 0x022BD}, // NOR
+ {"barwed", 0x02305}, // PROJECTIVE
+ {"Barwed", 0x02306}, // PERSPECTIVE
+ {"barwedge", 0x02305}, // PROJECTIVE
+// "b.beta", 0x1D6C3}, // MATHEMATICAL BOLD SMALL BETA
+ {"bbrk", 0x023B5}, // BOTTOM SQUARE BRACKET
+ {"bbrktbrk", 0x023B6}, // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET
+// "b.chi", 0x1D6D8}, // MATHEMATICAL BOLD SMALL CHI
+ {"bcong", 0x0224C}, // ALL EQUAL TO
+ {"Bcy", 0x00411}, // CYRILLIC CAPITAL LETTER BE
+ {"bcy", 0x00431}, // CYRILLIC SMALL LETTER BE
+// "b.Delta", 0x1D6AB}, // MATHEMATICAL BOLD CAPITAL DELTA
+// "b.delta", 0x1D6C5}, // MATHEMATICAL BOLD SMALL DELTA
+ {"bdquo", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK
+ {"becaus", 0x02235}, // BECAUSE
+ {"because", 0x02235}, // BECAUSE
+ {"Because", 0x02235}, // BECAUSE
+ {"bemptyv", 0x029B0}, // REVERSED EMPTY SET
+ {"bepsi", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL
+// "b.epsi", 0x1D6C6}, // MATHEMATICAL BOLD SMALL EPSILON
+// "b.epsiv", 0x1D6DC}, // MATHEMATICAL BOLD EPSILON SYMBOL
+ {"bernou", 0x0212C}, // SCRIPT CAPITAL B
+ {"Bernoullis", 0x0212C}, // SCRIPT CAPITAL B
+ {"Beta", 0x00392}, // GREEK CAPITAL LETTER BETA
+ {"beta", 0x003B2}, // GREEK SMALL LETTER BETA
+// "b.eta", 0x1D6C8}, // MATHEMATICAL BOLD SMALL ETA
+ {"beth", 0x02136}, // BET SYMBOL
+ {"between", 0x0226C}, // BETWEEN
+ {"Bfr", 0x1D505}, // MATHEMATICAL FRAKTUR CAPITAL B
+ {"bfr", 0x1D51F}, // MATHEMATICAL FRAKTUR SMALL B
+// "b.Gamma", 0x1D6AA}, // MATHEMATICAL BOLD CAPITAL GAMMA
+// "b.gamma", 0x1D6C4}, // MATHEMATICAL BOLD SMALL GAMMA
+// "b.Gammad", 0x1D7CA}, // MATHEMATICAL BOLD CAPITAL DIGAMMA
+// "b.gammad", 0x1D7CB}, // MATHEMATICAL BOLD SMALL DIGAMMA
+ {"Bgr", 0x00392}, // GREEK CAPITAL LETTER BETA
+ {"bgr", 0x003B2}, // GREEK SMALL LETTER BETA
+ {"bigcap", 0x022C2}, // N-ARY INTERSECTION
+ {"bigcirc", 0x025EF}, // LARGE CIRCLE
+ {"bigcup", 0x022C3}, // N-ARY UNION
+ {"bigodot", 0x02A00}, // N-ARY CIRCLED DOT OPERATOR
+ {"bigoplus", 0x02A01}, // N-ARY CIRCLED PLUS OPERATOR
+ {"bigotimes", 0x02A02}, // N-ARY CIRCLED TIMES OPERATOR
+ {"bigsqcup", 0x02A06}, // N-ARY SQUARE UNION OPERATOR
+ {"bigstar", 0x02605}, // BLACK STAR
+ {"bigtriangledown", 0x025BD}, // WHITE DOWN-POINTING TRIANGLE
+ {"bigtriangleup", 0x025B3}, // WHITE UP-POINTING TRIANGLE
+ {"biguplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS
+ {"bigvee", 0x022C1}, // N-ARY LOGICAL OR
+ {"bigwedge", 0x022C0}, // N-ARY LOGICAL AND
+// "b.iota", 0x1D6CA}, // MATHEMATICAL BOLD SMALL IOTA
+// "b.kappa", 0x1D6CB}, // MATHEMATICAL BOLD SMALL KAPPA
+// "b.kappav", 0x1D6DE}, // MATHEMATICAL BOLD KAPPA SYMBOL
+ {"bkarow", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW
+ {"blacklozenge", 0x029EB}, // BLACK LOZENGE
+ {"blacksquare", 0x025AA}, // BLACK SMALL SQUARE
+ {"blacktriangle", 0x025B4}, // BLACK UP-POINTING SMALL TRIANGLE
+ {"blacktriangledown", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE
+ {"blacktriangleleft", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE
+ {"blacktriangleright", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE
+// "b.Lambda", 0x1D6B2}, // MATHEMATICAL BOLD CAPITAL LAMDA
+// "b.lambda", 0x1D6CC}, // MATHEMATICAL BOLD SMALL LAMDA
+ {"blank", 0x02423}, // OPEN BOX
+ {"blk12", 0x02592}, // MEDIUM SHADE
+ {"blk14", 0x02591}, // LIGHT SHADE
+ {"blk34", 0x02593}, // DARK SHADE
+ {"block", 0x02588}, // FULL BLOCK
+// "b.mu", 0x1D6CD}, // MATHEMATICAL BOLD SMALL MU
+// "bne", 0x0003D;0x020E5}, // EQUALS SIGN with reverse slash
+// "bnequiv", 0x02261;0x020E5}, // IDENTICAL TO with reverse slash
+ {"bnot", 0x02310}, // REVERSED NOT SIGN
+ {"bNot", 0x02AED}, // REVERSED DOUBLE STROKE NOT SIGN
+// "b.nu", 0x1D6CE}, // MATHEMATICAL BOLD SMALL NU
+// "b.Omega", 0x1D6C0}, // MATHEMATICAL BOLD CAPITAL OMEGA
+// "b.omega", 0x1D6DA}, // MATHEMATICAL BOLD SMALL OMEGA
+ {"Bopf", 0x1D539}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+ {"bopf", 0x1D553}, // MATHEMATICAL DOUBLE-STRUCK SMALL B
+ {"bot", 0x022A5}, // UP TACK
+ {"bottom", 0x022A5}, // UP TACK
+ {"bowtie", 0x022C8}, // BOWTIE
+ {"boxbox", 0x029C9}, // TWO JOINED SQUARES
+ {"boxdl", 0x02510}, // BOX DRAWINGS LIGHT DOWN AND LEFT
+ {"boxdL", 0x02555}, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ {"boxDl", 0x02556}, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ {"boxDL", 0x02557}, // BOX DRAWINGS DOUBLE DOWN AND LEFT
+ {"boxdr", 0x0250C}, // BOX DRAWINGS LIGHT DOWN AND RIGHT
+ {"boxdR", 0x02552}, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ {"boxDr", 0x02553}, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ {"boxDR", 0x02554}, // BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ {"boxh", 0x02500}, // BOX DRAWINGS LIGHT HORIZONTAL
+ {"boxH", 0x02550}, // BOX DRAWINGS DOUBLE HORIZONTAL
+ {"boxhd", 0x0252C}, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ {"boxHd", 0x02564}, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ {"boxhD", 0x02565}, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ {"boxHD", 0x02566}, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ {"boxhu", 0x02534}, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ {"boxHu", 0x02567}, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ {"boxhU", 0x02568}, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ {"boxHU", 0x02569}, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ {"boxminus", 0x0229F}, // SQUARED MINUS
+ {"boxplus", 0x0229E}, // SQUARED PLUS
+ {"boxtimes", 0x022A0}, // SQUARED TIMES
+ {"boxul", 0x02518}, // BOX DRAWINGS LIGHT UP AND LEFT
+ {"boxuL", 0x0255B}, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ {"boxUl", 0x0255C}, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ {"boxUL", 0x0255D}, // BOX DRAWINGS DOUBLE UP AND LEFT
+ {"boxur", 0x02514}, // BOX DRAWINGS LIGHT UP AND RIGHT
+ {"boxuR", 0x02558}, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ {"boxUr", 0x02559}, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ {"boxUR", 0x0255A}, // BOX DRAWINGS DOUBLE UP AND RIGHT
+ {"boxv", 0x02502}, // BOX DRAWINGS LIGHT VERTICAL
+ {"boxV", 0x02551}, // BOX DRAWINGS DOUBLE VERTICAL
+ {"boxvh", 0x0253C}, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ {"boxvH", 0x0256A}, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ {"boxVh", 0x0256B}, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ {"boxVH", 0x0256C}, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ {"boxvl", 0x02524}, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ {"boxvL", 0x02561}, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ {"boxVl", 0x02562}, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ {"boxVL", 0x02563}, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ {"boxvr", 0x0251C}, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ {"boxvR", 0x0255E}, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ {"boxVr", 0x0255F}, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ {"boxVR", 0x02560}, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+// "b.Phi", 0x1D6BD}, // MATHEMATICAL BOLD CAPITAL PHI
+// "b.phi", 0x1D6D7}, // MATHEMATICAL BOLD SMALL PHI
+// "b.phiv", 0x1D6DF}, // MATHEMATICAL BOLD PHI SYMBOL
+// "b.Pi", 0x1D6B7}, // MATHEMATICAL BOLD CAPITAL PI
+// "b.pi", 0x1D6D1}, // MATHEMATICAL BOLD SMALL PI
+// "b.piv", 0x1D6E1}, // MATHEMATICAL BOLD PI SYMBOL
+ {"bprime", 0x02035}, // REVERSED PRIME
+// "b.Psi", 0x1D6BF}, // MATHEMATICAL BOLD CAPITAL PSI
+// "b.psi", 0x1D6D9}, // MATHEMATICAL BOLD SMALL PSI
+ {"breve", 0x002D8}, // BREVE
+ {"Breve", 0x002D8}, // BREVE
+// "b.rho", 0x1D6D2}, // MATHEMATICAL BOLD SMALL RHO
+// "b.rhov", 0x1D6E0}, // MATHEMATICAL BOLD RHO SYMBOL
+ {"brvbar", 0x000A6}, // BROKEN BAR
+ {"Bscr", 0x0212C}, // SCRIPT CAPITAL B
+ {"bscr", 0x1D4B7}, // MATHEMATICAL SCRIPT SMALL B
+ {"bsemi", 0x0204F}, // REVERSED SEMICOLON
+// "b.Sigma", 0x1D6BA}, // MATHEMATICAL BOLD CAPITAL SIGMA
+// "b.sigma", 0x1D6D4}, // MATHEMATICAL BOLD SMALL SIGMA
+// "b.sigmav", 0x1D6D3}, // MATHEMATICAL BOLD SMALL FINAL SIGMA
+ {"bsim", 0x0223D}, // REVERSED TILDE
+ {"bsime", 0x022CD}, // REVERSED TILDE EQUALS
+ {"bsol", 0x0005C}, // REVERSE SOLIDUS
+ {"bsolb", 0x029C5}, // SQUARED FALLING DIAGONAL SLASH
+ {"bsolhsub", 0x027C8}, // REVERSE SOLIDUS PRECEDING SUBSET
+// "b.tau", 0x1D6D5}, // MATHEMATICAL BOLD SMALL TAU
+// "b.Theta", 0x1D6AF}, // MATHEMATICAL BOLD CAPITAL THETA
+// "b.thetas", 0x1D6C9}, // MATHEMATICAL BOLD SMALL THETA
+// "b.thetav", 0x1D6DD}, // MATHEMATICAL BOLD THETA SYMBOL
+ {"bull", 0x02022}, // BULLET
+ {"bullet", 0x02022}, // BULLET
+ {"bump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
+ {"bumpe", 0x0224F}, // DIFFERENCE BETWEEN
+ {"bumpE", 0x02AAE}, // EQUALS SIGN WITH BUMPY ABOVE
+ {"Bumpeq", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
+ {"bumpeq", 0x0224F}, // DIFFERENCE BETWEEN
+// "b.Upsi", 0x1D6BC}, // MATHEMATICAL BOLD CAPITAL UPSILON
+// "b.upsi", 0x1D6D6}, // MATHEMATICAL BOLD SMALL UPSILON
+// "b.Xi", 0x1D6B5}, // MATHEMATICAL BOLD CAPITAL XI
+// "b.xi", 0x1D6CF}, // MATHEMATICAL BOLD SMALL XI
+// "b.zeta", 0x1D6C7}, // MATHEMATICAL BOLD SMALL ZETA
+ {NULL, 0}
+};
+
+static NameId namesC[]={
+ {"Cacute", 0x00106}, // LATIN CAPITAL LETTER C WITH ACUTE
+ {"cacute", 0x00107}, // LATIN SMALL LETTER C WITH ACUTE
+ {"cap", 0x02229}, // INTERSECTION
+ {"Cap", 0x022D2}, // DOUBLE INTERSECTION
+ {"capand", 0x02A44}, // INTERSECTION WITH LOGICAL AND
+ {"capbrcup", 0x02A49}, // INTERSECTION ABOVE BAR ABOVE UNION
+ {"capcap", 0x02A4B}, // INTERSECTION BESIDE AND JOINED WITH INTERSECTION
+ {"capcup", 0x02A47}, // INTERSECTION ABOVE UNION
+ {"capdot", 0x02A40}, // INTERSECTION WITH DOT
+ {"CapitalDifferentialD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D
+// "caps", 0x02229;0x0FE00}, // INTERSECTION with serifs
+ {"caret", 0x02041}, // CARET INSERTION POINT
+ {"caron", 0x002C7}, // CARON
+ {"Cayleys", 0x0212D}, // BLACK-LETTER CAPITAL C
+ {"ccaps", 0x02A4D}, // CLOSED INTERSECTION WITH SERIFS
+ {"Ccaron", 0x0010C}, // LATIN CAPITAL LETTER C WITH CARON
+ {"ccaron", 0x0010D}, // LATIN SMALL LETTER C WITH CARON
+ {"Ccedil", 0x000C7}, // LATIN CAPITAL LETTER C WITH CEDILLA
+ {"ccedil", 0x000E7}, // LATIN SMALL LETTER C WITH CEDILLA
+ {"Ccirc", 0x00108}, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+ {"ccirc", 0x00109}, // LATIN SMALL LETTER C WITH CIRCUMFLEX
+ {"Cconint", 0x02230}, // VOLUME INTEGRAL
+ {"ccups", 0x02A4C}, // CLOSED UNION WITH SERIFS
+ {"ccupssm", 0x02A50}, // CLOSED UNION WITH SERIFS AND SMASH PRODUCT
+ {"Cdot", 0x0010A}, // LATIN CAPITAL LETTER C WITH DOT ABOVE
+ {"cdot", 0x0010B}, // LATIN SMALL LETTER C WITH DOT ABOVE
+ {"cedil", 0x000B8}, // CEDILLA
+ {"Cedilla", 0x000B8}, // CEDILLA
+ {"cemptyv", 0x029B2}, // EMPTY SET WITH SMALL CIRCLE ABOVE
+ {"cent", 0x000A2}, // CENT SIGN
+ {"centerdot", 0x000B7}, // MIDDLE DOT
+ {"CenterDot", 0x000B7}, // MIDDLE DOT
+ {"Cfr", 0x0212D}, // BLACK-LETTER CAPITAL C
+ {"cfr", 0x1D520}, // MATHEMATICAL FRAKTUR SMALL C
+ {"CHcy", 0x00427}, // CYRILLIC CAPITAL LETTER CHE
+ {"chcy", 0x00447}, // CYRILLIC SMALL LETTER CHE
+ {"check", 0x02713}, // CHECK MARK
+ {"checkmark", 0x02713}, // CHECK MARK
+ {"Chi", 0x003A7}, // GREEK CAPITAL LETTER CHI
+ {"chi", 0x003C7}, // GREEK SMALL LETTER CHI
+ {"cir", 0x025CB}, // WHITE CIRCLE
+ {"circ", 0x002C6}, // MODIFIER LETTER CIRCUMFLEX ACCENT
+ {"circeq", 0x02257}, // RING EQUAL TO
+ {"circlearrowleft", 0x021BA}, // ANTICLOCKWISE OPEN CIRCLE ARROW
+ {"circlearrowright", 0x021BB}, // CLOCKWISE OPEN CIRCLE ARROW
+ {"circledast", 0x0229B}, // CIRCLED ASTERISK OPERATOR
+ {"circledcirc", 0x0229A}, // CIRCLED RING OPERATOR
+ {"circleddash", 0x0229D}, // CIRCLED DASH
+ {"CircleDot", 0x02299}, // CIRCLED DOT OPERATOR
+ {"circledR", 0x000AE}, // REGISTERED SIGN
+ {"circledS", 0x024C8}, // CIRCLED LATIN CAPITAL LETTER S
+ {"CircleMinus", 0x02296}, // CIRCLED MINUS
+ {"CirclePlus", 0x02295}, // CIRCLED PLUS
+ {"CircleTimes", 0x02297}, // CIRCLED TIMES
+ {"cire", 0x02257}, // RING EQUAL TO
+ {"cirE", 0x029C3}, // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT
+ {"cirfnint", 0x02A10}, // CIRCULATION FUNCTION
+ {"cirmid", 0x02AEF}, // VERTICAL LINE WITH CIRCLE ABOVE
+ {"cirscir", 0x029C2}, // CIRCLE WITH SMALL CIRCLE TO THE RIGHT
+ {"ClockwiseContourIntegral", 0x02232}, // CLOCKWISE CONTOUR INTEGRAL
+ {"CloseCurlyDoubleQuote", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
+ {"CloseCurlyQuote", 0x02019}, // RIGHT SINGLE QUOTATION MARK
+ {"clubs", 0x02663}, // BLACK CLUB SUIT
+ {"clubsuit", 0x02663}, // BLACK CLUB SUIT
+ {"colon", 0x0003A}, // COLON
+ {"Colon", 0x02237}, // PROPORTION
+ {"colone", 0x02254}, // COLON EQUALS
+ {"Colone", 0x02A74}, // DOUBLE COLON EQUAL
+ {"coloneq", 0x02254}, // COLON EQUALS
+ {"comma", 0x0002C}, // COMMA
+ {"commat", 0x00040}, // COMMERCIAL AT
+ {"comp", 0x02201}, // COMPLEMENT
+ {"compfn", 0x02218}, // RING OPERATOR
+ {"complement", 0x02201}, // COMPLEMENT
+ {"complexes", 0x02102}, // DOUBLE-STRUCK CAPITAL C
+ {"cong", 0x02245}, // APPROXIMATELY EQUAL TO
+ {"congdot", 0x02A6D}, // CONGRUENT WITH DOT ABOVE
+ {"Congruent", 0x02261}, // IDENTICAL TO
+ {"conint", 0x0222E}, // CONTOUR INTEGRAL
+ {"Conint", 0x0222F}, // SURFACE INTEGRAL
+ {"ContourIntegral", 0x0222E}, // CONTOUR INTEGRAL
+ {"Copf", 0x02102}, // DOUBLE-STRUCK CAPITAL C
+ {"copf", 0x1D554}, // MATHEMATICAL DOUBLE-STRUCK SMALL C
+ {"coprod", 0x02210}, // N-ARY COPRODUCT
+ {"Coproduct", 0x02210}, // N-ARY COPRODUCT
+ {"copy", 0x000A9}, // COPYRIGHT SIGN
+ {"COPY", 0x000A9}, // COPYRIGHT SIGN
+ {"copysr", 0x02117}, // SOUND RECORDING COPYRIGHT
+ {"CounterClockwiseContourIntegral", 0x02233}, // ANTICLOCKWISE CONTOUR INTEGRAL
+ {"crarr", 0x021B5}, // DOWNWARDS ARROW WITH CORNER LEFTWARDS
+ {"cross", 0x02717}, // BALLOT X
+ {"Cross", 0x02A2F}, // VECTOR OR CROSS PRODUCT
+ {"Cscr", 0x1D49E}, // MATHEMATICAL SCRIPT CAPITAL C
+ {"cscr", 0x1D4B8}, // MATHEMATICAL SCRIPT SMALL C
+ {"csub", 0x02ACF}, // CLOSED SUBSET
+ {"csube", 0x02AD1}, // CLOSED SUBSET OR EQUAL TO
+ {"csup", 0x02AD0}, // CLOSED SUPERSET
+ {"csupe", 0x02AD2}, // CLOSED SUPERSET OR EQUAL TO
+ {"ctdot", 0x022EF}, // MIDLINE HORIZONTAL ELLIPSIS
+ {"cudarrl", 0x02938}, // RIGHT-SIDE ARC CLOCKWISE ARROW
+ {"cudarrr", 0x02935}, // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
+ {"cuepr", 0x022DE}, // EQUAL TO OR PRECEDES
+ {"cuesc", 0x022DF}, // EQUAL TO OR SUCCEEDS
+ {"cularr", 0x021B6}, // ANTICLOCKWISE TOP SEMICIRCLE ARROW
+ {"cularrp", 0x0293D}, // TOP ARC ANTICLOCKWISE ARROW WITH PLUS
+ {"cup", 0x0222A}, // UNION
+ {"Cup", 0x022D3}, // DOUBLE UNION
+ {"cupbrcap", 0x02A48}, // UNION ABOVE BAR ABOVE INTERSECTION
+ {"CupCap", 0x0224D}, // EQUIVALENT TO
+ {"cupcap", 0x02A46}, // UNION ABOVE INTERSECTION
+ {"cupcup", 0x02A4A}, // UNION BESIDE AND JOINED WITH UNION
+ {"cupdot", 0x0228D}, // MULTISET MULTIPLICATION
+ {"cupor", 0x02A45}, // UNION WITH LOGICAL OR
+// "cups", 0x0222A;0x0FE00}, // UNION with serifs
+ {"curarr", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW
+ {"curarrm", 0x0293C}, // TOP ARC CLOCKWISE ARROW WITH MINUS
+ {"curlyeqprec", 0x022DE}, // EQUAL TO OR PRECEDES
+ {"curlyeqsucc", 0x022DF}, // EQUAL TO OR SUCCEEDS
+ {"curlyvee", 0x022CE}, // CURLY LOGICAL OR
+ {"curlywedge", 0x022CF}, // CURLY LOGICAL AND
+ {"curren", 0x000A4}, // CURRENCY SIGN
+ {"curvearrowleft", 0x021B6}, // ANTICLOCKWISE TOP SEMICIRCLE ARROW
+ {"curvearrowright", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW
+ {"cuvee", 0x022CE}, // CURLY LOGICAL OR
+ {"cuwed", 0x022CF}, // CURLY LOGICAL AND
+ {"cwconint", 0x02232}, // CLOCKWISE CONTOUR INTEGRAL
+ {"cwint", 0x02231}, // CLOCKWISE INTEGRAL
+ {"cylcty", 0x0232D}, // CYLINDRICITY
+ {NULL, 0}
+};
+
+static NameId namesD[]={
+ {"dagger", 0x02020}, // DAGGER
+ {"Dagger", 0x02021}, // DOUBLE DAGGER
+ {"daleth", 0x02138}, // DALET SYMBOL
+ {"darr", 0x02193}, // DOWNWARDS ARROW
+ {"Darr", 0x021A1}, // DOWNWARDS TWO HEADED ARROW
+ {"dArr", 0x021D3}, // DOWNWARDS DOUBLE ARROW
+ {"dash", 0x02010}, // HYPHEN
+ {"dashv", 0x022A3}, // LEFT TACK
+ {"Dashv", 0x02AE4}, // VERTICAL BAR DOUBLE LEFT TURNSTILE
+ {"dbkarow", 0x0290F}, // RIGHTWARDS TRIPLE DASH ARROW
+ {"dblac", 0x002DD}, // DOUBLE ACUTE ACCENT
+ {"Dcaron", 0x0010E}, // LATIN CAPITAL LETTER D WITH CARON
+ {"dcaron", 0x0010F}, // LATIN SMALL LETTER D WITH CARON
+ {"Dcy", 0x00414}, // CYRILLIC CAPITAL LETTER DE
+ {"dcy", 0x00434}, // CYRILLIC SMALL LETTER DE
+ {"DD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D
+ {"dd", 0x02146}, // DOUBLE-STRUCK ITALIC SMALL D
+ {"ddagger", 0x02021}, // DOUBLE DAGGER
+ {"ddarr", 0x021CA}, // DOWNWARDS PAIRED ARROWS
+ {"DDotrahd", 0x02911}, // RIGHTWARDS ARROW WITH DOTTED STEM
+ {"ddotseq", 0x02A77}, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
+ {"deg", 0x000B0}, // DEGREE SIGN
+ {"Del", 0x02207}, // NABLA
+ {"Delta", 0x00394}, // GREEK CAPITAL LETTER DELTA
+ {"delta", 0x003B4}, // GREEK SMALL LETTER DELTA
+ {"demptyv", 0x029B1}, // EMPTY SET WITH OVERBAR
+ {"dfisht", 0x0297F}, // DOWN FISH TAIL
+ {"Dfr", 0x1D507}, // MATHEMATICAL FRAKTUR CAPITAL D
+ {"dfr", 0x1D521}, // MATHEMATICAL FRAKTUR SMALL D
+ {"Dgr", 0x00394}, // GREEK CAPITAL LETTER DELTA
+ {"dgr", 0x003B4}, // GREEK SMALL LETTER DELTA
+ {"dHar", 0x02965}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ {"dharl", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+ {"dharr", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+ {"DiacriticalAcute", 0x000B4}, // ACUTE ACCENT
+ {"DiacriticalDot", 0x002D9}, // DOT ABOVE
+ {"DiacriticalDoubleAcute", 0x002DD}, // DOUBLE ACUTE ACCENT
+ {"DiacriticalGrave", 0x00060}, // GRAVE ACCENT
+ {"DiacriticalTilde", 0x002DC}, // SMALL TILDE
+ {"diam", 0x022C4}, // DIAMOND OPERATOR
+ {"diamond", 0x022C4}, // DIAMOND OPERATOR
+ {"Diamond", 0x022C4}, // DIAMOND OPERATOR
+ {"diamondsuit", 0x02666}, // BLACK DIAMOND SUIT
+ {"diams", 0x02666}, // BLACK DIAMOND SUIT
+ {"die", 0x000A8}, // DIAERESIS
+ {"DifferentialD", 0x02146}, // DOUBLE-STRUCK ITALIC SMALL D
+ {"digamma", 0x003DD}, // GREEK SMALL LETTER DIGAMMA
+ {"disin", 0x022F2}, // ELEMENT OF WITH LONG HORIZONTAL STROKE
+ {"div", 0x000F7}, // DIVISION SIGN
+ {"divide", 0x000F7}, // DIVISION SIGN
+ {"divideontimes", 0x022C7}, // DIVISION TIMES
+ {"divonx", 0x022C7}, // DIVISION TIMES
+ {"DJcy", 0x00402}, // CYRILLIC CAPITAL LETTER DJE
+ {"djcy", 0x00452}, // CYRILLIC SMALL LETTER DJE
+ {"dlcorn", 0x0231E}, // BOTTOM LEFT CORNER
+ {"dlcrop", 0x0230D}, // BOTTOM LEFT CROP
+ {"dollar", 0x00024}, // DOLLAR SIGN
+ {"Dopf", 0x1D53B}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL D
+ {"dopf", 0x1D555}, // MATHEMATICAL DOUBLE-STRUCK SMALL D
+ {"Dot", 0x000A8}, // DIAERESIS
+ {"dot", 0x002D9}, // DOT ABOVE
+ {"DotDot", 0x020DC}, // COMBINING FOUR DOTS ABOVE
+ {"doteq", 0x02250}, // APPROACHES THE LIMIT
+ {"doteqdot", 0x02251}, // GEOMETRICALLY EQUAL TO
+ {"DotEqual", 0x02250}, // APPROACHES THE LIMIT
+ {"dotminus", 0x02238}, // DOT MINUS
+ {"dotplus", 0x02214}, // DOT PLUS
+ {"dotsquare", 0x022A1}, // SQUARED DOT OPERATOR
+ {"doublebarwedge", 0x02306}, // PERSPECTIVE
+ {"DoubleContourIntegral", 0x0222F}, // SURFACE INTEGRAL
+ {"DoubleDot", 0x000A8}, // DIAERESIS
+ {"DoubleDownArrow", 0x021D3}, // DOWNWARDS DOUBLE ARROW
+ {"DoubleLeftArrow", 0x021D0}, // LEFTWARDS DOUBLE ARROW
+ {"DoubleLeftRightArrow", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"DoubleLeftTee", 0x02AE4}, // VERTICAL BAR DOUBLE LEFT TURNSTILE
+ {"DoubleLongLeftArrow", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
+ {"DoubleLongLeftRightArrow", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
+ {"DoubleLongRightArrow", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
+ {"DoubleRightArrow", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"DoubleRightTee", 0x022A8}, // TRUE
+ {"DoubleUpArrow", 0x021D1}, // UPWARDS DOUBLE ARROW
+ {"DoubleUpDownArrow", 0x021D5}, // UP DOWN DOUBLE ARROW
+ {"DoubleVerticalBar", 0x02225}, // PARALLEL TO
+ {"downarrow", 0x02193}, // DOWNWARDS ARROW
+ {"DownArrow", 0x02193}, // DOWNWARDS ARROW
+ {"Downarrow", 0x021D3}, // DOWNWARDS DOUBLE ARROW
+ {"DownArrowBar", 0x02913}, // DOWNWARDS ARROW TO BAR
+ {"DownArrowUpArrow", 0x021F5}, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
+ {"DownBreve", 0x00311}, // COMBINING INVERTED BREVE
+ {"downdownarrows", 0x021CA}, // DOWNWARDS PAIRED ARROWS
+ {"downharpoonleft", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+ {"downharpoonright", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+ {"DownLeftRightVector", 0x02950}, // LEFT BARB DOWN RIGHT BARB DOWN HARPOON
+ {"DownLeftTeeVector", 0x0295E}, // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR
+ {"DownLeftVector", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+ {"DownLeftVectorBar", 0x02956}, // LEFTWARDS HARPOON WITH BARB DOWN TO BAR
+ {"DownRightTeeVector", 0x0295F}, // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR
+ {"DownRightVector", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+ {"DownRightVectorBar", 0x02957}, // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR
+ {"DownTee", 0x022A4}, // DOWN TACK
+ {"DownTeeArrow", 0x021A7}, // DOWNWARDS ARROW FROM BAR
+ {"drbkarow", 0x02910}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
+ {"drcorn", 0x0231F}, // BOTTOM RIGHT CORNER
+ {"drcrop", 0x0230C}, // BOTTOM RIGHT CROP
+ {"Dscr", 0x1D49F}, // MATHEMATICAL SCRIPT CAPITAL D
+ {"dscr", 0x1D4B9}, // MATHEMATICAL SCRIPT SMALL D
+ {"DScy", 0x00405}, // CYRILLIC CAPITAL LETTER DZE
+ {"dscy", 0x00455}, // CYRILLIC SMALL LETTER DZE
+ {"dsol", 0x029F6}, // SOLIDUS WITH OVERBAR
+ {"Dstrok", 0x00110}, // LATIN CAPITAL LETTER D WITH STROKE
+ {"dstrok", 0x00111}, // LATIN SMALL LETTER D WITH STROKE
+ {"dtdot", 0x022F1}, // DOWN RIGHT DIAGONAL ELLIPSIS
+ {"dtri", 0x025BF}, // WHITE DOWN-POINTING SMALL TRIANGLE
+ {"dtrif", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE
+ {"duarr", 0x021F5}, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
+ {"duhar", 0x0296F}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ {"dwangle", 0x029A6}, // OBLIQUE ANGLE OPENING UP
+ {"DZcy", 0x0040F}, // CYRILLIC CAPITAL LETTER DZHE
+ {"dzcy", 0x0045F}, // CYRILLIC SMALL LETTER DZHE
+ {"dzigrarr", 0x027FF}, // LONG RIGHTWARDS SQUIGGLE ARROW
+ {NULL, 0}
+};
+
+static NameId namesE[]={
+ {"Eacgr", 0x00388}, // GREEK CAPITAL LETTER EPSILON WITH TONOS
+ {"eacgr", 0x003AD}, // GREEK SMALL LETTER EPSILON WITH TONOS
+ {"Eacute", 0x000C9}, // LATIN CAPITAL LETTER E WITH ACUTE
+ {"eacute", 0x000E9}, // LATIN SMALL LETTER E WITH ACUTE
+ {"easter", 0x02A6E}, // EQUALS WITH ASTERISK
+ {"Ecaron", 0x0011A}, // LATIN CAPITAL LETTER E WITH CARON
+ {"ecaron", 0x0011B}, // LATIN SMALL LETTER E WITH CARON
+ {"ecir", 0x02256}, // RING IN EQUAL TO
+ {"Ecirc", 0x000CA}, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ {"ecirc", 0x000EA}, // LATIN SMALL LETTER E WITH CIRCUMFLEX
+ {"ecolon", 0x02255}, // EQUALS COLON
+ {"Ecy", 0x0042D}, // CYRILLIC CAPITAL LETTER E
+ {"ecy", 0x0044D}, // CYRILLIC SMALL LETTER E
+ {"eDDot", 0x02A77}, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
+ {"Edot", 0x00116}, // LATIN CAPITAL LETTER E WITH DOT ABOVE
+ {"edot", 0x00117}, // LATIN SMALL LETTER E WITH DOT ABOVE
+ {"eDot", 0x02251}, // GEOMETRICALLY EQUAL TO
+ {"ee", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
+ {"EEacgr", 0x00389}, // GREEK CAPITAL LETTER ETA WITH TONOS
+ {"eeacgr", 0x003AE}, // GREEK SMALL LETTER ETA WITH TONOS
+ {"EEgr", 0x00397}, // GREEK CAPITAL LETTER ETA
+ {"eegr", 0x003B7}, // GREEK SMALL LETTER ETA
+ {"efDot", 0x02252}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ {"Efr", 0x1D508}, // MATHEMATICAL FRAKTUR CAPITAL E
+ {"efr", 0x1D522}, // MATHEMATICAL FRAKTUR SMALL E
+ {"eg", 0x02A9A}, // DOUBLE-LINE EQUAL TO OR GREATER-THAN
+ {"Egr", 0x00395}, // GREEK CAPITAL LETTER EPSILON
+ {"egr", 0x003B5}, // GREEK SMALL LETTER EPSILON
+ {"Egrave", 0x000C8}, // LATIN CAPITAL LETTER E WITH GRAVE
+ {"egrave", 0x000E8}, // LATIN SMALL LETTER E WITH GRAVE
+ {"egs", 0x02A96}, // SLANTED EQUAL TO OR GREATER-THAN
+ {"egsdot", 0x02A98}, // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE
+ {"el", 0x02A99}, // DOUBLE-LINE EQUAL TO OR LESS-THAN
+ {"Element", 0x02208}, // ELEMENT OF
+ {"elinters", 0x023E7}, // ELECTRICAL INTERSECTION
+ {"ell", 0x02113}, // SCRIPT SMALL L
+ {"els", 0x02A95}, // SLANTED EQUAL TO OR LESS-THAN
+ {"elsdot", 0x02A97}, // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE
+ {"Emacr", 0x00112}, // LATIN CAPITAL LETTER E WITH MACRON
+ {"emacr", 0x00113}, // LATIN SMALL LETTER E WITH MACRON
+ {"empty", 0x02205}, // EMPTY SET
+ {"emptyset", 0x02205}, // EMPTY SET
+ {"EmptySmallSquare", 0x025FB}, // WHITE MEDIUM SQUARE
+ {"emptyv", 0x02205}, // EMPTY SET
+ {"EmptyVerySmallSquare", 0x025AB}, // WHITE SMALL SQUARE
+ {"emsp", 0x02003}, // EM SPACE
+ {"emsp13", 0x02004}, // THREE-PER-EM SPACE
+ {"emsp14", 0x02005}, // FOUR-PER-EM SPACE
+ {"ENG", 0x0014A}, // LATIN CAPITAL LETTER ENG
+ {"eng", 0x0014B}, // LATIN SMALL LETTER ENG
+ {"ensp", 0x02002}, // EN SPACE
+ {"Eogon", 0x00118}, // LATIN CAPITAL LETTER E WITH OGONEK
+ {"eogon", 0x00119}, // LATIN SMALL LETTER E WITH OGONEK
+ {"Eopf", 0x1D53C}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL E
+ {"eopf", 0x1D556}, // MATHEMATICAL DOUBLE-STRUCK SMALL E
+ {"epar", 0x022D5}, // EQUAL AND PARALLEL TO
+ {"eparsl", 0x029E3}, // EQUALS SIGN AND SLANTED PARALLEL
+ {"eplus", 0x02A71}, // EQUALS SIGN ABOVE PLUS SIGN
+ {"epsi", 0x003B5}, // GREEK SMALL LETTER EPSILON
+ {"Epsilon", 0x00395}, // GREEK CAPITAL LETTER EPSILON
+ {"epsilon", 0x003B5}, // GREEK SMALL LETTER EPSILON
+ {"epsiv", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
+ {"eqcirc", 0x02256}, // RING IN EQUAL TO
+ {"eqcolon", 0x02255}, // EQUALS COLON
+ {"eqsim", 0x02242}, // MINUS TILDE
+ {"eqslantgtr", 0x02A96}, // SLANTED EQUAL TO OR GREATER-THAN
+ {"eqslantless", 0x02A95}, // SLANTED EQUAL TO OR LESS-THAN
+ {"Equal", 0x02A75}, // TWO CONSECUTIVE EQUALS SIGNS
+ {"equals", 0x0003D}, // EQUALS SIGN
+ {"EqualTilde", 0x02242}, // MINUS TILDE
+ {"equest", 0x0225F}, // QUESTIONED EQUAL TO
+ {"Equilibrium", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+ {"equiv", 0x02261}, // IDENTICAL TO
+ {"equivDD", 0x02A78}, // EQUIVALENT WITH FOUR DOTS ABOVE
+ {"eqvparsl", 0x029E5}, // IDENTICAL TO AND SLANTED PARALLEL
+ {"erarr", 0x02971}, // EQUALS SIGN ABOVE RIGHTWARDS ARROW
+ {"erDot", 0x02253}, // IMAGE OF OR APPROXIMATELY EQUAL TO
+ {"escr", 0x0212F}, // SCRIPT SMALL E
+ {"Escr", 0x02130}, // SCRIPT CAPITAL E
+ {"esdot", 0x02250}, // APPROACHES THE LIMIT
+ {"esim", 0x02242}, // MINUS TILDE
+ {"Esim", 0x02A73}, // EQUALS SIGN ABOVE TILDE OPERATOR
+ {"Eta", 0x00397}, // GREEK CAPITAL LETTER ETA
+ {"eta", 0x003B7}, // GREEK SMALL LETTER ETA
+ {"ETH", 0x000D0}, // LATIN CAPITAL LETTER ETH
+ {"eth", 0x000F0}, // LATIN SMALL LETTER ETH
+ {"Euml", 0x000CB}, // LATIN CAPITAL LETTER E WITH DIAERESIS
+ {"euml", 0x000EB}, // LATIN SMALL LETTER E WITH DIAERESIS
+ {"euro", 0x020AC}, // EURO SIGN
+ {"excl", 0x00021}, // EXCLAMATION MARK
+ {"exist", 0x02203}, // THERE EXISTS
+ {"Exists", 0x02203}, // THERE EXISTS
+ {"expectation", 0x02130}, // SCRIPT CAPITAL E
+ {"exponentiale", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
+ {"ExponentialE", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
+ {NULL, 0}
+};
+
+static NameId namesF[]={
+ {"fallingdotseq", 0x02252}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ {"Fcy", 0x00424}, // CYRILLIC CAPITAL LETTER EF
+ {"fcy", 0x00444}, // CYRILLIC SMALL LETTER EF
+ {"female", 0x02640}, // FEMALE SIGN
+ {"ffilig", 0x0FB03}, // LATIN SMALL LIGATURE FFI
+ {"fflig", 0x0FB00}, // LATIN SMALL LIGATURE FF
+ {"ffllig", 0x0FB04}, // LATIN SMALL LIGATURE FFL
+ {"Ffr", 0x1D509}, // MATHEMATICAL FRAKTUR CAPITAL F
+ {"ffr", 0x1D523}, // MATHEMATICAL FRAKTUR SMALL F
+ {"filig", 0x0FB01}, // LATIN SMALL LIGATURE FI
+ {"FilledSmallSquare", 0x025FC}, // BLACK MEDIUM SQUARE
+ {"FilledVerySmallSquare", 0x025AA}, // BLACK SMALL SQUARE
+// "fjlig", 0x00066;0x0006A}, // fj ligature
+ {"flat", 0x0266D}, // MUSIC FLAT SIGN
+ {"fllig", 0x0FB02}, // LATIN SMALL LIGATURE FL
+ {"fltns", 0x025B1}, // WHITE PARALLELOGRAM
+ {"fnof", 0x00192}, // LATIN SMALL LETTER F WITH HOOK
+ {"Fopf", 0x1D53D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL F
+ {"fopf", 0x1D557}, // MATHEMATICAL DOUBLE-STRUCK SMALL F
+ {"forall", 0x02200}, // FOR ALL
+ {"ForAll", 0x02200}, // FOR ALL
+ {"fork", 0x022D4}, // PITCHFORK
+ {"forkv", 0x02AD9}, // ELEMENT OF OPENING DOWNWARDS
+ {"Fouriertrf", 0x02131}, // SCRIPT CAPITAL F
+ {"fpartint", 0x02A0D}, // FINITE PART INTEGRAL
+ {"frac12", 0x000BD}, // VULGAR FRACTION ONE HALF
+ {"frac13", 0x02153}, // VULGAR FRACTION ONE THIRD
+ {"frac14", 0x000BC}, // VULGAR FRACTION ONE QUARTER
+ {"frac15", 0x02155}, // VULGAR FRACTION ONE FIFTH
+ {"frac16", 0x02159}, // VULGAR FRACTION ONE SIXTH
+ {"frac18", 0x0215B}, // VULGAR FRACTION ONE EIGHTH
+ {"frac23", 0x02154}, // VULGAR FRACTION TWO THIRDS
+ {"frac25", 0x02156}, // VULGAR FRACTION TWO FIFTHS
+ {"frac34", 0x000BE}, // VULGAR FRACTION THREE QUARTERS
+ {"frac35", 0x02157}, // VULGAR FRACTION THREE FIFTHS
+ {"frac38", 0x0215C}, // VULGAR FRACTION THREE EIGHTHS
+ {"frac45", 0x02158}, // VULGAR FRACTION FOUR FIFTHS
+ {"frac56", 0x0215A}, // VULGAR FRACTION FIVE SIXTHS
+ {"frac58", 0x0215D}, // VULGAR FRACTION FIVE EIGHTHS
+ {"frac78", 0x0215E}, // VULGAR FRACTION SEVEN EIGHTHS
+ {"frasl", 0x02044}, // FRACTION SLASH
+ {"frown", 0x02322}, // FROWN
+ {"Fscr", 0x02131}, // SCRIPT CAPITAL F
+ {"fscr", 0x1D4BB}, // MATHEMATICAL SCRIPT SMALL F
+ {NULL, 0}
+};
+
+static NameId namesG[]={
+ {"gacute", 0x001F5}, // LATIN SMALL LETTER G WITH ACUTE
+ {"Gamma", 0x00393}, // GREEK CAPITAL LETTER GAMMA
+ {"gamma", 0x003B3}, // GREEK SMALL LETTER GAMMA
+ {"Gammad", 0x003DC}, // GREEK LETTER DIGAMMA
+ {"gammad", 0x003DD}, // GREEK SMALL LETTER DIGAMMA
+ {"gap", 0x02A86}, // GREATER-THAN OR APPROXIMATE
+ {"Gbreve", 0x0011E}, // LATIN CAPITAL LETTER G WITH BREVE
+ {"gbreve", 0x0011F}, // LATIN SMALL LETTER G WITH BREVE
+ {"Gcedil", 0x00122}, // LATIN CAPITAL LETTER G WITH CEDILLA
+ {"Gcirc", 0x0011C}, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+ {"gcirc", 0x0011D}, // LATIN SMALL LETTER G WITH CIRCUMFLEX
+ {"Gcy", 0x00413}, // CYRILLIC CAPITAL LETTER GHE
+ {"gcy", 0x00433}, // CYRILLIC SMALL LETTER GHE
+ {"Gdot", 0x00120}, // LATIN CAPITAL LETTER G WITH DOT ABOVE
+ {"gdot", 0x00121}, // LATIN SMALL LETTER G WITH DOT ABOVE
+ {"ge", 0x02265}, // GREATER-THAN OR EQUAL TO
+ {"gE", 0x02267}, // GREATER-THAN OVER EQUAL TO
+ {"gel", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
+ {"gEl", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
+ {"geq", 0x02265}, // GREATER-THAN OR EQUAL TO
+ {"geqq", 0x02267}, // GREATER-THAN OVER EQUAL TO
+ {"geqslant", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
+ {"ges", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
+ {"gescc", 0x02AA9}, // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+ {"gesdot", 0x02A80}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+ {"gesdoto", 0x02A82}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+ {"gesdotol", 0x02A84}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
+// "gesl", 0x022DB;0x0FE00}, // GREATER-THAN slanted EQUAL TO OR LESS-THAN
+ {"gesles", 0x02A94}, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
+ {"Gfr", 0x1D50A}, // MATHEMATICAL FRAKTUR CAPITAL G
+ {"gfr", 0x1D524}, // MATHEMATICAL FRAKTUR SMALL G
+ {"gg", 0x0226B}, // MUCH GREATER-THAN
+ {"Gg", 0x022D9}, // VERY MUCH GREATER-THAN
+ {"ggg", 0x022D9}, // VERY MUCH GREATER-THAN
+ {"Ggr", 0x00393}, // GREEK CAPITAL LETTER GAMMA
+ {"ggr", 0x003B3}, // GREEK SMALL LETTER GAMMA
+ {"gimel", 0x02137}, // GIMEL SYMBOL
+ {"GJcy", 0x00403}, // CYRILLIC CAPITAL LETTER GJE
+ {"gjcy", 0x00453}, // CYRILLIC SMALL LETTER GJE
+ {"gl", 0x02277}, // GREATER-THAN OR LESS-THAN
+ {"gla", 0x02AA5}, // GREATER-THAN BESIDE LESS-THAN
+ {"glE", 0x02A92}, // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL
+ {"glj", 0x02AA4}, // GREATER-THAN OVERLAPPING LESS-THAN
+ {"gnap", 0x02A8A}, // GREATER-THAN AND NOT APPROXIMATE
+ {"gnapprox", 0x02A8A}, // GREATER-THAN AND NOT APPROXIMATE
+ {"gnE", 0x02269}, // GREATER-THAN BUT NOT EQUAL TO
+ {"gne", 0x02A88}, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"gneq", 0x02A88}, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"gneqq", 0x02269}, // GREATER-THAN BUT NOT EQUAL TO
+ {"gnsim", 0x022E7}, // GREATER-THAN BUT NOT EQUIVALENT TO
+ {"Gopf", 0x1D53E}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+ {"gopf", 0x1D558}, // MATHEMATICAL DOUBLE-STRUCK SMALL G
+ {"grave", 0x00060}, // GRAVE ACCENT
+ {"GreaterEqual", 0x02265}, // GREATER-THAN OR EQUAL TO
+ {"GreaterEqualLess", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
+ {"GreaterFullEqual", 0x02267}, // GREATER-THAN OVER EQUAL TO
+ {"GreaterGreater", 0x02AA2}, // DOUBLE NESTED GREATER-THAN
+ {"GreaterLess", 0x02277}, // GREATER-THAN OR LESS-THAN
+ {"GreaterSlantEqual", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
+ {"GreaterTilde", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
+ {"gscr", 0x0210A}, // SCRIPT SMALL G
+ {"Gscr", 0x1D4A2}, // MATHEMATICAL SCRIPT CAPITAL G
+ {"gsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
+ {"gsime", 0x02A8E}, // GREATER-THAN ABOVE SIMILAR OR EQUAL
+ {"gsiml", 0x02A90}, // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN
+ {"gt", 0x0003E}, // GREATER-THAN SIGN
+ {"GT", 0x0003E}, // GREATER-THAN SIGN
+ {"Gt", 0x0226B}, // MUCH GREATER-THAN
+ {"gtcc", 0x02AA7}, // GREATER-THAN CLOSED BY CURVE
+ {"gtcir", 0x02A7A}, // GREATER-THAN WITH CIRCLE INSIDE
+ {"gtdot", 0x022D7}, // GREATER-THAN WITH DOT
+ {"gtlPar", 0x02995}, // DOUBLE LEFT ARC GREATER-THAN BRACKET
+ {"gtquest", 0x02A7C}, // GREATER-THAN WITH QUESTION MARK ABOVE
+ {"gtrapprox", 0x02A86}, // GREATER-THAN OR APPROXIMATE
+ {"gtrarr", 0x02978}, // GREATER-THAN ABOVE RIGHTWARDS ARROW
+ {"gtrdot", 0x022D7}, // GREATER-THAN WITH DOT
+ {"gtreqless", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
+ {"gtreqqless", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
+ {"gtrless", 0x02277}, // GREATER-THAN OR LESS-THAN
+ {"gtrsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
+// "gvertneqq", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
+// "gvnE", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
+ {NULL, 0}
+};
+
+static NameId namesH[]={
+ {"Hacek", 0x002C7}, // CARON
+ {"hairsp", 0x0200A}, // HAIR SPACE
+ {"half", 0x000BD}, // VULGAR FRACTION ONE HALF
+ {"hamilt", 0x0210B}, // SCRIPT CAPITAL H
+ {"HARDcy", 0x0042A}, // CYRILLIC CAPITAL LETTER HARD SIGN
+ {"hardcy", 0x0044A}, // CYRILLIC SMALL LETTER HARD SIGN
+ {"harr", 0x02194}, // LEFT RIGHT ARROW
+ {"hArr", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"harrcir", 0x02948}, // LEFT RIGHT ARROW THROUGH SMALL CIRCLE
+ {"harrw", 0x021AD}, // LEFT RIGHT WAVE ARROW
+ {"Hat", 0x0005E}, // CIRCUMFLEX ACCENT
+ {"hbar", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"Hcirc", 0x00124}, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+ {"hcirc", 0x00125}, // LATIN SMALL LETTER H WITH CIRCUMFLEX
+ {"hearts", 0x02665}, // BLACK HEART SUIT
+ {"heartsuit", 0x02665}, // BLACK HEART SUIT
+ {"hellip", 0x02026}, // HORIZONTAL ELLIPSIS
+ {"hercon", 0x022B9}, // HERMITIAN CONJUGATE MATRIX
+ {"Hfr", 0x0210C}, // BLACK-LETTER CAPITAL H
+ {"hfr", 0x1D525}, // MATHEMATICAL FRAKTUR SMALL H
+ {"HilbertSpace", 0x0210B}, // SCRIPT CAPITAL H
+ {"hksearow", 0x02925}, // SOUTH EAST ARROW WITH HOOK
+ {"hkswarow", 0x02926}, // SOUTH WEST ARROW WITH HOOK
+ {"hoarr", 0x021FF}, // LEFT RIGHT OPEN-HEADED ARROW
+ {"homtht", 0x0223B}, // HOMOTHETIC
+ {"hookleftarrow", 0x021A9}, // LEFTWARDS ARROW WITH HOOK
+ {"hookrightarrow", 0x021AA}, // RIGHTWARDS ARROW WITH HOOK
+ {"Hopf", 0x0210D}, // DOUBLE-STRUCK CAPITAL H
+ {"hopf", 0x1D559}, // MATHEMATICAL DOUBLE-STRUCK SMALL H
+ {"horbar", 0x02015}, // HORIZONTAL BAR
+ {"HorizontalLine", 0x02500}, // BOX DRAWINGS LIGHT HORIZONTAL
+ {"Hscr", 0x0210B}, // SCRIPT CAPITAL H
+ {"hscr", 0x1D4BD}, // MATHEMATICAL SCRIPT SMALL H
+ {"hslash", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"Hstrok", 0x00126}, // LATIN CAPITAL LETTER H WITH STROKE
+ {"hstrok", 0x00127}, // LATIN SMALL LETTER H WITH STROKE
+ {"HumpDownHump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
+ {"HumpEqual", 0x0224F}, // DIFFERENCE BETWEEN
+ {"hybull", 0x02043}, // HYPHEN BULLET
+ {"hyphen", 0x02010}, // HYPHEN
+ {NULL, 0}
+};
+
+static NameId namesI[]={
+ {"Iacgr", 0x0038A}, // GREEK CAPITAL LETTER IOTA WITH TONOS
+ {"iacgr", 0x003AF}, // GREEK SMALL LETTER IOTA WITH TONOS
+ {"Iacute", 0x000CD}, // LATIN CAPITAL LETTER I WITH ACUTE
+ {"iacute", 0x000ED}, // LATIN SMALL LETTER I WITH ACUTE
+ {"ic", 0x02063}, // INVISIBLE SEPARATOR
+ {"Icirc", 0x000CE}, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ {"icirc", 0x000EE}, // LATIN SMALL LETTER I WITH CIRCUMFLEX
+ {"Icy", 0x00418}, // CYRILLIC CAPITAL LETTER I
+ {"icy", 0x00438}, // CYRILLIC SMALL LETTER I
+ {"idiagr", 0x00390}, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ {"Idigr", 0x003AA}, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ {"idigr", 0x003CA}, // GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ {"Idot", 0x00130}, // LATIN CAPITAL LETTER I WITH DOT ABOVE
+ {"IEcy", 0x00415}, // CYRILLIC CAPITAL LETTER IE
+ {"iecy", 0x00435}, // CYRILLIC SMALL LETTER IE
+ {"iexcl", 0x000A1}, // INVERTED EXCLAMATION MARK
+ {"iff", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"Ifr", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"ifr", 0x1D526}, // MATHEMATICAL FRAKTUR SMALL I
+ {"Igr", 0x00399}, // GREEK CAPITAL LETTER IOTA
+ {"igr", 0x003B9}, // GREEK SMALL LETTER IOTA
+ {"Igrave", 0x000CC}, // LATIN CAPITAL LETTER I WITH GRAVE
+ {"igrave", 0x000EC}, // LATIN SMALL LETTER I WITH GRAVE
+ {"ii", 0x02148}, // DOUBLE-STRUCK ITALIC SMALL I
+ {"iiiint", 0x02A0C}, // QUADRUPLE INTEGRAL OPERATOR
+ {"iiint", 0x0222D}, // TRIPLE INTEGRAL
+ {"iinfin", 0x029DC}, // INCOMPLETE INFINITY
+ {"iiota", 0x02129}, // TURNED GREEK SMALL LETTER IOTA
+ {"IJlig", 0x00132}, // LATIN CAPITAL LIGATURE IJ
+ {"ijlig", 0x00133}, // LATIN SMALL LIGATURE IJ
+ {"Im", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"Imacr", 0x0012A}, // LATIN CAPITAL LETTER I WITH MACRON
+ {"imacr", 0x0012B}, // LATIN SMALL LETTER I WITH MACRON
+ {"image", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"ImaginaryI", 0x02148}, // DOUBLE-STRUCK ITALIC SMALL I
+ {"imagline", 0x02110}, // SCRIPT CAPITAL I
+ {"imagpart", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"imath", 0x00131}, // LATIN SMALL LETTER DOTLESS I
+ {"imof", 0x022B7}, // IMAGE OF
+ {"imped", 0x001B5}, // LATIN CAPITAL LETTER Z WITH STROKE
+ {"Implies", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"in", 0x02208}, // ELEMENT OF
+ {"incare", 0x02105}, // CARE OF
+ {"infin", 0x0221E}, // INFINITY
+ {"infintie", 0x029DD}, // TIE OVER INFINITY
+ {"inodot", 0x00131}, // LATIN SMALL LETTER DOTLESS I
+ {"int", 0x0222B}, // INTEGRAL
+ {"Int", 0x0222C}, // DOUBLE INTEGRAL
+ {"intcal", 0x022BA}, // INTERCALATE
+ {"integers", 0x02124}, // DOUBLE-STRUCK CAPITAL Z
+ {"Integral", 0x0222B}, // INTEGRAL
+ {"intercal", 0x022BA}, // INTERCALATE
+ {"Intersection", 0x022C2}, // N-ARY INTERSECTION
+ {"intlarhk", 0x02A17}, // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK
+ {"intprod", 0x02A3C}, // INTERIOR PRODUCT
+ {"InvisibleComma", 0x02063}, // INVISIBLE SEPARATOR
+ {"InvisibleTimes", 0x02062}, // INVISIBLE TIMES
+ {"IOcy", 0x00401}, // CYRILLIC CAPITAL LETTER IO
+ {"iocy", 0x00451}, // CYRILLIC SMALL LETTER IO
+ {"Iogon", 0x0012E}, // LATIN CAPITAL LETTER I WITH OGONEK
+ {"iogon", 0x0012F}, // LATIN SMALL LETTER I WITH OGONEK
+ {"Iopf", 0x1D540}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL I
+ {"iopf", 0x1D55A}, // MATHEMATICAL DOUBLE-STRUCK SMALL I
+ {"Iota", 0x00399}, // GREEK CAPITAL LETTER IOTA
+ {"iota", 0x003B9}, // GREEK SMALL LETTER IOTA
+ {"iprod", 0x02A3C}, // INTERIOR PRODUCT
+ {"iquest", 0x000BF}, // INVERTED QUESTION MARK
+ {"Iscr", 0x02110}, // SCRIPT CAPITAL I
+ {"iscr", 0x1D4BE}, // MATHEMATICAL SCRIPT SMALL I
+ {"isin", 0x02208}, // ELEMENT OF
+ {"isindot", 0x022F5}, // ELEMENT OF WITH DOT ABOVE
+ {"isinE", 0x022F9}, // ELEMENT OF WITH TWO HORIZONTAL STROKES
+ {"isins", 0x022F4}, // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"isinsv", 0x022F3}, // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"isinv", 0x02208}, // ELEMENT OF
+ {"it", 0x02062}, // INVISIBLE TIMES
+ {"Itilde", 0x00128}, // LATIN CAPITAL LETTER I WITH TILDE
+ {"itilde", 0x00129}, // LATIN SMALL LETTER I WITH TILDE
+ {"Iukcy", 0x00406}, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+ {"iukcy", 0x00456}, // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ {"Iuml", 0x000CF}, // LATIN CAPITAL LETTER I WITH DIAERESIS
+ {"iuml", 0x000EF}, // LATIN SMALL LETTER I WITH DIAERESIS
+ {NULL, 0}
+};
+
+static NameId namesJ[]={
+ {"Jcirc", 0x00134}, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+ {"jcirc", 0x00135}, // LATIN SMALL LETTER J WITH CIRCUMFLEX
+ {"Jcy", 0x00419}, // CYRILLIC CAPITAL LETTER SHORT I
+ {"jcy", 0x00439}, // CYRILLIC SMALL LETTER SHORT I
+ {"Jfr", 0x1D50D}, // MATHEMATICAL FRAKTUR CAPITAL J
+ {"jfr", 0x1D527}, // MATHEMATICAL FRAKTUR SMALL J
+ {"jmath", 0x00237}, // LATIN SMALL LETTER DOTLESS J
+ {"Jopf", 0x1D541}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL J
+ {"jopf", 0x1D55B}, // MATHEMATICAL DOUBLE-STRUCK SMALL J
+ {"Jscr", 0x1D4A5}, // MATHEMATICAL SCRIPT CAPITAL J
+ {"jscr", 0x1D4BF}, // MATHEMATICAL SCRIPT SMALL J
+ {"Jsercy", 0x00408}, // CYRILLIC CAPITAL LETTER JE
+ {"jsercy", 0x00458}, // CYRILLIC SMALL LETTER JE
+ {"Jukcy", 0x00404}, // CYRILLIC CAPITAL LETTER UKRAINIAN IE
+ {"jukcy", 0x00454}, // CYRILLIC SMALL LETTER UKRAINIAN IE
+ {NULL, 0}
+};
+
+static NameId namesK[]={
+ {"Kappa", 0x0039A}, // GREEK CAPITAL LETTER KAPPA
+ {"kappa", 0x003BA}, // GREEK SMALL LETTER KAPPA
+ {"kappav", 0x003F0}, // GREEK KAPPA SYMBOL
+ {"Kcedil", 0x00136}, // LATIN CAPITAL LETTER K WITH CEDILLA
+ {"kcedil", 0x00137}, // LATIN SMALL LETTER K WITH CEDILLA
+ {"Kcy", 0x0041A}, // CYRILLIC CAPITAL LETTER KA
+ {"kcy", 0x0043A}, // CYRILLIC SMALL LETTER KA
+ {"Kfr", 0x1D50E}, // MATHEMATICAL FRAKTUR CAPITAL K
+ {"kfr", 0x1D528}, // MATHEMATICAL FRAKTUR SMALL K
+ {"Kgr", 0x0039A}, // GREEK CAPITAL LETTER KAPPA
+ {"kgr", 0x003BA}, // GREEK SMALL LETTER KAPPA
+ {"kgreen", 0x00138}, // LATIN SMALL LETTER KRA
+ {"KHcy", 0x00425}, // CYRILLIC CAPITAL LETTER HA
+ {"khcy", 0x00445}, // CYRILLIC SMALL LETTER HA
+ {"KHgr", 0x003A7}, // GREEK CAPITAL LETTER CHI
+ {"khgr", 0x003C7}, // GREEK SMALL LETTER CHI
+ {"KJcy", 0x0040C}, // CYRILLIC CAPITAL LETTER KJE
+ {"kjcy", 0x0045C}, // CYRILLIC SMALL LETTER KJE
+ {"Kopf", 0x1D542}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL K
+ {"kopf", 0x1D55C}, // MATHEMATICAL DOUBLE-STRUCK SMALL K
+ {"Kscr", 0x1D4A6}, // MATHEMATICAL SCRIPT CAPITAL K
+ {"kscr", 0x1D4C0}, // MATHEMATICAL SCRIPT SMALL K
+ {NULL, 0}
+};
+
+static NameId namesL[]={
+ {"lAarr", 0x021DA}, // LEFTWARDS TRIPLE ARROW
+ {"Lacute", 0x00139}, // LATIN CAPITAL LETTER L WITH ACUTE
+ {"lacute", 0x0013A}, // LATIN SMALL LETTER L WITH ACUTE
+ {"laemptyv", 0x029B4}, // EMPTY SET WITH LEFT ARROW ABOVE
+ {"lagran", 0x02112}, // SCRIPT CAPITAL L
+ {"Lambda", 0x0039B}, // GREEK CAPITAL LETTER LAMDA
+ {"lambda", 0x003BB}, // GREEK SMALL LETTER LAMDA
+ {"lang", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
+ {"Lang", 0x027EA}, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+ {"langd", 0x02991}, // LEFT ANGLE BRACKET WITH DOT
+ {"langle", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
+ {"lap", 0x02A85}, // LESS-THAN OR APPROXIMATE
+ {"Laplacetrf", 0x02112}, // SCRIPT CAPITAL L
+ {"laquo", 0x000AB}, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {"larr", 0x02190}, // LEFTWARDS ARROW
+ {"Larr", 0x0219E}, // LEFTWARDS TWO HEADED ARROW
+ {"lArr", 0x021D0}, // LEFTWARDS DOUBLE ARROW
+ {"larrb", 0x021E4}, // LEFTWARDS ARROW TO BAR
+ {"larrbfs", 0x0291F}, // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND
+ {"larrfs", 0x0291D}, // LEFTWARDS ARROW TO BLACK DIAMOND
+ {"larrhk", 0x021A9}, // LEFTWARDS ARROW WITH HOOK
+ {"larrlp", 0x021AB}, // LEFTWARDS ARROW WITH LOOP
+ {"larrpl", 0x02939}, // LEFT-SIDE ARC ANTICLOCKWISE ARROW
+ {"larrsim", 0x02973}, // LEFTWARDS ARROW ABOVE TILDE OPERATOR
+ {"larrtl", 0x021A2}, // LEFTWARDS ARROW WITH TAIL
+ {"lat", 0x02AAB}, // LARGER THAN
+ {"latail", 0x02919}, // LEFTWARDS ARROW-TAIL
+ {"lAtail", 0x0291B}, // LEFTWARDS DOUBLE ARROW-TAIL
+ {"late", 0x02AAD}, // LARGER THAN OR EQUAL TO
+// "lates", 0x02AAD;0x0FE00}, // LARGER THAN OR slanted EQUAL
+ {"lbarr", 0x0290C}, // LEFTWARDS DOUBLE DASH ARROW
+ {"lBarr", 0x0290E}, // LEFTWARDS TRIPLE DASH ARROW
+ {"lbbrk", 0x02772}, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+ {"lbrace", 0x0007B}, // LEFT CURLY BRACKET
+ {"lbrack", 0x0005B}, // LEFT SQUARE BRACKET
+ {"lbrke", 0x0298B}, // LEFT SQUARE BRACKET WITH UNDERBAR
+ {"lbrksld", 0x0298F}, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {"lbrkslu", 0x0298D}, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {"Lcaron", 0x0013D}, // LATIN CAPITAL LETTER L WITH CARON
+ {"lcaron", 0x0013E}, // LATIN SMALL LETTER L WITH CARON
+ {"Lcedil", 0x0013B}, // LATIN CAPITAL LETTER L WITH CEDILLA
+ {"lcedil", 0x0013C}, // LATIN SMALL LETTER L WITH CEDILLA
+ {"lceil", 0x02308}, // LEFT CEILING
+ {"lcub", 0x0007B}, // LEFT CURLY BRACKET
+ {"Lcy", 0x0041B}, // CYRILLIC CAPITAL LETTER EL
+ {"lcy", 0x0043B}, // CYRILLIC SMALL LETTER EL
+ {"ldca", 0x02936}, // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS
+ {"ldquo", 0x0201C}, // LEFT DOUBLE QUOTATION MARK
+ {"ldquor", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK
+ {"ldrdhar", 0x02967}, // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+ {"ldrushar", 0x0294B}, // LEFT BARB DOWN RIGHT BARB UP HARPOON
+ {"ldsh", 0x021B2}, // DOWNWARDS ARROW WITH TIP LEFTWARDS
+ {"le", 0x02264}, // LESS-THAN OR EQUAL TO
+ {"lE", 0x02266}, // LESS-THAN OVER EQUAL TO
+ {"LeftAngleBracket", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
+ {"leftarrow", 0x02190}, // LEFTWARDS ARROW
+ {"LeftArrow", 0x02190}, // LEFTWARDS ARROW
+ {"Leftarrow", 0x021D0}, // LEFTWARDS DOUBLE ARROW
+ {"LeftArrowBar", 0x021E4}, // LEFTWARDS ARROW TO BAR
+ {"LeftArrowRightArrow", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+ {"leftarrowtail", 0x021A2}, // LEFTWARDS ARROW WITH TAIL
+ {"LeftCeiling", 0x02308}, // LEFT CEILING
+ {"LeftDoubleBracket", 0x027E6}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ {"LeftDownTeeVector", 0x02961}, // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR
+ {"LeftDownVector", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+ {"LeftDownVectorBar", 0x02959}, // DOWNWARDS HARPOON WITH BARB LEFT TO BAR
+ {"LeftFloor", 0x0230A}, // LEFT FLOOR
+ {"leftharpoondown", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+ {"leftharpoonup", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
+ {"leftleftarrows", 0x021C7}, // LEFTWARDS PAIRED ARROWS
+ {"leftrightarrow", 0x02194}, // LEFT RIGHT ARROW
+ {"LeftRightArrow", 0x02194}, // LEFT RIGHT ARROW
+ {"Leftrightarrow", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"leftrightarrows", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+ {"leftrightharpoons", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+ {"leftrightsquigarrow", 0x021AD}, // LEFT RIGHT WAVE ARROW
+ {"LeftRightVector", 0x0294E}, // LEFT BARB UP RIGHT BARB UP HARPOON
+ {"LeftTee", 0x022A3}, // LEFT TACK
+ {"LeftTeeArrow", 0x021A4}, // LEFTWARDS ARROW FROM BAR
+ {"LeftTeeVector", 0x0295A}, // LEFTWARDS HARPOON WITH BARB UP FROM BAR
+ {"leftthreetimes", 0x022CB}, // LEFT SEMIDIRECT PRODUCT
+ {"LeftTriangle", 0x022B2}, // NORMAL SUBGROUP OF
+ {"LeftTriangleBar", 0x029CF}, // LEFT TRIANGLE BESIDE VERTICAL BAR
+ {"LeftTriangleEqual", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
+ {"LeftUpDownVector", 0x02951}, // UP BARB LEFT DOWN BARB LEFT HARPOON
+ {"LeftUpTeeVector", 0x02960}, // UPWARDS HARPOON WITH BARB LEFT FROM BAR
+ {"LeftUpVector", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
+ {"LeftUpVectorBar", 0x02958}, // UPWARDS HARPOON WITH BARB LEFT TO BAR
+ {"LeftVector", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
+ {"LeftVectorBar", 0x02952}, // LEFTWARDS HARPOON WITH BARB UP TO BAR
+ {"leg", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
+ {"lEg", 0x02A8B}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
+ {"leq", 0x02264}, // LESS-THAN OR EQUAL TO
+ {"leqq", 0x02266}, // LESS-THAN OVER EQUAL TO
+ {"leqslant", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
+ {"les", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
+ {"lescc", 0x02AA8}, // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+ {"lesdot", 0x02A7F}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+ {"lesdoto", 0x02A81}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+ {"lesdotor", 0x02A83}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
+// "lesg", 0x022DA;0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN
+ {"lesges", 0x02A93}, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
+ {"lessapprox", 0x02A85}, // LESS-THAN OR APPROXIMATE
+ {"lessdot", 0x022D6}, // LESS-THAN WITH DOT
+ {"lesseqgtr", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
+ {"lesseqqgtr", 0x02A8B}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
+ {"LessEqualGreater", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
+ {"LessFullEqual", 0x02266}, // LESS-THAN OVER EQUAL TO
+ {"LessGreater", 0x02276}, // LESS-THAN OR GREATER-THAN
+ {"lessgtr", 0x02276}, // LESS-THAN OR GREATER-THAN
+ {"LessLess", 0x02AA1}, // DOUBLE NESTED LESS-THAN
+ {"lesssim", 0x02272}, // LESS-THAN OR EQUIVALENT TO
+ {"LessSlantEqual", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
+ {"LessTilde", 0x02272}, // LESS-THAN OR EQUIVALENT TO
+ {"lfisht", 0x0297C}, // LEFT FISH TAIL
+ {"lfloor", 0x0230A}, // LEFT FLOOR
+ {"Lfr", 0x1D50F}, // MATHEMATICAL FRAKTUR CAPITAL L
+ {"lfr", 0x1D529}, // MATHEMATICAL FRAKTUR SMALL L
+ {"lg", 0x02276}, // LESS-THAN OR GREATER-THAN
+ {"lgE", 0x02A91}, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL
+ {"Lgr", 0x0039B}, // GREEK CAPITAL LETTER LAMDA
+ {"lgr", 0x003BB}, // GREEK SMALL LETTER LAMDA
+ {"lHar", 0x02962}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+ {"lhard", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+ {"lharu", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
+ {"lharul", 0x0296A}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+ {"lhblk", 0x02584}, // LOWER HALF BLOCK
+ {"LJcy", 0x00409}, // CYRILLIC CAPITAL LETTER LJE
+ {"ljcy", 0x00459}, // CYRILLIC SMALL LETTER LJE
+ {"ll", 0x0226A}, // MUCH LESS-THAN
+ {"Ll", 0x022D8}, // VERY MUCH LESS-THAN
+ {"llarr", 0x021C7}, // LEFTWARDS PAIRED ARROWS
+ {"llcorner", 0x0231E}, // BOTTOM LEFT CORNER
+ {"Lleftarrow", 0x021DA}, // LEFTWARDS TRIPLE ARROW
+ {"llhard", 0x0296B}, // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+ {"lltri", 0x025FA}, // LOWER LEFT TRIANGLE
+ {"Lmidot", 0x0013F}, // LATIN CAPITAL LETTER L WITH MIDDLE DOT
+ {"lmidot", 0x00140}, // LATIN SMALL LETTER L WITH MIDDLE DOT
+ {"lmoust", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
+ {"lmoustache", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
+ {"lnap", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE
+ {"lnapprox", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE
+ {"lnE", 0x02268}, // LESS-THAN BUT NOT EQUAL TO
+ {"lne", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"lneq", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"lneqq", 0x02268}, // LESS-THAN BUT NOT EQUAL TO
+ {"lnsim", 0x022E6}, // LESS-THAN BUT NOT EQUIVALENT TO
+ {"loang", 0x027EC}, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+ {"loarr", 0x021FD}, // LEFTWARDS OPEN-HEADED ARROW
+ {"lobrk", 0x027E6}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ {"longleftarrow", 0x027F5}, // LONG LEFTWARDS ARROW
+ {"LongLeftArrow", 0x027F5}, // LONG LEFTWARDS ARROW
+ {"Longleftarrow", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
+ {"longleftrightarrow", 0x027F7}, // LONG LEFT RIGHT ARROW
+ {"LongLeftRightArrow", 0x027F7}, // LONG LEFT RIGHT ARROW
+ {"Longleftrightarrow", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
+ {"longmapsto", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR
+ {"longrightarrow", 0x027F6}, // LONG RIGHTWARDS ARROW
+ {"LongRightArrow", 0x027F6}, // LONG RIGHTWARDS ARROW
+ {"Longrightarrow", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
+ {"looparrowleft", 0x021AB}, // LEFTWARDS ARROW WITH LOOP
+ {"looparrowright", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP
+ {"lopar", 0x02985}, // LEFT WHITE PARENTHESIS
+ {"Lopf", 0x1D543}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL L
+ {"lopf", 0x1D55D}, // MATHEMATICAL DOUBLE-STRUCK SMALL L
+ {"loplus", 0x02A2D}, // PLUS SIGN IN LEFT HALF CIRCLE
+ {"lotimes", 0x02A34}, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE
+ {"lowast", 0x02217}, // ASTERISK OPERATOR
+ {"lowbar", 0x0005F}, // LOW LINE
+ {"LowerLeftArrow", 0x02199}, // SOUTH WEST ARROW
+ {"LowerRightArrow", 0x02198}, // SOUTH EAST ARROW
+ {"loz", 0x025CA}, // LOZENGE
+ {"lozenge", 0x025CA}, // LOZENGE
+ {"lozf", 0x029EB}, // BLACK LOZENGE
+ {"lpar", 0x00028}, // LEFT PARENTHESIS
+ {"lparlt", 0x02993}, // LEFT ARC LESS-THAN BRACKET
+ {"lrarr", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+ {"lrcorner", 0x0231F}, // BOTTOM RIGHT CORNER
+ {"lrhar", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+ {"lrhard", 0x0296D}, // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+ {"lrm", 0x0200E}, // LEFT-TO-RIGHT MARK
+ {"lrtri", 0x022BF}, // RIGHT TRIANGLE
+ {"lsaquo", 0x02039}, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ {"Lscr", 0x02112}, // SCRIPT CAPITAL L
+ {"lscr", 0x1D4C1}, // MATHEMATICAL SCRIPT SMALL L
+ {"lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS
+ {"Lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS
+ {"lsim", 0x02272}, // LESS-THAN OR EQUIVALENT TO
+ {"lsime", 0x02A8D}, // LESS-THAN ABOVE SIMILAR OR EQUAL
+ {"lsimg", 0x02A8F}, // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN
+ {"lsqb", 0x0005B}, // LEFT SQUARE BRACKET
+ {"lsquo", 0x02018}, // LEFT SINGLE QUOTATION MARK
+ {"lsquor", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK
+ {"Lstrok", 0x00141}, // LATIN CAPITAL LETTER L WITH STROKE
+ {"lstrok", 0x00142}, // LATIN SMALL LETTER L WITH STROKE
+ {"lt", 0x0003C}, // LESS-THAN SIGN
+ {"LT", 0x0003C}, // LESS-THAN SIGN
+ {"Lt", 0x0226A}, // MUCH LESS-THAN
+ {"ltcc", 0x02AA6}, // LESS-THAN CLOSED BY CURVE
+ {"ltcir", 0x02A79}, // LESS-THAN WITH CIRCLE INSIDE
+ {"ltdot", 0x022D6}, // LESS-THAN WITH DOT
+ {"lthree", 0x022CB}, // LEFT SEMIDIRECT PRODUCT
+ {"ltimes", 0x022C9}, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
+ {"ltlarr", 0x02976}, // LESS-THAN ABOVE LEFTWARDS ARROW
+ {"ltquest", 0x02A7B}, // LESS-THAN WITH QUESTION MARK ABOVE
+ {"ltri", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE
+ {"ltrie", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
+ {"ltrif", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE
+ {"ltrPar", 0x02996}, // DOUBLE RIGHT ARC LESS-THAN BRACKET
+ {"lurdshar", 0x0294A}, // LEFT BARB UP RIGHT BARB DOWN HARPOON
+ {"luruhar", 0x02966}, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP
+// "lvertneqq", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
+// "lvnE", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
+ {NULL, 0}
+};
+
+static NameId namesM[]={
+ {"macr", 0x000AF}, // MACRON
+ {"male", 0x02642}, // MALE SIGN
+ {"malt", 0x02720}, // MALTESE CROSS
+ {"maltese", 0x02720}, // MALTESE CROSS
+ {"map", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
+ {"Map", 0x02905}, // RIGHTWARDS TWO-HEADED ARROW FROM BAR
+ {"mapsto", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
+ {"mapstodown", 0x021A7}, // DOWNWARDS ARROW FROM BAR
+ {"mapstoleft", 0x021A4}, // LEFTWARDS ARROW FROM BAR
+ {"mapstoup", 0x021A5}, // UPWARDS ARROW FROM BAR
+ {"marker", 0x025AE}, // BLACK VERTICAL RECTANGLE
+ {"mcomma", 0x02A29}, // MINUS SIGN WITH COMMA ABOVE
+ {"Mcy", 0x0041C}, // CYRILLIC CAPITAL LETTER EM
+ {"mcy", 0x0043C}, // CYRILLIC SMALL LETTER EM
+ {"mdash", 0x02014}, // EM DASH
+ {"mDDot", 0x0223A}, // GEOMETRIC PROPORTION
+ {"measuredangle", 0x02221}, // MEASURED ANGLE
+ {"MediumSpace", 0x0205F}, // MEDIUM MATHEMATICAL SPACE
+ {"Mellintrf", 0x02133}, // SCRIPT CAPITAL M
+ {"Mfr", 0x1D510}, // MATHEMATICAL FRAKTUR CAPITAL M
+ {"mfr", 0x1D52A}, // MATHEMATICAL FRAKTUR SMALL M
+ {"Mgr", 0x0039C}, // GREEK CAPITAL LETTER MU
+ {"mgr", 0x003BC}, // GREEK SMALL LETTER MU
+ {"mho", 0x02127}, // INVERTED OHM SIGN
+ {"micro", 0x000B5}, // MICRO SIGN
+ {"mid", 0x02223}, // DIVIDES
+ {"midast", 0x0002A}, // ASTERISK
+ {"midcir", 0x02AF0}, // VERTICAL LINE WITH CIRCLE BELOW
+ {"middot", 0x000B7}, // MIDDLE DOT
+ {"minus", 0x02212}, // MINUS SIGN
+ {"minusb", 0x0229F}, // SQUARED MINUS
+ {"minusd", 0x02238}, // DOT MINUS
+ {"minusdu", 0x02A2A}, // MINUS SIGN WITH DOT BELOW
+ {"MinusPlus", 0x02213}, // MINUS-OR-PLUS SIGN
+ {"mlcp", 0x02ADB}, // TRANSVERSAL INTERSECTION
+ {"mldr", 0x02026}, // HORIZONTAL ELLIPSIS
+ {"mnplus", 0x02213}, // MINUS-OR-PLUS SIGN
+ {"models", 0x022A7}, // MODELS
+ {"Mopf", 0x1D544}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+ {"mopf", 0x1D55E}, // MATHEMATICAL DOUBLE-STRUCK SMALL M
+ {"mp", 0x02213}, // MINUS-OR-PLUS SIGN
+ {"Mscr", 0x02133}, // SCRIPT CAPITAL M
+ {"mscr", 0x1D4C2}, // MATHEMATICAL SCRIPT SMALL M
+ {"mstpos", 0x0223E}, // INVERTED LAZY S
+ {"Mu", 0x0039C}, // GREEK CAPITAL LETTER MU
+ {"mu", 0x003BC}, // GREEK SMALL LETTER MU
+ {"multimap", 0x022B8}, // MULTIMAP
+ {"mumap", 0x022B8}, // MULTIMAP
+ {NULL, 0}
+};
+
+static NameId namesN[]={
+ {"nabla", 0x02207}, // NABLA
+ {"Nacute", 0x00143}, // LATIN CAPITAL LETTER N WITH ACUTE
+ {"nacute", 0x00144}, // LATIN SMALL LETTER N WITH ACUTE
+// "nang", 0x02220;0x020D2}, // ANGLE with vertical line
+ {"nap", 0x02249}, // NOT ALMOST EQUAL TO
+// "napE", 0x02A70;0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash
+// "napid", 0x0224B;0x00338}, // TRIPLE TILDE with slash
+ {"napos", 0x00149}, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+ {"napprox", 0x02249}, // NOT ALMOST EQUAL TO
+ {"natur", 0x0266E}, // MUSIC NATURAL SIGN
+ {"natural", 0x0266E}, // MUSIC NATURAL SIGN
+ {"naturals", 0x02115}, // DOUBLE-STRUCK CAPITAL N
+ {"nbsp", 0x000A0}, // NO-BREAK SPACE
+// "nbump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
+// "nbumpe", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
+ {"ncap", 0x02A43}, // INTERSECTION WITH OVERBAR
+ {"Ncaron", 0x00147}, // LATIN CAPITAL LETTER N WITH CARON
+ {"ncaron", 0x00148}, // LATIN SMALL LETTER N WITH CARON
+ {"Ncedil", 0x00145}, // LATIN CAPITAL LETTER N WITH CEDILLA
+ {"ncedil", 0x00146}, // LATIN SMALL LETTER N WITH CEDILLA
+ {"ncong", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+// "ncongdot", 0x02A6D;0x00338}, // CONGRUENT WITH DOT ABOVE with slash
+ {"ncup", 0x02A42}, // UNION WITH OVERBAR
+ {"Ncy", 0x0041D}, // CYRILLIC CAPITAL LETTER EN
+ {"ncy", 0x0043D}, // CYRILLIC SMALL LETTER EN
+ {"ndash", 0x02013}, // EN DASH
+ {"ne", 0x02260}, // NOT EQUAL TO
+ {"nearhk", 0x02924}, // NORTH EAST ARROW WITH HOOK
+ {"nearr", 0x02197}, // NORTH EAST ARROW
+ {"neArr", 0x021D7}, // NORTH EAST DOUBLE ARROW
+ {"nearrow", 0x02197}, // NORTH EAST ARROW
+// "nedot", 0x02250;0x00338}, // APPROACHES THE LIMIT with slash
+ {"NegativeMediumSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"NegativeThickSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"NegativeThinSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"NegativeVeryThinSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"nequiv", 0x02262}, // NOT IDENTICAL TO
+ {"nesear", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW
+// "nesim", 0x02242;0x00338}, // MINUS TILDE with slash
+ {"NestedGreaterGreater", 0x0226B}, // MUCH GREATER-THAN
+ {"NestedLessLess", 0x0226A}, // MUCH LESS-THAN
+ {"NewLine", 0x0000A}, // LINE FEED (LF)
+ {"nexist", 0x02204}, // THERE DOES NOT EXIST
+ {"nexists", 0x02204}, // THERE DOES NOT EXIST
+ {"Nfr", 0x1D511}, // MATHEMATICAL FRAKTUR CAPITAL N
+ {"nfr", 0x1D52B}, // MATHEMATICAL FRAKTUR SMALL N
+// "ngE", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
+ {"nge", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
+ {"ngeq", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
+// "ngeqq", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
+// "ngeqslant", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
+// "nges", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
+// "nGg", 0x022D9;0x00338}, // VERY MUCH GREATER-THAN with slash
+ {"Ngr", 0x0039D}, // GREEK CAPITAL LETTER NU
+ {"ngr", 0x003BD}, // GREEK SMALL LETTER NU
+ {"ngsim", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
+// "nGt", 0x0226B;0x020D2}, // MUCH GREATER THAN with vertical line
+ {"ngt", 0x0226F}, // NOT GREATER-THAN
+ {"ngtr", 0x0226F}, // NOT GREATER-THAN
+// "nGtv", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
+ {"nharr", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
+ {"nhArr", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
+ {"nhpar", 0x02AF2}, // PARALLEL WITH HORIZONTAL STROKE
+ {"ni", 0x0220B}, // CONTAINS AS MEMBER
+ {"nis", 0x022FC}, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"nisd", 0x022FA}, // CONTAINS WITH LONG HORIZONTAL STROKE
+ {"niv", 0x0220B}, // CONTAINS AS MEMBER
+ {"NJcy", 0x0040A}, // CYRILLIC CAPITAL LETTER NJE
+ {"njcy", 0x0045A}, // CYRILLIC SMALL LETTER NJE
+ {"nlarr", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
+ {"nlArr", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
+ {"nldr", 0x02025}, // TWO DOT LEADER
+// "nlE", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
+ {"nle", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
+ {"nleftarrow", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
+ {"nLeftarrow", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
+ {"nleftrightarrow", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
+ {"nLeftrightarrow", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
+ {"nleq", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
+// "nleqq", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
+// "nleqslant", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
+// "nles", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
+ {"nless", 0x0226E}, // NOT LESS-THAN
+// "nLl", 0x022D8;0x00338}, // VERY MUCH LESS-THAN with slash
+ {"nlsim", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
+// "nLt", 0x0226A;0x020D2}, // MUCH LESS THAN with vertical line
+ {"nlt", 0x0226E}, // NOT LESS-THAN
+ {"nltri", 0x022EA}, // NOT NORMAL SUBGROUP OF
+ {"nltrie", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
+// "nLtv", 0x0226A;0x00338}, // MUCH LESS THAN with slash
+ {"nmid", 0x02224}, // DOES NOT DIVIDE
+ {"NoBreak", 0x02060}, // WORD JOINER
+ {"NonBreakingSpace", 0x000A0}, // NO-BREAK SPACE
+ {"Nopf", 0x02115}, // DOUBLE-STRUCK CAPITAL N
+ {"nopf", 0x1D55F}, // MATHEMATICAL DOUBLE-STRUCK SMALL N
+ {"not", 0x000AC}, // NOT SIGN
+ {"Not", 0x02AEC}, // DOUBLE STROKE NOT SIGN
+ {"NotCongruent", 0x02262}, // NOT IDENTICAL TO
+ {"NotCupCap", 0x0226D}, // NOT EQUIVALENT TO
+ {"NotDoubleVerticalBar", 0x02226}, // NOT PARALLEL TO
+ {"NotElement", 0x02209}, // NOT AN ELEMENT OF
+ {"NotEqual", 0x02260}, // NOT EQUAL TO
+// "NotEqualTilde", 0x02242;0x00338}, // MINUS TILDE with slash
+ {"NotExists", 0x02204}, // THERE DOES NOT EXIST
+ {"NotGreater", 0x0226F}, // NOT GREATER-THAN
+ {"NotGreaterEqual", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
+// "NotGreaterFullEqual", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
+// "NotGreaterGreater", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
+ {"NotGreaterLess", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
+// "NotGreaterSlantEqual", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
+ {"NotGreaterTilde", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
+// "NotHumpDownHump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
+// "NotHumpEqual", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
+ {"notin", 0x02209}, // NOT AN ELEMENT OF
+// "notindot", 0x022F5;0x00338}, // ELEMENT OF WITH DOT ABOVE with slash
+// "notinE", 0x022F9;0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash
+ {"notinva", 0x02209}, // NOT AN ELEMENT OF
+ {"notinvb", 0x022F7}, // SMALL ELEMENT OF WITH OVERBAR
+ {"notinvc", 0x022F6}, // ELEMENT OF WITH OVERBAR
+ {"NotLeftTriangle", 0x022EA}, // NOT NORMAL SUBGROUP OF
+// "NotLeftTriangleBar", 0x029CF;0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash
+ {"NotLeftTriangleEqual", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
+ {"NotLess", 0x0226E}, // NOT LESS-THAN
+ {"NotLessEqual", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
+ {"NotLessGreater", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN
+// "NotLessLess", 0x0226A;0x00338}, // MUCH LESS THAN with slash
+// "NotLessSlantEqual", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
+ {"NotLessTilde", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
+// "NotNestedGreaterGreater", 0x02AA2;0x00338}, // DOUBLE NESTED GREATER-THAN with slash
+// "NotNestedLessLess", 0x02AA1;0x00338}, // DOUBLE NESTED LESS-THAN with slash
+ {"notni", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
+ {"notniva", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
+ {"notnivb", 0x022FE}, // SMALL CONTAINS WITH OVERBAR
+ {"notnivc", 0x022FD}, // CONTAINS WITH OVERBAR
+ {"NotPrecedes", 0x02280}, // DOES NOT PRECEDE
+// "NotPrecedesEqual", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"NotPrecedesSlantEqual", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
+ {"NotReverseElement", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
+ {"NotRightTriangle", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
+// "NotRightTriangleBar", 0x029D0;0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash
+ {"NotRightTriangleEqual", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+// "NotSquareSubset", 0x0228F;0x00338}, // SQUARE IMAGE OF with slash
+ {"NotSquareSubsetEqual", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO
+// "NotSquareSuperset", 0x02290;0x00338}, // SQUARE ORIGINAL OF with slash
+ {"NotSquareSupersetEqual", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
+// "NotSubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
+ {"NotSubsetEqual", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
+ {"NotSucceeds", 0x02281}, // DOES NOT SUCCEED
+// "NotSucceedsEqual", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"NotSucceedsSlantEqual", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
+// "NotSucceedsTilde", 0x0227F;0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash
+// "NotSuperset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
+ {"NotSupersetEqual", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
+ {"NotTilde", 0x02241}, // NOT TILDE
+ {"NotTildeEqual", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
+ {"NotTildeFullEqual", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+ {"NotTildeTilde", 0x02249}, // NOT ALMOST EQUAL TO
+ {"NotVerticalBar", 0x02224}, // DOES NOT DIVIDE
+ {"npar", 0x02226}, // NOT PARALLEL TO
+ {"nparallel", 0x02226}, // NOT PARALLEL TO
+// "nparsl", 0x02AFD;0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash
+// "npart", 0x02202;0x00338}, // PARTIAL DIFFERENTIAL with slash
+ {"npolint", 0x02A14}, // LINE INTEGRATION NOT INCLUDING THE POLE
+ {"npr", 0x02280}, // DOES NOT PRECEDE
+ {"nprcue", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
+// "npre", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"nprec", 0x02280}, // DOES NOT PRECEDE
+// "npreceq", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"nrarr", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
+ {"nrArr", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
+// "nrarrc", 0x02933;0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash
+// "nrarrw", 0x0219D;0x00338}, // RIGHTWARDS WAVE ARROW with slash
+ {"nrightarrow", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
+ {"nRightarrow", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
+ {"nrtri", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
+ {"nrtrie", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+ {"nsc", 0x02281}, // DOES NOT SUCCEED
+ {"nsccue", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
+// "nsce", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"Nscr", 0x1D4A9}, // MATHEMATICAL SCRIPT CAPITAL N
+ {"nscr", 0x1D4C3}, // MATHEMATICAL SCRIPT SMALL N
+ {"nshortmid", 0x02224}, // DOES NOT DIVIDE
+ {"nshortparallel", 0x02226}, // NOT PARALLEL TO
+ {"nsim", 0x02241}, // NOT TILDE
+ {"nsime", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
+ {"nsimeq", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
+ {"nsmid", 0x02224}, // DOES NOT DIVIDE
+ {"nspar", 0x02226}, // NOT PARALLEL TO
+ {"nsqsube", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO
+ {"nsqsupe", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
+ {"nsub", 0x02284}, // NOT A SUBSET OF
+ {"nsube", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
+// "nsubE", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
+// "nsubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
+ {"nsubseteq", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
+// "nsubseteqq", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
+ {"nsucc", 0x02281}, // DOES NOT SUCCEED
+// "nsucceq", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"nsup", 0x02285}, // NOT A SUPERSET OF
+ {"nsupe", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
+// "nsupE", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
+// "nsupset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
+ {"nsupseteq", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
+// "nsupseteqq", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
+ {"ntgl", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
+ {"Ntilde", 0x000D1}, // LATIN CAPITAL LETTER N WITH TILDE
+ {"ntilde", 0x000F1}, // LATIN SMALL LETTER N WITH TILDE
+ {"ntlg", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN
+ {"ntriangleleft", 0x022EA}, // NOT NORMAL SUBGROUP OF
+ {"ntrianglelefteq", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
+ {"ntriangleright", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
+ {"ntrianglerighteq", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+ {"Nu", 0x0039D}, // GREEK CAPITAL LETTER NU
+ {"nu", 0x003BD}, // GREEK SMALL LETTER NU
+ {"num", 0x00023}, // NUMBER SIGN
+ {"numero", 0x02116}, // NUMERO SIGN
+ {"numsp", 0x02007}, // FIGURE SPACE
+// "nvap", 0x0224D;0x020D2}, // EQUIVALENT TO with vertical line
+ {"nvdash", 0x022AC}, // DOES NOT PROVE
+ {"nvDash", 0x022AD}, // NOT TRUE
+ {"nVdash", 0x022AE}, // DOES NOT FORCE
+ {"nVDash", 0x022AF}, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+// "nvge", 0x02265;0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line
+// "nvgt", 0x0003E;0x020D2}, // GREATER-THAN SIGN with vertical line
+ {"nvHarr", 0x02904}, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE
+ {"nvinfin", 0x029DE}, // INFINITY NEGATED WITH VERTICAL BAR
+ {"nvlArr", 0x02902}, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+// "nvle", 0x02264;0x020D2}, // LESS-THAN OR EQUAL TO with vertical line
+// "nvlt", 0x0003C;0x020D2}, // LESS-THAN SIGN with vertical line
+// "nvltrie", 0x022B4;0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line
+ {"nvrArr", 0x02903}, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+// "nvrtrie", 0x022B5;0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line
+// "nvsim", 0x0223C;0x020D2}, // TILDE OPERATOR with vertical line
+ {"nwarhk", 0x02923}, // NORTH WEST ARROW WITH HOOK
+ {"nwarr", 0x02196}, // NORTH WEST ARROW
+ {"nwArr", 0x021D6}, // NORTH WEST DOUBLE ARROW
+ {"nwarrow", 0x02196}, // NORTH WEST ARROW
+ {"nwnear", 0x02927}, // NORTH WEST ARROW AND NORTH EAST ARROW
+ {NULL, 0}
+};
+
+static NameId namesO[]={
+ {"Oacgr", 0x0038C}, // GREEK CAPITAL LETTER OMICRON WITH TONOS
+ {"oacgr", 0x003CC}, // GREEK SMALL LETTER OMICRON WITH TONOS
+ {"Oacute", 0x000D3}, // LATIN CAPITAL LETTER O WITH ACUTE
+ {"oacute", 0x000F3}, // LATIN SMALL LETTER O WITH ACUTE
+ {"oast", 0x0229B}, // CIRCLED ASTERISK OPERATOR
+ {"ocir", 0x0229A}, // CIRCLED RING OPERATOR
+ {"Ocirc", 0x000D4}, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ {"ocirc", 0x000F4}, // LATIN SMALL LETTER O WITH CIRCUMFLEX
+ {"Ocy", 0x0041E}, // CYRILLIC CAPITAL LETTER O
+ {"ocy", 0x0043E}, // CYRILLIC SMALL LETTER O
+ {"odash", 0x0229D}, // CIRCLED DASH
+ {"Odblac", 0x00150}, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+ {"odblac", 0x00151}, // LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ {"odiv", 0x02A38}, // CIRCLED DIVISION SIGN
+ {"odot", 0x02299}, // CIRCLED DOT OPERATOR
+ {"odsold", 0x029BC}, // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN
+ {"OElig", 0x00152}, // LATIN CAPITAL LIGATURE OE
+ {"oelig", 0x00153}, // LATIN SMALL LIGATURE OE
+ {"ofcir", 0x029BF}, // CIRCLED BULLET
+ {"Ofr", 0x1D512}, // MATHEMATICAL FRAKTUR CAPITAL O
+ {"ofr", 0x1D52C}, // MATHEMATICAL FRAKTUR SMALL O
+ {"ogon", 0x002DB}, // OGONEK
+ {"Ogr", 0x0039F}, // GREEK CAPITAL LETTER OMICRON
+ {"ogr", 0x003BF}, // GREEK SMALL LETTER OMICRON
+ {"Ograve", 0x000D2}, // LATIN CAPITAL LETTER O WITH GRAVE
+ {"ograve", 0x000F2}, // LATIN SMALL LETTER O WITH GRAVE
+ {"ogt", 0x029C1}, // CIRCLED GREATER-THAN
+ {"OHacgr", 0x0038F}, // GREEK CAPITAL LETTER OMEGA WITH TONOS
+ {"ohacgr", 0x003CE}, // GREEK SMALL LETTER OMEGA WITH TONOS
+ {"ohbar", 0x029B5}, // CIRCLE WITH HORIZONTAL BAR
+ {"OHgr", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
+ {"ohgr", 0x003C9}, // GREEK SMALL LETTER OMEGA
+ {"ohm", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
+ {"oint", 0x0222E}, // CONTOUR INTEGRAL
+ {"olarr", 0x021BA}, // ANTICLOCKWISE OPEN CIRCLE ARROW
+ {"olcir", 0x029BE}, // CIRCLED WHITE BULLET
+ {"olcross", 0x029BB}, // CIRCLE WITH SUPERIMPOSED X
+ {"oline", 0x0203E}, // OVERLINE
+ {"olt", 0x029C0}, // CIRCLED LESS-THAN
+ {"Omacr", 0x0014C}, // LATIN CAPITAL LETTER O WITH MACRON
+ {"omacr", 0x0014D}, // LATIN SMALL LETTER O WITH MACRON
+ {"Omega", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
+ {"omega", 0x003C9}, // GREEK SMALL LETTER OMEGA
+ {"Omicron", 0x0039F}, // GREEK CAPITAL LETTER OMICRON
+ {"omicron", 0x003BF}, // GREEK SMALL LETTER OMICRON
+ {"omid", 0x029B6}, // CIRCLED VERTICAL BAR
+ {"ominus", 0x02296}, // CIRCLED MINUS
+ {"Oopf", 0x1D546}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+ {"oopf", 0x1D560}, // MATHEMATICAL DOUBLE-STRUCK SMALL O
+ {"opar", 0x029B7}, // CIRCLED PARALLEL
+ {"OpenCurlyDoubleQuote", 0x0201C}, // LEFT DOUBLE QUOTATION MARK
+ {"OpenCurlyQuote", 0x02018}, // LEFT SINGLE QUOTATION MARK
+ {"operp", 0x029B9}, // CIRCLED PERPENDICULAR
+ {"oplus", 0x02295}, // CIRCLED PLUS
+ {"or", 0x02228}, // LOGICAL OR
+ {"Or", 0x02A54}, // DOUBLE LOGICAL OR
+ {"orarr", 0x021BB}, // CLOCKWISE OPEN CIRCLE ARROW
+ {"ord", 0x02A5D}, // LOGICAL OR WITH HORIZONTAL DASH
+ {"order", 0x02134}, // SCRIPT SMALL O
+ {"orderof", 0x02134}, // SCRIPT SMALL O
+ {"ordf", 0x000AA}, // FEMININE ORDINAL INDICATOR
+ {"ordm", 0x000BA}, // MASCULINE ORDINAL INDICATOR
+ {"origof", 0x022B6}, // ORIGINAL OF
+ {"oror", 0x02A56}, // TWO INTERSECTING LOGICAL OR
+ {"orslope", 0x02A57}, // SLOPING LARGE OR
+ {"orv", 0x02A5B}, // LOGICAL OR WITH MIDDLE STEM
+ {"oS", 0x024C8}, // CIRCLED LATIN CAPITAL LETTER S
+ {"oscr", 0x02134}, // SCRIPT SMALL O
+ {"Oscr", 0x1D4AA}, // MATHEMATICAL SCRIPT CAPITAL O
+ {"Oslash", 0x000D8}, // LATIN CAPITAL LETTER O WITH STROKE
+ {"oslash", 0x000F8}, // LATIN SMALL LETTER O WITH STROKE
+ {"osol", 0x02298}, // CIRCLED DIVISION SLASH
+ {"Otilde", 0x000D5}, // LATIN CAPITAL LETTER O WITH TILDE
+ {"otilde", 0x000F5}, // LATIN SMALL LETTER O WITH TILDE
+ {"otimes", 0x02297}, // CIRCLED TIMES
+ {"Otimes", 0x02A37}, // MULTIPLICATION SIGN IN DOUBLE CIRCLE
+ {"otimesas", 0x02A36}, // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT
+ {"Ouml", 0x000D6}, // LATIN CAPITAL LETTER O WITH DIAERESIS
+ {"ouml", 0x000F6}, // LATIN SMALL LETTER O WITH DIAERESIS
+ {"ovbar", 0x0233D}, // APL FUNCTIONAL SYMBOL CIRCLE STILE
+ {"OverBar", 0x0203E}, // OVERLINE
+ {"OverBrace", 0x023DE}, // TOP CURLY BRACKET
+ {"OverBracket", 0x023B4}, // TOP SQUARE BRACKET
+ {"OverParenthesis", 0x023DC}, // TOP PARENTHESIS
+ {NULL, 0}
+};
+
+static NameId namesP[]={
+ {"par", 0x02225}, // PARALLEL TO
+ {"para", 0x000B6}, // PILCROW SIGN
+ {"parallel", 0x02225}, // PARALLEL TO
+ {"parsim", 0x02AF3}, // PARALLEL WITH TILDE OPERATOR
+ {"parsl", 0x02AFD}, // DOUBLE SOLIDUS OPERATOR
+ {"part", 0x02202}, // PARTIAL DIFFERENTIAL
+ {"PartialD", 0x02202}, // PARTIAL DIFFERENTIAL
+ {"Pcy", 0x0041F}, // CYRILLIC CAPITAL LETTER PE
+ {"pcy", 0x0043F}, // CYRILLIC SMALL LETTER PE
+ {"percnt", 0x00025}, // PERCENT SIGN
+ {"period", 0x0002E}, // FULL STOP
+ {"permil", 0x02030}, // PER MILLE SIGN
+ {"perp", 0x022A5}, // UP TACK
+ {"pertenk", 0x02031}, // PER TEN THOUSAND SIGN
+ {"Pfr", 0x1D513}, // MATHEMATICAL FRAKTUR CAPITAL P
+ {"pfr", 0x1D52D}, // MATHEMATICAL FRAKTUR SMALL P
+ {"Pgr", 0x003A0}, // GREEK CAPITAL LETTER PI
+ {"pgr", 0x003C0}, // GREEK SMALL LETTER PI
+ {"PHgr", 0x003A6}, // GREEK CAPITAL LETTER PHI
+ {"phgr", 0x003C6}, // GREEK SMALL LETTER PHI
+ {"Phi", 0x003A6}, // GREEK CAPITAL LETTER PHI
+ {"phi", 0x003C6}, // GREEK SMALL LETTER PHI
+ {"phiv", 0x003D5}, // GREEK PHI SYMBOL
+ {"phmmat", 0x02133}, // SCRIPT CAPITAL M
+ {"phone", 0x0260E}, // BLACK TELEPHONE
+ {"Pi", 0x003A0}, // GREEK CAPITAL LETTER PI
+ {"pi", 0x003C0}, // GREEK SMALL LETTER PI
+ {"pitchfork", 0x022D4}, // PITCHFORK
+ {"piv", 0x003D6}, // GREEK PI SYMBOL
+ {"planck", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"planckh", 0x0210E}, // PLANCK CONSTANT
+ {"plankv", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"plus", 0x0002B}, // PLUS SIGN
+ {"plusacir", 0x02A23}, // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE
+ {"plusb", 0x0229E}, // SQUARED PLUS
+ {"pluscir", 0x02A22}, // PLUS SIGN WITH SMALL CIRCLE ABOVE
+ {"plusdo", 0x02214}, // DOT PLUS
+ {"plusdu", 0x02A25}, // PLUS SIGN WITH DOT BELOW
+ {"pluse", 0x02A72}, // PLUS SIGN ABOVE EQUALS SIGN
+ {"PlusMinus", 0x000B1}, // PLUS-MINUS SIGN
+ {"plusmn", 0x000B1}, // PLUS-MINUS SIGN
+ {"plussim", 0x02A26}, // PLUS SIGN WITH TILDE BELOW
+ {"plustwo", 0x02A27}, // PLUS SIGN WITH SUBSCRIPT TWO
+ {"pm", 0x000B1}, // PLUS-MINUS SIGN
+ {"Poincareplane", 0x0210C}, // BLACK-LETTER CAPITAL H
+ {"pointint", 0x02A15}, // INTEGRAL AROUND A POINT OPERATOR
+ {"Popf", 0x02119}, // DOUBLE-STRUCK CAPITAL P
+ {"popf", 0x1D561}, // MATHEMATICAL DOUBLE-STRUCK SMALL P
+ {"pound", 0x000A3}, // POUND SIGN
+ {"pr", 0x0227A}, // PRECEDES
+ {"Pr", 0x02ABB}, // DOUBLE PRECEDES
+ {"prap", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO
+ {"prcue", 0x0227C}, // PRECEDES OR EQUAL TO
+ {"pre", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+ {"prE", 0x02AB3}, // PRECEDES ABOVE EQUALS SIGN
+ {"prec", 0x0227A}, // PRECEDES
+ {"precapprox", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO
+ {"preccurlyeq", 0x0227C}, // PRECEDES OR EQUAL TO
+ {"Precedes", 0x0227A}, // PRECEDES
+ {"PrecedesEqual", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+ {"PrecedesSlantEqual", 0x0227C}, // PRECEDES OR EQUAL TO
+ {"PrecedesTilde", 0x0227E}, // PRECEDES OR EQUIVALENT TO
+ {"preceq", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+ {"precnapprox", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO
+ {"precneqq", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO
+ {"precnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO
+ {"precsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO
+ {"prime", 0x02032}, // PRIME
+ {"Prime", 0x02033}, // DOUBLE PRIME
+ {"primes", 0x02119}, // DOUBLE-STRUCK CAPITAL P
+ {"prnap", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO
+ {"prnE", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO
+ {"prnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO
+ {"prod", 0x0220F}, // N-ARY PRODUCT
+ {"Product", 0x0220F}, // N-ARY PRODUCT
+ {"profalar", 0x0232E}, // ALL AROUND-PROFILE
+ {"profline", 0x02312}, // ARC
+ {"profsurf", 0x02313}, // SEGMENT
+ {"prop", 0x0221D}, // PROPORTIONAL TO
+ {"Proportion", 0x02237}, // PROPORTION
+ {"Proportional", 0x0221D}, // PROPORTIONAL TO
+ {"propto", 0x0221D}, // PROPORTIONAL TO
+ {"prsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO
+ {"prurel", 0x022B0}, // PRECEDES UNDER RELATION
+ {"Pscr", 0x1D4AB}, // MATHEMATICAL SCRIPT CAPITAL P
+ {"pscr", 0x1D4C5}, // MATHEMATICAL SCRIPT SMALL P
+ {"PSgr", 0x003A8}, // GREEK CAPITAL LETTER PSI
+ {"psgr", 0x003C8}, // GREEK SMALL LETTER PSI
+ {"Psi", 0x003A8}, // GREEK CAPITAL LETTER PSI
+ {"psi", 0x003C8}, // GREEK SMALL LETTER PSI
+ {"puncsp", 0x02008}, // PUNCTUATION SPACE
+ {NULL, 0}
+};
+
+static NameId namesQ[]={
+ {"Qfr", 0x1D514}, // MATHEMATICAL FRAKTUR CAPITAL Q
+ {"qfr", 0x1D52E}, // MATHEMATICAL FRAKTUR SMALL Q
+ {"qint", 0x02A0C}, // QUADRUPLE INTEGRAL OPERATOR
+ {"Qopf", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q
+ {"qopf", 0x1D562}, // MATHEMATICAL DOUBLE-STRUCK SMALL Q
+ {"qprime", 0x02057}, // QUADRUPLE PRIME
+ {"Qscr", 0x1D4AC}, // MATHEMATICAL SCRIPT CAPITAL Q
+ {"qscr", 0x1D4C6}, // MATHEMATICAL SCRIPT SMALL Q
+ {"quaternions", 0x0210D}, // DOUBLE-STRUCK CAPITAL H
+ {"quatint", 0x02A16}, // QUATERNION INTEGRAL OPERATOR
+ {"quest", 0x0003F}, // QUESTION MARK
+ {"questeq", 0x0225F}, // QUESTIONED EQUAL TO
+ {"quot", 0x00022}, // QUOTATION MARK
+ {"QUOT", 0x00022}, // QUOTATION MARK
+ {NULL, 0}
+};
+
+static NameId namesR[]={
+ {"rAarr", 0x021DB}, // RIGHTWARDS TRIPLE ARROW
+// "race", 0x0223D;0x00331}, // REVERSED TILDE with underline
+ {"Racute", 0x00154}, // LATIN CAPITAL LETTER R WITH ACUTE
+ {"racute", 0x00155}, // LATIN SMALL LETTER R WITH ACUTE
+ {"radic", 0x0221A}, // SQUARE ROOT
+ {"raemptyv", 0x029B3}, // EMPTY SET WITH RIGHT ARROW ABOVE
+ {"rang", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ {"Rang", 0x027EB}, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+ {"rangd", 0x02992}, // RIGHT ANGLE BRACKET WITH DOT
+ {"range", 0x029A5}, // REVERSED ANGLE WITH UNDERBAR
+ {"rangle", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ {"raquo", 0x000BB}, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {"rarr", 0x02192}, // RIGHTWARDS ARROW
+ {"Rarr", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW
+ {"rArr", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"rarrap", 0x02975}, // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO
+ {"rarrb", 0x021E5}, // RIGHTWARDS ARROW TO BAR
+ {"rarrbfs", 0x02920}, // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND
+ {"rarrc", 0x02933}, // WAVE ARROW POINTING DIRECTLY RIGHT
+ {"rarrfs", 0x0291E}, // RIGHTWARDS ARROW TO BLACK DIAMOND
+ {"rarrhk", 0x021AA}, // RIGHTWARDS ARROW WITH HOOK
+ {"rarrlp", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP
+ {"rarrpl", 0x02945}, // RIGHTWARDS ARROW WITH PLUS BELOW
+ {"rarrsim", 0x02974}, // RIGHTWARDS ARROW ABOVE TILDE OPERATOR
+ {"rarrtl", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL
+ {"Rarrtl", 0x02916}, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL
+ {"rarrw", 0x0219D}, // RIGHTWARDS WAVE ARROW
+ {"ratail", 0x0291A}, // RIGHTWARDS ARROW-TAIL
+ {"rAtail", 0x0291C}, // RIGHTWARDS DOUBLE ARROW-TAIL
+ {"ratio", 0x02236}, // RATIO
+ {"rationals", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q
+ {"rbarr", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW
+ {"rBarr", 0x0290F}, // RIGHTWARDS TRIPLE DASH ARROW
+ {"RBarr", 0x02910}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
+ {"rbbrk", 0x02773}, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+ {"rbrace", 0x0007D}, // RIGHT CURLY BRACKET
+ {"rbrack", 0x0005D}, // RIGHT SQUARE BRACKET
+ {"rbrke", 0x0298C}, // RIGHT SQUARE BRACKET WITH UNDERBAR
+ {"rbrksld", 0x0298E}, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {"rbrkslu", 0x02990}, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {"Rcaron", 0x00158}, // LATIN CAPITAL LETTER R WITH CARON
+ {"rcaron", 0x00159}, // LATIN SMALL LETTER R WITH CARON
+ {"Rcedil", 0x00156}, // LATIN CAPITAL LETTER R WITH CEDILLA
+ {"rcedil", 0x00157}, // LATIN SMALL LETTER R WITH CEDILLA
+ {"rceil", 0x02309}, // RIGHT CEILING
+ {"rcub", 0x0007D}, // RIGHT CURLY BRACKET
+ {"Rcy", 0x00420}, // CYRILLIC CAPITAL LETTER ER
+ {"rcy", 0x00440}, // CYRILLIC SMALL LETTER ER
+ {"rdca", 0x02937}, // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS
+ {"rdldhar", 0x02969}, // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+ {"rdquo", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
+ {"rdquor", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
+ {"rdsh", 0x021B3}, // DOWNWARDS ARROW WITH TIP RIGHTWARDS
+ {"Re", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"real", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"realine", 0x0211B}, // SCRIPT CAPITAL R
+ {"realpart", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"reals", 0x0211D}, // DOUBLE-STRUCK CAPITAL R
+ {"rect", 0x025AD}, // WHITE RECTANGLE
+ {"reg", 0x000AE}, // REGISTERED SIGN
+ {"REG", 0x000AE}, // REGISTERED SIGN
+ {"ReverseElement", 0x0220B}, // CONTAINS AS MEMBER
+ {"ReverseEquilibrium", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+ {"ReverseUpEquilibrium", 0x0296F}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ {"rfisht", 0x0297D}, // RIGHT FISH TAIL
+ {"rfloor", 0x0230B}, // RIGHT FLOOR
+ {"Rfr", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"rfr", 0x1D52F}, // MATHEMATICAL FRAKTUR SMALL R
+ {"Rgr", 0x003A1}, // GREEK CAPITAL LETTER RHO
+ {"rgr", 0x003C1}, // GREEK SMALL LETTER RHO
+ {"rHar", 0x02964}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+ {"rhard", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+ {"rharu", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
+ {"rharul", 0x0296C}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+ {"Rho", 0x003A1}, // GREEK CAPITAL LETTER RHO
+ {"rho", 0x003C1}, // GREEK SMALL LETTER RHO
+ {"rhov", 0x003F1}, // GREEK RHO SYMBOL
+ {"RightAngleBracket", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ {"rightarrow", 0x02192}, // RIGHTWARDS ARROW
+ {"RightArrow", 0x02192}, // RIGHTWARDS ARROW
+ {"Rightarrow", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"RightArrowBar", 0x021E5}, // RIGHTWARDS ARROW TO BAR
+ {"RightArrowLeftArrow", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+ {"rightarrowtail", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL
+ {"RightCeiling", 0x02309}, // RIGHT CEILING
+ {"RightDoubleBracket", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ {"RightDownTeeVector", 0x0295D}, // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR
+ {"RightDownVector", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+ {"RightDownVectorBar", 0x02955}, // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR
+ {"RightFloor", 0x0230B}, // RIGHT FLOOR
+ {"rightharpoondown", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+ {"rightharpoonup", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
+ {"rightleftarrows", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+ {"rightleftharpoons", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+ {"rightrightarrows", 0x021C9}, // RIGHTWARDS PAIRED ARROWS
+ {"rightsquigarrow", 0x0219D}, // RIGHTWARDS WAVE ARROW
+ {"RightTee", 0x022A2}, // RIGHT TACK
+ {"RightTeeArrow", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
+ {"RightTeeVector", 0x0295B}, // RIGHTWARDS HARPOON WITH BARB UP FROM BAR
+ {"rightthreetimes", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT
+ {"RightTriangle", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
+ {"RightTriangleBar", 0x029D0}, // VERTICAL BAR BESIDE RIGHT TRIANGLE
+ {"RightTriangleEqual", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+ {"RightUpDownVector", 0x0294F}, // UP BARB RIGHT DOWN BARB RIGHT HARPOON
+ {"RightUpTeeVector", 0x0295C}, // UPWARDS HARPOON WITH BARB RIGHT FROM BAR
+ {"RightUpVector", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
+ {"RightUpVectorBar", 0x02954}, // UPWARDS HARPOON WITH BARB RIGHT TO BAR
+ {"RightVector", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
+ {"RightVectorBar", 0x02953}, // RIGHTWARDS HARPOON WITH BARB UP TO BAR
+ {"ring", 0x002DA}, // RING ABOVE
+ {"risingdotseq", 0x02253}, // IMAGE OF OR APPROXIMATELY EQUAL TO
+ {"rlarr", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+ {"rlhar", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+ {"rlm", 0x0200F}, // RIGHT-TO-LEFT MARK
+ {"rmoust", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
+ {"rmoustache", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
+ {"rnmid", 0x02AEE}, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH
+ {"roang", 0x027ED}, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+ {"roarr", 0x021FE}, // RIGHTWARDS OPEN-HEADED ARROW
+ {"robrk", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ {"ropar", 0x02986}, // RIGHT WHITE PARENTHESIS
+ {"Ropf", 0x0211D}, // DOUBLE-STRUCK CAPITAL R
+ {"ropf", 0x1D563}, // MATHEMATICAL DOUBLE-STRUCK SMALL R
+ {"roplus", 0x02A2E}, // PLUS SIGN IN RIGHT HALF CIRCLE
+ {"rotimes", 0x02A35}, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE
+ {"RoundImplies", 0x02970}, // RIGHT DOUBLE ARROW WITH ROUNDED HEAD
+ {"rpar", 0x00029}, // RIGHT PARENTHESIS
+ {"rpargt", 0x02994}, // RIGHT ARC GREATER-THAN BRACKET
+ {"rppolint", 0x02A12}, // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE
+ {"rrarr", 0x021C9}, // RIGHTWARDS PAIRED ARROWS
+ {"Rrightarrow", 0x021DB}, // RIGHTWARDS TRIPLE ARROW
+ {"rsaquo", 0x0203A}, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ {"Rscr", 0x0211B}, // SCRIPT CAPITAL R
+ {"rscr", 0x1D4C7}, // MATHEMATICAL SCRIPT SMALL R
+ {"rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS
+ {"Rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS
+ {"rsqb", 0x0005D}, // RIGHT SQUARE BRACKET
+ {"rsquo", 0x02019}, // RIGHT SINGLE QUOTATION MARK
+ {"rsquor", 0x02019}, // RIGHT SINGLE QUOTATION MARK
+ {"rthree", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT
+ {"rtimes", 0x022CA}, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
+ {"rtri", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE
+ {"rtrie", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+ {"rtrif", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE
+ {"rtriltri", 0x029CE}, // RIGHT TRIANGLE ABOVE LEFT TRIANGLE
+ {"RuleDelayed", 0x029F4}, // RULE-DELAYED
+ {"ruluhar", 0x02968}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP
+ {"rx", 0x0211E}, // PRESCRIPTION TAKE
+ {NULL, 0}
+};
+
+static NameId namesS[]={
+ {"Sacute", 0x0015A}, // LATIN CAPITAL LETTER S WITH ACUTE
+ {"sacute", 0x0015B}, // LATIN SMALL LETTER S WITH ACUTE
+ {"sbquo", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK
+ {"sc", 0x0227B}, // SUCCEEDS
+ {"Sc", 0x02ABC}, // DOUBLE SUCCEEDS
+ {"scap", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO
+ {"Scaron", 0x00160}, // LATIN CAPITAL LETTER S WITH CARON
+ {"scaron", 0x00161}, // LATIN SMALL LETTER S WITH CARON
+ {"sccue", 0x0227D}, // SUCCEEDS OR EQUAL TO
+ {"sce", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+ {"scE", 0x02AB4}, // SUCCEEDS ABOVE EQUALS SIGN
+ {"Scedil", 0x0015E}, // LATIN CAPITAL LETTER S WITH CEDILLA
+ {"scedil", 0x0015F}, // LATIN SMALL LETTER S WITH CEDILLA
+ {"Scirc", 0x0015C}, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+ {"scirc", 0x0015D}, // LATIN SMALL LETTER S WITH CIRCUMFLEX
+ {"scnap", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
+ {"scnE", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO
+ {"scnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO
+ {"scpolint", 0x02A13}, // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE
+ {"scsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
+ {"Scy", 0x00421}, // CYRILLIC CAPITAL LETTER ES
+ {"scy", 0x00441}, // CYRILLIC SMALL LETTER ES
+ {"sdot", 0x022C5}, // DOT OPERATOR
+ {"sdotb", 0x022A1}, // SQUARED DOT OPERATOR
+ {"sdote", 0x02A66}, // EQUALS SIGN WITH DOT BELOW
+ {"searhk", 0x02925}, // SOUTH EAST ARROW WITH HOOK
+ {"searr", 0x02198}, // SOUTH EAST ARROW
+ {"seArr", 0x021D8}, // SOUTH EAST DOUBLE ARROW
+ {"searrow", 0x02198}, // SOUTH EAST ARROW
+ {"sect", 0x000A7}, // SECTION SIGN
+ {"semi", 0x0003B}, // SEMICOLON
+ {"seswar", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW
+ {"setminus", 0x02216}, // SET MINUS
+ {"setmn", 0x02216}, // SET MINUS
+ {"sext", 0x02736}, // SIX POINTED BLACK STAR
+ {"sfgr", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+ {"Sfr", 0x1D516}, // MATHEMATICAL FRAKTUR CAPITAL S
+ {"sfr", 0x1D530}, // MATHEMATICAL FRAKTUR SMALL S
+ {"sfrown", 0x02322}, // FROWN
+ {"Sgr", 0x003A3}, // GREEK CAPITAL LETTER SIGMA
+ {"sgr", 0x003C3}, // GREEK SMALL LETTER SIGMA
+ {"sharp", 0x0266F}, // MUSIC SHARP SIGN
+ {"SHCHcy", 0x00429}, // CYRILLIC CAPITAL LETTER SHCHA
+ {"shchcy", 0x00449}, // CYRILLIC SMALL LETTER SHCHA
+ {"SHcy", 0x00428}, // CYRILLIC CAPITAL LETTER SHA
+ {"shcy", 0x00448}, // CYRILLIC SMALL LETTER SHA
+ {"ShortDownArrow", 0x02193}, // DOWNWARDS ARROW
+ {"ShortLeftArrow", 0x02190}, // LEFTWARDS ARROW
+ {"shortmid", 0x02223}, // DIVIDES
+ {"shortparallel", 0x02225}, // PARALLEL TO
+ {"ShortRightArrow", 0x02192}, // RIGHTWARDS ARROW
+ {"ShortUpArrow", 0x02191}, // UPWARDS ARROW
+ {"shy", 0x000AD}, // SOFT HYPHEN
+ {"Sigma", 0x003A3}, // GREEK CAPITAL LETTER SIGMA
+ {"sigma", 0x003C3}, // GREEK SMALL LETTER SIGMA
+ {"sigmaf", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+ {"sigmav", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+ {"sim", 0x0223C}, // TILDE OPERATOR
+ {"simdot", 0x02A6A}, // TILDE OPERATOR WITH DOT ABOVE
+ {"sime", 0x02243}, // ASYMPTOTICALLY EQUAL TO
+ {"simeq", 0x02243}, // ASYMPTOTICALLY EQUAL TO
+ {"simg", 0x02A9E}, // SIMILAR OR GREATER-THAN
+ {"simgE", 0x02AA0}, // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN
+ {"siml", 0x02A9D}, // SIMILAR OR LESS-THAN
+ {"simlE", 0x02A9F}, // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN
+ {"simne", 0x02246}, // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO
+ {"simplus", 0x02A24}, // PLUS SIGN WITH TILDE ABOVE
+ {"simrarr", 0x02972}, // TILDE OPERATOR ABOVE RIGHTWARDS ARROW
+ {"slarr", 0x02190}, // LEFTWARDS ARROW
+ {"SmallCircle", 0x02218}, // RING OPERATOR
+ {"smallsetminus", 0x02216}, // SET MINUS
+ {"smashp", 0x02A33}, // SMASH PRODUCT
+ {"smeparsl", 0x029E4}, // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE
+ {"smid", 0x02223}, // DIVIDES
+ {"smile", 0x02323}, // SMILE
+ {"smt", 0x02AAA}, // SMALLER THAN
+ {"smte", 0x02AAC}, // SMALLER THAN OR EQUAL TO
+// "smtes", 0x02AAC;0x0FE00}, // SMALLER THAN OR slanted EQUAL
+ {"SOFTcy", 0x0042C}, // CYRILLIC CAPITAL LETTER SOFT SIGN
+ {"softcy", 0x0044C}, // CYRILLIC SMALL LETTER SOFT SIGN
+ {"sol", 0x0002F}, // SOLIDUS
+ {"solb", 0x029C4}, // SQUARED RISING DIAGONAL SLASH
+ {"solbar", 0x0233F}, // APL FUNCTIONAL SYMBOL SLASH BAR
+ {"Sopf", 0x1D54A}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL S
+ {"sopf", 0x1D564}, // MATHEMATICAL DOUBLE-STRUCK SMALL S
+ {"spades", 0x02660}, // BLACK SPADE SUIT
+ {"spadesuit", 0x02660}, // BLACK SPADE SUIT
+ {"spar", 0x02225}, // PARALLEL TO
+ {"sqcap", 0x02293}, // SQUARE CAP
+// "sqcaps", 0x02293;0x0FE00}, // SQUARE CAP with serifs
+ {"sqcup", 0x02294}, // SQUARE CUP
+// "sqcups", 0x02294;0x0FE00}, // SQUARE CUP with serifs
+ {"Sqrt", 0x0221A}, // SQUARE ROOT
+ {"sqsub", 0x0228F}, // SQUARE IMAGE OF
+ {"sqsube", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
+ {"sqsubset", 0x0228F}, // SQUARE IMAGE OF
+ {"sqsubseteq", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
+ {"sqsup", 0x02290}, // SQUARE ORIGINAL OF
+ {"sqsupe", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
+ {"sqsupset", 0x02290}, // SQUARE ORIGINAL OF
+ {"sqsupseteq", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
+ {"squ", 0x025A1}, // WHITE SQUARE
+ {"square", 0x025A1}, // WHITE SQUARE
+ {"Square", 0x025A1}, // WHITE SQUARE
+ {"SquareIntersection", 0x02293}, // SQUARE CAP
+ {"SquareSubset", 0x0228F}, // SQUARE IMAGE OF
+ {"SquareSubsetEqual", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
+ {"SquareSuperset", 0x02290}, // SQUARE ORIGINAL OF
+ {"SquareSupersetEqual", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
+ {"SquareUnion", 0x02294}, // SQUARE CUP
+ {"squarf", 0x025AA}, // BLACK SMALL SQUARE
+ {"squf", 0x025AA}, // BLACK SMALL SQUARE
+ {"srarr", 0x02192}, // RIGHTWARDS ARROW
+ {"Sscr", 0x1D4AE}, // MATHEMATICAL SCRIPT CAPITAL S
+ {"sscr", 0x1D4C8}, // MATHEMATICAL SCRIPT SMALL S
+ {"ssetmn", 0x02216}, // SET MINUS
+ {"ssmile", 0x02323}, // SMILE
+ {"sstarf", 0x022C6}, // STAR OPERATOR
+ {"Star", 0x022C6}, // STAR OPERATOR
+ {"star", 0x02606}, // WHITE STAR
+ {"starf", 0x02605}, // BLACK STAR
+ {"straightepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
+ {"straightphi", 0x003D5}, // GREEK PHI SYMBOL
+ {"strns", 0x000AF}, // MACRON
+ {"sub", 0x02282}, // SUBSET OF
+ {"Sub", 0x022D0}, // DOUBLE SUBSET
+ {"subdot", 0x02ABD}, // SUBSET WITH DOT
+ {"sube", 0x02286}, // SUBSET OF OR EQUAL TO
+ {"subE", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN
+ {"subedot", 0x02AC3}, // SUBSET OF OR EQUAL TO WITH DOT ABOVE
+ {"submult", 0x02AC1}, // SUBSET WITH MULTIPLICATION SIGN BELOW
+ {"subne", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO
+ {"subnE", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO
+ {"subplus", 0x02ABF}, // SUBSET WITH PLUS SIGN BELOW
+ {"subrarr", 0x02979}, // SUBSET ABOVE RIGHTWARDS ARROW
+ {"subset", 0x02282}, // SUBSET OF
+ {"Subset", 0x022D0}, // DOUBLE SUBSET
+ {"subseteq", 0x02286}, // SUBSET OF OR EQUAL TO
+ {"subseteqq", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN
+ {"SubsetEqual", 0x02286}, // SUBSET OF OR EQUAL TO
+ {"subsetneq", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO
+ {"subsetneqq", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO
+ {"subsim", 0x02AC7}, // SUBSET OF ABOVE TILDE OPERATOR
+ {"subsub", 0x02AD5}, // SUBSET ABOVE SUBSET
+ {"subsup", 0x02AD3}, // SUBSET ABOVE SUPERSET
+ {"succ", 0x0227B}, // SUCCEEDS
+ {"succapprox", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO
+ {"succcurlyeq", 0x0227D}, // SUCCEEDS OR EQUAL TO
+ {"Succeeds", 0x0227B}, // SUCCEEDS
+ {"SucceedsEqual", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+ {"SucceedsSlantEqual", 0x0227D}, // SUCCEEDS OR EQUAL TO
+ {"SucceedsTilde", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
+ {"succeq", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+ {"succnapprox", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
+ {"succneqq", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO
+ {"succnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO
+ {"succsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
+ {"SuchThat", 0x0220B}, // CONTAINS AS MEMBER
+ {"sum", 0x02211}, // N-ARY SUMMATION
+ {"Sum", 0x02211}, // N-ARY SUMMATION
+ {"sung", 0x0266A}, // EIGHTH NOTE
+ {"sup", 0x02283}, // SUPERSET OF
+ {"Sup", 0x022D1}, // DOUBLE SUPERSET
+ {"sup1", 0x000B9}, // SUPERSCRIPT ONE
+ {"sup2", 0x000B2}, // SUPERSCRIPT TWO
+ {"sup3", 0x000B3}, // SUPERSCRIPT THREE
+ {"supdot", 0x02ABE}, // SUPERSET WITH DOT
+ {"supdsub", 0x02AD8}, // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET
+ {"supe", 0x02287}, // SUPERSET OF OR EQUAL TO
+ {"supE", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN
+ {"supedot", 0x02AC4}, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE
+ {"Superset", 0x02283}, // SUPERSET OF
+ {"SupersetEqual", 0x02287}, // SUPERSET OF OR EQUAL TO
+ {"suphsol", 0x027C9}, // SUPERSET PRECEDING SOLIDUS
+ {"suphsub", 0x02AD7}, // SUPERSET BESIDE SUBSET
+ {"suplarr", 0x0297B}, // SUPERSET ABOVE LEFTWARDS ARROW
+ {"supmult", 0x02AC2}, // SUPERSET WITH MULTIPLICATION SIGN BELOW
+ {"supne", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO
+ {"supnE", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO
+ {"supplus", 0x02AC0}, // SUPERSET WITH PLUS SIGN BELOW
+ {"supset", 0x02283}, // SUPERSET OF
+ {"Supset", 0x022D1}, // DOUBLE SUPERSET
+ {"supseteq", 0x02287}, // SUPERSET OF OR EQUAL TO
+ {"supseteqq", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN
+ {"supsetneq", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO
+ {"supsetneqq", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO
+ {"supsim", 0x02AC8}, // SUPERSET OF ABOVE TILDE OPERATOR
+ {"supsub", 0x02AD4}, // SUPERSET ABOVE SUBSET
+ {"supsup", 0x02AD6}, // SUPERSET ABOVE SUPERSET
+ {"swarhk", 0x02926}, // SOUTH WEST ARROW WITH HOOK
+ {"swarr", 0x02199}, // SOUTH WEST ARROW
+ {"swArr", 0x021D9}, // SOUTH WEST DOUBLE ARROW
+ {"swarrow", 0x02199}, // SOUTH WEST ARROW
+ {"swnwar", 0x0292A}, // SOUTH WEST ARROW AND NORTH WEST ARROW
+ {"szlig", 0x000DF}, // LATIN SMALL LETTER SHARP S
+ {NULL, 0}
+};
+
+static NameId namesT[]={
+ {"Tab", 0x00009}, // CHARACTER TABULATION
+ {"target", 0x02316}, // POSITION INDICATOR
+ {"Tau", 0x003A4}, // GREEK CAPITAL LETTER TAU
+ {"tau", 0x003C4}, // GREEK SMALL LETTER TAU
+ {"tbrk", 0x023B4}, // TOP SQUARE BRACKET
+ {"Tcaron", 0x00164}, // LATIN CAPITAL LETTER T WITH CARON
+ {"tcaron", 0x00165}, // LATIN SMALL LETTER T WITH CARON
+ {"Tcedil", 0x00162}, // LATIN CAPITAL LETTER T WITH CEDILLA
+ {"tcedil", 0x00163}, // LATIN SMALL LETTER T WITH CEDILLA
+ {"Tcy", 0x00422}, // CYRILLIC CAPITAL LETTER TE
+ {"tcy", 0x00442}, // CYRILLIC SMALL LETTER TE
+ {"tdot", 0x020DB}, // COMBINING THREE DOTS ABOVE
+ {"telrec", 0x02315}, // TELEPHONE RECORDER
+ {"Tfr", 0x1D517}, // MATHEMATICAL FRAKTUR CAPITAL T
+ {"tfr", 0x1D531}, // MATHEMATICAL FRAKTUR SMALL T
+ {"Tgr", 0x003A4}, // GREEK CAPITAL LETTER TAU
+ {"tgr", 0x003C4}, // GREEK SMALL LETTER TAU
+ {"there4", 0x02234}, // THEREFORE
+ {"therefore", 0x02234}, // THEREFORE
+ {"Therefore", 0x02234}, // THEREFORE
+ {"Theta", 0x00398}, // GREEK CAPITAL LETTER THETA
+ {"theta", 0x003B8}, // GREEK SMALL LETTER THETA
+ {"thetasym", 0x003D1}, // GREEK THETA SYMBOL
+ {"thetav", 0x003D1}, // GREEK THETA SYMBOL
+ {"THgr", 0x00398}, // GREEK CAPITAL LETTER THETA
+ {"thgr", 0x003B8}, // GREEK SMALL LETTER THETA
+ {"thickapprox", 0x02248}, // ALMOST EQUAL TO
+ {"thicksim", 0x0223C}, // TILDE OPERATOR
+// "ThickSpace", 0x0205F;0x0200A}, // space of width 5/18 em
+ {"thinsp", 0x02009}, // THIN SPACE
+ {"ThinSpace", 0x02009}, // THIN SPACE
+ {"thkap", 0x02248}, // ALMOST EQUAL TO
+ {"thksim", 0x0223C}, // TILDE OPERATOR
+ {"THORN", 0x000DE}, // LATIN CAPITAL LETTER THORN
+ {"thorn", 0x000FE}, // LATIN SMALL LETTER THORN
+ {"tilde", 0x002DC}, // SMALL TILDE
+ {"Tilde", 0x0223C}, // TILDE OPERATOR
+ {"TildeEqual", 0x02243}, // ASYMPTOTICALLY EQUAL TO
+ {"TildeFullEqual", 0x02245}, // APPROXIMATELY EQUAL TO
+ {"TildeTilde", 0x02248}, // ALMOST EQUAL TO
+ {"times", 0x000D7}, // MULTIPLICATION SIGN
+ {"timesb", 0x022A0}, // SQUARED TIMES
+ {"timesbar", 0x02A31}, // MULTIPLICATION SIGN WITH UNDERBAR
+ {"timesd", 0x02A30}, // MULTIPLICATION SIGN WITH DOT ABOVE
+ {"tint", 0x0222D}, // TRIPLE INTEGRAL
+ {"toea", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW
+ {"top", 0x022A4}, // DOWN TACK
+ {"topbot", 0x02336}, // APL FUNCTIONAL SYMBOL I-BEAM
+ {"topcir", 0x02AF1}, // DOWN TACK WITH CIRCLE BELOW
+ {"Topf", 0x1D54B}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL T
+ {"topf", 0x1D565}, // MATHEMATICAL DOUBLE-STRUCK SMALL T
+ {"topfork", 0x02ADA}, // PITCHFORK WITH TEE TOP
+ {"tosa", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW
+ {"tprime", 0x02034}, // TRIPLE PRIME
+ {"trade", 0x02122}, // TRADE MARK SIGN
+ {"TRADE", 0x02122}, // TRADE MARK SIGN
+ {"triangle", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE
+ {"triangledown", 0x025BF}, // WHITE DOWN-POINTING SMALL TRIANGLE
+ {"triangleleft", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE
+ {"trianglelefteq", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
+ {"triangleq", 0x0225C}, // DELTA EQUAL TO
+ {"triangleright", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE
+ {"trianglerighteq", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+ {"tridot", 0x025EC}, // WHITE UP-POINTING TRIANGLE WITH DOT
+ {"trie", 0x0225C}, // DELTA EQUAL TO
+ {"triminus", 0x02A3A}, // MINUS SIGN IN TRIANGLE
+ {"TripleDot", 0x020DB}, // COMBINING THREE DOTS ABOVE
+ {"triplus", 0x02A39}, // PLUS SIGN IN TRIANGLE
+ {"trisb", 0x029CD}, // TRIANGLE WITH SERIFS AT BOTTOM
+ {"tritime", 0x02A3B}, // MULTIPLICATION SIGN IN TRIANGLE
+ {"trpezium", 0x023E2}, // WHITE TRAPEZIUM
+ {"Tscr", 0x1D4AF}, // MATHEMATICAL SCRIPT CAPITAL T
+ {"tscr", 0x1D4C9}, // MATHEMATICAL SCRIPT SMALL T
+ {"TScy", 0x00426}, // CYRILLIC CAPITAL LETTER TSE
+ {"tscy", 0x00446}, // CYRILLIC SMALL LETTER TSE
+ {"TSHcy", 0x0040B}, // CYRILLIC CAPITAL LETTER TSHE
+ {"tshcy", 0x0045B}, // CYRILLIC SMALL LETTER TSHE
+ {"Tstrok", 0x00166}, // LATIN CAPITAL LETTER T WITH STROKE
+ {"tstrok", 0x00167}, // LATIN SMALL LETTER T WITH STROKE
+ {"twixt", 0x0226C}, // BETWEEN
+ {"twoheadleftarrow", 0x0219E}, // LEFTWARDS TWO HEADED ARROW
+ {"twoheadrightarrow", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW
+ {NULL, 0}
+};
+
+static NameId namesU[]={
+ {"Uacgr", 0x0038E}, // GREEK CAPITAL LETTER UPSILON WITH TONOS
+ {"uacgr", 0x003CD}, // GREEK SMALL LETTER UPSILON WITH TONOS
+ {"Uacute", 0x000DA}, // LATIN CAPITAL LETTER U WITH ACUTE
+ {"uacute", 0x000FA}, // LATIN SMALL LETTER U WITH ACUTE
+ {"uarr", 0x02191}, // UPWARDS ARROW
+ {"Uarr", 0x0219F}, // UPWARDS TWO HEADED ARROW
+ {"uArr", 0x021D1}, // UPWARDS DOUBLE ARROW
+ {"Uarrocir", 0x02949}, // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE
+ {"Ubrcy", 0x0040E}, // CYRILLIC CAPITAL LETTER SHORT U
+ {"ubrcy", 0x0045E}, // CYRILLIC SMALL LETTER SHORT U
+ {"Ubreve", 0x0016C}, // LATIN CAPITAL LETTER U WITH BREVE
+ {"ubreve", 0x0016D}, // LATIN SMALL LETTER U WITH BREVE
+ {"Ucirc", 0x000DB}, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ {"ucirc", 0x000FB}, // LATIN SMALL LETTER U WITH CIRCUMFLEX
+ {"Ucy", 0x00423}, // CYRILLIC CAPITAL LETTER U
+ {"ucy", 0x00443}, // CYRILLIC SMALL LETTER U
+ {"udarr", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
+ {"Udblac", 0x00170}, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ {"udblac", 0x00171}, // LATIN SMALL LETTER U WITH DOUBLE ACUTE
+ {"udhar", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ {"udiagr", 0x003B0}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ {"Udigr", 0x003AB}, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ {"udigr", 0x003CB}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ {"ufisht", 0x0297E}, // UP FISH TAIL
+ {"Ufr", 0x1D518}, // MATHEMATICAL FRAKTUR CAPITAL U
+ {"ufr", 0x1D532}, // MATHEMATICAL FRAKTUR SMALL U
+ {"Ugr", 0x003A5}, // GREEK CAPITAL LETTER UPSILON
+ {"ugr", 0x003C5}, // GREEK SMALL LETTER UPSILON
+ {"Ugrave", 0x000D9}, // LATIN CAPITAL LETTER U WITH GRAVE
+ {"ugrave", 0x000F9}, // LATIN SMALL LETTER U WITH GRAVE
+ {"uHar", 0x02963}, // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ {"uharl", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
+ {"uharr", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
+ {"uhblk", 0x02580}, // UPPER HALF BLOCK
+ {"ulcorn", 0x0231C}, // TOP LEFT CORNER
+ {"ulcorner", 0x0231C}, // TOP LEFT CORNER
+ {"ulcrop", 0x0230F}, // TOP LEFT CROP
+ {"ultri", 0x025F8}, // UPPER LEFT TRIANGLE
+ {"Umacr", 0x0016A}, // LATIN CAPITAL LETTER U WITH MACRON
+ {"umacr", 0x0016B}, // LATIN SMALL LETTER U WITH MACRON
+ {"uml", 0x000A8}, // DIAERESIS
+ {"UnderBar", 0x0005F}, // LOW LINE
+ {"UnderBrace", 0x023DF}, // BOTTOM CURLY BRACKET
+ {"UnderBracket", 0x023B5}, // BOTTOM SQUARE BRACKET
+ {"UnderParenthesis", 0x023DD}, // BOTTOM PARENTHESIS
+ {"Union", 0x022C3}, // N-ARY UNION
+ {"UnionPlus", 0x0228E}, // MULTISET UNION
+ {"Uogon", 0x00172}, // LATIN CAPITAL LETTER U WITH OGONEK
+ {"uogon", 0x00173}, // LATIN SMALL LETTER U WITH OGONEK
+ {"Uopf", 0x1D54C}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL U
+ {"uopf", 0x1D566}, // MATHEMATICAL DOUBLE-STRUCK SMALL U
+ {"uparrow", 0x02191}, // UPWARDS ARROW
+ {"UpArrow", 0x02191}, // UPWARDS ARROW
+ {"Uparrow", 0x021D1}, // UPWARDS DOUBLE ARROW
+ {"UpArrowBar", 0x02912}, // UPWARDS ARROW TO BAR
+ {"UpArrowDownArrow", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
+ {"updownarrow", 0x02195}, // UP DOWN ARROW
+ {"UpDownArrow", 0x02195}, // UP DOWN ARROW
+ {"Updownarrow", 0x021D5}, // UP DOWN DOUBLE ARROW
+ {"UpEquilibrium", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ {"upharpoonleft", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
+ {"upharpoonright", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
+ {"uplus", 0x0228E}, // MULTISET UNION
+ {"UpperLeftArrow", 0x02196}, // NORTH WEST ARROW
+ {"UpperRightArrow", 0x02197}, // NORTH EAST ARROW
+ {"upsi", 0x003C5}, // GREEK SMALL LETTER UPSILON
+ {"Upsi", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL
+ {"upsih", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL
+ {"Upsilon", 0x003A5}, // GREEK CAPITAL LETTER UPSILON
+ {"upsilon", 0x003C5}, // GREEK SMALL LETTER UPSILON
+ {"UpTee", 0x022A5}, // UP TACK
+ {"UpTeeArrow", 0x021A5}, // UPWARDS ARROW FROM BAR
+ {"upuparrows", 0x021C8}, // UPWARDS PAIRED ARROWS
+ {"urcorn", 0x0231D}, // TOP RIGHT CORNER
+ {"urcorner", 0x0231D}, // TOP RIGHT CORNER
+ {"urcrop", 0x0230E}, // TOP RIGHT CROP
+ {"Uring", 0x0016E}, // LATIN CAPITAL LETTER U WITH RING ABOVE
+ {"uring", 0x0016F}, // LATIN SMALL LETTER U WITH RING ABOVE
+ {"urtri", 0x025F9}, // UPPER RIGHT TRIANGLE
+ {"Uscr", 0x1D4B0}, // MATHEMATICAL SCRIPT CAPITAL U
+ {"uscr", 0x1D4CA}, // MATHEMATICAL SCRIPT SMALL U
+ {"utdot", 0x022F0}, // UP RIGHT DIAGONAL ELLIPSIS
+ {"Utilde", 0x00168}, // LATIN CAPITAL LETTER U WITH TILDE
+ {"utilde", 0x00169}, // LATIN SMALL LETTER U WITH TILDE
+ {"utri", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE
+ {"utrif", 0x025B4}, // BLACK UP-POINTING SMALL TRIANGLE
+ {"uuarr", 0x021C8}, // UPWARDS PAIRED ARROWS
+ {"Uuml", 0x000DC}, // LATIN CAPITAL LETTER U WITH DIAERESIS
+ {"uuml", 0x000FC}, // LATIN SMALL LETTER U WITH DIAERESIS
+ {"uwangle", 0x029A7}, // OBLIQUE ANGLE OPENING DOWN
+ {NULL, 0}
+};
+
+static NameId namesV[]={
+ {"vangrt", 0x0299C}, // RIGHT ANGLE VARIANT WITH SQUARE
+ {"varepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
+ {"varkappa", 0x003F0}, // GREEK KAPPA SYMBOL
+ {"varnothing", 0x02205}, // EMPTY SET
+ {"varphi", 0x003D5}, // GREEK PHI SYMBOL
+ {"varpi", 0x003D6}, // GREEK PI SYMBOL
+ {"varpropto", 0x0221D}, // PROPORTIONAL TO
+ {"varr", 0x02195}, // UP DOWN ARROW
+ {"vArr", 0x021D5}, // UP DOWN DOUBLE ARROW
+ {"varrho", 0x003F1}, // GREEK RHO SYMBOL
+ {"varsigma", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+// "varsubsetneq", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "varsubsetneqq", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+// "varsupsetneq", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "varsupsetneqq", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+ {"vartheta", 0x003D1}, // GREEK THETA SYMBOL
+ {"vartriangleleft", 0x022B2}, // NORMAL SUBGROUP OF
+ {"vartriangleright", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
+ {"vBar", 0x02AE8}, // SHORT UP TACK WITH UNDERBAR
+ {"Vbar", 0x02AEB}, // DOUBLE UP TACK
+ {"vBarv", 0x02AE9}, // SHORT UP TACK ABOVE SHORT DOWN TACK
+ {"Vcy", 0x00412}, // CYRILLIC CAPITAL LETTER VE
+ {"vcy", 0x00432}, // CYRILLIC SMALL LETTER VE
+ {"vdash", 0x022A2}, // RIGHT TACK
+ {"vDash", 0x022A8}, // TRUE
+ {"Vdash", 0x022A9}, // FORCES
+ {"VDash", 0x022AB}, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+ {"Vdashl", 0x02AE6}, // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL
+ {"vee", 0x02228}, // LOGICAL OR
+ {"Vee", 0x022C1}, // N-ARY LOGICAL OR
+ {"veebar", 0x022BB}, // XOR
+ {"veeeq", 0x0225A}, // EQUIANGULAR TO
+ {"vellip", 0x022EE}, // VERTICAL ELLIPSIS
+ {"verbar", 0x0007C}, // VERTICAL LINE
+ {"Verbar", 0x02016}, // DOUBLE VERTICAL LINE
+ {"vert", 0x0007C}, // VERTICAL LINE
+ {"Vert", 0x02016}, // DOUBLE VERTICAL LINE
+ {"VerticalBar", 0x02223}, // DIVIDES
+ {"VerticalLine", 0x0007C}, // VERTICAL LINE
+ {"VerticalSeparator", 0x02758}, // LIGHT VERTICAL BAR
+ {"VerticalTilde", 0x02240}, // WREATH PRODUCT
+ {"VeryThinSpace", 0x0200A}, // HAIR SPACE
+ {"Vfr", 0x1D519}, // MATHEMATICAL FRAKTUR CAPITAL V
+ {"vfr", 0x1D533}, // MATHEMATICAL FRAKTUR SMALL V
+ {"vltri", 0x022B2}, // NORMAL SUBGROUP OF
+// "vnsub", 0x02282;0x020D2}, // SUBSET OF with vertical line
+// "vnsup", 0x02283;0x020D2}, // SUPERSET OF with vertical line
+ {"Vopf", 0x1D54D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V
+ {"vopf", 0x1D567}, // MATHEMATICAL DOUBLE-STRUCK SMALL V
+ {"vprop", 0x0221D}, // PROPORTIONAL TO
+ {"vrtri", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
+ {"Vscr", 0x1D4B1}, // MATHEMATICAL SCRIPT CAPITAL V
+ {"vscr", 0x1D4CB}, // MATHEMATICAL SCRIPT SMALL V
+// "vsubne", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "vsubnE", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+// "vsupne", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "vsupnE", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+ {"Vvdash", 0x022AA}, // TRIPLE VERTICAL BAR RIGHT TURNSTILE
+ {"vzigzag", 0x0299A}, // VERTICAL ZIGZAG LINE
+ {NULL, 0}
+};
+
+static NameId namesW[]={
+ {"Wcirc", 0x00174}, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+ {"wcirc", 0x00175}, // LATIN SMALL LETTER W WITH CIRCUMFLEX
+ {"wedbar", 0x02A5F}, // LOGICAL AND WITH UNDERBAR
+ {"wedge", 0x02227}, // LOGICAL AND
+ {"Wedge", 0x022C0}, // N-ARY LOGICAL AND
+ {"wedgeq", 0x02259}, // ESTIMATES
+ {"weierp", 0x02118}, // SCRIPT CAPITAL P
+ {"Wfr", 0x1D51A}, // MATHEMATICAL FRAKTUR CAPITAL W
+ {"wfr", 0x1D534}, // MATHEMATICAL FRAKTUR SMALL W
+ {"Wopf", 0x1D54E}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL W
+ {"wopf", 0x1D568}, // MATHEMATICAL DOUBLE-STRUCK SMALL W
+ {"wp", 0x02118}, // SCRIPT CAPITAL P
+ {"wr", 0x02240}, // WREATH PRODUCT
+ {"wreath", 0x02240}, // WREATH PRODUCT
+ {"Wscr", 0x1D4B2}, // MATHEMATICAL SCRIPT CAPITAL W
+ {"wscr", 0x1D4CC}, // MATHEMATICAL SCRIPT SMALL W
+ {NULL, 0}
+};
+
+static NameId namesX[]={
+ {"xcap", 0x022C2}, // N-ARY INTERSECTION
+ {"xcirc", 0x025EF}, // LARGE CIRCLE
+ {"xcup", 0x022C3}, // N-ARY UNION
+ {"xdtri", 0x025BD}, // WHITE DOWN-POINTING TRIANGLE
+ {"Xfr", 0x1D51B}, // MATHEMATICAL FRAKTUR CAPITAL X
+ {"xfr", 0x1D535}, // MATHEMATICAL FRAKTUR SMALL X
+ {"Xgr", 0x0039E}, // GREEK CAPITAL LETTER XI
+ {"xgr", 0x003BE}, // GREEK SMALL LETTER XI
+ {"xharr", 0x027F7}, // LONG LEFT RIGHT ARROW
+ {"xhArr", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
+ {"Xi", 0x0039E}, // GREEK CAPITAL LETTER XI
+ {"xi", 0x003BE}, // GREEK SMALL LETTER XI
+ {"xlarr", 0x027F5}, // LONG LEFTWARDS ARROW
+ {"xlArr", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
+ {"xmap", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR
+ {"xnis", 0x022FB}, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"xodot", 0x02A00}, // N-ARY CIRCLED DOT OPERATOR
+ {"Xopf", 0x1D54F}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL X
+ {"xopf", 0x1D569}, // MATHEMATICAL DOUBLE-STRUCK SMALL X
+ {"xoplus", 0x02A01}, // N-ARY CIRCLED PLUS OPERATOR
+ {"xotime", 0x02A02}, // N-ARY CIRCLED TIMES OPERATOR
+ {"xrarr", 0x027F6}, // LONG RIGHTWARDS ARROW
+ {"xrArr", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
+ {"Xscr", 0x1D4B3}, // MATHEMATICAL SCRIPT CAPITAL X
+ {"xscr", 0x1D4CD}, // MATHEMATICAL SCRIPT SMALL X
+ {"xsqcup", 0x02A06}, // N-ARY SQUARE UNION OPERATOR
+ {"xuplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS
+ {"xutri", 0x025B3}, // WHITE UP-POINTING TRIANGLE
+ {"xvee", 0x022C1}, // N-ARY LOGICAL OR
+ {"xwedge", 0x022C0}, // N-ARY LOGICAL AND
+ {NULL, 0}
+};
+
+static NameId namesY[]={
+ {"Yacute", 0x000DD}, // LATIN CAPITAL LETTER Y WITH ACUTE
+ {"yacute", 0x000FD}, // LATIN SMALL LETTER Y WITH ACUTE
+ {"YAcy", 0x0042F}, // CYRILLIC CAPITAL LETTER YA
+ {"yacy", 0x0044F}, // CYRILLIC SMALL LETTER YA
+ {"Ycirc", 0x00176}, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+ {"ycirc", 0x00177}, // LATIN SMALL LETTER Y WITH CIRCUMFLEX
+ {"Ycy", 0x0042B}, // CYRILLIC CAPITAL LETTER YERU
+ {"ycy", 0x0044B}, // CYRILLIC SMALL LETTER YERU
+ {"yen", 0x000A5}, // YEN SIGN
+ {"Yfr", 0x1D51C}, // MATHEMATICAL FRAKTUR CAPITAL Y
+ {"yfr", 0x1D536}, // MATHEMATICAL FRAKTUR SMALL Y
+ {"YIcy", 0x00407}, // CYRILLIC CAPITAL LETTER YI
+ {"yicy", 0x00457}, // CYRILLIC SMALL LETTER YI
+ {"Yopf", 0x1D550}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+ {"yopf", 0x1D56A}, // MATHEMATICAL DOUBLE-STRUCK SMALL Y
+ {"Yscr", 0x1D4B4}, // MATHEMATICAL SCRIPT CAPITAL Y
+ {"yscr", 0x1D4CE}, // MATHEMATICAL SCRIPT SMALL Y
+ {"YUcy", 0x0042E}, // CYRILLIC CAPITAL LETTER YU
+ {"yucy", 0x0044E}, // CYRILLIC SMALL LETTER YU
+ {"yuml", 0x000FF}, // LATIN SMALL LETTER Y WITH DIAERESIS
+ {"Yuml", 0x00178}, // LATIN CAPITAL LETTER Y WITH DIAERESIS
+ {NULL, 0}
+};
+
+static NameId namesZ[]={
+ {"Zacute", 0x00179}, // LATIN CAPITAL LETTER Z WITH ACUTE
+ {"zacute", 0x0017A}, // LATIN SMALL LETTER Z WITH ACUTE
+ {"Zcaron", 0x0017D}, // LATIN CAPITAL LETTER Z WITH CARON
+ {"zcaron", 0x0017E}, // LATIN SMALL LETTER Z WITH CARON
+ {"Zcy", 0x00417}, // CYRILLIC CAPITAL LETTER ZE
+ {"zcy", 0x00437}, // CYRILLIC SMALL LETTER ZE
+ {"Zdot", 0x0017B}, // LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ {"zdot", 0x0017C}, // LATIN SMALL LETTER Z WITH DOT ABOVE
+ {"zeetrf", 0x02128}, // BLACK-LETTER CAPITAL Z
+ {"ZeroWidthSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"Zeta", 0x00396}, // GREEK CAPITAL LETTER ZETA
+ {"zeta", 0x003B6}, // GREEK SMALL LETTER ZETA
+ {"Zfr", 0x02128}, // BLACK-LETTER CAPITAL Z
+ {"zfr", 0x1D537}, // MATHEMATICAL FRAKTUR SMALL Z
+ {"Zgr", 0x00396}, // GREEK CAPITAL LETTER ZETA
+ {"zgr", 0x003B6}, // GREEK SMALL LETTER ZETA
+ {"ZHcy", 0x00416}, // CYRILLIC CAPITAL LETTER ZHE
+ {"zhcy", 0x00436}, // CYRILLIC SMALL LETTER ZHE
+ {"zigrarr", 0x021DD}, // RIGHTWARDS SQUIGGLE ARROW
+ {"Zopf", 0x02124}, // DOUBLE-STRUCK CAPITAL Z
+ {"zopf", 0x1D56B}, // MATHEMATICAL DOUBLE-STRUCK SMALL Z
+ {"Zscr", 0x1D4B5}, // MATHEMATICAL SCRIPT CAPITAL Z
+ {"zscr", 0x1D4CF}, // MATHEMATICAL SCRIPT SMALL Z
+ {"zwj", 0x0200D}, // ZERO WIDTH JOINER
+ {"zwnj", 0x0200C}, // ZERO WIDTH NON-JOINER
+ {NULL, 0}
+};
+
+// @todo@ order namesTable and names? by frequency
+static NameId* namesTable[] = {
+ namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI,
+ namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR,
+ namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL
+};
+
+int HtmlNamedEntity(const utf8_t *p, size_t length)
+{
+ int tableIndex = tolower(*p) - 'a';
+ if (tableIndex >= 0 && tableIndex < 26)
+ {
+ NameId* names = namesTable[tableIndex];
+
+ for (size_t i = 0; names[i].name; i++)
+ {
+ if (strncmp(names[i].name, (const char *)p, length) == 0)
+ return names[i].value;
+ }
+ }
+ return -1;
+}
+
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
new file mode 100644
index 0000000..072eacf
--- /dev/null
+++ b/gcc/d/dmd/enum.h
@@ -0,0 +1,95 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/enum.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "dsymbol.h"
+#include "declaration.h"
+#include "tokens.h"
+
+class Identifier;
+class Type;
+class Expression;
+class VarDeclaration;
+
+class EnumDeclaration : public ScopeDsymbol
+{
+public:
+ /* The separate, and distinct, cases are:
+ * 1. enum { ... }
+ * 2. enum : memtype { ... }
+ * 3. enum id { ... }
+ * 4. enum id : memtype { ... }
+ * 5. enum id : memtype;
+ * 6. enum id;
+ */
+ Type *type; // the TypeEnum
+ Type *memtype; // type of the members
+ Prot protection;
+
+ Expression *maxval;
+ Expression *minval;
+ Expression *defaultval; // default initializer
+
+ bool isdeprecated;
+ bool added;
+ int inuse;
+
+ EnumDeclaration(Loc loc, Identifier *id, Type *memtype);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void setScope(Scope *sc);
+ void semantic(Scope *sc);
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ Type *getType();
+ const char *kind();
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ bool isDeprecated(); // is Dsymbol deprecated?
+ Prot prot();
+ Expression *getMaxMinValue(Loc loc, Identifier *id);
+ bool isSpecial() const;
+ Expression *getDefaultValue(Loc loc);
+ Type *getMemtype(Loc loc);
+
+ EnumDeclaration *isEnumDeclaration() { return this; }
+
+ Symbol *sinit;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class EnumMember : public VarDeclaration
+{
+public:
+ /* Can take the following forms:
+ * 1. id
+ * 2. id = value
+ * 3. type id = value
+ */
+ Expression *&value();
+
+ // A cast() is injected to 'value' after semantic(),
+ // but 'origValue' will preserve the original value,
+ // or previous value + 1 if none was specified.
+ Expression *origValue;
+ Type *origType;
+
+ EnumDeclaration *ed;
+
+ EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ const char *kind();
+ void semantic(Scope *sc);
+ Expression *getVarExp(Loc loc, Scope *sc);
+
+ EnumMember *isEnumMember() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h
new file mode 100644
index 0000000..7b3ebc0
--- /dev/null
+++ b/gcc/d/dmd/errors.h
@@ -0,0 +1,50 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/errors.h
+ */
+
+#pragma once
+
+#include "globals.h"
+
+bool isConsoleColorSupported();
+
+#if defined(__GNUC__)
+#define D_ATTRIBUTE_FORMAT(m, n) __attribute__((format(printf, m, n))) __attribute__((nonnull (m)))
+#else
+#define D_ATTRIBUTE_FORMAT(m, n)
+#endif
+
+// Print a warning, deprecation, or error, accepts printf-like format specifiers.
+D_ATTRIBUTE_FORMAT(2, 3) void warning(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void warningSupplemental(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void deprecation(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void deprecationSupplemental(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void error(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void errorSupplemental(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 0) void verror(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL, const char *header = "Error: ");
+D_ATTRIBUTE_FORMAT(2, 0) void verrorSupplemental(const Loc& loc, const char *format, va_list ap);
+D_ATTRIBUTE_FORMAT(2, 0) void vwarning(const Loc& loc, const char *format, va_list);
+D_ATTRIBUTE_FORMAT(2, 0) void vwarningSupplemental(const Loc& loc, const char *format, va_list ap);
+D_ATTRIBUTE_FORMAT(2, 0) void vdeprecation(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL);
+D_ATTRIBUTE_FORMAT(2, 0) void vdeprecationSupplemental(const Loc& loc, const char *format, va_list ap);
+D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void message(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 0) void vmessage(const Loc& loc, const char *format, va_list);
+
+#if defined(__GNUC__) || defined(__clang__)
+#define D_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#elif _MSC_VER
+#define D_ATTRIBUTE_NORETURN __declspec(noreturn)
+#else
+#define D_ATTRIBUTE_NORETURN
+#endif
+
+// Called after printing out fatal error messages.
+D_ATTRIBUTE_NORETURN void fatal();
+D_ATTRIBUTE_NORETURN void halt();
diff --git a/gcc/d/dmd/escape.c b/gcc/d/dmd/escape.c
new file mode 100644
index 0000000..353e56f
--- /dev/null
+++ b/gcc/d/dmd/escape.c
@@ -0,0 +1,1234 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/escape.c
+ */
+
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "module.h"
+
+/************************************
+ * Aggregate the data collected by the escapeBy??() functions.
+ */
+struct EscapeByResults
+{
+ VarDeclarations byref; // array into which variables being returned by ref are inserted
+ VarDeclarations byvalue; // array into which variables with values containing pointers are inserted
+ FuncDeclarations byfunc; // nested functions that are turned into delegates
+ Expressions byexp; // array into which temporaries being returned by ref are inserted
+};
+
+static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag);
+static void inferReturn(FuncDeclaration *fd, VarDeclaration *v);
+static void escapeByValue(Expression *e, EscapeByResults *er);
+static void escapeByRef(Expression *e, EscapeByResults *er);
+static void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars);
+
+/* 'v' is assigned unsafely to 'par'
+*/
+static void unsafeAssign(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag,
+ bool &result, VarDeclaration *v, const char *desc)
+{
+ if (global.params.vsafe && sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(arg->loc, "%s %s assigned to non-scope parameter %s calling %s",
+ desc, v->toChars(),
+ par ? par->toChars() : "unnamed",
+ fdc ? fdc->toPrettyChars() : "indirectly");
+ result = true;
+ }
+}
+
+/****************************************
+ * Function parameter par is being initialized to arg,
+ * and par may escape.
+ * Detect if scoped values can escape this way.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * par = identifier of function parameter
+ * arg = initializer for param
+ * gag = do not print error messages
+ * Returns:
+ * true if pointers to the stack can escape via assignment
+ */
+bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag)
+{
+ //printf("checkParamArgumentEscape(arg: %s par: %s)\n", arg->toChars(), par->toChars());
+ //printf("type = %s, %d\n", arg->type->toChars(), arg->type->hasPointers());
+
+ if (!arg->type->hasPointers())
+ return false;
+
+ EscapeByResults er;
+
+ escapeByValue(arg, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
+ return false;
+
+ bool result = false;
+
+ for (size_t i = 0; i < er.byvalue.dim; i++)
+ {
+ //printf("byvalue %s\n", v->toChars());
+ VarDeclaration *v = er.byvalue[i];
+ if (v->isDataseg())
+ continue;
+
+ Dsymbol *p = v->toParent2();
+
+ v->storage_class &= ~STCmaybescope;
+
+ if (v->isScope())
+ {
+ unsafeAssign(sc, fdc, par, arg, gag, result, v, "scope variable");
+ }
+ else if (v->storage_class & STCvariadic && p == sc->func)
+ {
+ Type *tb = v->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ unsafeAssign(sc, fdc, par, arg, gag, result, v, "variadic variable");
+ }
+ }
+ else
+ {
+ /* v is not 'scope', and is assigned to a parameter that may escape.
+ * Therefore, v can never be 'scope'.
+ */
+ v->doNotInferScope = true;
+ }
+ }
+
+ for (size_t i = 0; i < er.byref.dim; i++)
+ {
+ VarDeclaration *v = er.byref[i];
+ if (v->isDataseg())
+ continue;
+
+ Dsymbol *p = v->toParent2();
+
+ v->storage_class &= ~STCmaybescope;
+
+ if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
+ {
+ unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local variable");
+ continue;
+ }
+ }
+
+ for (size_t i = 0; i < er.byfunc.dim; i++)
+ {
+ FuncDeclaration *fd = er.byfunc[i];
+ //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
+ VarDeclarations vars;
+ findAllOuterAccessedVariables(fd, &vars);
+
+ for (size_t j = 0; j < vars.dim; j++)
+ {
+ VarDeclaration *v = vars[j];
+ //printf("v = %s\n", v->toChars());
+ assert(!v->isDataseg()); // these are not put in the closureVars[]
+
+ Dsymbol *p = v->toParent2();
+
+ v->storage_class &= ~STCmaybescope;
+
+ if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
+ {
+ unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local");
+ continue;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < er.byexp.dim; i++)
+ {
+ Expression *ee = er.byexp[i];
+ if (sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope parameter %s",
+ ee->toChars(),
+ par ? par->toChars() : "unnamed");
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+/****************************************
+ * Given an AssignExp, determine if the lvalue will cause
+ * the contents of the rvalue to escape.
+ * Print error messages when these are detected.
+ * Infer 'scope' for the lvalue where possible, in order
+ * to eliminate the error.
+ * Params:
+ * sc = used to determine current function and module
+ * ae = AssignExp to check for any pointers to the stack
+ * gag = do not print error messages
+ * Returns:
+ * true if pointers to the stack can escape via assignment
+ */
+bool checkAssignEscape(Scope *sc, Expression *e, bool gag)
+{
+ //printf("checkAssignEscape(e: %s)\n", e->toChars());
+ if (e->op != TOKassign && e->op != TOKblit && e->op != TOKconstruct)
+ return false;
+ AssignExp *ae = (AssignExp *)e;
+ Expression *e1 = ae->e1;
+ Expression *e2 = ae->e2;
+ //printf("type = %s, %d\n", e1->type->toChars(), e1->type->hasPointers());
+
+ if (!e1->type->hasPointers())
+ return false;
+
+ if (e1->op == TOKslice)
+ return false;
+
+ EscapeByResults er;
+
+ escapeByValue(e2, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
+ return false;
+
+ VarDeclaration *va = NULL;
+ while (e1->op == TOKdotvar)
+ e1 = ((DotVarExp *)e1)->e1;
+
+ if (e1->op == TOKvar)
+ va = ((VarExp *)e1)->var->isVarDeclaration();
+ else if (e1->op == TOKthis)
+ va = ((ThisExp *)e1)->var->isVarDeclaration();
+ else if (e1->op == TOKindex)
+ {
+ IndexExp *ie = (IndexExp *)e1;
+ if (ie->e1->op == TOKvar && ie->e1->type->toBasetype()->ty == Tsarray)
+ va = ((VarExp *)ie->e1)->var->isVarDeclaration();
+ }
+
+ // Try to infer 'scope' for va if in a function not marked @system
+ bool inferScope = false;
+ if (va && sc->func && sc->func->type && sc->func->type->ty == Tfunction)
+ inferScope = ((TypeFunction *)sc->func->type)->trust != TRUSTsystem;
+
+ bool result = false;
+ for (size_t i = 0; i < er.byvalue.dim; i++)
+ {
+ VarDeclaration *v = er.byvalue[i];
+ //printf("byvalue: %s\n", v->toChars());
+ if (v->isDataseg())
+ continue;
+
+ Dsymbol *p = v->toParent2();
+
+ if (!(va && va->isScope()))
+ v->storage_class &= ~STCmaybescope;
+
+ if (v->isScope())
+ {
+ if (va && va->isScope() && va->storage_class & STCreturn && !(v->storage_class & STCreturn) &&
+ sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ae->loc, "scope variable %s assigned to return scope %s", v->toChars(), va->toChars());
+ result = true;
+ continue;
+ }
+
+ // If va's lifetime encloses v's, then error
+ if (va &&
+ ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) ||
+ // va is class reference
+ (ae->e1->op == TOKdotvar && va->type->toBasetype()->ty == Tclass && (va->enclosesLifetimeOf(v) || !va->isScope())) ||
+ va->storage_class & STCref) &&
+ sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ae->loc, "scope variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
+ result = true;
+ continue;
+ }
+
+ if (va && !va->isDataseg() && !va->doNotInferScope)
+ {
+ if (!va->isScope() && inferScope)
+ { //printf("inferring scope for %s\n", va->toChars());
+ va->storage_class |= STCscope | STCscopeinferred;
+ va->storage_class |= v->storage_class & STCreturn;
+ }
+ continue;
+ }
+ if (sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ae->loc, "scope variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
+ result = true;
+ }
+ }
+ else if (v->storage_class & STCvariadic && p == sc->func)
+ {
+ Type *tb = v->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (va && !va->isDataseg() && !va->doNotInferScope)
+ {
+ if (!va->isScope() && inferScope)
+ { //printf("inferring scope for %s\n", va->toChars());
+ va->storage_class |= STCscope | STCscopeinferred;
+ }
+ continue;
+ }
+ if (sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ae->loc, "variadic variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
+ result = true;
+ }
+ }
+ }
+ else
+ {
+ /* v is not 'scope', and we didn't check the scope of where we assigned it to.
+ * It may escape via that assignment, therefore, v can never be 'scope'.
+ */
+ v->doNotInferScope = true;
+ }
+ }
+
+ for (size_t i = 0; i < er.byref.dim; i++)
+ {
+ VarDeclaration *v = er.byref[i];
+ //printf("byref: %s\n", v->toChars());
+ if (v->isDataseg())
+ continue;
+
+ Dsymbol *p = v->toParent2();
+
+ // If va's lifetime encloses v's, then error
+ if (va &&
+ ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) || va->storage_class & STCref) &&
+ sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ae->loc, "address of variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
+ result = true;
+ continue;
+ }
+
+ if (!(va && va->isScope()))
+ v->storage_class &= ~STCmaybescope;
+
+ if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
+ {
+ if (va && !va->isDataseg() && !va->doNotInferScope)
+ {
+ if (!va->isScope() && inferScope)
+ { //printf("inferring scope for %s\n", va->toChars());
+ va->storage_class |= STCscope | STCscopeinferred;
+ }
+ continue;
+ }
+ if (sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ae->loc, "reference to local variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
+ result = true;
+ }
+ continue;
+ }
+ }
+
+ for (size_t i = 0; i < er.byfunc.dim; i++)
+ {
+ FuncDeclaration *fd = er.byfunc[i];
+ //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
+ VarDeclarations vars;
+ findAllOuterAccessedVariables(fd, &vars);
+
+ for (size_t j = 0; j < vars.dim; j++)
+ {
+ VarDeclaration *v = vars[j];
+ //printf("v = %s\n", v->toChars());
+ assert(!v->isDataseg()); // these are not put in the closureVars[]
+
+ Dsymbol *p = v->toParent2();
+
+ if (!(va && va->isScope()))
+ v->storage_class &= ~STCmaybescope;
+
+ if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
+ {
+ if (va && !va->isDataseg() && !va->doNotInferScope)
+ {
+ /* Don't infer STCscope for va, because then a closure
+ * won't be generated for sc->func.
+ */
+ //if (!va->isScope() && inferScope)
+ //va->storage_class |= STCscope | STCscopeinferred;
+ continue;
+ }
+ if (sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ae->loc, "reference to local %s assigned to non-scope %s in @safe code", v->toChars(), e1->toChars());
+ result = true;
+ }
+ continue;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < er.byexp.dim; i++)
+ {
+ Expression *ee = er.byexp[i];
+ if (va && !va->isDataseg() && !va->doNotInferScope)
+ {
+ if (!va->isScope() && inferScope)
+ { //printf("inferring scope for %s\n", va->toChars());
+ va->storage_class |= STCscope | STCscopeinferred;
+ }
+ continue;
+ }
+ if (sc->func->setUnsafe())
+ {
+ if (!gag)
+ error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope %s",
+ ee->toChars(), e1->toChars());
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+/************************************
+ * Detect cases where pointers to the stack can 'escape' the
+ * lifetime of the stack frame when throwing `e`.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check for any pointers to the stack
+ * gag = do not print error messages
+ * Returns:
+ * true if pointers to the stack can escape
+ */
+bool checkThrowEscape(Scope *sc, Expression *e, bool gag)
+{
+ //printf("[%s] checkThrowEscape, e = %s\n", e->loc->toChars(), e->toChars());
+ EscapeByResults er;
+
+ escapeByValue(e, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
+ return false;
+
+ bool result = false;
+ for (size_t i = 0; i < er.byvalue.dim; i++)
+ {
+ VarDeclaration *v = er.byvalue[i];
+ //printf("byvalue %s\n", v->toChars());
+ if (v->isDataseg())
+ continue;
+
+ if (v->isScope())
+ {
+ if (sc->_module && sc->_module->isRoot())
+ {
+ // Only look for errors if in module listed on command line
+ if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
+ {
+ if (!gag)
+ error(e->loc, "scope variable %s may not be thrown", v->toChars());
+ result = true;
+ }
+ continue;
+ }
+ }
+ else
+ {
+ //printf("no infer for %s\n", v->toChars());
+ v->doNotInferScope = true;
+ }
+ }
+ return result;
+}
+
+/************************************
+ * Detect cases where pointers to the stack can 'escape' the
+ * lifetime of the stack frame by returning 'e' by value.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check for any pointers to the stack
+ * gag = do not print error messages
+ * Returns:
+ * true if pointers to the stack can escape
+ */
+
+bool checkReturnEscape(Scope *sc, Expression *e, bool gag)
+{
+ //printf("[%s] checkReturnEscape, e = %s\n", e->loc->toChars(), e->toChars());
+ return checkReturnEscapeImpl(sc, e, false, gag);
+}
+
+/************************************
+ * Detect cases where returning 'e' by ref can result in a reference to the stack
+ * being returned.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check
+ * gag = do not print error messages
+ * Returns:
+ * true if references to the stack can escape
+ */
+bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag)
+{
+ //printf("[%s] checkReturnEscapeRef, e = %s\n", e->loc.toChars(), e->toChars());
+ //printf("current function %s\n", sc->func->toChars());
+ //printf("parent2 function %s\n", sc->func->toParent2()->toChars());
+
+ return checkReturnEscapeImpl(sc, e, true, gag);
+}
+
+static void escapingRef(VarDeclaration *v, Expression *e, bool &result, bool gag)
+{
+ if (!gag)
+ {
+ const char *msg;
+ if (v->storage_class & STCparameter)
+ msg = "returning `%s` escapes a reference to parameter `%s`, perhaps annotate with `return`";
+ else
+ msg = "returning `%s` escapes a reference to local variable `%s`";
+ error(e->loc, msg, e->toChars(), v->toChars());
+ }
+ result = true;
+}
+
+static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag)
+{
+ //printf("[%s] checkReturnEscapeImpl, e = %s\n", e->loc->toChars(), e->toChars());
+ EscapeByResults er;
+
+ if (refs)
+ escapeByRef(e, &er);
+ else
+ escapeByValue(e, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
+ return false;
+
+ bool result = false;
+ for (size_t i = 0; i < er.byvalue.dim; i++)
+ {
+ VarDeclaration *v = er.byvalue[i];
+ //printf("byvalue %s\n", v->toChars());
+ if (v->isDataseg())
+ continue;
+
+ Dsymbol *p = v->toParent2();
+
+ if ((v->isScope() || (v->storage_class & STCmaybescope)) &&
+ !(v->storage_class & STCreturn) &&
+ v->isParameter() &&
+ sc->func->flags & FUNCFLAGreturnInprocess &&
+ p == sc->func)
+ {
+ inferReturn(sc->func, v); // infer addition of 'return'
+ continue;
+ }
+
+ if (v->isScope())
+ {
+ if (v->storage_class & STCreturn)
+ continue;
+
+ if (sc->_module && sc->_module->isRoot() &&
+ /* This case comes up when the ReturnStatement of a __foreachbody is
+ * checked for escapes by the caller of __foreachbody. Skip it.
+ *
+ * struct S { static int opApply(int delegate(S*) dg); }
+ * S* foo() {
+ * foreach (S* s; S) // create __foreachbody for body of foreach
+ * return s; // s is inferred as 'scope' but incorrectly tested in foo()
+ * return null; }
+ */
+ !(!refs && p->parent == sc->func))
+ {
+ // Only look for errors if in module listed on command line
+ if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
+ {
+ if (!gag)
+ error(e->loc, "scope variable %s may not be returned", v->toChars());
+ result = true;
+ }
+ continue;
+ }
+ }
+ else if (v->storage_class & STCvariadic && p == sc->func)
+ {
+ Type *tb = v->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!gag)
+ error(e->loc, "returning `%s` escapes a reference to variadic parameter `%s`", e->toChars(), v->toChars());
+ result = false;
+ }
+ }
+ else
+ {
+ //printf("no infer for %s\n", v->toChars());
+ v->doNotInferScope = true;
+ }
+ }
+
+ for (size_t i = 0; i < er.byref.dim; i++)
+ {
+ VarDeclaration *v = er.byref[i];
+ //printf("byref %s\n", v->toChars());
+ if (v->isDataseg())
+ continue;
+
+ Dsymbol *p = v->toParent2();
+
+ if ((v->storage_class & (STCref | STCout)) == 0)
+ {
+ if (p == sc->func)
+ {
+ escapingRef(v, e, result, gag);
+ continue;
+ }
+ FuncDeclaration *fd = p->isFuncDeclaration();
+ if (fd && sc->func->flags & FUNCFLAGreturnInprocess)
+ {
+ /* Code like:
+ * int x;
+ * auto dg = () { return &x; }
+ * Making it:
+ * auto dg = () return { return &x; }
+ * Because dg.ptr points to x, this is returning dt.ptr+offset
+ */
+ if (global.params.vsafe)
+ sc->func->storage_class |= STCreturn;
+ }
+ }
+
+ /* Check for returning a ref variable by 'ref', but should be 'return ref'
+ * Infer the addition of 'return', or set result to be the offending expression.
+ */
+ if ( (v->storage_class & (STCref | STCout)) &&
+ !(v->storage_class & (STCreturn | STCforeach)))
+ {
+ if ((sc->func->flags & FUNCFLAGreturnInprocess) && p == sc->func)
+ {
+ inferReturn(sc->func, v); // infer addition of 'return'
+ }
+ else if (global.params.useDIP25 &&
+ sc->_module && sc->_module->isRoot())
+ {
+ // Only look for errors if in module listed on command line
+
+ if (p == sc->func)
+ {
+ //printf("escaping reference to local ref variable %s\n", v->toChars());
+ //printf("storage class = x%llx\n", v->storage_class);
+ escapingRef(v, e, result, gag);
+ continue;
+ }
+ // Don't need to be concerned if v's parent does not return a ref
+ FuncDeclaration *fd = p->isFuncDeclaration();
+ if (fd && fd->type && fd->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (tf->isref)
+ {
+ if (!gag)
+ error(e->loc, "escaping reference to outer local variable %s", v->toChars());
+ result = true;
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < er.byexp.dim; i++)
+ {
+ Expression *ee = er.byexp[i];
+ //printf("byexp %s\n", ee->toChars());
+ if (!gag)
+ error(ee->loc, "escaping reference to stack allocated value returned by %s", ee->toChars());
+ result = true;
+ }
+
+ return result;
+}
+
+
+/*************************************
+ * Variable v needs to have 'return' inferred for it.
+ * Params:
+ * fd = function that v is a parameter to
+ * v = parameter that needs to be STCreturn
+ */
+
+static void inferReturn(FuncDeclaration *fd, VarDeclaration *v)
+{
+ // v is a local in the current function
+
+ //printf("for function '%s' inferring 'return' for variable '%s'\n", fd->toChars(), v->toChars());
+ v->storage_class |= STCreturn;
+
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (v == fd->vthis)
+ {
+ /* v is the 'this' reference, so mark the function
+ */
+ fd->storage_class |= STCreturn;
+ if (tf->ty == Tfunction)
+ {
+ //printf("'this' too %p %s\n", tf, sc->func->toChars());
+ tf->isreturn = true;
+ }
+ }
+ else
+ {
+ // Perform 'return' inference on parameter
+ if (tf->ty == Tfunction && tf->parameters)
+ {
+ const size_t dim = Parameter::dim(tf->parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, i);
+ if (p->ident == v->ident)
+ {
+ p->storageClass |= STCreturn;
+ break; // there can be only one
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************
+ * e is an expression to be returned by value, and that value contains pointers.
+ * Walk e to determine which variables are possibly being
+ * returned by value, such as:
+ * int* function(int* p) { return p; }
+ * If e is a form of &p, determine which variables have content
+ * which is being returned as ref, such as:
+ * int* function(int i) { return &i; }
+ * Multiple variables can be inserted, because of expressions like this:
+ * int function(bool b, int i, int* p) { return b ? &i : p; }
+ *
+ * No side effects.
+ *
+ * Params:
+ * e = expression to be returned by value
+ * er = where to place collected data
+ */
+static void escapeByValue(Expression *e, EscapeByResults *er)
+{
+ //printf("[%s] escapeByValue, e: %s\n", e->loc.toChars(), e->toChars());
+
+ class EscapeVisitor : public Visitor
+ {
+ public:
+ EscapeByResults *er;
+
+ EscapeVisitor(EscapeByResults *er)
+ : er(er)
+ {
+ }
+
+ void visit(Expression *)
+ {
+ }
+
+ void visit(AddrExp *e)
+ {
+ escapeByRef(e->e1, er);
+ }
+
+ void visit(SymOffExp *e)
+ {
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (v)
+ er->byref.push(v);
+ }
+
+ void visit(VarExp *e)
+ {
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (v)
+ er->byvalue.push(v);
+ }
+
+ void visit(ThisExp *e)
+ {
+ if (e->var)
+ er->byvalue.push(e->var);
+ }
+
+ void visit(DotVarExp *e)
+ {
+ Type *t = e->e1->type->toBasetype();
+ if (t->ty == Tstruct)
+ e->e1->accept(this);
+ }
+
+ void visit(DelegateExp *e)
+ {
+ Type *t = e->e1->type->toBasetype();
+ if (t->ty == Tclass || t->ty == Tpointer)
+ escapeByValue(e->e1, er);
+ else
+ escapeByRef(e->e1, er);
+ er->byfunc.push(e->func);
+ }
+
+ void visit(FuncExp *e)
+ {
+ if (e->fd->tok == TOKdelegate)
+ er->byfunc.push(e->fd);
+ }
+
+ void visit(TupleExp *)
+ {
+ assert(0); // should have been lowered by now
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tsarray || tb->ty == Tarray)
+ {
+ if (e->basis)
+ e->basis->accept(this);
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *el = (*e->elements)[i];
+ if (el)
+ el->accept(this);
+ }
+ }
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ if (e->elements)
+ {
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *ex = (*e->elements)[i];
+ if (ex)
+ ex->accept(this);
+ }
+ }
+ }
+
+ void visit(NewExp *e)
+ {
+ Type *tb = e->newtype->toBasetype();
+ if (tb->ty == Tstruct && !e->member && e->arguments)
+ {
+ for (size_t i = 0; i < e->arguments->dim; i++)
+ {
+ Expression *ex = (*e->arguments)[i];
+ if (ex)
+ ex->accept(this);
+ }
+ }
+ }
+
+ void visit(CastExp *e)
+ {
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tarray &&
+ e->e1->type->toBasetype()->ty == Tsarray)
+ {
+ escapeByRef(e->e1, er);
+ }
+ else
+ e->e1->accept(this);
+ }
+
+ void visit(SliceExp *e)
+ {
+ if (e->e1->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
+ Type *tb = e->type->toBasetype();
+ if (v)
+ {
+ if (tb->ty == Tsarray)
+ return;
+ if (v->storage_class & STCvariadic)
+ {
+ er->byvalue.push(v);
+ return;
+ }
+ }
+ }
+ Type *t1b = e->e1->type->toBasetype();
+ if (t1b->ty == Tsarray)
+ {
+ Type *tb = e->type->toBasetype();
+ if (tb->ty != Tsarray)
+ escapeByRef(e->e1, er);
+ }
+ else
+ e->e1->accept(this);
+ }
+
+ void visit(BinExp *e)
+ {
+ Type *tb = e->type->toBasetype();
+ if (tb->ty == Tpointer)
+ {
+ e->e1->accept(this);
+ e->e2->accept(this);
+ }
+ }
+
+ void visit(BinAssignExp *e)
+ {
+ e->e1->accept(this);
+ }
+
+ void visit(AssignExp *e)
+ {
+ e->e1->accept(this);
+ }
+
+ void visit(CommaExp *e)
+ {
+ e->e2->accept(this);
+ }
+
+ void visit(CondExp *e)
+ {
+ e->e1->accept(this);
+ e->e2->accept(this);
+ }
+
+ void visit(CallExp *e)
+ {
+ //printf("CallExp(): %s\n", e->toChars());
+ /* Check each argument that is
+ * passed as 'return scope'.
+ */
+ Type *t1 = e->e1->type->toBasetype();
+ TypeFunction *tf = NULL;
+ TypeDelegate *dg = NULL;
+ if (t1->ty == Tdelegate)
+ {
+ dg = (TypeDelegate *)t1;
+ tf = (TypeFunction *)dg->next;
+ }
+ else if (t1->ty == Tfunction)
+ tf = (TypeFunction *)t1;
+ else
+ return;
+
+ if (e->arguments && e->arguments->dim)
+ {
+ /* j=1 if _arguments[] is first argument,
+ * skip it because it is not passed by ref
+ */
+ size_t j = (tf->linkage == LINKd && tf->varargs == 1);
+ for (size_t i = j; i < e->arguments->dim; ++i)
+ {
+ Expression *arg = (*e->arguments)[i];
+ size_t nparams = Parameter::dim(tf->parameters);
+ if (i - j < nparams && i >= j)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, i - j);
+ const StorageClass stc = tf->parameterStorageClass(p);
+ if ((stc & (STCscope)) && (stc & STCreturn))
+ arg->accept(this);
+ else if ((stc & (STCref)) && (stc & STCreturn))
+ escapeByRef(arg, er);
+ }
+ }
+ }
+ // If 'this' is returned, check it too
+ if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
+ {
+ DotVarExp *dve = (DotVarExp *)e->e1;
+ FuncDeclaration *fd = dve->var->isFuncDeclaration();
+ AggregateDeclaration *ad = NULL;
+ if (global.params.vsafe && tf->isreturn && fd && (ad = fd->isThis()) != NULL)
+ {
+ if (ad->isClassDeclaration() || tf->isscope) // this is 'return scope'
+ dve->e1->accept(this);
+ else if (ad->isStructDeclaration()) // this is 'return ref'
+ escapeByRef(dve->e1, er);
+ }
+ else if (dve->var->storage_class & STCreturn || tf->isreturn)
+ {
+ if (dve->var->storage_class & STCscope)
+ dve->e1->accept(this);
+ else if (dve->var->storage_class & STCref)
+ escapeByRef(dve->e1, er);
+ }
+ }
+
+ /* If returning the result of a delegate call, the .ptr
+ * field of the delegate must be checked.
+ */
+ if (dg)
+ {
+ if (tf->isreturn)
+ e->e1->accept(this);
+ }
+ }
+ };
+
+ EscapeVisitor v(er);
+ e->accept(&v);
+}
+
+/****************************************
+ * e is an expression to be returned by 'ref'.
+ * Walk e to determine which variables are possibly being
+ * returned by ref, such as:
+ * ref int function(int i) { return i; }
+ * If e is a form of *p, determine which variables have content
+ * which is being returned as ref, such as:
+ * ref int function(int* p) { return *p; }
+ * Multiple variables can be inserted, because of expressions like this:
+ * ref int function(bool b, int i, int* p) { return b ? i : *p; }
+ *
+ * No side effects.
+ *
+ * Params:
+ * e = expression to be returned by 'ref'
+ * er = where to place collected data
+ */
+static void escapeByRef(Expression *e, EscapeByResults *er)
+{
+ //printf("[%s] escapeByRef, e: %s\n", e->loc->toChars(), e->toChars());
+ class EscapeRefVisitor : public Visitor
+ {
+ public:
+ EscapeByResults *er;
+
+ EscapeRefVisitor(EscapeByResults *er)
+ : er(er)
+ {
+ }
+
+ void visit(Expression *)
+ {
+ }
+
+ void visit(VarExp *e)
+ {
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (v)
+ {
+ if (v->storage_class & STCref && v->storage_class & (STCforeach | STCtemp) && v->_init)
+ {
+ /* If compiler generated ref temporary
+ * (ref v = ex; ex)
+ * look at the initializer instead
+ */
+ if (ExpInitializer *ez = v->_init->isExpInitializer())
+ {
+ assert(ez->exp && ez->exp->op == TOKconstruct);
+ Expression *ex = ((ConstructExp *)ez->exp)->e2;
+ ex->accept(this);
+ }
+ }
+ else
+ er->byref.push(v);
+ }
+ }
+
+ void visit(ThisExp *e)
+ {
+ if (e->var)
+ er->byref.push(e->var);
+ }
+
+ void visit(PtrExp *e)
+ {
+ escapeByValue(e->e1, er);
+ }
+
+ void visit(IndexExp *e)
+ {
+ Type *tb = e->e1->type->toBasetype();
+ if (e->e1->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (v->storage_class & STCvariadic)
+ {
+ er->byref.push(v);
+ return;
+ }
+ }
+ }
+ if (tb->ty == Tsarray)
+ {
+ e->e1->accept(this);
+ }
+ else if (tb->ty == Tarray)
+ {
+ escapeByValue(e->e1, er);
+ }
+ }
+
+ void visit(DotVarExp *e)
+ {
+ Type *t1b = e->e1->type->toBasetype();
+ if (t1b->ty == Tclass)
+ escapeByValue(e->e1, er);
+ else
+ e->e1->accept(this);
+ }
+
+ void visit(BinAssignExp *e)
+ {
+ e->e1->accept(this);
+ }
+
+ void visit(AssignExp *e)
+ {
+ e->e1->accept(this);
+ }
+
+ void visit(CommaExp *e)
+ {
+ e->e2->accept(this);
+ }
+
+ void visit(CondExp *e)
+ {
+ e->e1->accept(this);
+ e->e2->accept(this);
+ }
+
+ void visit(CallExp *e)
+ {
+ /* If the function returns by ref, check each argument that is
+ * passed as 'return ref'.
+ */
+ Type *t1 = e->e1->type->toBasetype();
+ TypeFunction *tf;
+ if (t1->ty == Tdelegate)
+ tf = (TypeFunction *)((TypeDelegate *)t1)->next;
+ else if (t1->ty == Tfunction)
+ tf = (TypeFunction *)t1;
+ else
+ return;
+ if (tf->isref)
+ {
+ if (e->arguments && e->arguments->dim)
+ {
+ /* j=1 if _arguments[] is first argument,
+ * skip it because it is not passed by ref
+ */
+ size_t j = (tf->linkage == LINKd && tf->varargs == 1);
+
+ for (size_t i = j; i < e->arguments->dim; ++i)
+ {
+ Expression *arg = (*e->arguments)[i];
+ size_t nparams = Parameter::dim(tf->parameters);
+ if (i - j < nparams && i >= j)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, i - j);
+ const StorageClass stc = tf->parameterStorageClass(p);
+ if ((stc & (STCout | STCref)) && (stc & STCreturn))
+ arg->accept(this);
+ else if ((stc & STCscope) && (stc & STCreturn))
+ {
+ if (arg->op == TOKdelegate)
+ {
+ DelegateExp *de = (DelegateExp *)arg;
+ if (de->func->isNested())
+ er->byexp.push(de);
+ }
+ else
+ escapeByValue(arg, er);
+ }
+ }
+ }
+ }
+
+ // If 'this' is returned by ref, check it too
+ if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
+ {
+ DotVarExp *dve = (DotVarExp *)e->e1;
+ if (dve->var->storage_class & STCreturn || tf->isreturn)
+ {
+ if ((dve->var->storage_class & STCscope) || tf->isscope)
+ escapeByValue(dve->e1, er);
+ else if ((dve->var->storage_class & STCref) || tf->isref)
+ dve->e1->accept(this);
+ }
+
+ }
+ // If it's a delegate, check it too
+ if (e->e1->op == TOKvar && t1->ty == Tdelegate)
+ {
+ escapeByValue(e->e1, er);
+ }
+ }
+ else
+ er->byexp.push(e);
+ }
+ };
+
+ EscapeRefVisitor v(er);
+ e->accept(&v);
+}
+
+/*************************
+ * Find all variables accessed by this delegate that are
+ * in functions enclosing it.
+ * Params:
+ * fd = function
+ * vars = array to append found variables to
+ */
+void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars)
+{
+ //printf("findAllOuterAccessedVariables(fd: %s)\n", fd.toChars());
+ for (Dsymbol *p = fd->parent; p; p = p->parent)
+ {
+ FuncDeclaration *fdp = p->isFuncDeclaration();
+ if (fdp)
+ {
+ for (size_t i = 0; i < fdp->closureVars.dim; i++)
+ {
+ VarDeclaration *v = fdp->closureVars[i];
+ for (size_t j = 0; j < v->nestedrefs.dim; j++)
+ {
+ FuncDeclaration *fdv = v->nestedrefs[j];
+ if (fdv == fd)
+ {
+ //printf("accessed: %s, type %s\n", v->toChars(), v->type->toChars());
+ vars->push(v);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
new file mode 100644
index 0000000..dc0d8e7
--- /dev/null
+++ b/gcc/d/dmd/expression.c
@@ -0,0 +1,6945 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+#include "root/rmem.h"
+#include "root/root.h"
+
+#include "errors.h"
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "utf.h"
+#include "enum.h"
+#include "scope.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "import.h"
+#include "id.h"
+#include "dsymbol.h"
+#include "module.h"
+#include "attrib.h"
+#include "hdrgen.h"
+#include "parse.h"
+#include "doc.h"
+#include "root/aav.h"
+#include "nspace.h"
+#include "ctfe.h"
+#include "target.h"
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
+bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
+char *MODtoChars(MOD mod);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+MOD MODmerge(MOD mod1, MOD mod2);
+void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *semanticX(DotIdExp *exp, Scope *sc);
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
+
+/*************************************************************
+ * Given var, we need to get the
+ * right 'this' pointer if var is in an outer class, but our
+ * existing 'this' pointer is in an inner class.
+ * Input:
+ * e1 existing 'this'
+ * ad struct or class we need the correct 'this' for
+ * var the specific member of ad we're accessing
+ */
+
+Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
+ Expression *e1, Declaration *var, int flag = 0)
+{
+ //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
+ L1:
+ Type *t = e1->type->toBasetype();
+ //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
+
+ /* If e1 is not the 'this' pointer for ad
+ */
+ if (ad &&
+ !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
+ ((TypeStruct *)t->nextOf())->sym == ad)
+ &&
+ !(t->ty == Tstruct &&
+ ((TypeStruct *)t)->sym == ad)
+ )
+ {
+ ClassDeclaration *cd = ad->isClassDeclaration();
+ ClassDeclaration *tcd = t->isClassHandle();
+
+ /* e1 is the right this if ad is a base class of e1
+ */
+ if (!cd || !tcd ||
+ !(tcd == cd || cd->isBaseOf(tcd, NULL))
+ )
+ {
+ /* Only classes can be inner classes with an 'outer'
+ * member pointing to the enclosing class instance
+ */
+ if (tcd && tcd->isNested())
+ {
+ /* e1 is the 'this' pointer for an inner class: tcd.
+ * Rewrite it as the 'this' pointer for the outer class.
+ */
+
+ e1 = new DotVarExp(loc, e1, tcd->vthis);
+ e1->type = tcd->vthis->type;
+ e1->type = e1->type->addMod(t->mod);
+ // Do not call checkNestedRef()
+ //e1 = semantic(e1, sc);
+
+ // Skip up over nested functions, and get the enclosing
+ // class type.
+ int n = 0;
+ Dsymbol *s;
+ for (s = tcd->toParent();
+ s && s->isFuncDeclaration();
+ s = s->toParent())
+ {
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f->vthis)
+ {
+ //printf("rewriting e1 to %s's this\n", f->toChars());
+ n++;
+ e1 = new VarExp(loc, f->vthis);
+ }
+ else
+ {
+ e1->error("need 'this' of type %s to access member %s"
+ " from static function %s",
+ ad->toChars(), var->toChars(), f->toChars());
+ e1 = new ErrorExp();
+ return e1;
+ }
+ }
+ if (s && s->isClassDeclaration())
+ {
+ e1->type = s->isClassDeclaration()->type;
+ e1->type = e1->type->addMod(t->mod);
+ if (n > 1)
+ e1 = semantic(e1, sc);
+ }
+ else
+ e1 = semantic(e1, sc);
+ goto L1;
+ }
+
+ /* Can't find a path from e1 to ad
+ */
+ if (flag)
+ return NULL;
+ e1->error("this for %s needs to be type %s not type %s",
+ var->toChars(), ad->toChars(), t->toChars());
+ return new ErrorExp();
+ }
+ }
+ return e1;
+}
+
+/*****************************************
+ * Determine if 'this' is available.
+ * If it is, return the FuncDeclaration that has it.
+ */
+
+FuncDeclaration *hasThis(Scope *sc)
+{
+ //printf("hasThis()\n");
+ Dsymbol *p = sc->parent;
+ while (p && p->isTemplateMixin())
+ p = p->parent;
+ FuncDeclaration *fdthis = p ? p->isFuncDeclaration() : NULL;
+ //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : "");
+
+ // Go upwards until we find the enclosing member function
+ FuncDeclaration *fd = fdthis;
+ while (1)
+ {
+ if (!fd)
+ {
+ goto Lno;
+ }
+ if (!fd->isNested())
+ break;
+
+ Dsymbol *parent = fd->parent;
+ while (1)
+ {
+ if (!parent)
+ goto Lno;
+ TemplateInstance *ti = parent->isTemplateInstance();
+ if (ti)
+ parent = ti->parent;
+ else
+ break;
+ }
+ fd = parent->isFuncDeclaration();
+ }
+
+ if (!fd->isThis())
+ { //printf("test '%s'\n", fd->toChars());
+ goto Lno;
+ }
+
+ assert(fd->vthis);
+ return fd;
+
+Lno:
+ return NULL; // don't have 'this' available
+}
+
+bool isNeedThisScope(Scope *sc, Declaration *d)
+{
+ if (sc->intypeof == 1)
+ return false;
+
+ AggregateDeclaration *ad = d->isThis();
+ if (!ad)
+ return false;
+ //printf("d = %s, ad = %s\n", d->toChars(), ad->toChars());
+
+ for (Dsymbol *s = sc->parent; s; s = s->toParent2())
+ {
+ //printf("\ts = %s %s, toParent2() = %p\n", s->kind(), s->toChars(), s->toParent2());
+ if (AggregateDeclaration *ad2 = s->isAggregateDeclaration())
+ {
+ if (ad2 == ad)
+ return false;
+ else if (ad2->isNested())
+ continue;
+ else
+ return true;
+ }
+ if (FuncDeclaration *f = s->isFuncDeclaration())
+ {
+ if (f->isMember2())
+ break;
+ }
+ }
+ return true;
+}
+
+/***************************************
+ * Pull out any properties.
+ */
+
+Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+ //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
+ Loc loc = e1->loc;
+
+ OverloadSet *os;
+ Dsymbol *s;
+ Objects *tiargs;
+ Type *tthis;
+ if (e1->op == TOKdot)
+ {
+ DotExp *de = (DotExp *)e1;
+ if (de->e2->op == TOKoverloadset)
+ {
+ tiargs = NULL;
+ tthis = de->e1->type;
+ os = ((OverExp *)de->e2)->vars;
+ goto Los;
+ }
+ }
+ else if (e1->op == TOKoverloadset)
+ {
+ tiargs = NULL;
+ tthis = NULL;
+ os = ((OverExp *)e1)->vars;
+ Los:
+ assert(os);
+ FuncDeclaration *fd = NULL;
+ if (e2)
+ {
+ e2 = semantic(e2, sc);
+ if (e2->op == TOKerror)
+ return new ErrorExp();
+ e2 = resolveProperties(sc, e2);
+
+ Expressions a;
+ a.push(e2);
+
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
+ if (f)
+ {
+ if (f->errors)
+ return new ErrorExp();
+ fd = f;
+ assert(fd->type->ty == Tfunction);
+ }
+ }
+ if (fd)
+ {
+ Expression *e = new CallExp(loc, e1, e2);
+ return semantic(e, sc);
+ }
+ }
+ {
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
+ if (f)
+ {
+ if (f->errors)
+ return new ErrorExp();
+ fd = f;
+ assert(fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (!tf->isref && e2)
+ goto Leproplvalue;
+ }
+ }
+ if (fd)
+ {
+ Expression *e = new CallExp(loc, e1);
+ if (e2)
+ e = new AssignExp(loc, e, e2);
+ return semantic(e, sc);
+ }
+ }
+ if (e2)
+ goto Leprop;
+ }
+ else if (e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+ if (!dti->findTempDecl(sc))
+ goto Leprop;
+ if (!dti->ti->semanticTiargs(sc))
+ goto Leprop;
+ tiargs = dti->ti->tiargs;
+ tthis = dti->e1->type;
+ if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
+ goto Los;
+ if ((s = dti->ti->tempdecl) != NULL)
+ goto Lfd;
+ }
+ else if (e1->op == TOKdottd)
+ {
+ DotTemplateExp *dte = (DotTemplateExp *)e1;
+ s = dte->td;
+ tiargs = NULL;
+ tthis = dte->e1->type;
+ goto Lfd;
+ }
+ else if (e1->op == TOKscope)
+ {
+ s = ((ScopeExp *)e1)->sds;
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti && !ti->semanticRun && ti->tempdecl)
+ {
+ //assert(ti->needsTypeInference(sc));
+ if (!ti->semanticTiargs(sc))
+ goto Leprop;
+ tiargs = ti->tiargs;
+ tthis = NULL;
+ if ((os = ti->tempdecl->isOverloadSet()) != NULL)
+ goto Los;
+ if ((s = ti->tempdecl) != NULL)
+ goto Lfd;
+ }
+ }
+ else if (e1->op == TOKtemplate)
+ {
+ s = ((TemplateExp *)e1)->td;
+ tiargs = NULL;
+ tthis = NULL;
+ goto Lfd;
+ }
+ else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+ {
+ DotVarExp *dve = (DotVarExp *)e1;
+ s = dve->var->isFuncDeclaration();
+ tiargs = NULL;
+ tthis = dve->e1->type;
+ goto Lfd;
+ }
+ else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+ {
+ s = ((VarExp *)e1)->var->isFuncDeclaration();
+ tiargs = NULL;
+ tthis = NULL;
+ Lfd:
+ assert(s);
+ if (e2)
+ {
+ e2 = semantic(e2, sc);
+ if (e2->op == TOKerror)
+ return new ErrorExp();
+ e2 = resolveProperties(sc, e2);
+
+ Expressions a;
+ a.push(e2);
+
+ FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
+ if (fd && fd->type)
+ {
+ if (fd->errors)
+ return new ErrorExp();
+ assert(fd->type->ty == Tfunction);
+ Expression *e = new CallExp(loc, e1, e2);
+ return semantic(e, sc);
+ }
+ }
+ {
+ FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
+ if (fd && fd->type)
+ {
+ if (fd->errors)
+ return new ErrorExp();
+ assert(fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (!e2 || tf->isref)
+ {
+ Expression *e = new CallExp(loc, e1);
+ if (e2)
+ e = new AssignExp(loc, e, e2);
+ return semantic(e, sc);
+ }
+ }
+ }
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ // Keep better diagnostic message for invalid property usage of functions
+ assert(fd->type->ty == Tfunction);
+ Expression *e = new CallExp(loc, e1, e2);
+ return semantic(e, sc);
+ }
+ if (e2)
+ goto Leprop;
+ }
+ if (e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e1;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v && ve->checkPurity(sc, v))
+ return new ErrorExp();
+ }
+ if (e2)
+ return NULL;
+
+ if (e1->type &&
+ e1->op != TOKtype) // function type is not a property
+ {
+ /* Look for e1 being a lazy parameter; rewrite as delegate call
+ */
+ if (e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e1;
+
+ if (ve->var->storage_class & STClazy)
+ {
+ Expression *e = new CallExp(loc, e1);
+ return semantic(e, sc);
+ }
+ }
+ else if (e1->op == TOKdotvar)
+ {
+ // Check for reading overlapped pointer field in @safe code.
+ if (checkUnsafeAccess(sc, e1, true, true))
+ return new ErrorExp();
+ }
+ else if (e1->op == TOKdot)
+ {
+ e1->error("expression has no value");
+ return new ErrorExp();
+ }
+ else if (e1->op == TOKcall)
+ {
+ CallExp *ce = (CallExp *)e1;
+ // Check for reading overlapped pointer field in @safe code.
+ if (checkUnsafeAccess(sc, ce->e1, true, true))
+ return new ErrorExp();
+ }
+ }
+
+ if (!e1->type)
+ {
+ error(loc, "cannot resolve type for %s", e1->toChars());
+ e1 = new ErrorExp();
+ }
+ return e1;
+
+Leprop:
+ error(loc, "not a property %s", e1->toChars());
+ return new ErrorExp();
+
+Leproplvalue:
+ error(loc, "%s is not an lvalue", e1->toChars());
+ return new ErrorExp();
+}
+
+Expression *resolveProperties(Scope *sc, Expression *e)
+{
+ //printf("resolveProperties(%s)\n", e->toChars());
+
+ e = resolvePropertiesX(sc, e);
+ if (e->checkRightThis(sc))
+ return new ErrorExp();
+ return e;
+}
+
+/******************************
+ * Check the tail CallExp is really property function call.
+ */
+static bool checkPropertyCall(Expression *e)
+{
+ while (e->op == TOKcomma)
+ e = ((CommaExp *)e)->e2;
+
+ if (e->op == TOKcall)
+ {
+ CallExp *ce = (CallExp *)e;
+ TypeFunction *tf;
+ if (ce->f)
+ {
+ tf = (TypeFunction *)ce->f->type;
+ /* If a forward reference to ce->f, try to resolve it
+ */
+ if (!tf->deco && ce->f->_scope)
+ {
+ ce->f->semantic(ce->f->_scope);
+ tf = (TypeFunction *)ce->f->type;
+ }
+ }
+ else if (ce->e1->type->ty == Tfunction)
+ tf = (TypeFunction *)ce->e1->type;
+ else if (ce->e1->type->ty == Tdelegate)
+ tf = (TypeFunction *)ce->e1->type->nextOf();
+ else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
+ tf = (TypeFunction *)ce->e1->type->nextOf();
+ else
+ assert(0);
+ }
+ return false;
+}
+
+/******************************
+ * If e1 is a property function (template), resolve it.
+ */
+
+Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
+{
+ //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
+ OverloadSet *os;
+ FuncDeclaration *fd;
+ TemplateDeclaration *td;
+
+ if (e1->op == TOKdot)
+ {
+ DotExp *de = (DotExp *)e1;
+ if (de->e2->op == TOKoverloadset)
+ {
+ os = ((OverExp *)de->e2)->vars;
+ goto Los;
+ }
+ }
+ else if (e1->op == TOKoverloadset)
+ {
+ os = ((OverExp *)e1)->vars;
+ Los:
+ assert(os);
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ Dsymbol *s = os->a[i];
+ fd = s->isFuncDeclaration();
+ td = s->isTemplateDeclaration();
+ if (fd)
+ {
+ if (((TypeFunction *)fd->type)->isproperty)
+ return resolveProperties(sc, e1);
+ }
+ else if (td && td->onemember &&
+ (fd = td->onemember->isFuncDeclaration()) != NULL)
+ {
+ if (((TypeFunction *)fd->type)->isproperty ||
+ (fd->storage_class2 & STCproperty) ||
+ (td->_scope->stc & STCproperty))
+ {
+ return resolveProperties(sc, e1);
+ }
+ }
+ }
+ }
+ else if (e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+ if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
+ goto Ltd;
+ }
+ else if (e1->op == TOKdottd)
+ {
+ td = ((DotTemplateExp *)e1)->td;
+ goto Ltd;
+ }
+ else if (e1->op == TOKscope)
+ {
+ Dsymbol *s = ((ScopeExp *)e1)->sds;
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti && !ti->semanticRun && ti->tempdecl)
+ {
+ if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
+ goto Ltd;
+ }
+ }
+ else if (e1->op == TOKtemplate)
+ {
+ td = ((TemplateExp *)e1)->td;
+ Ltd:
+ assert(td);
+ if (td->onemember &&
+ (fd = td->onemember->isFuncDeclaration()) != NULL)
+ {
+ if (((TypeFunction *)fd->type)->isproperty ||
+ (fd->storage_class2 & STCproperty) ||
+ (td->_scope->stc & STCproperty))
+ {
+ return resolveProperties(sc, e1);
+ }
+ }
+ }
+ else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
+ {
+ DotVarExp *dve = (DotVarExp *)e1;
+ fd = dve->var->isFuncDeclaration();
+ goto Lfd;
+ }
+ else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
+ (sc->intypeof || !((VarExp *)e1)->var->needThis()))
+ {
+ fd = ((VarExp *)e1)->var->isFuncDeclaration();
+ Lfd:
+ assert(fd);
+ if (((TypeFunction *)fd->type)->isproperty)
+ return resolveProperties(sc, e1);
+ }
+ return e1;
+}
+
+
+// TODO: merge with Scope::search::searchScopes()
+static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
+{
+ Dsymbol *s = NULL;
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (!scx->scopesym)
+ continue;
+ if (scx->scopesym->isModule())
+ flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+ s = scx->scopesym->search(loc, ident, flags);
+ if (s)
+ {
+ // overload set contains only module scope symbols.
+ if (s->isOverloadSet())
+ break;
+ // selective/renamed imports also be picked up
+ if (AliasDeclaration *ad = s->isAliasDeclaration())
+ {
+ if (ad->_import)
+ break;
+ }
+ // See only module scope symbols for UFCS target.
+ Dsymbol *p = s->toParent2();
+ if (p && p->isModule())
+ break;
+ }
+ s = NULL;
+
+ // Stop when we hit a module, but keep going if that is not just under the global scope
+ if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
+ break;
+ }
+ return s;
+}
+
+/******************************
+ * Find symbol in accordance with the UFCS name look up rule
+ */
+
+Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
+{
+ //printf("searchUFCS(ident = %s)\n", ident->toChars());
+ Loc loc = ue->loc;
+ int flags = 0;
+ Dsymbol *s = NULL;
+
+ if (sc->flags & SCOPEignoresymbolvisibility)
+ flags |= IgnoreSymbolVisibility;
+
+ Dsymbol *sold = NULL;
+ if (global.params.bug10378 || global.params.check10378)
+ {
+ sold = searchScopes(sc, loc, ident, flags | IgnoreSymbolVisibility);
+ if (!global.params.check10378)
+ {
+ s = sold;
+ goto Lsearchdone;
+ }
+ }
+
+ // First look in local scopes
+ s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
+ if (!s)
+ {
+ // Second look in imported modules
+ s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
+
+ /** Still find private symbols, so that symbols that weren't access
+ * checked by the compiler remain usable. Once the deprecation is over,
+ * this should be moved to search_correct instead.
+ */
+ if (!s && !(flags & IgnoreSymbolVisibility))
+ {
+ s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
+ if (!s)
+ s = searchScopes(sc, loc, ident, flags | SearchImportsOnly | IgnoreSymbolVisibility);
+ if (s)
+ ::deprecation(loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toChars());
+ }
+ }
+ if (global.params.check10378)
+ {
+ Dsymbol *snew = s;
+ if (sold != snew)
+ Scope::deprecation10378(loc, sold, snew);
+ if (global.params.bug10378)
+ s = sold;
+ }
+Lsearchdone:
+
+ if (!s)
+ return ue->e1->type->Type::getProperty(loc, ident, 0);
+
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f)
+ {
+ TemplateDeclaration *td = getFuncTemplateDecl(f);
+ if (td)
+ {
+ if (td->overroot)
+ td = td->overroot;
+ s = td;
+ }
+ }
+
+ if (ue->op == TOKdotti)
+ {
+ DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
+ TemplateInstance *ti = new TemplateInstance(loc, s->ident);
+ ti->tiargs = dti->ti->tiargs; // for better diagnostic message
+ if (!ti->updateTempDecl(sc, s))
+ return new ErrorExp();
+ return new ScopeExp(loc, ti);
+ }
+ else
+ {
+ //printf("-searchUFCS() %s\n", s->toChars());
+ return new DsymbolExp(loc, s);
+ }
+}
+
+/******************************
+ * check e is exp.opDispatch!(tiargs) or not
+ * It's used to switch to UFCS the semantic analysis path
+ */
+
+bool isDotOpDispatch(Expression *e)
+{
+ return e->op == TOKdotti &&
+ ((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch;
+}
+
+/******************************
+ * Pull out callable entity with UFCS.
+ */
+
+Expression *resolveUFCS(Scope *sc, CallExp *ce)
+{
+ Loc loc = ce->loc;
+ Expression *eleft;
+ Expression *e;
+
+ if (ce->e1->op == TOKdotid)
+ {
+ DotIdExp *die = (DotIdExp *)ce->e1;
+ Identifier *ident = die->ident;
+
+ Expression *ex = semanticX(die, sc);
+ if (ex != die)
+ {
+ ce->e1 = ex;
+ return NULL;
+ }
+ eleft = die->e1;
+
+ Type *t = eleft->type->toBasetype();
+ if (t->ty == Tarray || t->ty == Tsarray ||
+ t->ty == Tnull || (t->isTypeBasic() && t->ty != Tvoid))
+ {
+ /* Built-in types and arrays have no callable properties, so do shortcut.
+ * It is necessary in: e.init()
+ */
+ }
+ else if (t->ty == Taarray)
+ {
+ if (ident == Id::remove)
+ {
+ /* Transform:
+ * aa.remove(arg) into delete aa[arg]
+ */
+ if (!ce->arguments || ce->arguments->dim != 1)
+ {
+ ce->error("expected key as argument to aa.remove()");
+ return new ErrorExp();
+ }
+ if (!eleft->type->isMutable())
+ {
+ ce->error("cannot remove key from %s associative array %s",
+ MODtoChars(t->mod), eleft->toChars());
+ return new ErrorExp();
+ }
+ Expression *key = (*ce->arguments)[0];
+ key = semantic(key, sc);
+ key = resolveProperties(sc, key);
+
+ TypeAArray *taa = (TypeAArray *)t;
+ key = key->implicitCastTo(sc, taa->index);
+
+ if (key->checkValue())
+ return new ErrorExp();
+
+ semanticTypeInfo(sc, taa->index);
+
+ return new RemoveExp(loc, eleft, key);
+ }
+ }
+ else
+ {
+ if (Expression *ey = semanticY(die, sc, 1))
+ {
+ if (ey->op == TOKerror)
+ return ey;
+ ce->e1 = ey;
+ if (isDotOpDispatch(ey))
+ {
+ unsigned errors = global.startGagging();
+ e = semantic(ce->syntaxCopy(), sc);
+ if (!global.endGagging(errors))
+ return e;
+ /* fall down to UFCS */
+ }
+ else
+ return NULL;
+ }
+ }
+ e = searchUFCS(sc, die, ident);
+ }
+ else if (ce->e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
+ if (Expression *ey = semanticY(dti, sc, 1))
+ {
+ ce->e1 = ey;
+ return NULL;
+ }
+ eleft = dti->e1;
+ e = searchUFCS(sc, dti, dti->ti->name);
+ }
+ else
+ return NULL;
+
+ // Rewrite
+ ce->e1 = e;
+ if (!ce->arguments)
+ ce->arguments = new Expressions();
+ ce->arguments->shift(eleft);
+
+ return NULL;
+}
+
+/******************************
+ * Pull out property with UFCS.
+ */
+
+Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+ Loc loc = e1->loc;
+ Expression *eleft;
+ Expression *e;
+
+ if (e1->op == TOKdotid)
+ {
+ DotIdExp *die = (DotIdExp *)e1;
+ eleft = die->e1;
+ e = searchUFCS(sc, die, die->ident);
+ }
+ else if (e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp *dti;
+ dti = (DotTemplateInstanceExp *)e1;
+ eleft = dti->e1;
+ e = searchUFCS(sc, dti, dti->ti->name);
+ }
+ else
+ return NULL;
+
+ if (e == NULL)
+ return NULL;
+
+ // Rewrite
+ if (e2)
+ {
+ // run semantic without gagging
+ e2 = semantic(e2, sc);
+
+ /* f(e1) = e2
+ */
+ Expression *ex = e->copy();
+ Expressions *a1 = new Expressions();
+ a1->setDim(1);
+ (*a1)[0] = eleft;
+ ex = new CallExp(loc, ex, a1);
+ ex = trySemantic(ex, sc);
+
+ /* f(e1, e2)
+ */
+ Expressions *a2 = new Expressions();
+ a2->setDim(2);
+ (*a2)[0] = eleft;
+ (*a2)[1] = e2;
+ e = new CallExp(loc, e, a2);
+ if (ex)
+ { // if fallback setter exists, gag errors
+ e = trySemantic(e, sc);
+ if (!e)
+ { checkPropertyCall(ex);
+ ex = new AssignExp(loc, ex, e2);
+ return semantic(ex, sc);
+ }
+ }
+ else
+ { // strict setter prints errors if fails
+ e = semantic(e, sc);
+ }
+ checkPropertyCall(e);
+ return e;
+ }
+ else
+ {
+ /* f(e1)
+ */
+ Expressions *arguments = new Expressions();
+ arguments->setDim(1);
+ (*arguments)[0] = eleft;
+ e = new CallExp(loc, e, arguments);
+ e = semantic(e, sc);
+ checkPropertyCall(e);
+ return semantic(e, sc);
+ }
+}
+
+/******************************
+ * Perform semantic() on an array of Expressions.
+ */
+
+bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
+{
+ bool err = false;
+ if (exps)
+ {
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *e = (*exps)[i];
+ if (e)
+ {
+ e = semantic(e, sc);
+ if (e->op == TOKerror)
+ err = true;
+ if (preserveErrors || e->op != TOKerror)
+ (*exps)[i] = e;
+ }
+ }
+ }
+ return err;
+}
+
+/****************************************
+ * Expand tuples.
+ * Input:
+ * exps aray of Expressions
+ * Output:
+ * exps rewritten in place
+ */
+
+void expandTuples(Expressions *exps)
+{
+ //printf("expandTuples()\n");
+ if (exps)
+ {
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *arg = (*exps)[i];
+ if (!arg)
+ continue;
+
+ // Look for tuple with 0 members
+ if (arg->op == TOKtype)
+ {
+ TypeExp *e = (TypeExp *)arg;
+ if (e->type->toBasetype()->ty == Ttuple)
+ {
+ TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
+
+ if (!tt->arguments || tt->arguments->dim == 0)
+ {
+ exps->remove(i);
+ if (i == exps->dim)
+ return;
+ i--;
+ continue;
+ }
+ }
+ }
+
+ // Inline expand all the tuples
+ while (arg->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)arg;
+ exps->remove(i); // remove arg
+ exps->insert(i, te->exps); // replace with tuple contents
+ if (i == exps->dim)
+ return; // empty tuple, no more arguments
+ (*exps)[i] = Expression::combine(te->e0, (*exps)[i]);
+ arg = (*exps)[i];
+ }
+ }
+ }
+}
+
+/****************************************
+ * Expand alias this tuples.
+ */
+
+TupleDeclaration *isAliasThisTuple(Expression *e)
+{
+ if (!e->type)
+ return NULL;
+
+ Type *t = e->type->toBasetype();
+Lagain:
+ if (Dsymbol *s = t->toDsymbol(NULL))
+ {
+ AggregateDeclaration *ad = s->isAggregateDeclaration();
+ if (ad)
+ {
+ s = ad->aliasthis;
+ if (s && s->isVarDeclaration())
+ {
+ TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration();
+ if (td && td->isexp)
+ return td;
+ }
+ if (Type *att = t->aliasthisOf())
+ {
+ t = att;
+ goto Lagain;
+ }
+ }
+ }
+ return NULL;
+}
+
+int expandAliasThisTuples(Expressions *exps, size_t starti)
+{
+ if (!exps || exps->dim == 0)
+ return -1;
+
+ for (size_t u = starti; u < exps->dim; u++)
+ {
+ Expression *exp = (*exps)[u];
+ TupleDeclaration *td = isAliasThisTuple(exp);
+ if (td)
+ {
+ exps->remove(u);
+ for (size_t i = 0; i<td->objects->dim; ++i)
+ {
+ Expression *e = isExpression((*td->objects)[i]);
+ assert(e);
+ assert(e->op == TOKdsymbol);
+ DsymbolExp *se = (DsymbolExp *)e;
+ Declaration *d = se->s->isDeclaration();
+ assert(d);
+ e = new DotVarExp(exp->loc, exp, d);
+ assert(d->type);
+ e->type = d->type;
+ exps->insert(u + i, e);
+ }
+ return (int)u;
+ }
+ }
+
+ return -1;
+}
+
+/****************************************
+ * The common type is determined by applying ?: to each pair.
+ * Output:
+ * exps[] properties resolved, implicitly cast to common type, rewritten in place
+ * *pt if pt is not NULL, set to the common type
+ * Returns:
+ * true a semantic error was detected
+ */
+
+bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
+{
+ /* Still have a problem with:
+ * ubyte[][] = [ cast(ubyte[])"hello", [1]];
+ * which works if the array literal is initialized top down with the ubyte[][]
+ * type, but fails with this function doing bottom up typing.
+ */
+ //printf("arrayExpressionToCommonType()\n");
+ IntegerExp integerexp(0);
+ CondExp condexp(Loc(), &integerexp, NULL, NULL);
+
+ Type *t0 = NULL;
+ Expression *e0 = NULL; // dead-store to prevent spurious warning
+ size_t j0 = ~0; // dead-store to prevent spurious warning
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *e = (*exps)[i];
+ if (!e)
+ continue;
+
+ e = resolveProperties(sc, e);
+ if (!e->type)
+ {
+ e->error("%s has no value", e->toChars());
+ t0 = Type::terror;
+ continue;
+ }
+ if (e->op == TOKtype)
+ {
+ e->checkValue(); // report an error "type T has no value"
+ t0 = Type::terror;
+ continue;
+ }
+ if (e->type->ty == Tvoid)
+ {
+ // void expressions do not concur to the determination of the common
+ // type.
+ continue;
+ }
+ if (checkNonAssignmentArrayOp(e))
+ {
+ t0 = Type::terror;
+ continue;
+ }
+
+ e = doCopyOrMove(sc, e);
+
+ if (t0 && !t0->equals(e->type))
+ {
+ /* This applies ?: to merge the types. It's backwards;
+ * ?: should call this function to merge types.
+ */
+ condexp.type = NULL;
+ condexp.e1 = e0;
+ condexp.e2 = e;
+ condexp.loc = e->loc;
+ Expression *ex = semantic(&condexp, sc);
+ if (ex->op == TOKerror)
+ e = ex;
+ else
+ {
+ (*exps)[j0] = condexp.e1;
+ e = condexp.e2;
+ }
+ }
+ j0 = i;
+ e0 = e;
+ t0 = e->type;
+ if (e->op != TOKerror)
+ (*exps)[i] = e;
+ }
+
+ if (!t0)
+ t0 = Type::tvoid; // [] is typed as void[]
+ else if (t0->ty != Terror)
+ {
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *e = (*exps)[i];
+ if (!e)
+ continue;
+
+ e = e->implicitCastTo(sc, t0);
+ //assert(e->op != TOKerror);
+ if (e->op == TOKerror)
+ {
+ /* Bugzilla 13024: a workaround for the bug in typeMerge -
+ * it should paint e1 and e2 by deduced common type,
+ * but doesn't in this particular case.
+ */
+ t0 = Type::terror;
+ break;
+ }
+ (*exps)[i] = e;
+ }
+ }
+ if (pt)
+ *pt = t0;
+
+ return (t0 == Type::terror);
+}
+
+/****************************************
+ * Get TemplateDeclaration enclosing FuncDeclaration.
+ */
+
+TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s)
+{
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f && f->parent)
+ {
+ TemplateInstance *ti = f->parent->isTemplateInstance();
+ if (ti && !ti->isTemplateMixin() &&
+ ti->tempdecl && ((TemplateDeclaration *)ti->tempdecl)->onemember &&
+ ti->tempdecl->ident == f->ident)
+ {
+ return (TemplateDeclaration *)ti->tempdecl;
+ }
+ }
+ return NULL;
+}
+
+/************************************************
+ * If we want the value of this expression, but do not want to call
+ * the destructor on it.
+ */
+
+Expression *valueNoDtor(Expression *e)
+{
+ if (e->op == TOKcall)
+ {
+ /* The struct value returned from the function is transferred
+ * so do not call the destructor on it.
+ * Recognize:
+ * ((S _ctmp = S.init), _ctmp).this(...)
+ * and make sure the destructor is not called on _ctmp
+ * BUG: if e is a CommaExp, we should go down the right side.
+ */
+ CallExp *ce = (CallExp *)e;
+ if (ce->e1->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp *)ce->e1;
+ if (dve->var->isCtorDeclaration())
+ {
+ // It's a constructor call
+ if (dve->e1->op == TOKcomma)
+ {
+ CommaExp *comma = (CommaExp *)dve->e1;
+ if (comma->e2->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)comma->e2;
+ VarDeclaration *ctmp = ve->var->isVarDeclaration();
+ if (ctmp)
+ {
+ ctmp->storage_class |= STCnodtor;
+ assert(!ce->isLvalue());
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (e->op == TOKvar)
+ {
+ VarDeclaration *vtmp = ((VarExp *)e)->var->isVarDeclaration();
+ if (vtmp && vtmp->storage_class & STCrvalue)
+ {
+ vtmp->storage_class |= STCnodtor;
+ }
+ }
+ return e;
+}
+
+/********************************************
+ * Issue an error if default construction is disabled for type t.
+ * Default construction is required for arrays and 'out' parameters.
+ * Returns:
+ * true an error was issued
+ */
+bool checkDefCtor(Loc loc, Type *t)
+{
+ t = t->baseElemOf();
+ if (t->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)t)->sym;
+ if (sd->noDefaultCtor)
+ {
+ sd->error(loc, "default construction is disabled");
+ return true;
+ }
+ }
+ return false;
+}
+
+/*********************************************
+ * If e is an instance of a struct, and that struct has a copy constructor,
+ * rewrite e as:
+ * (tmp = e),tmp
+ * Input:
+ * sc just used to specify the scope of created temporary variable
+ */
+Expression *callCpCtor(Scope *sc, Expression *e)
+{
+ Type *tv = e->type->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+ if (sd->postblit)
+ {
+ /* Create a variable tmp, and replace the argument e with:
+ * (tmp = e),tmp
+ * and let AssignExp() handle the construction.
+ * This is not the most efficent, ideally tmp would be constructed
+ * directly onto the stack.
+ */
+ VarDeclaration *tmp = copyToTemp(STCrvalue, "__copytmp", e);
+ tmp->storage_class |= STCnodtor;
+ tmp->semantic(sc);
+ Expression *de = new DeclarationExp(e->loc, tmp);
+ Expression *ve = new VarExp(e->loc, tmp);
+ de->type = Type::tvoid;
+ ve->type = e->type;
+ e = Expression::combine(de, ve);
+ }
+ }
+ return e;
+}
+
+/************************************************
+ * Handle the postblit call on lvalue, or the move of rvalue.
+ */
+Expression *doCopyOrMove(Scope *sc, Expression *e)
+{
+ if (e->op == TOKquestion)
+ {
+ CondExp *ce = (CondExp *)e;
+ ce->e1 = doCopyOrMove(sc, ce->e1);
+ ce->e2 = doCopyOrMove(sc, ce->e2);
+ }
+ else
+ {
+ e = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
+ }
+ return e;
+}
+
+/****************************************
+ * Now that we know the exact type of the function we're calling,
+ * the arguments[] need to be adjusted:
+ * 1. implicitly convert argument to the corresponding parameter type
+ * 2. add default arguments for any missing arguments
+ * 3. do default promotions on arguments corresponding to ...
+ * 4. add hidden _arguments[] argument
+ * 5. call copy constructor for struct value arguments
+ * Input:
+ * tf type of the function
+ * fd the function being called, NULL if called indirectly
+ * Output:
+ * *prettype return type of function
+ * *peprefix expression to execute before arguments[] are evaluated, NULL if none
+ * Returns:
+ * true errors happened
+ */
+
+bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
+ Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
+{
+ //printf("functionParameters()\n");
+ assert(arguments);
+ assert(fd || tf->next);
+ size_t nargs = arguments ? arguments->dim : 0;
+ size_t nparams = Parameter::dim(tf->parameters);
+ unsigned olderrors = global.errors;
+ bool err = false;
+ *prettype = Type::terror;
+ Expression *eprefix = NULL;
+ *peprefix = NULL;
+
+ if (nargs > nparams && tf->varargs == 0)
+ {
+ error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
+ return true;
+ }
+
+ // If inferring return type, and semantic3() needs to be run if not already run
+ if (!tf->next && fd->inferRetType)
+ {
+ fd->functionSemantic();
+ }
+ else if (fd && fd->parent)
+ {
+ TemplateInstance *ti = fd->parent->isTemplateInstance();
+ if (ti && ti->tempdecl)
+ {
+ fd->functionSemantic3();
+ }
+ }
+ bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
+
+ size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
+
+ /* If the function return type has wildcards in it, we'll need to figure out the actual type
+ * based on the actual argument types.
+ */
+ MOD wildmatch = 0;
+ if (tthis && tf->isWild() && !isCtorCall)
+ {
+ Type *t = tthis;
+ if (t->isImmutable())
+ wildmatch = MODimmutable;
+ else if (t->isWildConst())
+ wildmatch = MODwildconst;
+ else if (t->isWild())
+ wildmatch = MODwild;
+ else if (t->isConst())
+ wildmatch = MODconst;
+ else
+ wildmatch = MODmutable;
+ }
+
+ int done = 0;
+ for (size_t i = 0; i < n; i++)
+ {
+ Expression *arg;
+
+ if (i < nargs)
+ arg = (*arguments)[i];
+ else
+ arg = NULL;
+
+ if (i < nparams)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, i);
+
+ if (!arg)
+ {
+ if (!p->defaultArg)
+ {
+ if (tf->varargs == 2 && i + 1 == nparams)
+ goto L2;
+ error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+ return true;
+ }
+ arg = p->defaultArg;
+ arg = inlineCopy(arg, sc);
+ // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
+ arg = arg->resolveLoc(loc, sc);
+ arguments->push(arg);
+ nargs++;
+ }
+
+ if (tf->varargs == 2 && i + 1 == nparams)
+ {
+ //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
+ {
+ MATCH m;
+ if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
+ {
+ if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
+ goto L2;
+ else if (nargs != nparams)
+ { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+ return true;
+ }
+ goto L1;
+ }
+ }
+ L2:
+ Type *tb = p->type->toBasetype();
+ Type *tret = p->isLazyArray();
+ switch (tb->ty)
+ {
+ case Tsarray:
+ case Tarray:
+ {
+ /* Create a static array variable v of type arg->type:
+ * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
+ *
+ * The array literal in the initializer of the hidden variable
+ * is now optimized. See Bugzilla 2356.
+ */
+ Type *tbn = ((TypeArray *)tb)->next;
+ Type *tsa = tbn->sarrayOf(nargs - i);
+
+ Expressions *elements = new Expressions();
+ elements->setDim(nargs - i);
+ for (size_t u = 0; u < elements->dim; u++)
+ {
+ Expression *a = (*arguments)[i + u];
+ if (tret && a->implicitConvTo(tret))
+ {
+ a = a->implicitCastTo(sc, tret);
+ a = a->optimize(WANTvalue);
+ a = toDelegate(a, a->type, sc);
+ }
+ else
+ a = a->implicitCastTo(sc, tbn);
+ (*elements)[u] = a;
+ }
+ // Bugzilla 14395: Convert to a static array literal, or its slice.
+ arg = new ArrayLiteralExp(loc, elements);
+ arg->type = tsa;
+ if (tb->ty == Tarray)
+ {
+ arg = new SliceExp(loc, arg, NULL, NULL);
+ arg->type = p->type;
+ }
+ break;
+ }
+ case Tclass:
+ {
+ /* Set arg to be:
+ * new Tclass(arg0, arg1, ..., argn)
+ */
+ Expressions *args = new Expressions();
+ args->setDim(nargs - i);
+ for (size_t u = i; u < nargs; u++)
+ (*args)[u - i] = (*arguments)[u];
+ arg = new NewExp(loc, NULL, NULL, p->type, args);
+ break;
+ }
+ default:
+ if (!arg)
+ {
+ error(loc, "not enough arguments");
+ return true;
+ }
+ break;
+ }
+ arg = semantic(arg, sc);
+ //printf("\targ = '%s'\n", arg->toChars());
+ arguments->setDim(i + 1);
+ (*arguments)[i] = arg;
+ nargs = i + 1;
+ done = 1;
+ }
+
+ L1:
+ if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+ {
+ bool isRef = (p->storageClass & (STCref | STCout)) != 0;
+ if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
+ {
+ if (wildmatch)
+ wildmatch = MODmerge(wildmatch, wm);
+ else
+ wildmatch = wm;
+ //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
+ }
+ }
+ }
+ if (done)
+ break;
+ }
+ if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
+ tf->next->hasWild() &&
+ (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
+ {
+ if (fd)
+ {
+ /* If the called function may return the reference to
+ * outer inout data, it should be rejected.
+ *
+ * void foo(ref inout(int) x) {
+ * ref inout(int) bar(inout(int)) { return x; }
+ * struct S { ref inout(int) bar() inout { return x; } }
+ * bar(int.init) = 1; // bad!
+ * S().bar() = 1; // bad!
+ * }
+ */
+ Dsymbol *s = NULL;
+ if (fd->isThis() || fd->isNested())
+ s = fd->toParent2();
+ for (; s; s = s->toParent2())
+ {
+ if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+ {
+ if (ad->isNested())
+ continue;
+ break;
+ }
+ if (FuncDeclaration *ff = s->isFuncDeclaration())
+ {
+ if (((TypeFunction *)ff->type)->iswild)
+ goto Linouterr;
+
+ if (ff->isNested() || ff->isThis())
+ continue;
+ }
+ break;
+ }
+ }
+ else if (tf->isWild())
+ {
+ Linouterr:
+ const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
+ error(loc, "modify inout to %s is not allowed inside inout function", s);
+ return true;
+ }
+ }
+
+ assert(nargs >= nparams);
+ for (size_t i = 0; i < nargs; i++)
+ {
+ Expression *arg = (*arguments)[i];
+ assert(arg);
+ if (i < nparams)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, i);
+
+ if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+ {
+ Type *tprm = p->type;
+ if (p->type->hasWild())
+ tprm = p->type->substWildTo(wildmatch);
+ if (!tprm->equals(arg->type))
+ {
+ //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
+ arg = arg->implicitCastTo(sc, tprm);
+ arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+ }
+ }
+ if (p->storageClass & STCref)
+ {
+ arg = arg->toLvalue(sc, arg);
+
+ // Look for mutable misaligned pointer, etc., in @safe mode
+ err |= checkUnsafeAccess(sc, arg, false, true);
+ }
+ else if (p->storageClass & STCout)
+ {
+ Type *t = arg->type;
+ if (!t->isMutable() || !t->isAssignable()) // check blit assignable
+ {
+ arg->error("cannot modify struct %s with immutable members", arg->toChars());
+ err = true;
+ }
+ else
+ {
+ // Look for misaligned pointer, etc., in @safe mode
+ err |= checkUnsafeAccess(sc, arg, false, true);
+ err |= checkDefCtor(arg->loc, t); // t must be default constructible
+ }
+ arg = arg->toLvalue(sc, arg);
+ }
+ else if (p->storageClass & STClazy)
+ {
+ // Convert lazy argument to a delegate
+ if (p->type->ty == Tvoid)
+ arg = toDelegate(arg, p->type, sc);
+ else
+ arg = toDelegate(arg, arg->type, sc);
+ }
+
+ //printf("arg: %s\n", arg->toChars());
+ //printf("type: %s\n", arg->type->toChars());
+ if (tf->parameterEscapes(p))
+ {
+ /* Argument value can escape from the called function.
+ * Check arg to see if it matters.
+ */
+ if (global.params.vsafe)
+ err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
+ }
+ else
+ {
+ /* Argument value cannot escape from the called function.
+ */
+ Expression *a = arg;
+ if (a->op == TOKcast)
+ a = ((CastExp *)a)->e1;
+
+ if (a->op == TOKfunction)
+ {
+ /* Function literals can only appear once, so if this
+ * appearance was scoped, there cannot be any others.
+ */
+ FuncExp *fe = (FuncExp *)a;
+ fe->fd->tookAddressOf = 0;
+ }
+ else if (a->op == TOKdelegate)
+ {
+ /* For passing a delegate to a scoped parameter,
+ * this doesn't count as taking the address of it.
+ * We only worry about 'escaping' references to the function.
+ */
+ DelegateExp *de = (DelegateExp *)a;
+ if (de->e1->op == TOKvar)
+ { VarExp *ve = (VarExp *)de->e1;
+ FuncDeclaration *f = ve->var->isFuncDeclaration();
+ if (f)
+ { f->tookAddressOf--;
+ //printf("tookAddressOf = %d\n", f->tookAddressOf);
+ }
+ }
+ }
+ }
+ arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+ }
+ else
+ {
+ // These will be the trailing ... arguments
+
+ // If not D linkage, do promotions
+ if (tf->linkage != LINKd)
+ {
+ // Promote bytes, words, etc., to ints
+ arg = integralPromotions(arg, sc);
+
+ // Promote floats to doubles
+ switch (arg->type->ty)
+ {
+ case Tfloat32:
+ arg = arg->castTo(sc, Type::tfloat64);
+ break;
+
+ case Timaginary32:
+ arg = arg->castTo(sc, Type::timaginary64);
+ break;
+ }
+
+ if (tf->varargs == 1)
+ {
+ const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
+ if (arg->type->ty == Tarray)
+ {
+ arg->error("cannot pass dynamic arrays to %s vararg functions", p);
+ err = true;
+ }
+ if (arg->type->ty == Tsarray)
+ {
+ arg->error("cannot pass static arrays to %s vararg functions", p);
+ err = true;
+ }
+ }
+ }
+
+ // Do not allow types that need destructors
+ if (arg->type->needsDestruction())
+ {
+ arg->error("cannot pass types that need destruction as variadic arguments");
+ err = true;
+ }
+
+ // Convert static arrays to dynamic arrays
+ // BUG: I don't think this is right for D2
+ Type *tb = arg->type->toBasetype();
+ if (tb->ty == Tsarray)
+ {
+ TypeSArray *ts = (TypeSArray *)tb;
+ Type *ta = ts->next->arrayOf();
+ if (ts->size(arg->loc) == 0)
+ arg = new NullExp(arg->loc, ta);
+ else
+ arg = arg->castTo(sc, ta);
+ }
+ if (tb->ty == Tstruct)
+ {
+ //arg = callCpCtor(sc, arg);
+ }
+
+ // Give error for overloaded function addresses
+ if (arg->op == TOKsymoff)
+ { SymOffExp *se = (SymOffExp *)arg;
+ if (se->hasOverloads &&
+ !se->var->isFuncDeclaration()->isUnique())
+ { arg->error("function %s is overloaded", arg->toChars());
+ err = true;
+ }
+ }
+ if (arg->checkValue())
+ err = true;
+ arg = arg->optimize(WANTvalue);
+ }
+ (*arguments)[i] = arg;
+ }
+
+ /* Remaining problems:
+ * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
+ * implemented by calling a function) we'll defer this for now.
+ * 2. value structs (or static arrays of them) that need to be copy constructed
+ * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
+ * function gets called (functions normally destroy their parameters)
+ * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
+ * up properly. Pushing arguments on the stack then cannot fail.
+ */
+ if (1)
+ {
+ /* TODO: tackle problem 1)
+ */
+ const bool leftToRight = true; // TODO: something like !fd.isArrayOp
+ if (!leftToRight)
+ assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
+
+ const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
+ const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
+ const ptrdiff_t step = (leftToRight ? 1 : -1);
+
+ /* Compute indices of last throwing argument and first arg needing destruction.
+ * Used to not set up destructors unless an arg needs destruction on a throw
+ * in a later argument.
+ */
+ ptrdiff_t lastthrow = -1;
+ ptrdiff_t firstdtor = -1;
+ for (ptrdiff_t i = start; i != end; i += step)
+ {
+ Expression *arg = (*arguments)[i];
+ if (canThrow(arg, sc->func, false))
+ lastthrow = i;
+ if (firstdtor == -1 && arg->type->needsDestruction())
+ {
+ Parameter *p = (i >= (ptrdiff_t)nparams ? NULL : Parameter::getNth(tf->parameters, i));
+ if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
+ firstdtor = i;
+ }
+ }
+
+ /* Does problem 3) apply to this call?
+ */
+ const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
+ && (lastthrow - firstdtor) * step > 0);
+
+ /* If so, initialize 'eprefix' by declaring the gate
+ */
+ VarDeclaration *gate = NULL;
+ if (needsPrefix)
+ {
+ // eprefix => bool __gate [= false]
+ Identifier *idtmp = Identifier::generateId("__gate");
+ gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
+ gate->storage_class |= STCtemp | STCctfe | STCvolatile;
+ gate->semantic(sc);
+
+ Expression *ae = new DeclarationExp(loc, gate);
+ eprefix = semantic(ae, sc);
+ }
+
+ for (ptrdiff_t i = start; i != end; i += step)
+ {
+ Expression *arg = (*arguments)[i];
+
+ Parameter *parameter = (i >= (ptrdiff_t)nparams ? NULL : Parameter::getNth(tf->parameters, i));
+ const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
+ const bool isLazy = (parameter && (parameter->storageClass & STClazy));
+
+ /* Skip lazy parameters
+ */
+ if (isLazy)
+ continue;
+
+ /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
+ * Declare a temporary variable for this arg and append that declaration to 'eprefix',
+ * which will implicitly take care of potential problem 2) for this arg.
+ * 'eprefix' will therefore finally contain all args up to and including the last
+ * potentially throwing arg, excluding all lazy parameters.
+ */
+ if (gate)
+ {
+ const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
+
+ /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
+ */
+ VarDeclaration *tmp = copyToTemp(0,
+ needsDtor ? "__pfx" : "__pfy",
+ !isRef ? arg : arg->addressOf());
+ tmp->semantic(sc);
+
+ /* Modify the destructor so it only runs if gate==false, i.e.,
+ * only if there was a throw while constructing the args
+ */
+ if (!needsDtor)
+ {
+ if (tmp->edtor)
+ {
+ assert(i == lastthrow);
+ tmp->edtor = NULL;
+ }
+ }
+ else
+ {
+ // edtor => (__gate || edtor)
+ assert(tmp->edtor);
+ Expression *e = tmp->edtor;
+ e = new OrOrExp(e->loc, new VarExp(e->loc, gate), e);
+ tmp->edtor = semantic(e, sc);
+ //printf("edtor: %s\n", tmp->edtor->toChars());
+ }
+
+ // eprefix => (eprefix, auto __pfx/y = arg)
+ DeclarationExp *ae = new DeclarationExp(loc, tmp);
+ eprefix = Expression::combine(eprefix, semantic(ae, sc));
+
+ // arg => __pfx/y
+ arg = new VarExp(loc, tmp);
+ arg = semantic(arg, sc);
+ if (isRef)
+ {
+ arg = new PtrExp(loc, arg);
+ arg = semantic(arg, sc);
+ }
+
+ /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
+ * i.e., disable the dtors right after constructing the last throwing arg.
+ * From now on, the callee will take care of destructing the args because
+ * the args are implicitly moved into function parameters.
+ *
+ * Set gate to null to let the next iterations know they don't need to
+ * append to eprefix anymore.
+ */
+ if (i == lastthrow)
+ {
+ Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
+ eprefix = Expression::combine(eprefix, semantic(e, sc));
+ gate = NULL;
+ }
+ }
+ else
+ {
+ /* No gate, no prefix to append to.
+ * Handle problem 2) by calling the copy constructor for value structs
+ * (or static arrays of them) if appropriate.
+ */
+ Type *tv = arg->type->baseElemOf();
+ if (!isRef && tv->ty == Tstruct)
+ arg = doCopyOrMove(sc, arg);
+ }
+
+ (*arguments)[i] = arg;
+ }
+ }
+ //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
+
+ // If D linkage and variadic, add _arguments[] as first argument
+ if (tf->linkage == LINKd && tf->varargs == 1)
+ {
+ assert(arguments->dim >= nparams);
+
+ Parameters *args = new Parameters;
+ args->setDim(arguments->dim - nparams);
+ for (size_t i = 0; i < arguments->dim - nparams; i++)
+ {
+ Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL);
+ (*args)[i] = arg;
+ }
+
+ TypeTuple *tup = new TypeTuple(args);
+ Expression *e = new TypeidExp(loc, tup);
+ e = semantic(e, sc);
+ arguments->insert(0, e);
+ }
+
+ Type *tret = tf->next;
+ if (isCtorCall)
+ {
+ //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
+ // wildmatch, tf->isWild(), fd->isolateReturn());
+ if (!tthis)
+ {
+ assert(sc->intypeof || global.errors);
+ tthis = fd->isThis()->type->addMod(fd->type->mod);
+ }
+ if (tf->isWild() && !fd->isolateReturn())
+ {
+ if (wildmatch)
+ tret = tret->substWildTo(wildmatch);
+ int offset;
+ if (!tret->implicitConvTo(tthis) &&
+ !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
+ {
+ const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
+ const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
+ ::error(loc, "inout constructor %s creates%s object, not%s",
+ fd->toPrettyChars(), s1, s2);
+ err = true;
+ }
+ }
+ tret = tthis;
+ }
+ else if (wildmatch && tret)
+ {
+ /* Adjust function return type based on wildmatch
+ */
+ //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
+ tret = tret->substWildTo(wildmatch);
+ }
+ *prettype = tret;
+ *peprefix = eprefix;
+ return (err || olderrors != global.errors);
+}
+
+/******************************** Expression **************************/
+
+Expression::Expression(Loc loc, TOK op, int size)
+{
+ //printf("Expression::Expression(op = %d) this = %p\n", op, this);
+ this->loc = loc;
+ this->op = op;
+ this->size = (unsigned char)size;
+ this->parens = 0;
+ type = NULL;
+}
+
+void Expression::_init()
+{
+ CTFEExp::cantexp = new CTFEExp(TOKcantexp);
+ CTFEExp::voidexp = new CTFEExp(TOKvoidexp);
+ CTFEExp::breakexp = new CTFEExp(TOKbreak);
+ CTFEExp::continueexp = new CTFEExp(TOKcontinue);
+ CTFEExp::gotoexp = new CTFEExp(TOKgoto);
+}
+
+Expression *Expression::syntaxCopy()
+{
+ //printf("Expression::syntaxCopy()\n");
+ //print();
+ return copy();
+}
+
+/*********************************
+ * Does *not* do a deep copy.
+ */
+
+Expression *Expression::copy()
+{
+ Expression *e;
+ if (!size)
+ {
+ assert(0);
+ }
+ void *pe = mem.xmalloc(size);
+ //printf("Expression::copy(op = %d) e = %p\n", op, pe);
+ e = (Expression *)memcpy(pe, (void *)this, size);
+ return e;
+}
+
+void Expression::print()
+{
+ fprintf(stderr, "%s\n", toChars());
+ fflush(stderr);
+}
+
+const char *Expression::toChars()
+{
+ OutBuffer buf;
+ HdrGenState hgs;
+ toCBuffer(this, &buf, &hgs);
+ return buf.extractString();
+}
+
+void Expression::error(const char *format, ...) const
+{
+ if (type != Type::terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ ::verror(loc, format, ap);
+ va_end( ap );
+ }
+}
+
+void Expression::warning(const char *format, ...) const
+{
+ if (type != Type::terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ ::vwarning(loc, format, ap);
+ va_end( ap );
+ }
+}
+
+void Expression::deprecation(const char *format, ...) const
+{
+ if (type != Type::terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ ::vdeprecation(loc, format, ap);
+ va_end( ap );
+ }
+}
+
+/**********************************
+ * Combine e1 and e2 by CommaExp if both are not NULL.
+ */
+Expression *Expression::combine(Expression *e1, Expression *e2)
+{
+ if (e1)
+ {
+ if (e2)
+ {
+ e1 = new CommaExp(e1->loc, e1, e2);
+ e1->type = e2->type;
+ }
+ }
+ else
+ e1 = e2;
+ return e1;
+}
+
+/**********************************
+ * If 'e' is a tree of commas, returns the leftmost expression
+ * by stripping off it from the tree. The remained part of the tree
+ * is returned via *pe0.
+ * Otherwise 'e' is directly returned and *pe0 is set to NULL.
+ */
+Expression *Expression::extractLast(Expression *e, Expression **pe0)
+{
+ if (e->op != TOKcomma)
+ {
+ *pe0 = NULL;
+ return e;
+ }
+
+ CommaExp *ce = (CommaExp *)e;
+ if (ce->e2->op != TOKcomma)
+ {
+ *pe0 = ce->e1;
+ return ce->e2;
+ }
+ else
+ {
+ *pe0 = e;
+
+ Expression **pce = &ce->e2;
+ while (((CommaExp *)(*pce))->e2->op == TOKcomma)
+ {
+ pce = &((CommaExp *)(*pce))->e2;
+ }
+ assert((*pce)->op == TOKcomma);
+ ce = (CommaExp *)(*pce);
+ *pce = ce->e1;
+
+ return ce->e2;
+ }
+}
+
+dinteger_t Expression::toInteger()
+{
+ //printf("Expression %s\n", Token::toChars(op));
+ error("integer constant expression expected instead of %s", toChars());
+ return 0;
+}
+
+uinteger_t Expression::toUInteger()
+{
+ //printf("Expression %s\n", Token::toChars(op));
+ return (uinteger_t)toInteger();
+}
+
+real_t Expression::toReal()
+{
+ error("floating point constant expression expected instead of %s", toChars());
+ return CTFloat::zero;
+}
+
+real_t Expression::toImaginary()
+{
+ error("floating point constant expression expected instead of %s", toChars());
+ return CTFloat::zero;
+}
+
+complex_t Expression::toComplex()
+{
+ error("floating point constant expression expected instead of %s", toChars());
+ return complex_t(CTFloat::zero);
+}
+
+StringExp *Expression::toStringExp()
+{
+ return NULL;
+}
+
+/***************************************
+ * Return !=0 if expression is an lvalue.
+ */
+
+bool Expression::isLvalue()
+{
+ return false;
+}
+
+/*******************************
+ * Give error if we're not an lvalue.
+ * If we can, convert expression to be an lvalue.
+ */
+
+Expression *Expression::toLvalue(Scope *, Expression *e)
+{
+ if (!e)
+ e = this;
+ else if (!loc.filename)
+ loc = e->loc;
+
+ if (e->op == TOKtype)
+ error("%s '%s' is a type, not an lvalue", e->type->kind(), e->type->toChars());
+ else
+ error("%s is not an lvalue", e->toChars());
+
+ return new ErrorExp();
+}
+
+/***************************************
+ * Parameters:
+ * sc: scope
+ * flag: 1: do not issue error message for invalid modification
+ * Returns:
+ * 0: is not modifiable
+ * 1: is modifiable in default == being related to type->isMutable()
+ * 2: is modifiable, because this is a part of initializing.
+ */
+
+int Expression::checkModifiable(Scope *, int)
+{
+ return type ? 1 : 0; // default modifiable
+}
+
+Expression *Expression::modifiableLvalue(Scope *sc, Expression *e)
+{
+ //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars());
+
+ // See if this expression is a modifiable lvalue (i.e. not const)
+ if (checkModifiable(sc) == 1)
+ {
+ assert(type);
+ if (!type->isMutable())
+ {
+ error("cannot modify %s expression %s", MODtoChars(type->mod), toChars());
+ return new ErrorExp();
+ }
+ else if (!type->isAssignable())
+ {
+ error("cannot modify struct %s %s with immutable members", toChars(), type->toChars());
+ return new ErrorExp();
+ }
+ }
+ return toLvalue(sc, e);
+}
+
+/****************************************
+ * Check that the expression has a valid type.
+ * If not, generates an error "... has no type".
+ * Returns:
+ * true if the expression is not valid.
+ * Note:
+ * When this function returns true, `checkValue()` should also return true.
+ */
+bool Expression::checkType()
+{
+ return false;
+}
+
+/****************************************
+ * Check that the expression has a valid value.
+ * If not, generates an error "... has no value".
+ * Returns:
+ * true if the expression is not valid or has void type.
+ */
+bool Expression::checkValue()
+{
+ if (type && type->toBasetype()->ty == Tvoid)
+ {
+ error("expression %s is void and has no value", toChars());
+ //print(); halt();
+ if (!global.gag)
+ type = Type::terror;
+ return true;
+ }
+ return false;
+}
+
+bool Expression::checkScalar()
+{
+ if (op == TOKerror)
+ return true;
+ if (type->toBasetype()->ty == Terror)
+ return true;
+ if (!type->isscalar())
+ {
+ error("'%s' is not a scalar, it is a %s", toChars(), type->toChars());
+ return true;
+ }
+ return checkValue();
+}
+
+bool Expression::checkNoBool()
+{
+ if (op == TOKerror)
+ return true;
+ if (type->toBasetype()->ty == Terror)
+ return true;
+ if (type->toBasetype()->ty == Tbool)
+ {
+ error("operation not allowed on bool '%s'", toChars());
+ return true;
+ }
+ return false;
+}
+
+bool Expression::checkIntegral()
+{
+ if (op == TOKerror)
+ return true;
+ if (type->toBasetype()->ty == Terror)
+ return true;
+ if (!type->isintegral())
+ {
+ error("'%s' is not of integral type, it is a %s", toChars(), type->toChars());
+ return true;
+ }
+ return checkValue();
+}
+
+bool Expression::checkArithmetic()
+{
+ if (op == TOKerror)
+ return true;
+ if (type->toBasetype()->ty == Terror)
+ return true;
+ if (!type->isintegral() && !type->isfloating())
+ {
+ error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars());
+ return true;
+ }
+ return checkValue();
+}
+
+void Expression::checkDeprecated(Scope *sc, Dsymbol *s)
+{
+ s->checkDeprecated(loc, sc);
+}
+
+/*********************************************
+ * Calling function f.
+ * Check the purity, i.e. if we're in a pure function
+ * we can only call other pure functions.
+ * Returns true if error occurs.
+ */
+bool Expression::checkPurity(Scope *sc, FuncDeclaration *f)
+{
+ if (!sc->func)
+ return false;
+ if (sc->func == f)
+ return false;
+ if (sc->intypeof == 1)
+ return false;
+ if (sc->flags & (SCOPEctfe | SCOPEdebug))
+ return false;
+
+ /* Given:
+ * void f() {
+ * pure void g() {
+ * /+pure+/ void h() {
+ * /+pure+/ void i() { }
+ * }
+ * }
+ * }
+ * g() can call h() but not f()
+ * i() can call h() and g() but not f()
+ */
+
+ // Find the closest pure parent of the calling function
+ FuncDeclaration *outerfunc = sc->func;
+ FuncDeclaration *calledparent = f;
+
+ if (outerfunc->isInstantiated())
+ {
+ // The attributes of outerfunc should be inferred from the call of f.
+ }
+ else if (f->isInstantiated())
+ {
+ // The attributes of f are inferred from its body.
+ }
+ else if (f->isFuncLiteralDeclaration())
+ {
+ // The attributes of f are always inferred in its declared place.
+ }
+ else
+ {
+ /* Today, static local functions are impure by default, but they cannot
+ * violate purity of enclosing functions.
+ *
+ * auto foo() pure { // non instantiated funciton
+ * static auto bar() { // static, without pure attribute
+ * impureFunc(); // impure call
+ * // Although impureFunc is called inside bar, f(= impureFunc)
+ * // is not callable inside pure outerfunc(= foo <- bar).
+ * }
+ *
+ * bar();
+ * // Although bar is called inside foo, f(= bar) is callable
+ * // bacause calledparent(= foo) is same with outerfunc(= foo).
+ * }
+ */
+
+ while (outerfunc->toParent2() &&
+ outerfunc->isPureBypassingInference() == PUREimpure &&
+ outerfunc->toParent2()->isFuncDeclaration())
+ {
+ outerfunc = outerfunc->toParent2()->isFuncDeclaration();
+ if (outerfunc->type->ty == Terror)
+ return true;
+ }
+ while (calledparent->toParent2() &&
+ calledparent->isPureBypassingInference() == PUREimpure &&
+ calledparent->toParent2()->isFuncDeclaration())
+ {
+ calledparent = calledparent->toParent2()->isFuncDeclaration();
+ if (calledparent->type->ty == Terror)
+ return true;
+ }
+ }
+
+ // If the caller has a pure parent, then either the called func must be pure,
+ // OR, they must have the same pure parent.
+ if (!f->isPure() && calledparent != outerfunc)
+ {
+ FuncDeclaration *ff = outerfunc;
+ if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
+ {
+ error("pure %s '%s' cannot call impure %s '%s'",
+ ff->kind(), ff->toPrettyChars(), f->kind(), f->toPrettyChars());
+ return true;
+ }
+ }
+ return false;
+}
+
+/*******************************************
+ * Accessing variable v.
+ * Check for purity and safety violations.
+ * Returns true if error occurs.
+ */
+bool Expression::checkPurity(Scope *sc, VarDeclaration *v)
+{
+ //printf("v = %s %s\n", v->type->toChars(), v->toChars());
+
+ /* Look for purity and safety violations when accessing variable v
+ * from current function.
+ */
+ if (!sc->func)
+ return false;
+ if (sc->intypeof == 1)
+ return false; // allow violations inside typeof(expression)
+ if (sc->flags & (SCOPEctfe | SCOPEdebug))
+ return false; // allow violations inside compile-time evaluated expressions and debug conditionals
+ if (v->ident == Id::ctfe)
+ return false; // magic variable never violates pure and safe
+ if (v->isImmutable())
+ return false; // always safe and pure to access immutables...
+ if (v->isConst() && !v->isRef() && (v->isDataseg() || v->isParameter()) &&
+ v->type->implicitConvTo(v->type->immutableOf()))
+ return false; // or const global/parameter values which have no mutable indirections
+ if (v->storage_class & STCmanifest)
+ return false; // ...or manifest constants
+
+ bool err = false;
+ if (v->isDataseg())
+ {
+ // Bugzilla 7533: Accessing implicit generated __gate is pure.
+ if (v->ident == Id::gate)
+ return false;
+
+ /* Accessing global mutable state.
+ * Therefore, this function and all its immediately enclosing
+ * functions must be pure.
+ */
+ /* Today, static local functions are impure by default, but they cannot
+ * violate purity of enclosing functions.
+ *
+ * auto foo() pure { // non instantiated funciton
+ * static auto bar() { // static, without pure attribute
+ * globalData++; // impure access
+ * // Although globalData is accessed inside bar,
+ * // it is not accessible inside pure foo.
+ * }
+ * }
+ */
+ for (Dsymbol *s = sc->func; s; s = s->toParent2())
+ {
+ FuncDeclaration *ff = s->isFuncDeclaration();
+ if (!ff)
+ break;
+ if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
+ {
+ error("pure %s '%s' cannot access mutable static data '%s'",
+ ff->kind(), ff->toPrettyChars(), v->toChars());
+ err = true;
+ break;
+ }
+ /* If the enclosing is an instantiated function or a lambda, its
+ * attribute inference result is preferred.
+ */
+ if (ff->isInstantiated())
+ break;
+ if (ff->isFuncLiteralDeclaration())
+ break;
+ }
+ }
+ else
+ {
+ /* Given:
+ * void f() {
+ * int fx;
+ * pure void g() {
+ * int gx;
+ * /+pure+/ void h() {
+ * int hx;
+ * /+pure+/ void i() { }
+ * }
+ * }
+ * }
+ * i() can modify hx and gx but not fx
+ */
+
+ Dsymbol *vparent = v->toParent2();
+ for (Dsymbol *s = sc->func; !err && s; s = s->toParent2())
+ {
+ if (s == vparent)
+ break;
+
+ if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+ {
+ if (ad->isNested())
+ continue;
+ break;
+ }
+ FuncDeclaration *ff = s->isFuncDeclaration();
+ if (!ff)
+ break;
+ if (ff->isNested() || ff->isThis())
+ {
+ if (ff->type->isImmutable() ||
+ (ff->type->isShared() && !MODimplicitConv(ff->type->mod, v->type->mod)))
+ {
+ OutBuffer ffbuf;
+ OutBuffer vbuf;
+ MODMatchToBuffer(&ffbuf, ff->type->mod, v->type->mod);
+ MODMatchToBuffer(&vbuf, v->type->mod, ff->type->mod);
+ error("%s%s '%s' cannot access %sdata '%s'",
+ ffbuf.peekString(), ff->kind(), ff->toPrettyChars(), vbuf.peekString(), v->toChars());
+ err = true;
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+ }
+
+ /* Do not allow safe functions to access __gshared data
+ */
+ if (v->storage_class & STCgshared)
+ {
+ if (sc->func->setUnsafe())
+ {
+ error("safe %s '%s' cannot access __gshared data '%s'",
+ sc->func->kind(), sc->func->toChars(), v->toChars());
+ err = true;
+ }
+ }
+
+ return err;
+}
+
+/*********************************************
+ * Calling function f.
+ * Check the safety, i.e. if we're in a @safe function
+ * we can only call @safe or @trusted functions.
+ * Returns true if error occurs.
+ */
+bool Expression::checkSafety(Scope *sc, FuncDeclaration *f)
+{
+ if (!sc->func)
+ return false;
+ if (sc->func == f)
+ return false;
+ if (sc->intypeof == 1)
+ return false;
+ if (sc->flags & SCOPEctfe)
+ return false;
+
+ if (!f->isSafe() && !f->isTrusted())
+ {
+ if (sc->flags & SCOPEcompile ? sc->func->isSafeBypassingInference() : sc->func->setUnsafe())
+ {
+ if (loc.linnum == 0) // e.g. implicitly generated dtor
+ loc = sc->func->loc;
+
+ error("@safe %s '%s' cannot call @system %s '%s'",
+ sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
+ return true;
+ }
+ }
+ return false;
+}
+
+/*********************************************
+ * Calling function f.
+ * Check the @nogc-ness, i.e. if we're in a @nogc function
+ * we can only call other @nogc functions.
+ * Returns true if error occurs.
+ */
+bool Expression::checkNogc(Scope *sc, FuncDeclaration *f)
+{
+ if (!sc->func)
+ return false;
+ if (sc->func == f)
+ return false;
+ if (sc->intypeof == 1)
+ return false;
+ if (sc->flags & SCOPEctfe)
+ return false;
+
+ if (!f->isNogc())
+ {
+ if (sc->flags & SCOPEcompile ? sc->func->isNogcBypassingInference() : sc->func->setGC())
+ {
+ if (loc.linnum == 0) // e.g. implicitly generated dtor
+ loc = sc->func->loc;
+
+ error("@nogc %s '%s' cannot call non-@nogc %s '%s'",
+ sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
+ return true;
+ }
+ }
+ return false;
+}
+
+/********************************************
+ * Check that the postblit is callable if t is an array of structs.
+ * Returns true if error happens.
+ */
+bool Expression::checkPostblit(Scope *sc, Type *t)
+{
+ t = t->baseElemOf();
+ if (t->ty == Tstruct)
+ {
+ // Bugzilla 11395: Require TypeInfo generation for array concatenation
+ semanticTypeInfo(sc, t);
+
+ StructDeclaration *sd = ((TypeStruct *)t)->sym;
+ if (sd->postblit)
+ {
+ if (sd->postblit->storage_class & STCdisable)
+ {
+ sd->error(loc, "is not copyable because it is annotated with @disable");
+ return true;
+ }
+ //checkDeprecated(sc, sd->postblit); // necessary?
+ checkPurity(sc, sd->postblit);
+ checkSafety(sc, sd->postblit);
+ checkNogc(sc, sd->postblit);
+ //checkAccess(sd, loc, sc, sd->postblit); // necessary?
+ return false;
+ }
+ }
+ return false;
+}
+
+bool Expression::checkRightThis(Scope *sc)
+{
+ if (op == TOKerror)
+ return true;
+ if (op == TOKvar && type->ty != Terror)
+ {
+ VarExp *ve = (VarExp *)this;
+ if (isNeedThisScope(sc, ve->var))
+ {
+ //printf("checkRightThis sc->intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
+ // sc->intypeof, sc->getStructClassScope(), func, fdthis);
+ error("need 'this' for '%s' of type '%s'", ve->var->toChars(), ve->var->type->toChars());
+ return true;
+ }
+ }
+ return false;
+}
+
+/*******************************
+ * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
+ * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
+ * Returns true if error occurs.
+ */
+bool Expression::checkReadModifyWrite(TOK rmwOp, Expression *ex)
+{
+ //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex->toChars() : "");
+ if (!type || !type->isShared())
+ return false;
+
+ // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
+ switch (rmwOp)
+ {
+ case TOKplusplus:
+ case TOKpreplusplus:
+ rmwOp = TOKaddass;
+ break;
+
+ case TOKminusminus:
+ case TOKpreminusminus:
+ rmwOp = TOKminass;
+ break;
+
+ default:
+ break;
+ }
+
+ deprecation("read-modify-write operations are not allowed for shared variables. "
+ "Use core.atomic.atomicOp!\"%s\"(%s, %s) instead.",
+ Token::tochars[rmwOp], toChars(), ex ? ex->toChars() : "1");
+ return false;
+
+ // note: enable when deprecation becomes an error.
+ // return true;
+}
+
+/*****************************
+ * If expression can be tested for true or false,
+ * returns the modified expression.
+ * Otherwise returns ErrorExp.
+ */
+Expression *Expression::toBoolean(Scope *sc)
+{
+ // Default is 'yes' - do nothing
+ Expression *e = this;
+ Type *t = type;
+ Type *tb = type->toBasetype();
+ Type *att = NULL;
+Lagain:
+ // Structs can be converted to bool using opCast(bool)()
+ if (tb->ty == Tstruct)
+ {
+ AggregateDeclaration *ad = ((TypeStruct *)tb)->sym;
+ /* Don't really need to check for opCast first, but by doing so we
+ * get better error messages if it isn't there.
+ */
+ Dsymbol *fd = search_function(ad, Id::_cast);
+ if (fd)
+ {
+ e = new CastExp(loc, e, Type::tbool);
+ e = semantic(e, sc);
+ return e;
+ }
+
+ // Forward to aliasthis.
+ if (ad->aliasthis && tb != att)
+ {
+ if (!att && tb->checkAliasThisRec())
+ att = tb;
+ e = resolveAliasThis(sc, e);
+ t = e->type;
+ tb = e->type->toBasetype();
+ goto Lagain;
+ }
+ }
+
+ if (!t->isBoolean())
+ {
+ if (tb != Type::terror)
+ error("expression %s of type %s does not have a boolean value", toChars(), t->toChars());
+ return new ErrorExp();
+ }
+ return e;
+}
+
+/******************************
+ * Take address of expression.
+ */
+
+Expression *Expression::addressOf()
+{
+ //printf("Expression::addressOf()\n");
+ Expression *e = new AddrExp(loc, this);
+ e->type = type->pointerTo();
+ return e;
+}
+
+/******************************
+ * If this is a reference, dereference it.
+ */
+
+Expression *Expression::deref()
+{
+ //printf("Expression::deref()\n");
+ // type could be null if forward referencing an 'auto' variable
+ if (type && type->ty == Treference)
+ {
+ Expression *e = new PtrExp(loc, this);
+ e->type = ((TypeReference *)type)->next;
+ return e;
+ }
+ return this;
+}
+
+/********************************
+ * Does this expression statically evaluate to a boolean 'result' (true or false)?
+ */
+bool Expression::isBool(bool)
+{
+ return false;
+}
+
+/****************************************
+ * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__ to loc.
+ */
+
+Expression *Expression::resolveLoc(Loc, Scope *)
+{
+ return this;
+}
+
+Expressions *Expression::arraySyntaxCopy(Expressions *exps)
+{
+ Expressions *a = NULL;
+ if (exps)
+ {
+ a = new Expressions();
+ a->setDim(exps->dim);
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ Expression *e = (*exps)[i];
+ (*a)[i] = e ? e->syntaxCopy() : NULL;
+ }
+ }
+ return a;
+}
+
+/************************************************
+ * Destructors are attached to VarDeclarations.
+ * Hence, if expression returns a temp that needs a destructor,
+ * make sure and create a VarDeclaration for that temp.
+ */
+
+Expression *Expression::addDtorHook(Scope *)
+{
+ return this;
+}
+
+/******************************** IntegerExp **************************/
+
+IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type)
+ : Expression(loc, TOKint64, sizeof(IntegerExp))
+{
+ //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : "");
+ assert(type);
+ if (!type->isscalar())
+ {
+ //printf("%s, loc = %d\n", toChars(), loc.linnum);
+ if (type->ty != Terror)
+ error("integral constant must be scalar type, not %s", type->toChars());
+ type = Type::terror;
+ }
+ this->type = type;
+ setInteger(value);
+}
+
+IntegerExp::IntegerExp(dinteger_t value)
+ : Expression(Loc(), TOKint64, sizeof(IntegerExp))
+{
+ this->type = Type::tint32;
+ this->value = (d_int32) value;
+}
+
+IntegerExp *IntegerExp::create(Loc loc, dinteger_t value, Type *type)
+{
+ return new IntegerExp(loc, value, type);
+}
+
+bool IntegerExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (((Expression *)o)->op == TOKint64)
+ {
+ IntegerExp *ne = (IntegerExp *)o;
+ if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+ value == ne->value)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void IntegerExp::setInteger(dinteger_t value)
+{
+ this->value = value;
+ normalize();
+}
+
+void IntegerExp::normalize()
+{
+ /* 'Normalize' the value of the integer to be in range of the type
+ */
+ switch (type->toBasetype()->ty)
+ {
+ case Tbool: value = (value != 0); break;
+ case Tint8: value = (d_int8) value; break;
+ case Tchar:
+ case Tuns8: value = (d_uns8) value; break;
+ case Tint16: value = (d_int16) value; break;
+ case Twchar:
+ case Tuns16: value = (d_uns16) value; break;
+ case Tint32: value = (d_int32) value; break;
+ case Tdchar:
+ case Tuns32: value = (d_uns32) value; break;
+ case Tint64: value = (d_int64) value; break;
+ case Tuns64: value = (d_uns64) value; break;
+ case Tpointer:
+ if (Target::ptrsize == 4)
+ value = (d_uns32) value;
+ else if (Target::ptrsize == 8)
+ value = (d_uns64) value;
+ else
+ assert(0);
+ break;
+ default:
+ break;
+ }
+}
+
+dinteger_t IntegerExp::toInteger()
+{
+ normalize(); // necessary until we fix all the paints of 'type'
+ return value;
+}
+
+real_t IntegerExp::toReal()
+{
+ normalize(); // necessary until we fix all the paints of 'type'
+ Type *t = type->toBasetype();
+ if (t->ty == Tuns64)
+ return ldouble((d_uns64)value);
+ else
+ return ldouble((d_int64)value);
+}
+
+real_t IntegerExp::toImaginary()
+{
+ return CTFloat::zero;
+}
+
+complex_t IntegerExp::toComplex()
+{
+ return (complex_t)toReal();
+}
+
+bool IntegerExp::isBool(bool result)
+{
+ bool r = toInteger() != 0;
+ return result ? r : !r;
+}
+
+Expression *IntegerExp::toLvalue(Scope *, Expression *e)
+{
+ if (!e)
+ e = this;
+ else if (!loc.filename)
+ loc = e->loc;
+ e->error("constant %s is not an lvalue", e->toChars());
+ return new ErrorExp();
+}
+
+/******************************** ErrorExp **************************/
+
+/* Use this expression for error recovery.
+ * It should behave as a 'sink' to prevent further cascaded error messages.
+ */
+
+ErrorExp::ErrorExp()
+ : Expression(Loc(), TOKerror, sizeof(ErrorExp))
+{
+ type = Type::terror;
+}
+
+Expression *ErrorExp::toLvalue(Scope *, Expression *)
+{
+ return this;
+}
+
+/******************************** RealExp **************************/
+
+RealExp::RealExp(Loc loc, real_t value, Type *type)
+ : Expression(loc, TOKfloat64, sizeof(RealExp))
+{
+ //printf("RealExp::RealExp(%Lg)\n", value);
+ this->value = value;
+ this->type = type;
+}
+
+RealExp *RealExp::create(Loc loc, real_t value, Type *type)
+{
+ return new RealExp(loc, value,type);
+}
+
+dinteger_t RealExp::toInteger()
+{
+ return (sinteger_t) toReal();
+}
+
+uinteger_t RealExp::toUInteger()
+{
+ return (uinteger_t) toReal();
+}
+
+real_t RealExp::toReal()
+{
+ return type->isreal() ? value : CTFloat::zero;
+}
+
+real_t RealExp::toImaginary()
+{
+ return type->isreal() ? CTFloat::zero : value;
+}
+
+complex_t RealExp::toComplex()
+{
+ return complex_t(toReal(), toImaginary());
+}
+
+/********************************
+ * Test to see if two reals are the same.
+ * Regard NaN's as equivalent.
+ * Regard +0 and -0 as different.
+ */
+
+int RealEquals(real_t x1, real_t x2)
+{
+ return (CTFloat::isNaN(x1) && CTFloat::isNaN(x2)) ||
+ CTFloat::isIdentical(x1, x2);
+}
+
+bool RealExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (((Expression *)o)->op == TOKfloat64)
+ {
+ RealExp *ne = (RealExp *)o;
+ if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+ RealEquals(value, ne->value))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RealExp::isBool(bool result)
+{
+ return result ? (bool)value : !(bool)value;
+}
+
+/******************************** ComplexExp **************************/
+
+ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type)
+ : Expression(loc, TOKcomplex80, sizeof(ComplexExp)), value(value)
+{
+ this->type = type;
+ //printf("ComplexExp::ComplexExp(%s)\n", toChars());
+}
+
+ComplexExp *ComplexExp::create(Loc loc, complex_t value, Type *type)
+{
+ return new ComplexExp(loc, value, type);
+}
+
+dinteger_t ComplexExp::toInteger()
+{
+ return (sinteger_t) toReal();
+}
+
+uinteger_t ComplexExp::toUInteger()
+{
+ return (uinteger_t) toReal();
+}
+
+real_t ComplexExp::toReal()
+{
+ return creall(value);
+}
+
+real_t ComplexExp::toImaginary()
+{
+ return cimagl(value);
+}
+
+complex_t ComplexExp::toComplex()
+{
+ return value;
+}
+
+bool ComplexExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (((Expression *)o)->op == TOKcomplex80)
+ {
+ ComplexExp *ne = (ComplexExp *)o;
+ if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+ RealEquals(creall(value), creall(ne->value)) &&
+ RealEquals(cimagl(value), cimagl(ne->value)))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ComplexExp::isBool(bool result)
+{
+ if (result)
+ return (bool)(value);
+ else
+ return !value;
+}
+
+/******************************** IdentifierExp **************************/
+
+IdentifierExp::IdentifierExp(Loc loc, Identifier *ident)
+ : Expression(loc, TOKidentifier, sizeof(IdentifierExp))
+{
+ this->ident = ident;
+}
+
+IdentifierExp *IdentifierExp::create(Loc loc, Identifier *ident)
+{
+ return new IdentifierExp(loc, ident);
+}
+
+bool IdentifierExp::isLvalue()
+{
+ return true;
+}
+
+Expression *IdentifierExp::toLvalue(Scope *, Expression *)
+{
+ return this;
+}
+
+/******************************** DollarExp **************************/
+
+DollarExp::DollarExp(Loc loc)
+ : IdentifierExp(loc, Id::dollar)
+{
+}
+
+/******************************** DsymbolExp **************************/
+
+DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads)
+ : Expression(loc, TOKdsymbol, sizeof(DsymbolExp))
+{
+ this->s = s;
+ this->hasOverloads = hasOverloads;
+}
+
+/****************************************
+ * Resolve a symbol `s` and wraps it in an expression object.
+ * Params:
+ * hasOverloads = works if the aliased symbol is a function.
+ * true: it's overloaded and will be resolved later.
+ * false: it's exact function symbol.
+ */
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads)
+{
+Lagain:
+ Expression *e;
+
+ //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
+ //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind());
+ Dsymbol *olds = s;
+ Declaration *d = s->isDeclaration();
+ if (d && (d->storage_class & STCtemplateparameter))
+ {
+ s = s->toAlias();
+ }
+ else
+ {
+ if (!s->isFuncDeclaration()) // functions are checked after overloading
+ s->checkDeprecated(loc, sc);
+
+ // Bugzilla 12023: if 's' is a tuple variable, the tuple is returned.
+ s = s->toAlias();
+
+ //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis());
+ if (s != olds && !s->isFuncDeclaration())
+ s->checkDeprecated(loc, sc);
+ }
+
+ if (EnumMember *em = s->isEnumMember())
+ {
+ return em->getVarExp(loc, sc);
+ }
+ if (VarDeclaration *v = s->isVarDeclaration())
+ {
+ //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
+ if (!v->type || // during variable type inference
+ (!v->type->deco && v->inuse)) // during variable type semantic
+ {
+ if (v->inuse) // variable type depends on the variable itself
+ ::error(loc, "circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ else // variable type cannot be determined
+ ::error(loc, "forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+ if (v->type->ty == Terror)
+ return new ErrorExp();
+
+ if ((v->storage_class & STCmanifest) && v->_init)
+ {
+ if (v->inuse)
+ {
+ ::error(loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+
+ e = v->expandInitializer(loc);
+ v->inuse++;
+ e = semantic(e, sc);
+ v->inuse--;
+ return e;
+ }
+
+ // Change the ancestor lambdas to delegate before hasThis(sc) call.
+ if (v->checkNestedReference(sc, loc))
+ return new ErrorExp();
+
+ if (v->needThis() && hasThis(sc))
+ e = new DotVarExp(loc, new ThisExp(loc), v);
+ else
+ e = new VarExp(loc, v);
+ e = semantic(e, sc);
+ return e;
+ }
+ if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
+ {
+ //printf("'%s' is a function literal\n", fld->toChars());
+ e = new FuncExp(loc, fld);
+ return semantic(e, sc);
+ }
+ if (FuncDeclaration *f = s->isFuncDeclaration())
+ {
+ f = f->toAliasFunc();
+ if (!f->functionSemantic())
+ return new ErrorExp();
+
+ if (!hasOverloads && f->checkForwardRef(loc))
+ return new ErrorExp();
+
+ FuncDeclaration *fd = s->isFuncDeclaration();
+ fd->type = f->type;
+ return new VarExp(loc, fd, hasOverloads);
+ }
+ if (OverDeclaration *od = s->isOverDeclaration())
+ {
+ e = new VarExp(loc, od, true);
+ e->type = Type::tvoid;
+ return e;
+ }
+ if (OverloadSet *o = s->isOverloadSet())
+ {
+ //printf("'%s' is an overload set\n", o->toChars());
+ return new OverExp(loc, o);
+ }
+
+ if (Import *imp = s->isImport())
+ {
+ if (!imp->pkg)
+ {
+ ::error(loc, "forward reference of import %s", imp->toChars());
+ return new ErrorExp();
+ }
+ ScopeExp *ie = new ScopeExp(loc, imp->pkg);
+ return semantic(ie, sc);
+ }
+ if (Package *pkg = s->isPackage())
+ {
+ ScopeExp *ie = new ScopeExp(loc, pkg);
+ return semantic(ie, sc);
+ }
+ if (Module *mod = s->isModule())
+ {
+ ScopeExp *ie = new ScopeExp(loc, mod);
+ return semantic(ie, sc);
+ }
+
+ if (Nspace *ns = s->isNspace())
+ {
+ ScopeExp *ie = new ScopeExp(loc, ns);
+ return semantic(ie, sc);
+ }
+
+ if (Type *t = s->getType())
+ {
+ return semantic(new TypeExp(loc, t), sc);
+ }
+
+ if (TupleDeclaration *tup = s->isTupleDeclaration())
+ {
+ if (tup->needThis() && hasThis(sc))
+ e = new DotVarExp(loc, new ThisExp(loc), tup);
+ else
+ e = new TupleExp(loc, tup);
+ e = semantic(e, sc);
+ return e;
+ }
+
+ if (TemplateInstance *ti = s->isTemplateInstance())
+ {
+ ti->semantic(sc);
+ if (!ti->inst || ti->errors)
+ return new ErrorExp();
+ s = ti->toAlias();
+ if (!s->isTemplateInstance())
+ goto Lagain;
+ e = new ScopeExp(loc, ti);
+ e = semantic(e, sc);
+ return e;
+ }
+ if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ {
+ Dsymbol *p = td->toParent2();
+ FuncDeclaration *fdthis = hasThis(sc);
+ AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL;
+ if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad &&
+ (td->_scope->stc & STCstatic) == 0)
+ {
+ e = new DotTemplateExp(loc, new ThisExp(loc), td);
+ }
+ else
+ e = new TemplateExp(loc, td);
+ e = semantic(e, sc);
+ return e;
+ }
+
+ ::error(loc, "%s '%s' is not a variable", s->kind(), s->toChars());
+ return new ErrorExp();
+}
+
+bool DsymbolExp::isLvalue()
+{
+ return true;
+}
+
+Expression *DsymbolExp::toLvalue(Scope *, Expression *)
+{
+ return this;
+}
+
+/******************************** ThisExp **************************/
+
+ThisExp::ThisExp(Loc loc)
+ : Expression(loc, TOKthis, sizeof(ThisExp))
+{
+ //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
+ var = NULL;
+}
+
+bool ThisExp::isBool(bool result)
+{
+ return result ? true : false;
+}
+
+bool ThisExp::isLvalue()
+{
+ // Class `this` should be an rvalue; struct `this` should be an lvalue.
+ return type->toBasetype()->ty != Tclass;
+}
+
+Expression *ThisExp::toLvalue(Scope *sc, Expression *e)
+{
+ if (type->toBasetype()->ty == Tclass)
+ {
+ // Class `this` is an rvalue; struct `this` is an lvalue.
+ return Expression::toLvalue(sc, e);
+ }
+ return this;
+}
+
+/******************************** SuperExp **************************/
+
+SuperExp::SuperExp(Loc loc)
+ : ThisExp(loc)
+{
+ op = TOKsuper;
+}
+
+/******************************** NullExp **************************/
+
+NullExp::NullExp(Loc loc, Type *type)
+ : Expression(loc, TOKnull, sizeof(NullExp))
+{
+ committed = 0;
+ this->type = type;
+}
+
+bool NullExp::equals(RootObject *o)
+{
+ if (o && o->dyncast() == DYNCAST_EXPRESSION)
+ {
+ Expression *e = (Expression *)o;
+ if (e->op == TOKnull &&
+ type->equals(e->type))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool NullExp::isBool(bool result)
+{
+ return result ? false : true;
+}
+
+StringExp *NullExp::toStringExp()
+{
+ if (implicitConvTo(Type::tstring))
+ {
+ StringExp *se = new StringExp(loc, (char*)mem.xcalloc(1, 1), 0);
+ se->type = Type::tstring;
+ return se;
+ }
+ return NULL;
+}
+
+/******************************** StringExp **************************/
+
+StringExp::StringExp(Loc loc, char *string)
+ : Expression(loc, TOKstring, sizeof(StringExp))
+{
+ this->string = string;
+ this->len = strlen(string);
+ this->sz = 1;
+ this->committed = 0;
+ this->postfix = 0;
+ this->ownedByCtfe = OWNEDcode;
+}
+
+StringExp::StringExp(Loc loc, void *string, size_t len)
+ : Expression(loc, TOKstring, sizeof(StringExp))
+{
+ this->string = string;
+ this->len = len;
+ this->sz = 1;
+ this->committed = 0;
+ this->postfix = 0;
+ this->ownedByCtfe = OWNEDcode;
+}
+
+StringExp::StringExp(Loc loc, void *string, size_t len, utf8_t postfix)
+ : Expression(loc, TOKstring, sizeof(StringExp))
+{
+ this->string = string;
+ this->len = len;
+ this->sz = 1;
+ this->committed = 0;
+ this->postfix = postfix;
+ this->ownedByCtfe = OWNEDcode;
+}
+
+StringExp *StringExp::create(Loc loc, char *s)
+{
+ return new StringExp(loc, s);
+}
+
+StringExp *StringExp::create(Loc loc, void *string, size_t len)
+{
+ return new StringExp(loc, string, len);
+}
+
+bool StringExp::equals(RootObject *o)
+{
+ //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars());
+ if (o && o->dyncast() == DYNCAST_EXPRESSION)
+ {
+ Expression *e = (Expression *)o;
+ if (e->op == TOKstring)
+ {
+ return compare(o) == 0;
+ }
+ }
+ return false;
+}
+
+/**********************************
+ * Return the number of code units the string would be if it were re-encoded
+ * as tynto.
+ * Params:
+ * tynto = code unit type of the target encoding
+ * Returns:
+ * number of code units
+ */
+
+size_t StringExp::numberOfCodeUnits(int tynto) const
+{
+ int encSize;
+ switch (tynto)
+ {
+ case 0: return len;
+ case Tchar: encSize = 1; break;
+ case Twchar: encSize = 2; break;
+ case Tdchar: encSize = 4; break;
+ default:
+ assert(0);
+ }
+ if (sz == encSize)
+ return len;
+
+ size_t result = 0;
+ dchar_t c;
+
+ switch (sz)
+ {
+ case 1:
+ for (size_t u = 0; u < len;)
+ {
+ if (const char *p = utf_decodeChar((utf8_t *)string, len, &u, &c))
+ {
+ error("%s", p);
+ return 0;
+ }
+ result += utf_codeLength(encSize, c);
+ }
+ break;
+
+ case 2:
+ for (size_t u = 0; u < len;)
+ {
+ if (const char *p = utf_decodeWchar((utf16_t *)string, len, &u, &c))
+ {
+ error("%s", p);
+ return 0;
+ }
+ result += utf_codeLength(encSize, c);
+ }
+ break;
+
+ case 4:
+ for (size_t u = 0; u < len;)
+ {
+ c = *((utf32_t *)((char *)string + u));
+ u += 4;
+ result += utf_codeLength(encSize, c);
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ return result;
+}
+
+/**********************************************
+ * Write the contents of the string to dest.
+ * Use numberOfCodeUnits() to determine size of result.
+ * Params:
+ * dest = destination
+ * tyto = encoding type of the result
+ * zero = add terminating 0
+ */
+void StringExp::writeTo(void *dest, bool zero, int tyto) const
+{
+ int encSize;
+ switch (tyto)
+ {
+ case 0: encSize = sz; break;
+ case Tchar: encSize = 1; break;
+ case Twchar: encSize = 2; break;
+ case Tdchar: encSize = 4; break;
+ default:
+ assert(0);
+ }
+ if (sz == encSize)
+ {
+ memcpy(dest, string, len * sz);
+ if (zero)
+ memset((char *)dest + len * sz, 0, sz);
+ }
+ else
+ assert(0);
+}
+
+/**************************************************
+ * If the string data is UTF-8 and can be accessed directly,
+ * return a pointer to it.
+ * Do not assume a terminating 0.
+ * Returns:
+ * pointer to string data if possible, null if not
+ */
+char *StringExp::toPtr()
+{
+ return (sz == 1) ? (char*)string : NULL;
+}
+
+StringExp *StringExp::toStringExp()
+{
+ return this;
+}
+
+/****************************************
+ * Convert string to char[].
+ */
+
+StringExp *StringExp::toUTF8(Scope *sc)
+{
+ if (sz != 1)
+ { // Convert to UTF-8 string
+ committed = 0;
+ Expression *e = castTo(sc, Type::tchar->arrayOf());
+ e = e->optimize(WANTvalue);
+ assert(e->op == TOKstring);
+ StringExp *se = (StringExp *)e;
+ assert(se->sz == 1);
+ return se;
+ }
+ return this;
+}
+
+int StringExp::compare(RootObject *obj)
+{
+ //printf("StringExp::compare()\n");
+ // Used to sort case statement expressions so we can do an efficient lookup
+ StringExp *se2 = (StringExp *)(obj);
+
+ // This is a kludge so isExpression() in template.c will return 5
+ // for StringExp's.
+ if (!se2)
+ return 5;
+
+ assert(se2->op == TOKstring);
+
+ size_t len1 = len;
+ size_t len2 = se2->len;
+
+ //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
+ if (len1 == len2)
+ {
+ switch (sz)
+ {
+ case 1:
+ return memcmp((char *)string, (char *)se2->string, len1);
+
+ case 2:
+ {
+ d_uns16 *s1 = (d_uns16 *)string;
+ d_uns16 *s2 = (d_uns16 *)se2->string;
+
+ for (size_t u = 0; u < len; u++)
+ {
+ if (s1[u] != s2[u])
+ return s1[u] - s2[u];
+ }
+ }
+ break;
+
+ case 4:
+ {
+ d_uns32 *s1 = (d_uns32 *)string;
+ d_uns32 *s2 = (d_uns32 *)se2->string;
+
+ for (size_t u = 0; u < len; u++)
+ {
+ if (s1[u] != s2[u])
+ return s1[u] - s2[u];
+ }
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ return (int)(len1 - len2);
+}
+
+bool StringExp::isBool(bool result)
+{
+ return result ? true : false;
+}
+
+
+bool StringExp::isLvalue()
+{
+ /* string literal is rvalue in default, but
+ * conversion to reference of static array is only allowed.
+ */
+ return (type && type->toBasetype()->ty == Tsarray);
+}
+
+Expression *StringExp::toLvalue(Scope *sc, Expression *e)
+{
+ //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
+ return (type && type->toBasetype()->ty == Tsarray)
+ ? this : Expression::toLvalue(sc, e);
+}
+
+Expression *StringExp::modifiableLvalue(Scope *, Expression *)
+{
+ error("cannot modify string literal %s", toChars());
+ return new ErrorExp();
+}
+
+unsigned StringExp::charAt(uinteger_t i) const
+{ unsigned value;
+
+ switch (sz)
+ {
+ case 1:
+ value = ((utf8_t *)string)[(size_t)i];
+ break;
+
+ case 2:
+ value = ((unsigned short *)string)[(size_t)i];
+ break;
+
+ case 4:
+ value = ((unsigned int *)string)[(size_t)i];
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ return value;
+}
+
+/************************ ArrayLiteralExp ************************************/
+
+// [ e1, e2, e3, ... ]
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements)
+ : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+ this->basis = NULL;
+ this->elements = elements;
+ this->ownedByCtfe = OWNEDcode;
+}
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e)
+ : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+ this->basis = NULL;
+ elements = new Expressions;
+ elements->push(e);
+ this->ownedByCtfe = OWNEDcode;
+}
+
+ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *basis, Expressions *elements)
+ : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
+{
+ this->basis = basis;
+ this->elements = elements;
+ this->ownedByCtfe = OWNEDcode;
+}
+
+ArrayLiteralExp *ArrayLiteralExp::create(Loc loc, Expressions *elements)
+{
+ return new ArrayLiteralExp(loc, elements);
+}
+
+bool ArrayLiteralExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (o && o->dyncast() == DYNCAST_EXPRESSION &&
+ ((Expression *)o)->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)o;
+ if (elements->dim != ae->elements->dim)
+ return false;
+ if (elements->dim == 0 &&
+ !type->equals(ae->type))
+ {
+ return false;
+ }
+ for (size_t i = 0; i < elements->dim; i++)
+ {
+ Expression *e1 = (*elements)[i];
+ Expression *e2 = (*ae->elements)[i];
+ if (!e1)
+ e1 = basis;
+ if (!e2)
+ e2 = basis;
+ if (e1 != e2 &&
+ (!e1 || !e2 || !e1->equals(e2)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+Expression *ArrayLiteralExp::syntaxCopy()
+{
+ return new ArrayLiteralExp(loc,
+ basis ? basis->syntaxCopy() : NULL,
+ arraySyntaxCopy(elements));
+}
+
+Expression *ArrayLiteralExp::getElement(d_size_t i)
+{
+ Expression *el = (*elements)[i];
+ if (!el)
+ el = basis;
+ return el;
+}
+
+static void appendArrayLiteral(Expressions *elems, ArrayLiteralExp *ale)
+{
+ if (!ale->elements)
+ return;
+ size_t d = elems->dim;
+ elems->append(ale->elements);
+ for (size_t i = d; i < elems->dim; i++)
+ {
+ Expression *el = (*elems)[i];
+ if (!el)
+ (*elems)[i] = ale->basis;
+ }
+}
+
+/* Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
+ * Params:
+ * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
+ * Otherwise, `e1` itself will be pushed into the new `Expressions`.
+ * e2 = If it's not `null`, it will be pushed/appended to the new
+ * `Expressions` by the same way with `e1`.
+ * Returns:
+ * Newly allocated `Expressions`. Note that it points to the original
+ * `Expression` values in e1 and e2.
+ */
+Expressions* ArrayLiteralExp::copyElements(Expression *e1, Expression *e2)
+{
+ Expressions *elems = new Expressions();
+
+ if (e1->op == TOKarrayliteral)
+ appendArrayLiteral(elems, (ArrayLiteralExp *)e1);
+ else
+ elems->push(e1);
+
+ if (e2)
+ {
+ if (e2->op == TOKarrayliteral)
+ appendArrayLiteral(elems, (ArrayLiteralExp *)e2);
+ else
+ elems->push(e2);
+ }
+
+ return elems;
+}
+
+bool ArrayLiteralExp::isBool(bool result)
+{
+ size_t dim = elements ? elements->dim : 0;
+ return result ? (dim != 0) : (dim == 0);
+}
+
+StringExp *ArrayLiteralExp::toStringExp()
+{
+ TY telem = type->nextOf()->toBasetype()->ty;
+
+ if (telem == Tchar || telem == Twchar || telem == Tdchar ||
+ (telem == Tvoid && (!elements || elements->dim == 0)))
+ {
+ unsigned char sz = 1;
+ if (telem == Twchar) sz = 2;
+ else if (telem == Tdchar) sz = 4;
+
+ OutBuffer buf;
+ if (elements)
+ {
+ for (size_t i = 0; i < elements->dim; ++i)
+ {
+ Expression *ch = getElement(i);
+ if (ch->op != TOKint64)
+ return NULL;
+ if (sz == 1)
+ buf.writeByte((unsigned)ch->toInteger());
+ else if (sz == 2)
+ buf.writeword((unsigned)ch->toInteger());
+ else
+ buf.write4((unsigned)ch->toInteger());
+ }
+ }
+ char prefix;
+ if (sz == 1) { prefix = 'c'; buf.writeByte(0); }
+ else if (sz == 2) { prefix = 'w'; buf.writeword(0); }
+ else { prefix = 'd'; buf.write4(0); }
+
+ const size_t len = buf.offset / sz - 1;
+ StringExp *se = new StringExp(loc, buf.extractData(), len, prefix);
+ se->sz = sz;
+ se->type = type;
+ return se;
+ }
+ return NULL;
+}
+
+/************************ AssocArrayLiteralExp ************************************/
+
+// [ key0 : value0, key1 : value1, ... ]
+
+AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc,
+ Expressions *keys, Expressions *values)
+ : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp))
+{
+ assert(keys->dim == values->dim);
+ this->keys = keys;
+ this->values = values;
+ this->ownedByCtfe = OWNEDcode;
+}
+
+bool AssocArrayLiteralExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (o && o->dyncast() == DYNCAST_EXPRESSION &&
+ ((Expression *)o)->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)o;
+ if (keys->dim != ae->keys->dim)
+ return false;
+ size_t count = 0;
+ for (size_t i = 0; i < keys->dim; i++)
+ {
+ for (size_t j = 0; j < ae->keys->dim; j++)
+ {
+ if ((*keys)[i]->equals((*ae->keys)[j]))
+ {
+ if (!(*values)[i]->equals((*ae->values)[j]))
+ return false;
+ ++count;
+ }
+ }
+ }
+ return count == keys->dim;
+ }
+ return false;
+}
+
+Expression *AssocArrayLiteralExp::syntaxCopy()
+{
+ return new AssocArrayLiteralExp(loc,
+ arraySyntaxCopy(keys), arraySyntaxCopy(values));
+}
+
+bool AssocArrayLiteralExp::isBool(bool result)
+{
+ size_t dim = keys->dim;
+ return result ? (dim != 0) : (dim == 0);
+}
+
+/************************ StructLiteralExp ************************************/
+
+// sd( e1, e2, e3, ... )
+
+StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype)
+ : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp))
+{
+ this->sd = sd;
+ if (!elements)
+ elements = new Expressions();
+ this->elements = elements;
+ this->stype = stype;
+ this->useStaticInit = false;
+ this->sym = NULL;
+ this->ownedByCtfe = OWNEDcode;
+ this->origin = this;
+ this->stageflags = 0;
+ this->inlinecopy = NULL;
+ //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
+}
+
+StructLiteralExp *StructLiteralExp::create(Loc loc, StructDeclaration *sd, void *elements, Type *stype)
+{
+ return new StructLiteralExp(loc, sd, (Expressions *)elements, stype);
+}
+
+bool StructLiteralExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (o && o->dyncast() == DYNCAST_EXPRESSION &&
+ ((Expression *)o)->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)o;
+ if (!type->equals(se->type))
+ return false;
+ if (elements->dim != se->elements->dim)
+ return false;
+ for (size_t i = 0; i < elements->dim; i++)
+ {
+ Expression *e1 = (*elements)[i];
+ Expression *e2 = (*se->elements)[i];
+ if (e1 != e2 &&
+ (!e1 || !e2 || !e1->equals(e2)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+Expression *StructLiteralExp::syntaxCopy()
+{
+ StructLiteralExp *exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
+ exp->origin = this;
+ return exp;
+}
+
+Expression *StructLiteralExp::addDtorHook(Scope *sc)
+{
+ /* If struct requires a destructor, rewrite as:
+ * (S tmp = S()),tmp
+ * so that the destructor can be hung on tmp.
+ */
+ if (sd->dtor && sc->func)
+ {
+ /* Make an identifier for the temporary of the form:
+ * __sl%s%d, where %s is the struct name
+ */
+ const size_t len = 10;
+ char buf[len + 1];
+ buf[len] = 0;
+ strcpy(buf, "__sl");
+ strncat(buf, sd->ident->toChars(), len - 4 - 1);
+ assert(buf[len] == 0);
+
+ VarDeclaration *tmp = copyToTemp(0, buf, this);
+ Expression *ae = new DeclarationExp(loc, tmp);
+ Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp));
+ e = semantic(e, sc);
+ return e;
+ }
+ return this;
+}
+
+/**************************************
+ * Gets expression at offset of type.
+ * Returns NULL if not found.
+ */
+
+Expression *StructLiteralExp::getField(Type *type, unsigned offset)
+{
+ //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
+ // /*toChars()*/"", type->toChars(), offset);
+ Expression *e = NULL;
+ int i = getFieldIndex(type, offset);
+
+ if (i != -1)
+ {
+ //printf("\ti = %d\n", i);
+ if (i == (int)sd->fields.dim - 1 && sd->isNested())
+ return NULL;
+
+ assert(i < (int)elements->dim);
+ e = (*elements)[i];
+ if (e)
+ {
+ //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars());
+
+ /* If type is a static array, and e is an initializer for that array,
+ * then the field initializer should be an array literal of e.
+ */
+ if (e->type->castMod(0) != type->castMod(0) && type->ty == Tsarray)
+ { TypeSArray *tsa = (TypeSArray *)type;
+ size_t length = (size_t)tsa->dim->toInteger();
+ Expressions *z = new Expressions;
+ z->setDim(length);
+ for (size_t q = 0; q < length; ++q)
+ (*z)[q] = e->copy();
+ e = new ArrayLiteralExp(loc, z);
+ e->type = type;
+ }
+ else
+ {
+ e = e->copy();
+ e->type = type;
+ }
+ if (useStaticInit && e->op == TOKstructliteral &&
+ e->type->needsNested())
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ se->useStaticInit = true;
+ }
+ }
+ }
+ return e;
+}
+
+/************************************
+ * Get index of field.
+ * Returns -1 if not found.
+ */
+
+int StructLiteralExp::getFieldIndex(Type *type, unsigned offset)
+{
+ /* Find which field offset is by looking at the field offsets
+ */
+ if (elements->dim)
+ {
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *v = sd->fields[i];
+
+ if (offset == v->offset &&
+ type->size() == v->type->size())
+ {
+ /* context field might not be filled. */
+ if (i == sd->fields.dim - 1 && sd->isNested())
+ return (int)i;
+ Expression *e = (*elements)[i];
+ if (e)
+ {
+ return (int)i;
+ }
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+/************************ TypeDotIdExp ************************************/
+
+/* Things like:
+ * int.size
+ * foo.size
+ * (foo).size
+ * cast(foo).size
+ */
+
+DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident)
+{
+ return new DotIdExp(loc, new TypeExp(loc, type), ident);
+}
+
+
+/************************************************************/
+
+// Mainly just a placeholder
+
+TypeExp::TypeExp(Loc loc, Type *type)
+ : Expression(loc, TOKtype, sizeof(TypeExp))
+{
+ //printf("TypeExp::TypeExp(%s)\n", type->toChars());
+ this->type = type;
+}
+
+Expression *TypeExp::syntaxCopy()
+{
+ return new TypeExp(loc, type->syntaxCopy());
+}
+
+bool TypeExp::checkType()
+{
+ error("type %s is not an expression", toChars());
+ return true;
+}
+
+bool TypeExp::checkValue()
+{
+ error("type %s has no value", toChars());
+ return true;
+}
+
+/************************************************************/
+
+/***********************************************************
+ * Mainly just a placeholder of
+ * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
+ *
+ * A template instance that requires IFTI:
+ * foo!tiargs(fargs) // foo!tiargs
+ * is left until CallExp::semantic() or resolveProperties()
+ */
+ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *sds)
+ : Expression(loc, TOKscope, sizeof(ScopeExp))
+{
+ //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds->toChars());
+ //static int count; if (++count == 38) *(char*)0=0;
+ this->sds = sds;
+ assert(!sds->isTemplateDeclaration()); // instead, you should use TemplateExp
+}
+
+Expression *ScopeExp::syntaxCopy()
+{
+ return new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL));
+}
+
+bool ScopeExp::checkType()
+{
+ if (sds->isPackage())
+ {
+ error("%s %s has no type", sds->kind(), sds->toChars());
+ return true;
+ }
+ if (TemplateInstance *ti = sds->isTemplateInstance())
+ {
+ //assert(ti->needsTypeInference(sc));
+ if (ti->tempdecl &&
+ ti->semantictiargsdone &&
+ ti->semanticRun == PASSinit)
+ {
+ error("partial %s %s has no type", sds->kind(), toChars());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ScopeExp::checkValue()
+{
+ error("%s %s has no value", sds->kind(), sds->toChars());
+ return true;
+}
+
+/********************** TemplateExp **************************************/
+
+// Mainly just a placeholder
+
+TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd)
+ : Expression(loc, TOKtemplate, sizeof(TemplateExp))
+{
+ //printf("TemplateExp(): %s\n", td->toChars());
+ this->td = td;
+ this->fd = fd;
+}
+
+bool TemplateExp::checkType()
+{
+ error("%s %s has no type", td->kind(), toChars());
+ return true;
+}
+
+bool TemplateExp::checkValue()
+{
+ error("%s %s has no value", td->kind(), toChars());
+ return true;
+}
+
+bool TemplateExp::isLvalue()
+{
+ return fd != NULL;
+}
+
+Expression *TemplateExp::toLvalue(Scope *sc, Expression *e)
+{
+ if (!fd)
+ return Expression::toLvalue(sc, e);
+
+ assert(sc);
+ return resolve(loc, sc, fd, true);
+}
+
+/********************** NewExp **************************************/
+
+/* thisexp.new(newargs) newtype(arguments) */
+
+NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
+ Type *newtype, Expressions *arguments)
+ : Expression(loc, TOKnew, sizeof(NewExp))
+{
+ this->thisexp = thisexp;
+ this->newargs = newargs;
+ this->newtype = newtype;
+ this->arguments = arguments;
+ argprefix = NULL;
+ member = NULL;
+ allocator = NULL;
+ onstack = 0;
+}
+
+NewExp *NewExp::create(Loc loc, Expression *thisexp, Expressions *newargs,
+ Type *newtype, Expressions *arguments)
+{
+ return new NewExp(loc, thisexp, newargs, newtype, arguments);
+}
+
+Expression *NewExp::syntaxCopy()
+{
+ return new NewExp(loc,
+ thisexp ? thisexp->syntaxCopy() : NULL,
+ arraySyntaxCopy(newargs),
+ newtype->syntaxCopy(), arraySyntaxCopy(arguments));
+}
+
+/********************** NewAnonClassExp **************************************/
+
+NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp,
+ Expressions *newargs, ClassDeclaration *cd, Expressions *arguments)
+ : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp))
+{
+ this->thisexp = thisexp;
+ this->newargs = newargs;
+ this->cd = cd;
+ this->arguments = arguments;
+}
+
+Expression *NewAnonClassExp::syntaxCopy()
+{
+ return new NewAnonClassExp(loc,
+ thisexp ? thisexp->syntaxCopy() : NULL,
+ arraySyntaxCopy(newargs),
+ (ClassDeclaration *)cd->syntaxCopy(NULL),
+ arraySyntaxCopy(arguments));
+}
+
+/********************** SymbolExp **************************************/
+
+SymbolExp::SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads)
+ : Expression(loc, op, size)
+{
+ assert(var);
+ this->var = var;
+ this->hasOverloads = hasOverloads;
+}
+
+/********************** SymOffExp **************************************/
+
+SymOffExp::SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads)
+ : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var,
+ var->isVarDeclaration() ? false : hasOverloads)
+{
+ if (VarDeclaration *v = var->isVarDeclaration())
+ {
+ // FIXME: This error report will never be handled anyone.
+ // It should be done before the SymOffExp construction.
+ if (v->needThis())
+ ::error(loc, "need 'this' for address of %s", v->toChars());
+ }
+ this->offset = offset;
+}
+
+bool SymOffExp::isBool(bool result)
+{
+ return result ? true : false;
+}
+
+/******************************** VarExp **************************/
+
+VarExp::VarExp(Loc loc, Declaration *var, bool hasOverloads)
+ : SymbolExp(loc, TOKvar, sizeof(VarExp), var,
+ var->isVarDeclaration() ? false : hasOverloads)
+{
+ //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars());
+ //if (strcmp(var->ident->toChars(), "func") == 0) halt();
+ this->type = var->type;
+}
+
+VarExp *VarExp::create(Loc loc, Declaration *var, bool hasOverloads)
+{
+ return new VarExp(loc, var, hasOverloads);
+}
+
+bool VarExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (((Expression *)o)->op == TOKvar)
+ {
+ VarExp *ne = (VarExp *)o;
+ if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
+ var == ne->var)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool VarExp::isLvalue()
+{
+ if (var->storage_class & (STClazy | STCrvalue | STCmanifest))
+ return false;
+ return true;
+}
+
+Expression *VarExp::toLvalue(Scope *, Expression *)
+{
+ if (var->storage_class & STCmanifest)
+ {
+ error("manifest constant '%s' is not lvalue", var->toChars());
+ return new ErrorExp();
+ }
+ if (var->storage_class & STClazy)
+ {
+ error("lazy variables cannot be lvalues");
+ return new ErrorExp();
+ }
+ if (var->ident == Id::ctfe)
+ {
+ error("compiler-generated variable __ctfe is not an lvalue");
+ return new ErrorExp();
+ }
+ if (var->ident == Id::dollar) // Bugzilla 13574
+ {
+ error("'$' is not an lvalue");
+ return new ErrorExp();
+ }
+ return this;
+}
+
+int VarExp::checkModifiable(Scope *sc, int flag)
+{
+ //printf("VarExp::checkModifiable %s", toChars());
+ assert(type);
+ return var->checkModify(loc, sc, type, NULL, flag);
+}
+
+Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+ //printf("VarExp::modifiableLvalue('%s')\n", var->toChars());
+ if (var->storage_class & STCmanifest)
+ {
+ error("cannot modify manifest constant '%s'", toChars());
+ return new ErrorExp();
+ }
+ // See if this expression is a modifiable lvalue (i.e. not const)
+ return Expression::modifiableLvalue(sc, e);
+}
+
+
+/******************************** OverExp **************************/
+
+OverExp::OverExp(Loc loc, OverloadSet *s)
+ : Expression(loc, TOKoverloadset, sizeof(OverExp))
+{
+ //printf("OverExp(this = %p, '%s')\n", this, var->toChars());
+ vars = s;
+ type = Type::tvoid;
+}
+
+bool OverExp::isLvalue()
+{
+ return true;
+}
+
+Expression *OverExp::toLvalue(Scope *, Expression *)
+{
+ return this;
+}
+
+/******************************** TupleExp **************************/
+
+TupleExp::TupleExp(Loc loc, Expression *e0, Expressions *exps)
+ : Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+ //printf("TupleExp(this = %p)\n", this);
+ this->e0 = e0;
+ this->exps = exps;
+}
+
+TupleExp::TupleExp(Loc loc, Expressions *exps)
+ : Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+ //printf("TupleExp(this = %p)\n", this);
+ this->e0 = NULL;
+ this->exps = exps;
+}
+
+TupleExp::TupleExp(Loc loc, TupleDeclaration *tup)
+ : Expression(loc, TOKtuple, sizeof(TupleExp))
+{
+ this->e0 = NULL;
+ this->exps = new Expressions();
+
+ this->exps->reserve(tup->objects->dim);
+ for (size_t i = 0; i < tup->objects->dim; i++)
+ { RootObject *o = (*tup->objects)[i];
+ if (Dsymbol *s = getDsymbol(o))
+ {
+ /* If tuple element represents a symbol, translate to DsymbolExp
+ * to supply implicit 'this' if needed later.
+ */
+ Expression *e = new DsymbolExp(loc, s);
+ this->exps->push(e);
+ }
+ else if (o->dyncast() == DYNCAST_EXPRESSION)
+ {
+ Expression *e = ((Expression *)o)->copy();
+ e->loc = loc; // Bugzilla 15669
+ this->exps->push(e);
+ }
+ else if (o->dyncast() == DYNCAST_TYPE)
+ {
+ Type *t = (Type *)o;
+ Expression *e = new TypeExp(loc, t);
+ this->exps->push(e);
+ }
+ else
+ {
+ error("%s is not an expression", o->toChars());
+ }
+ }
+}
+
+bool TupleExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (((Expression *)o)->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)o;
+ if (exps->dim != te->exps->dim)
+ return false;
+ if ((e0 && !e0->equals(te->e0)) || (!e0 && te->e0))
+ return false;
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *e1 = (*exps)[i];
+ Expression *e2 = (*te->exps)[i];
+ if (!e1->equals(e2))
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+Expression *TupleExp::syntaxCopy()
+{
+ return new TupleExp(loc, e0 ? e0->syntaxCopy() : NULL, arraySyntaxCopy(exps));
+}
+
+/******************************** FuncExp *********************************/
+
+FuncExp::FuncExp(Loc loc, Dsymbol *s)
+ : Expression(loc, TOKfunction, sizeof(FuncExp))
+{
+ this->td = s->isTemplateDeclaration();
+ this->fd = s->isFuncLiteralDeclaration();
+ if (td)
+ {
+ assert(td->literal);
+ assert(td->members && td->members->dim == 1);
+ fd = (*td->members)[0]->isFuncLiteralDeclaration();
+ }
+ tok = fd->tok; // save original kind of function/delegate/(infer)
+ assert(fd->fbody);
+}
+
+bool FuncExp::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+ if (o->dyncast() != DYNCAST_EXPRESSION)
+ return false;
+ if (((Expression *)o)->op == TOKfunction)
+ {
+ FuncExp *fe = (FuncExp *)o;
+ return fd == fe->fd;
+ }
+ return false;
+}
+
+void FuncExp::genIdent(Scope *sc)
+{
+ if (fd->ident == Id::empty)
+ {
+ const char *s;
+ if (fd->fes) s = "__foreachbody";
+ else if (fd->tok == TOKreserved) s = "__lambda";
+ else if (fd->tok == TOKdelegate) s = "__dgliteral";
+ else s = "__funcliteral";
+
+ DsymbolTable *symtab;
+ if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
+ {
+ if (func->localsymtab == NULL)
+ {
+ // Inside template constraint, symtab is not set yet.
+ // Initialize it lazily.
+ func->localsymtab = new DsymbolTable();
+ }
+ symtab = func->localsymtab;
+ }
+ else
+ {
+ ScopeDsymbol *sds = sc->parent->isScopeDsymbol();
+ if (!sds->symtab)
+ {
+ // Inside template constraint, symtab may not be set yet.
+ // Initialize it lazily.
+ assert(sds->isTemplateInstance());
+ sds->symtab = new DsymbolTable();
+ }
+ symtab = sds->symtab;
+ }
+ assert(symtab);
+ int num = (int)dmd_aaLen(symtab->tab) + 1;
+ Identifier *id = Identifier::generateId(s, num);
+ fd->ident = id;
+ if (td) td->ident = id;
+ symtab->insert(td ? (Dsymbol *)td : (Dsymbol *)fd);
+ }
+}
+
+Expression *FuncExp::syntaxCopy()
+{
+ if (td)
+ return new FuncExp(loc, td->syntaxCopy(NULL));
+ else if (fd->semanticRun == PASSinit)
+ return new FuncExp(loc, fd->syntaxCopy(NULL));
+ else // Bugzilla 13481: Prevent multiple semantic analysis of lambda body.
+ return new FuncExp(loc, fd);
+}
+
+MATCH FuncExp::matchType(Type *to, Scope *sc, FuncExp **presult, int flag)
+{
+ //printf("FuncExp::matchType('%s'), to=%s\n", type ? type->toChars() : "null", to->toChars());
+ if (presult)
+ *presult = NULL;
+
+ TypeFunction *tof = NULL;
+ if (to->ty == Tdelegate)
+ {
+ if (tok == TOKfunction)
+ {
+ if (!flag)
+ error("cannot match function literal to delegate type '%s'", to->toChars());
+ return MATCHnomatch;
+ }
+ tof = (TypeFunction *)to->nextOf();
+ }
+ else if (to->ty == Tpointer && to->nextOf()->ty == Tfunction)
+ {
+ if (tok == TOKdelegate)
+ {
+ if (!flag)
+ error("cannot match delegate literal to function pointer type '%s'", to->toChars());
+ return MATCHnomatch;
+ }
+ tof = (TypeFunction *)to->nextOf();
+ }
+
+ if (td)
+ {
+ if (!tof)
+ {
+ L1:
+ if (!flag)
+ error("cannot infer parameter types from %s", to->toChars());
+ return MATCHnomatch;
+ }
+
+ // Parameter types inference from 'tof'
+ assert(td->_scope);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ //printf("\ttof = %s\n", tof->toChars());
+ //printf("\ttf = %s\n", tf->toChars());
+ size_t dim = Parameter::dim(tf->parameters);
+
+ if (Parameter::dim(tof->parameters) != dim ||
+ tof->varargs != tf->varargs)
+ goto L1;
+
+ Objects *tiargs = new Objects();
+ tiargs->reserve(td->parameters->dim);
+
+ for (size_t i = 0; i < td->parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*td->parameters)[i];
+ size_t u = 0;
+ for (; u < dim; u++)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, u);
+ if (p->type->ty == Tident &&
+ ((TypeIdentifier *)p->type)->ident == tp->ident)
+ {
+ break;
+ }
+ }
+ assert(u < dim);
+ Parameter *pto = Parameter::getNth(tof->parameters, u);
+ Type *t = pto->type;
+ if (t->ty == Terror)
+ goto L1;
+ tiargs->push(t);
+ }
+
+ // Set target of return type inference
+ if (!tf->next && tof->next)
+ fd->treq = to;
+
+ TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
+ Expression *ex = new ScopeExp(loc, ti);
+ ex = ::semantic(ex, td->_scope);
+
+ // Reset inference target for the later re-semantic
+ fd->treq = NULL;
+
+ if (ex->op == TOKerror)
+ return MATCHnomatch;
+ if (ex->op != TOKfunction)
+ goto L1;
+ return ((FuncExp *)ex)->matchType(to, sc, presult, flag);
+ }
+
+ if (!tof || !tof->next)
+ return MATCHnomatch;
+
+ assert(type && type != Type::tvoid);
+ TypeFunction *tfx = (TypeFunction *)fd->type;
+ bool convertMatch = (type->ty != to->ty);
+
+ if (fd->inferRetType && tfx->next->implicitConvTo(tof->next) == MATCHconvert)
+ {
+ /* If return type is inferred and covariant return,
+ * tweak return statements to required return type.
+ *
+ * interface I {}
+ * class C : Object, I{}
+ *
+ * I delegate() dg = delegate() { return new class C(); }
+ */
+ convertMatch = true;
+
+ TypeFunction *tfy = new TypeFunction(tfx->parameters, tof->next, tfx->varargs, tfx->linkage, STCundefined);
+ tfy->mod = tfx->mod;
+ tfy->isnothrow = tfx->isnothrow;
+ tfy->isnogc = tfx->isnogc;
+ tfy->purity = tfx->purity;
+ tfy->isproperty = tfx->isproperty;
+ tfy->isref = tfx->isref;
+ tfy->iswild = tfx->iswild;
+ tfy->deco = tfy->merge()->deco;
+
+ tfx = tfy;
+ }
+
+ Type *tx;
+ if (tok == TOKdelegate ||
+ (tok == TOKreserved && (type->ty == Tdelegate ||
+ (type->ty == Tpointer && to->ty == Tdelegate))))
+ {
+ // Allow conversion from implicit function pointer to delegate
+ tx = new TypeDelegate(tfx);
+ tx->deco = tx->merge()->deco;
+ }
+ else
+ {
+ assert(tok == TOKfunction ||
+ (tok == TOKreserved && type->ty == Tpointer));
+ tx = tfx->pointerTo();
+ }
+ //printf("\ttx = %s, to = %s\n", tx->toChars(), to->toChars());
+
+ MATCH m = tx->implicitConvTo(to);
+ if (m > MATCHnomatch)
+ {
+ // MATCHexact: exact type match
+ // MATCHconst: covairiant type match (eg. attributes difference)
+ // MATCHconvert: context conversion
+ m = convertMatch ? MATCHconvert : tx->equals(to) ? MATCHexact : MATCHconst;
+
+ if (presult)
+ {
+ (*presult) = (FuncExp *)copy();
+ (*presult)->type = to;
+
+ // Bugzilla 12508: Tweak function body for covariant returns.
+ (*presult)->fd->modifyReturns(sc, tof->next);
+ }
+ }
+ else if (!flag)
+ {
+ error("cannot implicitly convert expression (%s) of type %s to %s",
+ toChars(), tx->toChars(), to->toChars());
+ }
+ return m;
+}
+
+const char *FuncExp::toChars()
+{
+ return fd->toChars();
+}
+
+bool FuncExp::checkType()
+{
+ if (td)
+ {
+ error("template lambda has no type");
+ return true;
+ }
+ return false;
+}
+
+bool FuncExp::checkValue()
+{
+ if (td)
+ {
+ error("template lambda has no value");
+ return true;
+ }
+ return false;
+}
+
+/******************************** DeclarationExp **************************/
+
+DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration)
+ : Expression(loc, TOKdeclaration, sizeof(DeclarationExp))
+{
+ this->declaration = declaration;
+}
+
+Expression *DeclarationExp::syntaxCopy()
+{
+ return new DeclarationExp(loc, declaration->syntaxCopy(NULL));
+}
+
+bool DeclarationExp::hasCode()
+{
+ if (VarDeclaration *vd = declaration->isVarDeclaration())
+ {
+ return !(vd->storage_class & (STCmanifest | STCstatic));
+ }
+ return false;
+}
+
+/************************ TypeidExp ************************************/
+
+/*
+ * typeid(int)
+ */
+
+TypeidExp::TypeidExp(Loc loc, RootObject *o)
+ : Expression(loc, TOKtypeid, sizeof(TypeidExp))
+{
+ this->obj = o;
+}
+
+Expression *TypeidExp::syntaxCopy()
+{
+ return new TypeidExp(loc, objectSyntaxCopy(obj));
+}
+
+/************************ TraitsExp ************************************/
+/*
+ * __traits(identifier, args...)
+ */
+
+TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args)
+ : Expression(loc, TOKtraits, sizeof(TraitsExp))
+{
+ this->ident = ident;
+ this->args = args;
+}
+
+Expression *TraitsExp::syntaxCopy()
+{
+ return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args));
+}
+
+/************************************************************/
+
+HaltExp::HaltExp(Loc loc)
+ : Expression(loc, TOKhalt, sizeof(HaltExp))
+{
+}
+
+/************************************************************/
+
+IsExp::IsExp(Loc loc, Type *targ, Identifier *id, TOK tok,
+ Type *tspec, TOK tok2, TemplateParameters *parameters)
+ : Expression(loc, TOKis, sizeof(IsExp))
+{
+ this->targ = targ;
+ this->id = id;
+ this->tok = tok;
+ this->tspec = tspec;
+ this->tok2 = tok2;
+ this->parameters = parameters;
+}
+
+Expression *IsExp::syntaxCopy()
+{
+ // This section is identical to that in TemplateDeclaration::syntaxCopy()
+ TemplateParameters *p = NULL;
+ if (parameters)
+ {
+ p = new TemplateParameters();
+ p->setDim(parameters->dim);
+ for (size_t i = 0; i < p->dim; i++)
+ (*p)[i] = (*parameters)[i]->syntaxCopy();
+ }
+ return new IsExp(loc,
+ targ->syntaxCopy(),
+ id,
+ tok,
+ tspec ? tspec->syntaxCopy() : NULL,
+ tok2,
+ p);
+}
+
+void unSpeculative(Scope *sc, RootObject *o);
+
+/************************************************************/
+
+UnaExp::UnaExp(Loc loc, TOK op, int size, Expression *e1)
+ : Expression(loc, op, size)
+{
+ this->e1 = e1;
+ this->att1 = NULL;
+}
+
+Expression *UnaExp::syntaxCopy()
+{
+ UnaExp *e = (UnaExp *)copy();
+ e->type = NULL;
+ e->e1 = e->e1->syntaxCopy();
+ return e;
+}
+
+/********************************
+ * The type for a unary expression is incompatible.
+ * Print error message.
+ * Returns:
+ * ErrorExp
+ */
+Expression *UnaExp::incompatibleTypes()
+{
+ if (e1->type->toBasetype() == Type::terror)
+ return e1;
+
+ if (e1->op == TOKtype)
+ {
+ error("incompatible type for (%s(%s)): cannot use '%s' with types",
+ Token::toChars(op), e1->toChars(), Token::toChars(op));
+ }
+ else
+ {
+ error("incompatible type for (%s(%s)): '%s'",
+ Token::toChars(op), e1->toChars(), e1->type->toChars());
+ }
+ return new ErrorExp();
+}
+
+Expression *UnaExp::resolveLoc(Loc loc, Scope *sc)
+{
+ e1 = e1->resolveLoc(loc, sc);
+ return this;
+}
+
+/************************************************************/
+
+BinExp::BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
+ : Expression(loc, op, size)
+{
+ this->e1 = e1;
+ this->e2 = e2;
+
+ this->att1 = NULL;
+ this->att2 = NULL;
+}
+
+Expression *BinExp::syntaxCopy()
+{
+ BinExp *e = (BinExp *)copy();
+ e->type = NULL;
+ e->e1 = e->e1->syntaxCopy();
+ e->e2 = e->e2->syntaxCopy();
+ return e;
+}
+
+Expression *BinExp::checkOpAssignTypes(Scope *sc)
+{
+ // At that point t1 and t2 are the merged types. type is the original type of the lhs.
+ Type *t1 = e1->type;
+ Type *t2 = e2->type;
+
+ // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
+ // See issue 3841.
+ // Should we also prevent double to float (type->isfloating() && type->size() < t2 ->size()) ?
+ if (op == TOKaddass || op == TOKminass ||
+ op == TOKmulass || op == TOKdivass || op == TOKmodass ||
+ op == TOKpowass)
+ {
+ if ((type->isintegral() && t2->isfloating()))
+ {
+ warning("%s %s %s is performing truncating conversion",
+ type->toChars(), Token::toChars(op), t2->toChars());
+ }
+ }
+
+ // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
+ if (op == TOKmulass || op == TOKdivass || op == TOKmodass)
+ {
+ // Any multiplication by an imaginary or complex number yields a complex result.
+ // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
+ const char *opstr = Token::toChars(op);
+ if (t1->isreal() && t2->iscomplex())
+ {
+ error("%s %s %s is undefined. Did you mean %s %s %s.re ?",
+ t1->toChars(), opstr, t2->toChars(),
+ t1->toChars(), opstr, t2->toChars());
+ return new ErrorExp();
+ }
+ else if (t1->isimaginary() && t2->iscomplex())
+ {
+ error("%s %s %s is undefined. Did you mean %s %s %s.im ?",
+ t1->toChars(), opstr, t2->toChars(),
+ t1->toChars(), opstr, t2->toChars());
+ return new ErrorExp();
+ }
+ else if ((t1->isreal() || t1->isimaginary()) &&
+ t2->isimaginary())
+ {
+ error("%s %s %s is an undefined operation", t1->toChars(), opstr, t2->toChars());
+ return new ErrorExp();
+ }
+ }
+
+ // generate an error if this is a nonsensical += or -=, eg real += imaginary
+ if (op == TOKaddass || op == TOKminass)
+ {
+ // Addition or subtraction of a real and an imaginary is a complex result.
+ // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
+ if ((t1->isreal() && (t2->isimaginary() || t2->iscomplex())) ||
+ (t1->isimaginary() && (t2->isreal() || t2->iscomplex())))
+ {
+ error("%s %s %s is undefined (result is complex)",
+ t1->toChars(), Token::toChars(op), t2->toChars());
+ return new ErrorExp();
+ }
+ if (type->isreal() || type->isimaginary())
+ {
+ assert(global.errors || t2->isfloating());
+ e2 = e2->castTo(sc, t1);
+ }
+ }
+
+ if (op == TOKmulass)
+ {
+ if (t2->isfloating())
+ {
+ if (t1->isreal())
+ {
+ if (t2->isimaginary() || t2->iscomplex())
+ {
+ e2 = e2->castTo(sc, t1);
+ }
+ }
+ else if (t1->isimaginary())
+ {
+ if (t2->isimaginary() || t2->iscomplex())
+ {
+ switch (t1->ty)
+ {
+ case Timaginary32: t2 = Type::tfloat32; break;
+ case Timaginary64: t2 = Type::tfloat64; break;
+ case Timaginary80: t2 = Type::tfloat80; break;
+ default:
+ assert(0);
+ }
+ e2 = e2->castTo(sc, t2);
+ }
+ }
+ }
+ }
+ else if (op == TOKdivass)
+ {
+ if (t2->isimaginary())
+ {
+ if (t1->isreal())
+ {
+ // x/iv = i(-x/v)
+ // Therefore, the result is 0
+ e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat::zero, t1));
+ e2->type = t1;
+ Expression *e = new AssignExp(loc, e1, e2);
+ e->type = t1;
+ return e;
+ }
+ else if (t1->isimaginary())
+ {
+ Type *t3;
+ switch (t1->ty)
+ {
+ case Timaginary32: t3 = Type::tfloat32; break;
+ case Timaginary64: t3 = Type::tfloat64; break;
+ case Timaginary80: t3 = Type::tfloat80; break;
+ default:
+ assert(0);
+ }
+ e2 = e2->castTo(sc, t3);
+ Expression *e = new AssignExp(loc, e1, e2);
+ e->type = t1;
+ return e;
+ }
+ }
+ }
+ else if (op == TOKmodass)
+ {
+ if (t2->iscomplex())
+ {
+ error("cannot perform modulo complex arithmetic");
+ return new ErrorExp();
+ }
+ }
+ return this;
+}
+
+/********************************
+ * The types for a binary expression are incompatible.
+ * Print error message.
+ * Returns:
+ * ErrorExp
+ */
+Expression *BinExp::incompatibleTypes()
+{
+ if (e1->type->toBasetype() == Type::terror)
+ return e1;
+ if (e2->type->toBasetype() == Type::terror)
+ return e2;
+
+ // CondExp uses 'a ? b : c' but we're comparing 'b : c'
+ TOK thisOp = (op == TOKquestion) ? TOKcolon : op;
+ if (e1->op == TOKtype || e2->op == TOKtype)
+ {
+ error("incompatible types for ((%s) %s (%s)): cannot use '%s' with types",
+ e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op));
+ }
+ else
+ {
+ error("incompatible types for ((%s) %s (%s)): '%s' and '%s'",
+ e1->toChars(), Token::toChars(thisOp), e2->toChars(),
+ e1->type->toChars(), e2->type->toChars());
+ }
+ return new ErrorExp();
+}
+
+bool BinExp::checkIntegralBin()
+{
+ bool r1 = e1->checkIntegral();
+ bool r2 = e2->checkIntegral();
+ return (r1 || r2);
+}
+
+bool BinExp::checkArithmeticBin()
+{
+ bool r1 = e1->checkArithmetic();
+ bool r2 = e2->checkArithmetic();
+ return (r1 || r2);
+}
+
+/********************** BinAssignExp **************************************/
+
+BinAssignExp::BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
+ : BinExp(loc, op, size, e1, e2)
+{
+}
+
+bool BinAssignExp::isLvalue()
+{
+ return true;
+}
+
+Expression *BinAssignExp::toLvalue(Scope *, Expression *)
+{
+ // Lvalue-ness will be handled in glue layer.
+ return this;
+}
+
+Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *)
+{
+ // should check e1->checkModifiable() ?
+ return toLvalue(sc, this);
+}
+
+/************************************************************/
+
+CompileExp::CompileExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKmixin, sizeof(CompileExp), e)
+{
+}
+
+/************************************************************/
+
+ImportExp::ImportExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKimport, sizeof(ImportExp), e)
+{
+}
+
+/************************************************************/
+
+AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg)
+ : UnaExp(loc, TOKassert, sizeof(AssertExp), e)
+{
+ this->msg = msg;
+}
+
+Expression *AssertExp::syntaxCopy()
+{
+ return new AssertExp(loc, e1->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
+}
+
+/************************************************************/
+
+DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident)
+ : UnaExp(loc, TOKdotid, sizeof(DotIdExp), e)
+{
+ this->ident = ident;
+ this->wantsym = false;
+ this->noderef = false;
+}
+
+DotIdExp *DotIdExp::create(Loc loc, Expression *e, Identifier *ident)
+{
+ return new DotIdExp(loc, e, ident);
+}
+
+/********************** DotTemplateExp ***********************************/
+
+// Mainly just a placeholder
+
+DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td)
+ : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e)
+
+{
+ this->td = td;
+}
+
+/************************************************************/
+
+DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads)
+ : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e)
+{
+ //printf("DotVarExp()\n");
+ this->var = var;
+ this->hasOverloads = var->isVarDeclaration() ? false : hasOverloads;
+}
+
+bool DotVarExp::isLvalue()
+{
+ return true;
+}
+
+Expression *DotVarExp::toLvalue(Scope *, Expression *)
+{
+ //printf("DotVarExp::toLvalue(%s)\n", toChars());
+ return this;
+}
+
+/***********************************************
+ * Mark variable v as modified if it is inside a constructor that var
+ * is a field in.
+ */
+int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1)
+{
+ //printf("modifyFieldVar(var = %s)\n", var->toChars());
+ Dsymbol *s = sc->func;
+ while (1)
+ {
+ FuncDeclaration *fd = NULL;
+ if (s)
+ fd = s->isFuncDeclaration();
+ if (fd &&
+ ((fd->isCtorDeclaration() && var->isField()) ||
+ (fd->isStaticCtorDeclaration() && !var->isField())) &&
+ fd->toParent2() == var->toParent2() &&
+ (!e1 || e1->op == TOKthis)
+ )
+ {
+ bool result = true;
+
+ var->ctorinit = true;
+ //printf("setting ctorinit\n");
+
+ if (var->isField() && sc->fieldinit && !sc->intypeof)
+ {
+ assert(e1);
+ bool mustInit = ((var->storage_class & STCnodefaultctor) != 0 ||
+ var->type->needsNested());
+
+ size_t dim = sc->fieldinit_dim;
+ AggregateDeclaration *ad = fd->isMember2();
+ assert(ad);
+ size_t i;
+ for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
+ {
+ if (ad->fields[i] == var)
+ break;
+ }
+ assert(i < dim);
+ unsigned fi = sc->fieldinit[i];
+
+ if (fi & CSXthis_ctor)
+ {
+ if (var->type->isMutable() && e1->type->isMutable())
+ result = false;
+ else
+ {
+ const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
+ ::error(loc, "%s field '%s' initialized multiple times", modStr, var->toChars());
+ }
+ }
+ else if (sc->noctor || (fi & CSXlabel))
+ {
+ if (!mustInit && var->type->isMutable() && e1->type->isMutable())
+ result = false;
+ else
+ {
+ const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
+ ::error(loc, "%s field '%s' initialization is not allowed in loops or after labels", modStr, var->toChars());
+ }
+ }
+ sc->fieldinit[i] |= CSXthis_ctor;
+ if (var->overlapped) // Bugzilla 15258
+ {
+ for (size_t j = 0; j < ad->fields.dim; j++)
+ {
+ VarDeclaration *v = ad->fields[j];
+ if (v == var || !var->isOverlappedWith(v))
+ continue;
+ v->ctorinit = true;
+ sc->fieldinit[j] = CSXthis_ctor;
+ }
+ }
+ }
+ else if (fd != sc->func)
+ {
+ if (var->type->isMutable())
+ result = false;
+ else if (sc->func->fes)
+ {
+ const char *p = var->isField() ? "field" : var->kind();
+ ::error(loc, "%s %s '%s' initialization is not allowed in foreach loop",
+ MODtoChars(var->type->mod), p, var->toChars());
+ }
+ else
+ {
+ const char *p = var->isField() ? "field" : var->kind();
+ ::error(loc, "%s %s '%s' initialization is not allowed in nested function '%s'",
+ MODtoChars(var->type->mod), p, var->toChars(), sc->func->toChars());
+ }
+ }
+ return result;
+ }
+ else
+ {
+ if (s)
+ {
+ s = s->toParent2();
+ continue;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+int DotVarExp::checkModifiable(Scope *sc, int flag)
+{
+ //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type->toChars());
+ if (checkUnsafeAccess(sc, this, false, !flag))
+ return 2;
+
+ if (e1->op == TOKthis)
+ return var->checkModify(loc, sc, type, e1, flag);
+
+ //printf("\te1 = %s\n", e1->toChars());
+ return e1->checkModifiable(sc, flag);
+}
+
+Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+ return Expression::modifiableLvalue(sc, e);
+}
+
+/************************************************************/
+
+/* Things like:
+ * foo.bar!(args)
+ */
+
+DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs)
+ : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
+{
+ //printf("DotTemplateInstanceExp()\n");
+ this->ti = new TemplateInstance(loc, name);
+ this->ti->tiargs = tiargs;
+}
+
+DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti)
+ : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
+{
+ this->ti = ti;
+}
+
+Expression *DotTemplateInstanceExp::syntaxCopy()
+{
+ return new DotTemplateInstanceExp(loc,
+ e1->syntaxCopy(),
+ ti->name,
+ TemplateInstance::arraySyntaxCopy(ti->tiargs));
+}
+
+bool DotTemplateInstanceExp::findTempDecl(Scope *sc)
+{
+ if (ti->tempdecl)
+ return true;
+
+ Expression *e = new DotIdExp(loc, e1, ti->name);
+ e = semantic(e, sc);
+ if (e->op == TOKdot)
+ e = ((DotExp *)e)->e2;
+
+ Dsymbol *s = NULL;
+ switch (e->op)
+ {
+ case TOKoverloadset: s = ((OverExp *)e)->vars; break;
+ case TOKdottd: s = ((DotTemplateExp *)e)->td; break;
+ case TOKscope: s = ((ScopeExp *)e)->sds; break;
+ case TOKdotvar: s = ((DotVarExp *)e)->var; break;
+ case TOKvar: s = ((VarExp *)e)->var; break;
+ default: return false;
+ }
+ return ti->updateTempDecl(sc, s);
+}
+
+/************************************************************/
+
+DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, bool hasOverloads)
+ : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e)
+{
+ this->func = f;
+ this->hasOverloads = hasOverloads;
+}
+
+/************************************************************/
+
+DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s)
+ : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e)
+{
+ this->sym = s;
+ this->type = NULL;
+}
+
+/************************************************************/
+
+CallExp::CallExp(Loc loc, Expression *e, Expressions *exps)
+ : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+ this->arguments = exps;
+ this->f = NULL;
+ this->directcall = false;
+}
+
+CallExp::CallExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+ this->arguments = NULL;
+ this->f = NULL;
+ this->directcall = false;
+}
+
+CallExp::CallExp(Loc loc, Expression *e, Expression *earg1)
+ : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+ Expressions *arguments = new Expressions();
+ if (earg1)
+ {
+ arguments->setDim(1);
+ (*arguments)[0] = earg1;
+ }
+ this->arguments = arguments;
+ this->f = NULL;
+ this->directcall = false;
+}
+
+CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2)
+ : UnaExp(loc, TOKcall, sizeof(CallExp), e)
+{
+ Expressions *arguments = new Expressions();
+ arguments->setDim(2);
+ (*arguments)[0] = earg1;
+ (*arguments)[1] = earg2;
+
+ this->arguments = arguments;
+ this->f = NULL;
+ this->directcall = false;
+}
+
+CallExp *CallExp::create(Loc loc, Expression *e, Expressions *exps)
+{
+ return new CallExp(loc, e, exps);
+}
+
+CallExp *CallExp::create(Loc loc, Expression *e)
+{
+ return new CallExp(loc, e);
+}
+
+CallExp *CallExp::create(Loc loc, Expression *e, Expression *earg1)
+{
+ return new CallExp(loc, e, earg1);
+}
+
+Expression *CallExp::syntaxCopy()
+{
+ return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
+}
+
+bool CallExp::isLvalue()
+{
+ Type *tb = e1->type->toBasetype();
+ if (tb->ty == Tdelegate || tb->ty == Tpointer)
+ tb = tb->nextOf();
+ if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref)
+ {
+ if (e1->op == TOKdotvar)
+ if (((DotVarExp *)e1)->var->isCtorDeclaration())
+ return false;
+ return true; // function returns a reference
+ }
+ return false;
+}
+
+Expression *CallExp::toLvalue(Scope *sc, Expression *e)
+{
+ if (isLvalue())
+ return this;
+ return Expression::toLvalue(sc, e);
+}
+
+Expression *CallExp::addDtorHook(Scope *sc)
+{
+ /* Only need to add dtor hook if it's a type that needs destruction.
+ * Use same logic as VarDeclaration::callScopeDtor()
+ */
+
+ if (e1->type && e1->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)e1->type;
+ if (tf->isref)
+ return this;
+ }
+
+ Type *tv = type->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)tv;
+ StructDeclaration *sd = ts->sym;
+ if (sd->dtor)
+ {
+ /* Type needs destruction, so declare a tmp
+ * which the back end will recognize and call dtor on
+ */
+ VarDeclaration *tmp = copyToTemp(0, "__tmpfordtor", this);
+ DeclarationExp *de = new DeclarationExp(loc, tmp);
+ VarExp *ve = new VarExp(loc, tmp);
+ Expression *e = new CommaExp(loc, de, ve);
+ e = semantic(e, sc);
+ return e;
+ }
+ }
+ return this;
+}
+
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL)
+{
+ if (e->op == TOKaddress)
+ {
+ Expression *ae1 = ((AddrExp *)e)->e1;
+ if (ae1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)ae1;
+ if (hasOverloads)
+ *hasOverloads = ve->hasOverloads;
+ return ve->var->isFuncDeclaration();
+ }
+ if (ae1->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp *)ae1;
+ if (hasOverloads)
+ *hasOverloads = dve->hasOverloads;
+ return dve->var->isFuncDeclaration();
+ }
+ }
+ else
+ {
+ if (e->op == TOKsymoff)
+ {
+ SymOffExp *soe = (SymOffExp *)e;
+ if (hasOverloads)
+ *hasOverloads = soe->hasOverloads;
+ return soe->var->isFuncDeclaration();
+ }
+ if (e->op == TOKdelegate)
+ {
+ DelegateExp *dge = (DelegateExp *)e;
+ if (hasOverloads)
+ *hasOverloads = dge->hasOverloads;
+ return dge->func->isFuncDeclaration();
+ }
+ }
+ return NULL;
+}
+
+/************************************************************/
+
+AddrExp::AddrExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
+{
+}
+
+AddrExp::AddrExp(Loc loc, Expression *e, Type *t)
+ : UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
+{
+ type = t;
+}
+
+/************************************************************/
+
+PtrExp::PtrExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
+{
+// if (e->type)
+// type = ((TypePointer *)e->type)->next;
+}
+
+PtrExp::PtrExp(Loc loc, Expression *e, Type *t)
+ : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
+{
+ type = t;
+}
+
+bool PtrExp::isLvalue()
+{
+ return true;
+}
+
+Expression *PtrExp::toLvalue(Scope *, Expression *)
+{
+ return this;
+}
+
+int PtrExp::checkModifiable(Scope *sc, int flag)
+{
+ if (e1->op == TOKsymoff)
+ { SymOffExp *se = (SymOffExp *)e1;
+ return se->var->checkModify(loc, sc, type, NULL, flag);
+ }
+ else if (e1->op == TOKaddress)
+ {
+ AddrExp *ae = (AddrExp *)e1;
+ return ae->e1->checkModifiable(sc, flag);
+ }
+ return 1;
+}
+
+Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+ //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars());
+ return Expression::modifiableLvalue(sc, e);
+}
+
+/************************************************************/
+
+NegExp::NegExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKneg, sizeof(NegExp), e)
+{
+}
+
+/************************************************************/
+
+UAddExp::UAddExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKuadd, sizeof(UAddExp), e)
+{
+}
+
+/************************************************************/
+
+ComExp::ComExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKtilde, sizeof(ComExp), e)
+{
+}
+
+/************************************************************/
+
+NotExp::NotExp(Loc loc, Expression *e)
+ : UnaExp(loc, TOKnot, sizeof(NotExp), e)
+{
+}
+
+/************************************************************/
+
+DeleteExp::DeleteExp(Loc loc, Expression *e, bool isRAII)
+ : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e)
+{
+ this->isRAII = isRAII;
+}
+
+Expression *DeleteExp::toBoolean(Scope *)
+{
+ error("delete does not give a boolean result");
+ return new ErrorExp();
+}
+
+/************************************************************/
+
+CastExp::CastExp(Loc loc, Expression *e, Type *t)
+ : UnaExp(loc, TOKcast, sizeof(CastExp), e)
+{
+ this->to = t;
+ this->mod = (unsigned char)~0;
+}
+
+/* For cast(const) and cast(immutable)
+ */
+CastExp::CastExp(Loc loc, Expression *e, unsigned char mod)
+ : UnaExp(loc, TOKcast, sizeof(CastExp), e)
+{
+ this->to = NULL;
+ this->mod = mod;
+}
+
+Expression *CastExp::syntaxCopy()
+{
+ return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy())
+ : new CastExp(loc, e1->syntaxCopy(), mod);
+}
+
+/************************************************************/
+
+VectorExp::VectorExp(Loc loc, Expression *e, Type *t)
+ : UnaExp(loc, TOKvector, sizeof(VectorExp), e)
+{
+ assert(t->ty == Tvector);
+ to = (TypeVector *)t;
+ dim = ~0;
+}
+
+VectorExp *VectorExp::create(Loc loc, Expression *e, Type *t)
+{
+ return new VectorExp(loc, e, t);
+}
+
+Expression *VectorExp::syntaxCopy()
+{
+ return new VectorExp(loc, e1->syntaxCopy(), to->syntaxCopy());
+}
+
+/************************************************************/
+
+SliceExp::SliceExp(Loc loc, Expression *e1, IntervalExp *ie)
+ : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
+{
+ this->upr = ie ? ie->upr : NULL;
+ this->lwr = ie ? ie->lwr : NULL;
+ lengthVar = NULL;
+ upperIsInBounds = false;
+ lowerIsLessThanUpper = false;
+ arrayop = false;
+}
+
+SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr)
+ : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
+{
+ this->upr = upr;
+ this->lwr = lwr;
+ lengthVar = NULL;
+ upperIsInBounds = false;
+ lowerIsLessThanUpper = false;
+ arrayop = false;
+}
+
+Expression *SliceExp::syntaxCopy()
+{
+ SliceExp *se = new SliceExp(loc, e1->syntaxCopy(),
+ lwr ? lwr->syntaxCopy() : NULL,
+ upr ? upr->syntaxCopy() : NULL);
+ se->lengthVar = this->lengthVar; // bug7871
+ return se;
+}
+
+int SliceExp::checkModifiable(Scope *sc, int flag)
+{
+ //printf("SliceExp::checkModifiable %s\n", toChars());
+ if (e1->type->ty == Tsarray ||
+ (e1->op == TOKindex && e1->type->ty != Tarray) ||
+ e1->op == TOKslice)
+ {
+ return e1->checkModifiable(sc, flag);
+ }
+ return 1;
+}
+
+bool SliceExp::isLvalue()
+{
+ /* slice expression is rvalue in default, but
+ * conversion to reference of static array is only allowed.
+ */
+ return (type && type->toBasetype()->ty == Tsarray);
+}
+
+Expression *SliceExp::toLvalue(Scope *sc, Expression *e)
+{
+ //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
+ return (type && type->toBasetype()->ty == Tsarray)
+ ? this : Expression::toLvalue(sc, e);
+}
+
+Expression *SliceExp::modifiableLvalue(Scope *, Expression *)
+{
+ error("slice expression %s is not a modifiable lvalue", toChars());
+ return this;
+}
+
+bool SliceExp::isBool(bool result)
+{
+ return e1->isBool(result);
+}
+
+/********************** ArrayLength **************************************/
+
+ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
+ : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1)
+{
+}
+
+Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
+{ Expression *e;
+
+ switch (op)
+ {
+ case TOKaddass: e = new AddExp(loc, e1, e2); break;
+ case TOKminass: e = new MinExp(loc, e1, e2); break;
+ case TOKmulass: e = new MulExp(loc, e1, e2); break;
+ case TOKdivass: e = new DivExp(loc, e1, e2); break;
+ case TOKmodass: e = new ModExp(loc, e1, e2); break;
+ case TOKandass: e = new AndExp(loc, e1, e2); break;
+ case TOKorass: e = new OrExp (loc, e1, e2); break;
+ case TOKxorass: e = new XorExp(loc, e1, e2); break;
+ case TOKshlass: e = new ShlExp(loc, e1, e2); break;
+ case TOKshrass: e = new ShrExp(loc, e1, e2); break;
+ case TOKushrass: e = new UshrExp(loc, e1, e2); break;
+ default: assert(0);
+ }
+ return e;
+}
+
+/*********************
+ * Rewrite:
+ * array.length op= e2
+ * as:
+ * array.length = array.length op e2
+ * or:
+ * auto tmp = &array;
+ * (*tmp).length = (*tmp).length op e2
+ */
+
+Expression *ArrayLengthExp::rewriteOpAssign(BinExp *exp)
+{
+ Expression *e;
+
+ assert(exp->e1->op == TOKarraylength);
+ ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
+ if (ale->e1->op == TOKvar)
+ {
+ e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
+ e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
+ }
+ else
+ {
+ /* auto tmp = &array;
+ * (*tmp).length = (*tmp).length op e2
+ */
+ VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
+
+ Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
+ Expression *elvalue = e1->syntaxCopy();
+ e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
+ e = new AssignExp(exp->loc, elvalue, e);
+ e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
+ }
+ return e;
+}
+
+/*********************** IntervalExp ********************************/
+
+// Mainly just a placeholder
+
+IntervalExp::IntervalExp(Loc loc, Expression *lwr, Expression *upr)
+ : Expression(loc, TOKinterval, sizeof(IntervalExp))
+{
+ this->lwr = lwr;
+ this->upr = upr;
+}
+
+Expression *IntervalExp::syntaxCopy()
+{
+ return new IntervalExp(loc, lwr->syntaxCopy(), upr->syntaxCopy());
+}
+
+/********************** DelegatePtrExp **************************************/
+
+DelegatePtrExp::DelegatePtrExp(Loc loc, Expression *e1)
+ : UnaExp(loc, TOKdelegateptr, sizeof(DelegatePtrExp), e1)
+{
+}
+
+bool DelegatePtrExp::isLvalue()
+{
+ return e1->isLvalue();
+}
+
+Expression *DelegatePtrExp::toLvalue(Scope *sc, Expression *e)
+{
+ e1 = e1->toLvalue(sc, e);
+ return this;
+}
+
+Expression *DelegatePtrExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+ if (sc->func->setUnsafe())
+ {
+ error("cannot modify delegate pointer in @safe code %s", toChars());
+ return new ErrorExp();
+ }
+ return Expression::modifiableLvalue(sc, e);
+}
+
+/********************** DelegateFuncptrExp **************************************/
+
+DelegateFuncptrExp::DelegateFuncptrExp(Loc loc, Expression *e1)
+ : UnaExp(loc, TOKdelegatefuncptr, sizeof(DelegateFuncptrExp), e1)
+{
+}
+
+bool DelegateFuncptrExp::isLvalue()
+{
+ return e1->isLvalue();
+}
+
+Expression *DelegateFuncptrExp::toLvalue(Scope *sc, Expression *e)
+{
+ e1 = e1->toLvalue(sc, e);
+ return this;
+}
+
+Expression *DelegateFuncptrExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+ if (sc->func->setUnsafe())
+ {
+ error("cannot modify delegate function pointer in @safe code %s", toChars());
+ return new ErrorExp();
+ }
+ return Expression::modifiableLvalue(sc, e);
+}
+
+/*********************** ArrayExp *************************************/
+
+// e1 [ i1, i2, i3, ... ]
+
+ArrayExp::ArrayExp(Loc loc, Expression *e1, Expression *index)
+ : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
+{
+ arguments = new Expressions();
+ if (index)
+ arguments->push(index);
+ lengthVar = NULL;
+ currentDimension = 0;
+}
+
+ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args)
+ : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
+{
+ arguments = args;
+ lengthVar = NULL;
+ currentDimension = 0;
+}
+
+Expression *ArrayExp::syntaxCopy()
+{
+ ArrayExp *ae = new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
+ ae->lengthVar = this->lengthVar; // bug7871
+ return ae;
+}
+
+bool ArrayExp::isLvalue()
+{
+ if (type && type->toBasetype()->ty == Tvoid)
+ return false;
+ return true;
+}
+
+Expression *ArrayExp::toLvalue(Scope *, Expression *)
+{
+ if (type && type->toBasetype()->ty == Tvoid)
+ error("voids have no value");
+ return this;
+}
+
+/************************* DotExp ***********************************/
+
+DotExp::DotExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKdot, sizeof(DotExp), e1, e2)
+{
+}
+
+/************************* CommaExp ***********************************/
+
+CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated)
+ : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2)
+{
+ isGenerated = generated;
+ allowCommaExp = generated;
+}
+
+bool CommaExp::isLvalue()
+{
+ return e2->isLvalue();
+}
+
+Expression *CommaExp::toLvalue(Scope *sc, Expression *)
+{
+ e2 = e2->toLvalue(sc, NULL);
+ return this;
+}
+
+int CommaExp::checkModifiable(Scope *sc, int flag)
+{
+ return e2->checkModifiable(sc, flag);
+}
+
+Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+ e2 = e2->modifiableLvalue(sc, e);
+ return this;
+}
+
+bool CommaExp::isBool(bool result)
+{
+ return e2->isBool(result);
+}
+
+Expression *CommaExp::toBoolean(Scope *sc)
+{
+ Expression *ex2 = e2->toBoolean(sc);
+ if (ex2->op == TOKerror)
+ return ex2;
+ e2 = ex2;
+ type = e2->type;
+ return this;
+}
+
+Expression *CommaExp::addDtorHook(Scope *sc)
+{
+ e2 = e2->addDtorHook(sc);
+ return this;
+}
+
+/************************** IndexExp **********************************/
+
+// e1 [ e2 ]
+
+IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2)
+{
+ //printf("IndexExp::IndexExp('%s')\n", toChars());
+ lengthVar = NULL;
+ modifiable = false; // assume it is an rvalue
+ indexIsInBounds = false;
+}
+
+Expression *IndexExp::syntaxCopy()
+{
+ IndexExp *ie = new IndexExp(loc, e1->syntaxCopy(), e2->syntaxCopy());
+ ie->lengthVar = this->lengthVar; // bug7871
+ return ie;
+}
+
+bool IndexExp::isLvalue()
+{
+ return true;
+}
+
+Expression *IndexExp::toLvalue(Scope *, Expression *)
+{
+ return this;
+}
+
+int IndexExp::checkModifiable(Scope *sc, int flag)
+{
+ if (e1->type->ty == Tsarray ||
+ e1->type->ty == Taarray ||
+ (e1->op == TOKindex && e1->type->ty != Tarray) ||
+ e1->op == TOKslice)
+ {
+ return e1->checkModifiable(sc, flag);
+ }
+ return 1;
+}
+
+Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e)
+{
+ //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
+ Expression *ex = markSettingAAElem();
+ if (ex->op == TOKerror)
+ return ex;
+
+ return Expression::modifiableLvalue(sc, e);
+}
+
+Expression *IndexExp::markSettingAAElem()
+{
+ if (e1->type->toBasetype()->ty == Taarray)
+ {
+ Type *t2b = e2->type->toBasetype();
+ if (t2b->ty == Tarray && t2b->nextOf()->isMutable())
+ {
+ error("associative arrays can only be assigned values with immutable keys, not %s", e2->type->toChars());
+ return new ErrorExp();
+ }
+ modifiable = true;
+
+ if (e1->op == TOKindex)
+ {
+ Expression *ex = ((IndexExp *)e1)->markSettingAAElem();
+ if (ex->op == TOKerror)
+ return ex;
+ assert(ex == e1);
+ }
+ }
+ return this;
+}
+
+/************************* PostExp ***********************************/
+
+PostExp::PostExp(TOK op, Loc loc, Expression *e)
+ : BinExp(loc, op, sizeof(PostExp), e,
+ new IntegerExp(loc, 1, Type::tint32))
+{
+}
+
+/************************* PreExp ***********************************/
+
+PreExp::PreExp(TOK op, Loc loc, Expression *e)
+ : UnaExp(loc, op, sizeof(PreExp), e)
+{
+}
+
+/************************************************************/
+
+/* op can be TOKassign, TOKconstruct, or TOKblit */
+
+AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2)
+{
+ memset = 0;
+}
+
+bool AssignExp::isLvalue()
+{
+ // Array-op 'x[] = y[]' should make an rvalue.
+ // Setting array length 'x.length = v' should make an rvalue.
+ if (e1->op == TOKslice ||
+ e1->op == TOKarraylength)
+ {
+ return false;
+ }
+ return true;
+}
+
+Expression *AssignExp::toLvalue(Scope *sc, Expression *ex)
+{
+ if (e1->op == TOKslice ||
+ e1->op == TOKarraylength)
+ {
+ return Expression::toLvalue(sc, ex);
+ }
+
+ /* In front-end level, AssignExp should make an lvalue of e1.
+ * Taking the address of e1 will be handled in low level layer,
+ * so this function does nothing.
+ */
+ return this;
+}
+
+Expression *AssignExp::toBoolean(Scope *)
+{
+ // Things like:
+ // if (a = b) ...
+ // are usually mistakes.
+
+ error("assignment cannot be used as a condition, perhaps == was meant?");
+ return new ErrorExp();
+}
+
+/************************************************************/
+
+ConstructExp::ConstructExp(Loc loc, Expression *e1, Expression *e2)
+ : AssignExp(loc, e1, e2)
+{
+ op = TOKconstruct;
+}
+
+ConstructExp::ConstructExp(Loc loc, VarDeclaration *v, Expression *e2)
+ : AssignExp(loc, new VarExp(loc, v), e2)
+{
+ assert(v->type && e1->type);
+ op = TOKconstruct;
+
+ if (v->storage_class & (STCref | STCout))
+ memset |= referenceInit;
+}
+
+/************************************************************/
+
+BlitExp::BlitExp(Loc loc, Expression *e1, Expression *e2)
+ : AssignExp(loc, e1, e2)
+{
+ op = TOKblit;
+}
+
+BlitExp::BlitExp(Loc loc, VarDeclaration *v, Expression *e2)
+ : AssignExp(loc, new VarExp(loc, v), e2)
+{
+ assert(v->type && e1->type);
+ op = TOKblit;
+
+ if (v->storage_class & (STCref | STCout))
+ memset |= referenceInit;
+}
+
+/************************************************************/
+
+AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2)
+{
+}
+
+/***************** PowAssignExp *******************************************/
+
+PowAssignExp::PowAssignExp(Loc loc, Expression *e1, Expression *e2)
+ : BinAssignExp(loc, TOKpowass, sizeof(PowAssignExp), e1, e2)
+{
+}
+
+/************************* AddExp *****************************/
+
+AddExp::AddExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MinExp::MinExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2)
+{
+}
+
+/************************* CatExp *****************************/
+
+CatExp::CatExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+MulExp::MulExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+DivExp::DivExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ModExp::ModExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+PowExp::PowExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKpow, sizeof(PowExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+AndExp::AndExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKand, sizeof(AndExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+OrExp::OrExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKor, sizeof(OrExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+XorExp::XorExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2)
+{
+}
+
+Expression *OrOrExp::toBoolean(Scope *sc)
+{
+ Expression *ex2 = e2->toBoolean(sc);
+ if (ex2->op == TOKerror)
+ return ex2;
+ e2 = ex2;
+ return this;
+}
+
+/************************************************************/
+
+AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2)
+{
+}
+
+Expression *AndAndExp::toBoolean(Scope *sc)
+{
+ Expression *ex2 = e2->toBoolean(sc);
+ if (ex2->op == TOKerror)
+ return ex2;
+ e2 = ex2;
+ return this;
+}
+
+/************************************************************/
+
+InExp::InExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKin, sizeof(InExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+/* This deletes the key e1 from the associative array e2
+ */
+
+RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2)
+{
+ type = Type::tbool;
+}
+
+/************************************************************/
+
+CmpExp::CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, op, sizeof(CmpExp), e1, e2)
+{
+}
+
+/************************************************************/
+
+EqualExp::EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, op, sizeof(EqualExp), e1, e2)
+{
+ assert(op == TOKequal || op == TOKnotequal);
+}
+
+/************************************************************/
+
+IdentityExp::IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2)
+ : BinExp(loc, op, sizeof(IdentityExp), e1, e2)
+{
+}
+
+/****************************************************************/
+
+CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2)
+ : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2)
+{
+ this->econd = econd;
+}
+
+Expression *CondExp::syntaxCopy()
+{
+ return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy());
+}
+
+void CondExp::hookDtors(Scope *sc)
+{
+ class DtorVisitor : public StoppableVisitor
+ {
+ public:
+ Scope *sc;
+ CondExp *ce;
+ VarDeclaration *vcond;
+ bool isThen;
+
+ DtorVisitor(Scope *sc, CondExp *ce)
+ {
+ this->sc = sc;
+ this->ce = ce;
+ this->vcond = NULL;
+ }
+
+ void visit(Expression *)
+ {
+ //printf("(e = %s)\n", e->toChars());
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ VarDeclaration *v = e->declaration->isVarDeclaration();
+ if (v && !v->isDataseg())
+ {
+ if (v->_init)
+ {
+ ExpInitializer *ei = v->_init->isExpInitializer();
+ if (ei)
+ ei->exp->accept(this);
+ }
+
+ if (v->needsScopeDtor())
+ {
+ if (!vcond)
+ {
+ vcond = copyToTemp(STCvolatile, "__cond", ce->econd);
+ vcond->semantic(sc);
+
+ Expression *de = new DeclarationExp(ce->econd->loc, vcond);
+ de = semantic(de, sc);
+
+ Expression *ve = new VarExp(ce->econd->loc, vcond);
+ ce->econd = Expression::combine(de, ve);
+ }
+
+ //printf("\t++v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
+ Expression *ve = new VarExp(vcond->loc, vcond);
+ if (isThen)
+ v->edtor = new AndAndExp(v->edtor->loc, ve, v->edtor);
+ else
+ v->edtor = new OrOrExp(v->edtor->loc, ve, v->edtor);
+ v->edtor = semantic(v->edtor, sc);
+ //printf("\t--v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
+ }
+ }
+ }
+ };
+
+ DtorVisitor v(sc, this);
+ //printf("+%s\n", toChars());
+ v.isThen = true; walkPostorder(e1, &v);
+ v.isThen = false; walkPostorder(e2, &v);
+ //printf("-%s\n", toChars());
+}
+
+bool CondExp::isLvalue()
+{
+ return e1->isLvalue() && e2->isLvalue();
+}
+
+
+Expression *CondExp::toLvalue(Scope *sc, Expression *)
+{
+ // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
+ CondExp *e = (CondExp *)copy();
+ e->e1 = e1->toLvalue(sc, NULL)->addressOf();
+ e->e2 = e2->toLvalue(sc, NULL)->addressOf();
+ e->type = type->pointerTo();
+ return new PtrExp(loc, e, type);
+}
+
+int CondExp::checkModifiable(Scope *sc, int flag)
+{
+ return e1->checkModifiable(sc, flag) && e2->checkModifiable(sc, flag);
+}
+
+Expression *CondExp::modifiableLvalue(Scope *sc, Expression *)
+{
+ //error("conditional expression %s is not a modifiable lvalue", toChars());
+ e1 = e1->modifiableLvalue(sc, e1);
+ e2 = e2->modifiableLvalue(sc, e2);
+ return toLvalue(sc, this);
+}
+
+Expression *CondExp::toBoolean(Scope *sc)
+{
+ Expression *ex1 = e1->toBoolean(sc);
+ Expression *ex2 = e2->toBoolean(sc);
+ if (ex1->op == TOKerror)
+ return ex1;
+ if (ex2->op == TOKerror)
+ return ex2;
+ e1 = ex1;
+ e2 = ex2;
+ return this;
+}
+
+/****************************************************************/
+
+DefaultInitExp::DefaultInitExp(Loc loc, TOK subop, int size)
+ : Expression(loc, TOKdefault, size)
+{
+ this->subop = subop;
+}
+
+/****************************************************************/
+
+FileInitExp::FileInitExp(Loc loc, TOK tok)
+ : DefaultInitExp(loc, tok, sizeof(FileInitExp))
+{
+}
+
+Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+ //printf("FileInitExp::resolve() %s\n", toChars());
+ const char *s = loc.filename ? loc.filename : sc->_module->ident->toChars();
+ if (subop == TOKfilefullpath)
+ s = FileName::combine(sc->_module->srcfilePath, s);
+ Expression *e = new StringExp(loc, const_cast<char *>(s));
+ e = semantic(e, sc);
+ e = e->castTo(sc, type);
+ return e;
+}
+
+/****************************************************************/
+
+LineInitExp::LineInitExp(Loc loc)
+ : DefaultInitExp(loc, TOKline, sizeof(LineInitExp))
+{
+}
+
+Expression *LineInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+ Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32);
+ e = e->castTo(sc, type);
+ return e;
+}
+
+/****************************************************************/
+
+ModuleInitExp::ModuleInitExp(Loc loc)
+ : DefaultInitExp(loc, TOKmodulestring, sizeof(ModuleInitExp))
+{
+}
+
+Expression *ModuleInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+ const char *s;
+ if (sc->callsc)
+ s = sc->callsc->_module->toPrettyChars();
+ else
+ s = sc->_module->toPrettyChars();
+ Expression *e = new StringExp(loc, const_cast<char *>(s));
+ e = semantic(e, sc);
+ e = e->castTo(sc, type);
+ return e;
+}
+
+/****************************************************************/
+
+FuncInitExp::FuncInitExp(Loc loc)
+ : DefaultInitExp(loc, TOKfuncstring, sizeof(FuncInitExp))
+{
+}
+
+Expression *FuncInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+ const char *s;
+ if (sc->callsc && sc->callsc->func)
+ s = sc->callsc->func->Dsymbol::toPrettyChars();
+ else if (sc->func)
+ s = sc->func->Dsymbol::toPrettyChars();
+ else
+ s = "";
+ Expression *e = new StringExp(loc, const_cast<char *>(s));
+ e = semantic(e, sc);
+ e = e->castTo(sc, type);
+ return e;
+}
+
+/****************************************************************/
+
+PrettyFuncInitExp::PrettyFuncInitExp(Loc loc)
+ : DefaultInitExp(loc, TOKprettyfunc, sizeof(PrettyFuncInitExp))
+{
+}
+
+Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc)
+{
+ FuncDeclaration *fd;
+ if (sc->callsc && sc->callsc->func)
+ fd = sc->callsc->func;
+ else
+ fd = sc->func;
+
+ const char *s;
+ if (fd)
+ {
+ const char *funcStr = fd->Dsymbol::toPrettyChars();
+ OutBuffer buf;
+ functionToBufferWithIdent((TypeFunction *)fd->type, &buf, funcStr);
+ s = buf.extractString();
+ }
+ else
+ {
+ s = "";
+ }
+
+ Expression *e = new StringExp(loc, const_cast<char *>(s));
+ e = semantic(e, sc);
+ e = e->castTo(sc, type);
+ return e;
+}
+
+/****************************************************************/
+
+Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
+{
+ Expression *e0;
+ Expression *e1 = Expression::extractLast(ue->e1, &e0);
+ // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
+
+ if (!isTrivialExp(e1))
+ {
+ /* Even if opDollar is needed, 'e1' should be evaluate only once. So
+ * Rewrite:
+ * e1.opIndex( ... use of $ ... )
+ * e1.opSlice( ... use of $ ... )
+ * as:
+ * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
+ * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
+ */
+ e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
+ assert(e1->op == TOKvar);
+ VarExp *ve = (VarExp *)e1;
+ ve->var->storage_class |= STCexptemp; // lifetime limited to expression
+ }
+ ue->e1 = e1;
+ return e0;
+}
+
+/**************************************
+ * Runs semantic on ae->arguments. Declares temporary variables
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
+{
+ assert(!ae->lengthVar);
+
+ *pe0 = NULL;
+
+ AggregateDeclaration *ad = isAggregate(ae->e1->type);
+ Dsymbol *slice = search_function(ad, Id::slice);
+ //printf("slice = %s %s\n", slice->kind(), slice->toChars());
+
+ for (size_t i = 0; i < ae->arguments->dim; i++)
+ {
+ if (i == 0)
+ *pe0 = extractOpDollarSideEffect(sc, ae);
+
+ Expression *e = (*ae->arguments)[i];
+ if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
+ {
+ Lfallback:
+ if (ae->arguments->dim == 1)
+ return NULL;
+ ae->error("multi-dimensional slicing requires template opSlice");
+ return new ErrorExp();
+ }
+ //printf("[%d] e = %s\n", i, e->toChars());
+
+ // Create scope for '$' variable for this dimension
+ ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+ sym->loc = ae->loc;
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+ ae->lengthVar = NULL; // Create it only if required
+ ae->currentDimension = i; // Dimension for $, if required
+
+ e = semantic(e, sc);
+ e = resolveProperties(sc, e);
+
+ if (ae->lengthVar && sc->func)
+ {
+ // If $ was used, declare it now
+ Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+ de = semantic(de, sc);
+ *pe0 = Expression::combine(*pe0, de);
+ }
+ sc = sc->pop();
+
+ if (e->op == TOKinterval)
+ {
+ IntervalExp *ie = (IntervalExp *)e;
+
+ Objects *tiargs = new Objects();
+ Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
+ edim = semantic(edim, sc);
+ tiargs->push(edim);
+
+ Expressions *fargs = new Expressions();
+ fargs->push(ie->lwr);
+ fargs->push(ie->upr);
+
+ unsigned xerrors = global.startGagging();
+ sc = sc->push();
+ FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
+ sc = sc->pop();
+ global.endGagging(xerrors);
+ if (!fslice)
+ goto Lfallback;
+
+ e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
+ e = new CallExp(ae->loc, e, fargs);
+ e = semantic(e, sc);
+ }
+
+ if (!e->type)
+ {
+ ae->error("%s has no value", e->toChars());
+ e = new ErrorExp();
+ }
+ if (e->op == TOKerror)
+ return e;
+
+ (*ae->arguments)[i] = e;
+ }
+
+ return ae;
+}
+
+/**************************************
+ * Runs semantic on se->lwr and se->upr. Declares a temporary variable
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
+{
+ //assert(!ae->lengthVar);
+ if (!ie)
+ return ae;
+
+ VarDeclaration *lengthVar = ae->lengthVar;
+
+ // create scope for '$'
+ ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+ sym->loc = ae->loc;
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+
+ for (size_t i = 0; i < 2; ++i)
+ {
+ Expression *e = i == 0 ? ie->lwr : ie->upr;
+ e = semantic(e, sc);
+ e = resolveProperties(sc, e);
+ if (!e->type)
+ {
+ ae->error("%s has no value", e->toChars());
+ return new ErrorExp();
+ }
+ (i == 0 ? ie->lwr : ie->upr) = e;
+ }
+
+ if (lengthVar != ae->lengthVar && sc->func)
+ {
+ // If $ was used, declare it now
+ Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+ de = semantic(de, sc);
+ *pe0 = Expression::combine(*pe0, de);
+ }
+ sc = sc->pop();
+
+ return ae;
+}
+
+Expression *BinExp::reorderSettingAAElem(Scope *sc)
+{
+ BinExp *be = this;
+
+ if (be->e1->op != TOKindex)
+ return be;
+ IndexExp *ie = (IndexExp *)be->e1;
+ if (ie->e1->type->toBasetype()->ty != Taarray)
+ return be;
+
+ /* Fix evaluation order of setting AA element. (Bugzilla 3825)
+ * Rewrite:
+ * aa[k1][k2][k3] op= val;
+ * as:
+ * auto ref __aatmp = aa;
+ * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
+ * auto ref __aaval = val;
+ * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
+ */
+
+ Expression *e0 = NULL;
+ while (1)
+ {
+ Expression *de = NULL;
+ ie->e2 = extractSideEffect(sc, "__aakey", &de, ie->e2);
+ e0 = Expression::combine(de, e0);
+
+ Expression *ie1 = ie->e1;
+ if (ie1->op != TOKindex ||
+ ((IndexExp *)ie1)->e1->type->toBasetype()->ty != Taarray)
+ {
+ break;
+ }
+ ie = (IndexExp *)ie1;
+ }
+ assert(ie->e1->type->toBasetype()->ty == Taarray);
+
+ Expression *de = NULL;
+ ie->e1 = extractSideEffect(sc, "__aatmp", &de, ie->e1);
+ e0 = Expression::combine(de, e0);
+
+ be->e2 = extractSideEffect(sc, "__aaval", &e0, be->e2, true);
+
+ //printf("-e0 = %s, be = %s\n", e0->toChars(), be->toChars());
+ return Expression::combine(e0, be);
+}
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
new file mode 100644
index 0000000..57c516c
--- /dev/null
+++ b/gcc/d/dmd/expression.h
@@ -0,0 +1,1559 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/expression.h
+ */
+
+#pragma once
+
+#include "complex_t.h"
+#include "globals.h"
+#include "identifier.h"
+#include "arraytypes.h"
+#include "intrange.h"
+#include "visitor.h"
+#include "tokens.h"
+
+#include "root/rmem.h"
+
+class Type;
+class TypeVector;
+struct Scope;
+class TupleDeclaration;
+class VarDeclaration;
+class FuncDeclaration;
+class FuncLiteralDeclaration;
+class Declaration;
+class CtorDeclaration;
+class NewDeclaration;
+class Dsymbol;
+class Import;
+class Module;
+class ScopeDsymbol;
+class Expression;
+class Declaration;
+class AggregateDeclaration;
+class StructDeclaration;
+class TemplateInstance;
+class TemplateDeclaration;
+class ClassDeclaration;
+class BinExp;
+class OverloadSet;
+class Initializer;
+class StringExp;
+class ArrayExp;
+class SliceExp;
+struct UnionExp;
+#ifdef IN_GCC
+typedef union tree_node Symbol;
+#else
+struct Symbol; // back end symbol
+#endif
+
+Expression *resolveProperties(Scope *sc, Expression *e);
+Expression *resolvePropertiesOnly(Scope *sc, Expression *e1);
+bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d);
+bool checkAccess(Loc loc, Scope *sc, Package *p);
+Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d);
+Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid);
+void expandTuples(Expressions *exps);
+TupleDeclaration *isAliasThisTuple(Expression *e);
+int expandAliasThisTuples(Expressions *exps, size_t starti = 0);
+FuncDeclaration *hasThis(Scope *sc);
+Expression *fromConstInitializer(int result, Expression *e);
+bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors = false);
+TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s);
+Expression *valueNoDtor(Expression *e);
+int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1);
+Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag = false);
+Expression *doCopyOrMove(Scope *sc, Expression *e);
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0);
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0);
+Expression *integralPromotions(Expression *e, Scope *sc);
+bool discardValue(Expression *e);
+bool isTrivialExp(Expression *e);
+
+int isConst(Expression *e);
+Expression *toDelegate(Expression *e, Type* t, Scope *sc);
+AggregateDeclaration *isAggregate(Type *t);
+IntRange getIntRange(Expression *e);
+bool checkNonAssignmentArrayOp(Expression *e, bool suggestion = false);
+bool isUnaArrayOp(TOK op);
+bool isBinArrayOp(TOK op);
+bool isBinAssignArrayOp(TOK op);
+bool isArrayOpOperand(Expression *e);
+Expression *arrayOp(BinExp *e, Scope *sc);
+Expression *arrayOp(BinAssignExp *e, Scope *sc);
+bool hasSideEffect(Expression *e);
+bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow);
+Expression *Expression_optimize(Expression *e, int result, bool keepLvalue);
+MATCH implicitConvTo(Expression *e, Type *t);
+Expression *implicitCastTo(Expression *e, Scope *sc, Type *t);
+Expression *castTo(Expression *e, Scope *sc, Type *t);
+Expression *ctfeInterpret(Expression *);
+Expression *inlineCopy(Expression *e, Scope *sc);
+Expression *op_overload(Expression *e, Scope *sc);
+Type *toStaticArrayType(SliceExp *e);
+Expression *scaleFactor(BinExp *be, Scope *sc);
+Expression *typeCombine(BinExp *be, Scope *sc);
+Expression *inferType(Expression *e, Type *t, int flag = 0);
+Expression *semanticTraits(TraitsExp *e, Scope *sc);
+Type *getIndirection(Type *t);
+
+Expression *checkGC(Scope *sc, Expression *e);
+
+/* Run CTFE on the expression, but allow the expression to be a TypeExp
+ * or a tuple containing a TypeExp. (This is required by pragma(msg)).
+ */
+Expression *ctfeInterpretForPragmaMsg(Expression *e);
+
+enum OwnedBy
+{
+ OWNEDcode, // normal code expression in AST
+ OWNEDctfe, // value expression for CTFE
+ OWNEDcache // constant value cached for CTFE
+};
+
+#define WANTvalue 0 // default
+#define WANTexpand 1 // expand const/immutable variables if possible
+
+class Expression : public RootObject
+{
+public:
+ Loc loc; // file location
+ Type *type; // !=NULL means that semantic() has been run
+ TOK op; // to minimize use of dynamic_cast
+ unsigned char size; // # of bytes in Expression so we can copy() it
+ unsigned char parens; // if this is a parenthesized expression
+
+ Expression(Loc loc, TOK op, int size);
+ static void _init();
+ Expression *copy();
+ virtual Expression *syntaxCopy();
+
+ // kludge for template.isExpression()
+ int dyncast() const { return DYNCAST_EXPRESSION; }
+
+ void print();
+ const char *toChars();
+ void error(const char *format, ...) const;
+ void warning(const char *format, ...) const;
+ void deprecation(const char *format, ...) const;
+
+ // creates a single expression which is effectively (e1, e2)
+ // this new expression does not necessarily need to have valid D source code representation,
+ // for example, it may include declaration expressions
+ static Expression *combine(Expression *e1, Expression *e2);
+ static Expression *extractLast(Expression *e, Expression **pe0);
+ static Expressions *arraySyntaxCopy(Expressions *exps);
+
+ virtual dinteger_t toInteger();
+ virtual uinteger_t toUInteger();
+ virtual real_t toReal();
+ virtual real_t toImaginary();
+ virtual complex_t toComplex();
+ virtual StringExp *toStringExp();
+ virtual bool isLvalue();
+ virtual Expression *toLvalue(Scope *sc, Expression *e);
+ virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
+ Expression *implicitCastTo(Scope *sc, Type *t)
+ {
+ return ::implicitCastTo(this, sc, t);
+ }
+ MATCH implicitConvTo(Type *t)
+ {
+ return ::implicitConvTo(this, t);
+ }
+ Expression *castTo(Scope *sc, Type *t)
+ {
+ return ::castTo(this, sc, t);
+ }
+ virtual Expression *resolveLoc(Loc loc, Scope *sc);
+ virtual bool checkType();
+ virtual bool checkValue();
+ bool checkScalar();
+ bool checkNoBool();
+ bool checkIntegral();
+ bool checkArithmetic();
+ void checkDeprecated(Scope *sc, Dsymbol *s);
+ bool checkPurity(Scope *sc, FuncDeclaration *f);
+ bool checkPurity(Scope *sc, VarDeclaration *v);
+ bool checkSafety(Scope *sc, FuncDeclaration *f);
+ bool checkNogc(Scope *sc, FuncDeclaration *f);
+ bool checkPostblit(Scope *sc, Type *t);
+ bool checkRightThis(Scope *sc);
+ bool checkReadModifyWrite(TOK rmwOp, Expression *ex = NULL);
+ virtual int checkModifiable(Scope *sc, int flag = 0);
+ virtual Expression *toBoolean(Scope *sc);
+ virtual Expression *addDtorHook(Scope *sc);
+ Expression *addressOf();
+ Expression *deref();
+
+ Expression *optimize(int result, bool keepLvalue = false)
+ {
+ return Expression_optimize(this, result, keepLvalue);
+ }
+
+ // Entry point for CTFE.
+ // A compile-time result is required. Give an error if not possible
+ Expression *ctfeInterpret()
+ {
+ return ::ctfeInterpret(this);
+ }
+
+ int isConst() { return ::isConst(this); }
+ virtual bool isBool(bool result);
+ Expression *op_overload(Scope *sc)
+ {
+ return ::op_overload(this, sc);
+ }
+
+ virtual bool hasCode()
+ {
+ return true;
+ }
+
+ virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class IntegerExp : public Expression
+{
+public:
+ dinteger_t value;
+
+ IntegerExp(Loc loc, dinteger_t value, Type *type);
+ IntegerExp(dinteger_t value);
+ static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
+ bool equals(RootObject *o);
+ dinteger_t toInteger();
+ real_t toReal();
+ real_t toImaginary();
+ complex_t toComplex();
+ bool isBool(bool result);
+ Expression *toLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+ dinteger_t getInteger() { return value; }
+ void setInteger(dinteger_t value);
+ void normalize();
+};
+
+class ErrorExp : public Expression
+{
+public:
+ ErrorExp();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+
+ static ErrorExp *errorexp; // handy shared value
+};
+
+class RealExp : public Expression
+{
+public:
+ real_t value;
+
+ RealExp(Loc loc, real_t value, Type *type);
+ static RealExp *create(Loc loc, real_t value, Type *type);
+ bool equals(RootObject *o);
+ dinteger_t toInteger();
+ uinteger_t toUInteger();
+ real_t toReal();
+ real_t toImaginary();
+ complex_t toComplex();
+ bool isBool(bool result);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ComplexExp : public Expression
+{
+public:
+ complex_t value;
+
+ ComplexExp(Loc loc, complex_t value, Type *type);
+ static ComplexExp *create(Loc loc, complex_t value, Type *type);
+ bool equals(RootObject *o);
+ dinteger_t toInteger();
+ uinteger_t toUInteger();
+ real_t toReal();
+ real_t toImaginary();
+ complex_t toComplex();
+ bool isBool(bool result);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class IdentifierExp : public Expression
+{
+public:
+ Identifier *ident;
+
+ IdentifierExp(Loc loc, Identifier *ident);
+ static IdentifierExp *create(Loc loc, Identifier *ident);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DollarExp : public IdentifierExp
+{
+public:
+ DollarExp(Loc loc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DsymbolExp : public Expression
+{
+public:
+ Dsymbol *s;
+ bool hasOverloads;
+
+ DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads = true);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ThisExp : public Expression
+{
+public:
+ VarDeclaration *var;
+
+ ThisExp(Loc loc);
+ bool isBool(bool result);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SuperExp : public ThisExp
+{
+public:
+ SuperExp(Loc loc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class NullExp : public Expression
+{
+public:
+ unsigned char committed; // !=0 if type is committed
+
+ NullExp(Loc loc, Type *t = NULL);
+ bool equals(RootObject *o);
+ bool isBool(bool result);
+ StringExp *toStringExp();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StringExp : public Expression
+{
+public:
+ void *string; // char, wchar, or dchar data
+ size_t len; // number of chars, wchars, or dchars
+ unsigned char sz; // 1: char, 2: wchar, 4: dchar
+ unsigned char committed; // !=0 if type is committed
+ utf8_t postfix; // 'c', 'w', 'd'
+ OwnedBy ownedByCtfe;
+
+ StringExp(Loc loc, char *s);
+ StringExp(Loc loc, void *s, size_t len);
+ StringExp(Loc loc, void *s, size_t len, utf8_t postfix);
+ static StringExp *create(Loc loc, char *s);
+ static StringExp *create(Loc loc, void *s, size_t len);
+ bool equals(RootObject *o);
+ StringExp *toStringExp();
+ StringExp *toUTF8(Scope *sc);
+ int compare(RootObject *obj);
+ bool isBool(bool result);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ unsigned charAt(uinteger_t i) const;
+ void accept(Visitor *v) { v->visit(this); }
+ size_t numberOfCodeUnits(int tynto = 0) const;
+ void writeTo(void* dest, bool zero, int tyto = 0) const;
+ char *toPtr();
+};
+
+// Tuple
+
+class TupleExp : public Expression
+{
+public:
+ Expression *e0; // side-effect part
+ /* Tuple-field access may need to take out its side effect part.
+ * For example:
+ * foo().tupleof
+ * is rewritten as:
+ * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
+ * The declaration of temporary variable __tup will be stored in TupleExp::e0.
+ */
+ Expressions *exps;
+
+ TupleExp(Loc loc, Expression *e0, Expressions *exps);
+ TupleExp(Loc loc, Expressions *exps);
+ TupleExp(Loc loc, TupleDeclaration *tup);
+ Expression *syntaxCopy();
+ bool equals(RootObject *o);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ArrayLiteralExp : public Expression
+{
+public:
+ Expression *basis;
+ Expressions *elements;
+ OwnedBy ownedByCtfe;
+
+ ArrayLiteralExp(Loc loc, Expressions *elements);
+ ArrayLiteralExp(Loc loc, Expression *e);
+ ArrayLiteralExp(Loc loc, Expression *basis, Expressions *elements);
+ static ArrayLiteralExp *create(Loc loc, Expressions *elements);
+ Expression *syntaxCopy();
+ bool equals(RootObject *o);
+ Expression *getElement(d_size_t i);
+ static Expressions* copyElements(Expression *e1, Expression *e2 = NULL);
+ bool isBool(bool result);
+ StringExp *toStringExp();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AssocArrayLiteralExp : public Expression
+{
+public:
+ Expressions *keys;
+ Expressions *values;
+ OwnedBy ownedByCtfe;
+
+ AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values);
+ bool equals(RootObject *o);
+ Expression *syntaxCopy();
+ bool isBool(bool result);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// scrubReturnValue is running
+#define stageScrub 0x1
+// hasNonConstPointers is running
+#define stageSearchPointers 0x2
+// optimize is running
+#define stageOptimize 0x4
+// apply is running
+#define stageApply 0x8
+//inlineScan is running
+#define stageInlineScan 0x10
+// toCBuffer is running
+#define stageToCBuffer 0x20
+
+class StructLiteralExp : public Expression
+{
+public:
+ StructDeclaration *sd; // which aggregate this is for
+ Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip
+ Type *stype; // final type of result (can be different from sd's type)
+
+ bool useStaticInit; // if this is true, use the StructDeclaration's init symbol
+ Symbol *sym; // back end symbol to initialize with literal
+
+ OwnedBy ownedByCtfe;
+
+ // pointer to the origin instance of the expression.
+ // once a new expression is created, origin is set to 'this'.
+ // anytime when an expression copy is created, 'origin' pointer is set to
+ // 'origin' pointer value of the original expression.
+ StructLiteralExp *origin;
+
+ // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
+ StructLiteralExp *inlinecopy;
+
+ // anytime when recursive function is calling, 'stageflags' marks with bit flag of
+ // current stage and unmarks before return from this function.
+ // 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
+ // (with infinite recursion) of this expression.
+ int stageflags;
+
+ StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL);
+ static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
+ bool equals(RootObject *o);
+ Expression *syntaxCopy();
+ Expression *getField(Type *type, unsigned offset);
+ int getFieldIndex(Type *type, unsigned offset);
+ Expression *addDtorHook(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotIdExp;
+DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident);
+
+class TypeExp : public Expression
+{
+public:
+ TypeExp(Loc loc, Type *type);
+ Expression *syntaxCopy();
+ bool checkType();
+ bool checkValue();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ScopeExp : public Expression
+{
+public:
+ ScopeDsymbol *sds;
+
+ ScopeExp(Loc loc, ScopeDsymbol *sds);
+ Expression *syntaxCopy();
+ bool checkType();
+ bool checkValue();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TemplateExp : public Expression
+{
+public:
+ TemplateDeclaration *td;
+ FuncDeclaration *fd;
+
+ TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd = NULL);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ bool checkType();
+ bool checkValue();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class NewExp : public Expression
+{
+public:
+ /* thisexp.new(newargs) newtype(arguments)
+ */
+ Expression *thisexp; // if !NULL, 'this' for class being allocated
+ Expressions *newargs; // Array of Expression's to call new operator
+ Type *newtype;
+ Expressions *arguments; // Array of Expression's
+
+ Expression *argprefix; // expression to be evaluated just before arguments[]
+
+ CtorDeclaration *member; // constructor function
+ NewDeclaration *allocator; // allocator function
+ int onstack; // allocate on stack
+
+ NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
+ Type *newtype, Expressions *arguments);
+ static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
+ Expression *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class NewAnonClassExp : public Expression
+{
+public:
+ /* thisexp.new(newargs) class baseclasses { } (arguments)
+ */
+ Expression *thisexp; // if !NULL, 'this' for class being allocated
+ Expressions *newargs; // Array of Expression's to call new operator
+ ClassDeclaration *cd; // class being instantiated
+ Expressions *arguments; // Array of Expression's to call class constructor
+
+ NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs,
+ ClassDeclaration *cd, Expressions *arguments);
+ Expression *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SymbolExp : public Expression
+{
+public:
+ Declaration *var;
+ bool hasOverloads;
+ SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Offset from symbol
+
+class SymOffExp : public SymbolExp
+{
+public:
+ dinteger_t offset;
+
+ SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads = true);
+ bool isBool(bool result);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Variable
+
+class VarExp : public SymbolExp
+{
+public:
+ VarExp(Loc loc, Declaration *var, bool hasOverloads = true);
+ static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
+ bool equals(RootObject *o);
+ int checkModifiable(Scope *sc, int flag);
+ bool checkReadModifyWrite();
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Overload Set
+
+class OverExp : public Expression
+{
+public:
+ OverloadSet *vars;
+
+ OverExp(Loc loc, OverloadSet *s);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Function/Delegate literal
+
+class FuncExp : public Expression
+{
+public:
+ FuncLiteralDeclaration *fd;
+ TemplateDeclaration *td;
+ TOK tok;
+
+ FuncExp(Loc loc, Dsymbol *s);
+ bool equals(RootObject *o);
+ void genIdent(Scope *sc);
+ Expression *syntaxCopy();
+ MATCH matchType(Type *to, Scope *sc, FuncExp **pfe, int flag = 0);
+ const char *toChars();
+ bool checkType();
+ bool checkValue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Declaration of a symbol
+
+// D grammar allows declarations only as statements. However in AST representation
+// it can be part of any expression. This is used, for example, during internal
+// syntax re-writes to inject hidden symbols.
+class DeclarationExp : public Expression
+{
+public:
+ Dsymbol *declaration;
+
+ DeclarationExp(Loc loc, Dsymbol *declaration);
+ Expression *syntaxCopy();
+
+ bool hasCode();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeidExp : public Expression
+{
+public:
+ RootObject *obj;
+
+ TypeidExp(Loc loc, RootObject *obj);
+ Expression *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TraitsExp : public Expression
+{
+public:
+ Identifier *ident;
+ Objects *args;
+
+ TraitsExp(Loc loc, Identifier *ident, Objects *args);
+ Expression *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class HaltExp : public Expression
+{
+public:
+ HaltExp(Loc loc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class IsExp : public Expression
+{
+public:
+ /* is(targ id tok tspec)
+ * is(targ id == tok2)
+ */
+ Type *targ;
+ Identifier *id; // can be NULL
+ TOK tok; // ':' or '=='
+ Type *tspec; // can be NULL
+ TOK tok2; // 'struct', 'union', etc.
+ TemplateParameters *parameters;
+
+ IsExp(Loc loc, Type *targ, Identifier *id, TOK tok, Type *tspec,
+ TOK tok2, TemplateParameters *parameters);
+ Expression *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class UnaExp : public Expression
+{
+public:
+ Expression *e1;
+ Type *att1; // Save alias this type to detect recursion
+
+ UnaExp(Loc loc, TOK op, int size, Expression *e1);
+ Expression *syntaxCopy();
+ Expression *incompatibleTypes();
+ Expression *resolveLoc(Loc loc, Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+typedef UnionExp (*fp_t)(Loc loc, Type *, Expression *, Expression *);
+typedef int (*fp2_t)(Loc loc, TOK, Expression *, Expression *);
+
+class BinExp : public Expression
+{
+public:
+ Expression *e1;
+ Expression *e2;
+
+ Type *att1; // Save alias this type to detect recursion
+ Type *att2; // Save alias this type to detect recursion
+
+ BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
+ Expression *syntaxCopy();
+ Expression *incompatibleTypes();
+ Expression *checkOpAssignTypes(Scope *sc);
+ bool checkIntegralBin();
+ bool checkArithmeticBin();
+
+ Expression *reorderSettingAAElem(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class BinAssignExp : public BinExp
+{
+public:
+ BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
+
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *ex);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class CompileExp : public UnaExp
+{
+public:
+ CompileExp(Loc loc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ImportExp : public UnaExp
+{
+public:
+ ImportExp(Loc loc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AssertExp : public UnaExp
+{
+public:
+ Expression *msg;
+
+ AssertExp(Loc loc, Expression *e, Expression *msg = NULL);
+ Expression *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotIdExp : public UnaExp
+{
+public:
+ Identifier *ident;
+ bool noderef; // true if the result of the expression will never be dereferenced
+ bool wantsym; // do not replace Symbol with its initializer during semantic()
+
+ DotIdExp(Loc loc, Expression *e, Identifier *ident);
+ static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotTemplateExp : public UnaExp
+{
+public:
+ TemplateDeclaration *td;
+
+ DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotVarExp : public UnaExp
+{
+public:
+ Declaration *var;
+ bool hasOverloads;
+
+ DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads = true);
+ int checkModifiable(Scope *sc, int flag);
+ bool checkReadModifyWrite();
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotTemplateInstanceExp : public UnaExp
+{
+public:
+ TemplateInstance *ti;
+
+ DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs);
+ DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti);
+ Expression *syntaxCopy();
+ bool findTempDecl(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DelegateExp : public UnaExp
+{
+public:
+ FuncDeclaration *func;
+ bool hasOverloads;
+
+ DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, bool hasOverloads = true);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DotTypeExp : public UnaExp
+{
+public:
+ Dsymbol *sym; // symbol that represents a type
+
+ DotTypeExp(Loc loc, Expression *e, Dsymbol *sym);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CallExp : public UnaExp
+{
+public:
+ Expressions *arguments; // function arguments
+ FuncDeclaration *f; // symbol to call
+ bool directcall; // true if a virtual call is devirtualized
+ CallExp(Loc loc, Expression *e, Expressions *exps);
+ CallExp(Loc loc, Expression *e);
+ CallExp(Loc loc, Expression *e, Expression *earg1);
+ CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2);
+
+ static CallExp *create(Loc loc, Expression *e, Expressions *exps);
+ static CallExp *create(Loc loc, Expression *e);
+ static CallExp *create(Loc loc, Expression *e, Expression *earg1);
+
+ Expression *syntaxCopy();
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *addDtorHook(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AddrExp : public UnaExp
+{
+public:
+ AddrExp(Loc loc, Expression *e);
+ AddrExp(Loc loc, Expression *e, Type *t);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PtrExp : public UnaExp
+{
+public:
+ PtrExp(Loc loc, Expression *e);
+ PtrExp(Loc loc, Expression *e, Type *t);
+ int checkModifiable(Scope *sc, int flag);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class NegExp : public UnaExp
+{
+public:
+ NegExp(Loc loc, Expression *e);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class UAddExp : public UnaExp
+{
+public:
+ UAddExp(Loc loc, Expression *e);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ComExp : public UnaExp
+{
+public:
+ ComExp(Loc loc, Expression *e);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class NotExp : public UnaExp
+{
+public:
+ NotExp(Loc loc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DeleteExp : public UnaExp
+{
+public:
+ bool isRAII;
+ DeleteExp(Loc loc, Expression *e, bool isRAII);
+ Expression *toBoolean(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CastExp : public UnaExp
+{
+public:
+ // Possible to cast to one type while painting to another type
+ Type *to; // type to cast to
+ unsigned char mod; // MODxxxxx
+
+ CastExp(Loc loc, Expression *e, Type *t);
+ CastExp(Loc loc, Expression *e, unsigned char mod);
+ Expression *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class VectorExp : public UnaExp
+{
+public:
+ TypeVector *to; // the target vector type before semantic()
+ unsigned dim; // number of elements in the vector
+
+ VectorExp(Loc loc, Expression *e, Type *t);
+ static VectorExp *create(Loc loc, Expression *e, Type *t);
+ Expression *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SliceExp : public UnaExp
+{
+public:
+ Expression *upr; // NULL if implicit 0
+ Expression *lwr; // NULL if implicit [length - 1]
+ VarDeclaration *lengthVar;
+ bool upperIsInBounds; // true if upr <= e1.length
+ bool lowerIsLessThanUpper; // true if lwr <= upr
+ bool arrayop; // an array operation, rather than a slice
+
+ SliceExp(Loc loc, Expression *e1, IntervalExp *ie);
+ SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr);
+ Expression *syntaxCopy();
+ int checkModifiable(Scope *sc, int flag);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ bool isBool(bool result);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ArrayLengthExp : public UnaExp
+{
+public:
+ ArrayLengthExp(Loc loc, Expression *e1);
+
+ static Expression *rewriteOpAssign(BinExp *exp);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class IntervalExp : public Expression
+{
+public:
+ Expression *lwr;
+ Expression *upr;
+
+ IntervalExp(Loc loc, Expression *lwr, Expression *upr);
+ Expression *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DelegatePtrExp : public UnaExp
+{
+public:
+ DelegatePtrExp(Loc loc, Expression *e1);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DelegateFuncptrExp : public UnaExp
+{
+public:
+ DelegateFuncptrExp(Loc loc, Expression *e1);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// e1[a0,a1,a2,a3,...]
+
+class ArrayExp : public UnaExp
+{
+public:
+ Expressions *arguments; // Array of Expression's
+ size_t currentDimension; // for opDollar
+ VarDeclaration *lengthVar;
+
+ ArrayExp(Loc loc, Expression *e1, Expression *index = NULL);
+ ArrayExp(Loc loc, Expression *e1, Expressions *args);
+ Expression *syntaxCopy();
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class DotExp : public BinExp
+{
+public:
+ DotExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CommaExp : public BinExp
+{
+public:
+ bool isGenerated;
+ bool allowCommaExp;
+ CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated = true);
+ int checkModifiable(Scope *sc, int flag);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ bool isBool(bool result);
+ Expression *toBoolean(Scope *sc);
+ Expression *addDtorHook(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class IndexExp : public BinExp
+{
+public:
+ VarDeclaration *lengthVar;
+ bool modifiable;
+ bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
+
+ IndexExp(Loc loc, Expression *e1, Expression *e2);
+ Expression *syntaxCopy();
+ int checkModifiable(Scope *sc, int flag);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+
+ Expression *markSettingAAElem();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* For both i++ and i--
+ */
+class PostExp : public BinExp
+{
+public:
+ PostExp(TOK op, Loc loc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* For both ++i and --i
+ */
+class PreExp : public UnaExp
+{
+public:
+ PreExp(TOK op, Loc loc, Expression *e);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+enum MemorySet
+{
+ blockAssign = 1, // setting the contents of an array
+ referenceInit = 2 // setting the reference of STCref variable
+};
+
+class AssignExp : public BinExp
+{
+public:
+ int memset; // combination of MemorySet flags
+
+ AssignExp(Loc loc, Expression *e1, Expression *e2);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *ex);
+ Expression *toBoolean(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ConstructExp : public AssignExp
+{
+public:
+ ConstructExp(Loc loc, Expression *e1, Expression *e2);
+ ConstructExp(Loc loc, VarDeclaration *v, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class BlitExp : public AssignExp
+{
+public:
+ BlitExp(Loc loc, Expression *e1, Expression *e2);
+ BlitExp(Loc loc, VarDeclaration *v, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AddAssignExp : public BinAssignExp
+{
+public:
+ AddAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class MinAssignExp : public BinAssignExp
+{
+public:
+ MinAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class MulAssignExp : public BinAssignExp
+{
+public:
+ MulAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DivAssignExp : public BinAssignExp
+{
+public:
+ DivAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ModAssignExp : public BinAssignExp
+{
+public:
+ ModAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AndAssignExp : public BinAssignExp
+{
+public:
+ AndAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class OrAssignExp : public BinAssignExp
+{
+public:
+ OrAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class XorAssignExp : public BinAssignExp
+{
+public:
+ XorAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PowAssignExp : public BinAssignExp
+{
+public:
+ PowAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShlAssignExp : public BinAssignExp
+{
+public:
+ ShlAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShrAssignExp : public BinAssignExp
+{
+public:
+ ShrAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class UshrAssignExp : public BinAssignExp
+{
+public:
+ UshrAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CatAssignExp : public BinAssignExp
+{
+public:
+ CatAssignExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AddExp : public BinExp
+{
+public:
+ AddExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class MinExp : public BinExp
+{
+public:
+ MinExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CatExp : public BinExp
+{
+public:
+ CatExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class MulExp : public BinExp
+{
+public:
+ MulExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DivExp : public BinExp
+{
+public:
+ DivExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ModExp : public BinExp
+{
+public:
+ ModExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PowExp : public BinExp
+{
+public:
+ PowExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShlExp : public BinExp
+{
+public:
+ ShlExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ShrExp : public BinExp
+{
+public:
+ ShrExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class UshrExp : public BinExp
+{
+public:
+ UshrExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AndExp : public BinExp
+{
+public:
+ AndExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class OrExp : public BinExp
+{
+public:
+ OrExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class XorExp : public BinExp
+{
+public:
+ XorExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class OrOrExp : public BinExp
+{
+public:
+ OrOrExp(Loc loc, Expression *e1, Expression *e2);
+ Expression *toBoolean(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class AndAndExp : public BinExp
+{
+public:
+ AndAndExp(Loc loc, Expression *e1, Expression *e2);
+ Expression *toBoolean(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CmpExp : public BinExp
+{
+public:
+ CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class InExp : public BinExp
+{
+public:
+ InExp(Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class RemoveExp : public BinExp
+{
+public:
+ RemoveExp(Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// == and !=
+
+class EqualExp : public BinExp
+{
+public:
+ EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// is and !is
+
+class IdentityExp : public BinExp
+{
+public:
+ IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class CondExp : public BinExp
+{
+public:
+ Expression *econd;
+
+ CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2);
+ Expression *syntaxCopy();
+ int checkModifiable(Scope *sc, int flag);
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
+ Expression *modifiableLvalue(Scope *sc, Expression *e);
+ Expression *toBoolean(Scope *sc);
+ void hookDtors(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+class DefaultInitExp : public Expression
+{
+public:
+ TOK subop; // which of the derived classes this is
+
+ DefaultInitExp(Loc loc, TOK subop, int size);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class FileInitExp : public DefaultInitExp
+{
+public:
+ FileInitExp(Loc loc, TOK tok);
+ Expression *resolveLoc(Loc loc, Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class LineInitExp : public DefaultInitExp
+{
+public:
+ LineInitExp(Loc loc);
+ Expression *resolveLoc(Loc loc, Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ModuleInitExp : public DefaultInitExp
+{
+public:
+ ModuleInitExp(Loc loc);
+ Expression *resolveLoc(Loc loc, Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class FuncInitExp : public DefaultInitExp
+{
+public:
+ FuncInitExp(Loc loc);
+ Expression *resolveLoc(Loc loc, Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PrettyFuncInitExp : public DefaultInitExp
+{
+public:
+ PrettyFuncInitExp(Loc loc);
+ Expression *resolveLoc(Loc loc, Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/****************************************************************/
+
+/* A type meant as a union of all the Expression types,
+ * to serve essentially as a Variant that will sit on the stack
+ * during CTFE to reduce memory consumption.
+ */
+struct UnionExp
+{
+ UnionExp() { } // yes, default constructor does nothing
+
+ UnionExp(Expression *e)
+ {
+ memcpy(this, (void *)e, e->size);
+ }
+
+ /* Extract pointer to Expression
+ */
+ Expression *exp() { return (Expression *)&u; }
+
+ /* Convert to an allocated Expression
+ */
+ Expression *copy();
+
+private:
+ union
+ {
+ char exp [sizeof(Expression)];
+ char integerexp[sizeof(IntegerExp)];
+ char errorexp [sizeof(ErrorExp)];
+ char realexp [sizeof(RealExp)];
+ char complexexp[sizeof(ComplexExp)];
+ char symoffexp [sizeof(SymOffExp)];
+ char stringexp [sizeof(StringExp)];
+ char arrayliteralexp [sizeof(ArrayLiteralExp)];
+ char assocarrayliteralexp [sizeof(AssocArrayLiteralExp)];
+ char structliteralexp [sizeof(StructLiteralExp)];
+ char nullexp [sizeof(NullExp)];
+ char dotvarexp [sizeof(DotVarExp)];
+ char addrexp [sizeof(AddrExp)];
+ char indexexp [sizeof(IndexExp)];
+ char sliceexp [sizeof(SliceExp)];
+
+ // Ensure that the union is suitably aligned.
+ real_t for_alignment_only;
+ } u;
+};
+
+/****************************************************************/
+
+/* Special values used by the interpreter
+ */
+
+Expression *expType(Type *type, Expression *e);
+
+UnionExp Neg(Type *type, Expression *e1);
+UnionExp Com(Type *type, Expression *e1);
+UnionExp Not(Type *type, Expression *e1);
+UnionExp Bool(Type *type, Expression *e1);
+UnionExp Cast(Loc loc, Type *type, Type *to, Expression *e1);
+UnionExp ArrayLength(Type *type, Expression *e1);
+UnionExp Ptr(Type *type, Expression *e1);
+
+UnionExp Add(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Min(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Mul(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Mod(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Pow(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Shl(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Shr(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Ushr(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp And(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Or(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Xor(Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Index(Type *type, Expression *e1, Expression *e2);
+UnionExp Cat(Type *type, Expression *e1, Expression *e2);
+
+UnionExp Equal(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Cmp(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
+UnionExp Identity(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
+
+UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr);
+
+// Const-folding functions used by CTFE
+
+void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, size_t firstIndex);
+void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex);
+void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex);
+
+int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len);
+int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len);
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
new file mode 100644
index 0000000..247d143
--- /dev/null
+++ b/gcc/d/dmd/expressionsem.c
@@ -0,0 +1,8740 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <assert.h>
+
+#include "root/rmem.h"
+#include "root/root.h"
+
+#include "mars.h"
+#include "mangle.h"
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "utf.h"
+#include "enum.h"
+#include "scope.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "import.h"
+#include "id.h"
+#include "dsymbol.h"
+#include "module.h"
+#include "attrib.h"
+#include "hdrgen.h"
+#include "parse.h"
+#include "nspace.h"
+#include "ctfe.h"
+#include "target.h"
+
+bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2);
+bool isArrayOpValid(Expression *e);
+Expression *expandVar(int result, VarDeclaration *v);
+TypeTuple *toArgTypes(Type *t);
+bool checkAssignEscape(Scope *sc, Expression *e, bool gag);
+bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
+bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
+bool checkNestedRef(Dsymbol *s, Dsymbol *p);
+bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0);
+bool symbolIsVisible(Module *mod, Dsymbol *s);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
+Type *getTypeInfoType(Type *t, Scope *sc);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+MATCH MODmethodConv(MOD modfrom, MOD modto);
+void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
+
+void unSpeculative(Scope *sc, RootObject *o);
+bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt);
+bool checkDefCtor(Loc loc, Type *t);
+bool isDotOpDispatch(Expression *e);
+bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix);
+Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, Expression *e1, Declaration *var, int flag = 0);
+bool isNeedThisScope(Scope *sc, Declaration *d);
+Expression *resolveUFCS(Scope *sc, CallExp *ce);
+bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
+bool isSafeCast(Expression *e, Type *tfrom, Type *tto);
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+Expression *callCpCtor(Scope *sc, Expression *e);
+
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL);
+Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *unaSemantic(UnaExp *e, Scope *sc);
+Expression *binSemantic(BinExp *e, Scope *sc);
+Expression *binSemanticProp(BinExp *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
+
+/****************************************
+ * Preprocess arguments to function.
+ * Output:
+ * exps[] tuples expanded, properties resolved, rewritten in place
+ * Returns:
+ * true a semantic error occurred
+ */
+
+static bool preFunctionParameters(Scope *sc, Expressions *exps)
+{
+ bool err = false;
+ if (exps)
+ {
+ expandTuples(exps);
+
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *arg = (*exps)[i];
+
+ arg = resolveProperties(sc, arg);
+ if (arg->op == TOKtype)
+ {
+ arg->error("cannot pass type %s as a function argument", arg->toChars());
+ arg = new ErrorExp();
+ err = true;
+ }
+ else if (checkNonAssignmentArrayOp(arg))
+ {
+ arg = new ErrorExp();
+ err = true;
+ }
+ (*exps)[i] = arg;
+ }
+ }
+ return err;
+}
+
+class ExpressionSemanticVisitor : public Visitor
+{
+public:
+ Expression *result;
+ Scope *sc;
+
+ ExpressionSemanticVisitor(Scope *sc)
+ {
+ this->result = NULL;
+ this->sc = sc;
+ }
+
+private:
+ void setError()
+ {
+ result = new ErrorExp();
+ }
+
+ /*********************
+ * Mark the operand as will never be dereferenced,
+ * which is useful info for @safe checks.
+ * Do before semantic() on operands rewrites them.
+ */
+ static void setNoderefOperand(UnaExp *e)
+ {
+ if (e->e1->op == TOKdotid)
+ ((DotIdExp *)e->e1)->noderef = true;
+ }
+
+ /*********************
+ * Mark the operands as will never be dereferenced,
+ * which is useful info for @safe checks.
+ * Do before semantic() on operands rewrites them.
+ */
+ static void setNoderefOperands(BinExp *e)
+ {
+ if (e->e1->op == TOKdotid)
+ ((DotIdExp *)e->e1)->noderef = true;
+ if (e->e2->op == TOKdotid)
+ ((DotIdExp *)e->e2)->noderef = true;
+ }
+
+ static FuncDeclaration *resolveOverloadSet(Loc loc, Scope *sc,
+ OverloadSet *os, Objects* tiargs, Type *tthis, Expressions *arguments)
+ {
+ FuncDeclaration *f = NULL;
+ for (size_t i = 0; i < os->a.dim; i++)
+ {
+ Dsymbol *s = os->a[i];
+ if (tiargs && s->isFuncDeclaration())
+ continue;
+ if (FuncDeclaration *f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, 1))
+ {
+ if (f2->errors)
+ return NULL;
+ if (f)
+ {
+ /* Error if match in more than one overload set,
+ * even if one is a 'better' match than the other.
+ */
+ ScopeDsymbol::multiplyDefined(loc, f, f2);
+ }
+ else
+ f = f2;
+ }
+ }
+ if (!f)
+ ::error(loc, "no overload matches for %s", os->toChars());
+ else if (f->errors)
+ f = NULL;
+ return f;
+ }
+
+ /****************************************************
+ * Determine if `exp`, which takes the address of `v`, can do so safely.
+ * Params:
+ * sc = context
+ * exp = expression that takes the address of `v`
+ * v = the variable getting its address taken
+ * Returns:
+ * `true` if ok, `false` for error
+ */
+ static bool checkAddressVar(Scope *sc, UnaExp *e, VarDeclaration *v)
+ {
+ if (v)
+ {
+ if (!v->canTakeAddressOf())
+ {
+ e->error("cannot take address of %s", e->e1->toChars());
+ return false;
+ }
+ if (sc->func && !sc->intypeof && !v->isDataseg())
+ {
+ const char *p = v->isParameter() ? "parameter" : "local";
+ if (global.params.vsafe)
+ {
+ // Taking the address of v means it cannot be set to 'scope' later
+ v->storage_class &= ~STCmaybescope;
+ v->doNotInferScope = true;
+ if (v->storage_class & STCscope && sc->func->setUnsafe())
+ {
+ e->error("cannot take address of scope %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
+ return false;
+ }
+ }
+ else if (sc->func->setUnsafe())
+ {
+ e->error("cannot take address of %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ static bool checkVectorElem(Expression *e, Expression *elem)
+ {
+ if (elem->isConst() == 1)
+ return false;
+
+ e->error("constant expression expected, not %s", elem->toChars());
+ return true;
+ }
+
+public:
+ void visit(Expression *e)
+ {
+ if (e->type)
+ e->type = e->type->semantic(e->loc, sc);
+ else
+ e->type = Type::tvoid;
+ result = e;
+ }
+
+ void visit(IntegerExp *e)
+ {
+ assert(e->type);
+ if (e->type->ty == Terror)
+ return setError();
+ assert(e->type->deco);
+ e->normalize();
+ result = e;
+ }
+
+ void visit(RealExp *e)
+ {
+ if (!e->type)
+ e->type = Type::tfloat64;
+ else
+ e->type = e->type->semantic(e->loc, sc);
+ result = e;
+ }
+
+ void visit(ComplexExp *e)
+ {
+ if (!e->type)
+ e->type = Type::tcomplex80;
+ else
+ e->type = e->type->semantic(e->loc, sc);
+ result = e;
+ }
+
+ void visit(IdentifierExp *exp)
+ {
+ if (exp->type) // This is used as the dummy expression
+ {
+ result = exp;
+ return;
+ }
+
+ Dsymbol *scopesym;
+ Dsymbol *s = sc->search(exp->loc, exp->ident, &scopesym);
+ if (s)
+ {
+ if (s->errors)
+ return setError();
+
+ Expression *e;
+
+ /* See if the symbol was a member of an enclosing 'with'
+ */
+ WithScopeSymbol *withsym = scopesym->isWithScopeSymbol();
+ if (withsym && withsym->withstate->wthis)
+ {
+ /* Disallow shadowing
+ */
+ // First find the scope of the with
+ Scope *scwith = sc;
+ while (scwith->scopesym != scopesym)
+ {
+ scwith = scwith->enclosing;
+ assert(scwith);
+ }
+ // Look at enclosing scopes for symbols with the same name,
+ // in the same function
+ for (Scope *scx = scwith; scx && scx->func == scwith->func; scx = scx->enclosing)
+ {
+ Dsymbol *s2;
+ if (scx->scopesym && scx->scopesym->symtab &&
+ (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
+ s != s2)
+ {
+ exp->error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars());
+ return setError();
+ }
+ }
+ s = s->toAlias();
+
+ // Same as wthis.ident
+ // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
+ // The redudancy should be removed.
+ e = new VarExp(exp->loc, withsym->withstate->wthis);
+ e = new DotIdExp(exp->loc, e, exp->ident);
+ e = semantic(e, sc);
+ }
+ else
+ {
+ if (withsym)
+ {
+ Declaration *d = s->isDeclaration();
+ if (d)
+ checkAccess(exp->loc, sc, NULL, d);
+ }
+
+ /* If f is really a function template,
+ * then replace f with the function template declaration.
+ */
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f)
+ {
+ TemplateDeclaration *td = getFuncTemplateDecl(f);
+ if (td)
+ {
+ if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td->overroot; // then get the start
+ e = new TemplateExp(exp->loc, td, f);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ }
+ // Haven't done overload resolution yet, so pass 1
+ e = resolve(exp->loc, sc, s, true);
+ }
+ result = e;
+ return;
+ }
+
+ if (hasThis(sc))
+ {
+ AggregateDeclaration *ad = sc->getStructClassScope();
+ if (ad && ad->aliasthis)
+ {
+ Expression *e;
+ e = new IdentifierExp(exp->loc, Id::This);
+ e = new DotIdExp(exp->loc, e, ad->aliasthis->ident);
+ e = new DotIdExp(exp->loc, e, exp->ident);
+ e = trySemantic(e, sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ }
+
+ if (exp->ident == Id::ctfe)
+ {
+ if (sc->flags & SCOPEctfe)
+ {
+ exp->error("variable __ctfe cannot be read at compile time");
+ return setError();
+ }
+
+ // Create the magic __ctfe bool variable
+ VarDeclaration *vd = new VarDeclaration(exp->loc, Type::tbool, Id::ctfe, NULL);
+ vd->storage_class |= STCtemp;
+ Expression *e = new VarExp(exp->loc, vd);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+
+ // If we've reached this point and are inside a with() scope then we may
+ // try one last attempt by checking whether the 'wthis' object supports
+ // dynamic dispatching via opDispatch.
+ // This is done by rewriting this expression as wthis.ident.
+ for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing)
+ {
+ if (!sc2->scopesym)
+ continue;
+
+ if (WithScopeSymbol *ss = sc2->scopesym->isWithScopeSymbol())
+ {
+ if (ss->withstate->wthis)
+ {
+ Expression *e;
+ e = new VarExp(exp->loc, ss->withstate->wthis);
+ e = new DotIdExp(exp->loc, e, exp->ident);
+ e = trySemantic(e, sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Look for what user might have meant
+ */
+ if (const char *n = importHint(exp->ident->toChars()))
+ exp->error("`%s` is not defined, perhaps `import %s;` is needed?", exp->ident->toChars(), n);
+ else if (Dsymbol *s2 = sc->search_correct(exp->ident))
+ exp->error("undefined identifier `%s`, did you mean %s `%s`?", exp->ident->toChars(), s2->kind(), s2->toChars());
+ else if (const char *p = Scope::search_correct_C(exp->ident))
+ exp->error("undefined identifier `%s`, did you mean `%s`?", exp->ident->toChars(), p);
+ else
+ exp->error("undefined identifier `%s`", exp->ident->toChars());
+ return setError();
+ }
+
+ void visit(DsymbolExp *e)
+ {
+ result = resolve(e->loc, sc, e->s, e->hasOverloads);
+ }
+
+ void visit(ThisExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
+
+ /* Special case for typeof(this) and typeof(super) since both
+ * should work even if they are not inside a non-static member function
+ */
+ if (!fd && sc->intypeof == 1)
+ {
+ // Find enclosing struct or class
+ for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent)
+ {
+ if (!s)
+ {
+ e->error("%s is not in a class or struct scope", e->toChars());
+ goto Lerr;
+ }
+ ClassDeclaration *cd = s->isClassDeclaration();
+ if (cd)
+ {
+ e->type = cd->type;
+ result = e;
+ return;
+ }
+ StructDeclaration *sd = s->isStructDeclaration();
+ if (sd)
+ {
+ e->type = sd->type;
+ result = e;
+ return;
+ }
+ }
+ }
+ if (!fd)
+ goto Lerr;
+
+ assert(fd->vthis);
+ e->var = fd->vthis;
+ assert(e->var->parent);
+ e->type = e->var->type;
+ if (e->var->checkNestedReference(sc, e->loc))
+ return setError();
+ if (!sc->intypeof)
+ sc->callSuper |= CSXthis;
+ result = e;
+ return;
+
+ Lerr:
+ e->error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars());
+ return setError();
+ }
+
+ void visit(SuperExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ FuncDeclaration *fd = hasThis(sc);
+ ClassDeclaration *cd;
+ Dsymbol *s;
+
+ /* Special case for typeof(this) and typeof(super) since both
+ * should work even if they are not inside a non-static member function
+ */
+ if (!fd && sc->intypeof == 1)
+ {
+ // Find enclosing class
+ for (s = sc->getStructClassScope(); 1; s = s->parent)
+ {
+ if (!s)
+ {
+ e->error("%s is not in a class scope", e->toChars());
+ goto Lerr;
+ }
+ cd = s->isClassDeclaration();
+ if (cd)
+ {
+ cd = cd->baseClass;
+ if (!cd)
+ {
+ e->error("class %s has no 'super'", s->toChars());
+ goto Lerr;
+ }
+ e->type = cd->type;
+ result = e;
+ return;
+ }
+ }
+ }
+ if (!fd)
+ goto Lerr;
+
+ e->var = fd->vthis;
+ assert(e->var && e->var->parent);
+
+ s = fd->toParent();
+ while (s && s->isTemplateInstance())
+ s = s->toParent();
+ if (s->isTemplateDeclaration()) // allow inside template constraint
+ s = s->toParent();
+ assert(s);
+ cd = s->isClassDeclaration();
+ //printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars());
+ if (!cd)
+ goto Lerr;
+ if (!cd->baseClass)
+ {
+ e->error("no base class for %s", cd->toChars());
+ e->type = e->var->type;
+ }
+ else
+ {
+ e->type = cd->baseClass->type;
+ e->type = e->type->castMod(e->var->type->mod);
+ }
+
+ if (e->var->checkNestedReference(sc, e->loc))
+ return setError();
+
+ if (!sc->intypeof)
+ sc->callSuper |= CSXsuper;
+ result = e;
+ return;
+
+ Lerr:
+ e->error("'super' is only allowed in non-static class member functions");
+ return setError();
+ }
+
+ void visit(NullExp *e)
+ {
+ // NULL is the same as (void *)0
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+ e->type = Type::tnull;
+ result = e;
+ }
+
+ void visit(StringExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ OutBuffer buffer;
+ size_t newlen = 0;
+ const char *p;
+ size_t u;
+ unsigned c;
+
+ switch (e->postfix)
+ {
+ case 'd':
+ for (u = 0; u < e->len;)
+ {
+ p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
+ if (p)
+ {
+ e->error("%s", p);
+ return setError();
+ }
+ else
+ {
+ buffer.write4(c);
+ newlen++;
+ }
+ }
+ buffer.write4(0);
+ e->string = buffer.extractData();
+ e->len = newlen;
+ e->sz = 4;
+ e->type = new TypeDArray(Type::tdchar->immutableOf());
+ e->committed = 1;
+ break;
+
+ case 'w':
+ for (u = 0; u < e->len;)
+ {
+ p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
+ if (p)
+ {
+ e->error("%s", p);
+ return setError();
+ }
+ else
+ {
+ buffer.writeUTF16(c);
+ newlen++;
+ if (c >= 0x10000)
+ newlen++;
+ }
+ }
+ buffer.writeUTF16(0);
+ e->string = buffer.extractData();
+ e->len = newlen;
+ e->sz = 2;
+ e->type = new TypeDArray(Type::twchar->immutableOf());
+ e->committed = 1;
+ break;
+
+ case 'c':
+ e->committed = 1;
+ /* fall through */
+
+ default:
+ e->type = new TypeDArray(Type::tchar->immutableOf());
+ break;
+ }
+ e->type = e->type->semantic(e->loc, sc);
+ //e->type = e->type->immutableOf();
+ //printf("type = %s\n", e->type->toChars());
+
+ result = e;
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ /* Perhaps an empty array literal [ ] should be rewritten as null?
+ */
+
+ if (e->basis)
+ e->basis = semantic(e->basis, sc);
+ if (arrayExpressionSemantic(e->elements, sc) || (e->basis && e->basis->op == TOKerror))
+ return setError();
+ expandTuples(e->elements);
+
+ Type *t0;
+ if (e->basis)
+ e->elements->push(e->basis);
+ bool err = arrayExpressionToCommonType(sc, e->elements, &t0);
+ if (e->basis)
+ e->elements->pop();
+ if (err)
+ return setError();
+
+ e->type = t0->arrayOf();
+ e->type = e->type->semantic(e->loc, sc);
+
+ /* Disallow array literals of type void being used.
+ */
+ if (e->elements->dim > 0 && t0->ty == Tvoid)
+ {
+ e->error("%s of type %s has no value", e->toChars(), e->type->toChars());
+ return setError();
+ }
+
+ semanticTypeInfo(sc, e->type);
+
+ result = e;
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ // Run semantic() on each element
+ bool err_keys = arrayExpressionSemantic(e->keys, sc);
+ bool err_vals = arrayExpressionSemantic(e->values, sc);
+ if (err_keys || err_vals)
+ return setError();
+ expandTuples(e->keys);
+ expandTuples(e->values);
+ if (e->keys->dim != e->values->dim)
+ {
+ e->error("number of keys is %u, must match number of values %u", e->keys->dim, e->values->dim);
+ return setError();
+ }
+
+ Type *tkey = NULL;
+ Type *tvalue = NULL;
+ err_keys = arrayExpressionToCommonType(sc, e->keys, &tkey);
+ err_vals = arrayExpressionToCommonType(sc, e->values, &tvalue);
+ if (err_keys || err_vals)
+ return setError();
+
+ if (tkey == Type::terror || tvalue == Type::terror)
+ return setError();
+
+ e->type = new TypeAArray(tvalue, tkey);
+ e->type = e->type->semantic(e->loc, sc);
+
+ semanticTypeInfo(sc, e->type);
+
+ result = e;
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ e->sd->size(e->loc);
+ if (e->sd->sizeok != SIZEOKdone)
+ return setError();
+
+ if (arrayExpressionSemantic(e->elements, sc)) // run semantic() on each element
+ return setError();
+ expandTuples(e->elements);
+
+ /* Fit elements[] to the corresponding type of field[].
+ */
+ if (!e->sd->fit(e->loc, sc, e->elements, e->stype))
+ return setError();
+
+ /* Fill out remainder of elements[] with default initializers for fields[]
+ */
+ if (!e->sd->fill(e->loc, e->elements, false))
+ {
+ /* An error in the initializer needs to be recorded as an error
+ * in the enclosing function or template, since the initializer
+ * will be part of the stuct declaration.
+ */
+ global.increaseErrorCount();
+ return setError();
+ }
+
+ if (checkFrameAccess(e->loc, sc, e->sd, e->elements->dim))
+ return setError();
+
+ e->type = e->stype ? e->stype : e->sd->type;
+ result = e;
+ }
+
+ void visit(TypeExp *exp)
+ {
+ if (exp->type->ty == Terror)
+ return setError();
+
+ //printf("TypeExp::semantic(%s)\n", exp->type->toChars());
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+
+ exp->type->resolve(exp->loc, sc, &e, &t, &s, true);
+ if (e)
+ {
+ //printf("e = %s %s\n", Token::toChars(e->op), e->toChars());
+ e = semantic(e, sc);
+ }
+ else if (t)
+ {
+ //printf("t = %d %s\n", t->ty, t->toChars());
+ exp->type = t->semantic(exp->loc, sc);
+ e = exp;
+ }
+ else if (s)
+ {
+ //printf("s = %s %s\n", s->kind(), s->toChars());
+ e = resolve(exp->loc, sc, s, true);
+ }
+ else
+ assert(0);
+
+ if (global.params.vcomplex)
+ exp->type->checkComplexTransition(exp->loc);
+
+ result = e;
+ }
+
+ void visit(ScopeExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ ScopeDsymbol *sds2 = exp->sds;
+ TemplateInstance *ti = sds2->isTemplateInstance();
+ while (ti)
+ {
+ WithScopeSymbol *withsym;
+ if (!ti->findTempDecl(sc, &withsym) ||
+ !ti->semanticTiargs(sc))
+ return setError();
+ if (withsym && withsym->withstate->wthis)
+ {
+ Expression *e = new VarExp(exp->loc, withsym->withstate->wthis);
+ e = new DotTemplateInstanceExp(exp->loc, e, ti);
+ result = semantic(e, sc);
+ return;
+ }
+ if (ti->needsTypeInference(sc))
+ {
+ if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
+ {
+ Dsymbol *p = td->toParent2();
+ FuncDeclaration *fdthis = hasThis(sc);
+ AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL;
+ if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad &&
+ (td->_scope->stc & STCstatic) == 0)
+ {
+ Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
+ result = semantic(e, sc);
+ return;
+ }
+ }
+ else if (OverloadSet *os = ti->tempdecl->isOverloadSet())
+ {
+ FuncDeclaration *fdthis = hasThis(sc);
+ AggregateDeclaration *ad = os->parent->isAggregateDeclaration();
+ if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad)
+ {
+ Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
+ result = semantic(e, sc);
+ return;
+ }
+ }
+ // ti is an instance which requires IFTI.
+ exp->sds = ti;
+ exp->type = Type::tvoid;
+ result = exp;
+ return;
+ }
+ ti->semantic(sc);
+ if (!ti->inst || ti->errors)
+ return setError();
+
+ Dsymbol *s = ti->toAlias();
+ if (s == ti)
+ {
+ exp->sds = ti;
+ exp->type = Type::tvoid;
+ result = exp;
+ return;
+ }
+ sds2 = s->isScopeDsymbol();
+ if (sds2)
+ {
+ ti = sds2->isTemplateInstance();
+ //printf("+ sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
+ continue;
+ }
+
+ if (VarDeclaration *v = s->isVarDeclaration())
+ {
+ if (!v->type)
+ {
+ exp->error("forward reference of %s %s", v->kind(), v->toChars());
+ return setError();
+ }
+ if ((v->storage_class & STCmanifest) && v->_init)
+ {
+ /* When an instance that will be converted to a constant exists,
+ * the instance representation "foo!tiargs" is treated like a
+ * variable name, and its recursive appearance check (note that
+ * it's equivalent with a recursive instantiation of foo) is done
+ * separately from the circular initialization check for the
+ * eponymous enum variable declaration.
+ *
+ * template foo(T) {
+ * enum bool foo = foo; // recursive definition check (v.inuse)
+ * }
+ * template bar(T) {
+ * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
+ * }
+ */
+ if (ti->inuse)
+ {
+ exp->error("recursive expansion of %s '%s'", ti->kind(), ti->toPrettyChars());
+ return setError();
+ }
+
+ Expression *e = v->expandInitializer(exp->loc);
+ ti->inuse++;
+ e = semantic(e, sc);
+ ti->inuse--;
+ result = e;
+ return;
+ }
+ }
+
+ //printf("s = %s, '%s'\n", s->kind(), s->toChars());
+ Expression *e = resolve(exp->loc, sc, s, true);
+ //printf("-1ScopeExp::semantic()\n");
+ result = e;
+ return;
+ }
+
+ //printf("sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
+ //printf("\tparent = '%s'\n", sds2->parent->toChars());
+ sds2->semantic(sc);
+
+ if (Type *t = sds2->getType()) // (Aggregate|Enum)Declaration
+ {
+ Expression *ex = new TypeExp(exp->loc, t);
+ result = semantic(ex, sc);
+ return;
+ }
+
+ if (TemplateDeclaration *td = sds2->isTemplateDeclaration())
+ {
+ result = semantic(new TemplateExp(exp->loc, td), sc);
+ return;
+ }
+
+ exp->sds = sds2;
+ exp->type = Type::tvoid;
+ //printf("-2ScopeExp::semantic() %s\n", exp->toChars());
+ result = exp;
+ }
+
+ void visit(NewExp *exp)
+ {
+ if (exp->type) // if semantic() already run
+ {
+ result = exp;
+ return;
+ }
+
+ // Bugzilla 11581: With the syntax `new T[edim]` or `thisexp.new T[edim]`,
+ // T should be analyzed first and edim should go into arguments iff it's
+ // not a tuple.
+ Expression *edim = NULL;
+ if (!exp->arguments && exp->newtype->ty == Tsarray)
+ {
+ edim = ((TypeSArray *)exp->newtype)->dim;
+ exp->newtype = ((TypeNext *)exp->newtype)->next;
+ }
+
+ ClassDeclaration *cdthis = NULL;
+ if (exp->thisexp)
+ {
+ exp->thisexp = semantic(exp->thisexp, sc);
+ if (exp->thisexp->op == TOKerror)
+ return setError();
+ cdthis = exp->thisexp->type->isClassHandle();
+ if (!cdthis)
+ {
+ exp->error("'this' for nested class must be a class type, not %s", exp->thisexp->type->toChars());
+ return setError();
+ }
+
+ sc = sc->push(cdthis);
+ exp->type = exp->newtype->semantic(exp->loc, sc);
+ sc = sc->pop();
+ }
+ else
+ {
+ exp->type = exp->newtype->semantic(exp->loc, sc);
+ }
+ if (exp->type->ty == Terror)
+ return setError();
+
+ if (edim)
+ {
+ if (exp->type->toBasetype()->ty == Ttuple)
+ {
+ // --> new T[edim]
+ exp->type = new TypeSArray(exp->type, edim);
+ exp->type = exp->type->semantic(exp->loc, sc);
+ if (exp->type->ty == Terror)
+ return setError();
+ }
+ else
+ {
+ // --> new T[](edim)
+ exp->arguments = new Expressions();
+ exp->arguments->push(edim);
+ exp->type = exp->type->arrayOf();
+ }
+ }
+
+ exp->newtype = exp->type; // in case type gets cast to something else
+ Type *tb = exp->type->toBasetype();
+ //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco);
+
+ if (arrayExpressionSemantic(exp->newargs, sc) ||
+ preFunctionParameters(sc, exp->newargs))
+ {
+ return setError();
+ }
+ if (arrayExpressionSemantic(exp->arguments, sc) ||
+ preFunctionParameters(sc, exp->arguments))
+ {
+ return setError();
+ }
+
+ if (exp->thisexp && tb->ty != Tclass)
+ {
+ exp->error("e.new is only for allocating nested classes, not %s", tb->toChars());
+ return setError();
+ }
+
+ size_t nargs = exp->arguments ? exp->arguments->dim : 0;
+ Expression *newprefix = NULL;
+
+ if (tb->ty == Tclass)
+ {
+ ClassDeclaration *cd = ((TypeClass *)tb)->sym;
+ cd->size(exp->loc);
+ if (cd->sizeok != SIZEOKdone)
+ return setError();
+ if (!cd->ctor)
+ cd->ctor = cd->searchCtor();
+ if (cd->noDefaultCtor && !nargs && !cd->defaultCtor)
+ {
+ exp->error("default construction is disabled for type %s", cd->type->toChars());
+ return setError();
+ }
+
+ if (cd->isInterfaceDeclaration())
+ {
+ exp->error("cannot create instance of interface %s", cd->toChars());
+ return setError();
+ }
+ if (cd->isAbstract())
+ {
+ exp->error("cannot create instance of abstract class %s", cd->toChars());
+ for (size_t i = 0; i < cd->vtbl.dim; i++)
+ {
+ FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration();
+ if (fd && fd->isAbstract())
+ errorSupplemental(exp->loc, "function '%s' is not implemented", fd->toFullSignature());
+ }
+ return setError();
+ }
+ // checkDeprecated() is already done in newtype->semantic().
+
+ if (cd->isNested())
+ {
+ /* We need a 'this' pointer for the nested class.
+ * Ensure we have the right one.
+ */
+ Dsymbol *s = cd->toParent2();
+ //printf("cd isNested, parent = %s '%s'\n", s->kind(), s->toPrettyChars());
+ if (ClassDeclaration *cdn = s->isClassDeclaration())
+ {
+ if (!cdthis)
+ {
+ // Supply an implicit 'this' and try again
+ exp->thisexp = new ThisExp(exp->loc);
+ for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
+ {
+ if (!sp)
+ {
+ exp->error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars());
+ return setError();
+ }
+ ClassDeclaration *cdp = sp->isClassDeclaration();
+ if (!cdp)
+ continue;
+ if (cdp == cdn || cdn->isBaseOf(cdp, NULL))
+ break;
+ // Add a '.outer' and try again
+ exp->thisexp = new DotIdExp(exp->loc, exp->thisexp, Id::outer);
+ }
+ exp->thisexp = semantic(exp->thisexp, sc);
+ if (exp->thisexp->op == TOKerror)
+ return setError();
+ cdthis = exp->thisexp->type->isClassHandle();
+ }
+ if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL))
+ {
+ //printf("cdthis = %s\n", cdthis->toChars());
+ exp->error("'this' for nested class must be of type %s, not %s",
+ cdn->toChars(), exp->thisexp->type->toChars());
+ return setError();
+ }
+ if (!MODimplicitConv(exp->thisexp->type->mod, exp->newtype->mod))
+ {
+ exp->error("nested type %s should have the same or weaker constancy as enclosing type %s",
+ exp->newtype->toChars(), exp->thisexp->type->toChars());
+ return setError();
+ }
+ }
+ else if (exp->thisexp)
+ {
+ exp->error("e.new is only for allocating nested classes");
+ return setError();
+ }
+ else if (FuncDeclaration *fdn = s->isFuncDeclaration())
+ {
+ // make sure the parent context fdn of cd is reachable from sc
+ if (checkNestedRef(sc->parent, fdn))
+ {
+ exp->error("outer function context of %s is needed to 'new' nested class %s",
+ fdn->toPrettyChars(), cd->toPrettyChars());
+ return setError();
+ }
+ }
+ else
+ assert(0);
+ }
+ else if (exp->thisexp)
+ {
+ exp->error("e.new is only for allocating nested classes");
+ return setError();
+ }
+
+ if (cd->aggNew)
+ {
+ // Prepend the size argument to newargs[]
+ Expression *e = new IntegerExp(exp->loc, cd->size(exp->loc), Type::tsize_t);
+ if (!exp->newargs)
+ exp->newargs = new Expressions();
+ exp->newargs->shift(e);
+
+ FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->aggNew, NULL, tb, exp->newargs);
+ if (!f || f->errors)
+ return setError();
+ exp->checkDeprecated(sc, f);
+ exp->checkPurity(sc, f);
+ exp->checkSafety(sc, f);
+ exp->checkNogc(sc, f);
+ checkAccess(cd, exp->loc, sc, f);
+
+ TypeFunction *tf = (TypeFunction *)f->type;
+ Type *rettype;
+ if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
+ return setError();
+
+ exp->allocator = f->isNewDeclaration();
+ assert(exp->allocator);
+ }
+ else
+ {
+ if (exp->newargs && exp->newargs->dim)
+ {
+ exp->error("no allocator for %s", cd->toChars());
+ return setError();
+ }
+ }
+
+ if (cd->ctor)
+ {
+ FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->ctor, NULL, tb, exp->arguments, 0);
+ if (!f || f->errors)
+ return setError();
+ exp->checkDeprecated(sc, f);
+ exp->checkPurity(sc, f);
+ exp->checkSafety(sc, f);
+ exp->checkNogc(sc, f);
+ checkAccess(cd, exp->loc, sc, f);
+
+ TypeFunction *tf = (TypeFunction *)f->type;
+ if (!exp->arguments)
+ exp->arguments = new Expressions();
+ if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
+ return setError();
+
+ exp->member = f->isCtorDeclaration();
+ assert(exp->member);
+ }
+ else
+ {
+ if (nargs)
+ {
+ exp->error("no constructor for %s", cd->toChars());
+ return setError();
+ }
+ }
+ }
+ else if (tb->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ sd->size(exp->loc);
+ if (sd->sizeok != SIZEOKdone)
+ return setError();
+ if (!sd->ctor)
+ sd->ctor = sd->searchCtor();
+ if (sd->noDefaultCtor && !nargs)
+ {
+ exp->error("default construction is disabled for type %s", sd->type->toChars());
+ return setError();
+ }
+ // checkDeprecated() is already done in newtype->semantic().
+
+ if (sd->aggNew)
+ {
+ // Prepend the uint size argument to newargs[]
+ Expression *e = new IntegerExp(exp->loc, sd->size(exp->loc), Type::tsize_t);
+ if (!exp->newargs)
+ exp->newargs = new Expressions();
+ exp->newargs->shift(e);
+
+ FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->aggNew, NULL, tb, exp->newargs);
+ if (!f || f->errors)
+ return setError();
+ exp->checkDeprecated(sc, f);
+ exp->checkPurity(sc, f);
+ exp->checkSafety(sc, f);
+ exp->checkNogc(sc, f);
+ checkAccess(sd, exp->loc, sc, f);
+
+ TypeFunction *tf = (TypeFunction *)f->type;
+ Type *rettype;
+ if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
+ return setError();
+
+ exp->allocator = f->isNewDeclaration();
+ assert(exp->allocator);
+ }
+ else
+ {
+ if (exp->newargs && exp->newargs->dim)
+ {
+ exp->error("no allocator for %s", sd->toChars());
+ return setError();
+ }
+ }
+
+ if (sd->ctor && nargs)
+ {
+ FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->ctor, NULL, tb, exp->arguments, 0);
+ if (!f || f->errors)
+ return setError();
+ exp->checkDeprecated(sc, f);
+ exp->checkPurity(sc, f);
+ exp->checkSafety(sc, f);
+ exp->checkNogc(sc, f);
+ checkAccess(sd, exp->loc, sc, f);
+
+ TypeFunction *tf = (TypeFunction *)f->type;
+ if (!exp->arguments)
+ exp->arguments = new Expressions();
+ if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
+ return setError();
+
+ exp->member = f->isCtorDeclaration();
+ assert(exp->member);
+
+ if (checkFrameAccess(exp->loc, sc, sd, sd->fields.dim))
+ return setError();
+ }
+ else
+ {
+ if (!exp->arguments)
+ exp->arguments = new Expressions();
+
+ if (!sd->fit(exp->loc, sc, exp->arguments, tb))
+ return setError();
+ if (!sd->fill(exp->loc, exp->arguments, false))
+ return setError();
+ if (checkFrameAccess(exp->loc, sc, sd, exp->arguments ? exp->arguments->dim : 0))
+ return setError();
+ }
+
+ exp->type = exp->type->pointerTo();
+ }
+ else if (tb->ty == Tarray && nargs)
+ {
+ Type *tn = tb->nextOf()->baseElemOf();
+ Dsymbol *s = tn->toDsymbol(sc);
+ AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
+ if (ad && ad->noDefaultCtor)
+ {
+ exp->error("default construction is disabled for type %s", tb->nextOf()->toChars());
+ return setError();
+ }
+ for (size_t i = 0; i < nargs; i++)
+ {
+ if (tb->ty != Tarray)
+ {
+ exp->error("too many arguments for array");
+ return setError();
+ }
+
+ Expression *arg = (*exp->arguments)[i];
+ arg = resolveProperties(sc, arg);
+ arg = arg->implicitCastTo(sc, Type::tsize_t);
+ arg = arg->optimize(WANTvalue);
+ if (arg->op == TOKint64 && (sinteger_t)arg->toInteger() < 0)
+ {
+ exp->error("negative array index %s", arg->toChars());
+ return setError();
+ }
+ (*exp->arguments)[i] = arg;
+ tb = ((TypeDArray *)tb)->next->toBasetype();
+ }
+ }
+ else if (tb->isscalar())
+ {
+ if (!nargs)
+ {
+ }
+ else if (nargs == 1)
+ {
+ Expression *e = (*exp->arguments)[0];
+ e = e->implicitCastTo(sc, tb);
+ (*exp->arguments)[0] = e;
+ }
+ else
+ {
+ exp->error("more than one argument for construction of %s", exp->type->toChars());
+ return setError();
+ }
+
+ exp->type = exp->type->pointerTo();
+ }
+ else
+ {
+ exp->error("new can only create structs, dynamic arrays or class objects, not %s's", exp->type->toChars());
+ return setError();
+ }
+
+ //printf("NewExp: '%s'\n", toChars());
+ //printf("NewExp:type '%s'\n", exp->type->toChars());
+ semanticTypeInfo(sc, exp->type);
+
+ if (newprefix)
+ {
+ result = Expression::combine(newprefix, exp);
+ return;
+ }
+ result = exp;
+ }
+
+ void visit(NewAnonClassExp *e)
+ {
+ Expression *d = new DeclarationExp(e->loc, e->cd);
+ sc = sc->push(); // just create new scope
+ sc->flags &= ~SCOPEctfe; // temporary stop CTFE
+ d = semantic(d, sc);
+ sc = sc->pop();
+
+ if (!e->cd->errors && sc->intypeof && !sc->parent->inNonRoot())
+ {
+ ScopeDsymbol *sds = sc->tinst ? (ScopeDsymbol *)sc->tinst : sc->_module;
+ sds->members->push(e->cd);
+ }
+
+ Expression *n = new NewExp(e->loc, e->thisexp, e->newargs, e->cd->type, e->arguments);
+
+ Expression *c = new CommaExp(e->loc, d, n);
+ result = semantic(c, sc);
+ }
+
+ void visit(SymOffExp *e)
+ {
+ //var->semantic(sc);
+ if (!e->type)
+ e->type = e->var->type->pointerTo();
+ if (VarDeclaration *v = e->var->isVarDeclaration())
+ {
+ if (v->checkNestedReference(sc, e->loc))
+ return setError();
+ }
+ else if (FuncDeclaration *f = e->var->isFuncDeclaration())
+ {
+ if (f->checkNestedReference(sc, e->loc))
+ return setError();
+ }
+ result = e;
+ }
+
+ void visit(VarExp *e)
+ {
+ if (FuncDeclaration *fd = e->var->isFuncDeclaration())
+ {
+ //printf("L%d fd = %s\n", __LINE__, f->toChars());
+ if (!fd->functionSemantic())
+ return setError();
+ }
+
+ if (!e->type)
+ e->type = e->var->type;
+
+ if (e->type && !e->type->deco)
+ e->type = e->type->semantic(e->loc, sc);
+
+ /* Fix for 1161 doesn't work because it causes protection
+ * problems when instantiating imported templates passing private
+ * variables as alias template parameters.
+ */
+ //checkAccess(e->loc, sc, NULL, e->var);
+
+ if (VarDeclaration *vd = e->var->isVarDeclaration())
+ {
+ if (vd->checkNestedReference(sc, e->loc))
+ return setError();
+ // Bugzilla 12025: If the variable is not actually used in runtime code,
+ // the purity violation error is redundant.
+ //checkPurity(sc, vd);
+ }
+ else if (FuncDeclaration *fd = e->var->isFuncDeclaration())
+ {
+ // TODO: If fd isn't yet resolved its overload, the checkNestedReference
+ // call would cause incorrect validation.
+ // Maybe here should be moved in CallExp, or AddrExp for functions.
+ if (fd->checkNestedReference(sc, e->loc))
+ return setError();
+ }
+ else if (e->var->isOverDeclaration())
+ {
+ e->type = Type::tvoid; // ambiguous type?
+ }
+
+ result = e;
+ }
+
+ void visit(TupleExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (exp->e0)
+ exp->e0 = semantic(exp->e0, sc);
+
+ // Run semantic() on each argument
+ bool err = false;
+ for (size_t i = 0; i < exp->exps->dim; i++)
+ {
+ Expression *e = (*exp->exps)[i];
+ e = semantic(e, sc);
+ if (!e->type)
+ {
+ exp->error("%s has no value", e->toChars());
+ err = true;
+ }
+ else if (e->op == TOKerror)
+ err = true;
+ else
+ (*exp->exps)[i] = e;
+ }
+ if (err)
+ return setError();
+
+ expandTuples(exp->exps);
+ exp->type = new TypeTuple(exp->exps);
+ exp->type = exp->type->semantic(exp->loc, sc);
+ //printf("-TupleExp::semantic(%s)\n", exp->toChars());
+ result = exp;
+ }
+
+ void visit(FuncExp *exp)
+ {
+ Expression *e = exp;
+
+ sc = sc->push(); // just create new scope
+ sc->flags &= ~SCOPEctfe; // temporary stop CTFE
+ sc->protection = Prot(PROTpublic); // Bugzilla 12506
+
+ if (!exp->type || exp->type == Type::tvoid)
+ {
+ /* fd->treq might be incomplete type,
+ * so should not semantic it.
+ * void foo(T)(T delegate(int) dg){}
+ * foo(a=>a); // in IFTI, treq == T delegate(int)
+ */
+ //if (exp->fd->treq)
+ // exp->fd->treq = exp->fd->treq->semantic(exp->loc, sc);
+
+ exp->genIdent(sc);
+
+ // Set target of return type inference
+ if (exp->fd->treq && !exp->fd->type->nextOf())
+ {
+ TypeFunction *tfv = NULL;
+ if (exp->fd->treq->ty == Tdelegate ||
+ (exp->fd->treq->ty == Tpointer && exp->fd->treq->nextOf()->ty == Tfunction))
+ tfv = (TypeFunction *)exp->fd->treq->nextOf();
+ if (tfv)
+ {
+ TypeFunction *tfl = (TypeFunction *)exp->fd->type;
+ tfl->next = tfv->nextOf();
+ }
+ }
+
+ //printf("td = %p, treq = %p\n", exp->td, exp->fd->treq);
+ if (exp->td)
+ {
+ assert(exp->td->parameters && exp->td->parameters->dim);
+ exp->td->semantic(sc);
+ exp->type = Type::tvoid; // temporary type
+
+ if (exp->fd->treq) // defer type determination
+ {
+ FuncExp *fe;
+ if (exp->matchType(exp->fd->treq, sc, &fe) > MATCHnomatch)
+ e = fe;
+ else
+ e = new ErrorExp();
+ }
+ goto Ldone;
+ }
+
+ unsigned olderrors = global.errors;
+ exp->fd->semantic(sc);
+ if (olderrors == global.errors)
+ {
+ exp->fd->semantic2(sc);
+ if (olderrors == global.errors)
+ exp->fd->semantic3(sc);
+ }
+ if (olderrors != global.errors)
+ {
+ if (exp->fd->type && exp->fd->type->ty == Tfunction && !exp->fd->type->nextOf())
+ ((TypeFunction *)exp->fd->type)->next = Type::terror;
+ e = new ErrorExp();
+ goto Ldone;
+ }
+
+ // Type is a "delegate to" or "pointer to" the function literal
+ if ((exp->fd->isNested() && exp->fd->tok == TOKdelegate) ||
+ (exp->tok == TOKreserved && exp->fd->treq && exp->fd->treq->ty == Tdelegate))
+ {
+ exp->type = new TypeDelegate(exp->fd->type);
+ exp->type = exp->type->semantic(exp->loc, sc);
+
+ exp->fd->tok = TOKdelegate;
+ }
+ else
+ {
+ exp->type = new TypePointer(exp->fd->type);
+ exp->type = exp->type->semantic(exp->loc, sc);
+ //exp->type = exp->fd->type->pointerTo();
+
+ /* A lambda expression deduced to function pointer might become
+ * to a delegate literal implicitly.
+ *
+ * auto foo(void function() fp) { return 1; }
+ * assert(foo({}) == 1);
+ *
+ * So, should keep fd->tok == TOKreserve if fd->treq == NULL.
+ */
+ if (exp->fd->treq && exp->fd->treq->ty == Tpointer)
+ {
+ // change to non-nested
+ exp->fd->tok = TOKfunction;
+ exp->fd->vthis = NULL;
+ }
+ }
+ exp->fd->tookAddressOf++;
+ }
+ Ldone:
+ sc = sc->pop();
+ result = e;
+ }
+
+ // used from CallExp::semantic()
+ Expression *callExpSemantic(FuncExp *exp, Scope *sc, Expressions *arguments)
+ {
+ if ((!exp->type || exp->type == Type::tvoid) && exp->td && arguments && arguments->dim)
+ {
+ for (size_t k = 0; k < arguments->dim; k++)
+ { Expression *checkarg = (*arguments)[k];
+ if (checkarg->op == TOKerror)
+ return checkarg;
+ }
+
+ exp->genIdent(sc);
+
+ assert(exp->td->parameters && exp->td->parameters->dim);
+ exp->td->semantic(sc);
+
+ TypeFunction *tfl = (TypeFunction *)exp->fd->type;
+ size_t dim = Parameter::dim(tfl->parameters);
+ if (arguments->dim < dim)
+ { // Default arguments are always typed, so they don't need inference.
+ Parameter *p = Parameter::getNth(tfl->parameters, arguments->dim);
+ if (p->defaultArg)
+ dim = arguments->dim;
+ }
+
+ if ((!tfl->varargs && arguments->dim == dim) ||
+ ( tfl->varargs && arguments->dim >= dim))
+ {
+ Objects *tiargs = new Objects();
+ tiargs->reserve(exp->td->parameters->dim);
+
+ for (size_t i = 0; i < exp->td->parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*exp->td->parameters)[i];
+ for (size_t u = 0; u < dim; u++)
+ { Parameter *p = Parameter::getNth(tfl->parameters, u);
+ if (p->type->ty == Tident &&
+ ((TypeIdentifier *)p->type)->ident == tp->ident)
+ { Expression *e = (*arguments)[u];
+ tiargs->push(e->type);
+ u = dim; // break inner loop
+ }
+ }
+ }
+
+ TemplateInstance *ti = new TemplateInstance(exp->loc, exp->td, tiargs);
+ Expression *se = new ScopeExp(exp->loc, ti);
+ return semantic(se, sc);
+ }
+ exp->error("cannot infer function literal type");
+ return new ErrorExp();
+ }
+ return semantic(exp, sc);
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ unsigned olderrors = global.errors;
+
+ /* This is here to support extern(linkage) declaration,
+ * where the extern(linkage) winds up being an AttribDeclaration
+ * wrapper.
+ */
+ Dsymbol *s = e->declaration;
+
+ while (1)
+ {
+ AttribDeclaration *ad = s->isAttribDeclaration();
+ if (ad)
+ {
+ if (ad->decl && ad->decl->dim == 1)
+ {
+ s = (*ad->decl)[0];
+ continue;
+ }
+ }
+ break;
+ }
+
+ VarDeclaration *v = s->isVarDeclaration();
+ if (v)
+ {
+ // Do semantic() on initializer first, so:
+ // int a = a;
+ // will be illegal.
+ e->declaration->semantic(sc);
+ s->parent = sc->parent;
+ }
+
+ //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc);
+ // Insert into both local scope and function scope.
+ // Must be unique in both.
+ if (s->ident)
+ {
+ if (!sc->insert(s))
+ {
+ e->error("declaration %s is already defined", s->toPrettyChars());
+ return setError();
+ }
+ else if (sc->func)
+ {
+ // Bugzilla 11720 - include Dataseg variables
+ if ((s->isFuncDeclaration() ||
+ s->isAggregateDeclaration() ||
+ s->isEnumDeclaration() ||
+ (v && v->isDataseg())) &&
+ !sc->func->localsymtab->insert(s))
+ {
+ e->error("declaration %s is already defined in another scope in %s",
+ s->toPrettyChars(), sc->func->toChars());
+ return setError();
+ }
+ else
+ {
+ // Disallow shadowing
+ for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing)
+ {
+ Dsymbol *s2;
+ if (scx->scopesym && scx->scopesym->symtab &&
+ (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
+ s != s2)
+ {
+ e->error("%s %s is shadowing %s %s", s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
+ return setError();
+ }
+ }
+ }
+ }
+ }
+ if (!s->isVarDeclaration())
+ {
+ Scope *sc2 = sc;
+ if (sc2->stc & (STCpure | STCnothrow | STCnogc))
+ sc2 = sc->push();
+ sc2->stc &= ~(STCpure | STCnothrow | STCnogc);
+ e->declaration->semantic(sc2);
+ if (sc2 != sc)
+ sc2->pop();
+ s->parent = sc->parent;
+ }
+ if (global.errors == olderrors)
+ {
+ e->declaration->semantic2(sc);
+ if (global.errors == olderrors)
+ {
+ e->declaration->semantic3(sc);
+ }
+ }
+ // todo: error in declaration should be propagated.
+
+ e->type = Type::tvoid;
+ result = e;
+ }
+
+ void visit(TypeidExp *exp)
+ {
+ Type *ta = isType(exp->obj);
+ Expression *ea = isExpression(exp->obj);
+ Dsymbol *sa = isDsymbol(exp->obj);
+
+ //printf("ta %p ea %p sa %p\n", ta, ea, sa);
+
+ if (ta)
+ {
+ ta->resolve(exp->loc, sc, &ea, &ta, &sa, true);
+ }
+
+ if (ea)
+ {
+ if (Dsymbol *sym = getDsymbol(ea))
+ ea = resolve(exp->loc, sc, sym, false);
+ else
+ ea = semantic(ea, sc);
+ ea = resolveProperties(sc, ea);
+ ta = ea->type;
+ if (ea->op == TOKtype)
+ ea = NULL;
+ }
+
+ if (!ta)
+ {
+ //printf("ta %p ea %p sa %p\n", ta, ea, sa);
+ exp->error("no type for typeid(%s)", ea ? ea->toChars() : (sa ? sa->toChars() : ""));
+ return setError();
+ }
+
+ if (global.params.vcomplex)
+ ta->checkComplexTransition(exp->loc);
+
+ Expression *e;
+ if (ea && ta->toBasetype()->ty == Tclass)
+ {
+ /* Get the dynamic type, which is .classinfo
+ */
+ ea = semantic(ea, sc);
+ e = new TypeidExp(ea->loc, ea);
+ e->type = Type::typeinfoclass->type;
+ }
+ else if (ta->ty == Terror)
+ {
+ e = new ErrorExp();
+ }
+ else
+ {
+ // Handle this in the glue layer
+ e = new TypeidExp(exp->loc, ta);
+ e->type = getTypeInfoType(ta, sc);
+
+ semanticTypeInfo(sc, ta);
+
+ if (ea)
+ {
+ e = new CommaExp(exp->loc, ea, e); // execute ea
+ e = semantic(e, sc);
+ }
+ }
+ result = e;
+ }
+
+ void visit(TraitsExp *e)
+ {
+ result = semanticTraits(e, sc);
+ }
+
+ void visit(HaltExp *e)
+ {
+ e->type = Type::tvoid;
+ result = e;
+ }
+
+ void visit(IsExp *e)
+ {
+ /* is(targ id tok tspec)
+ * is(targ id : tok2)
+ * is(targ id == tok2)
+ */
+
+ //printf("IsExp::semantic(%s)\n", toChars());
+ if (e->id && !(sc->flags & SCOPEcondition))
+ {
+ e->error("can only declare type aliases within static if conditionals or static asserts");
+ return setError();
+ }
+
+ Type *tded = NULL;
+ Scope *sc2 = sc->copy(); // keep sc->flags
+ sc2->tinst = NULL;
+ sc2->minst = NULL;
+ sc2->flags |= SCOPEfullinst;
+ Type *t = e->targ->trySemantic(e->loc, sc2);
+ sc2->pop();
+ if (!t)
+ goto Lno; // errors, so condition is false
+ e->targ = t;
+ if (e->tok2 != TOKreserved)
+ {
+ switch (e->tok2)
+ {
+ case TOKstruct:
+ if (e->targ->ty != Tstruct)
+ goto Lno;
+ if (((TypeStruct *)e->targ)->sym->isUnionDeclaration())
+ goto Lno;
+ tded = e->targ;
+ break;
+
+ case TOKunion:
+ if (e->targ->ty != Tstruct)
+ goto Lno;
+ if (!((TypeStruct *)e->targ)->sym->isUnionDeclaration())
+ goto Lno;
+ tded = e->targ;
+ break;
+
+ case TOKclass:
+ if (e->targ->ty != Tclass)
+ goto Lno;
+ if (((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
+ goto Lno;
+ tded = e->targ;
+ break;
+
+ case TOKinterface:
+ if (e->targ->ty != Tclass)
+ goto Lno;
+ if (!((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
+ goto Lno;
+ tded = e->targ;
+ break;
+ case TOKconst:
+ if (!e->targ->isConst())
+ goto Lno;
+ tded = e->targ;
+ break;
+
+ case TOKimmutable:
+ if (!e->targ->isImmutable())
+ goto Lno;
+ tded = e->targ;
+ break;
+
+ case TOKshared:
+ if (!e->targ->isShared())
+ goto Lno;
+ tded = e->targ;
+ break;
+
+ case TOKwild:
+ if (!e->targ->isWild())
+ goto Lno;
+ tded = e->targ;
+ break;
+
+ case TOKsuper:
+ // If class or interface, get the base class and interfaces
+ if (e->targ->ty != Tclass)
+ goto Lno;
+ else
+ {
+ ClassDeclaration *cd = ((TypeClass *)e->targ)->sym;
+ Parameters *args = new Parameters;
+ args->reserve(cd->baseclasses->dim);
+ if (cd->_scope && !cd->symtab)
+ cd->semantic(cd->_scope);
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ BaseClass *b = (*cd->baseclasses)[i];
+ args->push(new Parameter(STCin, b->type, NULL, NULL));
+ }
+ tded = new TypeTuple(args);
+ }
+ break;
+
+ case TOKenum:
+ if (e->targ->ty != Tenum)
+ goto Lno;
+ if (e->id)
+ tded = ((TypeEnum *)e->targ)->sym->getMemtype(e->loc);
+ else
+ tded = e->targ;
+ if (tded->ty == Terror)
+ return setError();
+ break;
+
+ case TOKdelegate:
+ if (e->targ->ty != Tdelegate)
+ goto Lno;
+ tded = ((TypeDelegate *)e->targ)->next; // the underlying function type
+ break;
+
+ case TOKfunction:
+ case TOKparameters:
+ {
+ if (e->targ->ty != Tfunction)
+ goto Lno;
+ tded = e->targ;
+
+ /* Generate tuple from function parameter types.
+ */
+ assert(tded->ty == Tfunction);
+ Parameters *params = ((TypeFunction *)tded)->parameters;
+ size_t dim = Parameter::dim(params);
+ Parameters *args = new Parameters;
+ args->reserve(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *arg = Parameter::getNth(params, i);
+ assert(arg && arg->type);
+ /* If one of the default arguments was an error,
+ don't return an invalid tuple
+ */
+ if (e->tok2 == TOKparameters && arg->defaultArg &&
+ arg->defaultArg->op == TOKerror)
+ return setError();
+ args->push(new Parameter(arg->storageClass, arg->type,
+ (e->tok2 == TOKparameters) ? arg->ident : NULL,
+ (e->tok2 == TOKparameters) ? arg->defaultArg : NULL));
+ }
+ tded = new TypeTuple(args);
+ break;
+ }
+ case TOKreturn:
+ /* Get the 'return type' for the function,
+ * delegate, or pointer to function.
+ */
+ if (e->targ->ty == Tfunction)
+ tded = ((TypeFunction *)e->targ)->next;
+ else if (e->targ->ty == Tdelegate)
+ {
+ tded = ((TypeDelegate *)e->targ)->next;
+ tded = ((TypeFunction *)tded)->next;
+ }
+ else if (e->targ->ty == Tpointer &&
+ ((TypePointer *)e->targ)->next->ty == Tfunction)
+ {
+ tded = ((TypePointer *)e->targ)->next;
+ tded = ((TypeFunction *)tded)->next;
+ }
+ else
+ goto Lno;
+ break;
+
+ case TOKargTypes:
+ /* Generate a type tuple of the equivalent types used to determine if a
+ * function argument of this type can be passed in registers.
+ * The results of this are highly platform dependent, and intended
+ * primarly for use in implementing va_arg().
+ */
+ tded = toArgTypes(e->targ);
+ if (!tded)
+ goto Lno; // not valid for a parameter
+ break;
+
+ case TOKvector:
+ if (e->targ->ty != Tvector)
+ goto Lno;
+ tded = ((TypeVector *)e->targ)->basetype;
+ break;
+
+ default:
+ assert(0);
+ }
+ goto Lyes;
+ }
+ else if (e->tspec && !e->id && !(e->parameters && e->parameters->dim))
+ {
+ /* Evaluate to true if targ matches tspec
+ * is(targ == tspec)
+ * is(targ : tspec)
+ */
+ e->tspec = e->tspec->semantic(e->loc, sc);
+ //printf("targ = %s, %s\n", e->targ->toChars(), e->targ->deco);
+ //printf("tspec = %s, %s\n", e->tspec->toChars(), e->tspec->deco);
+ if (e->tok == TOKcolon)
+ {
+ if (e->targ->implicitConvTo(e->tspec))
+ goto Lyes;
+ else
+ goto Lno;
+ }
+ else /* == */
+ {
+ if (e->targ->equals(e->tspec))
+ goto Lyes;
+ else
+ goto Lno;
+ }
+ }
+ else if (e->tspec)
+ {
+ /* Evaluate to true if targ matches tspec.
+ * If true, declare id as an alias for the specialized type.
+ * is(targ == tspec, tpl)
+ * is(targ : tspec, tpl)
+ * is(targ id == tspec)
+ * is(targ id : tspec)
+ * is(targ id == tspec, tpl)
+ * is(targ id : tspec, tpl)
+ */
+
+ Identifier *tid = e->id ? e->id : Identifier::generateId("__isexp_id");
+ e->parameters->insert(0, new TemplateTypeParameter(e->loc, tid, NULL, NULL));
+
+ Objects dedtypes;
+ dedtypes.setDim(e->parameters->dim);
+ dedtypes.zero();
+
+ MATCH m = deduceType(e->targ, sc, e->tspec, e->parameters, &dedtypes);
+ //printf("targ: %s\n", e->targ->toChars());
+ //printf("tspec: %s\n", e->tspec->toChars());
+ if (m <= MATCHnomatch ||
+ (m != MATCHexact && e->tok == TOKequal))
+ {
+ goto Lno;
+ }
+ else
+ {
+ tded = (Type *)dedtypes[0];
+ if (!tded)
+ tded = e->targ;
+ Objects tiargs;
+ tiargs.setDim(1);
+ tiargs[0] = e->targ;
+
+ /* Declare trailing parameters
+ */
+ for (size_t i = 1; i < e->parameters->dim; i++)
+ {
+ TemplateParameter *tp = (*e->parameters)[i];
+ Declaration *s = NULL;
+
+ m = tp->matchArg(e->loc, sc, &tiargs, i, e->parameters, &dedtypes, &s);
+ if (m <= MATCHnomatch)
+ goto Lno;
+ s->semantic(sc);
+ if (sc->sds)
+ s->addMember(sc, sc->sds);
+ else if (!sc->insert(s))
+ e->error("declaration %s is already defined", s->toChars());
+
+ unSpeculative(sc, s);
+ }
+ goto Lyes;
+ }
+ }
+ else if (e->id)
+ {
+ /* Declare id as an alias for type targ. Evaluate to true
+ * is(targ id)
+ */
+ tded = e->targ;
+ goto Lyes;
+ }
+
+ Lyes:
+ if (e->id)
+ {
+ Dsymbol *s;
+ Tuple *tup = isTuple(tded);
+ if (tup)
+ s = new TupleDeclaration(e->loc, e->id, &(tup->objects));
+ else
+ s = new AliasDeclaration(e->loc, e->id, tded);
+ s->semantic(sc);
+ /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
+ * More investigation is needed.
+ */
+ if (!tup && !sc->insert(s))
+ e->error("declaration %s is already defined", s->toChars());
+ if (sc->sds)
+ s->addMember(sc, sc->sds);
+
+ unSpeculative(sc, s);
+ }
+ //printf("Lyes\n");
+ result = new IntegerExp(e->loc, 1, Type::tbool);
+ return;
+
+ Lno:
+ //printf("Lno\n");
+ result = new IntegerExp(e->loc, 0, Type::tbool);
+ }
+
+ void visit(BinAssignExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
+ return setError();
+
+ if (exp->e1->op == TOKarraylength)
+ {
+ // arr.length op= e2;
+ e = ArrayLengthExp::rewriteOpAssign(exp);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
+ {
+ if (exp->e1->op == TOKslice)
+ ((SliceExp *)exp->e1)->arrayop = true;
+
+ // T[] op= ...
+ if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
+ {
+ // T[] op= T
+ exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
+ }
+ else if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp->type = exp->e1->type;
+ result = arrayOp(exp, sc);
+ return;
+ }
+
+ exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = exp->e1->optimize(WANTvalue);
+ exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+ exp->type = exp->e1->type;
+ if (exp->checkScalar())
+ return setError();
+
+ int arith = (exp->op == TOKaddass || exp->op == TOKminass || exp->op == TOKmulass ||
+ exp->op == TOKdivass || exp->op == TOKmodass || exp->op == TOKpowass);
+ int bitwise = (exp->op == TOKandass || exp->op == TOKorass || exp->op == TOKxorass);
+ int shift = (exp->op == TOKshlass || exp->op == TOKshrass || exp->op == TOKushrass);
+
+ if (bitwise && exp->type->toBasetype()->ty == Tbool)
+ exp->e2 = exp->e2->implicitCastTo(sc, exp->type);
+ else if (exp->checkNoBool())
+ return setError();
+
+ if ((exp->op == TOKaddass || exp->op == TOKminass) &&
+ exp->e1->type->toBasetype()->ty == Tpointer &&
+ exp->e2->type->toBasetype()->isintegral())
+ {
+ result = scaleFactor(exp, sc);
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ if (arith && exp->checkArithmeticBin())
+ return setError();
+ if ((bitwise || shift) && exp->checkIntegralBin())
+ return setError();
+ if (shift)
+ {
+ if (exp->e2->type->toBasetype()->ty != Tvector)
+ exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+ }
+
+ if (!Target::isVectorOpSupported(exp->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
+ if (exp->e1->op == TOKerror || exp->e2->op == TOKerror)
+ return setError();
+
+ e = exp->checkOpAssignTypes(sc);
+ if (e->op == TOKerror)
+ {
+ result = e;
+ return;
+ }
+
+ assert(e->op == TOKassign || e == exp);
+ result = ((BinExp *)e)->reorderSettingAAElem(sc);
+ }
+
+ void visit(CompileExp *exp)
+ {
+ sc = sc->startCTFE();
+ exp->e1 = semantic(exp->e1, sc);
+ exp->e1 = resolveProperties(sc, exp->e1);
+ sc = sc->endCTFE();
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (!exp->e1->type->isString())
+ {
+ exp->error("argument to mixin must be a string type, not %s", exp->e1->type->toChars());
+ return setError();
+ }
+ exp->e1 = exp->e1->ctfeInterpret();
+ StringExp *se = exp->e1->toStringExp();
+ if (!se)
+ {
+ exp->error("argument to mixin must be a string, not (%s)", exp->e1->toChars());
+ return setError();
+ }
+ se = se->toUTF8(sc);
+ unsigned errors = global.errors;
+ Parser p(exp->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+ p.nextToken();
+ //printf("p.loc.linnum = %d\n", p.loc.linnum);
+ Expression *e = p.parseExpression();
+ if (p.errors)
+ {
+ assert(global.errors != errors); // should have caught all these cases
+ return setError();
+ }
+ if (p.token.value != TOKeof)
+ {
+ exp->error("incomplete mixin expression (%s)", se->toChars());
+ return setError();
+ }
+ result = semantic(e, sc);
+ }
+
+ void visit(ImportExp *e)
+ {
+ const char *name;
+ StringExp *se;
+
+ sc = sc->startCTFE();
+ e->e1 = semantic(e->e1, sc);
+ e->e1 = resolveProperties(sc, e->e1);
+ sc = sc->endCTFE();
+ e->e1 = e->e1->ctfeInterpret();
+ if (e->e1->op != TOKstring)
+ {
+ e->error("file name argument must be a string, not (%s)", e->e1->toChars());
+ goto Lerror;
+ }
+ se = (StringExp *)e->e1;
+ se = se->toUTF8(sc);
+ name = (char *)se->string;
+
+ if (!global.params.fileImppath)
+ {
+ e->error("need -Jpath switch to import text file %s", name);
+ goto Lerror;
+ }
+
+ /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
+ * ('Path Traversal') attacks.
+ * http://cwe.mitre.org/data/definitions/22.html
+ */
+
+ name = FileName::safeSearchPath(global.filePath, name);
+ if (!name)
+ {
+ e->error("file %s cannot be found or not in a path specified with -J", se->toChars());
+ goto Lerror;
+ }
+
+ if (global.params.verbose)
+ message("file %.*s\t(%s)", (int)se->len, (char *)se->string, name);
+ if (global.params.moduleDeps != NULL)
+ {
+ OutBuffer *ob = global.params.moduleDeps;
+ Module* imod = sc->instantiatingModule();
+
+ if (!global.params.moduleDepsFile)
+ ob->writestring("depsFile ");
+ ob->writestring(imod->toPrettyChars());
+ ob->writestring(" (");
+ escapePath(ob, imod->srcfile->toChars());
+ ob->writestring(") : ");
+ if (global.params.moduleDepsFile)
+ ob->writestring("string : ");
+ ob->writestring((char *) se->string);
+ ob->writestring(" (");
+ escapePath(ob, name);
+ ob->writestring(")");
+ ob->writenl();
+ }
+
+ {
+ File f(name);
+ if (f.read())
+ {
+ e->error("cannot read file %s", f.toChars());
+ goto Lerror;
+ }
+ else
+ {
+ f.ref = 1;
+ se = new StringExp(e->loc, f.buffer, f.len);
+ }
+ }
+ result = semantic(se, sc);
+ return;
+
+ Lerror:
+ return setError();
+ }
+
+ void visit(AssertExp *exp)
+ {
+ if (Expression *ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp->e1 = resolveProperties(sc, exp->e1);
+ // BUG: see if we can do compile time elimination of the Assert
+ exp->e1 = exp->e1->optimize(WANTvalue);
+ exp->e1 = exp->e1->toBoolean(sc);
+ if (exp->msg)
+ {
+ exp->msg = semantic(exp->msg, sc);
+ exp->msg = resolveProperties(sc, exp->msg);
+ exp->msg = exp->msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf());
+ exp->msg = exp->msg->optimize(WANTvalue);
+ }
+
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (exp->msg && exp->msg->op == TOKerror)
+ {
+ result = exp->msg;
+ return;
+ }
+
+ bool f1 = checkNonAssignmentArrayOp(exp->e1);
+ bool f2 = exp->msg && checkNonAssignmentArrayOp(exp->msg);
+ if (f1 || f2)
+ return setError();
+
+ if (exp->e1->isBool(false))
+ {
+ FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+ if (fd)
+ fd->hasReturnExp |= 4;
+ sc->callSuper |= CSXhalt;
+ if (sc->fieldinit)
+ {
+ for (size_t i = 0; i < sc->fieldinit_dim; i++)
+ sc->fieldinit[i] |= CSXhalt;
+ }
+
+ if (!global.params.useAssert)
+ {
+ Expression *e = new HaltExp(exp->loc);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ }
+ exp->type = Type::tvoid;
+ result = exp;
+ }
+
+ void visit(DotIdExp *exp)
+ {
+ Expression *e = semanticY(exp, sc, 1);
+ if (e && isDotOpDispatch(e))
+ {
+ unsigned errors = global.startGagging();
+ e = resolvePropertiesX(sc, e);
+ if (global.endGagging(errors))
+ e = NULL; /* fall down to UFCS */
+ else
+ {
+ result = e;
+ return;
+ }
+ }
+ if (!e) // if failed to find the property
+ {
+ /* If ident is not a valid property, rewrite:
+ * e1.ident
+ * as:
+ * .ident(e1)
+ */
+ e = resolveUFCSProperties(sc, exp);
+ }
+ result = e;
+ }
+
+ void visit(DotTemplateExp *e)
+ {
+ if (Expression *ex = unaSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ result = e;
+ }
+
+ void visit(DotVarExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp->var = exp->var->toAlias()->isDeclaration();
+
+ exp->e1 = semantic(exp->e1, sc);
+
+ if (TupleDeclaration *tup = exp->var->isTupleDeclaration())
+ {
+ /* Replace:
+ * e1.tuple(a, b, c)
+ * with:
+ * tuple(e1.a, e1.b, e1.c)
+ */
+ Expression *e0 = NULL;
+ Expression *ev = sc->func ? extractSideEffect(sc, "__tup", &e0, exp->e1) : exp->e1;
+
+ Expressions *exps = new Expressions;
+ exps->reserve(tup->objects->dim);
+ for (size_t i = 0; i < tup->objects->dim; i++)
+ {
+ RootObject *o = (*tup->objects)[i];
+ Expression *e;
+ if (o->dyncast() == DYNCAST_EXPRESSION)
+ {
+ e = (Expression *)o;
+ if (e->op == TOKdsymbol)
+ {
+ Dsymbol *s = ((DsymbolExp *)e)->s;
+ e = new DotVarExp(exp->loc, ev, s->isDeclaration());
+ }
+ }
+ else if (o->dyncast() == DYNCAST_DSYMBOL)
+ {
+ e = new DsymbolExp(exp->loc, (Dsymbol *)o);
+ }
+ else if (o->dyncast() == DYNCAST_TYPE)
+ {
+ e = new TypeExp(exp->loc, (Type *)o);
+ }
+ else
+ {
+ exp->error("%s is not an expression", o->toChars());
+ return setError();
+ }
+ exps->push(e);
+ }
+
+ Expression *e = new TupleExp(exp->loc, e0, exps);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+
+ exp->e1 = exp->e1->addDtorHook(sc);
+
+ Type *t1 = exp->e1->type;
+
+ if (FuncDeclaration *fd = exp->var->isFuncDeclaration())
+ {
+ // for functions, do checks after overload resolution
+ if (!fd->functionSemantic())
+ return setError();
+
+ /* Bugzilla 13843: If fd obviously has no overloads, we should
+ * normalize AST, and it will give a chance to wrap fd with FuncExp.
+ */
+ if (fd->isNested() || fd->isFuncLiteralDeclaration())
+ {
+ // (e1, fd)
+ Expression *e = resolve(exp->loc, sc, fd, false);
+ result = Expression::combine(exp->e1, e);
+ return;
+ }
+
+ exp->type = fd->type;
+ assert(exp->type);
+ }
+ else if (exp->var->isOverDeclaration())
+ {
+ exp->type = Type::tvoid; // ambiguous type?
+ }
+ else
+ {
+ exp->type = exp->var->type;
+ if (!exp->type && global.errors)
+ {
+ // var is goofed up, just return 0
+ return setError();
+ }
+ assert(exp->type);
+
+ if (t1->ty == Tpointer)
+ t1 = t1->nextOf();
+
+ exp->type = exp->type->addMod(t1->mod);
+
+ Dsymbol *vparent = exp->var->toParent();
+ AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL;
+
+ if (Expression *e1x = getRightThis(exp->loc, sc, ad, exp->e1, exp->var, 1))
+ exp->e1 = e1x;
+ else
+ {
+ /* Later checkRightThis will report correct error for invalid field variable access.
+ */
+ Expression *e = new VarExp(exp->loc, exp->var);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ checkAccess(exp->loc, sc, exp->e1, exp->var);
+
+ VarDeclaration *v = exp->var->isVarDeclaration();
+ if (v && (v->isDataseg() || (v->storage_class & STCmanifest)))
+ {
+ Expression *e = expandVar(WANTvalue, v);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+
+ if (v && v->isDataseg()) // fix bugzilla 8238
+ {
+ // (e1, v)
+ checkAccess(exp->loc, sc, exp->e1, v);
+ Expression *e = new VarExp(exp->loc, v);
+ e = new CommaExp(exp->loc, exp->e1, e);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ }
+
+ //printf("-DotVarExp::semantic('%s')\n", exp->toChars());
+ result = exp;
+ }
+
+ void visit(DotTemplateInstanceExp *exp)
+ {
+ // Indicate we need to resolve by UFCS.
+ Expression *e = semanticY(exp, sc, 1);
+ if (!e)
+ e = resolveUFCSProperties(sc, exp);
+ result = e;
+ }
+
+ void visit(DelegateExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ e->e1 = semantic(e->e1, sc);
+ e->type = new TypeDelegate(e->func->type);
+ e->type = e->type->semantic(e->loc, sc);
+ FuncDeclaration *f = e->func->toAliasFunc();
+ AggregateDeclaration *ad = f->toParent()->isAggregateDeclaration();
+ if (f->needThis())
+ e->e1 = getRightThis(e->loc, sc, ad, e->e1, f);
+ if (f->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)f->type;
+ if (!MODmethodConv(e->e1->type->mod, f->type->mod))
+ {
+ OutBuffer thisBuf, funcBuf;
+ MODMatchToBuffer(&thisBuf, e->e1->type->mod, tf->mod);
+ MODMatchToBuffer(&funcBuf, tf->mod, e->e1->type->mod);
+ e->error("%smethod %s is not callable using a %s%s",
+ funcBuf.peekString(), f->toPrettyChars(), thisBuf.peekString(), e->e1->toChars());
+ return setError();
+ }
+ }
+ if (ad && ad->isClassDeclaration() && ad->type != e->e1->type)
+ {
+ // A downcast is required for interfaces, see Bugzilla 3706
+ e->e1 = new CastExp(e->loc, e->e1, ad->type);
+ e->e1 = semantic(e->e1, sc);
+ }
+ result = e;
+ }
+
+ void visit(DotTypeExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *e = unaSemantic(exp, sc))
+ {
+ result = e;
+ return;
+ }
+
+ exp->type = exp->sym->getType()->addMod(exp->e1->type->mod);
+ result = exp;
+ }
+
+ void visit(CallExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp; // semantic() already run
+ return;
+ }
+
+ Type *t1;
+ Objects *tiargs = NULL; // initial list of template arguments
+ Expression *ethis = NULL;
+ Type *tthis = NULL;
+ Expression *e1org = exp->e1;
+
+ if (exp->e1->op == TOKcomma)
+ {
+ /* Rewrite (a,b)(args) as (a,(b(args)))
+ */
+ CommaExp *ce = (CommaExp *)exp->e1;
+ exp->e1 = ce->e2;
+ ce->e2 = exp;
+ result = semantic(ce, sc);
+ return;
+ }
+
+ if (exp->e1->op == TOKdelegate)
+ {
+ DelegateExp *de = (DelegateExp *)exp->e1;
+ exp->e1 = new DotVarExp(de->loc, de->e1, de->func, de->hasOverloads);
+ result = semantic(exp, sc);
+ return;
+ }
+
+ if (exp->e1->op == TOKfunction)
+ {
+ if (arrayExpressionSemantic(exp->arguments, sc) ||
+ preFunctionParameters(sc, exp->arguments))
+ {
+ return setError();
+ }
+
+ // Run e1 semantic even if arguments have any errors
+ FuncExp *fe = (FuncExp *)exp->e1;
+ exp->e1 = callExpSemantic(fe, sc, exp->arguments);
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ }
+
+ if (Expression *ex = resolveUFCS(sc, exp))
+ {
+ result = ex;
+ return;
+ }
+
+ /* This recognizes:
+ * foo!(tiargs)(funcargs)
+ */
+ if (exp->e1->op == TOKscope)
+ {
+ ScopeExp *se = (ScopeExp *)exp->e1;
+ TemplateInstance *ti = se->sds->isTemplateInstance();
+ if (ti)
+ {
+ /* Attempt to instantiate ti. If that works, go with it.
+ * If not, go with partial explicit specialization.
+ */
+ WithScopeSymbol *withsym;
+ if (!ti->findTempDecl(sc, &withsym) ||
+ !ti->semanticTiargs(sc))
+ {
+ return setError();
+ }
+ if (withsym && withsym->withstate->wthis)
+ {
+ exp->e1 = new VarExp(exp->e1->loc, withsym->withstate->wthis);
+ exp->e1 = new DotTemplateInstanceExp(exp->e1->loc, exp->e1, ti);
+ goto Ldotti;
+ }
+ if (ti->needsTypeInference(sc, 1))
+ {
+ /* Go with partial explicit specialization
+ */
+ tiargs = ti->tiargs;
+ assert(ti->tempdecl);
+ if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
+ exp->e1 = new TemplateExp(exp->loc, td);
+ else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
+ exp->e1 = new VarExp(exp->loc, od);
+ else
+ exp->e1 = new OverExp(exp->loc, ti->tempdecl->isOverloadSet());
+ }
+ else
+ {
+ Expression *e1x = semantic(exp->e1, sc);
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ exp->e1 = e1x;
+ }
+ }
+ }
+
+ /* This recognizes:
+ * expr.foo!(tiargs)(funcargs)
+ */
+ Ldotti:
+ if (exp->e1->op == TOKdotti && !exp->e1->type)
+ {
+ DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)exp->e1;
+ TemplateInstance *ti = se->ti;
+ {
+ /* Attempt to instantiate ti. If that works, go with it.
+ * If not, go with partial explicit specialization.
+ */
+ if (!se->findTempDecl(sc) ||
+ !ti->semanticTiargs(sc))
+ {
+ return setError();
+ }
+ if (ti->needsTypeInference(sc, 1))
+ {
+ /* Go with partial explicit specialization
+ */
+ tiargs = ti->tiargs;
+ assert(ti->tempdecl);
+ if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
+ exp->e1 = new DotTemplateExp(exp->loc, se->e1, td);
+ else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
+ {
+ exp->e1 = new DotVarExp(exp->loc, se->e1, od, true);
+ }
+ else
+ exp->e1 = new DotExp(exp->loc, se->e1, new OverExp(exp->loc, ti->tempdecl->isOverloadSet()));
+ }
+ else
+ {
+ Expression *e1x = semantic(exp->e1, sc);
+ if (e1x->op == TOKerror)
+ {
+ result =e1x;
+ return;
+ }
+ exp->e1 = e1x;
+ }
+ }
+ }
+
+ Lagain:
+ //printf("Lagain: %s\n", exp->toChars());
+ exp->f = NULL;
+ if (exp->e1->op == TOKthis || exp->e1->op == TOKsuper)
+ {
+ // semantic() run later for these
+ }
+ else
+ {
+ if (exp->e1->op == TOKdotid)
+ {
+ DotIdExp *die = (DotIdExp *)exp->e1;
+ exp->e1 = semantic(die, sc);
+ /* Look for e1 having been rewritten to expr.opDispatch!(string)
+ * We handle such earlier, so go back.
+ * Note that in the rewrite, we carefully did not run semantic() on e1
+ */
+ if (exp->e1->op == TOKdotti && !exp->e1->type)
+ {
+ goto Ldotti;
+ }
+ }
+ else
+ {
+ static int nest;
+ if (++nest > 500)
+ {
+ exp->error("recursive evaluation of %s", exp->toChars());
+ --nest;
+ return setError();
+ }
+ Expression *ex = unaSemantic(exp, sc);
+ --nest;
+ if (ex)
+ {
+ result = ex;
+ return;
+ }
+ }
+
+ /* Look for e1 being a lazy parameter
+ */
+ if (exp->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)exp->e1;
+ if (ve->var->storage_class & STClazy)
+ {
+ // lazy paramaters can be called without violating purity and safety
+ Type *tw = ve->var->type;
+ Type *tc = ve->var->type->substWildTo(MODconst);
+ TypeFunction *tf = new TypeFunction(NULL, tc, 0, LINKd, STCsafe | STCpure);
+ (tf = (TypeFunction *)tf->semantic(exp->loc, sc))->next = tw; // hack for bug7757
+ TypeDelegate *t = new TypeDelegate(tf);
+ ve->type = t->semantic(exp->loc, sc);
+ }
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v && ve->checkPurity(sc, v))
+ return setError();
+ }
+
+ if (exp->e1->op == TOKsymoff && ((SymOffExp *)exp->e1)->hasOverloads)
+ {
+ SymOffExp *se = (SymOffExp *)exp->e1;
+ exp->e1 = new VarExp(se->loc, se->var, true);
+ exp->e1 = semantic(exp->e1, sc);
+ }
+ else if (exp->e1->op == TOKdot)
+ {
+ DotExp *de = (DotExp *) exp->e1;
+
+ if (de->e2->op == TOKoverloadset)
+ {
+ ethis = de->e1;
+ tthis = de->e1->type;
+ exp->e1 = de->e2;
+ }
+ }
+ else if (exp->e1->op == TOKstar && exp->e1->type->ty == Tfunction)
+ {
+ // Rewrite (*fp)(arguments) to fp(arguments)
+ exp->e1 = ((PtrExp *)exp->e1)->e1;
+ }
+ }
+
+ t1 = exp->e1->type ? exp->e1->type->toBasetype() : NULL;
+
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (arrayExpressionSemantic(exp->arguments, sc) ||
+ preFunctionParameters(sc, exp->arguments))
+ {
+ return setError();
+ }
+
+ // Check for call operator overload
+ if (t1)
+ {
+ if (t1->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)t1)->sym;
+ sd->size(exp->loc); // Resolve forward references to construct object
+ if (sd->sizeok != SIZEOKdone)
+ return setError();
+ if (!sd->ctor)
+ sd->ctor = sd->searchCtor();
+
+ // First look for constructor
+ if (exp->e1->op == TOKtype && sd->ctor)
+ {
+ if (!sd->noDefaultCtor && !(exp->arguments && exp->arguments->dim))
+ goto Lx;
+
+ StructLiteralExp *sle = new StructLiteralExp(exp->loc, sd, NULL, exp->e1->type);
+ if (!sd->fill(exp->loc, sle->elements, true))
+ return setError();
+ if (checkFrameAccess(exp->loc, sc, sd, sle->elements->dim))
+ return setError();
+ // Bugzilla 14556: Set concrete type to avoid further redundant semantic().
+ sle->type = exp->e1->type;
+
+ /* Constructor takes a mutable object, so don't use
+ * the immutable initializer symbol.
+ */
+ sle->useStaticInit = false;
+
+ Expression *e = sle;
+ if (CtorDeclaration *cf = sd->ctor->isCtorDeclaration())
+ {
+ e = new DotVarExp(exp->loc, e, cf, true);
+ }
+ else if (TemplateDeclaration *td = sd->ctor->isTemplateDeclaration())
+ {
+ e = new DotTemplateExp(exp->loc, e, td);
+ }
+ else if (OverloadSet *os = sd->ctor->isOverloadSet())
+ {
+ e = new DotExp(exp->loc, e, new OverExp(exp->loc, os));
+ }
+ else
+ assert(0);
+ e = new CallExp(exp->loc, e, exp->arguments);
+ result = semantic(e, sc);
+ return;
+ }
+ // No constructor, look for overload of opCall
+ if (search_function(sd, Id::call))
+ goto L1; // overload of opCall, therefore it's a call
+
+ if (exp->e1->op != TOKtype)
+ {
+ if (sd->aliasthis && exp->e1->type != exp->att1)
+ {
+ if (!exp->att1 && exp->e1->type->checkAliasThisRec())
+ exp->att1 = exp->e1->type;
+ exp->e1 = resolveAliasThis(sc, exp->e1);
+ goto Lagain;
+ }
+ exp->error("%s %s does not overload ()", sd->kind(), sd->toChars());
+ return setError();
+ }
+
+ /* It's a struct literal
+ */
+ Lx:
+ Expression *e = new StructLiteralExp(exp->loc, sd, exp->arguments, exp->e1->type);
+ result = semantic(e, sc);
+ return;
+ }
+ else if (t1->ty == Tclass)
+ {
+ L1:
+ // Rewrite as e1.call(arguments)
+ Expression *e = new DotIdExp(exp->loc, exp->e1, Id::call);
+ e = new CallExp(exp->loc, e, exp->arguments);
+ result = semantic(e, sc);
+ return;
+ }
+ else if (exp->e1->op == TOKtype && t1->isscalar())
+ {
+ Expression *e;
+
+ // Make sure to use the the enum type itself rather than its
+ // base type (see bugzilla 16346)
+ if (exp->e1->type->ty == Tenum)
+ {
+ t1 = exp->e1->type;
+ }
+
+ if (!exp->arguments || exp->arguments->dim == 0)
+ {
+ e = t1->defaultInitLiteral(exp->loc);
+ }
+ else if (exp->arguments->dim == 1)
+ {
+ e = (*exp->arguments)[0];
+ e = e->implicitCastTo(sc, t1);
+ e = new CastExp(exp->loc, e, t1);
+ }
+ else
+ {
+ exp->error("more than one argument for construction of %s", t1->toChars());
+ e = new ErrorExp();
+ }
+ result = semantic(e, sc);
+ return;
+ }
+ }
+
+ if ((exp->e1->op == TOKdotvar && t1->ty == Tfunction) ||
+ exp->e1->op == TOKdottd)
+ {
+ UnaExp *ue = (UnaExp *)(exp->e1);
+
+ Expression *ue1 = ue->e1;
+ Expression *ue1old = ue1; // need for 'right this' check
+ VarDeclaration *v;
+ if (ue1->op == TOKvar &&
+ (v = ((VarExp *)ue1)->var->isVarDeclaration()) != NULL &&
+ v->needThis())
+ {
+ ue->e1 = new TypeExp(ue1->loc, ue1->type);
+ ue1 = NULL;
+ }
+
+ DotVarExp *dve;
+ DotTemplateExp *dte;
+ Dsymbol *s;
+ if (exp->e1->op == TOKdotvar)
+ {
+ dve = (DotVarExp *)(exp->e1);
+ dte = NULL;
+ s = dve->var;
+ tiargs = NULL;
+ }
+ else
+ {
+ dve = NULL;
+ dte = (DotTemplateExp *)(exp->e1);
+ s = dte->td;
+ }
+
+ // Do overload resolution
+ exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, ue1 ? ue1->type : NULL, exp->arguments);
+ if (!exp->f || exp->f->errors || exp->f->type->ty == Terror)
+ return setError();
+ if (exp->f->interfaceVirtual)
+ {
+ /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
+ */
+ BaseClass *b = exp->f->interfaceVirtual;
+ ClassDeclaration *ad2 = b->sym;
+ ue->e1 = ue->e1->castTo(sc, ad2->type->addMod(ue->e1->type->mod));
+ ue->e1 = semantic(ue->e1, sc);
+ ue1 = ue->e1;
+ int vi = exp->f->findVtblIndex((Dsymbols*)&ad2->vtbl, (int)ad2->vtbl.dim);
+ assert(vi >= 0);
+ exp->f = ad2->vtbl[vi]->isFuncDeclaration();
+ assert(exp->f);
+ }
+ if (exp->f->needThis())
+ {
+ AggregateDeclaration *ad = exp->f->toParent2()->isAggregateDeclaration();
+ ue->e1 = getRightThis(exp->loc, sc, ad, ue->e1, exp->f);
+ if (ue->e1->op == TOKerror)
+ {
+ result = ue->e1;
+ return;
+ }
+ ethis = ue->e1;
+ tthis = ue->e1->type;
+ if (!(exp->f->type->ty == Tfunction && ((TypeFunction *)exp->f->type)->isscope))
+ {
+ if (global.params.vsafe && checkParamArgumentEscape(sc, exp->f, Id::This, ethis, false))
+ return setError();
+ }
+ }
+
+ /* Cannot call public functions from inside invariant
+ * (because then the invariant would have infinite recursion)
+ */
+ if (sc->func && sc->func->isInvariantDeclaration() &&
+ ue->e1->op == TOKthis &&
+ exp->f->addPostInvariant()
+ )
+ {
+ exp->error("cannot call public/export function %s from invariant", exp->f->toChars());
+ return setError();
+ }
+
+ exp->checkDeprecated(sc, exp->f);
+ exp->checkPurity(sc, exp->f);
+ exp->checkSafety(sc, exp->f);
+ exp->checkNogc(sc, exp->f);
+ checkAccess(exp->loc, sc, ue->e1, exp->f);
+ if (!exp->f->needThis())
+ {
+ exp->e1 = Expression::combine(ue->e1, new VarExp(exp->loc, exp->f, false));
+ }
+ else
+ {
+ if (ue1old->checkRightThis(sc))
+ return setError();
+ if (exp->e1->op == TOKdotvar)
+ {
+ dve->var = exp->f;
+ exp->e1->type = exp->f->type;
+ }
+ else
+ {
+ exp->e1 = new DotVarExp(exp->loc, dte->e1, exp->f, false);
+ exp->e1 = semantic(exp->e1, sc);
+ if (exp->e1->op == TOKerror)
+ return setError();
+ ue = (UnaExp *)exp->e1;
+ }
+
+ // See if we need to adjust the 'this' pointer
+ AggregateDeclaration *ad = exp->f->isThis();
+ ClassDeclaration *cd = ue->e1->type->isClassHandle();
+ if (ad && cd && ad->isClassDeclaration())
+ {
+ if (ue->e1->op == TOKdottype)
+ {
+ ue->e1 = ((DotTypeExp *)ue->e1)->e1;
+ exp->directcall = true;
+ }
+ else if (ue->e1->op == TOKsuper)
+ exp->directcall = true;
+ else if ((cd->storage_class & STCfinal) != 0) // Bugzilla 14211
+ exp->directcall = true;
+
+ if (ad != cd)
+ {
+ ue->e1 = ue->e1->castTo(sc, ad->type->addMod(ue->e1->type->mod));
+ ue->e1 = semantic(ue->e1, sc);
+ }
+ }
+ }
+ // If we've got a pointer to a function then deference it
+ // https://issues.dlang.org/show_bug.cgi?id=16483
+ if (exp->e1->type->ty == Tpointer && exp->e1->type->nextOf()->ty == Tfunction)
+ {
+ Expression *e = new PtrExp(exp->loc, exp->e1);
+ e->type = exp->e1->type->nextOf();
+ exp->e1 = e;
+ }
+ t1 = exp->e1->type;
+ }
+ else if (exp->e1->op == TOKsuper)
+ {
+ // Base class constructor call
+ AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
+ ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
+ if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration())
+ {
+ exp->error("super class constructor call must be in a constructor");
+ return setError();
+ }
+ if (!cd->baseClass->ctor)
+ {
+ exp->error("no super class constructor for %s", cd->baseClass->toChars());
+ return setError();
+ }
+
+ if (!sc->intypeof && !(sc->callSuper & CSXhalt))
+ {
+ if (sc->noctor || sc->callSuper & CSXlabel)
+ exp->error("constructor calls not allowed in loops or after labels");
+ if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+ exp->error("multiple constructor calls");
+ if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
+ exp->error("an earlier return statement skips constructor");
+ sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
+ }
+
+ tthis = cd->type->addMod(sc->func->type->mod);
+ if (OverloadSet *os = cd->baseClass->ctor->isOverloadSet())
+ exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
+ else
+ exp->f = resolveFuncCall(exp->loc, sc, cd->baseClass->ctor, NULL, tthis, exp->arguments, 0);
+ if (!exp->f || exp->f->errors)
+ return setError();
+ exp->checkDeprecated(sc, exp->f);
+ exp->checkPurity(sc, exp->f);
+ exp->checkSafety(sc, exp->f);
+ exp->checkNogc(sc, exp->f);
+ checkAccess(exp->loc, sc, NULL, exp->f);
+
+ exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
+ exp->e1 = semantic(exp->e1, sc);
+ t1 = exp->e1->type;
+ }
+ else if (exp->e1->op == TOKthis)
+ {
+ // same class constructor call
+ AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
+ if (!ad || !sc->func->isCtorDeclaration())
+ {
+ exp->error("constructor call must be in a constructor");
+ return setError();
+ }
+
+ if (!sc->intypeof && !(sc->callSuper & CSXhalt))
+ {
+ if (sc->noctor || sc->callSuper & CSXlabel)
+ exp->error("constructor calls not allowed in loops or after labels");
+ if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
+ exp->error("multiple constructor calls");
+ if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
+ exp->error("an earlier return statement skips constructor");
+ sc->callSuper |= CSXany_ctor | CSXthis_ctor;
+ }
+
+ tthis = ad->type->addMod(sc->func->type->mod);
+ if (OverloadSet *os = ad->ctor->isOverloadSet())
+ exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
+ else
+ exp->f = resolveFuncCall(exp->loc, sc, ad->ctor, NULL, tthis, exp->arguments, 0);
+ if (!exp->f || exp->f->errors)
+ return setError();
+ exp->checkDeprecated(sc, exp->f);
+ exp->checkPurity(sc, exp->f);
+ exp->checkSafety(sc, exp->f);
+ exp->checkNogc(sc, exp->f);
+ //checkAccess(exp->loc, sc, NULL, exp->f); // necessary?
+
+ exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
+ exp->e1 = semantic(exp->e1, sc);
+ t1 = exp->e1->type;
+
+ // BUG: this should really be done by checking the static
+ // call graph
+ if (exp->f == sc->func)
+ {
+ exp->error("cyclic constructor call");
+ return setError();
+ }
+ }
+ else if (exp->e1->op == TOKoverloadset)
+ {
+ OverloadSet *os = ((OverExp *)exp->e1)->vars;
+ exp->f = resolveOverloadSet(exp->loc, sc, os, tiargs, tthis, exp->arguments);
+ if (!exp->f)
+ return setError();
+ if (ethis)
+ exp->e1 = new DotVarExp(exp->loc, ethis, exp->f, false);
+ else
+ exp->e1 = new VarExp(exp->loc, exp->f, false);
+ goto Lagain;
+ }
+ else if (!t1)
+ {
+ exp->error("function expected before (), not '%s'", exp->e1->toChars());
+ return setError();
+ }
+ else if (t1->ty == Terror)
+ {
+ return setError();
+ }
+ else if (t1->ty != Tfunction)
+ {
+ TypeFunction *tf;
+ const char *p;
+ Dsymbol *s;
+ exp->f = NULL;
+ if (exp->e1->op == TOKfunction)
+ {
+ // function literal that direct called is always inferred.
+ assert(((FuncExp *)exp->e1)->fd);
+ exp->f = ((FuncExp *)exp->e1)->fd;
+ tf = (TypeFunction *)exp->f->type;
+ p = "function literal";
+ }
+ else if (t1->ty == Tdelegate)
+ {
+ TypeDelegate *td = (TypeDelegate *)t1;
+ assert(td->next->ty == Tfunction);
+ tf = (TypeFunction *)(td->next);
+ p = "delegate";
+ }
+ else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction)
+ {
+ tf = (TypeFunction *)(((TypePointer *)t1)->next);
+ p = "function pointer";
+ }
+ else if (exp->e1->op == TOKdotvar &&
+ ((DotVarExp *)exp->e1)->var->isOverDeclaration())
+ {
+ DotVarExp *dve = (DotVarExp *)exp->e1;
+ exp->f = resolveFuncCall(exp->loc, sc, dve->var, tiargs, dve->e1->type, exp->arguments, 2);
+ if (!exp->f)
+ return setError();
+ if (exp->f->needThis())
+ {
+ dve->var = exp->f;
+ dve->type = exp->f->type;
+ dve->hasOverloads = false;
+ goto Lagain;
+ }
+ exp->e1 = new VarExp(dve->loc, exp->f, false);
+ Expression *e = new CommaExp(exp->loc, dve->e1, exp);
+ result = semantic(e, sc);
+ return;
+ }
+ else if (exp->e1->op == TOKvar &&
+ ((VarExp *)exp->e1)->var->isOverDeclaration())
+ {
+ s = ((VarExp *)exp->e1)->var;
+ goto L2;
+ }
+ else if (exp->e1->op == TOKtemplate)
+ {
+ s = ((TemplateExp *)exp->e1)->td;
+ L2:
+ exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, NULL, exp->arguments);
+ if (!exp->f || exp->f->errors)
+ return setError();
+ if (exp->f->needThis())
+ {
+ if (hasThis(sc))
+ {
+ // Supply an implicit 'this', as in
+ // this.ident
+ Expression *ex = new ThisExp(exp->loc);
+ ex = semantic(ex, sc);
+ exp->e1 = new DotVarExp(exp->loc, ex, exp->f, false);
+ goto Lagain;
+ }
+ else if (isNeedThisScope(sc, exp->f))
+ {
+ exp->error("need 'this' for '%s' of type '%s'", exp->f->toChars(), exp->f->type->toChars());
+ return setError();
+ }
+ }
+ exp->e1 = new VarExp(exp->e1->loc, exp->f, false);
+ goto Lagain;
+ }
+ else
+ {
+ exp->error("function expected before (), not %s of type %s", exp->e1->toChars(), exp->e1->type->toChars());
+ return setError();
+ }
+
+ if (!tf->callMatch(NULL, exp->arguments))
+ {
+ OutBuffer buf;
+
+ buf.writeByte('(');
+ argExpTypesToCBuffer(&buf, exp->arguments);
+ buf.writeByte(')');
+ if (tthis)
+ tthis->modToBuffer(&buf);
+
+ //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
+ ::error(exp->loc, "%s %s %s is not callable using argument types %s",
+ p, exp->e1->toChars(), parametersTypeToChars(tf->parameters, tf->varargs),
+ buf.peekString());
+
+ return setError();
+ }
+
+ // Purity and safety check should run after testing arguments matching
+ if (exp->f)
+ {
+ exp->checkPurity(sc, exp->f);
+ exp->checkSafety(sc, exp->f);
+ exp->checkNogc(sc, exp->f);
+ if (exp->f->checkNestedReference(sc, exp->loc))
+ return setError();
+ }
+ else if (sc->func && sc->intypeof != 1 && !(sc->flags & SCOPEctfe))
+ {
+ bool err = false;
+ if (!tf->purity && !(sc->flags & SCOPEdebug) && sc->func->setImpure())
+ {
+ exp->error("pure %s '%s' cannot call impure %s '%s'",
+ sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
+ err = true;
+ }
+ if (!tf->isnogc && sc->func->setGC())
+ {
+ exp->error("@nogc %s '%s' cannot call non-@nogc %s '%s'",
+ sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
+ err = true;
+ }
+ if (tf->trust <= TRUSTsystem && sc->func->setUnsafe())
+ {
+ exp->error("@safe %s '%s' cannot call @system %s '%s'",
+ sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
+ err = true;
+ }
+ if (err)
+ return setError();
+ }
+
+ if (t1->ty == Tpointer)
+ {
+ Expression *e = new PtrExp(exp->loc, exp->e1);
+ e->type = tf;
+ exp->e1 = e;
+ }
+ t1 = tf;
+ }
+ else if (exp->e1->op == TOKvar)
+ {
+ // Do overload resolution
+ VarExp *ve = (VarExp *)exp->e1;
+
+ exp->f = ve->var->isFuncDeclaration();
+ assert(exp->f);
+ tiargs = NULL;
+
+ if (ve->hasOverloads)
+ exp->f = resolveFuncCall(exp->loc, sc, exp->f, tiargs, NULL, exp->arguments, 2);
+ else
+ {
+ exp->f = exp->f->toAliasFunc();
+ TypeFunction *tf = (TypeFunction *)exp->f->type;
+ if (!tf->callMatch(NULL, exp->arguments))
+ {
+ OutBuffer buf;
+
+ buf.writeByte('(');
+ argExpTypesToCBuffer(&buf, exp->arguments);
+ buf.writeByte(')');
+
+ //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
+ ::error(exp->loc, "%s %s is not callable using argument types %s",
+ exp->e1->toChars(), parametersTypeToChars(tf->parameters, tf->varargs),
+ buf.peekString());
+
+ exp->f = NULL;
+ }
+ }
+ if (!exp->f || exp->f->errors)
+ return setError();
+
+ if (exp->f->needThis())
+ {
+ // Change the ancestor lambdas to delegate before hasThis(sc) call.
+ if (exp->f->checkNestedReference(sc, exp->loc))
+ return setError();
+
+ if (hasThis(sc))
+ {
+ // Supply an implicit 'this', as in
+ // this.ident
+
+ Expression *ex = new ThisExp(exp->loc);
+ ex = semantic(ex, sc);
+ exp->e1 = new DotVarExp(exp->loc, ex, ve->var);
+ // Note: we cannot use f directly, because further overload resolution
+ // through the supplied 'this' may cause different result.
+ goto Lagain;
+ }
+ else if (isNeedThisScope(sc, exp->f))
+ {
+ exp->error("need 'this' for '%s' of type '%s'", exp->f->toChars(), exp->f->type->toChars());
+ return setError();
+ }
+ }
+
+ exp->checkDeprecated(sc, exp->f);
+ exp->checkPurity(sc, exp->f);
+ exp->checkSafety(sc, exp->f);
+ exp->checkNogc(sc, exp->f);
+ checkAccess(exp->loc, sc, NULL, exp->f);
+ if (exp->f->checkNestedReference(sc, exp->loc))
+ return setError();
+
+ ethis = NULL;
+ tthis = NULL;
+
+ if (ve->hasOverloads)
+ {
+ exp->e1 = new VarExp(ve->loc, exp->f, false);
+ exp->e1->type = exp->f->type;
+ }
+ t1 = exp->f->type;
+ }
+ assert(t1->ty == Tfunction);
+
+ Expression *argprefix;
+ if (!exp->arguments)
+ exp->arguments = new Expressions();
+ if (functionParameters(exp->loc, sc, (TypeFunction *)(t1), tthis, exp->arguments, exp->f, &exp->type, &argprefix))
+ return setError();
+
+ if (!exp->type)
+ {
+ exp->e1 = e1org; // Bugzilla 10922, avoid recursive expression printing
+ exp->error("forward reference to inferred return type of function call '%s'", exp->toChars());
+ return setError();
+ }
+
+ if (exp->f && exp->f->tintro)
+ {
+ Type *t = exp->type;
+ int offset = 0;
+ TypeFunction *tf = (TypeFunction *)exp->f->tintro;
+
+ if (tf->next->isBaseOf(t, &offset) && offset)
+ {
+ exp->type = tf->next;
+ result = Expression::combine(argprefix, exp->castTo(sc, t));
+ return;
+ }
+ }
+
+ // Handle the case of a direct lambda call
+ if (exp->f && exp->f->isFuncLiteralDeclaration() &&
+ sc->func && !sc->intypeof)
+ {
+ exp->f->tookAddressOf = 0;
+ }
+
+ result = Expression::combine(argprefix, exp);
+ }
+
+ void visit(AddrExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ int wasCond = exp->e1->op == TOKquestion;
+ if (exp->e1->op == TOKdotti)
+ {
+ DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)exp->e1;
+ TemplateInstance *ti = dti->ti;
+ {
+ //assert(ti->needsTypeInference(sc));
+ ti->semantic(sc);
+ if (!ti->inst || ti->errors) // if template failed to expand
+ return setError();
+ Dsymbol *s = ti->toAlias();
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f)
+ {
+ exp->e1 = new DotVarExp(exp->e1->loc, dti->e1, f);
+ exp->e1 = semantic(exp->e1, sc);
+ }
+ }
+ }
+ else if (exp->e1->op == TOKscope)
+ {
+ TemplateInstance *ti = ((ScopeExp *)exp->e1)->sds->isTemplateInstance();
+ if (ti)
+ {
+ //assert(ti->needsTypeInference(sc));
+ ti->semantic(sc);
+ if (!ti->inst || ti->errors) // if template failed to expand
+ return setError();
+ Dsymbol *s = ti->toAlias();
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f)
+ {
+ exp->e1 = new VarExp(exp->e1->loc, f);
+ exp->e1 = semantic(exp->e1, sc);
+ }
+ }
+ }
+ exp->e1 = exp->e1->toLvalue(sc, NULL);
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (checkNonAssignmentArrayOp(exp->e1))
+ return setError();
+
+ if (!exp->e1->type)
+ {
+ exp->error("cannot take address of %s", exp->e1->toChars());
+ return setError();
+ }
+
+ bool hasOverloads = false;
+ if (FuncDeclaration *f = isFuncAddress(exp, &hasOverloads))
+ {
+ if (!hasOverloads && f->checkForwardRef(exp->loc))
+ return setError();
+ }
+ else if (!exp->e1->type->deco)
+ {
+ if (exp->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)exp->e1;
+ Declaration *d = ve->var;
+ exp->error("forward reference to %s %s", d->kind(), d->toChars());
+ }
+ else
+ exp->error("forward reference to %s", exp->e1->toChars());
+ return setError();
+ }
+
+ exp->type = exp->e1->type->pointerTo();
+
+ // See if this should really be a delegate
+ if (exp->e1->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp *)exp->e1;
+ FuncDeclaration *f = dve->var->isFuncDeclaration();
+ if (f)
+ {
+ f = f->toAliasFunc(); // FIXME, should see overloads - Bugzilla 1983
+ if (!dve->hasOverloads)
+ f->tookAddressOf++;
+
+ Expression *e;
+ if (f->needThis())
+ e = new DelegateExp(exp->loc, dve->e1, f, dve->hasOverloads);
+ else // It is a function pointer. Convert &v.f() --> (v, &V.f())
+ e = new CommaExp(exp->loc, dve->e1, new AddrExp(exp->loc, new VarExp(exp->loc, f, dve->hasOverloads)));
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+
+ // Look for misaligned pointer in @safe mode
+ if (checkUnsafeAccess(sc, dve, !exp->type->isMutable(), true))
+ return setError();
+
+ if (dve->e1->op == TOKvar && global.params.vsafe)
+ {
+ VarExp *ve = (VarExp *)dve->e1;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v)
+ {
+ if (!checkAddressVar(sc, exp, v))
+ return setError();
+ }
+ }
+ else if ((dve->e1->op == TOKthis || dve->e1->op == TOKsuper) && global.params.vsafe)
+ {
+ ThisExp *ve = (ThisExp *)dve->e1;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v && v->storage_class & STCref)
+ {
+ if (!checkAddressVar(sc, exp, v))
+ return setError();
+ }
+ }
+ }
+ else if (exp->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)exp->e1;
+
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v)
+ {
+ if (!checkAddressVar(sc, exp, v))
+ return setError();
+
+ ve->checkPurity(sc, v);
+ }
+
+ FuncDeclaration *f = ve->var->isFuncDeclaration();
+ if (f)
+ {
+ /* Because nested functions cannot be overloaded,
+ * mark here that we took its address because castTo()
+ * may not be called with an exact match.
+ */
+ if (!ve->hasOverloads || f->isNested())
+ f->tookAddressOf++;
+ if (f->isNested())
+ {
+ if (f->isFuncLiteralDeclaration())
+ {
+ if (!f->FuncDeclaration::isNested())
+ {
+ /* Supply a 'null' for a this pointer if no this is available
+ */
+ Expression *e = new DelegateExp(exp->loc, new NullExp(exp->loc, Type::tnull), f, ve->hasOverloads);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ }
+ Expression *e = new DelegateExp(exp->loc, exp->e1, f, ve->hasOverloads);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ if (f->needThis())
+ {
+ if (hasThis(sc))
+ {
+ /* Should probably supply 'this' after overload resolution,
+ * not before.
+ */
+ Expression *ethis = new ThisExp(exp->loc);
+ Expression *e = new DelegateExp(exp->loc, ethis, f, ve->hasOverloads);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ if (sc->func && !sc->intypeof)
+ {
+ if (sc->func->setUnsafe())
+ {
+ exp->error("'this' reference necessary to take address of member %s in @safe function %s",
+ f->toChars(), sc->func->toChars());
+ }
+ }
+ }
+ }
+ }
+ else if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && global.params.vsafe)
+ {
+ ThisExp *ve = (ThisExp *)exp->e1;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v)
+ {
+ if (!checkAddressVar(sc, exp, v))
+ return setError();
+ }
+ }
+ else if (exp->e1->op == TOKcall)
+ {
+ CallExp *ce = (CallExp *)exp->e1;
+ if (ce->e1->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)ce->e1->type;
+ if (tf->isref && sc->func && !sc->intypeof && sc->func->setUnsafe())
+ {
+ exp->error("cannot take address of ref return of %s() in @safe function %s",
+ ce->e1->toChars(), sc->func->toChars());
+ }
+ }
+ }
+ else if (exp->e1->op == TOKindex)
+ {
+ /* For:
+ * int[3] a;
+ * &a[i]
+ * check 'a' the same as for a regular variable
+ */
+ IndexExp *ei = (IndexExp *)exp->e1;
+ Type *tyi = ei->e1->type->toBasetype();
+ if (tyi->ty == Tsarray && ei->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)ei->e1;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ if (v)
+ {
+ if (!checkAddressVar(sc, exp, v))
+ return setError();
+
+ ve->checkPurity(sc, v);
+ }
+ }
+ }
+ else if (wasCond)
+ {
+ /* a ? b : c was transformed to *(a ? &b : &c), but we still
+ * need to do safety checks
+ */
+ assert(exp->e1->op == TOKstar);
+ PtrExp *pe = (PtrExp *)exp->e1;
+ assert(pe->e1->op == TOKquestion);
+ CondExp *ce = (CondExp *)pe->e1;
+ assert(ce->e1->op == TOKaddress);
+ assert(ce->e2->op == TOKaddress);
+
+ // Re-run semantic on the address expressions only
+ ce->e1->type = NULL;
+ ce->e1 = semantic(ce->e1, sc);
+ ce->e2->type = NULL;
+ ce->e2 = semantic(ce->e2, sc);
+ }
+
+ result = exp->optimize(WANTvalue);
+ }
+
+ void visit(PtrExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type *tb = exp->e1->type->toBasetype();
+ switch (tb->ty)
+ {
+ case Tpointer:
+ exp->type = ((TypePointer *)tb)->next;
+ break;
+
+ case Tsarray:
+ case Tarray:
+ exp->error("using * on an array is no longer supported; use *(%s).ptr instead", exp->e1->toChars());
+ exp->type = ((TypeArray *)tb)->next;
+ exp->e1 = exp->e1->castTo(sc, exp->type->pointerTo());
+ break;
+
+ default:
+ exp->error("can only * a pointer, not a '%s'", exp->e1->type->toChars());
+ /* fall through */
+
+ case Terror:
+ return setError();
+ }
+ if (exp->checkValue())
+ return setError();
+
+ result = exp;
+ }
+
+ void visit(NegExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ exp->type = exp->e1->type;
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp->e1))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (!Target::isVectorOpSupported(tb, exp->op))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if (exp->e1->checkNoBool())
+ return setError();
+ if (exp->e1->checkArithmetic())
+ return setError();
+
+ result = exp;
+ }
+
+ void visit(UAddExp *exp)
+ {
+ assert(!exp->type);
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if (exp->e1->checkNoBool())
+ return setError();
+ if (exp->e1->checkArithmetic())
+ return setError();
+
+ result = exp->e1;
+ }
+
+ void visit(ComExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ exp->type = exp->e1->type;
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp->e1))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (!Target::isVectorOpSupported(tb, exp->op))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if (exp->e1->checkNoBool())
+ return setError();
+ if (exp->e1->checkIntegral())
+ return setError();
+
+ result = exp;
+ }
+
+ void visit(NotExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ setNoderefOperand(e);
+
+ // Note there is no operator overload
+ if (Expression *ex = unaSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e->e1->op == TOKtype)
+ e->e1 = resolveAliasThis(sc, e->e1);
+
+ e->e1 = resolveProperties(sc, e->e1);
+ e->e1 = e->e1->toBoolean(sc);
+ if (e->e1->type == Type::terror)
+ {
+ result = e->e1;
+ return;
+ }
+
+ if (!Target::isVectorOpSupported(e->e1->type->toBasetype(), e->op))
+ {
+ result = e->incompatibleTypes();
+ return;
+ }
+ // Bugzilla 13910: Today NotExp can take an array as its operand.
+ if (checkNonAssignmentArrayOp(e->e1))
+ return setError();
+
+ e->type = Type::tbool;
+ result = e;
+ }
+
+ void visit(DeleteExp *exp)
+ {
+ if (Expression *ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp->e1 = resolveProperties(sc, exp->e1);
+ exp->e1 = exp->e1->modifiableLvalue(sc, NULL);
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ exp->type = Type::tvoid;
+
+ AggregateDeclaration *ad = NULL;
+ Type *tb = exp->e1->type->toBasetype();
+ switch (tb->ty)
+ { case Tclass:
+ {
+ ClassDeclaration *cd = ((TypeClass *)tb)->sym;
+
+ if (cd->isCOMinterface())
+ { /* Because COM classes are deleted by IUnknown.Release()
+ */
+ exp->error("cannot delete instance of COM interface %s", cd->toChars());
+ return setError();
+ }
+
+ ad = cd;
+ break;
+ }
+ case Tpointer:
+ tb = ((TypePointer *)tb)->next->toBasetype();
+ if (tb->ty == Tstruct)
+ {
+ ad = ((TypeStruct *)tb)->sym;
+ FuncDeclaration *f = ad->aggDelete;
+ FuncDeclaration *fd = ad->dtor;
+
+ if (!f)
+ {
+ semanticTypeInfo(sc, tb);
+ break;
+ }
+
+ /* Construct:
+ * ea = copy e1 to a tmp to do side effects only once
+ * eb = call destructor
+ * ec = call deallocator
+ */
+ Expression *ea = NULL;
+ Expression *eb = NULL;
+ Expression *ec = NULL;
+ VarDeclaration *v = NULL;
+
+ if (fd && f)
+ {
+ v = copyToTemp(0, "__tmpea", exp->e1);
+ v->semantic(sc);
+ ea = new DeclarationExp(exp->loc, v);
+ ea->type = v->type;
+ }
+
+ if (fd)
+ {
+ Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1;
+ e = new DotVarExp(Loc(), e, fd, false);
+ eb = new CallExp(exp->loc, e);
+ eb = semantic(eb, sc);
+ }
+
+ if (f)
+ {
+ Type *tpv = Type::tvoid->pointerTo();
+ Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1->castTo(sc, tpv);
+ e = new CallExp(exp->loc, new VarExp(exp->loc, f, false), e);
+ ec = semantic(e, sc);
+ }
+ ea = Expression::combine(ea, eb);
+ ea = Expression::combine(ea, ec);
+ assert(ea);
+ result = ea;
+ return;
+ }
+ break;
+
+ case Tarray:
+ {
+ Type *tv = tb->nextOf()->baseElemOf();
+ if (tv->ty == Tstruct)
+ {
+ ad = ((TypeStruct *)tv)->sym;
+ if (ad->dtor)
+ semanticTypeInfo(sc, ad->type);
+ }
+ break;
+ }
+ default:
+ exp->error("cannot delete type %s", exp->e1->type->toChars());
+ return setError();
+ }
+
+ bool err = false;
+ if (ad)
+ {
+ if (ad->dtor)
+ {
+ err |= exp->checkPurity(sc, ad->dtor);
+ err |= exp->checkSafety(sc, ad->dtor);
+ err |= exp->checkNogc(sc, ad->dtor);
+ }
+ if (ad->aggDelete && tb->ty != Tarray)
+ {
+ err |= exp->checkPurity(sc, ad->aggDelete);
+ err |= exp->checkSafety(sc, ad->aggDelete);
+ err |= exp->checkNogc(sc, ad->aggDelete);
+ }
+ if (err)
+ return setError();
+ }
+
+ if (!sc->intypeof && sc->func &&
+ !exp->isRAII &&
+ sc->func->setUnsafe())
+ {
+ exp->error("%s is not @safe but is used in @safe function %s", exp->toChars(), sc->func->toChars());
+ err = true;
+ }
+ if (err)
+ return setError();
+
+ result = exp;
+ }
+
+ void visit(CastExp *exp)
+ {
+ //static int x; assert(++x < 10);
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (exp->to)
+ {
+ exp->to = exp->to->semantic(exp->loc, sc);
+ if (exp->to == Type::terror)
+ return setError();
+
+ if (!exp->to->hasPointers())
+ setNoderefOperand(exp);
+
+ // When e1 is a template lambda, this cast may instantiate it with
+ // the type 'to'.
+ exp->e1 = inferType(exp->e1, exp->to);
+ }
+
+ if (Expression *ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e1x = resolveProperties(sc, exp->e1);
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ if (e1x->checkType())
+ return setError();
+ exp->e1 = e1x;
+
+ if (!exp->e1->type)
+ {
+ exp->error("cannot cast %s", exp->e1->toChars());
+ return setError();
+ }
+
+ if (!exp->to) // Handle cast(const) and cast(immutable), etc.
+ {
+ exp->to = exp->e1->type->castMod(exp->mod);
+ exp->to = exp->to->semantic(exp->loc, sc);
+ if (exp->to == Type::terror)
+ return setError();
+ }
+
+ if (exp->to->ty == Ttuple)
+ {
+ exp->error("cannot cast %s to tuple type %s", exp->e1->toChars(), exp->to->toChars());
+ return setError();
+ }
+ if (exp->e1->type->ty != Tvoid ||
+ (exp->e1->op == TOKfunction && exp->to->ty == Tvoid) ||
+ exp->e1->op == TOKtype ||
+ exp->e1->op == TOKtemplate)
+ {
+ if (exp->e1->checkValue())
+ return setError();
+ }
+
+ // cast(void) is used to mark e1 as unused, so it is safe
+ if (exp->to->ty == Tvoid)
+ {
+ exp->type = exp->to;
+ result = exp;
+ return;
+ }
+
+ if (!exp->to->equals(exp->e1->type) && exp->mod == (unsigned char)~0)
+ {
+ if (Expression *e = exp->op_overload(sc))
+ {
+ result = e->implicitCastTo(sc, exp->to);
+ return;
+ }
+ }
+
+ Type *t1b = exp->e1->type->toBasetype();
+ Type *tob = exp->to->toBasetype();
+
+ if (tob->ty == Tstruct && !tob->equals(t1b))
+ {
+ /* Look to replace:
+ * cast(S)t
+ * with:
+ * S(t)
+ */
+
+ // Rewrite as to.call(e1)
+ Expression *e = new TypeExp(exp->loc, exp->to);
+ e = new CallExp(exp->loc, e, exp->e1);
+ e = trySemantic(e, sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+
+ if (!t1b->equals(tob) && (t1b->ty == Tarray || t1b->ty == Tsarray))
+ {
+ if (checkNonAssignmentArrayOp(exp->e1))
+ return setError();
+ }
+
+ // Look for casting to a vector type
+ if (tob->ty == Tvector && t1b->ty != Tvector)
+ {
+ result = new VectorExp(exp->loc, exp->e1, exp->to);
+ return;
+ }
+
+ Expression *ex = exp->e1->castTo(sc, exp->to);
+ if (ex->op == TOKerror)
+ {
+ result = ex;
+ return;
+ }
+
+ // Check for unsafe casts
+ if (sc->func && !sc->intypeof &&
+ !isSafeCast(ex, t1b, tob) &&
+ sc->func->setUnsafe())
+ {
+ exp->error("cast from %s to %s not allowed in safe code", exp->e1->type->toChars(), exp->to->toChars());
+ return setError();
+ }
+
+ result = ex;
+ }
+
+ void visit(VectorExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp->e1 = semantic(exp->e1, sc);
+ exp->type = exp->to->semantic(exp->loc, sc);
+ if (exp->e1->op == TOKerror || exp->type->ty == Terror)
+ {
+ result = exp->e1;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ assert(tb->ty == Tvector);
+ TypeVector *tv = (TypeVector *)tb;
+ Type *te = tv->elementType();
+ exp->dim = (int)(tv->size(exp->loc) / te->size(exp->loc));
+
+ exp->e1 = exp->e1->optimize(WANTvalue);
+ bool res = false;
+ if (exp->e1->op == TOKarrayliteral)
+ {
+ for (size_t i = 0; i < exp->dim; i++)
+ {
+ // Do not stop on first error - check all AST nodes even if error found
+ res |= checkVectorElem(exp, ((ArrayLiteralExp *)exp->e1)->getElement(i));
+ }
+ }
+ else if (exp->e1->type->ty == Tvoid)
+ res = checkVectorElem(exp, exp->e1);
+
+ Expression *e = exp;
+ if (res)
+ e = new ErrorExp();
+ result = e;
+ }
+
+ void visit(SliceExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ // operator overloading should be handled in ArrayExp already.
+
+ if (Expression *ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp->e1 = resolveProperties(sc, exp->e1);
+ if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
+ {
+ if (exp->lwr || exp->upr)
+ {
+ exp->error("cannot slice type '%s'", exp->e1->toChars());
+ return setError();
+ }
+ Expression *e = new TypeExp(exp->loc, exp->e1->type->arrayOf());
+ result = semantic(e, sc);
+ return;
+ }
+ if (!exp->lwr && !exp->upr)
+ {
+ if (exp->e1->op == TOKarrayliteral)
+ {
+ // Convert [a,b,c][] to [a,b,c]
+ Type *t1b = exp->e1->type->toBasetype();
+ Expression *e = exp->e1;
+ if (t1b->ty == Tsarray)
+ {
+ e = e->copy();
+ e->type = t1b->nextOf()->arrayOf();
+ }
+ result = e;
+ return;
+ }
+ if (exp->e1->op == TOKslice)
+ {
+ // Convert e[][] to e[]
+ SliceExp *se = (SliceExp *)exp->e1;
+ if (!se->lwr && !se->upr)
+ {
+ result = se;
+ return;
+ }
+ }
+ if (isArrayOpOperand(exp->e1))
+ {
+ // Convert (a[]+b[])[] to a[]+b[]
+ result = exp->e1;
+ return;
+ }
+ }
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (exp->e1->type->ty == Terror)
+ return setError();
+
+ Type *t1b = exp->e1->type->toBasetype();
+ if (t1b->ty == Tpointer)
+ {
+ if (((TypePointer *)t1b)->next->ty == Tfunction)
+ {
+ exp->error("cannot slice function pointer %s", exp->e1->toChars());
+ return setError();
+ }
+ if (!exp->lwr || !exp->upr)
+ {
+ exp->error("need upper and lower bound to slice pointer");
+ return setError();
+ }
+ if (sc->func && !sc->intypeof && sc->func->setUnsafe())
+ {
+ exp->error("pointer slicing not allowed in safe functions");
+ return setError();
+ }
+ }
+ else if (t1b->ty == Tarray)
+ {
+ }
+ else if (t1b->ty == Tsarray)
+ {
+ if (!exp->arrayop && global.params.vsafe)
+ {
+ /* Slicing a static array is like taking the address of it.
+ * Perform checks as if e[] was &e
+ */
+ VarDeclaration *v = NULL;
+ if (exp->e1->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp *)exp->e1;
+ if (dve->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)dve->e1;
+ v = ve->var->isVarDeclaration();
+ }
+ else if (dve->e1->op == TOKthis || dve->e1->op == TOKsuper)
+ {
+ ThisExp *ve = (ThisExp *)dve->e1;
+ v = ve->var->isVarDeclaration();
+ if (v && !(v->storage_class & STCref))
+ v = NULL;
+ }
+ }
+ else if (exp->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)exp->e1;
+ v = ve->var->isVarDeclaration();
+ }
+ else if (exp->e1->op == TOKthis || exp->e1->op == TOKsuper)
+ {
+ ThisExp *ve = (ThisExp *)exp->e1;
+ v = ve->var->isVarDeclaration();
+ }
+
+ if (v)
+ {
+ if (!checkAddressVar(sc, exp, v))
+ return setError();
+ }
+ }
+ }
+ else if (t1b->ty == Ttuple)
+ {
+ if (!exp->lwr && !exp->upr)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (!exp->lwr || !exp->upr)
+ {
+ exp->error("need upper and lower bound to slice tuple");
+ return setError();
+ }
+ }
+ else if (t1b->ty == Tvector)
+ {
+ // Convert e1 to corresponding static array
+ TypeVector *tv1 = (TypeVector *)t1b;
+ t1b = tv1->basetype;
+ t1b = t1b->castMod(tv1->mod);
+ exp->e1->type = t1b;
+ }
+ else
+ {
+ exp->error("%s cannot be sliced with []",
+ t1b->ty == Tvoid ? exp->e1->toChars() : t1b->toChars());
+ return setError();
+ }
+
+ /* Run semantic on lwr and upr.
+ */
+ Scope *scx = sc;
+ if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
+ {
+ // Create scope for 'length' variable
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
+ sym->loc = exp->loc;
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+ }
+ if (exp->lwr)
+ {
+ if (t1b->ty == Ttuple) sc = sc->startCTFE();
+ exp->lwr = semantic(exp->lwr, sc);
+ exp->lwr = resolveProperties(sc, exp->lwr);
+ if (t1b->ty == Ttuple) sc = sc->endCTFE();
+ exp->lwr = exp->lwr->implicitCastTo(sc, Type::tsize_t);
+ }
+ if (exp->upr)
+ {
+ if (t1b->ty == Ttuple) sc = sc->startCTFE();
+ exp->upr = semantic(exp->upr, sc);
+ exp->upr = resolveProperties(sc, exp->upr);
+ if (t1b->ty == Ttuple) sc = sc->endCTFE();
+ exp->upr = exp->upr->implicitCastTo(sc, Type::tsize_t);
+ }
+ if (sc != scx)
+ sc = sc->pop();
+ if ((exp->lwr && exp->lwr->type == Type::terror) ||
+ (exp->upr && exp->upr->type == Type::terror))
+ {
+ return setError();
+ }
+
+ if (t1b->ty == Ttuple)
+ {
+ exp->lwr = exp->lwr->ctfeInterpret();
+ exp->upr = exp->upr->ctfeInterpret();
+ uinteger_t i1 = exp->lwr->toUInteger();
+ uinteger_t i2 = exp->upr->toUInteger();
+
+ TupleExp *te;
+ TypeTuple *tup;
+ size_t length;
+ if (exp->e1->op == TOKtuple) // slicing an expression tuple
+ {
+ te = (TupleExp *)exp->e1;
+ tup = NULL;
+ length = te->exps->dim;
+ }
+ else if (exp->e1->op == TOKtype) // slicing a type tuple
+ {
+ te = NULL;
+ tup = (TypeTuple *)t1b;
+ length = Parameter::dim(tup->arguments);
+ }
+ else
+ assert(0);
+
+ if (i2 < i1 || length < i2)
+ {
+ exp->error("string slice [%llu .. %llu] is out of bounds", i1, i2);
+ return setError();
+ }
+
+ size_t j1 = (size_t) i1;
+ size_t j2 = (size_t) i2;
+ Expression *e;
+ if (exp->e1->op == TOKtuple)
+ {
+ Expressions *exps = new Expressions;
+ exps->setDim(j2 - j1);
+ for (size_t i = 0; i < j2 - j1; i++)
+ {
+ (*exps)[i] = (*te->exps)[j1 + i];
+ }
+ e = new TupleExp(exp->loc, te->e0, exps);
+ }
+ else
+ {
+ Parameters *args = new Parameters;
+ args->reserve(j2 - j1);
+ for (size_t i = j1; i < j2; i++)
+ {
+ Parameter *arg = Parameter::getNth(tup->arguments, i);
+ args->push(arg);
+ }
+ e = new TypeExp(exp->e1->loc, new TypeTuple(args));
+ }
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+
+ exp->type = t1b->nextOf()->arrayOf();
+ // Allow typedef[] -> typedef[]
+ if (exp->type->equals(t1b))
+ exp->type = exp->e1->type;
+
+ if (exp->lwr && exp->upr)
+ {
+ exp->lwr = exp->lwr->optimize(WANTvalue);
+ exp->upr = exp->upr->optimize(WANTvalue);
+
+ IntRange lwrRange = getIntRange(exp->lwr);
+ IntRange uprRange = getIntRange(exp->upr);
+
+ if (t1b->ty == Tsarray || t1b->ty == Tarray)
+ {
+ Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
+ el = semantic(el, sc);
+ el = el->optimize(WANTvalue);
+ if (el->op == TOKint64)
+ {
+ dinteger_t length = el->toInteger();
+ IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length));
+ exp->upperIsInBounds = bounds.contains(uprRange);
+ }
+ }
+ else if (t1b->ty == Tpointer)
+ {
+ exp->upperIsInBounds = true;
+ }
+ else
+ assert(0);
+
+ exp->lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
+
+ //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", upperIsInBounds, lowerIsLessThanUpper);
+ }
+
+ result = exp;
+ }
+
+ void visit(ArrayLengthExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression *ex = unaSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ e->e1 = resolveProperties(sc, e->e1);
+
+ e->type = Type::tsize_t;
+ result = e;
+ }
+
+ void visit(IntervalExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ Expression *le = e->lwr;
+ le = semantic(le, sc);
+ le = resolveProperties(sc, le);
+
+ Expression *ue = e->upr;
+ ue = semantic(ue, sc);
+ ue = resolveProperties(sc, ue);
+
+ if (le->op == TOKerror)
+ {
+ result = le;
+ return;
+ }
+ if (ue->op == TOKerror)
+ {
+ result = ue;
+ return;
+ }
+
+ e->lwr = le;
+ e->upr = ue;
+
+ e->type = Type::tvoid;
+ result = e;
+ }
+
+ void visit(DelegatePtrExp *e)
+ {
+ if (!e->type)
+ {
+ unaSemantic(e, sc);
+ e->e1 = resolveProperties(sc, e->e1);
+
+ if (e->e1->op == TOKerror)
+ {
+ result = e->e1;
+ return;
+ }
+ e->type = Type::tvoidptr;
+ }
+ result = e;
+ }
+
+ void visit(DelegateFuncptrExp *e)
+ {
+ if (!e->type)
+ {
+ unaSemantic(e, sc);
+ e->e1 = resolveProperties(sc, e->e1);
+
+ if (e->e1->op == TOKerror)
+ {
+ result = e->e1;
+ return;
+ }
+ e->type = e->e1->type->nextOf()->pointerTo();
+ }
+ result = e;
+ }
+
+ void visit(ArrayExp *exp)
+ {
+ assert(!exp->type);
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (isAggregate(exp->e1->type))
+ exp->error("no [] operator overload for type %s", exp->e1->type->toChars());
+ else
+ exp->error("only one index allowed to index %s", exp->e1->type->toChars());
+ return setError();
+ }
+
+ void visit(DotExp *exp)
+ {
+ exp->e1 = semantic(exp->e1, sc);
+ exp->e2 = semantic(exp->e2, sc);
+
+ if (exp->e1->op == TOKtype)
+ {
+ result = exp->e2;
+ return;
+ }
+ if (exp->e2->op == TOKtype)
+ {
+ result = exp->e2;
+ return;
+ }
+ if (exp->e2->op == TOKtemplate)
+ {
+ TemplateDeclaration *td = ((TemplateExp *)exp->e2)->td;
+ Expression *e = new DotTemplateExp(exp->loc, exp->e1, td);
+ result = semantic(e, sc);
+ return;
+ }
+ if (!exp->type)
+ exp->type = exp->e2->type;
+ result = exp;
+ }
+
+ void visit(CommaExp *e)
+ {
+ if (e->type)
+ {
+ result = e;
+ return;
+ }
+
+ // Allow `((a,b),(x,y))`
+ if (e->allowCommaExp)
+ {
+ if (e->e1 && e->e1->op == TOKcomma)
+ ((CommaExp *)e->e1)->allowCommaExp = true;
+ if (e->e2 && e->e2->op == TOKcomma)
+ ((CommaExp *)e->e2)->allowCommaExp = true;
+ }
+
+ if (Expression *ex = binSemanticProp(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ e->e1 = e->e1->addDtorHook(sc);
+
+ if (checkNonAssignmentArrayOp(e->e1))
+ return setError();
+
+ e->type = e->e2->type;
+ if (e->type != Type::tvoid && !e->allowCommaExp && !e->isGenerated)
+ e->deprecation("Using the result of a comma expression is deprecated");
+ result = e;
+ }
+
+ void visit(IndexExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ // operator overloading should be handled in ArrayExp already.
+
+ if (!exp->e1->type)
+ exp->e1 = semantic(exp->e1, sc);
+ assert(exp->e1->type); // semantic() should already be run on it
+ if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
+ {
+ exp->e2 = semantic(exp->e2, sc);
+ exp->e2 = resolveProperties(sc, exp->e2);
+ Type *nt;
+ if (exp->e2->op == TOKtype)
+ nt = new TypeAArray(exp->e1->type, exp->e2->type);
+ else
+ nt = new TypeSArray(exp->e1->type, exp->e2);
+ Expression *e = new TypeExp(exp->loc, nt);
+ result = semantic(e, sc);
+ return;
+ }
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (exp->e1->type->ty == Terror)
+ return setError();
+
+ // Note that unlike C we do not implement the int[ptr]
+
+ Type *t1b = exp->e1->type->toBasetype();
+
+ if (t1b->ty == Tvector)
+ {
+ // Convert e1 to corresponding static array
+ TypeVector *tv1 = (TypeVector *)t1b;
+ t1b = tv1->basetype;
+ t1b = t1b->castMod(tv1->mod);
+ exp->e1->type = t1b;
+ }
+
+ /* Run semantic on e2
+ */
+ Scope *scx = sc;
+ if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
+ {
+ // Create scope for 'length' variable
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
+ sym->loc = exp->loc;
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+ }
+ if (t1b->ty == Ttuple) sc = sc->startCTFE();
+ exp->e2 = semantic(exp->e2, sc);
+ exp->e2 = resolveProperties(sc, exp->e2);
+ if (t1b->ty == Ttuple) sc = sc->endCTFE();
+ if (exp->e2->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)exp->e2;
+ if (te->exps && te->exps->dim == 1)
+ exp->e2 = Expression::combine(te->e0, (*te->exps)[0]); // bug 4444 fix
+ }
+ if (sc != scx)
+ sc = sc->pop();
+ if (exp->e2->type == Type::terror)
+ return setError();
+
+ if (checkNonAssignmentArrayOp(exp->e1))
+ return setError();
+
+ switch (t1b->ty)
+ {
+ case Tpointer:
+ if (((TypePointer *)t1b)->next->ty == Tfunction)
+ {
+ exp->error("cannot index function pointer %s", exp->e1->toChars());
+ return setError();
+ }
+ exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+ if (exp->e2->type == Type::terror)
+ return setError();
+ exp->e2 = exp->e2->optimize(WANTvalue);
+ if (exp->e2->op == TOKint64 && exp->e2->toInteger() == 0)
+ ;
+ else if (sc->func && sc->func->setUnsafe())
+ {
+ exp->error("safe function '%s' cannot index pointer '%s'",
+ sc->func->toPrettyChars(), exp->e1->toChars());
+ return setError();
+ }
+ exp->type = ((TypeNext *)t1b)->next;
+ break;
+
+ case Tarray:
+ exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+ if (exp->e2->type == Type::terror)
+ return setError();
+ exp->type = ((TypeNext *)t1b)->next;
+ break;
+
+ case Tsarray:
+ {
+ exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+ if (exp->e2->type == Type::terror)
+ return setError();
+ exp->type = t1b->nextOf();
+ break;
+ }
+
+ case Taarray:
+ {
+ TypeAArray *taa = (TypeAArray *)t1b;
+ /* We can skip the implicit conversion if they differ only by
+ * constness (Bugzilla 2684, see also bug 2954b)
+ */
+ if (!arrayTypeCompatibleWithoutCasting(exp->e2->type, taa->index))
+ {
+ exp->e2 = exp->e2->implicitCastTo(sc, taa->index); // type checking
+ if (exp->e2->type == Type::terror)
+ return setError();
+ }
+
+ semanticTypeInfo(sc, taa);
+
+ exp->type = taa->next;
+ break;
+ }
+
+ case Ttuple:
+ {
+ exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
+ if (exp->e2->type == Type::terror)
+ return setError();
+ exp->e2 = exp->e2->ctfeInterpret();
+ uinteger_t index = exp->e2->toUInteger();
+
+ TupleExp *te;
+ TypeTuple *tup;
+ size_t length;
+ if (exp->e1->op == TOKtuple)
+ {
+ te = (TupleExp *)exp->e1;
+ tup = NULL;
+ length = te->exps->dim;
+ }
+ else if (exp->e1->op == TOKtype)
+ {
+ te = NULL;
+ tup = (TypeTuple *)t1b;
+ length = Parameter::dim(tup->arguments);
+ }
+ else
+ assert(0);
+
+ if (length <= index)
+ {
+ exp->error("array index [%llu] is outside array bounds [0 .. %llu]",
+ index, (ulonglong)length);
+ return setError();
+ }
+
+ Expression *e;
+ if (exp->e1->op == TOKtuple)
+ {
+ e = (*te->exps)[(size_t)index];
+ e = Expression::combine(te->e0, e);
+ }
+ else
+ e = new TypeExp(exp->e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type);
+ result = e;
+ return;
+ }
+
+ default:
+ exp->error("%s must be an array or pointer type, not %s",
+ exp->e1->toChars(), exp->e1->type->toChars());
+ return setError();
+ }
+
+ if (t1b->ty == Tsarray || t1b->ty == Tarray)
+ {
+ Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
+ el = semantic(el, sc);
+ el = el->optimize(WANTvalue);
+ if (el->op == TOKint64)
+ {
+ exp->e2 = exp->e2->optimize(WANTvalue);
+ dinteger_t length = el->toInteger();
+ if (length)
+ {
+ IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length - 1));
+ exp->indexIsInBounds = bounds.contains(getIntRange(exp->e2));
+ }
+ }
+ }
+
+ result = exp;
+ }
+
+ void visit(PostExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e1x = resolveProperties(sc, exp->e1);
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ exp->e1 = e1x;
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->e1->checkReadModifyWrite(exp->op))
+ return setError();
+ if (exp->e1->op == TOKslice)
+ {
+ const char *s = exp->op == TOKplusplus ? "increment" : "decrement";
+ exp->error("cannot post-%s array slice '%s', use pre-%s instead", s, exp->e1->toChars(), s);
+ return setError();
+ }
+
+ exp->e1 = exp->e1->optimize(WANTvalue);
+
+ Type *t1 = exp->e1->type->toBasetype();
+ if (t1->ty == Tclass || t1->ty == Tstruct || exp->e1->op == TOKarraylength)
+ {
+ /* Check for operator overloading,
+ * but rewrite in terms of ++e instead of e++
+ */
+
+ /* If e1 is not trivial, take a reference to it
+ */
+ Expression *de = NULL;
+ if (exp->e1->op != TOKvar && exp->e1->op != TOKarraylength)
+ {
+ // ref v = e1;
+ VarDeclaration *v = copyToTemp(STCref, "__postref", exp->e1);
+ de = new DeclarationExp(exp->loc, v);
+ exp->e1 = new VarExp(exp->e1->loc, v);
+ }
+
+ /* Rewrite as:
+ * auto tmp = e1; ++e1; tmp
+ */
+ VarDeclaration *tmp = copyToTemp(0, "__pitmp", exp->e1);
+ Expression *ea = new DeclarationExp(exp->loc, tmp);
+
+ Expression *eb = exp->e1->syntaxCopy();
+ eb = new PreExp(exp->op == TOKplusplus ? TOKpreplusplus : TOKpreminusminus, exp->loc, eb);
+
+ Expression *ec = new VarExp(exp->loc, tmp);
+
+ // Combine de,ea,eb,ec
+ if (de)
+ ea = new CommaExp(exp->loc, de, ea);
+ e = new CommaExp(exp->loc, ea, eb);
+ e = new CommaExp(exp->loc, e, ec);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+
+ exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+
+ e = exp;
+ if (exp->e1->checkScalar())
+ return setError();
+ if (exp->e1->checkNoBool())
+ return setError();
+
+ if (exp->e1->type->ty == Tpointer)
+ e = scaleFactor(exp, sc);
+ else
+ exp->e2 = exp->e2->castTo(sc, exp->e1->type);
+ e->type = exp->e1->type;
+ result = e;
+ }
+
+ void visit(PreExp *exp)
+ {
+ Expression *e = exp->op_overload(sc);
+ // printf("PreExp::semantic('%s')\n", exp->toChars());
+
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ // Rewrite as e1+=1 or e1-=1
+ if (exp->op == TOKpreplusplus)
+ e = new AddAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
+ else
+ e = new MinAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
+ result = semantic(e, sc);
+ }
+
+ void visit(AssignExp *exp)
+ {
+ //printf("e1->op = %d, '%s'\n", exp->e1->op, Token::toChars(exp->e1->op));
+ //printf("e2->op = %d, '%s'\n", exp->e2->op, Token::toChars(exp->e2->op));
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression *e1old = exp->e1;
+
+ if (exp->e2->op == TOKcomma)
+ {
+ /* Rewrite to get rid of the comma from rvalue
+ */
+ if (!((CommaExp *)exp->e2)->isGenerated)
+ exp->deprecation("Using the result of a comma expression is deprecated");
+ Expression *e0;
+ exp->e2 = Expression::extractLast(exp->e2, &e0);
+ Expression *e = Expression::combine(e0, exp);
+ result = semantic(e, sc);
+ return;
+ }
+
+ /* Look for operator overloading of a[arguments] = e2.
+ * Do it before e1->semantic() otherwise the ArrayExp will have been
+ * converted to unary operator overloading already.
+ */
+ if (exp->e1->op == TOKarray)
+ {
+ Expression *res;
+
+ ArrayExp *ae = (ArrayExp *)exp->e1;
+ ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = resolveProperties(sc, ae->e1);
+ Expression *ae1old = ae->e1;
+
+ const bool maybeSlice =
+ (ae->arguments->dim == 0 ||
+ (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval));
+ IntervalExp *ie = NULL;
+ if (maybeSlice && ae->arguments->dim)
+ {
+ assert((*ae->arguments)[0]->op == TOKinterval);
+ ie = (IntervalExp *)(*ae->arguments)[0];
+ }
+
+ while (true)
+ {
+ if (ae->e1->op == TOKerror)
+ {
+ result = ae->e1;
+ return;
+ }
+ Expression *e0 = NULL;
+ Expression *ae1save = ae->e1;
+ ae->lengthVar = NULL;
+
+ Type *t1b = ae->e1->type->toBasetype();
+ AggregateDeclaration *ad = isAggregate(t1b);
+ if (!ad)
+ break;
+ if (search_function(ad, Id::indexass))
+ {
+ // Deal with $
+ res = resolveOpDollar(sc, ae, &e0);
+ if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
+ goto Lfallback;
+ if (res->op == TOKerror)
+ {
+ result = res;
+ return;
+ }
+
+ res = semantic(exp->e2, sc);
+ if (res->op == TOKerror)
+ {
+ result = res;
+ return;
+ }
+ exp->e2 = res;
+
+ /* Rewrite (a[arguments] = e2) as:
+ * a.opIndexAssign(e2, arguments)
+ */
+ Expressions *a = (Expressions *)ae->arguments->copy();
+ a->insert(0, exp->e2);
+ res = new DotIdExp(exp->loc, ae->e1, Id::indexass);
+ res = new CallExp(exp->loc, res, a);
+ if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
+ res = trySemantic(res, sc);
+ else
+ res = semantic(res, sc);
+ if (res)
+ {
+ res = Expression::combine(e0, res);
+ result = res;
+ return;
+ }
+ }
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id::sliceass))
+ {
+ // Deal with $
+ res = resolveOpDollar(sc, ae, ie, &e0);
+ if (res->op == TOKerror)
+ {
+ result = res;
+ return;
+ }
+
+ res = semantic(exp->e2, sc);
+ if (res->op == TOKerror)
+ {
+ result = res;
+ return;
+ }
+ exp->e2 = res;
+
+ /* Rewrite (a[i..j] = e2) as:
+ * a.opSliceAssign(e2, i, j)
+ */
+ Expressions *a = new Expressions();
+ a->push(exp->e2);
+ if (ie)
+ {
+ a->push(ie->lwr);
+ a->push(ie->upr);
+ }
+ res = new DotIdExp(exp->loc, ae->e1, Id::sliceass);
+ res = new CallExp(exp->loc, res, a);
+ res = semantic(res, sc);
+ res = Expression::combine(e0, res);
+ result = res;
+ return;
+ }
+
+ // No operator overloading member function found yet, but
+ // there might be an alias this to try.
+ if (ad->aliasthis && t1b != ae->att1)
+ {
+ if (!ae->att1 && t1b->checkAliasThisRec())
+ ae->att1 = t1b;
+
+ /* Rewrite (a[arguments] op e2) as:
+ * a.aliasthis[arguments] op e2
+ */
+ ae->e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae->e1)
+ continue;
+ }
+ break;
+ }
+ ae->e1 = ae1old; // recovery
+ ae->lengthVar = NULL;
+ }
+
+ /* Run exp->e1 semantic.
+ */
+ {
+ Expression *e1x = exp->e1;
+
+ /* With UFCS, e.f = value
+ * Could mean:
+ * .f(e, value)
+ * or:
+ * .f(e) = value
+ */
+ if (e1x->op == TOKdotti)
+ {
+ DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)e1x;
+ Expression *e = semanticY(dti, sc, 1);
+ if (!e)
+ {
+ result = resolveUFCSProperties(sc, e1x, exp->e2);
+ return;
+ }
+ e1x = e;
+ }
+ else if (e1x->op == TOKdotid)
+ {
+ DotIdExp *die = (DotIdExp *)e1x;
+ Expression *e = semanticY(die, sc, 1);
+ if (e && isDotOpDispatch(e))
+ {
+ unsigned errors = global.startGagging();
+ e = resolvePropertiesX(sc, e, exp->e2);
+ if (global.endGagging(errors))
+ e = NULL; /* fall down to UFCS */
+ else
+ {
+ result = e;
+ return;
+ }
+ }
+ if (!e)
+ {
+ result = resolveUFCSProperties(sc, e1x, exp->e2);
+ return;
+ }
+ e1x = e;
+ }
+ else
+ {
+ if (e1x->op == TOKslice)
+ ((SliceExp *)e1x)->arrayop = true;
+
+ e1x = semantic(e1x, sc);
+ }
+
+ /* We have f = value.
+ * Could mean:
+ * f(value)
+ * or:
+ * f() = value
+ */
+ if (Expression *e = resolvePropertiesX(sc, e1x, exp->e2))
+ {
+ result = e;
+ return;
+ }
+ if (e1x->checkRightThis(sc))
+ return setError();
+ exp->e1 = e1x;
+ assert(exp->e1->type);
+ }
+ Type *t1 = exp->e1->type->toBasetype();
+
+ /* Run exp->e2 semantic.
+ * Different from other binary expressions, the analysis of e2
+ * depends on the result of e1 in assignments.
+ */
+ {
+ Expression *e2x = inferType(exp->e2, t1->baseElemOf());
+
+ e2x = semantic(e2x, sc);
+ e2x = resolveProperties(sc, e2x);
+
+ if (e2x->op == TOKtype)
+ e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+ if (e2x->checkValue())
+ return setError();
+ exp->e2 = e2x;
+ }
+
+ /* Rewrite tuple assignment as a tuple of assignments.
+ */
+ {
+ Expression *e2x = exp->e2;
+
+ Ltupleassign:
+ if (exp->e1->op == TOKtuple && e2x->op == TOKtuple)
+ {
+ TupleExp *tup1 = (TupleExp *)exp->e1;
+ TupleExp *tup2 = (TupleExp *)e2x;
+ size_t dim = tup1->exps->dim;
+ Expression *e = NULL;
+ if (dim != tup2->exps->dim)
+ {
+ exp->error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim);
+ return setError();
+ }
+ if (dim == 0)
+ {
+ e = new IntegerExp(exp->loc, 0, Type::tint32);
+ e = new CastExp(exp->loc, e, Type::tvoid); // avoid "has no effect" error
+ e = Expression::combine(Expression::combine(tup1->e0, tup2->e0), e);
+ }
+ else
+ {
+ Expressions *exps = new Expressions;
+ exps->setDim(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression *ex1 = (*tup1->exps)[i];
+ Expression *ex2 = (*tup2->exps)[i];
+ (*exps)[i] = new AssignExp(exp->loc, ex1, ex2);
+ }
+ e = new TupleExp(exp->loc, Expression::combine(tup1->e0, tup2->e0), exps);
+ }
+ result = semantic(e, sc);
+ return;
+ }
+
+ /* Look for form: e1 = e2->aliasthis.
+ */
+ if (exp->e1->op == TOKtuple)
+ {
+ TupleDeclaration *td = isAliasThisTuple(e2x);
+ if (!td)
+ goto Lnomatch;
+
+ assert(exp->e1->type->ty == Ttuple);
+ TypeTuple *tt = (TypeTuple *)exp->e1->type;
+
+ Expression *e0 = NULL;
+ Expression *ev = extractSideEffect(sc, "__tup", &e0, e2x);
+
+ Expressions *iexps = new Expressions();
+ iexps->push(ev);
+
+ for (size_t u = 0; u < iexps->dim ; u++)
+ {
+ Lexpand:
+ Expression *e = (*iexps)[u];
+
+ Parameter *arg = Parameter::getNth(tt->arguments, u);
+ //printf("[%d] iexps->dim = %d, ", u, iexps->dim);
+ //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
+ //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
+
+ if (!arg || !e->type->implicitConvTo(arg->type))
+ {
+ // expand initializer to tuple
+ if (expandAliasThisTuples(iexps, u) != -1)
+ {
+ if (iexps->dim <= u)
+ break;
+ goto Lexpand;
+ }
+ goto Lnomatch;
+ }
+ }
+ e2x = new TupleExp(e2x->loc, e0, iexps);
+ e2x = semantic(e2x, sc);
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+ // Do not need to overwrite exp->e2
+ goto Ltupleassign;
+ }
+ Lnomatch:
+ ;
+ }
+
+ /* Inside constructor, if this is the first assignment of object field,
+ * rewrite this to initializing the field.
+ */
+ if (exp->op == TOKassign && exp->e1->checkModifiable(sc) == 2)
+ {
+ //printf("[%s] change to init - %s\n", exp->loc.toChars(), toChars());
+ exp->op = TOKconstruct;
+
+ // Bugzilla 13515: set Index::modifiable flag for complex AA element initialization
+ if (exp->e1->op == TOKindex)
+ {
+ Expression *e1x = ((IndexExp *)exp->e1)->markSettingAAElem();
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ }
+ }
+ else if (exp->op == TOKconstruct && exp->e1->op == TOKvar &&
+ ((VarExp *)exp->e1)->var->storage_class & (STCout | STCref))
+ {
+ exp->memset |= referenceInit;
+ }
+
+ /* If it is an assignment from a 'foreign' type,
+ * check for operator overloading.
+ */
+ if (exp->memset & referenceInit)
+ {
+ // If this is an initialization of a reference,
+ // do nothing
+ }
+ else if (t1->ty == Tstruct)
+ {
+ Expression *e1x = exp->e1;
+ Expression *e2x = exp->e2;
+ StructDeclaration *sd = ((TypeStruct *)t1)->sym;
+
+ if (exp->op == TOKconstruct)
+ {
+ Type *t2 = e2x->type->toBasetype();
+ if (t2->ty == Tstruct && sd == ((TypeStruct *)t2)->sym)
+ {
+ sd->size(exp->loc);
+ if (sd->sizeok != SIZEOKdone)
+ return setError();
+ if (!sd->ctor)
+ sd->ctor = sd->searchCtor();
+
+ // Bugzilla 15661: Look for the form from last of comma chain.
+ Expression *e2y = e2x;
+ while (e2y->op == TOKcomma)
+ e2y = ((CommaExp *)e2y)->e2;
+
+ CallExp *ce = (e2y->op == TOKcall) ? (CallExp *)e2y : NULL;
+ DotVarExp *dve = (ce && ce->e1->op == TOKdotvar)
+ ? (DotVarExp *)ce->e1 : NULL;
+ if (sd->ctor && ce && dve && dve->var->isCtorDeclaration() &&
+ e2y->type->implicitConvTo(t1))
+ {
+ /* Look for form of constructor call which is:
+ * __ctmp.ctor(arguments...)
+ */
+
+ /* Before calling the constructor, initialize
+ * variable with a bit copy of the default
+ * initializer
+ */
+ AssignExp *ae = exp;
+ if (sd->zeroInit == 1 && !sd->isNested())
+ {
+ // Bugzilla 14606: Always use BlitExp for the special expression: (struct = 0)
+ ae = new BlitExp(ae->loc, ae->e1, new IntegerExp(exp->loc, 0, Type::tint32));
+ }
+ else
+ {
+ // Keep ae->op == TOKconstruct
+ ae->e2 = sd->isNested() ? t1->defaultInitLiteral(exp->loc) : t1->defaultInit(exp->loc);
+ }
+ ae->type = e1x->type;
+
+ /* Replace __ctmp being constructed with e1.
+ * We need to copy constructor call expression,
+ * because it may be used in other place.
+ */
+ DotVarExp *dvx = (DotVarExp *)dve->copy();
+ dvx->e1 = e1x;
+ CallExp *cx = (CallExp *)ce->copy();
+ cx->e1 = dvx;
+
+ Expression *e0;
+ Expression::extractLast(e2x, &e0);
+
+ Expression *e = Expression::combine(ae, cx);
+ e = Expression::combine(e0, e);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ if (sd->postblit)
+ {
+ /* We have a copy constructor for this
+ */
+ if (e2x->op == TOKquestion)
+ {
+ /* Rewrite as:
+ * a ? e1 = b : e1 = c;
+ */
+ CondExp *econd = (CondExp *)e2x;
+ Expression *ea1 = new ConstructExp(econd->e1->loc, e1x, econd->e1);
+ Expression *ea2 = new ConstructExp(econd->e1->loc, e1x, econd->e2);
+ Expression *e = new CondExp(exp->loc, econd->econd, ea1, ea2);
+ result = semantic(e, sc);
+ return;
+ }
+
+ if (e2x->isLvalue())
+ {
+ if (!e2x->type->implicitConvTo(e1x->type))
+ {
+ exp->error("conversion error from %s to %s", e2x->type->toChars(), e1x->type->toChars());
+ return setError();
+ }
+
+ /* Rewrite as:
+ * (e1 = e2).postblit();
+ *
+ * Blit assignment e1 = e2 returns a reference to the original e1,
+ * then call the postblit on it.
+ */
+ Expression *e = e1x->copy();
+ e->type = e->type->mutableOf();
+ e = new BlitExp(exp->loc, e, e2x);
+ e = new DotVarExp(exp->loc, e, sd->postblit, false);
+ e = new CallExp(exp->loc, e);
+ result = semantic(e, sc);
+ return;
+ }
+ else
+ {
+ /* The struct value returned from the function is transferred
+ * so should not call the destructor on it.
+ */
+ e2x = valueNoDtor(e2x);
+ }
+ }
+ }
+ else if (!e2x->implicitConvTo(t1))
+ {
+ sd->size(exp->loc);
+ if (sd->sizeok != SIZEOKdone)
+ return setError();
+ if (!sd->ctor)
+ sd->ctor = sd->searchCtor();
+
+ if (sd->ctor)
+ {
+ /* Look for implicit constructor call
+ * Rewrite as:
+ * e1 = init, e1.ctor(e2)
+ */
+ Expression *einit;
+ einit = new BlitExp(exp->loc, e1x, e1x->type->defaultInit(exp->loc));
+ einit->type = e1x->type;
+
+ Expression *e;
+ e = new DotIdExp(exp->loc, e1x, Id::ctor);
+ e = new CallExp(exp->loc, e, e2x);
+ e = new CommaExp(exp->loc, einit, e);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ if (search_function(sd, Id::call))
+ {
+ /* Look for static opCall
+ * (See bugzilla 2702 for more discussion)
+ * Rewrite as:
+ * e1 = typeof(e1).opCall(arguments)
+ */
+ e2x = typeDotIdExp(e2x->loc, e1x->type, Id::call);
+ e2x = new CallExp(exp->loc, e2x, exp->e2);
+
+ e2x = semantic(e2x, sc);
+ e2x = resolveProperties(sc, e2x);
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+ if (e2x->checkValue())
+ return setError();
+ }
+ }
+ else // Bugzilla 11355
+ {
+ AggregateDeclaration *ad2 = isAggregate(e2x->type);
+ if (ad2 && ad2->aliasthis && !(exp->att2 && e2x->type == exp->att2))
+ {
+ if (!exp->att2 && exp->e2->type->checkAliasThisRec())
+ exp->att2 = exp->e2->type;
+
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ exp->e2 = new DotIdExp(exp->e2->loc, exp->e2, ad2->aliasthis->ident);
+ result = semantic(exp, sc);
+ return;
+ }
+ }
+ }
+ else if (exp->op == TOKassign)
+ {
+ if (e1x->op == TOKindex &&
+ ((IndexExp *)e1x)->e1->type->toBasetype()->ty == Taarray)
+ {
+ /*
+ * Rewrite:
+ * aa[key] = e2;
+ * as:
+ * ref __aatmp = aa;
+ * ref __aakey = key;
+ * ref __aaval = e2;
+ * (__aakey in __aatmp
+ * ? __aatmp[__aakey].opAssign(__aaval)
+ * : ConstructExp(__aatmp[__aakey], __aaval));
+ */
+ IndexExp *ie = (IndexExp *)e1x;
+ Type *t2 = e2x->type->toBasetype();
+
+ Expression *e0 = NULL;
+ Expression *ea = extractSideEffect(sc, "__aatmp", &e0, ie->e1);
+ Expression *ek = extractSideEffect(sc, "__aakey", &e0, ie->e2);
+ Expression *ev = extractSideEffect(sc, "__aaval", &e0, e2x);
+
+ AssignExp *ae = (AssignExp *)exp->copy();
+ ae->e1 = new IndexExp(exp->loc, ea, ek);
+ ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = ae->e1->optimize(WANTvalue);
+ ae->e2 = ev;
+ Expression *e = ae->op_overload(sc);
+ if (e)
+ {
+ Expression *ey = NULL;
+ if (t2->ty == Tstruct && sd == t2->toDsymbol(sc))
+ {
+ ey = ev;
+ }
+ else if (!ev->implicitConvTo(ie->type) && sd->ctor)
+ {
+ // Look for implicit constructor call
+ // Rewrite as S().ctor(e2)
+ ey = new StructLiteralExp(exp->loc, sd, NULL);
+ ey = new DotIdExp(exp->loc, ey, Id::ctor);
+ ey = new CallExp(exp->loc, ey, ev);
+ ey = trySemantic(ey, sc);
+ }
+ if (ey)
+ {
+ Expression *ex;
+ ex = new IndexExp(exp->loc, ea, ek);
+ ex = semantic(ex, sc);
+ ex = ex->optimize(WANTvalue);
+ ex = ex->modifiableLvalue(sc, ex); // allocate new slot
+ ey = new ConstructExp(exp->loc, ex, ey);
+ ey = semantic(ey, sc);
+ if (ey->op == TOKerror)
+ {
+ result = ey;
+ return;
+ }
+ ex = e;
+
+ // Bugzilla 14144: The whole expression should have the common type
+ // of opAssign() return and assigned AA entry.
+ // Even if there's no common type, expression should be typed as void.
+ Type *t = NULL;
+ if (!typeMerge(sc, TOKquestion, &t, &ex, &ey))
+ {
+ ex = new CastExp(ex->loc, ex, Type::tvoid);
+ ey = new CastExp(ey->loc, ey, Type::tvoid);
+ }
+ e = new CondExp(exp->loc, new InExp(exp->loc, ek, ea), ex, ey);
+ }
+ e = Expression::combine(e0, e);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ }
+ else
+ {
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ }
+ else
+ assert(exp->op == TOKblit);
+
+ exp->e1 = e1x;
+ exp->e2 = e2x;
+ }
+ else if (t1->ty == Tclass)
+ {
+ // Disallow assignment operator overloads for same type
+ if (exp->op == TOKassign && !exp->e2->implicitConvTo(exp->e1->type))
+ {
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ }
+ else if (t1->ty == Tsarray)
+ {
+ // SliceExp cannot have static array type without context inference.
+ assert(exp->e1->op != TOKslice);
+
+ Expression *e1x = exp->e1;
+ Expression *e2x = exp->e2;
+
+ if (e2x->implicitConvTo(e1x->type))
+ {
+ if (exp->op != TOKblit &&
+ ((e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue()) ||
+ (e2x->op == TOKcast && ((UnaExp *)e2x)->e1->isLvalue()) ||
+ (e2x->op != TOKslice && e2x->isLvalue())))
+ {
+ if (e1x->checkPostblit(sc, t1))
+ return setError();
+ }
+
+ // e2 matches to t1 because of the implicit length match, so
+ if (isUnaArrayOp(e2x->op) || isBinArrayOp(e2x->op))
+ {
+ // convert e1 to e1[]
+ // e.g. e1[] = a[] + b[];
+ SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
+ sle->arrayop = true;
+ e1x = semantic(sle, sc);
+ }
+ else
+ {
+ // convert e2 to t1 later
+ // e.g. e1 = [1, 2, 3];
+ }
+ }
+ else
+ {
+ if (e2x->implicitConvTo(t1->nextOf()->arrayOf()) > MATCHnomatch)
+ {
+ uinteger_t dim1 = ((TypeSArray *)t1)->dim->toInteger();
+ uinteger_t dim2 = dim1;
+ if (e2x->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)e2x;
+ dim2 = ale->elements ? ale->elements->dim : 0;
+ }
+ else if (e2x->op == TOKslice)
+ {
+ Type *tx = toStaticArrayType((SliceExp *)e2x);
+ if (tx)
+ dim2 = ((TypeSArray *)tx)->dim->toInteger();
+ }
+ if (dim1 != dim2)
+ {
+ exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
+ return setError();
+ }
+ }
+
+ // May be block or element-wise assignment, so
+ // convert e1 to e1[]
+ if (exp->op != TOKassign)
+ {
+ // If multidimensional static array, treat as one large array
+ dinteger_t dim = ((TypeSArray *)t1)->dim->toInteger();
+ Type *t = t1;
+ while (1)
+ {
+ t = t->nextOf()->toBasetype();
+ if (t->ty != Tsarray)
+ break;
+ dim *= ((TypeSArray *)t)->dim->toInteger();
+ e1x->type = t->nextOf()->sarrayOf(dim);
+ }
+ }
+ SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
+ sle->arrayop = true;
+ e1x = semantic(sle, sc);
+ }
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+
+ exp->e1 = e1x;
+ exp->e2 = e2x;
+ t1 = e1x->type->toBasetype();
+ }
+
+ /* Check the mutability of e1.
+ */
+ if (exp->e1->op == TOKarraylength)
+ {
+ // e1 is not an lvalue, but we let code generator handle it
+ ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
+
+ Expression *ale1x = ale->e1;
+ ale1x = ale1x->modifiableLvalue(sc, exp->e1);
+ if (ale1x->op == TOKerror)
+ {
+ result = ale1x;
+ return;
+ }
+ ale->e1 = ale1x;
+
+ Type *tn = ale->e1->type->toBasetype()->nextOf();
+ checkDefCtor(ale->loc, tn);
+ semanticTypeInfo(sc, tn);
+ }
+ else if (exp->e1->op == TOKslice)
+ {
+ Type *tn = exp->e1->type->nextOf();
+ if (exp->op == TOKassign && !tn->isMutable())
+ {
+ exp->error("slice %s is not mutable", exp->e1->toChars());
+ return setError();
+ }
+
+ // For conditional operator, both branches need conversion.
+ SliceExp *se = (SliceExp *)exp->e1;
+ while (se->e1->op == TOKslice)
+ se = (SliceExp *)se->e1;
+ if (se->e1->op == TOKquestion &&
+ se->e1->type->toBasetype()->ty == Tsarray)
+ {
+ se->e1 = se->e1->modifiableLvalue(sc, exp->e1);
+ if (se->e1->op == TOKerror)
+ {
+ result = se->e1;
+ return;
+ }
+ }
+ }
+ else
+ {
+ Expression *e1x = exp->e1;
+
+ // Try to do a decent error message with the expression
+ // before it got constant folded
+ if (e1x->op != TOKvar)
+ e1x = e1x->optimize(WANTvalue);
+
+ if (exp->op == TOKassign)
+ e1x = e1x->modifiableLvalue(sc, e1old);
+
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ exp->e1 = e1x;
+ }
+
+ /* Tweak e2 based on the type of e1.
+ */
+ Expression *e2x = exp->e2;
+ Type *t2 = e2x->type->toBasetype();
+
+ // If it is a array, get the element type. Note that it may be
+ // multi-dimensional.
+ Type *telem = t1;
+ while (telem->ty == Tarray)
+ telem = telem->nextOf();
+
+ if (exp->e1->op == TOKslice &&
+ t1->nextOf() && (telem->ty != Tvoid || e2x->op == TOKnull) &&
+ e2x->implicitConvTo(t1->nextOf())
+ )
+ {
+ // Check for block assignment. If it is of type void[], void[][], etc,
+ // '= null' is the only allowable block assignment (Bug 7493)
+ // memset
+ exp->memset |= blockAssign; // make it easy for back end to tell what this is
+ e2x = e2x->implicitCastTo(sc, t1->nextOf());
+ if (exp->op != TOKblit && e2x->isLvalue() &&
+ exp->e1->checkPostblit(sc, t1->nextOf()))
+ return setError();
+ }
+ else if (exp->e1->op == TOKslice &&
+ (t2->ty == Tarray || t2->ty == Tsarray) &&
+ t2->nextOf()->implicitConvTo(t1->nextOf()))
+ {
+ // Check element-wise assignment.
+
+ /* If assigned elements number is known at compile time,
+ * check the mismatch.
+ */
+ SliceExp *se1 = (SliceExp *)exp->e1;
+ TypeSArray *tsa1 = (TypeSArray *)toStaticArrayType(se1);
+ TypeSArray *tsa2 = NULL;
+ if (e2x->op == TOKarrayliteral)
+ tsa2 = (TypeSArray *)t2->nextOf()->sarrayOf(((ArrayLiteralExp *)e2x)->elements->dim);
+ else if (e2x->op == TOKslice)
+ tsa2 = (TypeSArray *)toStaticArrayType((SliceExp *)e2x);
+ else if (t2->ty == Tsarray)
+ tsa2 = (TypeSArray *)t2;
+ if (tsa1 && tsa2)
+ {
+ uinteger_t dim1 = tsa1->dim->toInteger();
+ uinteger_t dim2 = tsa2->dim->toInteger();
+ if (dim1 != dim2)
+ {
+ exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
+ return setError();
+ }
+ }
+
+ if (exp->op != TOKblit &&
+ ((e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue()) ||
+ (e2x->op == TOKcast && ((UnaExp *)e2x)->e1->isLvalue()) ||
+ (e2x->op != TOKslice && e2x->isLvalue())))
+ {
+ if (exp->e1->checkPostblit(sc, t1->nextOf()))
+ return setError();
+ }
+
+ if (0 && global.params.warnings != DIAGNOSTICoff && !global.gag && exp->op == TOKassign &&
+ e2x->op != TOKslice && e2x->op != TOKassign &&
+ e2x->op != TOKarrayliteral && e2x->op != TOKstring &&
+ !(e2x->op == TOKadd || e2x->op == TOKmin ||
+ e2x->op == TOKmul || e2x->op == TOKdiv ||
+ e2x->op == TOKmod || e2x->op == TOKxor ||
+ e2x->op == TOKand || e2x->op == TOKor ||
+ e2x->op == TOKpow ||
+ e2x->op == TOKtilde || e2x->op == TOKneg))
+ {
+ const char* e1str = exp->e1->toChars();
+ const char* e2str = e2x->toChars();
+ exp->warning("explicit element-wise assignment %s = (%s)[] is better than %s = %s",
+ e1str, e2str, e1str, e2str);
+ }
+
+ Type *t2n = t2->nextOf();
+ Type *t1n = t1->nextOf();
+ int offset;
+ if (t2n->equivalent(t1n) ||
+ (t1n->isBaseOf(t2n, &offset) && offset == 0))
+ {
+ /* Allow copy of distinct qualifier elements.
+ * eg.
+ * char[] dst; const(char)[] src;
+ * dst[] = src;
+ *
+ * class C {} class D : C {}
+ * C[2] ca; D[] da;
+ * ca[] = da;
+ */
+ if (isArrayOpValid(e2x))
+ {
+ // Don't add CastExp to keep AST for array operations
+ e2x = e2x->copy();
+ e2x->type = exp->e1->type->constOf();
+ }
+ else
+ e2x = e2x->castTo(sc, exp->e1->type->constOf());
+ }
+ else
+ {
+ /* Bugzilla 15778: A string literal has an array type of immutable
+ * elements by default, and normally it cannot be convertible to
+ * array type of mutable elements. But for element-wise assignment,
+ * elements need to be const at best. So we should give a chance
+ * to change code unit size for polysemous string literal.
+ */
+ if (e2x->op == TOKstring)
+ e2x = e2x->implicitCastTo(sc, exp->e1->type->constOf());
+ else
+ e2x = e2x->implicitCastTo(sc, exp->e1->type);
+ }
+ if (t1n->toBasetype()->ty == Tvoid && t2n->toBasetype()->ty == Tvoid)
+ {
+ if (!sc->intypeof && sc->func && sc->func->setUnsafe())
+ {
+ exp->error("cannot copy void[] to void[] in @safe code");
+ return setError();
+ }
+ }
+ }
+ else
+ {
+ if (0 && global.params.warnings != DIAGNOSTICoff && !global.gag && exp->op == TOKassign &&
+ t1->ty == Tarray && t2->ty == Tsarray &&
+ e2x->op != TOKslice &&
+ t2->implicitConvTo(t1))
+ { // Disallow ar[] = sa (Converted to ar[] = sa[])
+ // Disallow da = sa (Converted to da = sa[])
+ const char* e1str = exp->e1->toChars();
+ const char* e2str = e2x->toChars();
+ const char* atypestr = exp->e1->op == TOKslice ? "element-wise" : "slice";
+ exp->warning("explicit %s assignment %s = (%s)[] is better than %s = %s",
+ atypestr, e1str, e2str, e1str, e2str);
+ }
+ if (exp->op == TOKblit)
+ e2x = e2x->castTo(sc, exp->e1->type);
+ else
+ e2x = e2x->implicitCastTo(sc, exp->e1->type);
+ }
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+ exp->e2 = e2x;
+ t2 = exp->e2->type->toBasetype();
+
+ /* Look for array operations
+ */
+ if ((t2->ty == Tarray || t2->ty == Tsarray) && isArrayOpValid(exp->e2))
+ {
+ // Look for valid array operations
+ if (!(exp->memset & blockAssign) && exp->e1->op == TOKslice &&
+ (isUnaArrayOp(exp->e2->op) || isBinArrayOp(exp->e2->op)))
+ {
+ exp->type = exp->e1->type;
+ if (exp->op == TOKconstruct) // Bugzilla 10282: tweak mutability of e1 element
+ exp->e1->type = exp->e1->type->nextOf()->mutableOf()->arrayOf();
+ result = arrayOp(exp, sc);
+ return;
+ }
+
+ // Drop invalid array operations in e2
+ // d = a[] + b[], d = (a[] + b[])[0..2], etc
+ if (checkNonAssignmentArrayOp(exp->e2, !(exp->memset & blockAssign) && exp->op == TOKassign))
+ return setError();
+
+ // Remains valid array assignments
+ // d = d[], d = [1,2,3], etc
+ }
+
+ /* Don't allow assignment to classes that were allocated on the stack with:
+ * scope Class c = new Class();
+ */
+
+ if (exp->e1->op == TOKvar && exp->op == TOKassign)
+ {
+ VarExp *ve = (VarExp *)exp->e1;
+ VarDeclaration *vd = ve->var->isVarDeclaration();
+ if (vd && (vd->onstack || vd->mynew))
+ {
+ assert(t1->ty == Tclass);
+ exp->error("cannot rebind scope variables");
+ }
+ }
+ if (exp->e1->op == TOKvar && ((VarExp *)exp->e1)->var->ident == Id::ctfe)
+ {
+ exp->error("cannot modify compiler-generated variable __ctfe");
+ }
+
+ exp->type = exp->e1->type;
+ assert(exp->type);
+ Expression *res = exp->op == TOKassign ? exp->reorderSettingAAElem(sc) : exp;
+ checkAssignEscape(sc, res, false);
+ result = res;
+ }
+
+ void visit(CatAssignExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ //printf("CatAssignExp::semantic() %s\n", toChars());
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->e1->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *)exp->e1;
+ if (se->e1->type->toBasetype()->ty == Tsarray)
+ {
+ exp->error("cannot append to static array %s", se->e1->type->toChars());
+ return setError();
+ }
+ }
+
+ exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+ if (exp->e1->op == TOKerror)
+ {
+ result = exp->e1;
+ return;
+ }
+ if (exp->e2->op == TOKerror)
+ {
+ result = exp->e2;
+ return;
+ }
+
+ if (checkNonAssignmentArrayOp(exp->e2))
+ return setError();
+
+ Type *tb1 = exp->e1->type->toBasetype();
+ Type *tb1next = tb1->nextOf();
+ Type *tb2 = exp->e2->type->toBasetype();
+
+ if ((tb1->ty == Tarray) &&
+ (tb2->ty == Tarray || tb2->ty == Tsarray) &&
+ (exp->e2->implicitConvTo(exp->e1->type)
+ || (tb2->nextOf()->implicitConvTo(tb1next) &&
+ (tb2->nextOf()->size(Loc()) == tb1next->size(Loc())))
+ )
+ )
+ {
+ // Append array
+ if (exp->e1->checkPostblit(sc, tb1next))
+ return setError();
+ exp->e2 = exp->e2->castTo(sc, exp->e1->type);
+ }
+ else if ((tb1->ty == Tarray) &&
+ exp->e2->implicitConvTo(tb1next)
+ )
+ {
+ // Append element
+ if (exp->e2->checkPostblit(sc, tb2))
+ return setError();
+ exp->e2 = exp->e2->castTo(sc, tb1next);
+ exp->e2 = doCopyOrMove(sc, exp->e2);
+ }
+ else if (tb1->ty == Tarray &&
+ (tb1next->ty == Tchar || tb1next->ty == Twchar) &&
+ exp->e2->type->ty != tb1next->ty &&
+ exp->e2->implicitConvTo(Type::tdchar)
+ )
+ { // Append dchar to char[] or wchar[]
+ exp->e2 = exp->e2->castTo(sc, Type::tdchar);
+
+ /* Do not allow appending wchar to char[] because if wchar happens
+ * to be a surrogate pair, nothing good can result.
+ */
+ }
+ else
+ {
+ exp->error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars());
+ return setError();
+ }
+ if (exp->e2->checkValue())
+ return setError();
+
+ exp->type = exp->e1->type;
+ result = exp->reorderSettingAAElem(sc);
+ }
+
+ void visit(PowAssignExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
+ return setError();
+
+ assert(exp->e1->type && exp->e2->type);
+ if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
+ {
+ // T[] ^^= ...
+ if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
+ {
+ // T[] ^^= T
+ exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
+ }
+ else if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ // Check element types are arithmetic
+ Type *tb1 = exp->e1->type->nextOf()->toBasetype();
+ Type *tb2 = exp->e2->type->toBasetype();
+ if (tb2->ty == Tarray || tb2->ty == Tsarray)
+ tb2 = tb2->nextOf()->toBasetype();
+
+ if ( (tb1->isintegral() || tb1->isfloating()) &&
+ (tb2->isintegral() || tb2->isfloating()))
+ {
+ exp->type = exp->e1->type;
+ result = arrayOp(exp, sc);
+ return;
+ }
+ }
+ else
+ {
+ exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
+ }
+
+ if ((exp->e1->type->isintegral() || exp->e1->type->isfloating()) &&
+ (exp->e2->type->isintegral() || exp->e2->type->isfloating()))
+ {
+ Expression *e0 = NULL;
+ e = exp->reorderSettingAAElem(sc);
+ e = Expression::extractLast(e, &e0);
+ assert(e == exp);
+
+ if (exp->e1->op == TOKvar)
+ {
+ // Rewrite: e1 = e1 ^^ e2
+ e = new PowExp(exp->loc, exp->e1->syntaxCopy(), exp->e2);
+ e = new AssignExp(exp->loc, exp->e1, e);
+ }
+ else
+ {
+ // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
+ VarDeclaration *v = copyToTemp(STCref, "__powtmp", exp->e1);
+ Expression *de = new DeclarationExp(exp->e1->loc, v);
+ VarExp *ve = new VarExp(exp->e1->loc, v);
+ e = new PowExp(exp->loc, ve, exp->e2);
+ e = new AssignExp(exp->loc, new VarExp(exp->e1->loc, v), e);
+ e = new CommaExp(exp->loc, de, e);
+ }
+ e = Expression::combine(e0, e);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ result = exp->incompatibleTypes();
+ }
+
+ void visit(AddExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type *tb1 = exp->e1->type->toBasetype();
+ Type *tb2 = exp->e2->type->toBasetype();
+
+ bool err = false;
+ if (tb1->ty == Tdelegate ||
+ (tb1->ty == Tpointer && tb1->nextOf()->ty == Tfunction))
+ {
+ err |= exp->e1->checkArithmetic();
+ }
+ if (tb2->ty == Tdelegate ||
+ (tb2->ty == Tpointer && tb2->nextOf()->ty == Tfunction))
+ {
+ err |= exp->e2->checkArithmetic();
+ }
+ if (err)
+ return setError();
+
+ if ((tb1->ty == Tpointer && exp->e2->type->isintegral()) ||
+ (tb2->ty == Tpointer && exp->e1->type->isintegral()))
+ {
+ result = scaleFactor(exp, sc);
+ return;
+ }
+
+ if (tb1->ty == Tpointer && tb2->ty == Tpointer)
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ tb1 = exp->e1->type->toBasetype();
+ if (!Target::isVectorOpSupported(tb1, exp->op, tb2))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if ((tb1->isreal() && exp->e2->type->isimaginary()) ||
+ (tb1->isimaginary() && exp->e2->type->isreal()))
+ {
+ switch (exp->type->toBasetype()->ty)
+ {
+ case Tfloat32:
+ case Timaginary32:
+ exp->type = Type::tcomplex32;
+ break;
+
+ case Tfloat64:
+ case Timaginary64:
+ exp->type = Type::tcomplex64;
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ exp->type = Type::tcomplex80;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ result = exp;
+ }
+
+ void visit(MinExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type *t1 = exp->e1->type->toBasetype();
+ Type *t2 = exp->e2->type->toBasetype();
+
+ bool err = false;
+ if (t1->ty == Tdelegate ||
+ (t1->ty == Tpointer && t1->nextOf()->ty == Tfunction))
+ {
+ err |= exp->e1->checkArithmetic();
+ }
+ if (t2->ty == Tdelegate ||
+ (t2->ty == Tpointer && t2->nextOf()->ty == Tfunction))
+ {
+ err |= exp->e2->checkArithmetic();
+ }
+ if (err)
+ return setError();
+
+ if (t1->ty == Tpointer)
+ {
+ if (t2->ty == Tpointer)
+ {
+ // Need to divide the result by the stride
+ // Replace (ptr - ptr) with (ptr - ptr) / stride
+ d_int64 stride;
+
+ // make sure pointer types are compatible
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ exp->type = Type::tptrdiff_t;
+ stride = t2->nextOf()->size();
+ if (stride == 0)
+ {
+ e = new IntegerExp(exp->loc, 0, Type::tptrdiff_t);
+ }
+ else
+ {
+ e = new DivExp(exp->loc, exp, new IntegerExp(Loc(), stride, Type::tptrdiff_t));
+ e->type = Type::tptrdiff_t;
+ }
+ }
+ else if (t2->isintegral())
+ e = scaleFactor(exp, sc);
+ else
+ {
+ exp->error("can't subtract %s from pointer", t2->toChars());
+ e = new ErrorExp();
+ }
+ result = e;
+ return;
+ }
+ if (t2->ty == Tpointer)
+ {
+ exp->type = exp->e2->type;
+ exp->error("can't subtract pointer from %s", exp->e1->type->toChars());
+ return setError();
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ t1 = exp->e1->type->toBasetype();
+ t2 = exp->e2->type->toBasetype();
+ if (!Target::isVectorOpSupported(t1, exp->op, t2))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if ((t1->isreal() && t2->isimaginary()) ||
+ (t1->isimaginary() && t2->isreal()))
+ {
+ switch (exp->type->ty)
+ {
+ case Tfloat32:
+ case Timaginary32:
+ exp->type = Type::tcomplex32;
+ break;
+
+ case Tfloat64:
+ case Timaginary64:
+ exp->type = Type::tcomplex64;
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ exp->type = Type::tcomplex80;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ result = exp;
+ }
+
+ void visit(CatExp *exp)
+ {
+ //printf("CatExp::semantic() %s\n", exp->toChars());
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type *tb1 = exp->e1->type->toBasetype();
+ Type *tb2 = exp->e2->type->toBasetype();
+
+ bool f1 = checkNonAssignmentArrayOp(exp->e1);
+ bool f2 = checkNonAssignmentArrayOp(exp->e2);
+ if (f1 || f2)
+ return setError();
+
+ /* BUG: Should handle things like:
+ * char c;
+ * c ~ ' '
+ * ' ' ~ c;
+ */
+ Type *tb1next = tb1->nextOf();
+ Type *tb2next = tb2->nextOf();
+
+ // Check for: array ~ array
+ if (tb1next && tb2next &&
+ (tb1next->implicitConvTo(tb2next) >= MATCHconst ||
+ tb2next->implicitConvTo(tb1next) >= MATCHconst ||
+ (exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2)) ||
+ (exp->e2->op == TOKarrayliteral && exp->e2->implicitConvTo(tb1))
+ )
+ )
+ {
+ /* Bugzilla 9248: Here to avoid the case of:
+ * void*[] a = [cast(void*)1];
+ * void*[] b = [cast(void*)2];
+ * a ~ b;
+ * becoming:
+ * a ~ [cast(void*)b];
+ */
+
+ /* Bugzilla 14682: Also to avoid the case of:
+ * int[][] a;
+ * a ~ [];
+ * becoming:
+ * a ~ cast(int[])[];
+ */
+ goto Lpeer;
+ }
+
+ // Check for: array ~ element
+ if ((tb1->ty == Tsarray || tb1->ty == Tarray) && tb2->ty != Tvoid)
+ {
+ if (exp->e1->op == TOKarrayliteral)
+ {
+ exp->e2 = exp->e2->isLvalue() ? callCpCtor(sc, exp->e2) : valueNoDtor(exp->e2);
+ // Bugzilla 14686: Postblit call appears in AST, and this is
+ // finally translated to an ArrayLiteralExp in below otpimize().
+ }
+ else if (exp->e1->op == TOKstring)
+ {
+ // No postblit call exists on character (integer) value.
+ }
+ else
+ {
+ if (exp->e2->checkPostblit(sc, tb2))
+ return setError();
+ // Postblit call will be done in runtime helper function
+ }
+
+ if (exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2->arrayOf()))
+ {
+ exp->e1 = exp->e1->implicitCastTo(sc, tb2->arrayOf());
+ exp->type = tb2->arrayOf();
+ goto L2elem;
+ }
+ if (exp->e2->implicitConvTo(tb1next) >= MATCHconvert)
+ {
+ exp->e2 = exp->e2->implicitCastTo(sc, tb1next);
+ exp->type = tb1next->arrayOf();
+ L2elem:
+ if (tb2->ty == Tarray || tb2->ty == Tsarray)
+ {
+ // Make e2 into [e2]
+ exp->e2 = new ArrayLiteralExp(exp->e2->loc, exp->e2);
+ exp->e2->type = exp->type;
+ }
+ result = exp->optimize(WANTvalue);
+ return;
+ }
+ }
+ // Check for: element ~ array
+ if ((tb2->ty == Tsarray || tb2->ty == Tarray) && tb1->ty != Tvoid)
+ {
+ if (exp->e2->op == TOKarrayliteral)
+ {
+ exp->e1 = exp->e1->isLvalue() ? callCpCtor(sc, exp->e1) : valueNoDtor(exp->e1);
+ }
+ else if (exp->e2->op == TOKstring)
+ {
+ }
+ else
+ {
+ if (exp->e1->checkPostblit(sc, tb1))
+ return setError();
+ }
+
+ if (exp->e2->op == TOKarrayliteral && exp->e2->implicitConvTo(tb1->arrayOf()))
+ {
+ exp->e2 = exp->e2->implicitCastTo(sc, tb1->arrayOf());
+ exp->type = tb1->arrayOf();
+ goto L1elem;
+ }
+ if (exp->e1->implicitConvTo(tb2next) >= MATCHconvert)
+ {
+ exp->e1 = exp->e1->implicitCastTo(sc, tb2next);
+ exp->type = tb2next->arrayOf();
+ L1elem:
+ if (tb1->ty == Tarray || tb1->ty == Tsarray)
+ {
+ // Make e1 into [e1]
+ exp->e1 = new ArrayLiteralExp(exp->e1->loc, exp->e1);
+ exp->e1->type = exp->type;
+ }
+ result = exp->optimize(WANTvalue);
+ return;
+ }
+ }
+
+ Lpeer:
+ if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
+ (tb2->ty == Tsarray || tb2->ty == Tarray) &&
+ (tb1next->mod || tb2next->mod) &&
+ (tb1next->mod != tb2next->mod)
+ )
+ {
+ Type *t1 = tb1next->mutableOf()->constOf()->arrayOf();
+ Type *t2 = tb2next->mutableOf()->constOf()->arrayOf();
+ if (exp->e1->op == TOKstring && !((StringExp *)exp->e1)->committed)
+ exp->e1->type = t1;
+ else
+ exp->e1 = exp->e1->castTo(sc, t1);
+ if (exp->e2->op == TOKstring && !((StringExp *)exp->e2)->committed)
+ exp->e2->type = t2;
+ else
+ exp->e2 = exp->e2->castTo(sc, t2);
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp->type = exp->type->toHeadMutable();
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tsarray)
+ exp->type = tb->nextOf()->arrayOf();
+ if (exp->type->ty == Tarray && tb1next && tb2next &&
+ tb1next->mod != tb2next->mod)
+ {
+ exp->type = exp->type->nextOf()->toHeadMutable()->arrayOf();
+ }
+ if (Type *tbn = tb->nextOf())
+ {
+ if (exp->checkPostblit(sc, tbn))
+ return setError();
+ }
+ Type *t1 = exp->e1->type->toBasetype();
+ Type *t2 = exp->e2->type->toBasetype();
+ if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+ (t2->ty == Tarray || t2->ty == Tsarray))
+ {
+ // Normalize to ArrayLiteralExp or StringExp as far as possible
+ e = exp->optimize(WANTvalue);
+ }
+ else
+ {
+ //printf("(%s) ~ (%s)\n", exp->e1->toChars(), exp->e2->toChars());
+ result = exp->incompatibleTypes();
+ return;
+ }
+ result = e;
+ }
+
+ void visit(MulExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (exp->checkArithmeticBin())
+ return setError();
+
+ if (exp->type->isfloating())
+ {
+ Type *t1 = exp->e1->type;
+ Type *t2 = exp->e2->type;
+
+ if (t1->isreal())
+ {
+ exp->type = t2;
+ }
+ else if (t2->isreal())
+ {
+ exp->type = t1;
+ }
+ else if (t1->isimaginary())
+ {
+ if (t2->isimaginary())
+ {
+
+ switch (t1->toBasetype()->ty)
+ {
+ case Timaginary32:
+ exp->type = Type::tfloat32;
+ break;
+
+ case Timaginary64:
+ exp->type = Type::tfloat64;
+ break;
+
+ case Timaginary80:
+ exp->type = Type::tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ // iy * iv = -yv
+ exp->e1->type = exp->type;
+ exp->e2->type = exp->type;
+ e = new NegExp(exp->loc, exp);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ else
+ exp->type = t2; // t2 is complex
+ }
+ else if (t2->isimaginary())
+ {
+ exp->type = t1; // t1 is complex
+ }
+ }
+ else if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ result = exp;
+ }
+
+ void visit(DivExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (exp->checkArithmeticBin())
+ return setError();
+
+ if (exp->type->isfloating())
+ {
+ Type *t1 = exp->e1->type;
+ Type *t2 = exp->e2->type;
+
+ if (t1->isreal())
+ {
+ exp->type = t2;
+ if (t2->isimaginary())
+ {
+ // x/iv = i(-x/v)
+ exp->e2->type = t1;
+ e = new NegExp(exp->loc, exp);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+ }
+ else if (t2->isreal())
+ {
+ exp->type = t1;
+ }
+ else if (t1->isimaginary())
+ {
+ if (t2->isimaginary())
+ {
+ switch (t1->toBasetype()->ty)
+ {
+ case Timaginary32:
+ exp->type = Type::tfloat32;
+ break;
+
+ case Timaginary64:
+ exp->type = Type::tfloat64;
+ break;
+
+ case Timaginary80:
+ exp->type = Type::tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ else
+ exp->type = t2; // t2 is complex
+ }
+ else if (t2->isimaginary())
+ {
+ exp->type = t1; // t1 is complex
+ }
+ }
+ else if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ result = exp;
+ }
+
+ void visit(ModExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+ if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
+ if (exp->checkArithmeticBin())
+ return setError();
+
+ if (exp->type->isfloating())
+ {
+ exp->type = exp->e1->type;
+ if (exp->e2->type->iscomplex())
+ {
+ exp->error("cannot perform modulo complex arithmetic");
+ return setError();
+ }
+ }
+ result = exp;
+ }
+
+ Module *loadStdMath()
+ {
+ static Import *impStdMath = NULL;
+ if (!impStdMath)
+ {
+ Identifiers *a = new Identifiers();
+ a->push(Id::std);
+ Import *s = new Import(Loc(), a, Id::math, NULL, false);
+ s->load(NULL);
+ if (s->mod)
+ {
+ s->mod->importAll(NULL);
+ s->mod->semantic(NULL);
+ }
+ impStdMath = s;
+ }
+ return impStdMath->mod;
+ }
+
+ void visit(PowExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ //printf("PowExp::semantic() %s\n", exp->toChars());
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (exp->checkArithmeticBin())
+ return setError();
+
+ if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
+ // For built-in numeric types, there are several cases.
+ // TODO: backend support, especially for e1 ^^ 2.
+
+ // First, attempt to fold the expression.
+ e = exp->optimize(WANTvalue);
+ if (e->op != TOKpow)
+ {
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+
+ // Determine if we're raising to an integer power.
+ sinteger_t intpow = 0;
+ if (exp->e2->op == TOKint64 && ((sinteger_t)exp->e2->toInteger() == 2 || (sinteger_t)exp->e2->toInteger() == 3))
+ intpow = exp->e2->toInteger();
+ else if (exp->e2->op == TOKfloat64 && (exp->e2->toReal() == ldouble((sinteger_t)exp->e2->toReal())))
+ intpow = (sinteger_t)(exp->e2->toReal());
+
+ // Deal with x^^2, x^^3 immediately, since they are of practical importance.
+ if (intpow == 2 || intpow == 3)
+ {
+ // Replace x^^2 with (tmp = x, tmp*tmp)
+ // Replace x^^3 with (tmp = x, tmp*tmp*tmp)
+ VarDeclaration *tmp = copyToTemp(0, "__powtmp", exp->e1);
+ Expression *de = new DeclarationExp(exp->loc, tmp);
+ Expression *ve = new VarExp(exp->loc, tmp);
+
+ /* Note that we're reusing ve. This should be ok.
+ */
+ Expression *me = new MulExp(exp->loc, ve, ve);
+ if (intpow == 3)
+ me = new MulExp(exp->loc, me, ve);
+ e = new CommaExp(exp->loc, de, me);
+ e = semantic(e, sc);
+ result = e;
+ return;
+ }
+
+ Module *mmath = loadStdMath();
+ if (!mmath)
+ {
+ //exp->error("requires std.math for ^^ operators");
+ //fatal();
+
+ // Leave handling of PowExp to the backend, or throw
+ // an error gracefully if no backend support exists.
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ result = exp;
+ return;
+ }
+ e = new ScopeExp(exp->loc, mmath);
+
+ if (exp->e2->op == TOKfloat64 && exp->e2->toReal() == CTFloat::half)
+ {
+ // Replace e1 ^^ 0.5 with .std.math.sqrt(x)
+ e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_sqrt), exp->e1);
+ }
+ else
+ {
+ // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
+ e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_pow), exp->e1, exp->e2);
+ }
+ e = semantic(e, sc);
+ result = e;
+ }
+
+ void visit(ShlExp *exp)
+ {
+ //printf("ShlExp::semantic(), type = %p\n", exp->type);
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->checkIntegralBin())
+ return setError();
+ if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ exp->e1 = integralPromotions(exp->e1, sc);
+ if (exp->e2->type->toBasetype()->ty != Tvector)
+ exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+
+ exp->type = exp->e1->type;
+ result = exp;
+ }
+
+ void visit(ShrExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->checkIntegralBin())
+ return setError();
+ if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ exp->e1 = integralPromotions(exp->e1, sc);
+ if (exp->e2->type->toBasetype()->ty != Tvector)
+ exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+
+ exp->type = exp->e1->type;
+ result = exp;
+ }
+
+ void visit(UshrExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->checkIntegralBin())
+ return setError();
+ if (!Target::isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ exp->e1 = integralPromotions(exp->e1, sc);
+ if (exp->e2->type->toBasetype()->ty != Tvector)
+ exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
+
+ exp->type = exp->e1->type;
+ result = exp;
+ }
+
+ void visit(AndExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->e1->type->toBasetype()->ty == Tbool &&
+ exp->e2->type->toBasetype()->ty == Tbool)
+ {
+ exp->type = exp->e1->type;
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if (exp->checkIntegralBin())
+ return setError();
+
+ result = exp;
+ }
+
+ void visit(OrExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->e1->type->toBasetype()->ty == Tbool &&
+ exp->e2->type->toBasetype()->ty == Tbool)
+ {
+ exp->type = exp->e1->type;
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if (exp->checkIntegralBin())
+ return setError();
+
+ result = exp;
+ }
+
+ void visit(XorExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp->e1->type->toBasetype()->ty == Tbool &&
+ exp->e2->type->toBasetype()->ty == Tbool)
+ {
+ exp->type = exp->e1->type;
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type *tb = exp->type->toBasetype();
+ if (tb->ty == Tarray || tb->ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ exp->error("invalid array operation %s (possible missing [])", exp->toChars());
+ return setError();
+ }
+ result = exp;
+ return;
+ }
+
+ if (!Target::isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ if (exp->checkIntegralBin())
+ return setError();
+
+ result = exp;
+ }
+
+ void visit(OrOrExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ setNoderefOperands(exp);
+
+ // same as for AndAnd
+ Expression *e1x = semantic(exp->e1, sc);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e1x->op == TOKtype)
+ e1x = resolveAliasThis(sc, e1x);
+
+ e1x = resolveProperties(sc, e1x);
+ e1x = e1x->toBoolean(sc);
+ unsigned cs1 = sc->callSuper;
+
+ if (sc->flags & SCOPEcondition)
+ {
+ /* If in static if, don't evaluate e2 if we don't have to.
+ */
+ e1x = e1x->optimize(WANTvalue);
+ if (e1x->isBool(true))
+ {
+ result = new IntegerExp(exp->loc, 1, Type::tbool);
+ return;
+ }
+ }
+
+ Expression *e2x = semantic(exp->e2, sc);
+ sc->mergeCallSuper(exp->loc, cs1);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e2x->op == TOKtype)
+ e2x = resolveAliasThis(sc, e2x);
+
+ e2x = resolveProperties(sc, e2x);
+
+ bool f1 = checkNonAssignmentArrayOp(e1x);
+ bool f2 = checkNonAssignmentArrayOp(e2x);
+ if (f1 || f2)
+ return setError();
+
+ // Unless the right operand is 'void', the expression is converted to 'bool'.
+ if (e2x->type->ty != Tvoid)
+ e2x = e2x->toBoolean(sc);
+
+ if (e2x->op == TOKtype || e2x->op == TOKscope)
+ {
+ exp->error("%s is not an expression", exp->e2->toChars());
+ return setError();
+ }
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+
+ // The result type is 'bool', unless the right operand has type 'void'.
+ if (e2x->type->ty == Tvoid)
+ exp->type = Type::tvoid;
+ else
+ exp->type = Type::tbool;
+
+ exp->e1 = e1x;
+ exp->e2 = e2x;
+ result = exp;
+ }
+
+ void visit(AndAndExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ setNoderefOperands(exp);
+
+ // same as for OrOr
+ Expression *e1x = semantic(exp->e1, sc);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e1x->op == TOKtype)
+ e1x = resolveAliasThis(sc, e1x);
+
+ e1x = resolveProperties(sc, e1x);
+ e1x = e1x->toBoolean(sc);
+ unsigned cs1 = sc->callSuper;
+
+ if (sc->flags & SCOPEcondition)
+ {
+ /* If in static if, don't evaluate e2 if we don't have to.
+ */
+ e1x = e1x->optimize(WANTvalue);
+ if (e1x->isBool(false))
+ {
+ result = new IntegerExp(exp->loc, 0, Type::tbool);
+ return;
+ }
+ }
+
+ Expression *e2x = semantic(exp->e2, sc);
+ sc->mergeCallSuper(exp->loc, cs1);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e2x->op == TOKtype)
+ e2x = resolveAliasThis(sc, e2x);
+
+ e2x = resolveProperties(sc, e2x);
+
+ bool f1 = checkNonAssignmentArrayOp(e1x);
+ bool f2 = checkNonAssignmentArrayOp(e2x);
+ if (f1 || f2)
+ return setError();
+
+ // Unless the right operand is 'void', the expression is converted to 'bool'.
+ if (e2x->type->ty != Tvoid)
+ e2x = e2x->toBoolean(sc);
+
+ if (e2x->op == TOKtype || e2x->op == TOKscope)
+ {
+ exp->error("%s is not an expression", exp->e2->toChars());
+ return setError();
+ }
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+
+ // The result type is 'bool', unless the right operand has type 'void'.
+ if (e2x->type->ty == Tvoid)
+ exp->type = Type::tvoid;
+ else
+ exp->type = Type::tbool;
+
+ exp->e1 = e1x;
+ exp->e2 = e2x;
+ result = exp;
+ }
+
+ void visit(InExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type *t2b = exp->e2->type->toBasetype();
+ switch (t2b->ty)
+ {
+ case Taarray:
+ {
+ TypeAArray *ta = (TypeAArray *)t2b;
+
+ // Special handling for array keys
+ if (!arrayTypeCompatible(exp->e1->loc, exp->e1->type, ta->index))
+ {
+ // Convert key to type of key
+ exp->e1 = exp->e1->implicitCastTo(sc, ta->index);
+ }
+
+ semanticTypeInfo(sc, ta->index);
+
+ // Return type is pointer to value
+ exp->type = ta->nextOf()->pointerTo();
+ break;
+ }
+
+ default:
+ result = exp->incompatibleTypes();
+ return;
+
+ case Terror:
+ return setError();
+ }
+ result = exp;
+ }
+
+ void visit(RemoveExp *e)
+ {
+ if (Expression *ex = binSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ result = e;
+ }
+
+ void visit(CmpExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ setNoderefOperands(exp);
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Type *t1 = exp->e1->type->toBasetype();
+ Type *t2 = exp->e2->type->toBasetype();
+ if ((t1->ty == Tclass && exp->e2->op == TOKnull) ||
+ (t2->ty == Tclass && exp->e1->op == TOKnull))
+ {
+ exp->error("do not use null when comparing class types");
+ return setError();
+ }
+
+ Expression *e = exp->op_overload(sc);
+ if (e)
+ {
+ if (!e->type->isscalar() && e->type->equals(exp->e1->type))
+ {
+ exp->error("recursive opCmp expansion");
+ return setError();
+ }
+ if (e->op == TOKcall)
+ {
+ e = new CmpExp(exp->op, exp->loc, e, new IntegerExp(exp->loc, 0, Type::tint32));
+ e = semantic(e, sc);
+ }
+ result = e;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ bool f1 = checkNonAssignmentArrayOp(exp->e1);
+ bool f2 = checkNonAssignmentArrayOp(exp->e2);
+ if (f1 || f2)
+ return setError();
+
+ exp->type = Type::tbool;
+
+ // Special handling for array comparisons
+ t1 = exp->e1->type->toBasetype();
+ t2 = exp->e2->type->toBasetype();
+ if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
+ (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
+ {
+ Type *t1next = t1->nextOf();
+ Type *t2next = t2->nextOf();
+ if (t1next->implicitConvTo(t2next) < MATCHconst &&
+ t2next->implicitConvTo(t1next) < MATCHconst &&
+ (t1next->ty != Tvoid && t2next->ty != Tvoid))
+ {
+ exp->error("array comparison type mismatch, %s vs %s", t1next->toChars(), t2next->toChars());
+ return setError();
+ }
+ if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+ (t2->ty == Tarray || t2->ty == Tsarray))
+ {
+ semanticTypeInfo(sc, t1->nextOf());
+ }
+ }
+ else if (t1->ty == Tstruct || t2->ty == Tstruct ||
+ (t1->ty == Tclass && t2->ty == Tclass))
+ {
+ if (t2->ty == Tstruct)
+ exp->error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars());
+ else
+ exp->error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars());
+ return setError();
+ }
+ else if (t1->iscomplex() || t2->iscomplex())
+ {
+ exp->error("compare not defined for complex operands");
+ return setError();
+ }
+ else if (t1->ty == Taarray || t2->ty == Taarray)
+ {
+ exp->error("%s is not defined for associative arrays", Token::toChars(exp->op));
+ return setError();
+ }
+ else if (!Target::isVectorOpSupported(t1, exp->op, t2))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+ else
+ {
+ bool r1 = exp->e1->checkValue();
+ bool r2 = exp->e2->checkValue();
+ if (r1 || r2)
+ return setError();
+ }
+
+ TOK altop;
+ switch (exp->op)
+ {
+ // Refer rel_integral[] table
+ case TOKunord: altop = TOKerror; break;
+ case TOKlg: altop = TOKnotequal; break;
+ case TOKleg: altop = TOKerror; break;
+ case TOKule: altop = TOKle; break;
+ case TOKul: altop = TOKlt; break;
+ case TOKuge: altop = TOKge; break;
+ case TOKug: altop = TOKgt; break;
+ case TOKue: altop = TOKequal; break;
+ default: altop = TOKreserved; break;
+ }
+ if (altop == TOKerror &&
+ (t1->ty == Tarray || t1->ty == Tsarray ||
+ t2->ty == Tarray || t2->ty == Tsarray))
+ {
+ exp->error("'%s' is not defined for array comparisons", Token::toChars(exp->op));
+ return setError();
+ }
+ if (altop != TOKreserved)
+ {
+ if (!t1->isfloating())
+ {
+ if (altop == TOKerror)
+ {
+ const char *s = exp->op == TOKunord ? "false" : "true";
+ exp->error("floating point operator '%s' always returns %s for non-floating comparisons",
+ Token::toChars(exp->op), s);
+ }
+ else
+ {
+ exp->error("use '%s' for non-floating comparisons rather than floating point operator '%s'",
+ Token::toChars(altop), Token::toChars(exp->op));
+ }
+ }
+ else
+ {
+ exp->error("use std.math.isNaN to deal with NaN operands rather than floating point operator '%s'",
+ Token::toChars(exp->op));
+ }
+ return setError();
+ }
+
+ //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars());
+ result = exp;
+ }
+
+ void visit(EqualExp *exp)
+ {
+ //printf("EqualExp::semantic('%s')\n", toChars());
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ setNoderefOperands(exp);
+
+ if (Expression *e = binSemanticProp(exp, sc))
+ {
+ result = e;
+ return;
+ }
+ if (exp->e1->op == TOKtype || exp->e2->op == TOKtype)
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
+ {
+ Type *t1 = exp->e1->type;
+ Type *t2 = exp->e2->type;
+ if (t1->ty == Tenum && t2->ty == Tenum && !t1->equivalent(t2))
+ exp->deprecation("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
+ t1->toChars(), t2->toChars());
+ }
+
+ /* Before checking for operator overloading, check to see if we're
+ * comparing the addresses of two statics. If so, we can just see
+ * if they are the same symbol.
+ */
+ if (exp->e1->op == TOKaddress && exp->e2->op == TOKaddress)
+ {
+ AddrExp *ae1 = (AddrExp *)exp->e1;
+ AddrExp *ae2 = (AddrExp *)exp->e2;
+ if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar)
+ {
+ VarExp *ve1 = (VarExp *)ae1->e1;
+ VarExp *ve2 = (VarExp *)ae2->e1;
+
+ if (ve1->var == ve2->var)
+ {
+ // They are the same, result is 'true' for ==, 'false' for !=
+ result = new IntegerExp(exp->loc, (exp->op == TOKequal), Type::tbool);
+ return;
+ }
+ }
+ }
+
+ if (Expression *e = exp->op_overload(sc))
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression *e = typeCombine(exp, sc))
+ {
+ result = e;
+ return;
+ }
+
+ bool f1 = checkNonAssignmentArrayOp(exp->e1);
+ bool f2 = checkNonAssignmentArrayOp(exp->e2);
+ if (f1 || f2)
+ return setError();
+
+ exp->type = Type::tbool;
+
+ // Special handling for array comparisons
+ if (!arrayTypeCompatible(exp->loc, exp->e1->type, exp->e2->type))
+ {
+ if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
+ {
+ // Cast both to complex
+ exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
+ exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
+ }
+ }
+ if (exp->e1->type->toBasetype()->ty == Taarray)
+ semanticTypeInfo(sc, exp->e1->type->toBasetype());
+
+ Type *t1 = exp->e1->type->toBasetype();
+ Type *t2 = exp->e2->type->toBasetype();
+
+ if (!Target::isVectorOpSupported(t1, exp->op, t2))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
+ result = exp;
+ }
+
+ void visit(IdentityExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ setNoderefOperands(exp);
+
+ if (Expression *ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ bool f1 = checkNonAssignmentArrayOp(exp->e1);
+ bool f2 = checkNonAssignmentArrayOp(exp->e2);
+ if (f1 || f2)
+ return setError();
+
+ exp->type = Type::tbool;
+
+ if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
+ {
+ // Cast both to complex
+ exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
+ exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
+ }
+
+ Type *tb1 = exp->e1->type->toBasetype();
+ Type *tb2 = exp->e2->type->toBasetype();
+ if (!Target::isVectorOpSupported(tb1, exp->op, tb2))
+ {
+ result = exp->incompatibleTypes();
+ return;
+ }
+
+ result = exp;
+ }
+
+ void visit(CondExp *exp)
+ {
+ if (exp->type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (exp->econd->op == TOKdotid)
+ ((DotIdExp *)exp->econd)->noderef = true;
+
+ Expression *ec = semantic(exp->econd, sc);
+ ec = resolveProperties(sc, ec);
+ ec = ec->toBoolean(sc);
+
+ unsigned cs0 = sc->callSuper;
+ unsigned *fi0 = sc->saveFieldInit();
+ Expression *e1x = semantic(exp->e1, sc);
+ e1x = resolveProperties(sc, e1x);
+
+ unsigned cs1 = sc->callSuper;
+ unsigned *fi1 = sc->fieldinit;
+ sc->callSuper = cs0;
+ sc->fieldinit = fi0;
+ Expression *e2x = semantic(exp->e2, sc);
+ e2x = resolveProperties(sc, e2x);
+
+ sc->mergeCallSuper(exp->loc, cs1);
+ sc->mergeFieldInit(exp->loc, fi1);
+
+ if (ec->op == TOKerror)
+ {
+ result = ec;
+ return;
+ }
+ if (ec->type == Type::terror)
+ return setError();
+ exp->econd = ec;
+
+ if (e1x->op == TOKerror)
+ {
+ result = e1x;
+ return;
+ }
+ if (e1x->type == Type::terror)
+ return setError();
+ exp->e1 = e1x;
+
+ if (e2x->op == TOKerror)
+ {
+ result = e2x;
+ return;
+ }
+ if (e2x->type == Type::terror)
+ return setError();
+ exp->e2 = e2x;
+
+ bool f0 = checkNonAssignmentArrayOp(exp->econd);
+ bool f1 = checkNonAssignmentArrayOp(exp->e1);
+ bool f2 = checkNonAssignmentArrayOp(exp->e2);
+ if (f0 || f1 || f2)
+ return setError();
+
+ Type *t1 = exp->e1->type;
+ Type *t2 = exp->e2->type;
+ // If either operand is void the result is void, we have to cast both
+ // the expression to void so that we explicitly discard the expression
+ // value if any (bugzilla 16598)
+ if (t1->ty == Tvoid || t2->ty == Tvoid)
+ {
+ exp->type = Type::tvoid;
+ exp->e1 = exp->e1->castTo(sc, exp->type);
+ exp->e2 = exp->e2->castTo(sc, exp->type);
+ }
+ else if (t1 == t2)
+ exp->type = t1;
+ else
+ {
+ if (Expression *ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ switch (exp->e1->type->toBasetype()->ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ exp->e2 = exp->e2->castTo(sc, exp->e1->type);
+ break;
+ }
+ switch (exp->e2->type->toBasetype()->ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ exp->e1 = exp->e1->castTo(sc, exp->e2->type);
+ break;
+ }
+ if (exp->type->toBasetype()->ty == Tarray)
+ {
+ exp->e1 = exp->e1->castTo(sc, exp->type);
+ exp->e2 = exp->e2->castTo(sc, exp->type);
+ }
+ }
+ exp->type = exp->type->merge2();
+
+ /* Bugzilla 14696: If either e1 or e2 contain temporaries which need dtor,
+ * make them conditional.
+ * Rewrite:
+ * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
+ * to:
+ * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
+ * and replace edtors of __tmp1 and __tmp2 with:
+ * __tmp1->edtor --> __cond && __tmp1.dtor()
+ * __tmp2->edtor --> __cond || __tmp2.dtor()
+ */
+ exp->hookDtors(sc);
+
+ result = exp;
+ }
+
+ void visit(FileInitExp *e)
+ {
+ //printf("FileInitExp::semantic()\n");
+ e->type = Type::tstring;
+ result = e;
+ }
+
+ void visit(LineInitExp *e)
+ {
+ e->type = Type::tint32;
+ result = e;
+ }
+
+ void visit(ModuleInitExp *e)
+ {
+ //printf("ModuleInitExp::semantic()\n");
+ e->type = Type::tstring;
+ result = e;
+ }
+
+ void visit(FuncInitExp *e)
+ {
+ //printf("FuncInitExp::semantic()\n");
+ e->type = Type::tstring;
+ if (sc->func)
+ {
+ result = e->resolveLoc(Loc(), sc);
+ return;
+ }
+ result = e;
+ }
+
+ void visit(PrettyFuncInitExp *e)
+ {
+ //printf("PrettyFuncInitExp::semantic()\n");
+ e->type = Type::tstring;
+ if (sc->func)
+ {
+ result = e->resolveLoc(Loc(), sc);
+ return;
+ }
+ result = e;
+ }
+};
+
+/**********************************
+ * Try to run semantic routines.
+ * If they fail, return NULL.
+ */
+Expression *trySemantic(Expression *exp, Scope* sc)
+{
+ //printf("+trySemantic(%s)\n", toChars());
+ unsigned errors = global.startGagging();
+ Expression *e = semantic(exp, sc);
+ if (global.endGagging(errors))
+ {
+ e = NULL;
+ }
+ //printf("-trySemantic(%s)\n", toChars());
+ return e;
+}
+
+/**************************
+ * Helper function for easy error propagation.
+ * If error occurs, returns ErrorExp. Otherwise returns NULL.
+ */
+Expression *unaSemantic(UnaExp *e, Scope *sc)
+{
+ Expression *e1x = semantic(e->e1, sc);
+ if (e1x->op == TOKerror)
+ return e1x;
+ e->e1 = e1x;
+ return NULL;
+}
+
+/**************************
+ * Helper function for easy error propagation.
+ * If error occurs, returns ErrorExp. Otherwise returns NULL.
+ */
+Expression *binSemantic(BinExp *e, Scope *sc)
+{
+ Expression *e1x = semantic(e->e1, sc);
+ Expression *e2x = semantic(e->e2, sc);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e1x->op == TOKtype)
+ e1x = resolveAliasThis(sc, e1x);
+ if (e2x->op == TOKtype)
+ e2x = resolveAliasThis(sc, e2x);
+
+ if (e1x->op == TOKerror)
+ return e1x;
+ if (e2x->op == TOKerror)
+ return e2x;
+ e->e1 = e1x;
+ e->e2 = e2x;
+ return NULL;
+}
+
+Expression *binSemanticProp(BinExp *e, Scope *sc)
+{
+ if (Expression *ex = binSemantic(e, sc))
+ return ex;
+ Expression *e1x = resolveProperties(sc, e->e1);
+ Expression *e2x = resolveProperties(sc, e->e2);
+ if (e1x->op == TOKerror)
+ return e1x;
+ if (e2x->op == TOKerror)
+ return e2x;
+ e->e1 = e1x;
+ e->e2 = e2x;
+ return NULL;
+}
+
+// entrypoint for semantic ExpressionSemanticVisitor
+Expression *semantic(Expression *e, Scope *sc)
+{
+ ExpressionSemanticVisitor v = ExpressionSemanticVisitor(sc);
+ e->accept(&v);
+ return v.result;
+}
+
+Expression *semanticX(DotIdExp *exp, Scope *sc)
+{
+ //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
+ if (Expression *ex = unaSemantic(exp, sc))
+ return ex;
+
+ if (exp->ident == Id::_mangleof)
+ {
+ // symbol.mangleof
+ Dsymbol *ds;
+ switch (exp->e1->op)
+ {
+ case TOKscope:
+ ds = ((ScopeExp *)exp->e1)->sds;
+ goto L1;
+ case TOKvar:
+ ds = ((VarExp *)exp->e1)->var;
+ goto L1;
+ case TOKdotvar:
+ ds = ((DotVarExp *)exp->e1)->var;
+ goto L1;
+ case TOKoverloadset:
+ ds = ((OverExp *)exp->e1)->vars;
+ goto L1;
+ case TOKtemplate:
+ {
+ TemplateExp *te = (TemplateExp *)exp->e1;
+ ds = te->fd ? (Dsymbol *)te->fd : te->td;
+ }
+ L1:
+ {
+ assert(ds);
+ if (FuncDeclaration *f = ds->isFuncDeclaration())
+ {
+ if (f->checkForwardRef(exp->loc))
+ return new ErrorExp();
+ }
+ OutBuffer buf;
+ mangleToBuffer(ds, &buf);
+ const char *s = buf.extractString();
+ Expression *e = new StringExp(exp->loc, const_cast<char*>(s), strlen(s));
+ e = semantic(e, sc);
+ return e;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (exp->e1->op == TOKvar && exp->e1->type->toBasetype()->ty == Tsarray && exp->ident == Id::length)
+ {
+ // bypass checkPurity
+ return exp->e1->type->dotExp(sc, exp->e1, exp->ident, exp->noderef ? 2 : 0);
+ }
+
+ if (exp->e1->op == TOKdot)
+ {
+ }
+ else
+ {
+ exp->e1 = resolvePropertiesX(sc, exp->e1);
+ }
+ if (exp->e1->op == TOKtuple && exp->ident == Id::offsetof)
+ {
+ /* 'distribute' the .offsetof to each of the tuple elements.
+ */
+ TupleExp *te = (TupleExp *)exp->e1;
+ Expressions *exps = new Expressions();
+ exps->setDim(te->exps->dim);
+ for (size_t i = 0; i < exps->dim; i++)
+ {
+ Expression *e = (*te->exps)[i];
+ e = semantic(e, sc);
+ e = new DotIdExp(e->loc, e, Id::offsetof);
+ (*exps)[i] = e;
+ }
+ // Don't evaluate te->e0 in runtime
+ Expression *e = new TupleExp(exp->loc, NULL, exps);
+ e = semantic(e, sc);
+ return e;
+ }
+ if (exp->e1->op == TOKtuple && exp->ident == Id::length)
+ {
+ TupleExp *te = (TupleExp *)exp->e1;
+ // Don't evaluate te->e0 in runtime
+ Expression *e = new IntegerExp(exp->loc, te->exps->dim, Type::tsize_t);
+ return e;
+ }
+
+ // Bugzilla 14416: Template has no built-in properties except for 'stringof'.
+ if ((exp->e1->op == TOKdottd || exp->e1->op == TOKtemplate) && exp->ident != Id::stringof)
+ {
+ exp->error("template %s does not have property '%s'", exp->e1->toChars(), exp->ident->toChars());
+ return new ErrorExp();
+ }
+
+ if (!exp->e1->type)
+ {
+ exp->error("expression %s does not have property '%s'", exp->e1->toChars(), exp->ident->toChars());
+ return new ErrorExp();
+ }
+
+ return exp;
+}
+
+// Resolve e1.ident without seeing UFCS.
+// If flag == 1, stop "not a property" error and return NULL.
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag)
+{
+ //printf("DotIdExp::semanticY(this = %p, '%s')\n", this, toChars());
+
+ //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
+
+ /* Special case: rewrite this.id and super.id
+ * to be classtype.id and baseclasstype.id
+ * if we have no this pointer.
+ */
+ if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && !hasThis(sc))
+ {
+ if (AggregateDeclaration *ad = sc->getStructClassScope())
+ {
+ if (exp->e1->op == TOKthis)
+ {
+ exp->e1 = new TypeExp(exp->e1->loc, ad->type);
+ }
+ else
+ {
+ ClassDeclaration *cd = ad->isClassDeclaration();
+ if (cd && cd->baseClass)
+ exp->e1 = new TypeExp(exp->e1->loc, cd->baseClass->type);
+ }
+ }
+ }
+
+ Expression *e = semanticX(exp, sc);
+ if (e != exp)
+ return e;
+
+ Expression *eleft;
+ Expression *eright;
+ if (exp->e1->op == TOKdot)
+ {
+ DotExp *de = (DotExp *)exp->e1;
+ eleft = de->e1;
+ eright = de->e2;
+ }
+ else
+ {
+ eleft = NULL;
+ eright = exp->e1;
+ }
+
+ Type *t1b = exp->e1->type->toBasetype();
+
+ if (eright->op == TOKscope) // also used for template alias's
+ {
+ ScopeExp *ie = (ScopeExp *)eright;
+ int flags = SearchLocalsOnly;
+
+ /* Disable access to another module's private imports.
+ * The check for 'is sds our current module' is because
+ * the current module should have access to its own imports.
+ */
+ if (ie->sds->isModule() && ie->sds != sc->_module)
+ flags |= IgnorePrivateImports;
+ if (sc->flags & SCOPEignoresymbolvisibility)
+ flags |= IgnoreSymbolVisibility;
+ Dsymbol *s = ie->sds->search(exp->loc, exp->ident, flags);
+ /* Check for visibility before resolving aliases because public
+ * aliases to private symbols are public.
+ */
+ if (s && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc->_module, s))
+ {
+ if (s->isDeclaration())
+ ::error(exp->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toChars());
+ else
+ ::deprecation(exp->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toChars());
+ // s = NULL
+ }
+ if (s)
+ {
+ if (Package *p = s->isPackage())
+ checkAccess(exp->loc, sc, p);
+
+ // if 's' is a tuple variable, the tuple is returned.
+ s = s->toAlias();
+
+ exp->checkDeprecated(sc, s);
+
+ EnumMember *em = s->isEnumMember();
+ if (em)
+ {
+ return em->getVarExp(exp->loc, sc);
+ }
+
+ VarDeclaration *v = s->isVarDeclaration();
+ if (v)
+ {
+ //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
+ if (!v->type ||
+ (!v->type->deco && v->inuse))
+ {
+ if (v->inuse)
+ exp->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ else
+ exp->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+ if (v->type->ty == Terror)
+ return new ErrorExp();
+
+ if ((v->storage_class & STCmanifest) && v->_init && !exp->wantsym)
+ {
+ /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
+ * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
+ * be reverted. `wantsym` is the hack to work around the problem.
+ */
+ if (v->inuse)
+ {
+ ::error(exp->loc, "circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+ e = v->expandInitializer(exp->loc);
+ v->inuse++;
+ e = semantic(e, sc);
+ v->inuse--;
+ return e;
+ }
+
+ if (v->needThis())
+ {
+ if (!eleft)
+ eleft = new ThisExp(exp->loc);
+ e = new DotVarExp(exp->loc, eleft, v);
+ e = semantic(e, sc);
+ }
+ else
+ {
+ e = new VarExp(exp->loc, v);
+ if (eleft)
+ { e = new CommaExp(exp->loc, eleft, e);
+ e->type = v->type;
+ }
+ }
+ e = e->deref();
+ return semantic(e, sc);
+ }
+
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (f)
+ {
+ //printf("it's a function\n");
+ if (!f->functionSemantic())
+ return new ErrorExp();
+ if (f->needThis())
+ {
+ if (!eleft)
+ eleft = new ThisExp(exp->loc);
+ e = new DotVarExp(exp->loc, eleft, f, true);
+ e = semantic(e, sc);
+ }
+ else
+ {
+ e = new VarExp(exp->loc, f, true);
+ if (eleft)
+ { e = new CommaExp(exp->loc, eleft, e);
+ e->type = f->type;
+ }
+ }
+ return e;
+ }
+ if (TemplateDeclaration *td = s->isTemplateDeclaration())
+ {
+ if (eleft)
+ e = new DotTemplateExp(exp->loc, eleft, td);
+ else
+ e = new TemplateExp(exp->loc, td);
+ e = semantic(e, sc);
+ return e;
+ }
+ if (OverDeclaration *od = s->isOverDeclaration())
+ {
+ e = new VarExp(exp->loc, od, true);
+ if (eleft)
+ {
+ e = new CommaExp(exp->loc, eleft, e);
+ e->type = Type::tvoid; // ambiguous type?
+ }
+ return e;
+ }
+ OverloadSet *o = s->isOverloadSet();
+ if (o)
+ { //printf("'%s' is an overload set\n", o->toChars());
+ return new OverExp(exp->loc, o);
+ }
+
+ if (Type *t = s->getType())
+ {
+ return semantic(new TypeExp(exp->loc, t), sc);
+ }
+
+ TupleDeclaration *tup = s->isTupleDeclaration();
+ if (tup)
+ {
+ if (eleft)
+ {
+ e = new DotVarExp(exp->loc, eleft, tup);
+ e = semantic(e, sc);
+ return e;
+ }
+ e = new TupleExp(exp->loc, tup);
+ e = semantic(e, sc);
+ return e;
+ }
+
+ ScopeDsymbol *sds = s->isScopeDsymbol();
+ if (sds)
+ {
+ //printf("it's a ScopeDsymbol %s\n", exp->ident->toChars());
+ e = new ScopeExp(exp->loc, sds);
+ e = semantic(e, sc);
+ if (eleft)
+ e = new DotExp(exp->loc, eleft, e);
+ return e;
+ }
+
+ Import *imp = s->isImport();
+ if (imp)
+ {
+ ie = new ScopeExp(exp->loc, imp->pkg);
+ return semantic(ie, sc);
+ }
+
+ // BUG: handle other cases like in IdentifierExp::semantic()
+ assert(0);
+ }
+ else if (exp->ident == Id::stringof)
+ {
+ const char *p = ie->toChars();
+ e = new StringExp(exp->loc, const_cast<char *>(p), strlen(p));
+ e = semantic(e, sc);
+ return e;
+ }
+ if (ie->sds->isPackage() ||
+ ie->sds->isImport() ||
+ ie->sds->isModule())
+ {
+ flag = 0;
+ }
+ if (flag)
+ return NULL;
+ s = ie->sds->search_correct(exp->ident);
+ if (s)
+ exp->error("undefined identifier '%s' in %s '%s', did you mean %s '%s'?",
+ exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->kind(), s->toChars());
+ else
+ exp->error("undefined identifier '%s' in %s '%s'",
+ exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars());
+ return new ErrorExp();
+ }
+ else if (t1b->ty == Tpointer && exp->e1->type->ty != Tenum &&
+ exp->ident != Id::_init && exp->ident != Id::__sizeof &&
+ exp->ident != Id::__xalignof && exp->ident != Id::offsetof &&
+ exp->ident != Id::_mangleof && exp->ident != Id::stringof)
+ {
+ Type *t1bn = t1b->nextOf();
+ if (flag)
+ {
+ AggregateDeclaration *ad = isAggregate(t1bn);
+ if (ad && !ad->members) // Bugzilla 11312
+ return NULL;
+ }
+
+ /* Rewrite:
+ * p.ident
+ * as:
+ * (*p).ident
+ */
+ if (flag && t1bn->ty == Tvoid)
+ return NULL;
+ e = new PtrExp(exp->loc, exp->e1);
+ e = semantic(e, sc);
+ return e->type->dotExp(sc, e, exp->ident, flag | (exp->noderef ? 2 : 0));
+ }
+ else
+ {
+ if (exp->e1->op == TOKtype || exp->e1->op == TOKtemplate)
+ flag = 0;
+ e = exp->e1->type->dotExp(sc, exp->e1, exp->ident, flag | (exp->noderef ? 2 : 0));
+ if (e)
+ e = semantic(e, sc);
+ return e;
+ }
+}
+
+// Resolve e1.ident!tiargs without seeing UFCS.
+// If flag == 1, stop "not a property" error and return NULL.
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag)
+{
+ DotIdExp *die = new DotIdExp(exp->loc, exp->e1, exp->ti->name);
+
+ Expression *e = semanticX(die, sc);
+ if (e == die)
+ {
+ exp->e1 = die->e1; // take back
+
+ Type *t1b = exp->e1->type->toBasetype();
+ if (t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Taarray ||
+ t1b->ty == Tnull || (t1b->isTypeBasic() && t1b->ty != Tvoid))
+ {
+ /* No built-in type has templatized properties, so do shortcut.
+ * It is necessary in: 1024.max!"a < b"
+ */
+ if (flag)
+ return NULL;
+ }
+ e = semanticY(die, sc, flag);
+ if (flag && e && isDotOpDispatch(e))
+ {
+ /* opDispatch!tiargs would be a function template that needs IFTI,
+ * so it's not a template
+ */
+ e = NULL; /* fall down to UFCS */
+ }
+ if (flag && !e)
+ return NULL;
+ }
+ assert(e);
+
+ if (e->op == TOKerror)
+ return e;
+ if (e->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp *)e;
+ if (FuncDeclaration *fd = dve->var->isFuncDeclaration())
+ {
+ TemplateDeclaration *td = fd->findTemplateDeclRoot();
+ if (td)
+ {
+ e = new DotTemplateExp(dve->loc, dve->e1, td);
+ e = semantic(e, sc);
+ }
+ }
+ else if (dve->var->isOverDeclaration())
+ {
+ exp->e1 = dve->e1; // pull semantic() result
+ if (!exp->findTempDecl(sc))
+ goto Lerr;
+ if (exp->ti->needsTypeInference(sc))
+ return exp;
+ exp->ti->semantic(sc);
+ if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
+ return new ErrorExp();
+ Dsymbol *s = exp->ti->toAlias();
+ Declaration *v = s->isDeclaration();
+ if (v)
+ {
+ if (v->type && !v->type->deco)
+ v->type = v->type->semantic(v->loc, sc);
+ e = new DotVarExp(exp->loc, exp->e1, v);
+ e = semantic(e, sc);
+ return e;
+ }
+ e = new ScopeExp(exp->loc, exp->ti);
+ e = new DotExp(exp->loc, exp->e1, e);
+ e = semantic(e, sc);
+ return e;
+ }
+ }
+ else if (e->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e;
+ if (FuncDeclaration *fd = ve->var->isFuncDeclaration())
+ {
+ TemplateDeclaration *td = fd->findTemplateDeclRoot();
+ if (td)
+ {
+ e = new TemplateExp(ve->loc, td);
+ e = semantic(e, sc);
+ }
+ }
+ else if (OverDeclaration *od = ve->var->isOverDeclaration())
+ {
+ exp->ti->tempdecl = od;
+ e = new ScopeExp(exp->loc, exp->ti);
+ e = semantic(e, sc);
+ return e;
+ }
+ }
+ if (e->op == TOKdottd)
+ {
+ DotTemplateExp *dte = (DotTemplateExp *)e;
+ exp->e1 = dte->e1; // pull semantic() result
+
+ exp->ti->tempdecl = dte->td;
+ if (!exp->ti->semanticTiargs(sc))
+ return new ErrorExp();
+ if (exp->ti->needsTypeInference(sc))
+ return exp;
+ exp->ti->semantic(sc);
+ if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
+ return new ErrorExp();
+ Dsymbol *s = exp->ti->toAlias();
+ Declaration *v = s->isDeclaration();
+ if (v && (v->isFuncDeclaration() || v->isVarDeclaration()))
+ {
+ e = new DotVarExp(exp->loc, exp->e1, v);
+ e = semantic(e, sc);
+ return e;
+ }
+ e = new ScopeExp(exp->loc, exp->ti);
+ e = new DotExp(exp->loc, exp->e1, e);
+ e = semantic(e, sc);
+ return e;
+ }
+ else if (e->op == TOKtemplate)
+ {
+ exp->ti->tempdecl = ((TemplateExp *)e)->td;
+ e = new ScopeExp(exp->loc, exp->ti);
+ e = semantic(e, sc);
+ return e;
+ }
+ else if (e->op == TOKdot)
+ {
+ DotExp *de = (DotExp *)e;
+
+ if (de->e2->op == TOKoverloadset)
+ {
+ if (!exp->findTempDecl(sc) ||
+ !exp->ti->semanticTiargs(sc))
+ {
+ return new ErrorExp();
+ }
+ if (exp->ti->needsTypeInference(sc))
+ return exp;
+ exp->ti->semantic(sc);
+ if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
+ return new ErrorExp();
+ Dsymbol *s = exp->ti->toAlias();
+ Declaration *v = s->isDeclaration();
+ if (v)
+ {
+ if (v->type && !v->type->deco)
+ v->type = v->type->semantic(v->loc, sc);
+ e = new DotVarExp(exp->loc, exp->e1, v);
+ e = semantic(e, sc);
+ return e;
+ }
+ e = new ScopeExp(exp->loc, exp->ti);
+ e = new DotExp(exp->loc, exp->e1, e);
+ e = semantic(e, sc);
+ return e;
+ }
+ }
+ else if (e->op == TOKoverloadset)
+ {
+ OverExp *oe = (OverExp *)e;
+ exp->ti->tempdecl = oe->vars;
+ e = new ScopeExp(exp->loc, exp->ti);
+ e = semantic(e, sc);
+ return e;
+ }
+Lerr:
+ e->error("%s isn't a template", e->toChars());
+ return new ErrorExp();
+}
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
new file mode 100644
index 0000000..2feea91
--- /dev/null
+++ b/gcc/d/dmd/func.c
@@ -0,0 +1,5626 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/func.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "declaration.h"
+#include "attrib.h"
+#include "expression.h"
+#include "scope.h"
+#include "mtype.h"
+#include "aggregate.h"
+#include "identifier.h"
+#include "id.h"
+#include "module.h"
+#include "statement.h"
+#include "template.h"
+#include "hdrgen.h"
+#include "target.h"
+#include "parse.h"
+#include "root/rmem.h"
+#include "visitor.h"
+#include "objc.h"
+
+Expression *addInvariant(Loc loc, Scope *sc, AggregateDeclaration *ad, VarDeclaration *vthis, bool direct);
+bool checkReturnEscape(Scope *sc, Expression *e, bool gag);
+bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag);
+bool checkNestedRef(Dsymbol *s, Dsymbol *p);
+Statement *semantic(Statement *s, Scope *sc);
+void semantic(Catch *c, Scope *sc);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *semantic(Expression *e, Scope *sc);
+int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
+TypeIdentifier *getThrowable();
+
+RET retStyle(TypeFunction *tf);
+void MODtoBuffer(OutBuffer *buf, MOD mod);
+char *MODtoChars(MOD mod);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+MATCH MODmethodConv(MOD modfrom, MOD modto);
+void allocFieldinit(Scope *sc, size_t dim);
+void freeFieldinit(Scope *sc);
+Objc *objc();
+
+
+/* A visitor to walk entire statements and provides ability to replace any sub-statements.
+ */
+class StatementRewriteWalker : public Visitor
+{
+ /* Point the currently visited statement.
+ * By using replaceCurrent() method, you can replace AST during walking.
+ */
+ Statement **ps;
+public:
+ void visitStmt(Statement *&s) { ps = &s; s->accept(this); }
+ void replaceCurrent(Statement *s) { *ps = s; }
+
+ void visit(ErrorStatement *) { }
+ void visit(PeelStatement *s)
+ {
+ if (s->s)
+ visitStmt(s->s);
+ }
+ void visit(ExpStatement *) { }
+ void visit(DtorExpStatement *) { }
+ void visit(CompileStatement *) { }
+ void visit(CompoundStatement *s)
+ {
+ if (s->statements && s->statements->dim)
+ {
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ if ((*s->statements)[i])
+ visitStmt((*s->statements)[i]);
+ }
+ }
+ }
+ void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
+ void visit(UnrolledLoopStatement *s)
+ {
+ if (s->statements && s->statements->dim)
+ {
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ if ((*s->statements)[i])
+ visitStmt((*s->statements)[i]);
+ }
+ }
+ }
+ void visit(ScopeStatement *s)
+ {
+ if (s->statement)
+ visitStmt(s->statement);
+ }
+ void visit(WhileStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(DoStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(ForStatement *s)
+ {
+ if (s->_init)
+ visitStmt(s->_init);
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(ForeachStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(ForeachRangeStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(IfStatement *s)
+ {
+ if (s->ifbody)
+ visitStmt(s->ifbody);
+ if (s->elsebody)
+ visitStmt(s->elsebody);
+ }
+ void visit(ConditionalStatement *) { }
+ void visit(PragmaStatement *) { }
+ void visit(StaticAssertStatement *) { }
+ void visit(SwitchStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(CaseStatement *s)
+ {
+ if (s->statement)
+ visitStmt(s->statement);
+ }
+ void visit(CaseRangeStatement *s)
+ {
+ if (s->statement)
+ visitStmt(s->statement);
+ }
+ void visit(DefaultStatement *s)
+ {
+ if (s->statement)
+ visitStmt(s->statement);
+ }
+ void visit(GotoDefaultStatement *) { }
+ void visit(GotoCaseStatement *) { }
+ void visit(SwitchErrorStatement *) { }
+ void visit(ReturnStatement *) { }
+ void visit(BreakStatement *) { }
+ void visit(ContinueStatement *) { }
+ void visit(SynchronizedStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(WithStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ }
+ void visit(TryCatchStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ if (s->catches && s->catches->dim)
+ {
+ for (size_t i = 0; i < s->catches->dim; i++)
+ {
+ Catch *c = (*s->catches)[i];
+ if (c && c->handler)
+ visitStmt(c->handler);
+ }
+ }
+ }
+ void visit(TryFinallyStatement *s)
+ {
+ if (s->_body)
+ visitStmt(s->_body);
+ if (s->finalbody)
+ visitStmt(s->finalbody);
+ }
+ void visit(OnScopeStatement *) { }
+ void visit(ThrowStatement *) { }
+ void visit(DebugStatement *s)
+ {
+ if (s->statement)
+ visitStmt(s->statement);
+ }
+ void visit(GotoStatement *) { }
+ void visit(LabelStatement *s)
+ {
+ if (s->statement)
+ visitStmt(s->statement);
+ }
+ void visit(AsmStatement *) { }
+ void visit(ImportStatement *) { }
+};
+
+/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
+ */
+class NrvoWalker : public StatementRewriteWalker
+{
+public:
+ FuncDeclaration *fd;
+ Scope *sc;
+
+ void visit(ReturnStatement *s)
+ {
+ // See if all returns are instead to be replaced with a goto returnLabel;
+ if (fd->returnLabel)
+ {
+ /* Rewrite:
+ * return exp;
+ * as:
+ * vresult = exp; goto Lresult;
+ */
+ GotoStatement *gs = new GotoStatement(s->loc, Id::returnLabel);
+ gs->label = fd->returnLabel;
+
+ Statement *s1 = gs;
+ if (s->exp)
+ s1 = new CompoundStatement(s->loc, new ExpStatement(s->loc, s->exp), gs);
+
+ replaceCurrent(s1);
+ }
+ }
+ void visit(TryFinallyStatement *s)
+ {
+ DtorExpStatement *des;
+ if (fd->nrvo_can &&
+ s->finalbody && (des = s->finalbody->isDtorExpStatement()) != NULL &&
+ fd->nrvo_var == des->var)
+ {
+ /* Normally local variable dtors are called regardless exceptions.
+ * But for nrvo_var, its dtor should be called only when exception is thrown.
+ *
+ * Rewrite:
+ * try { s->body; } finally { nrvo_var->edtor; }
+ * // equivalent with:
+ * // s->body; scope(exit) nrvo_var->edtor;
+ * as:
+ * try { s->body; } catch(Throwable __o) { nrvo_var->edtor; throw __o; }
+ * // equivalent with:
+ * // s->body; scope(failure) nrvo_var->edtor;
+ */
+ Statement *sexception = new DtorExpStatement(Loc(), fd->nrvo_var->edtor, fd->nrvo_var);
+ Identifier *id = Identifier::generateId("__o");
+
+ Statement *handler = new PeelStatement(sexception);
+ if (blockExit(sexception, fd, false) & BEfallthru)
+ {
+ ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
+ ts->internalThrow = true;
+ handler = new CompoundStatement(Loc(), handler, ts);
+ }
+
+ Catches *catches = new Catches();
+ Catch *ctch = new Catch(Loc(), getThrowable(), id, handler);
+ ctch->internalCatch = true;
+ ::semantic(ctch, sc); // Run semantic to resolve identifier '__o'
+ catches->push(ctch);
+
+ Statement *s2 = new TryCatchStatement(Loc(), s->_body, catches);
+ replaceCurrent(s2);
+ s2->accept(this);
+ }
+ else
+ StatementRewriteWalker::visit(s);
+ }
+};
+
+/********************************* FuncDeclaration ****************************/
+
+FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
+ : Declaration(id)
+{
+ //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
+ //printf("storage_class = x%x\n", storage_class);
+ this->storage_class = storage_class;
+ this->type = type;
+ if (type)
+ {
+ // Normalize storage_class, because function-type related attributes
+ // are already set in the 'type' in parsing phase.
+ this->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
+ }
+ this->loc = loc;
+ this->endloc = endloc;
+ fthrows = NULL;
+ frequire = NULL;
+ fdrequire = NULL;
+ fdensure = NULL;
+ mangleString = NULL;
+ outId = NULL;
+ vresult = NULL;
+ returnLabel = NULL;
+ fensure = NULL;
+ fbody = NULL;
+ localsymtab = NULL;
+ vthis = NULL;
+ v_arguments = NULL;
+ v_argptr = NULL;
+ parameters = NULL;
+ labtab = NULL;
+ overnext = NULL;
+ overnext0 = NULL;
+ vtblIndex = -1;
+ hasReturnExp = 0;
+ naked = false;
+ generated = false;
+ inlineStatusExp = ILSuninitialized;
+ inlineStatusStmt = ILSuninitialized;
+ inlining = PINLINEdefault;
+ inlineNest = 0;
+ ctfeCode = NULL;
+ isArrayOp = 0;
+ semantic3Errors = false;
+ fes = NULL;
+ interfaceVirtual = NULL;
+ introducing = 0;
+ tintro = NULL;
+ /* The type given for "infer the return type" is a TypeFunction with
+ * NULL for the return type.
+ */
+ inferRetType = (type && type->nextOf() == NULL);
+ storage_class2 = 0;
+ hasReturnExp = 0;
+ nrvo_can = 1;
+ nrvo_var = NULL;
+ shidden = NULL;
+ builtin = BUILTINunknown;
+ tookAddressOf = 0;
+ requiresClosure = false;
+ inlinedNestedCallees = NULL;
+ flags = 0;
+ returns = NULL;
+ gotos = NULL;
+ selector = NULL;
+}
+
+FuncDeclaration *FuncDeclaration::create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
+{
+ return new FuncDeclaration(loc, endloc, id, storage_class, type);
+}
+
+Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
+{
+ //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
+ FuncDeclaration *f =
+ s ? (FuncDeclaration *)s
+ : new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy());
+ f->outId = outId;
+ f->frequire = frequire ? frequire->syntaxCopy() : NULL;
+ f->fensure = fensure ? fensure->syntaxCopy() : NULL;
+ f->fbody = fbody ? fbody->syntaxCopy() : NULL;
+ assert(!fthrows); // deprecated
+ return f;
+}
+
+/**********************************
+ * Decide if attributes for this function can be inferred from examining
+ * the function body.
+ * Returns:
+ * true if can
+ */
+static bool canInferAttributes(FuncDeclaration *fd, Scope *sc)
+{
+ if (!fd->fbody)
+ return false;
+
+ if (fd->isVirtualMethod())
+ return false; // since they may be overridden
+
+ if (sc->func &&
+ /********** this is for backwards compatibility for the moment ********/
+ (!fd->isMember() || (sc->func->isSafeBypassingInference() && !fd->isInstantiated())))
+ return true;
+
+ if (fd->isFuncLiteralDeclaration() || // externs are not possible with literals
+ (fd->storage_class & STCinference) || // do attribute inference
+ (fd->inferRetType && !fd->isCtorDeclaration()))
+ return true;
+
+ if (fd->isInstantiated())
+ {
+ TemplateInstance *ti = fd->parent->isTemplateInstance();
+ if (ti == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == fd->ident)
+ return true;
+ }
+
+ return false;
+}
+
+/*****************************************
+ * Initialize for inferring the attributes of this function.
+ */
+static void initInferAttributes(FuncDeclaration *fd)
+{
+ assert(fd->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (tf->purity == PUREimpure) // purity not specified
+ fd->flags |= FUNCFLAGpurityInprocess;
+
+ if (tf->trust == TRUSTdefault)
+ fd->flags |= FUNCFLAGsafetyInprocess;
+
+ if (!tf->isnothrow)
+ fd->flags |= FUNCFLAGnothrowInprocess;
+
+ if (!tf->isnogc)
+ fd->flags |= FUNCFLAGnogcInprocess;
+
+ if (!fd->isVirtual() || fd->introducing)
+ fd->flags |= FUNCFLAGreturnInprocess;
+
+ // Initialize for inferring STCscope
+ if (global.params.vsafe)
+ fd->flags |= FUNCFLAGinferScope;
+}
+
+// Do the semantic analysis on the external interface to the function.
+
+void FuncDeclaration::semantic(Scope *sc)
+{
+ TypeFunction *f;
+ AggregateDeclaration *ad;
+ InterfaceDeclaration *id;
+
+ if (semanticRun != PASSinit && isFuncLiteralDeclaration())
+ {
+ /* Member functions that have return types that are
+ * forward references can have semantic() run more than
+ * once on them.
+ * See test\interface2.d, test20
+ */
+ return;
+ }
+
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ assert(semanticRun <= PASSsemantic);
+ semanticRun = PASSsemantic;
+
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *parent = toParent();
+
+ foverrides.setDim(0); // reset in case semantic() is being retried for this function
+
+ storage_class |= sc->stc & ~STCref;
+ ad = isThis();
+ // Don't nest structs b/c of generated methods which should not access the outer scopes.
+ // https://issues.dlang.org/show_bug.cgi?id=16627
+ if (ad && !generated)
+ {
+ storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized);
+ ad->makeNested();
+ }
+ if (sc->func)
+ storage_class |= sc->func->storage_class & STCdisable;
+ // Remove prefix storage classes silently.
+ if ((storage_class & STC_TYPECTOR) && !(ad || isNested()))
+ storage_class &= ~STC_TYPECTOR;
+
+ //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", storage_class, sc->stc, Declaration::isFinal());
+
+ FuncLiteralDeclaration *fld = isFuncLiteralDeclaration();
+ if (fld && fld->treq)
+ {
+ Type *treq = fld->treq;
+ assert(treq->nextOf()->ty == Tfunction);
+ if (treq->ty == Tdelegate)
+ fld->tok = TOKdelegate;
+ else if (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)
+ fld->tok = TOKfunction;
+ else
+ assert(0);
+ linkage = ((TypeFunction *)treq->nextOf())->linkage;
+ }
+ else
+ linkage = sc->linkage;
+ inlining = sc->inlining;
+ protection = sc->protection;
+ userAttribDecl = sc->userAttribDecl;
+
+ if (!originalType)
+ originalType = type->syntaxCopy();
+ if (!type->deco)
+ {
+ sc = sc->push();
+ sc->stc |= storage_class & (STCdisable | STCdeprecated); // forward to function type
+ TypeFunction *tf = (TypeFunction *)type;
+
+ if (sc->func)
+ {
+ /* If the nesting parent is pure without inference,
+ * then this function defaults to pure too.
+ *
+ * auto foo() pure {
+ * auto bar() {} // become a weak purity funciton
+ * class C { // nested class
+ * auto baz() {} // become a weak purity funciton
+ * }
+ *
+ * static auto boo() {} // typed as impure
+ * // Even though, boo cannot call any impure functions.
+ * // See also Expression::checkPurity().
+ * }
+ */
+ if (tf->purity == PUREimpure && (isNested() || isThis()))
+ {
+ FuncDeclaration *fd = NULL;
+ for (Dsymbol *p = toParent2(); p; p = p->toParent2())
+ {
+ if (AggregateDeclaration *adx = p->isAggregateDeclaration())
+ {
+ if (adx->isNested())
+ continue;
+ break;
+ }
+ if ((fd = p->isFuncDeclaration()) != NULL)
+ break;
+ }
+
+ /* If the parent's purity is inferred, then this function's purity needs
+ * to be inferred first.
+ */
+ if (fd && fd->isPureBypassingInference() >= PUREweak &&
+ !isInstantiated())
+ {
+ tf->purity = PUREfwdref; // default to pure
+ }
+ }
+ }
+
+ if (tf->isref) sc->stc |= STCref;
+ if (tf->isscope) sc->stc |= STCscope;
+ if (tf->isnothrow) sc->stc |= STCnothrow;
+ if (tf->isnogc) sc->stc |= STCnogc;
+ if (tf->isproperty) sc->stc |= STCproperty;
+ if (tf->purity == PUREfwdref) sc->stc |= STCpure;
+ if (tf->trust != TRUSTdefault)
+ sc->stc &= ~(STCsafe | STCsystem | STCtrusted);
+ if (tf->trust == TRUSTsafe) sc->stc |= STCsafe;
+ if (tf->trust == TRUSTsystem) sc->stc |= STCsystem;
+ if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted;
+
+ if (isCtorDeclaration())
+ {
+ sc->flags |= SCOPEctor;
+
+ Type *tret = ad->handleType();
+ assert(tret);
+ tret = tret->addStorageClass(storage_class | sc->stc);
+ tret = tret->addMod(type->mod);
+ tf->next = tret;
+
+ if (ad->isStructDeclaration())
+ sc->stc |= STCref;
+ }
+
+ // 'return' on a non-static class member function implies 'scope' as well
+ if (ad && ad->isClassDeclaration() && (tf->isreturn || sc->stc & STCreturn) && !(sc->stc & STCstatic))
+ sc->stc |= STCscope;
+
+ // If 'this' has no pointers, remove 'scope' as it has no meaning
+ if (sc->stc & STCscope && ad && ad->isStructDeclaration() && !ad->type->hasPointers())
+ {
+ sc->stc &= ~STCscope;
+ tf->isscope = false;
+ }
+
+ sc->linkage = linkage;
+
+ if (!tf->isNaked() && !(isThis() || isNested()))
+ {
+ OutBuffer buf;
+ MODtoBuffer(&buf, tf->mod);
+ error("without 'this' cannot be %s", buf.peekString());
+ tf->mod = 0; // remove qualifiers
+ }
+
+ /* Apply const, immutable, wild and shared storage class
+ * to the function type. Do this before type semantic.
+ */
+ StorageClass stc = storage_class;
+ if (type->isImmutable())
+ stc |= STCimmutable;
+ if (type->isConst())
+ stc |= STCconst;
+ if (type->isShared() || storage_class & STCsynchronized)
+ stc |= STCshared;
+ if (type->isWild())
+ stc |= STCwild;
+ switch (stc & STC_TYPECTOR)
+ {
+ case STCimmutable:
+ case STCimmutable | STCconst:
+ case STCimmutable | STCwild:
+ case STCimmutable | STCwild | STCconst:
+ case STCimmutable | STCshared:
+ case STCimmutable | STCshared | STCconst:
+ case STCimmutable | STCshared | STCwild:
+ case STCimmutable | STCshared | STCwild | STCconst:
+ // Don't use immutableOf(), as that will do a merge()
+ type = type->makeImmutable();
+ break;
+
+ case STCconst:
+ type = type->makeConst();
+ break;
+
+ case STCwild:
+ type = type->makeWild();
+ break;
+
+ case STCwild | STCconst:
+ type = type->makeWildConst();
+ break;
+
+ case STCshared:
+ type = type->makeShared();
+ break;
+
+ case STCshared | STCconst:
+ type = type->makeSharedConst();
+ break;
+
+ case STCshared | STCwild:
+ type = type->makeSharedWild();
+ break;
+
+ case STCshared | STCwild | STCconst:
+ type = type->makeSharedWildConst();
+ break;
+
+ case 0:
+ break;
+
+ default:
+ assert(0);
+ }
+
+ type = type->semantic(loc, sc);
+ sc = sc->pop();
+ }
+ if (type->ty != Tfunction)
+ {
+ if (type->ty != Terror)
+ {
+ error("%s must be a function instead of %s", toChars(), type->toChars());
+ type = Type::terror;
+ }
+ errors = true;
+ return;
+ }
+ else
+ {
+ // Merge back function attributes into 'originalType'.
+ // It's used for mangling, ddoc, and json output.
+ TypeFunction *tfo = (TypeFunction *)originalType;
+ TypeFunction *tfx = (TypeFunction *)type;
+ tfo->mod = tfx->mod;
+ tfo->isscope = tfx->isscope;
+ tfo->isscopeinferred = tfx->isscopeinferred;
+ tfo->isref = tfx->isref;
+ tfo->isnothrow = tfx->isnothrow;
+ tfo->isnogc = tfx->isnogc;
+ tfo->isproperty = tfx->isproperty;
+ tfo->purity = tfx->purity;
+ tfo->trust = tfx->trust;
+
+ storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
+ }
+
+ f = (TypeFunction *)type;
+
+ if ((storage_class & STCauto) && !f->isref && !inferRetType)
+ error("storage class 'auto' has no effect if return type is not inferred");
+ /* Functions can only be 'scope' if they have a 'this'
+ */
+ if (f->isscope && !isNested() && !ad)
+ {
+ error("functions cannot be scope");
+ }
+
+ if (f->isreturn && !needThis() && !isNested())
+ {
+ /* Non-static nested functions have a hidden 'this' pointer to which
+ * the 'return' applies
+ */
+ error("static member has no 'this' to which 'return' can apply");
+ }
+
+ if (isAbstract() && !isVirtual())
+ {
+ const char *sfunc;
+ if (isStatic())
+ sfunc = "static";
+ else if (protection.kind == PROTprivate || protection.kind == PROTpackage)
+ sfunc = protectionToChars(protection.kind);
+ else
+ sfunc = "non-virtual";
+ error("%s functions cannot be abstract", sfunc);
+ }
+
+ if (isOverride() && !isVirtual())
+ {
+ PROTKIND kind = prot().kind;
+ if ((kind == PROTprivate || kind == PROTpackage) && isMember())
+ error("%s method is not virtual and cannot override", protectionToChars(kind));
+ else
+ error("cannot override a non-virtual function");
+ }
+
+ if (isAbstract() && isFinalFunc())
+ error("cannot be both final and abstract");
+
+ id = parent->isInterfaceDeclaration();
+ if (id)
+ {
+ storage_class |= STCabstract;
+
+ if (isCtorDeclaration() ||
+ isPostBlitDeclaration() ||
+ isDtorDeclaration() ||
+ isInvariantDeclaration() ||
+ isNewDeclaration() || isDelete())
+ error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id->toChars());
+ if (fbody && isVirtual())
+ error("function body only allowed in final functions in interface %s", id->toChars());
+ }
+
+ if (UnionDeclaration *ud = parent->isUnionDeclaration())
+ {
+ if (isPostBlitDeclaration() ||
+ isDtorDeclaration() ||
+ isInvariantDeclaration())
+ error("destructors, postblits and invariants are not allowed in union %s", ud->toChars());
+ }
+
+ /* Contracts can only appear without a body when they are virtual interface functions
+ */
+ if (!fbody && (fensure || frequire) && !(id && isVirtual()))
+ error("in and out contracts require function body");
+
+ if (parent->isStructDeclaration())
+ {
+ if (isCtorDeclaration())
+ {
+ goto Ldone;
+ }
+ }
+
+ if (ClassDeclaration *cd = parent->isClassDeclaration())
+ {
+ if (isCtorDeclaration())
+ {
+ goto Ldone;
+ }
+
+ if (storage_class & STCabstract)
+ cd->isabstract = ABSyes;
+
+ // if static function, do not put in vtbl[]
+ if (!isVirtual())
+ {
+ //printf("\tnot virtual\n");
+ goto Ldone;
+ }
+ // Suppress further errors if the return type is an error
+ if (type->nextOf() == Type::terror)
+ goto Ldone;
+
+ bool may_override = false;
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ BaseClass *b = (*cd->baseclasses)[i];
+ ClassDeclaration *cbd = b->type->toBasetype()->isClassHandle();
+ if (!cbd)
+ continue;
+ for (size_t j = 0; j < cbd->vtbl.dim; j++)
+ {
+ FuncDeclaration *f2 = cbd->vtbl[j]->isFuncDeclaration();
+ if (!f2 || f2->ident != ident)
+ continue;
+ if (cbd->parent && cbd->parent->isTemplateInstance())
+ {
+ if (!f2->functionSemantic())
+ goto Ldone;
+ }
+ may_override = true;
+ }
+ }
+ if (may_override && type->nextOf() == NULL)
+ {
+ /* If same name function exists in base class but 'this' is auto return,
+ * cannot find index of base class's vtbl[] to override.
+ */
+ error("return type inference is not supported if may override base class function");
+ }
+
+ /* Find index of existing function in base class's vtbl[] to override
+ * (the index will be the same as in cd's current vtbl[])
+ */
+ int vi = cd->baseClass ? findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.dim)
+ : -1;
+
+ bool doesoverride = false;
+ switch (vi)
+ {
+ case -1:
+ Lintro:
+ /* Didn't find one, so
+ * This is an 'introducing' function which gets a new
+ * slot in the vtbl[].
+ */
+
+ // Verify this doesn't override previous final function
+ if (cd->baseClass)
+ {
+ Dsymbol *s = cd->baseClass->search(loc, ident);
+ if (s)
+ {
+ FuncDeclaration *f2 = s->isFuncDeclaration();
+ if (f2)
+ {
+ f2 = f2->overloadExactMatch(type);
+ if (f2 && f2->isFinalFunc() && f2->prot().kind != PROTprivate)
+ error("cannot override final function %s", f2->toPrettyChars());
+ }
+ }
+ }
+
+ /* These quirky conditions mimic what VC++ appears to do
+ */
+ if (global.params.mscoff && cd->cpp &&
+ cd->baseClass && cd->baseClass->vtbl.dim)
+ {
+ /* if overriding an interface function, then this is not
+ * introducing and don't put it in the class vtbl[]
+ */
+ interfaceVirtual = overrideInterface();
+ if (interfaceVirtual)
+ {
+ //printf("\tinterface function %s\n", toChars());
+ cd->vtblFinal.push(this);
+ goto Linterfaces;
+ }
+ }
+
+ if (isFinalFunc())
+ {
+ // Don't check here, as it may override an interface function
+ //if (isOverride())
+ //error("is marked as override, but does not override any function");
+ cd->vtblFinal.push(this);
+ }
+ else
+ {
+ //printf("\tintroducing function %s\n", toChars());
+ introducing = 1;
+ if (cd->cpp && Target::reverseCppOverloads)
+ {
+ // with dmc, overloaded functions are grouped and in reverse order
+ vtblIndex = (int)cd->vtbl.dim;
+ for (int i = 0; i < (int)cd->vtbl.dim; i++)
+ {
+ if (cd->vtbl[i]->ident == ident && cd->vtbl[i]->parent == parent)
+ {
+ vtblIndex = (int)i;
+ break;
+ }
+ }
+ // shift all existing functions back
+ for (int i = (int)cd->vtbl.dim; i > vtblIndex; i--)
+ {
+ FuncDeclaration *fd = cd->vtbl[i-1]->isFuncDeclaration();
+ assert(fd);
+ fd->vtblIndex++;
+ }
+ cd->vtbl.insert(vtblIndex, this);
+ }
+ else
+ {
+ // Append to end of vtbl[]
+ vi = (int)cd->vtbl.dim;
+ cd->vtbl.push(this);
+ vtblIndex = vi;
+ }
+ }
+ break;
+
+ case -2:
+ // can't determine because of forward references
+ return;
+
+ default:
+ {
+ FuncDeclaration *fdv = cd->baseClass->vtbl[vi]->isFuncDeclaration();
+ FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration();
+ // This function is covariant with fdv
+
+ if (fdc == this)
+ {
+ doesoverride = true;
+ break;
+ }
+
+ if (fdc->toParent() == parent)
+ {
+ //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n",
+ // vi, this, this->toChars(), this->type->toChars(), this->loc.toChars(),
+ // fdc, fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(),
+ // fdv, fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars());
+
+ // fdc overrides fdv exactly, then this introduces new function.
+ if (fdc->type->mod == fdv->type->mod && this->type->mod != fdv->type->mod)
+ goto Lintro;
+ }
+
+ // This function overrides fdv
+ if (fdv->isFinalFunc())
+ error("cannot override final function %s", fdv->toPrettyChars());
+
+ if (!isOverride())
+ {
+ if (fdv->isFuture())
+ {
+ ::deprecation(loc, "@future base class method %s is being overridden by %s; rename the latter",
+ fdv->toPrettyChars(), toPrettyChars());
+ // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[]
+ goto Lintro;
+ }
+ else
+ {
+ int vi2 = findVtblIndex(&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.dim, false);
+ if (vi2 < 0)
+ // https://issues.dlang.org/show_bug.cgi?id=17349
+ ::deprecation(loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute",
+ fdv->toPrettyChars(), toPrettyChars());
+ else
+ ::error(loc, "implicitly overriding base class method %s with %s deprecated; add 'override' attribute",
+ fdv->toPrettyChars(), toPrettyChars());
+ }
+ }
+
+ doesoverride = true;
+ if (fdc->toParent() == parent)
+ {
+ // If both are mixins, or both are not, then error.
+ // If either is not, the one that is not overrides the other.
+ bool thismixin = this->parent->isClassDeclaration() != NULL;
+ bool fdcmixin = fdc->parent->isClassDeclaration() != NULL;
+ if (thismixin == fdcmixin)
+ {
+ error("multiple overrides of same function");
+ }
+ else if (!thismixin) // fdc overrides fdv
+ {
+ // this doesn't override any function
+ break;
+ }
+ }
+ cd->vtbl[vi] = this;
+ vtblIndex = vi;
+
+ /* Remember which functions this overrides
+ */
+ foverrides.push(fdv);
+
+ /* This works by whenever this function is called,
+ * it actually returns tintro, which gets dynamically
+ * cast to type. But we know that tintro is a base
+ * of type, so we could optimize it by not doing a
+ * dynamic cast, but just subtracting the isBaseOf()
+ * offset if the value is != null.
+ */
+
+ if (fdv->tintro)
+ tintro = fdv->tintro;
+ else if (!type->equals(fdv->type))
+ {
+ /* Only need to have a tintro if the vptr
+ * offsets differ
+ */
+ int offset;
+ if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
+ {
+ tintro = fdv->type;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Go through all the interface bases.
+ * If this function is covariant with any members of those interface
+ * functions, set the tintro.
+ */
+ Linterfaces:
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ vi = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.dim);
+ switch (vi)
+ {
+ case -1:
+ break;
+
+ case -2:
+ // can't determine because of forward references
+ return;
+
+ default:
+ {
+ FuncDeclaration *fdv = (FuncDeclaration *)b->sym->vtbl[vi];
+ Type *ti = NULL;
+
+ /* Remember which functions this overrides
+ */
+ foverrides.push(fdv);
+
+ /* Should we really require 'override' when implementing
+ * an interface function?
+ */
+ //if (!isOverride())
+ //warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars());
+
+ if (fdv->tintro)
+ ti = fdv->tintro;
+ else if (!type->equals(fdv->type))
+ {
+ /* Only need to have a tintro if the vptr
+ * offsets differ
+ */
+ int offset;
+ if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset))
+ {
+ ti = fdv->type;
+ }
+ }
+ if (ti)
+ {
+ if (tintro)
+ {
+ if (!tintro->nextOf()->equals(ti->nextOf()) &&
+ !tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) &&
+ !ti->nextOf()->isBaseOf(tintro->nextOf(), NULL))
+ {
+ error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars());
+ }
+ }
+ tintro = ti;
+ }
+ goto L2;
+ }
+ }
+ }
+
+ if (!doesoverride && isOverride() && (type->nextOf() || !may_override))
+ {
+ BaseClass *bc = NULL;
+ Dsymbol *s = NULL;
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ bc = (*cd->baseclasses)[i];
+ s = bc->sym->search_correct(ident);
+ if (s) break;
+ }
+
+ if (s)
+ error("does not override any function, did you mean to override '%s%s'?",
+ bc->sym->isCPPclass() ? "extern (C++) " : "", s->toPrettyChars());
+ else
+ error("does not override any function");
+ }
+
+ L2: ;
+
+ /* Go through all the interface bases.
+ * Disallow overriding any final functions in the interface(s).
+ */
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ if (b->sym)
+ {
+ Dsymbol *s = search_function(b->sym, ident);
+ if (s)
+ {
+ FuncDeclaration *f2 = s->isFuncDeclaration();
+ if (f2)
+ {
+ f2 = f2->overloadExactMatch(type);
+ if (f2 && f2->isFinalFunc() && f2->prot().kind != PROTprivate)
+ error("cannot override final function %s.%s", b->sym->toChars(), f2->toPrettyChars());
+ }
+ }
+ }
+ }
+
+ if (isOverride())
+ {
+ if (storage_class & STCdisable)
+ deprecation("overridden functions cannot be annotated @disable");
+ if (isDeprecated())
+ deprecation("deprecated functions cannot be annotated @disable");
+ }
+ }
+ else if (isOverride() && !parent->isTemplateInstance())
+ error("override only applies to class member functions");
+
+ // Reflect this->type to f because it could be changed by findVtblIndex
+ assert(type->ty == Tfunction);
+ f = (TypeFunction *)type;
+
+ /* Do not allow template instances to add virtual functions
+ * to a class.
+ */
+ if (isVirtual())
+ {
+ 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
+ ClassDeclaration *cd = ti->tempdecl->isClassMember();
+ if (cd)
+ {
+ error("cannot use template to add virtual function to class '%s'", cd->toChars());
+ }
+ }
+ }
+
+ if (isMain())
+ checkDmain(); // Check main() parameters and return type
+
+Ldone:
+ /* Purity and safety can be inferred for some functions by examining
+ * the function body.
+ */
+ if (canInferAttributes(this, sc))
+ initInferAttributes(this);
+
+ Module::dprogress++;
+ semanticRun = PASSsemanticdone;
+
+ /* Save scope for possible later use (if we need the
+ * function internals)
+ */
+ _scope = sc->copy();
+ _scope->setNoFree();
+
+ static bool printedMain = false; // semantic might run more than once
+ if (global.params.verbose && !printedMain)
+ {
+ const char *type = isMain() ? "main" : isWinMain() ? "winmain" : isDllMain() ? "dllmain" : (const char *)NULL;
+ Module *mod = sc->_module;
+
+ if (type && mod)
+ {
+ printedMain = true;
+ const char *name = FileName::searchPath(global.path, mod->srcfile->toChars(), true);
+ message("entry %-10s\t%s", type, name);
+ }
+ }
+
+ if (fbody && isMain() && sc->_module->isRoot())
+ Compiler::genCmain(sc);
+
+ assert(type->ty != Terror || errors);
+}
+
+void FuncDeclaration::semantic2(Scope *sc)
+{
+ if (semanticRun >= PASSsemantic2done)
+ return;
+ assert(semanticRun <= PASSsemantic2);
+ semanticRun = PASSsemantic2;
+
+ objc()->setSelector(this, sc);
+ objc()->validateSelector(this);
+
+ if (parent->isClassDeclaration())
+ {
+ objc()->checkLinkage(this);
+ }
+}
+
+/****************************************************
+ * Determine whether an 'out' contract is declared inside
+ * the given function or any of its overrides.
+ * Params:
+ * fd = the function to search
+ * Returns:
+ * true found an 'out' contract
+ * false didn't find one
+ */
+static bool needsFensure(FuncDeclaration *fd)
+{
+ if (fd->fensure)
+ return true;
+
+ for (size_t i = 0; i < fd->foverrides.dim; i++)
+ {
+ FuncDeclaration *fdv = fd->foverrides[i];
+
+ if (fdv->fensure)
+ return true;
+
+ if (needsFensure(fdv))
+ return true;
+ }
+ return false;
+}
+
+/****************************************************
+ * Rewrite contracts as nested functions, then call them. Doing it as nested
+ * functions means that overriding functions can call them.
+ * Params:
+ * fd = the function to rewrite contracts for
+ */
+static void buildEnsureRequire(FuncDeclaration *fdx)
+{
+ if (!fdx->isVirtual())
+ return;
+
+ TypeFunction *f = (TypeFunction *)fdx->type;
+
+ if (fdx->frequire)
+ {
+ /* in { ... }
+ * becomes:
+ * void __require() { ... }
+ * __require();
+ */
+ Loc loc = fdx->frequire->loc;
+ TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd);
+ tf->isnothrow = f->isnothrow;
+ tf->isnogc = f->isnogc;
+ tf->purity = f->purity;
+ tf->trust = f->trust;
+ FuncDeclaration *fd = new FuncDeclaration(loc, loc,
+ Id::require, STCundefined, tf);
+ fd->fbody = fdx->frequire;
+ Statement *s1 = new ExpStatement(loc, fd);
+ Expression *e = new CallExp(loc, new VarExp(loc, fd, false), (Expressions *)NULL);
+ Statement *s2 = new ExpStatement(loc, e);
+ fdx->frequire = new CompoundStatement(loc, s1, s2);
+ fdx->fdrequire = fd;
+ }
+
+ if (!fdx->outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid)
+ fdx->outId = Id::result; // provide a default
+
+ if (fdx->fensure)
+ {
+ /* out (result) { ... }
+ * becomes:
+ * void __ensure(ref tret result) { ... }
+ * __ensure(result);
+ */
+ Loc loc = fdx->fensure->loc;
+ Parameters *fparams = new Parameters();
+ Parameter *p = NULL;
+ if (fdx->outId)
+ {
+ p = new Parameter(STCref | STCconst, f->nextOf(), fdx->outId, NULL);
+ fparams->push(p);
+ }
+ TypeFunction *tf = new TypeFunction(fparams, Type::tvoid, 0, LINKd);
+ tf->isnothrow = f->isnothrow;
+ tf->isnogc = f->isnogc;
+ tf->purity = f->purity;
+ tf->trust = f->trust;
+ FuncDeclaration *fd = new FuncDeclaration(loc, loc,
+ Id::ensure, STCundefined, tf);
+ fd->fbody = fdx->fensure;
+ Statement *s1 = new ExpStatement(loc, fd);
+ Expression *eresult = NULL;
+ if (fdx->outId)
+ eresult = new IdentifierExp(loc, fdx->outId);
+ Expression *e = new CallExp(loc, new VarExp(loc, fd, false), eresult);
+ Statement *s2 = new ExpStatement(loc, e);
+ fdx->fensure = new CompoundStatement(loc, s1, s2);
+ fdx->fdensure = fd;
+ }
+}
+
+// Do the semantic analysis on the internals of the function.
+
+void FuncDeclaration::semantic3(Scope *sc)
+{
+ VarDeclaration *_arguments = NULL;
+
+ if (!parent)
+ {
+ if (global.errors)
+ return;
+ //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
+ assert(0);
+ }
+ if (errors || isError(parent))
+ {
+ errors = true;
+ return;
+ }
+ //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", parent->toChars(), toChars(), this, sc, loc.toChars());
+ //fflush(stdout);
+ //printf("storage class = x%x %x\n", sc->stc, storage_class);
+ //{ static int x; if (++x == 2) *(char*)0=0; }
+ //printf("\tlinkage = %d\n", sc->linkage);
+
+ if (ident == Id::assign && !inuse)
+ {
+ if (storage_class & STCinference)
+ {
+ /* Bugzilla 15044: For generated opAssign function, any errors
+ * from its body need to be gagged.
+ */
+ unsigned oldErrors = global.startGagging();
+ ++inuse;
+ semantic3(sc);
+ --inuse;
+ if (global.endGagging(oldErrors)) // if errors happened
+ {
+ // Disable generated opAssign, because some members forbid identity assignment.
+ storage_class |= STCdisable;
+ fbody = NULL; // remove fbody which contains the error
+ semantic3Errors = false;
+ }
+ return;
+ }
+ }
+
+ //printf(" sc->incontract = %d\n", (sc->flags & SCOPEcontract));
+ if (semanticRun >= PASSsemantic3)
+ return;
+ semanticRun = PASSsemantic3;
+ semantic3Errors = false;
+
+ if (!type || type->ty != Tfunction)
+ return;
+ TypeFunction *f = (TypeFunction *)type;
+ if (!inferRetType && f->next->ty == Terror)
+ return;
+
+ if (!fbody && inferRetType && !f->next)
+ {
+ error("has no function body with return type inference");
+ return;
+ }
+
+ unsigned oldErrors = global.errors;
+
+ if (frequire)
+ {
+ for (size_t i = 0; i < foverrides.dim; i++)
+ {
+ FuncDeclaration *fdv = foverrides[i];
+
+ if (fdv->fbody && !fdv->frequire)
+ {
+ error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars());
+ break;
+ }
+ }
+ }
+
+ // Remember whether we need to generate an 'out' contract.
+ bool needEnsure = needsFensure(this);
+
+ if (fbody || frequire || needEnsure)
+ {
+ /* Symbol table into which we place parameters and nested functions,
+ * solely to diagnose name collisions.
+ */
+ localsymtab = new DsymbolTable();
+
+ // Establish function scope
+ ScopeDsymbol *ss = new ScopeDsymbol();
+ // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
+ for (Scope *scx = sc; ; scx = scx->enclosing)
+ {
+ if (scx->scopesym)
+ {
+ ss->parent = scx->scopesym;
+ break;
+ }
+ }
+ ss->loc = loc;
+ ss->endlinnum = endloc.linnum;
+ Scope *sc2 = sc->push(ss);
+ sc2->func = this;
+ sc2->parent = this;
+ sc2->callSuper = 0;
+ sc2->sbreak = NULL;
+ sc2->scontinue = NULL;
+ sc2->sw = NULL;
+ sc2->fes = fes;
+ sc2->linkage = LINKd;
+ sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract |
+ STCdeprecated | STCoverride |
+ STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | STCreturn |
+ STCproperty | STCnothrow | STCpure | STCsafe | STCtrusted | STCsystem);
+ sc2->protection = Prot(PROTpublic);
+ sc2->explicitProtection = 0;
+ sc2->aligndecl = NULL;
+ if (this->ident != Id::require && this->ident != Id::ensure)
+ sc2->flags = sc->flags & ~SCOPEcontract;
+ sc2->flags &= ~SCOPEcompile;
+ sc2->tf = NULL;
+ sc2->os = NULL;
+ sc2->noctor = 0;
+ sc2->userAttribDecl = NULL;
+ if (sc2->intypeof == 1) sc2->intypeof = 2;
+ sc2->fieldinit = NULL;
+ sc2->fieldinit_dim = 0;
+
+ /* Note: When a lambda is defined immediately under aggregate member
+ * scope, it should be contextless due to prevent interior pointers.
+ * e.g.
+ * // dg points 'this' - it's interior pointer
+ * class C { int x; void delegate() dg = (){ this.x = 1; }; }
+ *
+ * However, lambdas could be used inside typeof, in order to check
+ * some expressions varidity at compile time. For such case the lambda
+ * body can access aggregate instance members.
+ * e.g.
+ * class C { int x; static assert(is(typeof({ this.x = 1; }))); }
+ *
+ * To properly accept it, mark these lambdas as member functions -
+ * isThis() returns true and isNested() returns false.
+ */
+ if (FuncLiteralDeclaration *fld = isFuncLiteralDeclaration())
+ {
+ if (AggregateDeclaration *ad = isMember2())
+ {
+ if (!sc->intypeof)
+ {
+ if (fld->tok == TOKdelegate)
+ error("cannot be %s members", ad->kind());
+ else
+ fld->tok = TOKfunction;
+ }
+ else
+ {
+ if (fld->tok != TOKfunction)
+ fld->tok = TOKdelegate;
+ }
+ assert(!isNested());
+ }
+ }
+
+ // Declare 'this'
+ AggregateDeclaration *ad = isThis();
+ vthis = declareThis(sc2, ad);
+ //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis);
+ //if (vthis) printf("\tvthis->type = %s\n", vthis->type->toChars());
+
+ // Declare hidden variable _arguments[] and _argptr
+ if (f->varargs == 1)
+ {
+ if (f->linkage == LINKd)
+ {
+ // Declare _arguments[]
+ v_arguments = new VarDeclaration(Loc(), Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL);
+ v_arguments->storage_class |= STCtemp | STCparameter;
+ v_arguments->semantic(sc2);
+ sc2->insert(v_arguments);
+ v_arguments->parent = this;
+
+ //Type *t = Type::typeinfo->type->constOf()->arrayOf();
+ Type *t = Type::dtypeinfo->type->arrayOf();
+ _arguments = new VarDeclaration(Loc(), t, Id::_arguments, NULL);
+ _arguments->storage_class |= STCtemp;
+ _arguments->semantic(sc2);
+ sc2->insert(_arguments);
+ _arguments->parent = this;
+ }
+ if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters)))
+ {
+ // Declare _argptr
+ Type *t = Type::tvalist;
+ v_argptr = new VarDeclaration(Loc(), t, Id::_argptr, NULL);
+ v_argptr->storage_class |= STCtemp;
+ v_argptr->semantic(sc2);
+ sc2->insert(v_argptr);
+ v_argptr->parent = this;
+ }
+ }
+
+ /* Declare all the function parameters as variables
+ * and install them in parameters[]
+ */
+ size_t nparams = Parameter::dim(f->parameters);
+ if (nparams)
+ {
+ /* parameters[] has all the tuples removed, as the back end
+ * doesn't know about tuples
+ */
+ parameters = new VarDeclarations();
+ parameters->reserve(nparams);
+ for (size_t i = 0; i < nparams; i++)
+ {
+ Parameter *fparam = Parameter::getNth(f->parameters, i);
+ Identifier *id = fparam->ident;
+ StorageClass stc = 0;
+ if (!id)
+ {
+ /* Generate identifier for un-named parameter,
+ * because we need it later on.
+ */
+ fparam->ident = id = Identifier::generateId("_param_", i);
+ stc |= STCtemp;
+ }
+ Type *vtype = fparam->type;
+ VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL);
+ //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars());
+ stc |= STCparameter;
+ if (f->varargs == 2 && i + 1 == nparams)
+ stc |= STCvariadic;
+ if (flags & FUNCFLAGinferScope && !(fparam->storageClass & STCscope))
+ stc |= STCmaybescope;
+ stc |= fparam->storageClass & (STCin | STCout | STCref | STCreturn | STCscope | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
+ v->storage_class = stc;
+ v->semantic(sc2);
+ if (!sc2->insert(v))
+ error("parameter %s.%s is already defined", toChars(), v->toChars());
+ else
+ parameters->push(v);
+ localsymtab->insert(v);
+ v->parent = this;
+ }
+ }
+
+ // Declare the tuple symbols and put them in the symbol table,
+ // but not in parameters[].
+ if (f->parameters)
+ {
+ for (size_t i = 0; i < f->parameters->dim; i++)
+ {
+ Parameter *fparam = (*f->parameters)[i];
+
+ if (!fparam->ident)
+ continue; // never used, so ignore
+ if (fparam->type->ty == Ttuple)
+ {
+ TypeTuple *t = (TypeTuple *)fparam->type;
+ size_t dim = Parameter::dim(t->arguments);
+ Objects *exps = new Objects();
+ exps->setDim(dim);
+ for (size_t j = 0; j < dim; j++)
+ {
+ Parameter *narg = Parameter::getNth(t->arguments, j);
+ assert(narg->ident);
+ VarDeclaration *v = sc2->search(Loc(), narg->ident, NULL)->isVarDeclaration();
+ assert(v);
+ Expression *e = new VarExp(v->loc, v);
+ (*exps)[j] = e;
+ }
+ assert(fparam->ident);
+ TupleDeclaration *v = new TupleDeclaration(loc, fparam->ident, exps);
+ //printf("declaring tuple %s\n", v->toChars());
+ v->isexp = true;
+ if (!sc2->insert(v))
+ error("parameter %s.%s is already defined", toChars(), v->toChars());
+ localsymtab->insert(v);
+ v->parent = this;
+ }
+ }
+ }
+
+ // Precondition invariant
+ Statement *fpreinv = NULL;
+ if (addPreInvariant())
+ {
+ Expression *e = addInvariant(loc, sc, ad, vthis, isDtorDeclaration() != NULL);
+ if (e)
+ fpreinv = new ExpStatement(Loc(), e);
+ }
+
+ // Postcondition invariant
+ Statement *fpostinv = NULL;
+ if (addPostInvariant())
+ {
+ Expression *e = addInvariant(loc, sc, ad, vthis, isCtorDeclaration() != NULL);
+ if (e)
+ fpostinv = new ExpStatement(Loc(), e);
+ }
+
+ // Pre/Postcondition contract
+ if (!fbody)
+ buildEnsureRequire(this);
+
+ Scope *scout = NULL;
+ if (needEnsure || addPostInvariant())
+ {
+ if ((needEnsure && global.params.useOut) || fpostinv)
+ {
+ returnLabel = new LabelDsymbol(Id::returnLabel);
+ }
+
+ // scope of out contract (need for vresult->semantic)
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc2->scopesym;
+ sym->loc = loc;
+ sym->endlinnum = endloc.linnum;
+ scout = sc2->push(sym);
+ }
+
+ if (fbody)
+ {
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc2->scopesym;
+ sym->loc = loc;
+ sym->endlinnum = endloc.linnum;
+ sc2 = sc2->push(sym);
+
+ AggregateDeclaration *ad2 = isMember2();
+
+ /* If this is a class constructor
+ */
+ if (ad2 && isCtorDeclaration())
+ {
+ allocFieldinit(sc2, ad2->fields.dim);
+ for (size_t i = 0; i < ad2->fields.dim; i++)
+ {
+ VarDeclaration *v = ad2->fields[i];
+ v->ctorinit = 0;
+ }
+ }
+
+ if (!inferRetType && retStyle(f) != RETstack)
+ nrvo_can = 0;
+
+ bool inferRef = (f->isref && (storage_class & STCauto));
+
+ fbody = ::semantic(fbody, sc2);
+ if (!fbody)
+ fbody = new CompoundStatement(Loc(), new Statements());
+
+ if (naked)
+ {
+ fpreinv = NULL; // can't accommodate with no stack frame
+ fpostinv = NULL;
+ }
+
+ assert(type == f ||
+ (type->ty == Tfunction &&
+ f->purity == PUREimpure &&
+ ((TypeFunction *)type)->purity >= PUREfwdref));
+ f = (TypeFunction *)type;
+
+ if (inferRetType)
+ {
+ // If no return type inferred yet, then infer a void
+ if (!f->next)
+ f->next = Type::tvoid;
+ if (f->checkRetType(loc))
+ fbody = new ErrorStatement();
+ }
+ if (global.params.vcomplex && f->next != NULL)
+ f->next->checkComplexTransition(loc);
+
+ if (returns && !fbody->isErrorStatement())
+ {
+ for (size_t i = 0; i < returns->dim; )
+ {
+ Expression *exp = (*returns)[i]->exp;
+ if (exp->op == TOKvar && ((VarExp *)exp)->var == vresult)
+ {
+ exp->type = f->next;
+ // Remove `return vresult;` from returns
+ returns->remove(i);
+ continue;
+ }
+ if (inferRef && f->isref && !exp->type->constConv(f->next)) // Bugzilla 13336
+ f->isref = false;
+ i++;
+ }
+ }
+ if (f->isref) // Function returns a reference
+ {
+ if (storage_class & STCauto)
+ storage_class &= ~STCauto;
+ }
+ if (retStyle(f) != RETstack)
+ nrvo_can = 0;
+
+ if (fbody->isErrorStatement())
+ ;
+ else if (isStaticCtorDeclaration())
+ {
+ /* It's a static constructor. Ensure that all
+ * ctor consts were initialized.
+ */
+ ScopeDsymbol *pd = toParent()->isScopeDsymbol();
+ for (size_t i = 0; i < pd->members->dim; i++)
+ {
+ Dsymbol *s = (*pd->members)[i];
+ s->checkCtorConstInit();
+ }
+ }
+ else if (ad2 && isCtorDeclaration())
+ {
+ ClassDeclaration *cd = ad2->isClassDeclaration();
+
+ // Verify that all the ctorinit fields got initialized
+ if (!(sc2->callSuper & CSXthis_ctor))
+ {
+ for (size_t i = 0; i < ad2->fields.dim; i++)
+ {
+ VarDeclaration *v = ad2->fields[i];
+ if (v->isThisDeclaration())
+ continue;
+ if (v->ctorinit == 0)
+ {
+ /* Current bugs in the flow analysis:
+ * 1. union members should not produce error messages even if
+ * not assigned to
+ * 2. structs should recognize delegating opAssign calls as well
+ * as delegating calls to other constructors
+ */
+ if (v->isCtorinit() && !v->type->isMutable() && cd)
+ error("missing initializer for %s field %s", MODtoChars(v->type->mod), v->toChars());
+ else if (v->storage_class & STCnodefaultctor)
+ ::error(loc, "field %s must be initialized in constructor", v->toChars());
+ else if (v->type->needsNested())
+ ::error(loc, "field %s must be initialized in constructor, because it is nested struct", v->toChars());
+ }
+ else
+ {
+ bool mustInit = (v->storage_class & STCnodefaultctor ||
+ v->type->needsNested());
+ if (mustInit && !(sc2->fieldinit[i] & CSXthis_ctor))
+ {
+ error("field %s must be initialized but skipped", v->toChars());
+ }
+ }
+ }
+ }
+ freeFieldinit(sc2);
+
+ if (cd &&
+ !(sc2->callSuper & CSXany_ctor) &&
+ cd->baseClass && cd->baseClass->ctor)
+ {
+ sc2->callSuper = 0;
+
+ // Insert implicit super() at start of fbody
+ FuncDeclaration *fd = resolveFuncCall(Loc(), sc2, cd->baseClass->ctor, NULL, vthis->type, NULL, 1);
+ if (!fd)
+ {
+ error("no match for implicit super() call in constructor");
+ }
+ else if (fd->storage_class & STCdisable)
+ {
+ error("cannot call super() implicitly because it is annotated with @disable");
+ }
+ else
+ {
+ Expression *e1 = new SuperExp(Loc());
+ Expression *e = new CallExp(Loc(), e1);
+ e = ::semantic(e, sc2);
+
+ Statement *s = new ExpStatement(Loc(), e);
+ fbody = new CompoundStatement(Loc(), s, fbody);
+ }
+ }
+ //printf("callSuper = x%x\n", sc2->callSuper);
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=17502
+ * Wait until after the return type has been inferred before
+ * generating the contracts for this function, and merging contracts
+ * from overrides.
+ *
+ * https://issues.dlang.org/show_bug.cgi?id=17893
+ * However should take care to generate this before inferered
+ * function attributes are applied, such as 'nothrow'.
+ *
+ * This was originally at the end of the first semantic pass, but
+ * required a fix-up to be done here for the '__result' variable
+ * type of __ensure() inside auto functions, but this didn't work
+ * if the out parameter was implicit.
+ */
+ buildEnsureRequire(this);
+
+ int blockexit = BEnone;
+ if (!fbody->isErrorStatement())
+ {
+ // Check for errors related to 'nothrow'.
+ unsigned int nothrowErrors = global.errors;
+ blockexit = blockExit(fbody, this, f->isnothrow);
+ if (f->isnothrow && (global.errors != nothrowErrors))
+ ::error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars());
+ if (flags & FUNCFLAGnothrowInprocess)
+ {
+ if (type == f) f = (TypeFunction *)f->copy();
+ f->isnothrow = !(blockexit & BEthrow);
+ }
+ }
+
+ if (fbody->isErrorStatement())
+ ;
+ else if (ad2 && isCtorDeclaration())
+ {
+ /* Append:
+ * return this;
+ * to function body
+ */
+ if (blockexit & BEfallthru)
+ {
+ Statement *s = new ReturnStatement(loc, NULL);
+ s = ::semantic(s, sc2);
+ fbody = new CompoundStatement(loc, fbody, s);
+ hasReturnExp |= (hasReturnExp & 1 ? 16 : 1);
+ }
+ }
+ else if (fes)
+ {
+ // For foreach(){} body, append a return 0;
+ if (blockexit & BEfallthru)
+ {
+ Expression *e = new IntegerExp(0);
+ Statement *s = new ReturnStatement(Loc(), e);
+ fbody = new CompoundStatement(Loc(), fbody, s);
+ hasReturnExp |= (hasReturnExp & 1 ? 16 : 1);
+ }
+ assert(!returnLabel);
+ }
+ else
+ {
+ const bool inlineAsm = (hasReturnExp & 8) != 0;
+ if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
+ {
+ Expression *e;
+ if (!hasReturnExp)
+ error("has no return statement, but is expected to return a value of type %s", f->next->toChars());
+ else
+ error("no return exp; or assert(0); at end of function");
+ if (global.params.useAssert &&
+ !global.params.useInline)
+ {
+ /* Add an assert(0, msg); where the missing return
+ * should be.
+ */
+ e = new AssertExp(
+ endloc,
+ new IntegerExp(0),
+ new StringExp(loc, const_cast<char *>("missing return expression"))
+ );
+ }
+ else
+ e = new HaltExp(endloc);
+ e = new CommaExp(Loc(), e, f->next->defaultInit());
+ e = ::semantic(e, sc2);
+ Statement *s = new ExpStatement(Loc(), e);
+ fbody = new CompoundStatement(Loc(), fbody, s);
+ }
+ }
+
+ if (returns)
+ {
+ bool implicit0 = (f->next->ty == Tvoid && isMain());
+ Type *tret = implicit0 ? Type::tint32 : f->next;
+ assert(tret->ty != Tvoid);
+ if (vresult || returnLabel)
+ buildResultVar(scout ? scout : sc2, tret);
+
+ /* Cannot move this loop into NrvoWalker, because
+ * returns[i] may be in the nested delegate for foreach-body.
+ */
+ for (size_t i = 0; i < returns->dim; i++)
+ {
+ ReturnStatement *rs = (*returns)[i];
+ Expression *exp = rs->exp;
+ if (exp->op == TOKerror)
+ continue;
+ if (tret->ty == Terror)
+ {
+ // Bugzilla 13702
+ exp = checkGC(sc2, exp);
+ continue;
+ }
+
+ if (!exp->implicitConvTo(tret) &&
+ parametersIntersect(exp->type))
+ {
+ if (exp->type->immutableOf()->implicitConvTo(tret))
+ exp = exp->castTo(sc2, exp->type->immutableOf());
+ else if (exp->type->wildOf()->implicitConvTo(tret))
+ exp = exp->castTo(sc2, exp->type->wildOf());
+ }
+ exp = exp->implicitCastTo(sc2, tret);
+
+ if (f->isref)
+ {
+ // Function returns a reference
+ exp = exp->toLvalue(sc2, exp);
+ checkReturnEscapeRef(sc2, exp, false);
+ }
+ else
+ {
+ exp = exp->optimize(WANTvalue);
+
+ /* Bugzilla 10789:
+ * If NRVO is not possible, all returned lvalues should call their postblits.
+ */
+ if (!nrvo_can)
+ exp = doCopyOrMove(sc2, exp);
+
+ if (tret->hasPointers())
+ checkReturnEscape(sc2, exp, false);
+ }
+
+ exp = checkGC(sc2, exp);
+
+ if (vresult)
+ {
+ // Create: return vresult = exp;
+ exp = new BlitExp(rs->loc, vresult, exp);
+ exp->type = vresult->type;
+
+ if (rs->caseDim)
+ exp = Expression::combine(exp, new IntegerExp(rs->caseDim));
+ }
+ else if (tintro && !tret->equals(tintro->nextOf()))
+ {
+ exp = exp->implicitCastTo(sc2, tintro->nextOf());
+ }
+ rs->exp = exp;
+ }
+ }
+ if (nrvo_var || returnLabel)
+ {
+ NrvoWalker nw;
+ nw.fd = this;
+ nw.sc = sc2;
+ nw.visitStmt(fbody);
+ }
+
+ sc2 = sc2->pop();
+ }
+
+ frequire = mergeFrequire(frequire);
+ fensure = mergeFensure(fensure, outId);
+
+ Statement *freq = frequire;
+ Statement *fens = fensure;
+
+ /* Do the semantic analysis on the [in] preconditions and
+ * [out] postconditions.
+ */
+ if (freq)
+ {
+ /* frequire is composed of the [in] contracts
+ */
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc2->scopesym;
+ sym->loc = loc;
+ sym->endlinnum = endloc.linnum;
+ sc2 = sc2->push(sym);
+ sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPErequire;
+
+ // BUG: need to error if accessing out parameters
+ // BUG: need to treat parameters as const
+ // BUG: need to disallow returns and throws
+ // BUG: verify that all in and ref parameters are read
+ freq = ::semantic(freq, sc2);
+ blockExit(freq, this, false);
+
+ sc2 = sc2->pop();
+
+ if (!global.params.useIn)
+ freq = NULL;
+ }
+
+ if (fens)
+ {
+ /* fensure is composed of the [out] contracts
+ */
+ if (f->next->ty == Tvoid && outId)
+ error("void functions have no result");
+
+ sc2 = scout; //push
+ sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPEensure;
+
+ // BUG: need to treat parameters as const
+ // BUG: need to disallow returns and throws
+ if (fensure && f->next->ty != Tvoid)
+ buildResultVar(scout, f->next);
+
+ fens = ::semantic(fens, sc2);
+ blockExit(fens, this, false);
+
+ sc2 = sc2->pop();
+
+ if (!global.params.useOut)
+ fens = NULL;
+ }
+
+ if (fbody && fbody->isErrorStatement())
+ ;
+ else
+ {
+ Statements *a = new Statements();
+
+ // Merge in initialization of 'out' parameters
+ if (parameters)
+ {
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ VarDeclaration *v = (*parameters)[i];
+ if (v->storage_class & STCout)
+ {
+ assert(v->_init);
+ ExpInitializer *ie = v->_init->isExpInitializer();
+ assert(ie);
+ if (ie->exp->op == TOKconstruct)
+ ie->exp->op = TOKassign; // construction occured in parameter processing
+ a->push(new ExpStatement(Loc(), ie->exp));
+ }
+ }
+ }
+
+ if (v_argptr)
+ {
+ // Handled in FuncDeclaration::toObjFile
+ v_argptr->_init = new VoidInitializer(loc);
+ }
+
+ if (_arguments)
+ {
+ /* Advance to elements[] member of TypeInfo_Tuple with:
+ * _arguments = v_arguments.elements;
+ */
+ Expression *e = new VarExp(Loc(), v_arguments);
+ e = new DotIdExp(Loc(), e, Id::elements);
+ e = new ConstructExp(Loc(), _arguments, e);
+ e = ::semantic(e, sc2);
+
+ _arguments->_init = new ExpInitializer(Loc(), e);
+ DeclarationExp *de = new DeclarationExp(Loc(), _arguments);
+ a->push(new ExpStatement(Loc(), de));
+ }
+
+ // Merge contracts together with body into one compound statement
+
+ if (freq || fpreinv)
+ {
+ if (!freq)
+ freq = fpreinv;
+ else if (fpreinv)
+ freq = new CompoundStatement(Loc(), freq, fpreinv);
+
+ a->push(freq);
+ }
+
+ if (fbody)
+ a->push(fbody);
+
+ if (fens || fpostinv)
+ {
+ if (!fens)
+ fens = fpostinv;
+ else if (fpostinv)
+ fens = new CompoundStatement(Loc(), fpostinv, fens);
+
+ LabelStatement *ls = new LabelStatement(Loc(), Id::returnLabel, fens);
+ returnLabel->statement = ls;
+ a->push(returnLabel->statement);
+
+ if (f->next->ty != Tvoid && vresult)
+ {
+ // Create: return vresult;
+ Expression *e = new VarExp(Loc(), vresult);
+ if (tintro)
+ {
+ e = e->implicitCastTo(sc, tintro->nextOf());
+ e = ::semantic(e, sc);
+ }
+ ReturnStatement *s = new ReturnStatement(Loc(), e);
+ a->push(s);
+ }
+ }
+ if (isMain() && f->next->ty == Tvoid)
+ {
+ // Add a return 0; statement
+ Statement *s = new ReturnStatement(Loc(), new IntegerExp(0));
+ a->push(s);
+ }
+
+ Statement *sbody = new CompoundStatement(Loc(), a);
+ /* Append destructor calls for parameters as finally blocks.
+ */
+ if (parameters)
+ {
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ VarDeclaration *v = (*parameters)[i];
+
+ if (v->storage_class & (STCref | STCout | STClazy))
+ continue;
+
+ if (v->needsScopeDtor())
+ {
+ // same with ExpStatement.scopeCode()
+ Statement *s = new DtorExpStatement(Loc(), v->edtor, v);
+ v->storage_class |= STCnodtor;
+
+ s = ::semantic(s, sc2);
+
+ bool isnothrow = f->isnothrow & !(flags & FUNCFLAGnothrowInprocess);
+ int blockexit = blockExit(s, this, isnothrow);
+ if (f->isnothrow && isnothrow && blockexit & BEthrow)
+ ::error(loc, "nothrow %s '%s' may throw", kind(), toPrettyChars());
+ if (flags & FUNCFLAGnothrowInprocess && blockexit & BEthrow)
+ f->isnothrow = false;
+ if (blockExit(sbody, this, f->isnothrow) == BEfallthru)
+ sbody = new CompoundStatement(Loc(), sbody, s);
+ else
+ sbody = new TryFinallyStatement(Loc(), sbody, s);
+ }
+ }
+ }
+ // from this point on all possible 'throwers' are checked
+ flags &= ~FUNCFLAGnothrowInprocess;
+
+ if (isSynchronized())
+ {
+ /* Wrap the entire function body in a synchronized statement
+ */
+ ClassDeclaration *cd = isThis() ? isThis()->isClassDeclaration() : parent->isClassDeclaration();
+
+ if (cd)
+ {
+ if (!global.params.is64bit &&
+ global.params.isWindows &&
+ !isStatic() && !sbody->usesEH() && !global.params.trace)
+ {
+ /* The back end uses the "jmonitor" hack for syncing;
+ * no need to do the sync at this level.
+ */
+ }
+ else
+ {
+ Expression *vsync;
+ if (isStatic())
+ {
+ // The monitor is in the ClassInfo
+ vsync = new DotIdExp(loc, resolve(loc, sc2, cd, false), Id::classinfo);
+ }
+ else
+ {
+ // 'this' is the monitor
+ vsync = new VarExp(loc, vthis);
+ }
+ sbody = new PeelStatement(sbody); // don't redo semantic()
+ sbody = new SynchronizedStatement(loc, vsync, sbody);
+ sbody = ::semantic(sbody, sc2);
+ }
+ }
+ else
+ {
+ error("synchronized function %s must be a member of a class", toChars());
+ }
+ }
+
+ // If declaration has no body, don't set sbody to prevent incorrect codegen.
+ InterfaceDeclaration *id = parent->isInterfaceDeclaration();
+ if (fbody || (id && (fdensure || fdrequire) && isVirtual()))
+ fbody = sbody;
+ }
+
+ // Fix up forward-referenced gotos
+ if (gotos)
+ {
+ for (size_t i = 0; i < gotos->dim; ++i)
+ {
+ (*gotos)[i]->checkLabel();
+ }
+ }
+
+ if (naked && (fensure || frequire))
+ error("naked assembly functions with contracts are not supported");
+
+ sc2->callSuper = 0;
+ sc2->pop();
+ }
+
+ if (checkClosure())
+ {
+ // We should be setting errors here instead of relying on the global error count.
+ //errors = true;
+ }
+
+ /* If function survived being marked as impure, then it is pure
+ */
+ if (flags & FUNCFLAGpurityInprocess)
+ {
+ flags &= ~FUNCFLAGpurityInprocess;
+ if (type == f)
+ f = (TypeFunction *)f->copy();
+ f->purity = PUREfwdref;
+ }
+
+ if (flags & FUNCFLAGsafetyInprocess)
+ {
+ flags &= ~FUNCFLAGsafetyInprocess;
+ if (type == f)
+ f = (TypeFunction *)f->copy();
+ f->trust = TRUSTsafe;
+ }
+
+ if (flags & FUNCFLAGnogcInprocess)
+ {
+ flags &= ~FUNCFLAGnogcInprocess;
+ if (type == f)
+ f = (TypeFunction *)f->copy();
+ f->isnogc = true;
+ }
+
+ if (flags & FUNCFLAGreturnInprocess)
+ {
+ flags &= ~FUNCFLAGreturnInprocess;
+ if (storage_class & STCreturn)
+ {
+ if (type == f)
+ f = (TypeFunction *)f->copy();
+ f->isreturn = true;
+ }
+ }
+
+ flags &= ~FUNCFLAGinferScope;
+
+ // Infer STCscope
+ if (parameters)
+ {
+ size_t nfparams = Parameter::dim(f->parameters);
+ assert(nfparams == parameters->dim);
+ for (size_t u = 0; u < parameters->dim; u++)
+ {
+ VarDeclaration *v = (*parameters)[u];
+ if (v->storage_class & STCmaybescope)
+ {
+ //printf("Inferring scope for %s\n", v->toChars());
+ Parameter *p = Parameter::getNth(f->parameters, u);
+ v->storage_class &= ~STCmaybescope;
+ v->storage_class |= STCscope | STCscopeinferred;
+ p->storageClass |= STCscope | STCscopeinferred;
+ assert(!(p->storageClass & STCmaybescope));
+ }
+ }
+ }
+
+ if (vthis && vthis->storage_class & STCmaybescope)
+ {
+ vthis->storage_class &= ~STCmaybescope;
+ vthis->storage_class |= STCscope | STCscopeinferred;
+ f->isscope = true;
+ f->isscopeinferred = true;
+ }
+
+ // reset deco to apply inference result to mangled name
+ if (f != type)
+ f->deco = NULL;
+
+ // Do semantic type AFTER pure/nothrow inference.
+ if (!f->deco && ident != Id::xopEquals && ident != Id::xopCmp)
+ {
+ sc = sc->push();
+ if (isCtorDeclaration()) // Bugzilla #15665
+ sc->flags |= SCOPEctor;
+ sc->stc = 0;
+ sc->linkage = linkage; // Bugzilla 8496
+ type = f->semantic(loc, sc);
+ sc = sc->pop();
+ }
+
+ /* If this function had instantiated with gagging, error reproduction will be
+ * done by TemplateInstance::semantic.
+ * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
+ */
+ semanticRun = PASSsemantic3done;
+ semantic3Errors = (global.errors != oldErrors) || (fbody && fbody->isErrorStatement());
+ if (type->ty == Terror)
+ errors = true;
+ //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars());
+ //fflush(stdout);
+}
+
+/****************************************************
+ * Resolve forward reference of function signature -
+ * parameter types, return type, and attributes.
+ * Returns false if any errors exist in the signature.
+ */
+bool FuncDeclaration::functionSemantic()
+{
+ if (!_scope)
+ return !errors;
+
+ if (!originalType) // semantic not yet run
+ {
+ TemplateInstance *spec = isSpeculative();
+ unsigned olderrs = global.errors;
+ unsigned oldgag = global.gag;
+ if (global.gag && !spec)
+ global.gag = 0;
+ semantic(_scope);
+ global.gag = oldgag;
+ if (spec && global.errors != olderrs)
+ spec->errors = (global.errors - olderrs != 0);
+ if (olderrs != global.errors) // if errors compiling this function
+ return false;
+ }
+
+ // if inferring return type, sematic3 needs to be run
+ // - When the function body contains any errors, we cannot assume
+ // the inferred return type is valid.
+ // So, the body errors should become the function signature error.
+ if (inferRetType && type && !type->nextOf())
+ return functionSemantic3();
+
+ TemplateInstance *ti;
+ if (isInstantiated() && !isVirtualMethod() &&
+ ((ti = parent->isTemplateInstance()) == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == ident))
+ {
+ AggregateDeclaration *ad = isMember2();
+ if (ad && ad->sizeok != SIZEOKdone)
+ {
+ /* Currently dmd cannot resolve forward references per methods,
+ * then setting SIZOKfwd is too conservative and would break existing code.
+ * So, just stop method attributes inference until ad->semantic() done.
+ */
+ //ad->sizeok = SIZEOKfwd;
+ }
+ else
+ return functionSemantic3() || !errors;
+ }
+
+ if (storage_class & STCinference)
+ return functionSemantic3() || !errors;
+
+ return !errors;
+}
+
+/****************************************************
+ * Resolve forward reference of function body.
+ * Returns false if any errors exist in the body.
+ */
+bool FuncDeclaration::functionSemantic3()
+{
+ if (semanticRun < PASSsemantic3 && _scope)
+ {
+ /* Forward reference - we need to run semantic3 on this function.
+ * If errors are gagged, and it's not part of a template instance,
+ * we need to temporarily ungag errors.
+ */
+ TemplateInstance *spec = isSpeculative();
+ unsigned olderrs = global.errors;
+ unsigned oldgag = global.gag;
+ if (global.gag && !spec)
+ global.gag = 0;
+ semantic3(_scope);
+ global.gag = oldgag;
+
+ // If it is a speculatively-instantiated template, and errors occur,
+ // we need to mark the template as having errors.
+ if (spec && global.errors != olderrs)
+ spec->errors = (global.errors - olderrs != 0);
+ if (olderrs != global.errors) // if errors compiling this function
+ return false;
+ }
+
+ return !errors && !semantic3Errors;
+}
+
+/****************************************************
+ * Check that this function type is properly resolved.
+ * If not, report "forward reference error" and return true.
+ */
+bool FuncDeclaration::checkForwardRef(Loc loc)
+{
+ if (!functionSemantic())
+ return true;
+
+ /* No deco means the functionSemantic() call could not resolve
+ * forward referenes in the type of this function.
+ */
+ if (!type->deco)
+ {
+ bool inSemantic3 = (inferRetType && semanticRun >= PASSsemantic3);
+ ::error(loc, "forward reference to %s'%s'",
+ (inSemantic3 ? "inferred return type of function " : ""),
+ toChars());
+ return true;
+ }
+ return false;
+}
+
+VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad)
+{
+ if (ad)
+ {
+ VarDeclaration *v;
+ {
+ //printf("declareThis() %s\n", toChars());
+ Type *thandle = ad->handleType();
+ assert(thandle);
+ thandle = thandle->addMod(type->mod);
+ thandle = thandle->addStorageClass(storage_class);
+ v = new ThisDeclaration(loc, thandle);
+ v->storage_class |= STCparameter;
+ if (thandle->ty == Tstruct)
+ {
+ v->storage_class |= STCref;
+
+ // if member function is marked 'inout', then 'this' is 'return ref'
+ if (type->ty == Tfunction && ((TypeFunction *)type)->iswild & 2)
+ v->storage_class |= STCreturn;
+ }
+ if (type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)type;
+ if (tf->isreturn)
+ v->storage_class |= STCreturn;
+ if (tf->isscope)
+ v->storage_class |= STCscope;
+ }
+ if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
+ v->storage_class |= STCmaybescope;
+
+ v->semantic(sc);
+ if (!sc->insert(v))
+ assert(0);
+ v->parent = this;
+ return v;
+ }
+ }
+ else if (isNested())
+ {
+ /* The 'this' for a nested function is the link to the
+ * enclosing function's stack frame.
+ * Note that nested functions and member functions are disjoint.
+ */
+ VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo());
+ v->storage_class |= STCparameter;
+ if (type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)type;
+ if (tf->isreturn)
+ v->storage_class |= STCreturn;
+ if (tf->isscope)
+ v->storage_class |= STCscope;
+ }
+ if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
+ v->storage_class |= STCmaybescope;
+
+ v->semantic(sc);
+ if (!sc->insert(v))
+ assert(0);
+ v->parent = this;
+ return v;
+ }
+
+ return NULL;
+}
+
+bool FuncDeclaration::equals(RootObject *o)
+{
+ if (this == o)
+ return true;
+
+ Dsymbol *s = isDsymbol(o);
+ if (s)
+ {
+ FuncDeclaration *fd1 = this;
+ FuncDeclaration *fd2 = s->isFuncDeclaration();
+ if (!fd2)
+ return false;
+
+ FuncAliasDeclaration *fa1 = fd1->isFuncAliasDeclaration();
+ FuncAliasDeclaration *fa2 = fd2->isFuncAliasDeclaration();
+ if (fa1 && fa2)
+ {
+ return fa1->toAliasFunc()->equals(fa2->toAliasFunc()) &&
+ fa1->hasOverloads == fa2->hasOverloads;
+ }
+
+ if (fa1 && (fd1 = fa1->toAliasFunc())->isUnique() && !fa1->hasOverloads)
+ fa1 = NULL;
+ if (fa2 && (fd2 = fa2->toAliasFunc())->isUnique() && !fa2->hasOverloads)
+ fa2 = NULL;
+ if ((fa1 != NULL) != (fa2 != NULL))
+ return false;
+
+ return fd1->toParent()->equals(fd2->toParent()) &&
+ fd1->ident->equals(fd2->ident) && fd1->type->equals(fd2->type);
+ }
+ return false;
+}
+
+/****************************************************
+ * Declare result variable lazily.
+ */
+
+void FuncDeclaration::buildResultVar(Scope *sc, Type *tret)
+{
+ if (!vresult)
+ {
+ Loc loc = fensure ? fensure->loc : this->loc;
+
+ /* If inferRetType is true, tret may not be a correct return type yet.
+ * So, in here it may be a temporary type for vresult, and after
+ * fbody->semantic() running, vresult->type might be modified.
+ */
+ vresult = new VarDeclaration(loc, tret, outId ? outId : Id::result, NULL);
+ vresult->storage_class |= STCnodtor;
+
+ if (outId == Id::result)
+ vresult->storage_class |= STCtemp;
+ if (!isVirtual())
+ vresult->storage_class |= STCconst;
+ vresult->storage_class |= STCresult;
+
+ // set before the semantic() for checkNestedReference()
+ vresult->parent = this;
+ }
+
+ if (sc && vresult->semanticRun == PASSinit)
+ {
+ assert(type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)type;
+ if (tf->isref)
+ vresult->storage_class |= STCref;
+ vresult->type = tret;
+
+ vresult->semantic(sc);
+
+ if (!sc->insert(vresult))
+ error("out result %s is already defined", vresult->toChars());
+ assert(vresult->parent == this);
+ }
+}
+
+/****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ * 'in's are OR'd together, i.e. only one of them needs to pass.
+ */
+
+Statement *FuncDeclaration::mergeFrequire(Statement *sf)
+{
+ /* If a base function and its override both have an IN contract, then
+ * only one of them needs to succeed. This is done by generating:
+ *
+ * void derived.in() {
+ * try {
+ * base.in();
+ * }
+ * catch () {
+ * ... body of derived.in() ...
+ * }
+ * }
+ *
+ * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
+ * If base.in() throws, then derived.in()'s body is executed.
+ */
+
+ /* Implementing this is done by having the overriding function call
+ * nested functions (the fdrequire functions) nested inside the overridden
+ * function. This requires that the stack layout of the calling function's
+ * parameters and 'this' pointer be in the same place (as the nested
+ * function refers to them).
+ * This is easy for the parameters, as they are all on the stack in the same
+ * place by definition, since it's an overriding function. The problem is
+ * getting the 'this' pointer in the same place, since it is a local variable.
+ * We did some hacks in the code generator to make this happen:
+ * 1. always generate exception handler frame, or at least leave space for it
+ * in the frame (Windows 32 SEH only)
+ * 2. always generate an EBP style frame
+ * 3. since 'this' is passed in a register that is subsequently copied into
+ * a stack local, allocate that local immediately following the exception
+ * handler block, so it is always at the same offset from EBP.
+ */
+ for (size_t i = 0; i < foverrides.dim; i++)
+ {
+ FuncDeclaration *fdv = foverrides[i];
+
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602
+ */
+ if (fdv->frequire && fdv->semanticRun != PASSsemantic3done)
+ {
+ assert(fdv->_scope);
+ Scope *sc = fdv->_scope->push();
+ sc->stc &= ~STCoverride;
+ fdv->semantic3(sc);
+ sc->pop();
+ }
+
+ sf = fdv->mergeFrequire(sf);
+ if (sf && fdv->fdrequire)
+ {
+ //printf("fdv->frequire: %s\n", fdv->frequire->toChars());
+ /* Make the call:
+ * try { __require(); }
+ * catch (Throwable) { frequire; }
+ */
+ Expression *eresult = NULL;
+ Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, false), eresult);
+ Statement *s2 = new ExpStatement(loc, e);
+
+ Catch *c = new Catch(loc, getThrowable(), NULL, sf);
+ c->internalCatch = true;
+ Catches *catches = new Catches();
+ catches->push(c);
+ sf = new TryCatchStatement(loc, s2, catches);
+ }
+ else
+ return NULL;
+ }
+ return sf;
+}
+
+/****************************************************
+ * Merge into this function the 'out' contracts of all it overrides.
+ * 'out's are AND'd together, i.e. all of them need to pass.
+ */
+
+Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid)
+{
+ /* Same comments as for mergeFrequire(), except that we take care
+ * of generating a consistent reference to the 'result' local by
+ * explicitly passing 'result' to the nested function as a reference
+ * argument.
+ * This won't work for the 'this' parameter as it would require changing
+ * the semantic code for the nested function so that it looks on the parameter
+ * list for the 'this' pointer, something that would need an unknown amount
+ * of tweaking of various parts of the compiler that I'd rather leave alone.
+ */
+ for (size_t i = 0; i < foverrides.dim; i++)
+ {
+ FuncDeclaration *fdv = foverrides[i];
+
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602 and
+ * https://issues.dlang.org/show_bug.cgi?id=5230
+ */
+ if (needsFensure(fdv) && fdv->semanticRun != PASSsemantic3done)
+ {
+ assert(fdv->_scope);
+ Scope *sc = fdv->_scope->push();
+ sc->stc &= ~STCoverride;
+ fdv->semantic3(sc);
+ sc->pop();
+ }
+
+ sf = fdv->mergeFensure(sf, oid);
+ if (fdv->fdensure)
+ {
+ //printf("fdv->fensure: %s\n", fdv->fensure->toChars());
+ // Make the call: __ensure(result)
+ Expression *eresult = NULL;
+ if (outId)
+ {
+ eresult = new IdentifierExp(loc, oid);
+
+ Type *t1 = fdv->type->nextOf()->toBasetype();
+ Type *t2 = this->type->nextOf()->toBasetype();
+ if (t1->isBaseOf(t2, NULL))
+ {
+ /* Making temporary reference variable is necessary
+ * in covariant return.
+ * See bugzilla 5204 and 10479.
+ */
+ ExpInitializer *ei = new ExpInitializer(Loc(), eresult);
+ VarDeclaration *v = new VarDeclaration(Loc(), t1, Identifier::generateId("__covres"), ei);
+ v->storage_class |= STCtemp;
+ DeclarationExp *de = new DeclarationExp(Loc(), v);
+ VarExp *ve = new VarExp(Loc(), v);
+ eresult = new CommaExp(Loc(), de, ve);
+ }
+ }
+ Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, false), eresult);
+ Statement *s2 = new ExpStatement(loc, e);
+
+ if (sf)
+ {
+ sf = new CompoundStatement(sf->loc, s2, sf);
+ }
+ else
+ sf = s2;
+ }
+ }
+ return sf;
+}
+
+/****************************************************
+ * Determine if 'this' overrides fd.
+ * Return !=0 if it does.
+ */
+
+int FuncDeclaration::overrides(FuncDeclaration *fd)
+{ int result = 0;
+
+ if (fd->ident == ident)
+ {
+ int cov = type->covariant(fd->type);
+ if (cov)
+ { ClassDeclaration *cd1 = toParent()->isClassDeclaration();
+ ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration();
+
+ if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL))
+ result = 1;
+ }
+ }
+ return result;
+}
+
+/*************************************************
+ * Find index of function in vtbl[0..dim] that
+ * this function overrides.
+ * Prefer an exact match to a covariant one.
+ * Params:
+ * fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
+ * Returns:
+ * -1 didn't find one
+ * -2 can't determine because of forward references
+ */
+
+int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349)
+{
+ //printf("findVtblIndex() %s\n", toChars());
+ FuncDeclaration *mismatch = NULL;
+ StorageClass mismatchstc = 0;
+ int mismatchvi = -1;
+ int exactvi = -1;
+ int bestvi = -1;
+ for (int vi = 0; vi < dim; vi++)
+ {
+ FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration();
+ if (fdv && fdv->ident == ident)
+ {
+ if (type->equals(fdv->type)) // if exact match
+ {
+ if (fdv->parent->isClassDeclaration())
+ {
+ if (fdv->isFuture())
+ {
+ bestvi = vi;
+ continue; // keep looking
+ }
+ return vi; // no need to look further
+ }
+
+ if (exactvi >= 0)
+ {
+ error("cannot determine overridden function");
+ return exactvi;
+ }
+ exactvi = vi;
+
+ bestvi = vi;
+ continue;
+ }
+
+ StorageClass stc = 0;
+ int cov = type->covariant(fdv->type, &stc, fix17349);
+ //printf("\tbaseclass cov = %d\n", cov);
+ switch (cov)
+ {
+ case 0: // types are distinct
+ break;
+
+ case 1:
+ bestvi = vi; // covariant, but not identical
+ break; // keep looking for an exact match
+
+ case 2:
+ mismatchvi = vi;
+ mismatchstc = stc;
+ mismatch = fdv; // overrides, but is not covariant
+ break; // keep looking for an exact match
+
+ case 3:
+ return -2; // forward references
+
+ default:
+ assert(0);
+ }
+ }
+ }
+ if (bestvi == -1 && mismatch)
+ {
+ //type->print();
+ //mismatch->type->print();
+ //printf("%s %s\n", type->deco, mismatch->type->deco);
+ //printf("stc = %llx\n", mismatchstc);
+ if (mismatchstc)
+ { // Fix it by modifying the type to add the storage classes
+ type = type->addStorageClass(mismatchstc);
+ bestvi = mismatchvi;
+ }
+ }
+ return bestvi;
+}
+
+/*********************************
+ * If function a function in a base class,
+ * return that base class.
+ * Params:
+ * cd = class that function is in
+ * Returns:
+ * base class if overriding, NULL if not
+ */
+BaseClass *FuncDeclaration::overrideInterface()
+{
+ ClassDeclaration *cd = parent->isClassDeclaration();
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ int v = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.dim);
+ if (v >= 0)
+ return b;
+ }
+ return NULL;
+}
+
+/****************************************************
+ * Overload this FuncDeclaration with the new one f.
+ * Return true if successful; i.e. no conflict.
+ */
+
+bool FuncDeclaration::overloadInsert(Dsymbol *s)
+{
+ //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars());
+ assert(s != this);
+
+ AliasDeclaration *ad = s->isAliasDeclaration();
+ if (ad)
+ {
+ if (overnext)
+ return overnext->overloadInsert(ad);
+ if (!ad->aliassym && ad->type->ty != Tident && ad->type->ty != Tinstance)
+ {
+ //printf("\tad = '%s'\n", ad->type->toChars());
+ return false;
+ }
+ overnext = ad;
+ //printf("\ttrue: no conflict\n");
+ return true;
+ }
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (td)
+ {
+ if (!td->funcroot)
+ td->funcroot = this;
+ if (overnext)
+ return overnext->overloadInsert(td);
+ overnext = td;
+ return true;
+ }
+ FuncDeclaration *fd = s->isFuncDeclaration();
+ if (!fd)
+ return false;
+
+ if (overnext)
+ {
+ td = overnext->isTemplateDeclaration();
+ if (td)
+ fd->overloadInsert(td);
+ else
+ return overnext->overloadInsert(fd);
+ }
+ overnext = fd;
+ //printf("\ttrue: no conflict\n");
+ return true;
+}
+
+/***************************************************
+ * Visit each overloaded function/template in turn, and call
+ * (*fp)(param, s) on it.
+ * Exit when no more, or (*fp)(param, f) returns nonzero.
+ * Returns:
+ * ==0 continue
+ * !=0 done
+ */
+
+int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *))
+{
+ Dsymbol *d;
+ Dsymbol *next;
+ for (d = fstart; d; d = next)
+ {
+ if (OverDeclaration *od = d->isOverDeclaration())
+ {
+ if (od->hasOverloads)
+ {
+ if (int r = overloadApply(od->aliassym, param, fp))
+ return r;
+ }
+ else
+ {
+ if (int r = (*fp)(param, od->aliassym))
+ return r;
+ }
+ next = od->overnext;
+ }
+ else if (FuncAliasDeclaration *fa = d->isFuncAliasDeclaration())
+ {
+ if (fa->hasOverloads)
+ {
+ if (int r = overloadApply(fa->funcalias, param, fp))
+ return r;
+ }
+ else
+ {
+ FuncDeclaration *fd = fa->toAliasFunc();
+ if (!fd)
+ {
+ d->error("is aliased to a function");
+ break;
+ }
+ if (int r = (*fp)(param, fd))
+ return r;
+ }
+ next = fa->overnext;
+ }
+ else if (AliasDeclaration *ad = d->isAliasDeclaration())
+ {
+ next = ad->toAlias();
+ if (next == ad)
+ break;
+ if (next == fstart)
+ break;
+ }
+ else if (TemplateDeclaration *td = d->isTemplateDeclaration())
+ {
+ if (int r = (*fp)(param, td))
+ return r;
+ next = td->overnext;
+ }
+ else
+ {
+ FuncDeclaration *fd = d->isFuncDeclaration();
+ if (!fd)
+ {
+ d->error("is aliased to a function");
+ break; // BUG: should print error message?
+ }
+ if (int r = (*fp)(param, fd))
+ return r;
+ next = fd->overnext;
+ }
+ }
+ return 0;
+}
+
+/********************************************
+ * If there are no overloads of function f, return that function,
+ * otherwise return NULL.
+ */
+
+FuncDeclaration *FuncDeclaration::isUnique()
+{
+ struct ParamUnique
+ {
+ static int fp(void *param, Dsymbol *s)
+ {
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (!f)
+ return 0;
+ FuncDeclaration **pf = (FuncDeclaration **)param;
+
+ if (*pf)
+ {
+ *pf = NULL;
+ return 1; // ambiguous, done
+ }
+ else
+ {
+ *pf = f;
+ return 0;
+ }
+ }
+ };
+ FuncDeclaration *result = NULL;
+ overloadApply(this, &result, &ParamUnique::fp);
+ return result;
+}
+
+/********************************************
+ * Find function in overload list that exactly matches t.
+ */
+
+FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t)
+{
+ struct ParamExact
+ {
+ Type *t; // type to match
+ FuncDeclaration *f; // return value
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (!f)
+ return 0;
+ ParamExact *p = (ParamExact *)param;
+ Type *t = p->t;
+
+ if (t->equals(f->type))
+ {
+ p->f = f;
+ return 1;
+ }
+
+ /* Allow covariant matches, as long as the return type
+ * is just a const conversion.
+ * This allows things like pure functions to match with an impure function type.
+ */
+ if (t->ty == Tfunction)
+ { TypeFunction *tf = (TypeFunction *)f->type;
+ if (tf->covariant(t) == 1 &&
+ tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst)
+ {
+ p->f = f;
+ return 1;
+ }
+ }
+ return 0;
+ }
+ };
+ ParamExact p;
+ p.t = t;
+ p.f = NULL;
+ overloadApply(this, &p, &ParamExact::fp);
+ return p.f;
+}
+
+void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod)
+{
+ bool bothMutable = ((lhsMod & rhsMod) == 0);
+ bool sharedMismatch = ((lhsMod ^ rhsMod) & MODshared) != 0;
+ bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODshared);
+
+ if (lhsMod & MODshared)
+ buf->writestring("shared ");
+ else if (sharedMismatch && !(lhsMod & MODimmutable))
+ buf->writestring("non-shared ");
+
+ if (bothMutable && sharedMismatchOnly)
+ { }
+ else if (lhsMod & MODimmutable)
+ buf->writestring("immutable ");
+ else if (lhsMod & MODconst)
+ buf->writestring("const ");
+ else if (lhsMod & MODwild)
+ buf->writestring("inout ");
+ else
+ buf->writestring("mutable ");
+}
+
+/********************************************
+ * Find function in overload list that matches to the 'this' modifier.
+ * There's four result types.
+ *
+ * 1. If the 'tthis' matches only one candidate, it's an "exact match".
+ * Returns the function and 'hasOverloads' is set to false.
+ * eg. If 'tthis" is mutable and there's only one mutable method.
+ * 2. If there's two or more match candidates, but a candidate function will be
+ * a "better match".
+ * Returns the better match function but 'hasOverloads' is set to true.
+ * eg. If 'tthis' is mutable, and there's both mutable and const methods,
+ * the mutable method will be a better match.
+ * 3. If there's two or more match candidates, but there's no better match,
+ * Returns NULL and 'hasOverloads' is set to true to represent "ambiguous match".
+ * eg. If 'tthis' is mutable, and there's two or more mutable methods.
+ * 4. If there's no candidates, it's "no match" and returns NULL with error report.
+ * e.g. If 'tthis' is const but there's no const methods.
+ */
+FuncDeclaration *FuncDeclaration::overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads)
+{
+ //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
+ Match m;
+ memset(&m, 0, sizeof(m));
+ m.last = MATCHnomatch;
+
+ struct ParamMod
+ {
+ Match *m;
+ Type *tthis;
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ if (FuncDeclaration *fd = s->isFuncDeclaration())
+ return ((ParamMod *)param)->fp(fd);
+ return 0;
+ }
+ int fp(FuncDeclaration *f)
+ {
+ if (f == m->lastf) // skip duplicates
+ return 0;
+
+ m->anyf = f;
+ TypeFunction *tf = (TypeFunction *)f->type;
+ //printf("tf = %s\n", tf->toChars());
+
+ MATCH match;
+ if (tthis) // non-static functions are preferred than static ones
+ {
+ if (f->needThis())
+ match = f->isCtorDeclaration() ? MATCHexact : MODmethodConv(tthis->mod, tf->mod);
+ else
+ match = MATCHconst; // keep static funciton in overload candidates
+ }
+ else // static functions are preferred than non-static ones
+ {
+ if (f->needThis())
+ match = MATCHconvert;
+ else
+ match = MATCHexact;
+ }
+ if (match != MATCHnomatch)
+ {
+ if (match > m->last) goto LfIsBetter;
+ if (match < m->last) goto LlastIsBetter;
+
+ /* See if one of the matches overrides the other.
+ */
+ if (m->lastf->overrides(f)) goto LlastIsBetter;
+ if (f->overrides(m->lastf)) goto LfIsBetter;
+
+ //printf("\tambiguous\n");
+ m->nextf = f;
+ m->count++;
+ return 0;
+
+ LlastIsBetter:
+ //printf("\tlastbetter\n");
+ m->count++; // count up
+ return 0;
+
+ LfIsBetter:
+ //printf("\tisbetter\n");
+ if (m->last <= MATCHconvert)
+ {
+ // clear last secondary matching
+ m->nextf = NULL;
+ m->count = 0;
+ }
+ m->last = match;
+ m->lastf = f;
+ m->count++; // count up
+ return 0;
+ }
+ return 0;
+ }
+ };
+ ParamMod p;
+ p.m = &m;
+ p.tthis = tthis;
+ overloadApply(this, &p, &ParamMod::fp);
+
+ if (m.count == 1) // exact match
+ {
+ hasOverloads = false;
+ }
+ else if (m.count > 1) // better or ambiguous match
+ {
+ hasOverloads = true;
+ }
+ else // no match
+ {
+ hasOverloads = true;
+ TypeFunction *tf = (TypeFunction *)this->type;
+ assert(tthis);
+ assert(!MODimplicitConv(tthis->mod, tf->mod)); // modifier mismatch
+ {
+ OutBuffer thisBuf, funcBuf;
+ MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
+ MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
+ ::error(loc, "%smethod %s is not callable using a %sobject",
+ funcBuf.peekString(), this->toPrettyChars(), thisBuf.peekString());
+ }
+ }
+
+ return m.lastf;
+}
+
+/********************************************
+ * Returns true if function was declared
+ * directly or indirectly in a unittest block
+ */
+bool FuncDeclaration::inUnittest()
+{
+ Dsymbol *f = this;
+ do
+ {
+ if (f->isUnitTestDeclaration())
+ return true;
+ f = f->toParent();
+ } while (f);
+
+ return false;
+}
+
+/********************************************
+ * find function template root in overload list
+ */
+
+TemplateDeclaration *FuncDeclaration::findTemplateDeclRoot()
+{
+ FuncDeclaration *f = this;
+ while (f && f->overnext)
+ {
+ //printf("f->overnext = %p %s\n", f->overnext, f->overnext->toChars());
+ TemplateDeclaration *td = f->overnext->isTemplateDeclaration();
+ if (td)
+ return td;
+ f = f->overnext->isFuncDeclaration();
+ }
+ return NULL;
+}
+
+/*************************************
+ * Determine partial specialization order of 'this' vs g.
+ * This is very similar to TemplateDeclaration::leastAsSpecialized().
+ * Returns:
+ * match 'this' is at least as specialized as g
+ * 0 g is more specialized than 'this'
+ */
+
+MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g)
+{
+ /* This works by calling g() with f()'s parameters, and
+ * if that is possible, then f() is at least as specialized
+ * as g() is.
+ */
+
+ TypeFunction *tf = (TypeFunction *)type;
+ TypeFunction *tg = (TypeFunction *)g->type;
+ size_t nfparams = Parameter::dim(tf->parameters);
+
+ /* If both functions have a 'this' pointer, and the mods are not
+ * the same and g's is not const, then this is less specialized.
+ */
+ if (needThis() && g->needThis() && tf->mod != tg->mod)
+ {
+ if (isCtorDeclaration())
+ {
+ if (!MODimplicitConv(tg->mod, tf->mod))
+ return MATCHnomatch;
+ }
+ else
+ {
+ if (!MODimplicitConv(tf->mod, tg->mod))
+ return MATCHnomatch;
+ }
+ }
+
+ /* Create a dummy array of arguments out of the parameters to f()
+ */
+ Expressions args;
+ args.setDim(nfparams);
+ for (size_t u = 0; u < nfparams; u++)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, u);
+ Expression *e;
+ if (p->storageClass & (STCref | STCout))
+ {
+ e = new IdentifierExp(Loc(), p->ident);
+ e->type = p->type;
+ }
+ else
+ e = p->type->defaultInitLiteral(Loc());
+ args[u] = e;
+ }
+
+ MATCH m = (MATCH) tg->callMatch(NULL, &args, 1);
+ if (m > MATCHnomatch)
+ {
+ /* A variadic parameter list is less specialized than a
+ * non-variadic one.
+ */
+ if (tf->varargs && !tg->varargs)
+ goto L1; // less specialized
+
+ return m;
+ }
+ L1:
+ return MATCHnomatch;
+}
+
+/// Walk through candidate template overloads and print them in the diagnostics.
+struct TemplateCandidateWalker
+{
+ Loc loc;
+ int numToDisplay; // max num of overloads to print (-v overrides this).
+
+ /// Count template overloads.
+ struct CountWalker
+ {
+ int numOverloads;
+
+ static int fp(void *param, Dsymbol *)
+ {
+ CountWalker *p = (CountWalker *)param;
+ ++(p->numOverloads);
+ return 0;
+ }
+ };
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ TemplateDeclaration *t = s->isTemplateDeclaration();
+ if (!t) return 0;
+
+ TemplateCandidateWalker *p = (TemplateCandidateWalker *)param;
+
+ ::errorSupplemental(t->loc, "%s", t->toPrettyChars());
+
+ if (!global.params.verbose && --(p->numToDisplay) == 0 && t->overnext)
+ {
+ // Too many overloads to sensibly display.
+ // Just show count of remaining overloads.
+ CountWalker cw;
+ cw.numOverloads = 0;
+ overloadApply(t->overnext, &cw, &CountWalker::fp);
+
+ if (cw.numOverloads > 0)
+ ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
+
+ return 1; // stop iterating
+ }
+
+ return 0;
+ }
+};
+
+/// Walk through candidate template overloads and print them in the diagnostics.
+struct FuncCandidateWalker
+{
+ Loc loc;
+ int numToDisplay; // max num of overloads to print (-v overrides this).
+
+ /// Count function overloads.
+ struct CountWalker
+ {
+ int numOverloads;
+
+ static int fp(void *param, Dsymbol *)
+ {
+ CountWalker *p = (CountWalker *)param;
+ ++(p->numOverloads);
+ return 0;
+ }
+ };
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ FuncDeclaration *fd = s->isFuncDeclaration();
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (fd)
+ {
+ if (fd->errors || fd->type->ty == Terror)
+ return 0;
+
+ TypeFunction *tf = (TypeFunction *)fd->type;
+
+ ::errorSupplemental(fd->loc, "%s%s", fd->toPrettyChars(),
+ parametersTypeToChars(tf->parameters, tf->varargs));
+ }
+ else
+ {
+ ::errorSupplemental(td->loc, "%s", td->toPrettyChars());
+ }
+
+ FuncCandidateWalker *p = (FuncCandidateWalker *)param;
+ if (global.params.verbose || --(p->numToDisplay) != 0 || !fd)
+ return 0;
+
+ // Too many overloads to sensibly display.
+ CountWalker cw;
+ cw.numOverloads = 0;
+ overloadApply(fd->overnext, &cw, &CountWalker::fp);
+
+ if (cw.numOverloads > 0)
+ ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
+
+ return 1; // stop iterating
+ }
+};
+
+/*******************************************
+ * Given a symbol that could be either a FuncDeclaration or
+ * a function template, resolve it to a function symbol.
+ * loc instantiation location
+ * sc instantiation scope
+ * tiargs initial list of template arguments
+ * tthis if !NULL, the 'this' pointer argument
+ * fargs arguments to function
+ * flags 1: do not issue error message on no match, just return NULL
+ * 2: overloadResolve only
+ */
+
+FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
+ Objects *tiargs, Type *tthis, Expressions *fargs, int flags)
+{
+ if (!s)
+ return NULL; // no match
+
+ if ((tiargs && arrayObjectIsError(tiargs)) ||
+ (fargs && arrayObjectIsError((Objects *)fargs)))
+ {
+ return NULL;
+ }
+
+ Match m;
+ memset(&m, 0, sizeof(m));
+ m.last = MATCHnomatch;
+
+ functionResolve(&m, s, loc, sc, tiargs, tthis, fargs);
+
+ if (m.last > MATCHnomatch && m.lastf)
+ {
+ if (m.count == 1) // exactly one match
+ {
+ if (!(flags & 1))
+ m.lastf->functionSemantic();
+ return m.lastf;
+ }
+ if ((flags & 2) && !tthis && m.lastf->needThis())
+ {
+ return m.lastf;
+ }
+ }
+
+ /* Failed to find a best match.
+ * Do nothing or print error.
+ */
+ if (m.last <= MATCHnomatch)
+ {
+ // error was caused on matched function
+ if (m.count == 1)
+ return m.lastf;
+
+ // if do not print error messages
+ if (flags & 1)
+ return NULL; // no match
+ }
+
+ FuncDeclaration *fd = s->isFuncDeclaration();
+ OverDeclaration *od = s->isOverDeclaration();
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (td && td->funcroot)
+ s = fd = td->funcroot;
+
+ OutBuffer tiargsBuf;
+ arrayObjectsToBuffer(&tiargsBuf, tiargs);
+
+ OutBuffer fargsBuf;
+ fargsBuf.writeByte('(');
+ argExpTypesToCBuffer(&fargsBuf, fargs);
+ fargsBuf.writeByte(')');
+ if (tthis)
+ tthis->modToBuffer(&fargsBuf);
+
+ const int numOverloadsDisplay = 5; // sensible number to display
+
+ if (!m.lastf && !(flags & 1)) // no match
+ {
+ if (td && !fd) // all of overloads are templates
+ {
+ ::error(loc, "%s %s.%s cannot deduce function from argument types !(%s)%s, candidates are:",
+ td->kind(), td->parent->toPrettyChars(), td->ident->toChars(),
+ tiargsBuf.peekString(), fargsBuf.peekString());
+
+ // Display candidate templates (even if there are no multiple overloads)
+ TemplateCandidateWalker tcw;
+ tcw.loc = loc;
+ tcw.numToDisplay = numOverloadsDisplay;
+ overloadApply(td, &tcw, &TemplateCandidateWalker::fp);
+ }
+ else if (od)
+ {
+ ::error(loc, "none of the overloads of '%s' are callable using argument types !(%s)%s",
+ od->ident->toChars(), tiargsBuf.peekString(), fargsBuf.peekString());
+ }
+ else
+ {
+ assert(fd);
+
+ bool hasOverloads = fd->overnext != NULL;
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ if (tthis && !MODimplicitConv(tthis->mod, tf->mod)) // modifier mismatch
+ {
+ OutBuffer thisBuf, funcBuf;
+ MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
+ MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
+ if (hasOverloads)
+ ::error(loc, "none of the overloads of '%s' are callable using a %sobject, candidates are:",
+ fd->ident->toChars(), thisBuf.peekString());
+ else
+ ::error(loc, "%smethod %s is not callable using a %sobject",
+ funcBuf.peekString(), fd->toPrettyChars(), thisBuf.peekString());
+ }
+ else
+ {
+ //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco);
+ if (hasOverloads)
+ ::error(loc, "none of the overloads of '%s' are callable using argument types %s, candidates are:",
+ fd->ident->toChars(), fargsBuf.peekString());
+ else
+ fd->error(loc, "%s%s is not callable using argument types %s",
+ parametersTypeToChars(tf->parameters, tf->varargs),
+ tf->modToChars(),
+ fargsBuf.peekString());
+ }
+
+ // Display candidate functions
+ if (hasOverloads)
+ {
+ FuncCandidateWalker fcw;
+ fcw.loc = loc;
+ fcw.numToDisplay = numOverloadsDisplay;
+ overloadApply(fd, &fcw, &FuncCandidateWalker::fp);
+ }
+ }
+ }
+ else if (m.nextf)
+ {
+ TypeFunction *tf1 = (TypeFunction *)m.lastf->type;
+ TypeFunction *tf2 = (TypeFunction *)m.nextf->type;
+ const char *lastprms = parametersTypeToChars(tf1->parameters, tf1->varargs);
+ const char *nextprms = parametersTypeToChars(tf2->parameters, tf2->varargs);
+ ::error(loc, "%s.%s called with argument types %s matches both:\n"
+ "%s: %s%s\nand:\n%s: %s%s",
+ s->parent->toPrettyChars(), s->ident->toChars(),
+ fargsBuf.peekString(),
+ m.lastf->loc.toChars(), m.lastf->toPrettyChars(), lastprms,
+ m.nextf->loc.toChars(), m.nextf->toPrettyChars(), nextprms);
+ }
+ return NULL;
+}
+
+/********************************
+ * Labels are in a separate scope, one per function.
+ */
+
+LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident)
+{ Dsymbol *s;
+
+ if (!labtab)
+ labtab = new DsymbolTable(); // guess we need one
+
+ s = labtab->lookup(ident);
+ if (!s)
+ {
+ s = new LabelDsymbol(ident);
+ labtab->insert(s);
+ }
+ return (LabelDsymbol *)s;
+}
+
+/*****************************************
+ * Determine lexical level difference from 'this' to nested function 'fd'.
+ * Error if this cannot call fd.
+ * Returns:
+ * 0 same level
+ * >0 decrease nesting by number
+ * -1 increase nesting by 1 (fd is nested within 'this')
+ * -2 error
+ */
+
+int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd)
+{
+ int level;
+ Dsymbol *s;
+ Dsymbol *fdparent;
+
+ //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars());
+ fdparent = fd->toParent2();
+ if (fdparent == this)
+ return -1;
+ s = this;
+ level = 0;
+ while (fd != s && fdparent != s->toParent2())
+ {
+ //printf("\ts = %s, '%s'\n", s->kind(), s->toChars());
+ FuncDeclaration *thisfd = s->isFuncDeclaration();
+ if (thisfd)
+ {
+ if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof)
+ goto Lerr;
+ }
+ else
+ {
+ AggregateDeclaration *thiscd = s->isAggregateDeclaration();
+ if (thiscd)
+ {
+ /* AggregateDeclaration::isNested returns true only when
+ * it has a hidden pointer.
+ * But, calling the function belongs unrelated lexical scope
+ * is still allowed inside typeof.
+ *
+ * struct Map(alias fun) {
+ * typeof({ return fun(); }) RetType;
+ * // No member function makes Map struct 'not nested'.
+ * }
+ */
+ if (!thiscd->isNested() && !sc->intypeof)
+ goto Lerr;
+ }
+ else
+ goto Lerr;
+ }
+
+ s = s->toParent2();
+ assert(s);
+ level++;
+ }
+ return level;
+
+Lerr:
+ // Don't give error if in template constraint
+ if (!(sc->flags & SCOPEconstraint))
+ {
+ const char *xstatic = isStatic() ? "static " : "";
+ // better diagnostics for static functions
+ ::error(loc, "%s%s %s cannot access frame of function %s",
+ xstatic, kind(), toPrettyChars(), fd->toPrettyChars());
+ return -2;
+ }
+ return 1;
+}
+
+const char *FuncDeclaration::toPrettyChars(bool QualifyTypes)
+{
+ if (isMain())
+ return "D main";
+ else
+ return Dsymbol::toPrettyChars(QualifyTypes);
+}
+
+/** for diagnostics, e.g. 'int foo(int x, int y) pure' */
+const char *FuncDeclaration::toFullSignature()
+{
+ OutBuffer buf;
+ functionToBufferWithIdent((TypeFunction *)type, &buf, toChars());
+ return buf.extractString();
+}
+
+bool FuncDeclaration::isMain()
+{
+ return ident == Id::main &&
+ linkage != LINKc && !isMember() && !isNested();
+}
+
+bool FuncDeclaration::isCMain()
+{
+ return ident == Id::main &&
+ linkage == LINKc && !isMember() && !isNested();
+}
+
+bool FuncDeclaration::isWinMain()
+{
+ //printf("FuncDeclaration::isWinMain() %s\n", toChars());
+ return ident == Id::WinMain &&
+ linkage != LINKc && !isMember();
+}
+
+bool FuncDeclaration::isDllMain()
+{
+ return ident == Id::DllMain &&
+ linkage != LINKc && !isMember();
+}
+
+bool FuncDeclaration::isExport() const
+{
+ return protection.kind == PROTexport;
+}
+
+bool FuncDeclaration::isImportedSymbol() const
+{
+ //printf("isImportedSymbol()\n");
+ //printf("protection = %d\n", protection);
+ return (protection.kind == PROTexport) && !fbody;
+}
+
+// Determine if function goes into virtual function pointer table
+
+bool FuncDeclaration::isVirtual()
+{
+ if (toAliasFunc() != this)
+ return toAliasFunc()->isVirtual();
+
+ Dsymbol *p = toParent();
+ return isMember() &&
+ !(isStatic() || protection.kind == PROTprivate || protection.kind == PROTpackage) &&
+ p->isClassDeclaration() &&
+ !(p->isInterfaceDeclaration() && isFinalFunc());
+}
+
+// Determine if a function is pedantically virtual
+
+bool FuncDeclaration::isVirtualMethod()
+{
+ if (toAliasFunc() != this)
+ return toAliasFunc()->isVirtualMethod();
+
+ //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
+ if (!isVirtual())
+ return false;
+ // If it's a final method, and does not override anything, then it is not virtual
+ if (isFinalFunc() && foverrides.dim == 0)
+ {
+ return false;
+ }
+ return true;
+}
+
+bool FuncDeclaration::isFinalFunc()
+{
+ if (toAliasFunc() != this)
+ return toAliasFunc()->isFinalFunc();
+
+ ClassDeclaration *cd;
+ return isMember() &&
+ (Declaration::isFinal() ||
+ ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal));
+}
+
+bool FuncDeclaration::isCodeseg() const
+{
+ return true; // functions are always in the code segment
+}
+
+bool FuncDeclaration::isOverloadable()
+{
+ return true; // functions can be overloaded
+}
+
+PURE FuncDeclaration::isPure()
+{
+ //printf("FuncDeclaration::isPure() '%s'\n", toChars());
+ assert(type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)type;
+ if (flags & FUNCFLAGpurityInprocess)
+ setImpure();
+ if (tf->purity == PUREfwdref)
+ tf->purityLevel();
+ PURE purity = tf->purity;
+ if (purity > PUREweak && isNested())
+ purity = PUREweak;
+ if (purity > PUREweak && needThis())
+ {
+ // The attribute of the 'this' reference affects purity strength
+ if (type->mod & MODimmutable)
+ ;
+ else if (type->mod & (MODconst | MODwild) && purity >= PUREconst)
+ purity = PUREconst;
+ else
+ purity = PUREweak;
+ }
+ tf->purity = purity;
+ // ^ This rely on the current situation that every FuncDeclaration has a
+ // unique TypeFunction.
+ return purity;
+}
+
+PURE FuncDeclaration::isPureBypassingInference()
+{
+ if (flags & FUNCFLAGpurityInprocess)
+ return PUREfwdref;
+ else
+ return isPure();
+}
+
+/**************************************
+ * The function is doing something impure,
+ * so mark it as impure.
+ * If there's a purity error, return true.
+ */
+bool FuncDeclaration::setImpure()
+{
+ if (flags & FUNCFLAGpurityInprocess)
+ {
+ flags &= ~FUNCFLAGpurityInprocess;
+ if (fes)
+ fes->func->setImpure();
+ }
+ else if (isPure())
+ return true;
+ return false;
+}
+
+bool FuncDeclaration::isSafe()
+{
+ assert(type->ty == Tfunction);
+ if (flags & FUNCFLAGsafetyInprocess)
+ setUnsafe();
+ return ((TypeFunction *)type)->trust == TRUSTsafe;
+}
+
+bool FuncDeclaration::isSafeBypassingInference()
+{
+ return !(flags & FUNCFLAGsafetyInprocess) && isSafe();
+}
+
+bool FuncDeclaration::isTrusted()
+{
+ assert(type->ty == Tfunction);
+ if (flags & FUNCFLAGsafetyInprocess)
+ setUnsafe();
+ return ((TypeFunction *)type)->trust == TRUSTtrusted;
+}
+
+/**************************************
+ * The function is doing something unsave,
+ * so mark it as unsafe.
+ * If there's a safe error, return true.
+ */
+bool FuncDeclaration::setUnsafe()
+{
+ if (flags & FUNCFLAGsafetyInprocess)
+ {
+ flags &= ~FUNCFLAGsafetyInprocess;
+ ((TypeFunction *)type)->trust = TRUSTsystem;
+ if (fes)
+ fes->func->setUnsafe();
+ }
+ else if (isSafe())
+ return true;
+ return false;
+}
+
+bool FuncDeclaration::isNogc()
+{
+ assert(type->ty == Tfunction);
+ if (flags & FUNCFLAGnogcInprocess)
+ setGC();
+ return ((TypeFunction *)type)->isnogc;
+}
+
+bool FuncDeclaration::isNogcBypassingInference()
+{
+ return !(flags & FUNCFLAGnogcInprocess) && isNogc();
+}
+
+/**************************************
+ * The function is doing something that may allocate with the GC,
+ * so mark it as not nogc (not no-how).
+ * Returns:
+ * true if function is marked as @nogc, meaning a user error occurred
+ */
+bool FuncDeclaration::setGC()
+{
+ if (flags & FUNCFLAGnogcInprocess)
+ {
+ flags &= ~FUNCFLAGnogcInprocess;
+ ((TypeFunction *)type)->isnogc = false;
+ if (fes)
+ fes->func->setGC();
+ }
+ else if (isNogc())
+ return true;
+ return false;
+}
+
+/**************************************
+ * Returns an indirect type one step from t.
+ */
+
+Type *getIndirection(Type *t)
+{
+ t = t->baseElemOf();
+ if (t->ty == Tarray || t->ty == Tpointer)
+ return t->nextOf()->toBasetype();
+ if (t->ty == Taarray || t->ty == Tclass)
+ return t;
+ if (t->ty == Tstruct)
+ return t->hasPointers() ? t : NULL; // TODO
+
+ // should consider TypeDelegate?
+ return NULL;
+}
+
+/**************************************
+ * Returns true if memory reachable through a reference B to a value of type tb,
+ * which has been constructed with a reference A to a value of type ta
+ * available, can alias memory reachable from A based on the types involved
+ * (either directly or via any number of indirections).
+ *
+ * Note that this relation is not symmetric in the two arguments. For example,
+ * a const(int) reference can point to a pre-existing int, but not the other
+ * way round.
+ */
+bool traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool reversePass = false)
+{
+ Type *source = ta;
+ Type *target = tb;
+ if (reversePass)
+ {
+ source = tb;
+ target = ta;
+ }
+
+ if (source->constConv(target))
+ return true;
+ else if (target->ty == Tvoid && MODimplicitConv(source->mod, target->mod))
+ return true;
+
+ // No direct match, so try breaking up one of the types (starting with tb).
+ Type *tbb = tb->toBasetype()->baseElemOf();
+ if (tbb != tb)
+ return traverseIndirections(ta, tbb, p, reversePass);
+
+ // context date to detect circular look up
+ struct Ctxt
+ {
+ Ctxt *prev;
+ Type *type;
+ };
+ Ctxt *ctxt = (Ctxt *)p;
+
+ if (tb->ty == Tclass || tb->ty == Tstruct)
+ {
+ for (Ctxt *c = ctxt; c; c = c->prev)
+ if (tb == c->type) return false;
+ Ctxt c;
+ c.prev = ctxt;
+ c.type = tb;
+
+ AggregateDeclaration *sym = tb->toDsymbol(NULL)->isAggregateDeclaration();
+ for (size_t i = 0; i < sym->fields.dim; i++)
+ {
+ VarDeclaration *v = sym->fields[i];
+ Type *tprmi = v->type->addMod(tb->mod);
+ //printf("\ttb = %s, tprmi = %s\n", tb->toChars(), tprmi->toChars());
+ if (traverseIndirections(ta, tprmi, &c, reversePass))
+ return true;
+ }
+ }
+ else if (tb->ty == Tarray || tb->ty == Taarray || tb->ty == Tpointer)
+ {
+ Type *tind = tb->nextOf();
+ if (traverseIndirections(ta, tind, ctxt, reversePass))
+ return true;
+ }
+ else if (tb->hasPointers())
+ {
+ // FIXME: function pointer/delegate types should be considered.
+ return true;
+ }
+
+ // Still no match, so try breaking up ta if we have note done so yet.
+ if (!reversePass)
+ return traverseIndirections(tb, ta, ctxt, true);
+
+ return false;
+}
+
+/********************************************
+ * Returns true if the function return value has no indirection
+ * which comes from the parameters.
+ */
+
+bool FuncDeclaration::isolateReturn()
+{
+ assert(type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)type;
+ assert(tf->next);
+
+ Type *treti = tf->next;
+ treti = tf->isref ? treti : getIndirection(treti);
+ if (!treti)
+ return true; // target has no mutable indirection
+ return parametersIntersect(treti);
+}
+
+/********************************************
+ * Returns true if an object typed t can have indirections
+ * which come from the parameters.
+ */
+
+bool FuncDeclaration::parametersIntersect(Type *t)
+{
+ assert(t);
+ if (!isPureBypassingInference() || isNested())
+ return false;
+
+ assert(type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)type;
+
+ //printf("parametersIntersect(%s) t = %s\n", tf->toChars(), t->toChars());
+
+ size_t dim = Parameter::dim(tf->parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam = Parameter::getNth(tf->parameters, i);
+ if (!fparam->type)
+ continue;
+ Type *tprmi = (fparam->storageClass & (STClazy | STCout | STCref))
+ ? fparam->type : getIndirection(fparam->type);
+ if (!tprmi)
+ continue; // there is no mutable indirection
+
+ //printf("\t[%d] tprmi = %d %s\n", i, tprmi->ty, tprmi->toChars());
+ if (traverseIndirections(tprmi, t))
+ return false;
+ }
+ if (AggregateDeclaration *ad = isCtorDeclaration() ? NULL : isThis())
+ {
+ Type *tthis = ad->getType()->addMod(tf->mod);
+ //printf("\ttthis = %s\n", tthis->toChars());
+ if (traverseIndirections(tthis, t))
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************
+ * Determine if function needs a static frame pointer.
+ * Returns:
+ * `true` if function is really nested within other function.
+ * Contracts:
+ * If isNested() returns true, isThis() should return false.
+ */
+bool FuncDeclaration::isNested()
+{
+ FuncDeclaration *f = toAliasFunc();
+ //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars());
+ return ((f->storage_class & STCstatic) == 0) &&
+ (f->linkage == LINKd) &&
+ (f->toParent2()->isFuncDeclaration() != NULL);
+}
+
+/****************************************
+ * Determine if function is a non-static member function
+ * that has an implicit 'this' expression.
+ * Returns:
+ * The aggregate it is a member of, or null.
+ * Contracts:
+ * If isThis() returns true, isNested() should return false.
+ */
+AggregateDeclaration *FuncDeclaration::isThis()
+{
+ //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
+ AggregateDeclaration *ad = (storage_class & STCstatic) ? NULL : isMember2();
+ //printf("-FuncDeclaration::isThis() %p\n", ad);
+ return ad;
+}
+
+bool FuncDeclaration::needThis()
+{
+ //printf("FuncDeclaration::needThis() '%s'\n", toChars());
+ return toAliasFunc()->isThis() != NULL;
+}
+
+bool FuncDeclaration::addPreInvariant()
+{
+ AggregateDeclaration *ad = isThis();
+ ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
+ return (ad && !(cd && cd->isCPPclass()) &&
+ global.params.useInvariants &&
+ (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) &&
+ !naked);
+}
+
+bool FuncDeclaration::addPostInvariant()
+{
+ AggregateDeclaration *ad = isThis();
+ ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
+ return (ad && !(cd && cd->isCPPclass()) &&
+ ad->inv &&
+ global.params.useInvariants &&
+ (protection.kind == PROTprotected || protection.kind == PROTpublic || protection.kind == PROTexport) &&
+ !naked);
+}
+
+/********************************************************
+ * Generate Expression to call the invariant.
+ * Input:
+ * ad aggregate with the invariant
+ * vthis variable with 'this'
+ * direct call invariant directly
+ * Returns:
+ * void expression that calls the invariant
+ */
+Expression *addInvariant(Loc loc, Scope *sc, AggregateDeclaration *ad, VarDeclaration *vthis, bool direct)
+{
+ Expression *e = NULL;
+ if (direct)
+ {
+ // Call invariant directly only if it exists
+ FuncDeclaration *inv = ad->inv;
+ ClassDeclaration *cd = ad->isClassDeclaration();
+
+ while (!inv && cd)
+ {
+ cd = cd->baseClass;
+ if (!cd)
+ break;
+ inv = cd->inv;
+ }
+ if (inv)
+ {
+ #if 1
+ // Workaround for bugzilla 13394: For the correct mangling,
+ // run attribute inference on inv if needed.
+ inv->functionSemantic();
+ #endif
+
+ //e = new DsymbolExp(Loc(), inv);
+ //e = new CallExp(Loc(), e);
+ //e = e->semantic(sc2);
+
+ /* Bugzilla 13113: Currently virtual invariant calls completely
+ * bypass attribute enforcement.
+ * Change the behavior of pre-invariant call by following it.
+ */
+ e = new ThisExp(Loc());
+ e->type = vthis->type;
+ e = new DotVarExp(Loc(), e, inv, false);
+ e->type = inv->type;
+ e = new CallExp(Loc(), e);
+ e->type = Type::tvoid;
+ }
+ }
+ else
+ {
+ #if 1
+ // Workaround for bugzilla 13394: For the correct mangling,
+ // run attribute inference on inv if needed.
+ if (ad->isStructDeclaration() && ad->inv)
+ ad->inv->functionSemantic();
+ #endif
+
+ // Call invariant virtually
+ Expression *v = new ThisExp(Loc());
+ v->type = vthis->type;
+ if (ad->isStructDeclaration())
+ v = v->addressOf();
+ e = new StringExp(Loc(), const_cast<char *>("null this"));
+ e = new AssertExp(loc, v, e);
+ e = semantic(e, sc);
+ }
+ return e;
+}
+
+/**********************************
+ * Generate a FuncDeclaration for a runtime library function.
+ */
+
+FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, const char *name, StorageClass stc)
+{
+ return genCfunc(fparams, treturn, Identifier::idPool(name), stc);
+}
+
+FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, Identifier *id, StorageClass stc)
+{
+ FuncDeclaration *fd;
+ TypeFunction *tf;
+ Dsymbol *s;
+ static DsymbolTable *st = NULL;
+
+ //printf("genCfunc(name = '%s')\n", id->toChars());
+ //printf("treturn\n\t"); treturn->print();
+
+ // See if already in table
+ if (!st)
+ st = new DsymbolTable();
+ s = st->lookup(id);
+ if (s)
+ {
+ fd = s->isFuncDeclaration();
+ assert(fd);
+ assert(fd->type->nextOf()->equals(treturn));
+ }
+ else
+ {
+ tf = new TypeFunction(fparams, treturn, 0, LINKc, stc);
+ fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf);
+ fd->protection = Prot(PROTpublic);
+ fd->linkage = LINKc;
+
+ st->insert(fd);
+ }
+ return fd;
+}
+
+/******************
+ * Check parameters and return type of D main() function.
+ * Issue error messages.
+ */
+void FuncDeclaration::checkDmain()
+{
+ TypeFunction *tf = (TypeFunction *)type;
+ const size_t nparams = Parameter::dim(tf->parameters);
+ bool argerr = false;
+ if (nparams == 1)
+ {
+ Parameter *fparam0 = Parameter::getNth(tf->parameters, 0);
+ Type *t = fparam0->type->toBasetype();
+ if (t->ty != Tarray ||
+ t->nextOf()->ty != Tarray ||
+ t->nextOf()->nextOf()->ty != Tchar ||
+ fparam0->storageClass & (STCout | STCref | STClazy))
+ {
+ argerr = true;
+ }
+ }
+
+ if (!tf->nextOf())
+ error("must return int or void");
+ else if (tf->nextOf()->ty != Tint32 && tf->nextOf()->ty != Tvoid)
+ error("must return int or void, not %s", tf->nextOf()->toChars());
+ else if (tf->varargs || nparams >= 2 || argerr)
+ error("parameters must be main() or main(string[] args)");
+}
+
+const char *FuncDeclaration::kind()
+{
+ return generated ? "generated function" : "function";
+}
+
+/*********************************************
+ * In the current function, we are calling 'this' function.
+ * 1. Check to see if the current function can call 'this' function, issue error if not.
+ * 2. If the current function is not the parent of 'this' function, then add
+ * the current function to the list of siblings of 'this' function.
+ * 3. If the current function is a literal, and it's accessing an uplevel scope,
+ * then mark it as a delegate.
+ * Returns true if error occurs.
+ */
+bool FuncDeclaration::checkNestedReference(Scope *sc, Loc loc)
+{
+ //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
+
+ if (FuncLiteralDeclaration *fld = this->isFuncLiteralDeclaration())
+ {
+ if (fld->tok == TOKreserved)
+ {
+ fld->tok = TOKfunction;
+ fld->vthis = NULL;
+ }
+ }
+
+ if (!parent || parent == sc->parent)
+ return false;
+ if (ident == Id::require || ident == Id::ensure)
+ return false;
+ if (!isThis() && !isNested())
+ return false;
+
+ // The current function
+ FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
+ if (!fdthis)
+ return false; // out of function scope
+
+ Dsymbol *p = toParent2();
+
+ // Function literals from fdthis to p must be delegates
+ checkNestedRef(fdthis, p);
+
+ if (isNested())
+ {
+ // The function that this function is in
+ FuncDeclaration *fdv = p->isFuncDeclaration();
+ if (!fdv)
+ return false;
+ if (fdv == fdthis)
+ return false;
+
+ //printf("this = %s in [%s]\n", this->toChars(), this->loc.toChars());
+ //printf("fdv = %s in [%s]\n", fdv->toChars(), fdv->loc.toChars());
+ //printf("fdthis = %s in [%s]\n", fdthis->toChars(), fdthis->loc.toChars());
+
+ // Add this function to the list of those which called us
+ if (fdthis != this)
+ {
+ bool found = false;
+ for (size_t i = 0; i < siblingCallers.dim; ++i)
+ {
+ if (siblingCallers[i] == fdthis)
+ found = true;
+ }
+ if (!found)
+ {
+ //printf("\tadding sibling %s\n", fdthis->toPrettyChars());
+ if (!sc->intypeof && !(sc->flags & SCOPEcompile))
+ siblingCallers.push(fdthis);
+ }
+ }
+
+ int lv = fdthis->getLevel(loc, sc, fdv);
+ if (lv == -2)
+ return true; // error
+ if (lv == -1)
+ return false; // downlevel call
+ if (lv == 0)
+ return false; // same level call
+ // Uplevel call
+ }
+ return false;
+}
+
+/* For all functions between outerFunc and f, mark them as needing
+ * a closure.
+ */
+void markAsNeedingClosure(Dsymbol *f, FuncDeclaration *outerFunc)
+{
+ for (Dsymbol *sx = f; sx && sx != outerFunc; sx = sx->parent)
+ {
+ FuncDeclaration *fy = sx->isFuncDeclaration();
+ if (fy && fy->closureVars.dim)
+ {
+ /* fy needs a closure if it has closureVars[],
+ * because the frame pointer in the closure will be accessed.
+ */
+ fy->requiresClosure = true;
+ }
+ }
+}
+
+
+/* Given a nested function f inside a function outerFunc, check
+ * if any sibling callers of f have escaped. If so, mark
+ * all the enclosing functions as needing closures.
+ * Return true if any closures were detected.
+ * This is recursive: we need to check the callers of our siblings.
+ * Note that nested functions can only call lexically earlier nested
+ * functions, so loops are impossible.
+ */
+bool checkEscapingSiblings(FuncDeclaration *f, FuncDeclaration *outerFunc, void *p = NULL)
+{
+ struct PrevSibling
+ {
+ PrevSibling *p;
+ FuncDeclaration *f;
+ };
+
+ PrevSibling ps;
+ ps.p = (PrevSibling *)p;
+ ps.f = f;
+
+ //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f->toChars(), outerFunc->toChars());
+ bool bAnyClosures = false;
+ for (size_t i = 0; i < f->siblingCallers.dim; ++i)
+ {
+ FuncDeclaration *g = f->siblingCallers[i];
+ if (g->isThis() || g->tookAddressOf)
+ {
+ markAsNeedingClosure(g, outerFunc);
+ bAnyClosures = true;
+ }
+
+ PrevSibling *prev = (PrevSibling *)p;
+ while (1)
+ {
+ if (!prev)
+ {
+ bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
+ break;
+ }
+ if (prev->f == g)
+ break;
+ prev = prev->p;
+ }
+ }
+ //printf("\t%d\n", bAnyClosures);
+ return bAnyClosures;
+}
+
+
+/*******************************
+ * Look at all the variables in this function that are referenced
+ * by nested functions, and determine if a closure needs to be
+ * created for them.
+ */
+
+bool FuncDeclaration::needsClosure()
+{
+ /* Need a closure for all the closureVars[] if any of the
+ * closureVars[] are accessed by a
+ * function that escapes the scope of this function.
+ * We take the conservative approach and decide that a function needs
+ * a closure if it:
+ * 1) is a virtual function
+ * 2) has its address taken
+ * 3) has a parent that escapes
+ * 4) calls another nested function that needs a closure
+ *
+ * Note that since a non-virtual function can be called by
+ * a virtual one, if that non-virtual function accesses a closure
+ * var, the closure still has to be taken. Hence, we check for isThis()
+ * instead of isVirtual(). (thanks to David Friedman)
+ *
+ * When the function returns a local struct or class, `requiresClosure`
+ * is already set to `true` upon entering this function when the
+ * struct/class refers to a local variable and a closure is needed.
+ */
+
+ //printf("FuncDeclaration::needsClosure() %s\n", toChars());
+
+ if (requiresClosure)
+ goto Lyes;
+
+ for (size_t i = 0; i < closureVars.dim; i++)
+ {
+ VarDeclaration *v = closureVars[i];
+ //printf("\tv = %s\n", v->toChars());
+
+ for (size_t j = 0; j < v->nestedrefs.dim; j++)
+ {
+ FuncDeclaration *f = v->nestedrefs[j];
+ assert(f != this);
+
+ //printf("\t\tf = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf);
+
+ /* Look to see if f escapes. We consider all parents of f within
+ * this, and also all siblings which call f; if any of them escape,
+ * so does f.
+ * Mark all affected functions as requiring closures.
+ */
+ for (Dsymbol *s = f; s && s != this; s = s->parent)
+ {
+ FuncDeclaration *fx = s->isFuncDeclaration();
+ if (!fx)
+ continue;
+ if (fx->isThis() || fx->tookAddressOf)
+ {
+ //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx->toChars(), fx->isVirtual(), fx->isThis(), fx->tookAddressOf);
+
+ /* Mark as needing closure any functions between this and f
+ */
+ markAsNeedingClosure( (fx == f) ? fx->parent : fx, this);
+
+ requiresClosure = true;
+ }
+
+ /* We also need to check if any sibling functions that
+ * called us, have escaped. This is recursive: we need
+ * to check the callers of our siblings.
+ */
+ if (checkEscapingSiblings(fx, this))
+ requiresClosure = true;
+
+ /* Bugzilla 12406: Iterate all closureVars to mark all descendant
+ * nested functions that access to the closing context of this funciton.
+ */
+ }
+ }
+ }
+ if (requiresClosure)
+ goto Lyes;
+
+ return false;
+
+Lyes:
+ //printf("\tneeds closure\n");
+ return true;
+}
+
+/***********************************************
+ * Check that the function contains any closure.
+ * If it's @nogc, report suitable errors.
+ * This is mostly consistent with FuncDeclaration::needsClosure().
+ *
+ * Returns:
+ * true if any errors occur.
+ */
+bool FuncDeclaration::checkClosure()
+{
+ if (!needsClosure())
+ return false;
+
+ if (setGC())
+ {
+ error("is @nogc yet allocates closures with the GC");
+ if (global.gag) // need not report supplemental errors
+ return true;
+ }
+ else
+ {
+ printGCUsage(loc, "using closure causes GC allocation");
+ return false;
+ }
+
+ FuncDeclarations a;
+ for (size_t i = 0; i < closureVars.dim; i++)
+ {
+ VarDeclaration *v = closureVars[i];
+
+ for (size_t j = 0; j < v->nestedrefs.dim; j++)
+ {
+ FuncDeclaration *f = v->nestedrefs[j];
+ assert(f != this);
+
+ for (Dsymbol *s = f; s && s != this; s = s->parent)
+ {
+ FuncDeclaration *fx = s->isFuncDeclaration();
+ if (!fx)
+ continue;
+ if (fx->isThis() || fx->tookAddressOf)
+ goto Lfound;
+ if (checkEscapingSiblings(fx, this))
+ goto Lfound;
+ }
+ continue;
+
+ Lfound:
+ for (size_t k = 0; ; k++)
+ {
+ if (k == a.dim)
+ {
+ a.push(f);
+ ::errorSupplemental(f->loc, "%s closes over variable %s at %s",
+ f->toPrettyChars(), v->toChars(), v->loc.toChars());
+ break;
+ }
+ if (a[k] == f)
+ break;
+ }
+ continue;
+ }
+ }
+
+ return true;
+}
+
+/***********************************************
+ * Determine if function's variables are referenced by a function
+ * nested within it.
+ */
+
+bool FuncDeclaration::hasNestedFrameRefs()
+{
+ if (closureVars.dim)
+ return true;
+
+ /* If a virtual function has contracts, assume its variables are referenced
+ * by those contracts, even if they aren't. Because they might be referenced
+ * by the overridden or overriding function's contracts.
+ * This can happen because frequire and fensure are implemented as nested functions,
+ * and they can be called directly by an overriding function and the overriding function's
+ * context had better match, or Bugzilla 7335 will bite.
+ */
+ if (fdrequire || fdensure)
+ return true;
+
+ if (foverrides.dim && isVirtualMethod())
+ {
+ for (size_t i = 0; i < foverrides.dim; i++)
+ {
+ FuncDeclaration *fdv = foverrides[i];
+ if (fdv->hasNestedFrameRefs())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*********************************************
+ * Return the function's parameter list, and whether
+ * it is variadic or not.
+ */
+
+Parameters *FuncDeclaration::getParameters(int *pvarargs)
+{
+ Parameters *fparameters = NULL;
+ int fvarargs = 0;
+
+ if (type)
+ {
+ assert(type->ty == Tfunction);
+ TypeFunction *fdtype = (TypeFunction *)type;
+ fparameters = fdtype->parameters;
+ fvarargs = fdtype->varargs;
+ }
+ if (pvarargs)
+ *pvarargs = fvarargs;
+ return fparameters;
+}
+
+
+/****************************** FuncAliasDeclaration ************************/
+
+// Used as a way to import a set of functions from another scope into this one.
+
+FuncAliasDeclaration::FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads)
+ : FuncDeclaration(funcalias->loc, funcalias->endloc, ident,
+ funcalias->storage_class, funcalias->type)
+{
+ assert(funcalias != this);
+ this->funcalias = funcalias;
+
+ this->hasOverloads = hasOverloads;
+ if (hasOverloads)
+ {
+ if (FuncAliasDeclaration *fad = funcalias->isFuncAliasDeclaration())
+ this->hasOverloads = fad->hasOverloads;
+ }
+ else
+ { // for internal use
+ assert(!funcalias->isFuncAliasDeclaration());
+ this->hasOverloads = false;
+ }
+ userAttribDecl = funcalias->userAttribDecl;
+}
+
+const char *FuncAliasDeclaration::kind()
+{
+ return "function alias";
+}
+
+FuncDeclaration *FuncAliasDeclaration::toAliasFunc()
+{
+ return funcalias->toAliasFunc();
+}
+
+
+/****************************** FuncLiteralDeclaration ************************/
+
+FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type,
+ TOK tok, ForeachStatement *fes, Identifier *id)
+ : FuncDeclaration(loc, endloc, NULL, STCundefined, type)
+{
+ this->ident = id ? id : Id::empty;
+ this->tok = tok;
+ this->fes = fes;
+ this->treq = NULL;
+ this->deferToObj = false;
+ //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars());
+}
+
+Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s)
+{
+ //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
+ assert(!s);
+ FuncLiteralDeclaration *f = new FuncLiteralDeclaration(loc, endloc,
+ type->syntaxCopy(), tok, fes, ident);
+ f->treq = treq; // don't need to copy
+ return FuncDeclaration::syntaxCopy(f);
+}
+
+bool FuncLiteralDeclaration::isNested()
+{
+ //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
+ return (tok != TOKfunction) && !isThis();
+}
+
+AggregateDeclaration *FuncLiteralDeclaration::isThis()
+{
+ //printf("FuncLiteralDeclaration::isThis() '%s'\n", toChars());
+ return tok == TOKdelegate ? FuncDeclaration::isThis() : NULL;
+}
+
+bool FuncLiteralDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool FuncLiteralDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool FuncLiteralDeclaration::addPostInvariant()
+{
+ return false;
+}
+
+/*******************************
+ * Modify all expression type of return statements to tret.
+ *
+ * On function literals, return type may be modified based on the context type
+ * after its semantic3 is done, in FuncExp::implicitCastTo.
+ *
+ * A function() dg = (){ return new B(); } // OK if is(B : A) == true
+ *
+ * If B to A conversion is convariant that requires offseet adjusting,
+ * all return statements should be adjusted to return expressions typed A.
+ */
+void FuncLiteralDeclaration::modifyReturns(Scope *sc, Type *tret)
+{
+ class RetWalker : public StatementRewriteWalker
+ {
+ public:
+ Scope *sc;
+ Type *tret;
+ FuncLiteralDeclaration *fld;
+
+ void visit(ReturnStatement *s)
+ {
+ Expression *exp = s->exp;
+ if (exp && !exp->type->equals(tret))
+ {
+ s->exp = exp->castTo(sc, tret);
+ }
+ }
+ };
+
+ if (semanticRun < PASSsemantic3done)
+ return;
+
+ if (fes)
+ return;
+
+ RetWalker w;
+ w.sc = sc;
+ w.tret = tret;
+ w.fld = this;
+ fbody->accept(&w);
+
+ // Also update the inferred function type to match the new return type.
+ // This is required so the code generator does not try to cast the
+ // modified returns back to the original type.
+ if (inferRetType && type->nextOf() != tret)
+ ((TypeFunction *)type)->next = tret;
+}
+
+const char *FuncLiteralDeclaration::kind()
+{
+ return (tok != TOKfunction) ? "delegate" : "function";
+}
+
+const char *FuncLiteralDeclaration::toPrettyChars(bool QualifyTypes)
+{
+ if (parent)
+ {
+ TemplateInstance *ti = parent->isTemplateInstance();
+ if (ti)
+ return ti->tempdecl->toPrettyChars(QualifyTypes);
+ }
+ return Dsymbol::toPrettyChars(QualifyTypes);
+}
+
+/********************************* CtorDeclaration ****************************/
+
+CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type)
+ : FuncDeclaration(loc, endloc, Id::ctor, stc, type)
+{
+ //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
+}
+
+Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ CtorDeclaration *f = new CtorDeclaration(loc, endloc, storage_class, type->syntaxCopy());
+ return FuncDeclaration::syntaxCopy(f);
+}
+
+void CtorDeclaration::semantic(Scope *sc)
+{
+ //printf("CtorDeclaration::semantic() %s\n", toChars());
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = toParent2();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ ::error(loc, "constructor can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not a static constructor
+ sc->flags |= SCOPEctor;
+
+ FuncDeclaration::semantic(sc);
+
+ sc->pop();
+
+ if (errors)
+ return;
+
+ TypeFunction *tf = (TypeFunction *)type;
+ assert(tf && tf->ty == Tfunction);
+
+ /* See if it's the default constructor
+ * But, template constructor should not become a default constructor.
+ */
+ if (ad && (!parent->isTemplateInstance() || parent->isTemplateMixin()))
+ {
+ const size_t dim = Parameter::dim(tf->parameters);
+
+ if (StructDeclaration *sd = ad->isStructDeclaration())
+ {
+ if (dim == 0 && tf->varargs == 0) // empty default ctor w/o any varargs
+ {
+ if (fbody || !(storage_class & STCdisable) || dim)
+ {
+ error("default constructor for structs only allowed "
+ "with @disable, no body, and no parameters");
+ storage_class |= STCdisable;
+ fbody = NULL;
+ }
+ sd->noDefaultCtor = true;
+ }
+ else if (dim == 0 && tf->varargs) // allow varargs only ctor
+ {
+ }
+ else if (dim && Parameter::getNth(tf->parameters, 0)->defaultArg)
+ {
+ // if the first parameter has a default argument, then the rest does as well
+ if (storage_class & STCdisable)
+ {
+ deprecation("@disable'd constructor cannot have default "
+ "arguments for all parameters.");
+ deprecationSupplemental(loc, "Use @disable this(); if you want to disable default initialization.");
+ }
+ else
+ deprecation("all parameters have default arguments, "
+ "but structs cannot have default constructors.");
+ }
+
+ }
+ else if (dim == 0 && tf->varargs == 0)
+ {
+ ad->defaultCtor = this;
+ }
+ }
+}
+
+const char *CtorDeclaration::kind()
+{
+ return "constructor";
+}
+
+const char *CtorDeclaration::toChars()
+{
+ return "this";
+}
+
+bool CtorDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool CtorDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool CtorDeclaration::addPostInvariant()
+{
+ return (isThis() && vthis && global.params.useInvariants);
+}
+
+
+/********************************* PostBlitDeclaration ****************************/
+
+PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
+ : FuncDeclaration(loc, endloc, id, stc, NULL)
+{
+}
+
+Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
+ return FuncDeclaration::syntaxCopy(dd);
+}
+
+void PostBlitDeclaration::semantic(Scope *sc)
+{
+ //printf("PostBlitDeclaration::semantic() %s\n", toChars());
+ //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor);
+ //printf("stc = x%llx\n", sc->stc);
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = toParent2();
+ StructDeclaration *ad = p->isStructDeclaration();
+ if (!ad)
+ {
+ ::error(loc, "postblit can only be a member of struct/union, not %s %s",
+ p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ if (ident == Id::postblit && semanticRun < PASSsemantic)
+ ad->postblits.push(this);
+ if (!type)
+ type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not static
+ sc->linkage = LINKd;
+
+ FuncDeclaration::semantic(sc);
+
+ sc->pop();
+}
+
+bool PostBlitDeclaration::overloadInsert(Dsymbol *)
+{
+ return false; // cannot overload postblits
+}
+
+bool PostBlitDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool PostBlitDeclaration::addPostInvariant()
+{
+ return (isThis() && vthis && global.params.useInvariants);
+}
+
+bool PostBlitDeclaration::isVirtual()
+{
+ return false;
+}
+
+/********************************* DtorDeclaration ****************************/
+
+DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc)
+ : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL)
+{
+}
+
+DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
+ : FuncDeclaration(loc, endloc, id, stc, NULL)
+{
+}
+
+Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ DtorDeclaration *dd = new DtorDeclaration(loc, endloc, storage_class, ident);
+ return FuncDeclaration::syntaxCopy(dd);
+}
+
+void DtorDeclaration::semantic(Scope *sc)
+{
+ //printf("DtorDeclaration::semantic() %s\n", toChars());
+ //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor);
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = toParent2();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ ::error(loc, "destructor can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ if (ident == Id::dtor && semanticRun < PASSsemantic)
+ ad->dtors.push(this);
+ if (!type)
+ type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not a static destructor
+ if (sc->linkage != LINKcpp)
+ sc->linkage = LINKd;
+
+ FuncDeclaration::semantic(sc);
+
+ sc->pop();
+}
+
+bool DtorDeclaration::overloadInsert(Dsymbol *)
+{
+ return false; // cannot overload destructors
+}
+
+bool DtorDeclaration::addPreInvariant()
+{
+ return (isThis() && vthis && global.params.useInvariants);
+}
+
+bool DtorDeclaration::addPostInvariant()
+{
+ return false;
+}
+
+const char *DtorDeclaration::kind()
+{
+ return "destructor";
+}
+
+const char *DtorDeclaration::toChars()
+{
+ return "~this";
+}
+
+bool DtorDeclaration::isVirtual()
+{
+ // false so that dtor's don't get put into the vtbl[]
+ return false;
+}
+
+/********************************* StaticCtorDeclaration ****************************/
+
+StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+ : FuncDeclaration(loc, endloc,
+ Identifier::generateId("_staticCtor"), STCstatic | stc, NULL)
+{
+}
+
+StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
+ : FuncDeclaration(loc, endloc,
+ Identifier::generateId(name), STCstatic | stc, NULL)
+{
+}
+
+Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ StaticCtorDeclaration *scd = new StaticCtorDeclaration(loc, endloc, storage_class);
+ return FuncDeclaration::syntaxCopy(scd);
+}
+
+void StaticCtorDeclaration::semantic(Scope *sc)
+{
+ //printf("StaticCtorDeclaration::semantic()\n");
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = parent->pastMixin();
+ if (!p->isScopeDsymbol())
+ {
+ const char *s = (isSharedStaticCtorDeclaration() ? "shared " : "");
+ ::error(loc, "%sstatic constructor can only be member of module/aggregate/template, not %s %s",
+ s, p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ if (!type)
+ type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+ /* If the static ctor appears within a template instantiation,
+ * it could get called multiple times by the module constructors
+ * for different modules. Thus, protect it with a gate.
+ */
+ if (isInstantiated() && semanticRun < PASSsemantic)
+ {
+ /* Add this prefix to the function:
+ * static int gate;
+ * if (++gate != 1) return;
+ * Note that this is not thread safe; should not have threads
+ * during static construction.
+ */
+ VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
+ v->storage_class = STCtemp | (isSharedStaticCtorDeclaration() ? STCstatic : STCtls);
+ Statements *sa = new Statements();
+ Statement *s = new ExpStatement(Loc(), v);
+ sa->push(s);
+ Expression *e = new IdentifierExp(Loc(), v->ident);
+ e = new AddAssignExp(Loc(), e, new IntegerExp(1));
+ e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(1));
+ s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
+ sa->push(s);
+ if (fbody)
+ sa->push(fbody);
+ fbody = new CompoundStatement(Loc(), sa);
+ }
+
+ FuncDeclaration::semantic(sc);
+
+ // We're going to need ModuleInfo
+ Module *m = getModule();
+ if (!m)
+ m = sc->_module;
+ if (m)
+ {
+ m->needmoduleinfo = 1;
+ //printf("module1 %s needs moduleinfo\n", m->toChars());
+ }
+}
+
+AggregateDeclaration *StaticCtorDeclaration::isThis()
+{
+ return NULL;
+}
+
+bool StaticCtorDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool StaticCtorDeclaration::hasStaticCtorOrDtor()
+{
+ return true;
+}
+
+bool StaticCtorDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool StaticCtorDeclaration::addPostInvariant()
+{
+ return false;
+}
+
+/********************************* SharedStaticCtorDeclaration ****************************/
+
+SharedStaticCtorDeclaration::SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+ : StaticCtorDeclaration(loc, endloc, "_sharedStaticCtor", stc)
+{
+}
+
+Dsymbol *SharedStaticCtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ SharedStaticCtorDeclaration *scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
+ return FuncDeclaration::syntaxCopy(scd);
+}
+
+/********************************* StaticDtorDeclaration ****************************/
+
+StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+ : FuncDeclaration(loc, endloc,
+ Identifier::generateId("_staticDtor"), STCstatic | stc, NULL)
+{
+ vgate = NULL;
+}
+
+StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
+ : FuncDeclaration(loc, endloc,
+ Identifier::generateId(name), STCstatic | stc, NULL)
+{
+ vgate = NULL;
+}
+
+Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
+ return FuncDeclaration::syntaxCopy(sdd);
+}
+
+void StaticDtorDeclaration::semantic(Scope *sc)
+{
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = parent->pastMixin();
+ if (!p->isScopeDsymbol())
+ {
+ const char *s = (isSharedStaticDtorDeclaration() ? "shared " : "");
+ ::error(loc, "%sstatic destructor can only be member of module/aggregate/template, not %s %s",
+ s, p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ if (!type)
+ type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+ /* If the static ctor appears within a template instantiation,
+ * it could get called multiple times by the module constructors
+ * for different modules. Thus, protect it with a gate.
+ */
+ if (isInstantiated() && semanticRun < PASSsemantic)
+ {
+ /* Add this prefix to the function:
+ * static int gate;
+ * if (--gate != 0) return;
+ * Increment gate during constructor execution.
+ * Note that this is not thread safe; should not have threads
+ * during static destruction.
+ */
+ VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
+ v->storage_class = STCtemp | (isSharedStaticDtorDeclaration() ? STCstatic : STCtls);
+ Statements *sa = new Statements();
+ Statement *s = new ExpStatement(Loc(), v);
+ sa->push(s);
+ Expression *e = new IdentifierExp(Loc(), v->ident);
+ e = new AddAssignExp(Loc(), e, new IntegerExp(-1));
+ e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(0));
+ s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
+ sa->push(s);
+ if (fbody)
+ sa->push(fbody);
+ fbody = new CompoundStatement(Loc(), sa);
+ vgate = v;
+ }
+
+ FuncDeclaration::semantic(sc);
+
+ // We're going to need ModuleInfo
+ Module *m = getModule();
+ if (!m)
+ m = sc->_module;
+ if (m)
+ {
+ m->needmoduleinfo = 1;
+ //printf("module2 %s needs moduleinfo\n", m->toChars());
+ }
+}
+
+AggregateDeclaration *StaticDtorDeclaration::isThis()
+{
+ return NULL;
+}
+
+bool StaticDtorDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool StaticDtorDeclaration::hasStaticCtorOrDtor()
+{
+ return true;
+}
+
+bool StaticDtorDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool StaticDtorDeclaration::addPostInvariant()
+{
+ return false;
+}
+
+/********************************* SharedStaticDtorDeclaration ****************************/
+
+SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
+ : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor", stc)
+{
+}
+
+Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
+ return FuncDeclaration::syntaxCopy(sdd);
+}
+
+/********************************* InvariantDeclaration ****************************/
+
+InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
+ : FuncDeclaration(loc, endloc,
+ id ? id : Identifier::generateId("__invariant"),
+ stc, NULL)
+{
+}
+
+Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ InvariantDeclaration *id = new InvariantDeclaration(loc, endloc, storage_class);
+ return FuncDeclaration::syntaxCopy(id);
+}
+
+void InvariantDeclaration::semantic(Scope *sc)
+{
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = parent->pastMixin();
+ AggregateDeclaration *ad = p->isAggregateDeclaration();
+ if (!ad)
+ {
+ ::error(loc, "invariant can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ if (ident != Id::classInvariant &&
+ semanticRun < PASSsemantic &&
+ !ad->isUnionDeclaration() // users are on their own with union fields
+ )
+ ad->invs.push(this);
+ if (!type)
+ type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+
+ sc = sc->push();
+ sc->stc &= ~STCstatic; // not a static invariant
+ sc->stc |= STCconst; // invariant() is always const
+ sc->flags = (sc->flags & ~SCOPEcontract) | SCOPEinvariant;
+ sc->linkage = LINKd;
+
+ FuncDeclaration::semantic(sc);
+
+ sc->pop();
+}
+
+bool InvariantDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool InvariantDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool InvariantDeclaration::addPostInvariant()
+{
+ return false;
+}
+
+/********************************* UnitTestDeclaration ****************************/
+
+/*******************************
+ * Generate unique unittest function Id so we can have multiple
+ * instances per module.
+ */
+
+static Identifier *unitTestId(Loc loc)
+{
+ OutBuffer buf;
+ buf.printf("__unittestL%u_", loc.linnum);
+ return Identifier::generateId(buf.peekString());
+}
+
+UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc)
+ : FuncDeclaration(loc, endloc, unitTestId(loc), stc, NULL)
+{
+ this->codedoc = codedoc;
+}
+
+Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ UnitTestDeclaration *utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
+ return FuncDeclaration::syntaxCopy(utd);
+}
+
+void UnitTestDeclaration::semantic(Scope *sc)
+{
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ protection = sc->protection;
+
+ parent = sc->parent;
+ Dsymbol *p = parent->pastMixin();
+ if (!p->isScopeDsymbol())
+ {
+ ::error(loc, "unittest can only be a member of module/aggregate/template, not %s %s",
+ p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+
+ if (global.params.useUnitTests)
+ {
+ if (!type)
+ type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class);
+ Scope *sc2 = sc->push();
+ sc2->linkage = LINKd;
+ FuncDeclaration::semantic(sc2);
+ sc2->pop();
+ }
+}
+
+AggregateDeclaration *UnitTestDeclaration::isThis()
+{
+ return NULL;
+}
+
+bool UnitTestDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool UnitTestDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool UnitTestDeclaration::addPostInvariant()
+{
+ return false;
+}
+
+/********************************* NewDeclaration ****************************/
+
+NewDeclaration::NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams, int varargs)
+ : FuncDeclaration(loc, endloc, Id::classNew, STCstatic | stc, NULL)
+{
+ this->parameters = fparams;
+ this->varargs = varargs;
+}
+
+Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ NewDeclaration *f = new NewDeclaration(loc, endloc,
+ storage_class, Parameter::arraySyntaxCopy(parameters), varargs);
+ return FuncDeclaration::syntaxCopy(f);
+}
+
+void NewDeclaration::semantic(Scope *sc)
+{
+ //printf("NewDeclaration::semantic()\n");
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = parent->pastMixin();
+ if (!p->isAggregateDeclaration())
+ {
+ ::error(loc, "allocator can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ Type *tret = Type::tvoid->pointerTo();
+ if (!type)
+ type = new TypeFunction(parameters, tret, varargs, LINKd, storage_class);
+
+ type = type->semantic(loc, sc);
+ assert(type->ty == Tfunction);
+
+ // Check that there is at least one argument of type size_t
+ TypeFunction *tf = (TypeFunction *)type;
+ if (Parameter::dim(tf->parameters) < 1)
+ {
+ error("at least one argument of type size_t expected");
+ }
+ else
+ {
+ Parameter *fparam = Parameter::getNth(tf->parameters, 0);
+ if (!fparam->type->equals(Type::tsize_t))
+ error("first argument must be type size_t, not %s", fparam->type->toChars());
+ }
+
+ FuncDeclaration::semantic(sc);
+}
+
+const char *NewDeclaration::kind()
+{
+ return "allocator";
+}
+
+bool NewDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool NewDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool NewDeclaration::addPostInvariant()
+{
+ return false;
+}
+
+/********************************* DeleteDeclaration ****************************/
+
+DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams)
+ : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic | stc, NULL)
+{
+ this->parameters = fparams;
+}
+
+Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ DeleteDeclaration *f = new DeleteDeclaration(loc, endloc,
+ storage_class, Parameter::arraySyntaxCopy(parameters));
+ return FuncDeclaration::syntaxCopy(f);
+}
+
+void DeleteDeclaration::semantic(Scope *sc)
+{
+ //printf("DeleteDeclaration::semantic()\n");
+ if (semanticRun >= PASSsemanticdone)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+
+ parent = sc->parent;
+ Dsymbol *p = parent->pastMixin();
+ if (!p->isAggregateDeclaration())
+ {
+ ::error(loc, "deallocator can only be a member of aggregate, not %s %s",
+ p->kind(), p->toChars());
+ type = Type::terror;
+ errors = true;
+ return;
+ }
+ if (!type)
+ type = new TypeFunction(parameters, Type::tvoid, 0, LINKd, storage_class);
+
+ type = type->semantic(loc, sc);
+ assert(type->ty == Tfunction);
+
+ // Check that there is only one argument of type void*
+ TypeFunction *tf = (TypeFunction *)type;
+ if (Parameter::dim(tf->parameters) != 1)
+ {
+ error("one argument of type void* expected");
+ }
+ else
+ {
+ Parameter *fparam = Parameter::getNth(tf->parameters, 0);
+ if (!fparam->type->equals(Type::tvoid->pointerTo()))
+ error("one argument of type void* expected, not %s", fparam->type->toChars());
+ }
+
+ FuncDeclaration::semantic(sc);
+}
+
+const char *DeleteDeclaration::kind()
+{
+ return "deallocator";
+}
+
+bool DeleteDeclaration::isDelete()
+{
+ return true;
+}
+
+bool DeleteDeclaration::isVirtual()
+{
+ return false;
+}
+
+bool DeleteDeclaration::addPreInvariant()
+{
+ return false;
+}
+
+bool DeleteDeclaration::addPostInvariant()
+{
+ return false;
+}
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
new file mode 100644
index 0000000..63caeb7
--- /dev/null
+++ b/gcc/d/dmd/globals.h
@@ -0,0 +1,317 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/globals.h
+ */
+
+#pragma once
+
+#include "root/dcompat.h"
+#include "root/ctfloat.h"
+#include "root/outbuffer.h"
+#include "root/filename.h"
+#include "compiler.h"
+
+// Can't include arraytypes.h here, need to declare these directly.
+template <typename TYPE> struct Array;
+
+typedef unsigned char Diagnostic;
+enum
+{
+ DIAGNOSTICerror, // generate an error
+ DIAGNOSTICinform, // generate a warning
+ DIAGNOSTICoff // disable diagnostic
+};
+
+// The state of array bounds checking
+enum BOUNDSCHECK
+{
+ BOUNDSCHECKdefault, // initial value
+ BOUNDSCHECKoff, // never do bounds checking
+ BOUNDSCHECKon, // always do bounds checking
+ BOUNDSCHECKsafeonly // do bounds checking only in @safe functions
+};
+
+enum CPU
+{
+ x87,
+ mmx,
+ sse,
+ sse2,
+ sse3,
+ ssse3,
+ sse4_1,
+ sse4_2,
+ avx, // AVX1 instruction set
+ avx2, // AVX2 instruction set
+ avx512, // AVX-512 instruction set
+
+ // Special values that don't survive past the command line processing
+ baseline, // (default) the minimum capability CPU
+ native // the machine the compiler is being run on
+};
+
+// Put command line switches in here
+struct Param
+{
+ bool obj; // write object file
+ bool link; // perform link
+ bool dll; // generate shared dynamic library
+ bool lib; // write library file instead of object file(s)
+ bool multiobj; // break one object file into multiple ones
+ bool oneobj; // write one object file instead of multiple ones
+ bool trace; // insert profiling hooks
+ bool tracegc; // instrument calls to 'new'
+ bool verbose; // verbose compile
+ bool vcg_ast; // write-out codegen-ast
+ bool showColumns; // print character (column) numbers in diagnostics
+ bool vtls; // identify thread local variables
+ char vgc; // identify gc usage
+ bool vfield; // identify non-mutable field variables
+ bool vcomplex; // identify complex/imaginary type usage
+ char symdebug; // insert debug symbolic information
+ bool symdebugref; // insert debug information for all referenced types, too
+ bool alwaysframe; // always emit standard stack frame
+ bool optimize; // run optimizer
+ bool map; // generate linker .map file
+ bool is64bit; // generate 64 bit code
+ bool isLP64; // generate code for LP64
+ bool isLinux; // generate code for linux
+ bool isOSX; // generate code for Mac OSX
+ bool isWindows; // generate code for Windows
+ bool isFreeBSD; // generate code for FreeBSD
+ bool isOpenBSD; // generate code for OpenBSD
+ bool isSolaris; // generate code for Solaris
+ bool hasObjectiveC; // target supports Objective-C
+ bool mscoff; // for Win32: write COFF object files instead of OMF
+ Diagnostic useDeprecated;
+ bool useAssert; // generate runtime code for assert()'s
+ bool useInvariants; // generate class invariant checks
+ bool useIn; // generate precondition checks
+ bool useOut; // generate postcondition checks
+ bool stackstomp; // add stack stomping code
+ bool useSwitchError; // check for switches without a default
+ bool useUnitTests; // generate unittest code
+ bool useInline; // inline expand functions
+ bool useDIP25; // implement http://wiki.dlang.org/DIP25
+ bool release; // build release version
+ bool preservePaths; // true means don't strip path from source file
+ Diagnostic warnings;
+ bool pic; // generate position-independent-code for shared libs
+ bool color; // use ANSI colors in console output
+ bool cov; // generate code coverage data
+ unsigned char covPercent; // 0..100 code coverage percentage required
+ bool nofloat; // code should not pull in floating point support
+ bool ignoreUnsupportedPragmas; // rather than error on them
+ bool enforcePropertySyntax;
+ bool betterC; // be a "better C" compiler; no dependency on D runtime
+ bool addMain; // add a default main() function
+ bool allInst; // generate code for all template instantiations
+ bool check10378; // check for issues transitioning to 10738
+ bool bug10378; // use pre-bugzilla 10378 search strategy
+ bool vsafe; // use enhanced @safe checking
+ bool showGaggedErrors; // print gagged errors anyway
+
+ CPU cpu; // CPU instruction set to target
+ BOUNDSCHECK useArrayBounds;
+
+ const char *argv0; // program name
+ Array<const char *> *modFileAliasStrings; // array of char*'s of -I module filename alias strings
+ Array<const char *> *imppath; // array of char*'s of where to look for import modules
+ Array<const char *> *fileImppath; // array of char*'s of where to look for file import modules
+ const char *objdir; // .obj/.lib file output directory
+ const char *objname; // .obj file output name
+ const char *libname; // .lib file output name
+
+ bool doDocComments; // process embedded documentation comments
+ const char *docdir; // write documentation file to docdir directory
+ const char *docname; // write documentation file to docname
+ Array<const char *> *ddocfiles; // macro include files for Ddoc
+
+ bool doHdrGeneration; // process embedded documentation comments
+ const char *hdrdir; // write 'header' file to docdir directory
+ const char *hdrname; // write 'header' file to docname
+ bool hdrStripPlainFunctions; // strip the bodies of plain (non-template) functions
+
+ bool doJsonGeneration; // write JSON file
+ const char *jsonfilename; // write JSON file to jsonfilename
+
+ unsigned debuglevel; // debug level
+ Array<const char *> *debugids; // debug identifiers
+
+ unsigned versionlevel; // version level
+ Array<const char *> *versionids; // version identifiers
+
+ const char *defaultlibname; // default library for non-debug builds
+ const char *debuglibname; // default library for debug builds
+ const char *mscrtlib; // MS C runtime library
+
+ const char *moduleDepsFile; // filename for deps output
+ OutBuffer *moduleDeps; // contents to be written to deps file
+
+ // Hidden debug switches
+ bool debugb;
+ bool debugc;
+ bool debugf;
+ bool debugr;
+ bool debugx;
+ bool debugy;
+
+ bool run; // run resulting executable
+ Strings runargs; // arguments for executable
+
+ // Linker stuff
+ Array<const char *> *objfiles;
+ Array<const char *> *linkswitches;
+ Array<const char *> *libfiles;
+ Array<const char *> *dllfiles;
+ const char *deffile;
+ const char *resfile;
+ const char *exefile;
+ const char *mapfile;
+};
+
+typedef unsigned structalign_t;
+// magic value means "match whatever the underlying C compiler does"
+// other values are all powers of 2
+#define STRUCTALIGN_DEFAULT ((structalign_t) ~0)
+
+struct Global
+{
+ const char *inifilename;
+ const char *mars_ext;
+ const char *obj_ext;
+ const char *lib_ext;
+ const char *dll_ext;
+ const char *doc_ext; // for Ddoc generated files
+ const char *ddoc_ext; // for Ddoc macro include files
+ const char *hdr_ext; // for D 'header' import files
+ const char *json_ext; // for JSON files
+ const char *map_ext; // for .map files
+ bool run_noext; // allow -run sources without extensions.
+
+ const char *copyright;
+ const char *written;
+ const char *main_d; // dummy filename for dummy main()
+ Array<const char *> *path; // Array of char*'s which form the import lookup path
+ Array<const char *> *filePath; // Array of char*'s which form the file import lookup path
+
+ const char *version; // Compiler version string
+ const char *vendor; // Compiler backend name
+
+ Param params;
+ unsigned errors; // number of errors reported so far
+ unsigned warnings; // number of warnings reported so far
+ FILE *stdmsg; // where to send verbose messages
+ unsigned gag; // !=0 means gag reporting of errors & warnings
+ unsigned gaggedErrors; // number of errors reported while gagged
+
+ unsigned errorLimit;
+
+ void* console; // opaque pointer to console for controlling text attributes
+
+ /* Start gagging. Return the current number of gagged errors
+ */
+ unsigned startGagging();
+
+ /* End gagging, restoring the old gagged state.
+ * Return true if errors occurred while gagged.
+ */
+ bool endGagging(unsigned oldGagged);
+
+ /* Increment the error count to record that an error
+ * has occurred in the current context. An error message
+ * may or may not have been printed.
+ */
+ void increaseErrorCount();
+
+ void _init();
+};
+
+extern Global global;
+
+// Because int64_t and friends may be any integral type of the
+// correct size, we have to explicitly ask for the correct
+// integer type to get the correct mangling with ddmd
+#if __LP64__
+// Be careful not to care about sign when using dinteger_t
+// use this instead of integer_t to
+// avoid conflicts with system #include's
+typedef unsigned long dinteger_t;
+// Signed and unsigned variants
+typedef long sinteger_t;
+typedef unsigned long uinteger_t;
+#else
+typedef unsigned long long dinteger_t;
+typedef long long sinteger_t;
+typedef unsigned long long uinteger_t;
+#endif
+
+typedef int8_t d_int8;
+typedef uint8_t d_uns8;
+typedef int16_t d_int16;
+typedef uint16_t d_uns16;
+typedef int32_t d_int32;
+typedef uint32_t d_uns32;
+typedef int64_t d_int64;
+typedef uint64_t d_uns64;
+
+// file location
+struct Loc
+{
+ const char *filename;
+ unsigned linnum;
+ unsigned charnum;
+
+ Loc()
+ {
+ linnum = 0;
+ charnum = 0;
+ filename = NULL;
+ }
+
+ Loc(const char *filename, unsigned linnum, unsigned charnum);
+
+ const char *toChars() const;
+ bool equals(const Loc& loc);
+};
+
+enum LINK
+{
+ LINKdefault,
+ LINKd,
+ LINKc,
+ LINKcpp,
+ LINKwindows,
+ LINKpascal,
+ LINKobjc,
+ LINKsystem
+};
+
+enum CPPMANGLE
+{
+ CPPMANGLEdefault,
+ CPPMANGLEstruct,
+ CPPMANGLEclass
+};
+
+enum MATCH
+{
+ MATCHnomatch, // no match
+ MATCHconvert, // match with conversions
+ MATCHconst, // match with conversion to const
+ MATCHexact // exact match
+};
+
+enum PINLINE
+{
+ PINLINEdefault, // as specified on the command line
+ PINLINEnever, // never inline
+ PINLINEalways // always inline
+};
+
+typedef uinteger_t StorageClass;
diff --git a/gcc/d/dmd/hdrgen.c b/gcc/d/dmd/hdrgen.c
new file mode 100644
index 0000000..2c734b3
--- /dev/null
+++ b/gcc/d/dmd/hdrgen.c
@@ -0,0 +1,3414 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Dave Fladebo
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/hdrgen.c
+ */
+
+// Routines to emit header files
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "id.h"
+#include "init.h"
+
+#include "attrib.h"
+#include "cond.h"
+#include "doc.h"
+#include "enum.h"
+#include "import.h"
+#include "module.h"
+#include "mtype.h"
+#include "parse.h"
+#include "scope.h"
+#include "staticassert.h"
+#include "target.h"
+#include "template.h"
+#include "utf.h"
+#include "version.h"
+
+#include "declaration.h"
+#include "aggregate.h"
+#include "expression.h"
+#include "ctfe.h"
+#include "statement.h"
+#include "aliasthis.h"
+#include "nspace.h"
+#include "hdrgen.h"
+
+void linkageToBuffer(OutBuffer *buf, LINK linkage);
+void MODtoBuffer(OutBuffer *buf, MOD mod);
+
+void genhdrfile(Module *m)
+{
+ OutBuffer buf;
+ buf.doindent = 1;
+
+ buf.printf("// D import file generated from '%s'", m->srcfile->toChars());
+ buf.writenl();
+
+ HdrGenState hgs;
+ hgs.hdrgen = true;
+
+ toCBuffer(m, &buf, &hgs);
+
+ // Transfer image to file
+ m->hdrfile->setbuffer(buf.data, buf.offset);
+ buf.extractData();
+
+ ensurePathToNameExists(Loc(), m->hdrfile->toChars());
+ writeFile(m->loc, m->hdrfile);
+}
+
+/**
+ * Dumps the full contents of module `m` to `buf`.
+ * Params:
+ * buf = buffer to write to.
+ * m = module to visit all members of.
+ */
+void moduleToBuffer(OutBuffer *buf, Module *m)
+{
+ HdrGenState hgs;
+ hgs.fullDump = true;
+ toCBuffer(m, buf, &hgs);
+}
+
+class PrettyPrintVisitor : public Visitor
+{
+public:
+ OutBuffer *buf;
+ HdrGenState *hgs;
+ bool declstring; // set while declaring alias for string,wstring or dstring
+ EnumDeclaration *inEnumDecl;
+
+ PrettyPrintVisitor(OutBuffer *buf, HdrGenState *hgs)
+ : buf(buf), hgs(hgs), declstring(false), inEnumDecl(NULL)
+ {
+ }
+
+ void visit(Statement *)
+ {
+ buf->printf("Statement::toCBuffer()");
+ buf->writenl();
+ assert(0);
+ }
+
+ void visit(ErrorStatement *)
+ {
+ buf->printf("__error__");
+ buf->writenl();
+ }
+
+ void visit(ExpStatement *s)
+ {
+ if (s->exp && s->exp->op == TOKdeclaration)
+ {
+ // bypass visit(DeclarationExp)
+ ((DeclarationExp *)s->exp)->declaration->accept(this);
+ return;
+ }
+ if (s->exp)
+ s->exp->accept(this);
+ buf->writeByte(';');
+ if (!hgs->forStmtInit)
+ buf->writenl();
+ }
+
+ void visit(CompileStatement *s)
+ {
+ buf->writestring("mixin(");
+ s->exp->accept(this);
+ buf->writestring(");");
+ if (!hgs->forStmtInit)
+ buf->writenl();
+ }
+
+ void visit(CompoundStatement *s)
+ {
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ Statement *sx = (*s->statements)[i];
+ if (sx)
+ sx->accept(this);
+ }
+ }
+
+ void visit(CompoundDeclarationStatement *s)
+ {
+ bool anywritten = false;
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ Statement *sx = (*s->statements)[i];
+ ExpStatement *ds = sx ? sx->isExpStatement() : NULL;
+ if (ds && ds->exp->op == TOKdeclaration)
+ {
+ Dsymbol *d = ((DeclarationExp *)ds->exp)->declaration;
+ assert(d->isDeclaration());
+ if (VarDeclaration *v = d->isVarDeclaration())
+ visitVarDecl(v, anywritten);
+ else
+ d->accept(this);
+ anywritten = true;
+ }
+ }
+ buf->writeByte(';');
+ if (!hgs->forStmtInit)
+ buf->writenl();
+ }
+
+ void visit(UnrolledLoopStatement *s)
+ {
+ buf->writestring("unrolled {");
+ buf->writenl();
+ buf->level++;
+
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ Statement *sx = (*s->statements)[i];
+ if (sx)
+ sx->accept(this);
+ }
+
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(ScopeStatement *s)
+ {
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+
+ if (s->statement)
+ s->statement->accept(this);
+
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(WhileStatement *s)
+ {
+ buf->writestring("while (");
+ s->condition->accept(this);
+ buf->writeByte(')');
+ buf->writenl();
+ if (s->_body)
+ s->_body->accept(this);
+ }
+
+ void visit(DoStatement *s)
+ {
+ buf->writestring("do");
+ buf->writenl();
+ if (s->_body)
+ s->_body->accept(this);
+ buf->writestring("while (");
+ s->condition->accept(this);
+ buf->writestring(");");
+ buf->writenl();
+ }
+
+ void visit(ForStatement *s)
+ {
+ buf->writestring("for (");
+ if (s->_init)
+ {
+ hgs->forStmtInit++;
+ s->_init->accept(this);
+ hgs->forStmtInit--;
+ }
+ else
+ buf->writeByte(';');
+ if (s->condition)
+ {
+ buf->writeByte(' ');
+ s->condition->accept(this);
+ }
+ buf->writeByte(';');
+ if (s->increment)
+ {
+ buf->writeByte(' ');
+ s->increment->accept(this);
+ }
+ buf->writeByte(')');
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ if (s->_body)
+ s->_body->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(ForeachStatement *s)
+ {
+ buf->writestring(Token::toChars(s->op));
+ buf->writestring(" (");
+ for (size_t i = 0; i < s->parameters->dim; i++)
+ {
+ Parameter *p = (*s->parameters)[i];
+ if (i)
+ buf->writestring(", ");
+ if (stcToBuffer(buf, p->storageClass))
+ buf->writeByte(' ');
+ if (p->type)
+ typeToBuffer(p->type, p->ident);
+ else
+ buf->writestring(p->ident->toChars());
+ }
+ buf->writestring("; ");
+ s->aggr->accept(this);
+ buf->writeByte(')');
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ if (s->_body)
+ s->_body->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(ForeachRangeStatement *s)
+ {
+ buf->writestring(Token::toChars(s->op));
+ buf->writestring(" (");
+
+ if (s->prm->type)
+ typeToBuffer(s->prm->type, s->prm->ident);
+ else
+ buf->writestring(s->prm->ident->toChars());
+
+ buf->writestring("; ");
+ s->lwr->accept(this);
+ buf->writestring(" .. ");
+ s->upr->accept(this);
+ buf->writeByte(')');
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ if (s->_body)
+ s->_body->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(IfStatement *s)
+ {
+ buf->writestring("if (");
+ if (Parameter *p = s->prm)
+ {
+ StorageClass stc = p->storageClass;
+ if (!p->type && !stc)
+ stc = STCauto;
+ if (stcToBuffer(buf, stc))
+ buf->writeByte(' ');
+ if (p->type)
+ typeToBuffer(p->type, p->ident);
+ else
+ buf->writestring(p->ident->toChars());
+ buf->writestring(" = ");
+ }
+ s->condition->accept(this);
+ buf->writeByte(')');
+ buf->writenl();
+ if (s->ifbody->isScopeStatement())
+ {
+ s->ifbody->accept(this);
+ }
+ else
+ {
+ buf->level++;
+ s->ifbody->accept(this);
+ buf->level--;
+ }
+ if (s->elsebody)
+ {
+ buf->writestring("else");
+ if (!s->elsebody->isIfStatement())
+ {
+ buf->writenl();
+ }
+ else
+ {
+ buf->writeByte(' ');
+ }
+ if (s->elsebody->isScopeStatement() || s->elsebody->isIfStatement())
+ {
+ s->elsebody->accept(this);
+ }
+ else
+ {
+ buf->level++;
+ s->elsebody->accept(this);
+ buf->level--;
+ }
+ }
+ }
+
+ void visit(ConditionalStatement *s)
+ {
+ s->condition->accept(this);
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ if (s->ifbody)
+ s->ifbody->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ if (s->elsebody)
+ {
+ buf->writestring("else");
+ buf->writenl();
+ buf->writeByte('{');
+ buf->level++;
+ buf->writenl();
+ s->elsebody->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ }
+ buf->writenl();
+ }
+
+ void visit(PragmaStatement *s)
+ {
+ buf->writestring("pragma (");
+ buf->writestring(s->ident->toChars());
+ if (s->args && s->args->dim)
+ {
+ buf->writestring(", ");
+ argsToBuffer(s->args);
+ }
+ buf->writeByte(')');
+ if (s->_body)
+ {
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+
+ s->_body->accept(this);
+
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+ else
+ {
+ buf->writeByte(';');
+ buf->writenl();
+ }
+ }
+
+ void visit(StaticAssertStatement *s)
+ {
+ s->sa->accept(this);
+ }
+
+ void visit(SwitchStatement *s)
+ {
+ buf->writestring(s->isFinal ? "final switch (" : "switch (");
+ s->condition->accept(this);
+ buf->writeByte(')');
+ buf->writenl();
+ if (s->_body)
+ {
+ if (!s->_body->isScopeStatement())
+ {
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ s->_body->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+ else
+ {
+ s->_body->accept(this);
+ }
+ }
+ }
+
+ void visit(CaseStatement *s)
+ {
+ buf->writestring("case ");
+ s->exp->accept(this);
+ buf->writeByte(':');
+ buf->writenl();
+ s->statement->accept(this);
+ }
+
+ void visit(CaseRangeStatement *s)
+ {
+ buf->writestring("case ");
+ s->first->accept(this);
+ buf->writestring(": .. case ");
+ s->last->accept(this);
+ buf->writeByte(':');
+ buf->writenl();
+ s->statement->accept(this);
+ }
+
+ void visit(DefaultStatement *s)
+ {
+ buf->writestring("default:");
+ buf->writenl();
+ s->statement->accept(this);
+ }
+
+ void visit(GotoDefaultStatement *)
+ {
+ buf->writestring("goto default;");
+ buf->writenl();
+ }
+
+ void visit(GotoCaseStatement *s)
+ {
+ buf->writestring("goto case");
+ if (s->exp)
+ {
+ buf->writeByte(' ');
+ s->exp->accept(this);
+ }
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visit(SwitchErrorStatement *)
+ {
+ buf->writestring("SwitchErrorStatement::toCBuffer()");
+ buf->writenl();
+ }
+
+ void visit(ReturnStatement *s)
+ {
+ buf->printf("return ");
+ if (s->exp)
+ s->exp->accept(this);
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visit(BreakStatement *s)
+ {
+ buf->writestring("break");
+ if (s->ident)
+ {
+ buf->writeByte(' ');
+ buf->writestring(s->ident->toChars());
+ }
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visit(ContinueStatement *s)
+ {
+ buf->writestring("continue");
+ if (s->ident)
+ {
+ buf->writeByte(' ');
+ buf->writestring(s->ident->toChars());
+ }
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visit(SynchronizedStatement *s)
+ {
+ buf->writestring("synchronized");
+ if (s->exp)
+ {
+ buf->writeByte('(');
+ s->exp->accept(this);
+ buf->writeByte(')');
+ }
+ if (s->_body)
+ {
+ buf->writeByte(' ');
+ s->_body->accept(this);
+ }
+ }
+
+ void visit(WithStatement *s)
+ {
+ buf->writestring("with (");
+ s->exp->accept(this);
+ buf->writestring(")");
+ buf->writenl();
+ if (s->_body)
+ s->_body->accept(this);
+ }
+
+ void visit(TryCatchStatement *s)
+ {
+ buf->writestring("try");
+ buf->writenl();
+ if (s->_body)
+ s->_body->accept(this);
+ for (size_t i = 0; i < s->catches->dim; i++)
+ {
+ Catch *c = (*s->catches)[i];
+ visit(c);
+ }
+ }
+
+ void visit(TryFinallyStatement *s)
+ {
+ buf->writestring("try");
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ s->_body->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ buf->writestring("finally");
+ buf->writenl();
+ if (s->finalbody->isScopeStatement())
+ {
+ s->finalbody->accept(this);
+ }
+ else
+ {
+ buf->level++;
+ s->finalbody->accept(this);
+ buf->level--;
+ }
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(OnScopeStatement *s)
+ {
+ buf->writestring(Token::toChars(s->tok));
+ buf->writeByte(' ');
+ s->statement->accept(this);
+ }
+
+ void visit(ThrowStatement *s)
+ {
+ buf->printf("throw ");
+ s->exp->accept(this);
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visit(DebugStatement *s)
+ {
+ if (s->statement)
+ {
+ s->statement->accept(this);
+ }
+ }
+
+ void visit(GotoStatement *s)
+ {
+ buf->writestring("goto ");
+ buf->writestring(s->ident->toChars());
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visit(LabelStatement *s)
+ {
+ buf->writestring(s->ident->toChars());
+ buf->writeByte(':');
+ buf->writenl();
+ if (s->statement)
+ s->statement->accept(this);
+ }
+
+ void visit(AsmStatement *s)
+ {
+ buf->writestring("asm { ");
+ Token *t = s->tokens;
+ buf->level++;
+ while (t)
+ {
+ buf->writestring(t->toChars());
+ if (t->next &&
+ t->value != TOKmin &&
+ t->value != TOKcomma && t->next->value != TOKcomma &&
+ t->value != TOKlbracket && t->next->value != TOKlbracket &&
+ t->next->value != TOKrbracket &&
+ t->value != TOKlparen && t->next->value != TOKlparen &&
+ t->next->value != TOKrparen &&
+ t->value != TOKdot && t->next->value != TOKdot)
+ {
+ buf->writeByte(' ');
+ }
+ t = t->next;
+ }
+ buf->level--;
+ buf->writestring("; }");
+ buf->writenl();
+ }
+
+ void visit(ImportStatement *s)
+ {
+ for (size_t i = 0; i < s->imports->dim; i++)
+ {
+ Dsymbol *imp = (*s->imports)[i];
+ imp->accept(this);
+ }
+ }
+
+ void visit(Catch *c)
+ {
+ buf->writestring("catch");
+ if (c->type)
+ {
+ buf->writeByte('(');
+ typeToBuffer(c->type, c->ident);
+ buf->writeByte(')');
+ }
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ if (c->handler)
+ c->handler->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**************************************************
+ * An entry point to pretty-print type.
+ */
+ void typeToBuffer(Type *t, Identifier *ident)
+ {
+ if (t->ty == Tfunction)
+ {
+ visitFuncIdentWithPrefix((TypeFunction *)t, ident, NULL);
+ return;
+ }
+
+ visitWithMask(t, 0);
+
+ if (ident)
+ {
+ buf->writeByte(' ');
+ buf->writestring(ident->toChars());
+ }
+ }
+
+ void visitWithMask(Type *t, unsigned char modMask)
+ {
+ // Tuples and functions don't use the type constructor syntax
+ if (modMask == t->mod ||
+ t->ty == Tfunction ||
+ t->ty == Ttuple)
+ {
+ t->accept(this);
+ }
+ else
+ {
+ unsigned char m = t->mod & ~(t->mod & modMask);
+ if (m & MODshared)
+ {
+ MODtoBuffer(buf, MODshared);
+ buf->writeByte('(');
+ }
+ if (m & MODwild)
+ {
+ MODtoBuffer(buf, MODwild);
+ buf->writeByte('(');
+ }
+ if (m & (MODconst | MODimmutable))
+ {
+ MODtoBuffer(buf, m & (MODconst | MODimmutable));
+ buf->writeByte('(');
+ }
+
+ t->accept(this);
+
+ if (m & (MODconst | MODimmutable))
+ buf->writeByte(')');
+ if (m & MODwild)
+ buf->writeByte(')');
+ if (m & MODshared)
+ buf->writeByte(')');
+ }
+ }
+
+ void visit(Type *t)
+ {
+ printf("t = %p, ty = %d\n", t, t->ty);
+ assert(0);
+ }
+
+ void visit(TypeError *)
+ {
+ buf->writestring("_error_");
+ }
+
+ void visit(TypeBasic *t)
+ {
+ //printf("TypeBasic::toCBuffer2(t->mod = %d)\n", t->mod);
+ buf->writestring(t->dstring);
+ }
+
+ void visit(TypeVector *t)
+ {
+ //printf("TypeVector::toCBuffer2(t->mod = %d)\n", t->mod);
+ buf->writestring("__vector(");
+ visitWithMask(t->basetype, t->mod);
+ buf->writestring(")");
+ }
+
+ void visit(TypeSArray *t)
+ {
+ visitWithMask(t->next, t->mod);
+ buf->writeByte('[');
+ sizeToBuffer(t->dim);
+ buf->writeByte(']');
+ }
+
+ void visit(TypeDArray *t)
+ {
+ Type *ut = t->castMod(0);
+ if (declstring)
+ goto L1;
+ if (ut->equals(Type::tstring))
+ buf->writestring("string");
+ else if (ut->equals(Type::twstring))
+ buf->writestring("wstring");
+ else if (ut->equals(Type::tdstring))
+ buf->writestring("dstring");
+ else
+ {
+ L1:
+ visitWithMask(t->next, t->mod);
+ buf->writestring("[]");
+ }
+ }
+
+ void visit(TypeAArray *t)
+ {
+ visitWithMask(t->next, t->mod);
+ buf->writeByte('[');
+ visitWithMask(t->index, 0);
+ buf->writeByte(']');
+ }
+
+ void visit(TypePointer *t)
+ {
+ //printf("TypePointer::toCBuffer2() next = %d\n", t->next->ty);
+ if (t->next->ty == Tfunction)
+ visitFuncIdentWithPostfix((TypeFunction *)t->next, "function");
+ else
+ {
+ visitWithMask(t->next, t->mod);
+ buf->writeByte('*');
+ }
+ }
+
+ void visit(TypeReference *t)
+ {
+ visitWithMask(t->next, t->mod);
+ buf->writeByte('&');
+ }
+
+ void visit(TypeFunction *t)
+ {
+ //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t->isref);
+ visitFuncIdentWithPostfix(t, NULL);
+ }
+
+ // callback for TypeFunction::attributesApply
+ struct PrePostAppendStrings
+ {
+ OutBuffer *buf;
+ bool isPostfixStyle;
+ bool isCtor;
+
+ static int fp(void *param, const char *str)
+ {
+ PrePostAppendStrings *p = (PrePostAppendStrings *)param;
+
+ // don't write 'ref' for ctors
+ if (p->isCtor && strcmp(str, "ref") == 0)
+ return 0;
+
+ if ( p->isPostfixStyle) p->buf->writeByte(' ');
+ p->buf->writestring(str);
+ if (!p->isPostfixStyle) p->buf->writeByte(' ');
+ return 0;
+ }
+ };
+
+ void visitFuncIdentWithPostfix(TypeFunction *t, const char *ident)
+ {
+ if (t->inuse)
+ {
+ t->inuse = 2; // flag error to caller
+ return;
+ }
+ t->inuse++;
+
+ PrePostAppendStrings pas;
+ pas.buf = buf;
+ pas.isCtor = false;
+ pas.isPostfixStyle = true;
+
+ if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen)
+ {
+ linkageToBuffer(buf, t->linkage);
+ buf->writeByte(' ');
+ }
+
+ if (t->next)
+ {
+ typeToBuffer(t->next, NULL);
+ if (ident)
+ buf->writeByte(' ');
+ }
+ else if (hgs->ddoc)
+ buf->writestring("auto ");
+
+ if (ident)
+ buf->writestring(ident);
+
+ parametersToBuffer(t->parameters, t->varargs);
+
+ /* Use postfix style for attributes
+ */
+ if (t->mod)
+ {
+ buf->writeByte(' ');
+ MODtoBuffer(buf, t->mod);
+ }
+ t->attributesApply(&pas, &PrePostAppendStrings::fp);
+
+ t->inuse--;
+ }
+ void visitFuncIdentWithPrefix(TypeFunction *t, Identifier *ident, TemplateDeclaration *td)
+ {
+ if (t->inuse)
+ {
+ t->inuse = 2; // flag error to caller
+ return;
+ }
+ t->inuse++;
+
+ PrePostAppendStrings pas;
+ pas.buf = buf;
+ pas.isCtor = (ident == Id::ctor);
+ pas.isPostfixStyle = false;
+
+ /* Use 'storage class' (prefix) style for attributes
+ */
+ if (t->mod)
+ {
+ MODtoBuffer(buf, t->mod);
+ buf->writeByte(' ');
+ }
+ t->attributesApply(&pas, &PrePostAppendStrings::fp);
+
+ if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen)
+ {
+ linkageToBuffer(buf, t->linkage);
+ buf->writeByte(' ');
+ }
+
+ if (ident && ident->toHChars2() != ident->toChars())
+ {
+ // Don't print return type for ctor, dtor, unittest, etc
+ }
+ else if (t->next)
+ {
+ typeToBuffer(t->next, NULL);
+ if (ident)
+ buf->writeByte(' ');
+ }
+ else if (hgs->ddoc)
+ buf->writestring("auto ");
+
+ if (ident)
+ buf->writestring(ident->toHChars2());
+
+ if (td)
+ {
+ buf->writeByte('(');
+ for (size_t i = 0; i < td->origParameters->dim; i++)
+ {
+ TemplateParameter *p = (*td->origParameters)[i];
+ if (i)
+ buf->writestring(", ");
+ p->accept(this);
+ }
+ buf->writeByte(')');
+ }
+ parametersToBuffer(t->parameters, t->varargs);
+
+ t->inuse--;
+ }
+
+ void visit(TypeDelegate *t)
+ {
+ visitFuncIdentWithPostfix((TypeFunction *)t->next, "delegate");
+ }
+
+ void visitTypeQualifiedHelper(TypeQualified *t)
+ {
+ for (size_t i = 0; i < t->idents.dim; i++)
+ {
+ RootObject *id = t->idents[i];
+
+ if (id->dyncast() == DYNCAST_DSYMBOL)
+ {
+ buf->writeByte('.');
+ TemplateInstance *ti = (TemplateInstance *)id;
+ ti->accept(this);
+ }
+ else if (id->dyncast() == DYNCAST_EXPRESSION)
+ {
+ buf->writeByte('[');
+ ((Expression *)id)->accept(this);
+ buf->writeByte(']');
+ }
+ else if (id->dyncast() == DYNCAST_TYPE)
+ {
+ buf->writeByte('[');
+ ((Type *)id)->accept(this);
+ buf->writeByte(']');
+ }
+ else
+ {
+ buf->writeByte('.');
+ buf->writestring(id->toChars());
+ }
+ }
+ }
+
+ void visit(TypeIdentifier *t)
+ {
+ buf->writestring(t->ident->toChars());
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visit(TypeInstance *t)
+ {
+ t->tempinst->accept(this);
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visit(TypeTypeof *t)
+ {
+ buf->writestring("typeof(");
+ t->exp->accept(this);
+ buf->writeByte(')');
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visit(TypeReturn *t)
+ {
+ buf->writestring("typeof(return)");
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visit(TypeEnum *t)
+ {
+ buf->writestring(t->sym->toChars());
+ }
+
+ void visit(TypeStruct *t)
+ {
+ // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
+ // while printing messages.
+ TemplateInstance *ti = t->sym->parent ? t->sym->parent->isTemplateInstance() : NULL;
+ if (ti && ti->aliasdecl == t->sym)
+ buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars());
+ else
+ buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars());
+ }
+
+ void visit(TypeClass *t)
+ {
+ // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
+ // while printing messages.
+ TemplateInstance *ti = t->sym->parent->isTemplateInstance();
+ if (ti && ti->aliasdecl == t->sym)
+ buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars());
+ else
+ buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars());
+ }
+
+ void visit(TypeTuple *t)
+ {
+ parametersToBuffer(t->arguments, 0);
+ }
+
+ void visit(TypeSlice *t)
+ {
+ visitWithMask(t->next, t->mod);
+
+ buf->writeByte('[');
+ sizeToBuffer(t->lwr);
+ buf->writestring(" .. ");
+ sizeToBuffer(t->upr);
+ buf->writeByte(']');
+ }
+
+ void visit(TypeNull *)
+ {
+ buf->writestring("typeof(null)");
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void visit(Dsymbol *s)
+ {
+ buf->writestring(s->toChars());
+ }
+
+ void visit(StaticAssert *s)
+ {
+ buf->writestring(s->kind());
+ buf->writeByte('(');
+ s->exp->accept(this);
+ if (s->msg)
+ {
+ buf->writestring(", ");
+ s->msg->accept(this);
+ }
+ buf->writestring(");");
+ buf->writenl();
+ }
+
+ void visit(DebugSymbol *s)
+ {
+ buf->writestring("debug = ");
+ if (s->ident)
+ buf->writestring(s->ident->toChars());
+ else
+ buf->printf("%u", s->level);
+ buf->writestring(";");
+ buf->writenl();
+ }
+
+ void visit(VersionSymbol *s)
+ {
+ buf->writestring("version = ");
+ if (s->ident)
+ buf->writestring(s->ident->toChars());
+ else
+ buf->printf("%u", s->level);
+ buf->writestring(";");
+ buf->writenl();
+ }
+
+ void visit(EnumMember *em)
+ {
+ if (em->type)
+ typeToBuffer(em->type, em->ident);
+ else
+ buf->writestring(em->ident->toChars());
+ if (em->value())
+ {
+ buf->writestring(" = ");
+ em->value()->accept(this);
+ }
+ }
+
+ void visit(Import *imp)
+ {
+ if (hgs->hdrgen && imp->id == Id::object)
+ return; // object is imported by default
+
+ if (imp->isstatic)
+ buf->writestring("static ");
+ buf->writestring("import ");
+ if (imp->aliasId)
+ {
+ buf->printf("%s = ", imp->aliasId->toChars());
+ }
+ if (imp->packages && imp->packages->dim)
+ {
+ for (size_t i = 0; i < imp->packages->dim; i++)
+ {
+ Identifier *pid = (*imp->packages)[i];
+ buf->printf("%s.", pid->toChars());
+ }
+ }
+ buf->printf("%s", imp->id->toChars());
+ if (imp->names.dim)
+ {
+ buf->writestring(" : ");
+ for (size_t i = 0; i < imp->names.dim; i++)
+ {
+ if (i)
+ buf->writestring(", ");
+
+ Identifier *name = imp->names[i];
+ Identifier *alias = imp->aliases[i];
+ if (alias)
+ buf->printf("%s = %s", alias->toChars(), name->toChars());
+ else
+ buf->printf("%s", name->toChars());
+ }
+ }
+ buf->printf(";");
+ buf->writenl();
+ }
+
+ void visit(AliasThis *d)
+ {
+ buf->writestring("alias ");
+ buf->writestring(d->ident->toChars());
+ buf->writestring(" this;\n");
+ }
+
+ void visit(AttribDeclaration *d)
+ {
+ if (!d->decl)
+ {
+ buf->writeByte(';');
+ buf->writenl();
+ return;
+ }
+
+ if (d->decl->dim == 0)
+ buf->writestring("{}");
+ else if (hgs->hdrgen && d->decl->dim == 1 && (*d->decl)[0]->isUnitTestDeclaration())
+ {
+ // hack for bugzilla 8081
+ buf->writestring("{}");
+ }
+ else if (d->decl->dim == 1)
+ {
+ ((*d->decl)[0])->accept(this);
+ return;
+ }
+ else
+ {
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < d->decl->dim; i++)
+ {
+ Dsymbol *de = (*d->decl)[i];
+ de->accept(this);
+ }
+ buf->level--;
+ buf->writeByte('}');
+ }
+ buf->writenl();
+ }
+
+ void visit(StorageClassDeclaration *d)
+ {
+ if (stcToBuffer(buf, d->stc))
+ buf->writeByte(' ');
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(DeprecatedDeclaration *d)
+ {
+ buf->writestring("deprecated(");
+ d->msg->accept(this);
+ buf->writestring(") ");
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(LinkDeclaration *d)
+ {
+ const char *p;
+
+ switch (d->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;
+ case LINKobjc: p = "Objective-C"; break;
+ default:
+ assert(0);
+ break;
+ }
+ buf->writestring("extern (");
+ buf->writestring(p);
+ buf->writestring(") ");
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(CPPMangleDeclaration *d)
+ {
+ const char *p;
+
+ switch (d->cppmangle)
+ {
+ case CPPMANGLEclass: p = "class"; break;
+ case CPPMANGLEstruct: p = "struct"; break;
+ default:
+ assert(0);
+ break;
+ }
+ buf->writestring("extern (C++, ");
+ buf->writestring(p);
+ buf->writestring(") ");
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(ProtDeclaration *d)
+ {
+ protectionToBuffer(buf, d->protection);
+ buf->writeByte(' ');
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(AlignDeclaration *d)
+ {
+ if (!d->ealign)
+ buf->printf("align ");
+ else
+ buf->printf("align (%s)", d->ealign->toChars());
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(AnonDeclaration *d)
+ {
+ buf->printf(d->isunion ? "union" : "struct");
+ buf->writenl();
+ buf->writestring("{");
+ buf->writenl();
+ buf->level++;
+ if (d->decl)
+ {
+ for (size_t i = 0; i < d->decl->dim; i++)
+ {
+ Dsymbol *de = (*d->decl)[i];
+ de->accept(this);
+ }
+ }
+ buf->level--;
+ buf->writestring("}");
+ buf->writenl();
+ }
+
+ void visit(PragmaDeclaration *d)
+ {
+ buf->printf("pragma (%s", d->ident->toChars());
+ if (d->args && d->args->dim)
+ {
+ buf->writestring(", ");
+ argsToBuffer(d->args);
+ }
+ buf->writeByte(')');
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(ConditionalDeclaration *d)
+ {
+ d->condition->accept(this);
+ if (d->decl || d->elsedecl)
+ {
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ if (d->decl)
+ {
+ for (size_t i = 0; i < d->decl->dim; i++)
+ {
+ Dsymbol *de = (*d->decl)[i];
+ de->accept(this);
+ }
+ }
+ buf->level--;
+ buf->writeByte('}');
+ if (d->elsedecl)
+ {
+ buf->writenl();
+ buf->writestring("else");
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < d->elsedecl->dim; i++)
+ {
+ Dsymbol *de = (*d->elsedecl)[i];
+ de->accept(this);
+ }
+ buf->level--;
+ buf->writeByte('}');
+ }
+ }
+ else
+ buf->writeByte(':');
+ buf->writenl();
+ }
+
+ void visit(CompileDeclaration *d)
+ {
+ buf->writestring("mixin(");
+ d->exp->accept(this);
+ buf->writestring(");");
+ buf->writenl();
+ }
+
+ void visit(UserAttributeDeclaration *d)
+ {
+ buf->writestring("@(");
+ argsToBuffer(d->atts);
+ buf->writeByte(')');
+ visit((AttribDeclaration *)d);
+ }
+
+ void visit(TemplateDeclaration *d)
+ {
+ if ((hgs->hdrgen || hgs->fullDump) && visitEponymousMember(d))
+ return;
+
+ if (hgs->ddoc)
+ buf->writestring(d->kind());
+ else
+ buf->writestring("template");
+ buf->writeByte(' ');
+ buf->writestring(d->ident->toChars());
+ buf->writeByte('(');
+ visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
+ buf->writeByte(')');
+ visitTemplateConstraint(d->constraint);
+
+ if (hgs->hdrgen || hgs->fullDump)
+ {
+ hgs->tpltMember++;
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ hgs->tpltMember--;
+ }
+ }
+
+ bool visitEponymousMember(TemplateDeclaration *d)
+ {
+ if (!d->members || d->members->dim != 1)
+ return false;
+
+ Dsymbol *onemember = (*d->members)[0];
+ if (onemember->ident != d->ident)
+ return false;
+
+ if (FuncDeclaration *fd = onemember->isFuncDeclaration())
+ {
+ assert(fd->type);
+ if (stcToBuffer(buf, fd->storage_class))
+ buf->writeByte(' ');
+ functionToBufferFull((TypeFunction *)fd->type, buf, d->ident, hgs, d);
+ visitTemplateConstraint(d->constraint);
+
+ hgs->tpltMember++;
+ bodyToBuffer(fd);
+ hgs->tpltMember--;
+ return true;
+ }
+ if (AggregateDeclaration *ad = onemember->isAggregateDeclaration())
+ {
+ buf->writestring(ad->kind());
+ buf->writeByte(' ');
+ buf->writestring(ad->ident->toChars());
+ buf->writeByte('(');
+ visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
+ buf->writeByte(')');
+ visitTemplateConstraint(d->constraint);
+ visitBaseClasses(ad->isClassDeclaration());
+
+ hgs->tpltMember++;
+ if (ad->members)
+ {
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < ad->members->dim; i++)
+ {
+ Dsymbol *s = (*ad->members)[i];
+ s->accept(this);
+ }
+ buf->level--;
+ buf->writeByte('}');
+ }
+ else
+ buf->writeByte(';');
+ buf->writenl();
+ hgs->tpltMember--;
+ return true;
+ }
+ if (VarDeclaration *vd = onemember->isVarDeclaration())
+ {
+ if (d->constraint)
+ return false;
+
+ if (stcToBuffer(buf, vd->storage_class))
+ buf->writeByte(' ');
+ if (vd->type)
+ typeToBuffer(vd->type, vd->ident);
+ else
+ buf->writestring(vd->ident->toChars());
+
+ buf->writeByte('(');
+ visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
+ buf->writeByte(')');
+
+ if (vd->_init)
+ {
+ buf->writestring(" = ");
+ ExpInitializer *ie = vd->_init->isExpInitializer();
+ if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit))
+ ((AssignExp *)ie->exp)->e2->accept(this);
+ else
+ vd->_init->accept(this);
+ }
+ buf->writeByte(';');
+ buf->writenl();
+ return true;
+ }
+
+ return false;
+ }
+ void visitTemplateParameters(TemplateParameters *parameters)
+ {
+ if (!parameters || !parameters->dim)
+ return;
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ TemplateParameter *p = (*parameters)[i];
+ if (i)
+ buf->writestring(", ");
+ p->accept(this);
+ }
+ }
+ void visitTemplateConstraint(Expression *constraint)
+ {
+ if (!constraint)
+ return;
+ buf->writestring(" if (");
+ constraint->accept(this);
+ buf->writeByte(')');
+ }
+
+ void visit(TemplateInstance *ti)
+ {
+ buf->writestring(ti->name->toChars());
+ tiargsToBuffer(ti);
+
+ if (hgs->fullDump)
+ {
+ buf->writenl();
+ if (ti->aliasdecl)
+ {
+ // the ti.aliasDecl is the instantiated body
+ // if we have it, print it.
+ ti->aliasdecl->accept(this);
+ }
+ }
+ }
+
+ void visit(TemplateMixin *tm)
+ {
+ buf->writestring("mixin ");
+
+ typeToBuffer(tm->tqual, NULL);
+ tiargsToBuffer(tm);
+
+ if (tm->ident && memcmp(tm->ident->toChars(), "__mixin", 7) != 0)
+ {
+ buf->writeByte(' ');
+ buf->writestring(tm->ident->toChars());
+ }
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void tiargsToBuffer(TemplateInstance *ti)
+ {
+ buf->writeByte('!');
+ if (ti->nest)
+ {
+ buf->writestring("(...)");
+ return;
+ }
+ if (!ti->tiargs)
+ {
+ buf->writestring("()");
+ return;
+ }
+
+ if (ti->tiargs->dim == 1)
+ {
+ RootObject *oarg = (*ti->tiargs)[0];
+ if (Type *t = isType(oarg))
+ {
+ if (t->equals(Type::tstring) ||
+ t->equals(Type::twstring) ||
+ t->equals(Type::tdstring) ||
+ (t->mod == 0 &&
+ (t->isTypeBasic() ||
+ (t->ty == Tident && ((TypeIdentifier *)t)->idents.dim == 0))))
+ {
+ buf->writestring(t->toChars());
+ return;
+ }
+ }
+ else if (Expression *e = isExpression(oarg))
+ {
+ if (e->op == TOKint64 ||
+ e->op == TOKfloat64 ||
+ e->op == TOKnull ||
+ e->op == TOKstring ||
+ e->op == TOKthis)
+ {
+ buf->writestring(e->toChars());
+ return;
+ }
+ }
+ }
+ buf->writeByte('(');
+ ti->nest++;
+ for (size_t i = 0; i < ti->tiargs->dim; i++)
+ {
+ RootObject *arg = (*ti->tiargs)[i];
+ if (i)
+ buf->writestring(", ");
+ objectToBuffer(arg);
+ }
+ ti->nest--;
+ buf->writeByte(')');
+ }
+
+ /****************************************
+ * This makes a 'pretty' version of the template arguments.
+ * It's analogous to genIdent() which makes a mangled version.
+ */
+ void objectToBuffer(RootObject *oarg)
+ {
+ //printf("objectToBuffer()\n");
+
+ /* The logic of this should match what genIdent() does. The _dynamic_cast()
+ * function relies on all the pretty strings to be unique for different classes
+ * (see Bugzilla 7375).
+ * Perhaps it would be better to demangle what genIdent() does.
+ */
+ if (Type *t = isType(oarg))
+ {
+ //printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
+ typeToBuffer(t, NULL);
+ }
+ else if (Expression *e = isExpression(oarg))
+ {
+ if (e->op == TOKvar)
+ e = e->optimize(WANTvalue); // added to fix Bugzilla 7375
+ e->accept(this);
+ }
+ else if (Dsymbol *s = isDsymbol(oarg))
+ {
+ const char *p = s->ident ? s->ident->toChars() : s->toChars();
+ buf->writestring(p);
+ }
+ else if (Tuple *v = isTuple(oarg))
+ {
+ Objects *args = &v->objects;
+ for (size_t i = 0; i < args->dim; i++)
+ {
+ RootObject *arg = (*args)[i];
+ if (i)
+ buf->writestring(", ");
+ objectToBuffer(arg);
+ }
+ }
+ else if (!oarg)
+ {
+ buf->writestring("NULL");
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ void visit(EnumDeclaration *d)
+ {
+ EnumDeclaration *oldInEnumDecl = inEnumDecl;
+ inEnumDecl = d;
+ buf->writestring("enum ");
+ if (d->ident)
+ {
+ buf->writestring(d->ident->toChars());
+ buf->writeByte(' ');
+ }
+ if (d->memtype)
+ {
+ buf->writestring(": ");
+ typeToBuffer(d->memtype, NULL);
+ }
+ if (!d->members)
+ {
+ buf->writeByte(';');
+ buf->writenl();
+ inEnumDecl = oldInEnumDecl;
+ return;
+ }
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ EnumMember *em = (*d->members)[i]->isEnumMember();
+ if (!em)
+ continue;
+ em->accept(this);
+ buf->writeByte(',');
+ buf->writenl();
+ }
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ inEnumDecl = oldInEnumDecl;
+ }
+
+ void visit(Nspace *d)
+ {
+ buf->writestring("extern (C++, ");
+ buf->writestring(d->ident->toChars());
+ buf->writeByte(')');
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(StructDeclaration *d)
+ {
+ buf->printf("%s ", d->kind());
+ if (!d->isAnonymous())
+ buf->writestring(d->toChars());
+ if (!d->members)
+ {
+ buf->writeByte(';');
+ buf->writenl();
+ return;
+ }
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+ }
+
+ void visit(ClassDeclaration *d)
+ {
+ if (!d->isAnonymous())
+ {
+ buf->writestring(d->kind());
+ buf->writeByte(' ');
+ buf->writestring(d->ident->toChars());
+ }
+ visitBaseClasses(d);
+ if (d->members)
+ {
+ buf->writenl();
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ buf->level--;
+ buf->writeByte('}');
+ }
+ else
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visitBaseClasses(ClassDeclaration *d)
+ {
+ if (!d || !d->baseclasses->dim)
+ return;
+
+ buf->writestring(" : ");
+ for (size_t i = 0; i < d->baseclasses->dim; i++)
+ {
+ if (i)
+ buf->writestring(", ");
+ BaseClass *b = (*d->baseclasses)[i];
+ typeToBuffer(b->type, NULL);
+ }
+ }
+
+ void visit(AliasDeclaration *d)
+ {
+ buf->writestring("alias ");
+ if (d->aliassym)
+ {
+ buf->writestring(d->ident->toChars());
+ buf->writestring(" = ");
+ if (stcToBuffer(buf, d->storage_class))
+ buf->writeByte(' ');
+ d->aliassym->accept(this);
+ }
+ else if (d->type->ty == Tfunction)
+ {
+ if (stcToBuffer(buf, d->storage_class))
+ buf->writeByte(' ');
+ typeToBuffer(d->type, d->ident);
+ }
+ else
+ {
+ declstring = (d->ident == Id::string || d->ident == Id::wstring || d->ident == Id::dstring);
+ buf->writestring(d->ident->toChars());
+ buf->writestring(" = ");
+ if (stcToBuffer(buf, d->storage_class))
+ buf->writeByte(' ');
+ typeToBuffer(d->type, NULL);
+ declstring = false;
+ }
+ buf->writeByte(';');
+ buf->writenl();
+ }
+
+ void visit(VarDeclaration *d)
+ {
+ visitVarDecl(d, false);
+ buf->writeByte(';');
+ buf->writenl();
+ }
+ void visitVarDecl(VarDeclaration *v, bool anywritten)
+ {
+ if (anywritten)
+ {
+ buf->writestring(", ");
+ buf->writestring(v->ident->toChars());
+ }
+ else
+ {
+ if (stcToBuffer(buf, v->storage_class))
+ buf->writeByte(' ');
+ if (v->type)
+ typeToBuffer(v->type, v->ident);
+ else
+ buf->writestring(v->ident->toChars());
+ }
+ if (v->_init)
+ {
+ buf->writestring(" = ");
+ ExpInitializer *ie = v->_init->isExpInitializer();
+ if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit))
+ ((AssignExp *)ie->exp)->e2->accept(this);
+ else
+ v->_init->accept(this);
+ }
+ }
+
+ void visit(FuncDeclaration *f)
+ {
+ //printf("FuncDeclaration::toCBuffer() '%s'\n", f->toChars());
+
+ if (stcToBuffer(buf, f->storage_class))
+ buf->writeByte(' ');
+ TypeFunction *tf = (TypeFunction *)f->type;
+ typeToBuffer(tf, f->ident);
+ if (hgs->hdrgen)
+ {
+ // if the return type is missing (e.g. ref functions or auto)
+ if (!tf->next || f->storage_class & STCauto)
+ {
+ hgs->autoMember++;
+ bodyToBuffer(f);
+ hgs->autoMember--;
+ }
+ else if (hgs->tpltMember == 0 && global.params.hdrStripPlainFunctions)
+ {
+ buf->writeByte(';');
+ buf->writenl();
+ }
+ else
+ bodyToBuffer(f);
+ }
+ else
+ bodyToBuffer(f);
+ }
+
+ void bodyToBuffer(FuncDeclaration *f)
+ {
+ if (!f->fbody || (hgs->hdrgen && global.params.hdrStripPlainFunctions && !hgs->autoMember && !hgs->tpltMember))
+ {
+ buf->writeByte(';');
+ buf->writenl();
+ return;
+ }
+
+ int savetlpt = hgs->tpltMember;
+ int saveauto = hgs->autoMember;
+ hgs->tpltMember = 0;
+ hgs->autoMember = 0;
+
+ buf->writenl();
+
+ // in{}
+ if (f->frequire)
+ {
+ buf->writestring("in");
+ buf->writenl();
+ f->frequire->accept(this);
+ }
+
+ // out{}
+ if (f->fensure)
+ {
+ buf->writestring("out");
+ if (f->outId)
+ {
+ buf->writeByte('(');
+ buf->writestring(f->outId->toChars());
+ buf->writeByte(')');
+ }
+ buf->writenl();
+ f->fensure->accept(this);
+ }
+
+ if (f->frequire || f->fensure)
+ {
+ buf->writestring("body");
+ buf->writenl();
+ }
+
+ buf->writeByte('{');
+ buf->writenl();
+ buf->level++;
+ f->fbody->accept(this);
+ buf->level--;
+ buf->writeByte('}');
+ buf->writenl();
+
+ hgs->tpltMember = savetlpt;
+ hgs->autoMember = saveauto;
+ }
+
+ void visit(FuncLiteralDeclaration *f)
+ {
+ if (f->type->ty == Terror)
+ {
+ buf->writestring("__error");
+ return;
+ }
+
+ if (f->tok != TOKreserved)
+ {
+ buf->writestring(f->kind());
+ buf->writeByte(' ');
+ }
+
+ TypeFunction *tf = (TypeFunction *)f->type;
+ // Don't print tf->mod, tf->trust, and tf->linkage
+ if (!f->inferRetType && tf->next)
+ typeToBuffer(tf->next, NULL);
+ parametersToBuffer(tf->parameters, tf->varargs);
+
+ CompoundStatement *cs = f->fbody->isCompoundStatement();
+ Statement *s1;
+ if (f->semanticRun >= PASSsemantic3done && cs)
+ {
+ s1 = (*cs->statements)[cs->statements->dim - 1];
+ }
+ else
+ s1 = !cs ? f->fbody : NULL;
+ ReturnStatement *rs = s1 ? s1->isReturnStatement() : NULL;
+ if (rs && rs->exp)
+ {
+ buf->writestring(" => ");
+ rs->exp->accept(this);
+ }
+ else
+ {
+ hgs->tpltMember++;
+ bodyToBuffer(f);
+ hgs->tpltMember--;
+ }
+ }
+
+ void visit(PostBlitDeclaration *d)
+ {
+ if (stcToBuffer(buf, d->storage_class))
+ buf->writeByte(' ');
+ buf->writestring("this(this)");
+ bodyToBuffer(d);
+ }
+
+ void visit(DtorDeclaration *d)
+ {
+ if (d->storage_class & STCtrusted)
+ buf->writestring("@trusted ");
+ if (d->storage_class & STCsafe)
+ buf->writestring("@safe ");
+ if (d->storage_class & STCnogc)
+ buf->writestring("@nogc ");
+ if (d->storage_class & STCdisable)
+ buf->writestring("@disable ");
+
+ buf->writestring("~this()");
+ bodyToBuffer(d);
+ }
+
+ void visit(StaticCtorDeclaration *d)
+ {
+ if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+ buf->writeByte(' ');
+ if (d->isSharedStaticCtorDeclaration())
+ buf->writestring("shared ");
+ buf->writestring("static this()");
+ if (hgs->hdrgen && !hgs->tpltMember)
+ {
+ buf->writeByte(';');
+ buf->writenl();
+ }
+ else
+ bodyToBuffer(d);
+ }
+
+ void visit(StaticDtorDeclaration *d)
+ {
+ if (hgs->hdrgen)
+ return;
+ if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+ buf->writeByte(' ');
+ if (d->isSharedStaticDtorDeclaration())
+ buf->writestring("shared ");
+ buf->writestring("static ~this()");
+ bodyToBuffer(d);
+ }
+
+ void visit(InvariantDeclaration *d)
+ {
+ if (hgs->hdrgen)
+ return;
+ if (stcToBuffer(buf, d->storage_class))
+ buf->writeByte(' ');
+ buf->writestring("invariant");
+ bodyToBuffer(d);
+ }
+
+ void visit(UnitTestDeclaration *d)
+ {
+ if (hgs->hdrgen)
+ return;
+ if (stcToBuffer(buf, d->storage_class))
+ buf->writeByte(' ');
+ buf->writestring("unittest");
+ bodyToBuffer(d);
+ }
+
+ void visit(NewDeclaration *d)
+ {
+ if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+ buf->writeByte(' ');
+ buf->writestring("new");
+ parametersToBuffer(d->parameters, d->varargs);
+ bodyToBuffer(d);
+ }
+
+ void visit(DeleteDeclaration *d)
+ {
+ if (stcToBuffer(buf, d->storage_class & ~STCstatic))
+ buf->writeByte(' ');
+ buf->writestring("delete");
+ parametersToBuffer(d->parameters, 0);
+ bodyToBuffer(d);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void visit(ErrorInitializer *)
+ {
+ buf->writestring("__error__");
+ }
+
+ void visit(VoidInitializer *)
+ {
+ buf->writestring("void");
+ }
+
+ void visit(StructInitializer *si)
+ {
+ //printf("StructInitializer::toCBuffer()\n");
+ buf->writeByte('{');
+ for (size_t i = 0; i < si->field.dim; i++)
+ {
+ if (i)
+ buf->writestring(", ");
+ if (Identifier *id = si->field[i])
+ {
+ buf->writestring(id->toChars());
+ buf->writeByte(':');
+ }
+ if (Initializer *iz = si->value[i])
+ iz->accept(this);
+ }
+ buf->writeByte('}');
+ }
+
+ void visit(ArrayInitializer *ai)
+ {
+ buf->writeByte('[');
+ for (size_t i = 0; i < ai->index.dim; i++)
+ {
+ if (i)
+ buf->writestring(", ");
+ if (Expression *ex = ai->index[i])
+ {
+ ex->accept(this);
+ buf->writeByte(':');
+ }
+ if (Initializer *iz = ai->value[i])
+ iz->accept(this);
+ }
+ buf->writeByte(']');
+ }
+
+ void visit(ExpInitializer *ei)
+ {
+ ei->exp->accept(this);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**************************************************
+ * Write out argument list to buf.
+ */
+ void argsToBuffer(Expressions *expressions, Expression *basis = NULL)
+ {
+ if (!expressions || !expressions->dim)
+ return;
+
+ for (size_t i = 0; i < expressions->dim; i++)
+ {
+ Expression *el = (*expressions)[i];
+ if (i)
+ buf->writestring(", ");
+ if (!el)
+ el = basis;
+ if (el)
+ expToBuffer(el, PREC_assign);
+ }
+ }
+
+ void sizeToBuffer(Expression *e)
+ {
+ if (e->type == Type::tsize_t)
+ {
+ Expression *ex = (e->op == TOKcast ? ((CastExp *)e)->e1 : e);
+ ex = ex->optimize(WANTvalue);
+
+ dinteger_t uval = ex->op == TOKint64 ? ex->toInteger() : (dinteger_t)-1;
+ if ((sinteger_t)uval >= 0)
+ {
+ dinteger_t sizemax;
+ if (Target::ptrsize == 4)
+ sizemax = 0xFFFFFFFFUL;
+ else if (Target::ptrsize == 8)
+ sizemax = 0xFFFFFFFFFFFFFFFFULL;
+ else
+ assert(0);
+ if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFULL)
+ {
+ buf->printf("%llu", uval);
+ return;
+ }
+ }
+ }
+ expToBuffer(e, PREC_assign);
+ }
+
+ /**************************************************
+ * Write expression out to buf, but wrap it
+ * in ( ) if its precedence is less than pr.
+ */
+ void expToBuffer(Expression *e, PREC pr)
+ {
+ assert(precedence[e->op] != PREC_zero);
+ assert(pr != PREC_zero);
+
+ //if (precedence[e->op] == 0) e->print();
+ /* Despite precedence, we don't allow a<b<c expressions.
+ * They must be parenthesized.
+ */
+ if (precedence[e->op] < pr ||
+ (pr == PREC_rel && precedence[e->op] == pr))
+ {
+ buf->writeByte('(');
+ e->accept(this);
+ buf->writeByte(')');
+ }
+ else
+ e->accept(this);
+ }
+
+ void visit(Expression *e)
+ {
+ buf->writestring(Token::toChars(e->op));
+ }
+
+ void visit(IntegerExp *e)
+ {
+ dinteger_t v = e->toInteger();
+
+ if (e->type)
+ {
+ Type *t = e->type;
+ L1:
+ switch (t->ty)
+ {
+ case Tenum:
+ {
+ TypeEnum *te = (TypeEnum *)t;
+ if (hgs->fullDump)
+ {
+ EnumDeclaration *sym = te->sym;
+ if (inEnumDecl != sym)
+ {
+ for (size_t i = 0; i < sym->members->dim; i++)
+ {
+ EnumMember *em = (EnumMember *)(*sym->members)[i];
+ if (em->value()->toInteger() == v)
+ {
+ buf->printf("%s.%s", sym->toChars(), em->ident->toChars());
+ return;
+ }
+ }
+ }
+ }
+ buf->printf("cast(%s)", te->sym->toChars());
+ t = te->sym->memtype;
+ goto L1;
+ }
+
+ case Twchar: // BUG: need to cast(wchar)
+ case Tdchar: // BUG: need to cast(dchar)
+ if ((uinteger_t)v > 0xFF)
+ {
+ buf->printf("'\\U%08x'", v);
+ break;
+ }
+ /* fall through */
+ case Tchar:
+ {
+ size_t o = buf->offset;
+ if (v == '\'')
+ buf->writestring("'\\''");
+ else if (isprint((int)v) && v != '\\')
+ buf->printf("'%c'", (int)v);
+ else
+ buf->printf("'\\x%02x'", (int)v);
+ if (hgs->ddoc)
+ escapeDdocString(buf, o);
+ break;
+ }
+
+ case Tint8:
+ buf->writestring("cast(byte)");
+ goto L2;
+
+ case Tint16:
+ buf->writestring("cast(short)");
+ goto L2;
+
+ case Tint32:
+ L2:
+ buf->printf("%d", (int)v);
+ break;
+
+ case Tuns8:
+ buf->writestring("cast(ubyte)");
+ goto L3;
+
+ case Tuns16:
+ buf->writestring("cast(ushort)");
+ goto L3;
+
+ case Tuns32:
+ L3:
+ buf->printf("%uu", (unsigned)v);
+ break;
+
+ case Tint64:
+ buf->printf("%lldL", v);
+ break;
+
+ case Tuns64:
+ L4:
+ buf->printf("%lluLU", v);
+ break;
+
+ case Tbool:
+ buf->writestring(v ? "true" : "false");
+ break;
+
+ case Tpointer:
+ buf->writestring("cast(");
+ buf->writestring(t->toChars());
+ buf->writeByte(')');
+ if (Target::ptrsize == 4)
+ goto L3;
+ else if (Target::ptrsize == 8)
+ goto L4;
+ else
+ assert(0);
+
+ default:
+ /* This can happen if errors, such as
+ * the type is painted on like in fromConstInitializer().
+ */
+ if (!global.errors)
+ {
+ assert(0);
+ }
+ break;
+ }
+ }
+ else if (v & 0x8000000000000000LL)
+ buf->printf("0x%llx", v);
+ else
+ buf->printf("%lld", v);
+ }
+
+ void visit(ErrorExp *)
+ {
+ buf->writestring("__error");
+ }
+
+ void floatToBuffer(Type *type, real_t value)
+ {
+ /** sizeof(value)*3 is because each byte of mantissa is max
+ of 256 (3 characters). The string will be "-M.MMMMe-4932".
+ (ie, 8 chars more than mantissa). Plus one for trailing \0.
+ Plus one for rounding. */
+ const size_t BUFFER_LEN = sizeof(value) * 3 + 8 + 1 + 1;
+ char buffer[BUFFER_LEN] = {};
+ CTFloat::sprint(buffer, 'g', value);
+ assert(strlen(buffer) < BUFFER_LEN);
+
+ if (hgs->hdrgen)
+ {
+ real_t r = CTFloat::parse(buffer);
+ if (r != value) // if exact duplication
+ CTFloat::sprint(buffer, 'a', value);
+ }
+ buf->writestring(buffer);
+
+ if (type)
+ {
+ Type *t = type->toBasetype();
+ switch (t->ty)
+ {
+ case Tfloat32:
+ case Timaginary32:
+ case Tcomplex32:
+ buf->writeByte('F');
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ case Tcomplex80:
+ buf->writeByte('L');
+ break;
+
+ default:
+ break;
+ }
+ if (t->isimaginary())
+ buf->writeByte('i');
+ }
+ }
+
+ void visit(RealExp *e)
+ {
+ floatToBuffer(e->type, e->value);
+ }
+
+ void visit(ComplexExp *e)
+ {
+ /* Print as:
+ * (re+imi)
+ */
+ buf->writeByte('(');
+ floatToBuffer(e->type, creall(e->value));
+ buf->writeByte('+');
+ floatToBuffer(e->type, cimagl(e->value));
+ buf->writestring("i)");
+ }
+
+ void visit(IdentifierExp *e)
+ {
+ if (hgs->hdrgen || hgs->ddoc)
+ buf->writestring(e->ident->toHChars2());
+ else
+ buf->writestring(e->ident->toChars());
+ }
+
+ void visit(DsymbolExp *e)
+ {
+ buf->writestring(e->s->toChars());
+ }
+
+ void visit(ThisExp *)
+ {
+ buf->writestring("this");
+ }
+
+ void visit(SuperExp *)
+ {
+ buf->writestring("super");
+ }
+
+ void visit(NullExp *)
+ {
+ buf->writestring("null");
+ }
+
+ void visit(StringExp *e)
+ {
+ buf->writeByte('"');
+ size_t o = buf->offset;
+ for (size_t i = 0; i < e->len; i++)
+ {
+ unsigned c = e->charAt(i);
+ switch (c)
+ {
+ case '"':
+ case '\\':
+ buf->writeByte('\\');
+ /* fall through */
+ default:
+ if (c <= 0xFF)
+ {
+ if (c <= 0x7F && isprint(c))
+ buf->writeByte(c);
+ else
+ buf->printf("\\x%02x", c);
+ }
+ else if (c <= 0xFFFF)
+ buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
+ else
+ buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x",
+ c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
+ break;
+ }
+ }
+ if (hgs->ddoc)
+ escapeDdocString(buf, o);
+ buf->writeByte('"');
+ if (e->postfix)
+ buf->writeByte(e->postfix);
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ buf->writeByte('[');
+ argsToBuffer(e->elements, e->basis);
+ buf->writeByte(']');
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ buf->writeByte('[');
+ for (size_t i = 0; i < e->keys->dim; i++)
+ {
+ Expression *key = (*e->keys)[i];
+ Expression *value = (*e->values)[i];
+
+ if (i)
+ buf->writestring(", ");
+ expToBuffer(key, PREC_assign);
+ buf->writeByte(':');
+ expToBuffer(value, PREC_assign);
+ }
+ buf->writeByte(']');
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ buf->writestring(e->sd->toChars());
+ buf->writeByte('(');
+
+ // CTFE can generate struct literals that contain an AddrExp pointing
+ // to themselves, need to avoid infinite recursion:
+ // struct S { this(int){ this.s = &this; } S* s; }
+ // const foo = new S(0);
+ if (e->stageflags & stageToCBuffer)
+ buf->writestring("<recursion>");
+ else
+ {
+ int old = e->stageflags;
+ e->stageflags |= stageToCBuffer;
+ argsToBuffer(e->elements);
+ e->stageflags = old;
+ }
+
+ buf->writeByte(')');
+ }
+
+ void visit(TypeExp *e)
+ {
+ typeToBuffer(e->type, NULL);
+ }
+
+ void visit(ScopeExp *e)
+ {
+ if (e->sds->isTemplateInstance())
+ {
+ e->sds->accept(this);
+ }
+ else if (hgs != NULL && hgs->ddoc)
+ {
+ // fixes bug 6491
+ Module *m = e->sds->isModule();
+ if (m)
+ buf->writestring(m->md->toChars());
+ else
+ buf->writestring(e->sds->toChars());
+ }
+ else
+ {
+ buf->writestring(e->sds->kind());
+ buf->writeByte(' ');
+ buf->writestring(e->sds->toChars());
+ }
+ }
+
+ void visit(TemplateExp *e)
+ {
+ buf->writestring(e->td->toChars());
+ }
+
+ void visit(NewExp *e)
+ {
+ if (e->thisexp)
+ {
+ expToBuffer(e->thisexp, PREC_primary);
+ buf->writeByte('.');
+ }
+ buf->writestring("new ");
+ if (e->newargs && e->newargs->dim)
+ {
+ buf->writeByte('(');
+ argsToBuffer(e->newargs);
+ buf->writeByte(')');
+ }
+ typeToBuffer(e->newtype, NULL);
+ if (e->arguments && e->arguments->dim)
+ {
+ buf->writeByte('(');
+ argsToBuffer(e->arguments);
+ buf->writeByte(')');
+ }
+ }
+
+ void visit(NewAnonClassExp *e)
+ {
+ if (e->thisexp)
+ {
+ expToBuffer(e->thisexp, PREC_primary);
+ buf->writeByte('.');
+ }
+ buf->writestring("new");
+ if (e->newargs && e->newargs->dim)
+ {
+ buf->writeByte('(');
+ argsToBuffer(e->newargs);
+ buf->writeByte(')');
+ }
+ buf->writestring(" class ");
+ if (e->arguments && e->arguments->dim)
+ {
+ buf->writeByte('(');
+ argsToBuffer(e->arguments);
+ buf->writeByte(')');
+ }
+ if (e->cd)
+ e->cd->accept(this);
+ }
+
+ void visit(SymOffExp *e)
+ {
+ if (e->offset)
+ buf->printf("(& %s+%u)", e->var->toChars(), e->offset);
+ else if (e->var->isTypeInfoDeclaration())
+ buf->printf("%s", e->var->toChars());
+ else
+ buf->printf("& %s", e->var->toChars());
+ }
+
+ void visit(VarExp *e)
+ {
+ buf->writestring(e->var->toChars());
+ }
+
+ void visit(OverExp *e)
+ {
+ buf->writestring(e->vars->ident->toChars());
+ }
+
+ void visit(TupleExp *e)
+ {
+ if (e->e0)
+ {
+ buf->writeByte('(');
+ e->e0->accept(this);
+ buf->writestring(", tuple(");
+ argsToBuffer(e->exps);
+ buf->writestring("))");
+ }
+ else
+ {
+ buf->writestring("tuple(");
+ argsToBuffer(e->exps);
+ buf->writeByte(')');
+ }
+ }
+
+ void visit(FuncExp *e)
+ {
+ e->fd->accept(this);
+ //buf->writestring(e->fd->toChars());
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ /* Normal dmd execution won't reach here - regular variable declarations
+ * are handled in visit(ExpStatement), so here would be used only when
+ * we'll directly call Expression::toChars() for debugging.
+ */
+ if (VarDeclaration *v = e->declaration->isVarDeclaration())
+ {
+ // For debugging use:
+ // - Avoid printing newline.
+ // - Intentionally use the format (Type var;)
+ // which isn't correct as regular D code.
+ buf->writeByte('(');
+ visitVarDecl(v, false);
+ buf->writeByte(';');
+ buf->writeByte(')');
+ }
+ else
+ e->declaration->accept(this);
+ }
+
+ void visit(TypeidExp *e)
+ {
+ buf->writestring("typeid(");
+ objectToBuffer(e->obj);
+ buf->writeByte(')');
+ }
+
+ void visit(TraitsExp *e)
+ {
+ buf->writestring("__traits(");
+ buf->writestring(e->ident->toChars());
+ if (e->args)
+ {
+ for (size_t i = 0; i < e->args->dim; i++)
+ {
+ RootObject *arg = (*e->args)[i];
+ buf->writestring(", ");
+ objectToBuffer(arg);
+ }
+ }
+ buf->writeByte(')');
+ }
+
+ void visit(HaltExp *)
+ {
+ buf->writestring("halt");
+ }
+
+ void visit(IsExp *e)
+ {
+ buf->writestring("is(");
+ typeToBuffer(e->targ, e->id);
+ if (e->tok2 != TOKreserved)
+ {
+ buf->printf(" %s %s", Token::toChars(e->tok), Token::toChars(e->tok2));
+ }
+ else if (e->tspec)
+ {
+ if (e->tok == TOKcolon)
+ buf->writestring(" : ");
+ else
+ buf->writestring(" == ");
+ typeToBuffer(e->tspec, NULL);
+ }
+ if (e->parameters && e->parameters->dim)
+ {
+ buf->writestring(", ");
+ visitTemplateParameters(e->parameters);
+ }
+ buf->writeByte(')');
+ }
+
+ void visit(UnaExp *e)
+ {
+ buf->writestring(Token::toChars(e->op));
+ expToBuffer(e->e1, precedence[e->op]);
+ }
+
+ void visit(BinExp *e)
+ {
+ expToBuffer(e->e1, precedence[e->op]);
+ buf->writeByte(' ');
+ buf->writestring(Token::toChars(e->op));
+ buf->writeByte(' ');
+ expToBuffer(e->e2, (PREC)(precedence[e->op] + 1));
+ }
+
+ void visit(CompileExp *e)
+ {
+ buf->writestring("mixin(");
+ expToBuffer(e->e1, PREC_assign);
+ buf->writeByte(')');
+ }
+
+ void visit(ImportExp *e)
+ {
+ buf->writestring("import(");
+ expToBuffer(e->e1, PREC_assign);
+ buf->writeByte(')');
+ }
+
+ void visit(AssertExp *e)
+ {
+ buf->writestring("assert(");
+ expToBuffer(e->e1, PREC_assign);
+ if (e->msg)
+ {
+ buf->writestring(", ");
+ expToBuffer(e->msg, PREC_assign);
+ }
+ buf->writeByte(')');
+ }
+
+ void visit(DotIdExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('.');
+ buf->writestring(e->ident->toChars());
+ }
+
+ void visit(DotTemplateExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('.');
+ buf->writestring(e->td->toChars());
+ }
+
+ void visit(DotVarExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('.');
+ buf->writestring(e->var->toChars());
+ }
+
+ void visit(DotTemplateInstanceExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('.');
+ e->ti->accept(this);
+ }
+
+ void visit(DelegateExp *e)
+ {
+ buf->writeByte('&');
+ if (!e->func->isNested())
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('.');
+ }
+ buf->writestring(e->func->toChars());
+ }
+
+ void visit(DotTypeExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('.');
+ buf->writestring(e->sym->toChars());
+ }
+
+ void visit(CallExp *e)
+ {
+ if (e->e1->op == TOKtype)
+ {
+ /* Avoid parens around type to prevent forbidden cast syntax:
+ * (sometype)(arg1)
+ * This is ok since types in constructor calls
+ * can never depend on parens anyway
+ */
+ e->e1->accept(this);
+ }
+ else
+ expToBuffer(e->e1, precedence[e->op]);
+ buf->writeByte('(');
+ argsToBuffer(e->arguments);
+ buf->writeByte(')');
+ }
+
+ void visit(PtrExp *e)
+ {
+ buf->writeByte('*');
+ expToBuffer(e->e1, precedence[e->op]);
+ }
+
+ void visit(DeleteExp *e)
+ {
+ buf->writestring("delete ");
+ expToBuffer(e->e1, precedence[e->op]);
+ }
+
+ void visit(CastExp *e)
+ {
+ buf->writestring("cast(");
+ if (e->to)
+ typeToBuffer(e->to, NULL);
+ else
+ {
+ MODtoBuffer(buf, e->mod);
+ }
+ buf->writeByte(')');
+ expToBuffer(e->e1, precedence[e->op]);
+ }
+
+ void visit(VectorExp *e)
+ {
+ buf->writestring("cast(");
+ typeToBuffer(e->to, NULL);
+ buf->writeByte(')');
+ expToBuffer(e->e1, precedence[e->op]);
+ }
+
+ void visit(SliceExp *e)
+ {
+ expToBuffer(e->e1, precedence[e->op]);
+ buf->writeByte('[');
+ if (e->upr || e->lwr)
+ {
+ if (e->lwr)
+ sizeToBuffer(e->lwr);
+ else
+ buf->writeByte('0');
+ buf->writestring("..");
+ if (e->upr)
+ sizeToBuffer(e->upr);
+ else
+ buf->writeByte('$');
+ }
+ buf->writeByte(']');
+ }
+
+ void visit(ArrayLengthExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writestring(".length");
+ }
+
+ void visit(IntervalExp *e)
+ {
+ expToBuffer(e->lwr, PREC_assign);
+ buf->writestring("..");
+ expToBuffer(e->upr, PREC_assign);
+ }
+
+ void visit(DelegatePtrExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writestring(".ptr");
+ }
+
+ void visit(DelegateFuncptrExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writestring(".funcptr");
+ }
+
+ void visit(ArrayExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('[');
+ argsToBuffer(e->arguments);
+ buf->writeByte(']');
+ }
+
+ void visit(DotExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('.');
+ expToBuffer(e->e2, PREC_primary);
+ }
+
+ void visit(IndexExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writeByte('[');
+ sizeToBuffer(e->e2);
+ buf->writeByte(']');
+ }
+
+ void visit(PostExp *e)
+ {
+ expToBuffer(e->e1, precedence[e->op]);
+ buf->writestring(Token::toChars(e->op));
+ }
+
+ void visit(PreExp *e)
+ {
+ buf->writestring(Token::toChars(e->op));
+ expToBuffer(e->e1, precedence[e->op]);
+ }
+
+ void visit(RemoveExp *e)
+ {
+ expToBuffer(e->e1, PREC_primary);
+ buf->writestring(".remove(");
+ expToBuffer(e->e2, PREC_assign);
+ buf->writeByte(')');
+ }
+
+ void visit(CondExp *e)
+ {
+ expToBuffer(e->econd, PREC_oror);
+ buf->writestring(" ? ");
+ expToBuffer(e->e1, PREC_expr);
+ buf->writestring(" : ");
+ expToBuffer(e->e2, PREC_cond);
+ }
+
+ void visit(DefaultInitExp *e)
+ {
+ buf->writestring(Token::toChars(e->subop));
+ }
+
+ void visit(ClassReferenceExp *e)
+ {
+ buf->writestring(e->value->toChars());
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void visit(TemplateTypeParameter *tp)
+ {
+ buf->writestring(tp->ident->toChars());
+ if (tp->specType)
+ {
+ buf->writestring(" : ");
+ typeToBuffer(tp->specType, NULL);
+ }
+ if (tp->defaultType)
+ {
+ buf->writestring(" = ");
+ typeToBuffer(tp->defaultType, NULL);
+ }
+ }
+
+ void visit(TemplateThisParameter *tp)
+ {
+ buf->writestring("this ");
+ visit((TemplateTypeParameter *)tp);
+ }
+
+ void visit(TemplateAliasParameter *tp)
+ {
+ buf->writestring("alias ");
+ if (tp->specType)
+ typeToBuffer(tp->specType, tp->ident);
+ else
+ buf->writestring(tp->ident->toChars());
+ if (tp->specAlias)
+ {
+ buf->writestring(" : ");
+ objectToBuffer(tp->specAlias);
+ }
+ if (tp->defaultAlias)
+ {
+ buf->writestring(" = ");
+ objectToBuffer(tp->defaultAlias);
+ }
+ }
+
+ void visit(TemplateValueParameter *tp)
+ {
+ typeToBuffer(tp->valType, tp->ident);
+ if (tp->specValue)
+ {
+ buf->writestring(" : ");
+ tp->specValue->accept(this);
+ }
+ if (tp->defaultValue)
+ {
+ buf->writestring(" = ");
+ tp->defaultValue->accept(this);
+ }
+ }
+
+ void visit(TemplateTupleParameter *tp)
+ {
+ buf->writestring(tp->ident->toChars());
+ buf->writestring("...");
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void visit(DebugCondition *c)
+ {
+ if (c->ident)
+ buf->printf("debug (%s)", c->ident->toChars());
+ else
+ buf->printf("debug (%u)", c->level);
+ }
+
+ void visit(VersionCondition *c)
+ {
+ if (c->ident)
+ buf->printf("version (%s)", c->ident->toChars());
+ else
+ buf->printf("version (%u)", c->level);
+ }
+
+ void visit(StaticIfCondition *c)
+ {
+ buf->writestring("static if (");
+ c->exp->accept(this);
+ buf->writeByte(')');
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ void visit(Parameter *p)
+ {
+ if (p->storageClass & STCauto)
+ buf->writestring("auto ");
+
+ if (p->storageClass & STCreturn)
+ buf->writestring("return ");
+
+ if (p->storageClass & STCout)
+ buf->writestring("out ");
+ else if (p->storageClass & STCref)
+ buf->writestring("ref ");
+ else if (p->storageClass & STCin)
+ buf->writestring("in ");
+ else if (p->storageClass & STClazy)
+ buf->writestring("lazy ");
+ else if (p->storageClass & STCalias)
+ buf->writestring("alias ");
+
+ StorageClass stc = p->storageClass;
+ if (p->type && p->type->mod & MODshared)
+ stc &= ~STCshared;
+
+ if (stcToBuffer(buf, stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope | STCscopeinferred)))
+ buf->writeByte(' ');
+
+ if (p->storageClass & STCalias)
+ {
+ if (p->ident)
+ buf->writestring(p->ident->toChars());
+ }
+ else if (p->type->ty == Tident &&
+ strlen(((TypeIdentifier *)p->type)->ident->toChars()) > 3 &&
+ strncmp(((TypeIdentifier *)p->type)->ident->toChars(), "__T", 3) == 0)
+ {
+ // print parameter name, instead of undetermined type parameter
+ buf->writestring(p->ident->toChars());
+ }
+ else
+ typeToBuffer(p->type, p->ident);
+ if (p->defaultArg)
+ {
+ buf->writestring(" = ");
+ p->defaultArg->accept(this);
+ }
+ }
+
+ void parametersToBuffer(Parameters *parameters, int varargs)
+ {
+ buf->writeByte('(');
+ if (parameters)
+ {
+ size_t dim = Parameter::dim(parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ if (i)
+ buf->writestring(", ");
+ Parameter *fparam = Parameter::getNth(parameters, i);
+ fparam->accept(this);
+ }
+ if (varargs)
+ {
+ if (parameters->dim && varargs == 1)
+ buf->writestring(", ");
+ buf->writestring("...");
+ }
+ }
+ buf->writeByte(')');
+ }
+
+ void visit(Module *m)
+ {
+ if (m->md)
+ {
+ if (m->userAttribDecl)
+ {
+ buf->writestring("@(");
+ argsToBuffer(m->userAttribDecl->atts);
+ buf->writeByte(')');
+ buf->writenl();
+ }
+ if (m->md->isdeprecated)
+ {
+ if (m->md->msg)
+ {
+ buf->writestring("deprecated(");
+ m->md->msg->accept(this);
+ buf->writestring(") ");
+ }
+ else
+ buf->writestring("deprecated ");
+ }
+
+ buf->writestring("module ");
+ buf->writestring(m->md->toChars());
+ buf->writeByte(';');
+ buf->writenl();
+ }
+ for (size_t i = 0; i < m->members->dim; i++)
+ {
+ Dsymbol *s = (*m->members)[i];
+ s->accept(this);
+ }
+ }
+};
+
+void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs)
+{
+ PrettyPrintVisitor v(buf, hgs);
+ s->accept(&v);
+}
+
+void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
+{
+ PrettyPrintVisitor v(buf, hgs);
+ v.typeToBuffer(t, ident);
+}
+
+void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs)
+{
+ PrettyPrintVisitor v(buf, hgs);
+ s->accept(&v);
+}
+
+// used from TemplateInstance::toChars() and TemplateMixin::toChars()
+void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes)
+{
+ HdrGenState hgs;
+ hgs.fullQual = qualifyTypes;
+ PrettyPrintVisitor v(buf, &hgs);
+ v.visit(ti);
+}
+
+void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs)
+{
+ PrettyPrintVisitor v(buf, hgs);
+ iz->accept(&v);
+}
+
+bool stcToBuffer(OutBuffer *buf, StorageClass stc)
+{
+ bool result = false;
+ if ((stc & (STCreturn | STCscope)) == (STCreturn | STCscope))
+ stc &= ~STCscope;
+ if (stc & STCscopeinferred)
+ stc &= ~(STCscope | STCscopeinferred);
+ while (stc)
+ {
+ const char *p = stcToChars(stc);
+ if (!p)
+ break;
+ if (!result)
+ result = true;
+ else
+ buf->writeByte(' ');
+ buf->writestring(p);
+ }
+ return result;
+}
+
+/*************************************************
+ * Pick off one of the storage classes from stc,
+ * and return a pointer to a string representation of it.
+ * stc is reduced by the one picked.
+ */
+const char *stcToChars(StorageClass& stc)
+{
+ struct SCstring
+ {
+ StorageClass stc;
+ TOK tok;
+ const char *id;
+ };
+
+ static SCstring table[] =
+ {
+ { STCauto, TOKauto, NULL },
+ { STCscope, TOKscope, NULL },
+ { STCstatic, TOKstatic, NULL },
+ { STCextern, TOKextern, NULL },
+ { STCconst, TOKconst, NULL },
+ { STCfinal, TOKfinal, NULL },
+ { STCabstract, TOKabstract, NULL },
+ { STCsynchronized, TOKsynchronized, NULL },
+ { STCdeprecated, TOKdeprecated, NULL },
+ { STCoverride, TOKoverride, NULL },
+ { STClazy, TOKlazy, NULL },
+ { STCalias, TOKalias, NULL },
+ { STCout, TOKout, NULL },
+ { STCin, TOKin, NULL },
+ { STCmanifest, TOKenum, NULL },
+ { STCimmutable, TOKimmutable, NULL },
+ { STCshared, TOKshared, NULL },
+ { STCnothrow, TOKnothrow, NULL },
+ { STCwild, TOKwild, NULL },
+ { STCpure, TOKpure, NULL },
+ { STCref, TOKref, NULL },
+ { STCtls, TOKreserved, NULL },
+ { STCgshared, TOKgshared, NULL },
+ { STCnogc, TOKat, "@nogc" },
+ { STCproperty, TOKat, "@property" },
+ { STCsafe, TOKat, "@safe" },
+ { STCtrusted, TOKat, "@trusted" },
+ { STCsystem, TOKat, "@system" },
+ { STCdisable, TOKat, "@disable" },
+ { STCfuture, TOKat, "@__future" },
+ { 0, TOKreserved, NULL }
+ };
+
+ for (int i = 0; table[i].stc; i++)
+ {
+ StorageClass tbl = table[i].stc;
+ assert(tbl & STCStorageClass);
+ if (stc & tbl)
+ {
+ stc &= ~tbl;
+ if (tbl == STCtls) // TOKtls was removed
+ return "__thread";
+
+ TOK tok = table[i].tok;
+ if (tok == TOKat)
+ return table[i].id;
+ else
+ return Token::toChars(tok);
+ }
+ }
+ //printf("stc = %llx\n", stc);
+ return NULL;
+}
+
+void trustToBuffer(OutBuffer *buf, TRUST trust)
+{
+ const char *p = trustToChars(trust);
+ if (p)
+ buf->writestring(p);
+}
+
+const char *trustToChars(TRUST trust)
+{
+ switch (trust)
+ {
+ case TRUSTdefault: return NULL;
+ case TRUSTsystem: return "@system";
+ case TRUSTtrusted: return "@trusted";
+ case TRUSTsafe: return "@safe";
+ default: assert(0);
+ }
+ return NULL; // never reached
+}
+
+void linkageToBuffer(OutBuffer *buf, LINK linkage)
+{
+ const char *p = linkageToChars(linkage);
+ if (p)
+ {
+ buf->writestring("extern (");
+ buf->writestring(p);
+ buf->writeByte(')');
+ }
+}
+
+const char *linkageToChars(LINK linkage)
+{
+ switch (linkage)
+ {
+ case LINKdefault: return NULL;
+ case LINKd: return "D";
+ case LINKc: return "C";
+ case LINKcpp: return "C++";
+ case LINKwindows: return "Windows";
+ case LINKpascal: return "Pascal";
+ case LINKobjc: return "Objective-C";
+ case LINKsystem: return "System";
+ default: assert(0);
+ }
+ return NULL; // never reached
+}
+
+void protectionToBuffer(OutBuffer *buf, Prot prot)
+{
+ const char *p = protectionToChars(prot.kind);
+ if (p)
+ buf->writestring(p);
+
+ if (prot.kind == PROTpackage && prot.pkg)
+ {
+ buf->writeByte('(');
+ buf->writestring(prot.pkg->toPrettyChars(true));
+ buf->writeByte(')');
+ }
+}
+
+const char *protectionToChars(PROTKIND kind)
+{
+ switch (kind)
+ {
+ case PROTundefined: return NULL;
+ case PROTnone: return "none";
+ case PROTprivate: return "private";
+ case PROTpackage: return "package";
+ case PROTprotected: return "protected";
+ case PROTpublic: return "public";
+ case PROTexport: return "export";
+ default: assert(0);
+ }
+ return NULL; // never reached
+}
+
+// Print the full function signature with correct ident, attributes and template args
+void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident,
+ HdrGenState* hgs, TemplateDeclaration *td)
+{
+ //printf("TypeFunction::toCBuffer() this = %p\n", this);
+ PrettyPrintVisitor v(buf, hgs);
+ v.visitFuncIdentWithPrefix(tf, ident, td);
+}
+
+// ident is inserted before the argument list and will be "function" or "delegate" for a type
+void functionToBufferWithIdent(TypeFunction *tf, OutBuffer *buf, const char *ident)
+{
+ HdrGenState hgs;
+ PrettyPrintVisitor v(buf, &hgs);
+ v.visitFuncIdentWithPostfix(tf, ident);
+}
+
+void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs)
+{
+ PrettyPrintVisitor v(buf, hgs);
+ e->accept(&v);
+}
+
+/**************************************************
+ * Write out argument types to buf.
+ */
+void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments)
+{
+ if (!arguments || !arguments->dim)
+ return;
+
+ HdrGenState hgs;
+ PrettyPrintVisitor v(buf, &hgs);
+ for (size_t i = 0; i < arguments->dim; i++)
+ {
+ Expression *arg = (*arguments)[i];
+ if (i)
+ buf->writestring(", ");
+ v.typeToBuffer(arg->type, NULL);
+ }
+}
+
+void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs)
+{
+ PrettyPrintVisitor v(buf, hgs);
+ tp->accept(&v);
+}
+
+void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects)
+{
+ if (!objects || !objects->dim)
+ return;
+
+ HdrGenState hgs;
+ PrettyPrintVisitor v(buf, &hgs);
+ for (size_t i = 0; i < objects->dim; i++)
+ {
+ RootObject *o = (*objects)[i];
+ if (i)
+ buf->writestring(", ");
+ v.objectToBuffer(o);
+ }
+}
+
+const char *parametersTypeToChars(Parameters *parameters, int varargs)
+{
+ OutBuffer buf;
+ HdrGenState hgs;
+ PrettyPrintVisitor v(&buf, &hgs);
+ v.parametersToBuffer(parameters, varargs);
+ return buf.extractString();
+}
diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h
new file mode 100644
index 0000000..c4bafca
--- /dev/null
+++ b/gcc/d/dmd/hdrgen.h
@@ -0,0 +1,54 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Dave Fladebo
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.h
+ */
+
+#pragma once
+
+#include <string.h> // memset()
+
+#include "dsymbol.h"
+
+void genhdrfile(Module *m);
+
+struct HdrGenState
+{
+ bool hdrgen; // true if generating header file
+ bool ddoc; // true if generating Ddoc file
+ bool fullDump; // true if generating a full AST dump file
+ bool fullQual; // fully qualify types when printing
+ int tpltMember;
+ int autoMember;
+ int forStmtInit;
+
+ HdrGenState() { memset(this, 0, sizeof(HdrGenState)); }
+};
+
+void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
+void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs);
+void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs);
+
+void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes = false);
+
+void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TemplateDeclaration *td);
+void functionToBufferWithIdent(TypeFunction *t, OutBuffer *buf, const char *ident);
+
+void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments);
+
+void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects);
+
+void moduleToBuffer(OutBuffer *buf, Module *m);
+
+const char *parametersTypeToChars(Parameters *parameters, int varargs);
+
+bool stcToBuffer(OutBuffer *buf, StorageClass stc);
+const char *stcToChars(StorageClass& stc);
+const char *linkageToChars(LINK linkage);
diff --git a/gcc/d/dmd/iasm.c b/gcc/d/dmd/iasm.c
new file mode 100644
index 0000000..1a4d810
--- /dev/null
+++ b/gcc/d/dmd/iasm.c
@@ -0,0 +1,44 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/iasm.c
+ */
+
+/* Inline assembler for the D programming language compiler
+ */
+
+#include "scope.h"
+#include "declaration.h"
+#include "statement.h"
+
+#ifdef IN_GCC
+Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc);
+#else
+Statement *inlineAsmSemantic(InlineAsmStatement *s, Scope *sc);
+#endif
+
+Statement *asmSemantic(AsmStatement *s, Scope *sc)
+{
+ //printf("AsmStatement::semantic()\n");
+
+ FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+ assert(fd);
+
+ if (!s->tokens)
+ return NULL;
+
+ // Assume assembler code takes care of setting the return value
+ sc->func->hasReturnExp |= 8;
+
+#ifdef IN_GCC
+ GccAsmStatement *eas = new GccAsmStatement(s->loc, s->tokens);
+ return gccAsmSemantic(eas, sc);
+#else
+ InlineAsmStatement *ias = new InlineAsmStatement(s->loc, s->tokens);
+ return inlineAsmSemantic(ias, sc);
+#endif
+}
diff --git a/gcc/d/dmd/iasmgcc.c b/gcc/d/dmd/iasmgcc.c
new file mode 100644
index 0000000..5e0d9ae
--- /dev/null
+++ b/gcc/d/dmd/iasmgcc.c
@@ -0,0 +1,356 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2018 by The D Language Foundation, All Rights Reserved
+ * written by Iain Buclaw
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/iasmgcc.c
+ */
+
+/* Inline assembler for the GCC D compiler.
+ */
+
+#include "scope.h"
+#include "declaration.h"
+#include "parse.h"
+#include "statement.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+Statement *semantic(Statement *s, Scope *sc);
+
+/***********************************
+ * Parse list of extended asm input or output operands.
+ * Grammar:
+ * | Operands:
+ * | SymbolicName(opt) StringLiteral AssignExpression
+ * | SymbolicName(opt) StringLiteral AssignExpression , Operands
+ * |
+ * | SymbolicName:
+ * | [ Identifier ]
+ * Params:
+ * p = parser state
+ * s = asm statement to parse
+ * Returns:
+ * number of operands added to the gcc asm statement
+ */
+static int parseExtAsmOperands(Parser *p, GccAsmStatement *s)
+{
+ int numargs = 0;
+
+ while (1)
+ {
+ Expression *arg = NULL;
+ Identifier *name = NULL;
+ Expression *constraint = NULL;
+
+ switch (p->token.value)
+ {
+ case TOKsemicolon:
+ case TOKcolon:
+ case TOKeof:
+ return numargs;
+
+ case TOKlbracket:
+ if (p->peekNext() == TOKidentifier)
+ {
+ p->nextToken();
+ name = p->token.ident;
+ p->nextToken();
+ }
+ else
+ {
+ p->error(s->loc, "expected identifier after `[`");
+ goto Lerror;
+ }
+ p->check(TOKrbracket);
+ // fall through
+
+ case TOKstring:
+ constraint = p->parsePrimaryExp();
+ arg = p->parseAssignExp();
+
+ if (!s->args)
+ {
+ s->names = new Identifiers();
+ s->constraints = new Expressions();
+ s->args = new Expressions();
+ }
+ s->names->push(name);
+ s->args->push(arg);
+ s->constraints->push(constraint);
+ numargs++;
+
+ if (p->token.value == TOKcomma)
+ p->nextToken();
+ break;
+
+ default:
+ p->error("expected constant string constraint for operand, not `%s`",
+ p->token.toChars());
+ goto Lerror;
+ }
+ }
+Lerror:
+ while (p->token.value != TOKrcurly &&
+ p->token.value != TOKsemicolon &&
+ p->token.value != TOKeof)
+ p->nextToken();
+
+ return numargs;
+}
+
+/***********************************
+ * Parse list of extended asm clobbers.
+ * Grammar:
+ * | Clobbers:
+ * | StringLiteral
+ * | StringLiteral , Clobbers
+ * Params:
+ * p = parser state
+ * Returns:
+ * array of parsed clobber expressions
+ */
+static Expressions *parseExtAsmClobbers(Parser *p)
+{
+ Expressions *clobbers = NULL;
+
+ while (1)
+ {
+ Expression *clobber;
+
+ switch (p->token.value)
+ {
+ case TOKsemicolon:
+ case TOKcolon:
+ case TOKeof:
+ return clobbers;
+
+ case TOKstring:
+ clobber = p->parsePrimaryExp();
+ if (!clobbers)
+ clobbers = new Expressions();
+ clobbers->push(clobber);
+
+ if (p->token.value == TOKcomma)
+ p->nextToken();
+ break;
+
+ default:
+ p->error("expected constant string constraint for clobber name, not `%s`",
+ p->token.toChars());
+ goto Lerror;
+ }
+ }
+Lerror:
+ while (p->token.value != TOKrcurly &&
+ p->token.value != TOKsemicolon &&
+ p->token.value != TOKeof)
+ p->nextToken();
+
+ return clobbers;
+}
+
+/***********************************
+ * Parse list of extended asm goto labels.
+ * Grammar:
+ * | GotoLabels:
+ * | Identifier
+ * | Identifier , GotoLabels
+ * Params:
+ * p = parser state
+ * Returns:
+ * array of parsed goto labels
+ */
+static Identifiers *parseExtAsmGotoLabels(Parser *p)
+{
+ Identifiers *labels = NULL;
+
+ while (1)
+ {
+ switch (p->token.value)
+ {
+ case TOKsemicolon:
+ case TOKeof:
+ return labels;
+
+ case TOKidentifier:
+ if (!labels)
+ labels = new Identifiers();
+ labels->push(p->token.ident);
+
+ if (p->nextToken() == TOKcomma)
+ p->nextToken();
+ break;
+
+ default:
+ p->error("expected identifier for goto label name, not `%s`",
+ p->token.toChars());
+ goto Lerror;
+ }
+ }
+Lerror:
+ while (p->token.value != TOKrcurly &&
+ p->token.value != TOKsemicolon &&
+ p->token.value != TOKeof)
+ p->nextToken();
+
+ return labels;
+}
+
+/***********************************
+ * Parse a gcc asm statement.
+ * There are three forms of inline asm statements, basic, extended, and goto.
+ * Grammar:
+ * | AsmInstruction:
+ * | BasicAsmInstruction
+ * | ExtAsmInstruction
+ * | GotoAsmInstruction
+ * |
+ * | BasicAsmInstruction:
+ * | Expression
+ * |
+ * | ExtAsmInstruction:
+ * | Expression : Operands(opt) : Operands(opt) : Clobbers(opt)
+ * |
+ * | GotoAsmInstruction:
+ * | Expression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
+ * Params:
+ * p = parser state
+ * s = asm statement to parse
+ * Returns:
+ * the parsed gcc asm statement
+ */
+static GccAsmStatement *parseGccAsm(Parser *p, GccAsmStatement *s)
+{
+ s->insn = p->parseExpression();
+ if (p->token.value == TOKsemicolon)
+ goto Ldone;
+
+ // No semicolon followed after instruction template, treat as extended asm.
+ for (int section = 0; section < 4; ++section)
+ {
+ p->check(TOKcolon);
+
+ switch (section)
+ {
+ case 0:
+ s->outputargs = parseExtAsmOperands(p, s);
+ break;
+
+ case 1:
+ parseExtAsmOperands(p, s);
+ break;
+
+ case 2:
+ s->clobbers = parseExtAsmClobbers(p);
+ break;
+
+ case 3:
+ s->labels = parseExtAsmGotoLabels(p);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ if (p->token.value == TOKsemicolon)
+ goto Ldone;
+ }
+Ldone:
+ p->check(TOKsemicolon);
+
+ return s;
+}
+
+/***********************************
+ * Parse and run semantic analysis on a GccAsmStatement.
+ * Params:
+ * s = gcc asm statement being parsed
+ * sc = the scope where the asm statement is located
+ * Returns:
+ * the completed gcc asm statement, or null if errors occurred
+ */
+Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc)
+{
+ //printf("GccAsmStatement::semantic()\n");
+ Parser p(sc->_module, (const utf8_t *)";", 1, false);
+
+ // Make a safe copy of the token list before parsing.
+ Token *toklist = NULL;
+ Token **ptoklist = &toklist;
+
+ for (Token *token = s->tokens; token; token = token->next)
+ {
+ *ptoklist = Token::alloc();
+ memcpy(*ptoklist, token, sizeof(Token));
+ ptoklist = &(*ptoklist)->next;
+ *ptoklist = NULL;
+ }
+ p.token = *toklist;
+
+ // Parse the gcc asm statement.
+ s = parseGccAsm(&p, s);
+ if (p.errors)
+ return NULL;
+ s->stc = sc->stc;
+
+ // Fold the instruction template string.
+ s->insn = semantic(s->insn, sc);
+ s->insn = s->insn->ctfeInterpret();
+
+ if (s->insn->op != TOKstring || ((StringExp *) s->insn)->sz != 1)
+ s->insn->error("asm instruction template must be a constant char string");
+
+ if (s->labels && s->outputargs)
+ s->error("extended asm statements with labels cannot have output constraints");
+
+ // Analyse all input and output operands.
+ if (s->args)
+ {
+ for (size_t i = 0; i < s->args->dim; i++)
+ {
+ Expression *e = (*s->args)[i];
+ e = semantic(e, sc);
+ // Check argument is a valid lvalue/rvalue.
+ if (i < s->outputargs)
+ e = e->modifiableLvalue(sc, NULL);
+ else if (e->checkValue())
+ e = new ErrorExp();
+ (*s->args)[i] = e;
+
+ e = (*s->constraints)[i];
+ e = semantic(e, sc);
+ assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
+ (*s->constraints)[i] = e;
+ }
+ }
+
+ // Analyse all clobbers.
+ if (s->clobbers)
+ {
+ for (size_t i = 0; i < s->clobbers->dim; i++)
+ {
+ Expression *e = (*s->clobbers)[i];
+ e = semantic(e, sc);
+ assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
+ (*s->clobbers)[i] = e;
+ }
+ }
+
+ // Analyse all goto labels.
+ if (s->labels)
+ {
+ for (size_t i = 0; i < s->labels->dim; i++)
+ {
+ Identifier *ident = (*s->labels)[i];
+ GotoStatement *gs = new GotoStatement(s->loc, ident);
+ if (!s->gotos)
+ s->gotos = new GotoStatements();
+ s->gotos->push(gs);
+ semantic(gs, sc);
+ }
+ }
+
+ return s;
+}
diff --git a/gcc/d/dmd/identifier.c b/gcc/d/dmd/identifier.c
new file mode 100644
index 0000000..5e40746
--- /dev/null
+++ b/gcc/d/dmd/identifier.c
@@ -0,0 +1,190 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/identifier.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "root/root.h"
+#include "identifier.h"
+#include "mars.h"
+#include "id.h"
+#include "tokens.h"
+#include "utf.h"
+
+Identifier::Identifier(const char *string, size_t length, int value)
+{
+ //printf("Identifier('%s', %d)\n", string, value);
+ this->string = string;
+ this->value = value;
+ this->len = length;
+}
+
+Identifier::Identifier(const char *string)
+{
+ //printf("Identifier('%s')\n", string);
+ this->string = string;
+ this->value = TOKidentifier;
+ this->len = strlen(string);
+}
+
+Identifier *Identifier::create(const char *string)
+{
+ return new Identifier(string);
+}
+
+bool Identifier::equals(RootObject *o)
+{
+ return this == o || strncmp(string,o->toChars(),len+1) == 0;
+}
+
+int Identifier::compare(RootObject *o)
+{
+ return strncmp(string, o->toChars(), len + 1);
+}
+
+const char *Identifier::toChars()
+{
+ return string;
+}
+
+int Identifier::getValue() const
+{
+ return value;
+}
+
+const char *Identifier::toHChars2()
+{
+ const char *p = NULL;
+
+ if (this == Id::ctor) p = "this";
+ else if (this == Id::dtor) p = "~this";
+ else if (this == Id::unitTest) p = "unittest";
+ else if (this == Id::dollar) p = "$";
+ else if (this == Id::withSym) p = "with";
+ else if (this == Id::result) p = "result";
+ else if (this == Id::returnLabel) p = "return";
+ else
+ { p = toChars();
+ if (*p == '_')
+ {
+ if (strncmp(p, "_staticCtor", 11) == 0)
+ p = "static this";
+ else if (strncmp(p, "_staticDtor", 11) == 0)
+ p = "static ~this";
+ else if (strncmp(p, "__invariant", 11) == 0)
+ p = "invariant";
+ }
+ }
+
+ return p;
+}
+
+void Identifier::print()
+{
+ fprintf(stderr, "%s",string);
+}
+
+int Identifier::dyncast() const
+{
+ return DYNCAST_IDENTIFIER;
+}
+
+StringTable Identifier::stringtable;
+
+Identifier *Identifier::generateId(const char *prefix)
+{
+ static size_t i;
+
+ return generateId(prefix, ++i);
+}
+
+Identifier *Identifier::generateId(const char *prefix, size_t i)
+{ OutBuffer buf;
+
+ buf.writestring(prefix);
+ buf.printf("%llu", (ulonglong)i);
+
+ char *id = buf.peekString();
+ return idPool(id);
+}
+
+/********************************************
+ * Create an identifier in the string table.
+ */
+
+Identifier *Identifier::idPool(const char *s, size_t len)
+{
+ StringValue *sv = stringtable.update(s, len);
+ Identifier *id = (Identifier *) sv->ptrvalue;
+ if (!id)
+ {
+ id = new Identifier(sv->toDchars(), len, TOKidentifier);
+ sv->ptrvalue = (char *)id;
+ }
+ return id;
+}
+
+Identifier *Identifier::idPool(const char *s, size_t len, int value)
+{
+ StringValue *sv = stringtable.insert(s, len, NULL);
+ assert(sv);
+ Identifier *id = new Identifier(sv->toDchars(), len, value);
+ sv->ptrvalue = (char *)id;
+ return id;
+}
+
+/**********************************
+ * Determine if string is a valid Identifier.
+ * Returns:
+ * 0 invalid
+ */
+
+bool Identifier::isValidIdentifier(const char *p)
+{
+ size_t len;
+ size_t idx;
+
+ if (!p || !*p)
+ goto Linvalid;
+
+ if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars
+ goto Linvalid;
+
+ len = strlen(p);
+ idx = 0;
+ while (p[idx])
+ {
+ dchar_t dc;
+ const char *q = utf_decodeChar((const utf8_t *)p, len, &idx, &dc);
+ if (q)
+ goto Linvalid;
+
+ if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
+ goto Linvalid;
+ }
+ return true;
+
+Linvalid:
+ return false;
+}
+
+Identifier *Identifier::lookup(const char *s, size_t len)
+{
+ StringValue *sv = stringtable.lookup(s, len);
+ if (!sv)
+ return NULL;
+ return (Identifier *)sv->ptrvalue;
+}
+
+void Identifier::initTable()
+{
+ stringtable._init(28000);
+}
diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h
new file mode 100644
index 0000000..9352d28
--- /dev/null
+++ b/gcc/d/dmd/identifier.h
@@ -0,0 +1,49 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/identifier.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "root/stringtable.h"
+
+class Identifier : public RootObject
+{
+private:
+ int value;
+ const char *string;
+ size_t len;
+
+public:
+ Identifier(const char *string, size_t length, int value);
+ Identifier(const char *string);
+ static Identifier* create(const char *string);
+ bool equals(RootObject *o);
+ int compare(RootObject *o);
+ void print();
+ const char *toChars();
+ int getValue() const;
+ const char *toHChars2();
+ int dyncast() const;
+
+ static StringTable stringtable;
+ static Identifier *generateId(const char *prefix);
+ static Identifier *generateId(const char *prefix, size_t i);
+ static Identifier *idPool(const char *s, size_t len);
+ static Identifier *idPool(const char *s, size_t len, int value);
+
+ static inline Identifier *idPool(const char *s)
+ {
+ return idPool(s, strlen(s));
+ }
+
+ static bool isValidIdentifier(const char *p);
+ static Identifier *lookup(const char *s, size_t len);
+ static void initTable();
+};
diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c
new file mode 100644
index 0000000..d360ec8
--- /dev/null
+++ b/gcc/d/dmd/idgen.c
@@ -0,0 +1,503 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/idgen.c
+ */
+
+// Program to generate string files in d data structures.
+// Saves much tedious typing, and eliminates typo problems.
+// Generates:
+// id.h
+// id.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct Msgtable
+{
+ const char* ident; // name to use in DMD source
+ const char* name; // name in D executable
+};
+
+Msgtable msgtable[] =
+{
+ { "IUnknown", NULL },
+ { "Object", NULL },
+ { "object", NULL },
+ { "string", NULL },
+ { "wstring", NULL },
+ { "dstring", NULL },
+ { "max", NULL },
+ { "min", NULL },
+ { "This", "this" },
+ { "_super", "super" },
+ { "ctor", "__ctor" },
+ { "dtor", "__dtor" },
+ { "__xdtor", "__xdtor" },
+ { "__fieldDtor", "__fieldDtor" },
+ { "__aggrDtor", "__aggrDtor" },
+ { "postblit", "__postblit" },
+ { "__xpostblit", "__xpostblit" },
+ { "__fieldPostblit", "__fieldPostblit" },
+ { "__aggrPostblit", "__aggrPostblit" },
+ { "classInvariant", "__invariant" },
+ { "unitTest", "__unitTest" },
+ { "require", "__require" },
+ { "ensure", "__ensure" },
+ { "_init", "init" },
+ { "__sizeof", "sizeof" },
+ { "__xalignof", "alignof" },
+ { "_mangleof", "mangleof" },
+ { "stringof", NULL },
+ { "_tupleof", "tupleof" },
+ { "length", NULL },
+ { "remove", NULL },
+ { "ptr", NULL },
+ { "array", NULL },
+ { "funcptr", NULL },
+ { "dollar", "__dollar" },
+ { "ctfe", "__ctfe" },
+ { "offset", NULL },
+ { "offsetof", NULL },
+ { "ModuleInfo", NULL },
+ { "ClassInfo", NULL },
+ { "classinfo", NULL },
+ { "typeinfo", NULL },
+ { "outer", NULL },
+ { "Exception", NULL },
+ { "RTInfo", NULL },
+ { "Throwable", NULL },
+ { "Error", NULL },
+ { "withSym", "__withSym" },
+ { "result", "__result" },
+ { "returnLabel", "__returnLabel" },
+ { "line", NULL },
+ { "empty", "" },
+ { "p", NULL },
+ { "q", NULL },
+ { "__vptr", NULL },
+ { "__monitor", NULL },
+ { "gate", "__gate" },
+ { "__c_long", NULL },
+ { "__c_ulong", NULL },
+ { "__c_longlong", NULL },
+ { "__c_ulonglong", NULL },
+ { "__c_long_double", NULL },
+ { "cpp_type_info_ptr", "__cpp_type_info_ptr" },
+ { "_assert", "assert" },
+ { "_unittest", "unittest" },
+ { "_body", "body" },
+
+ { "TypeInfo", NULL },
+ { "TypeInfo_Class", NULL },
+ { "TypeInfo_Interface", NULL },
+ { "TypeInfo_Struct", NULL },
+ { "TypeInfo_Enum", NULL },
+ { "TypeInfo_Pointer", NULL },
+ { "TypeInfo_Vector", NULL },
+ { "TypeInfo_Array", NULL },
+ { "TypeInfo_StaticArray", NULL },
+ { "TypeInfo_AssociativeArray", NULL },
+ { "TypeInfo_Function", NULL },
+ { "TypeInfo_Delegate", NULL },
+ { "TypeInfo_Tuple", NULL },
+ { "TypeInfo_Const", NULL },
+ { "TypeInfo_Invariant", NULL },
+ { "TypeInfo_Shared", NULL },
+ { "TypeInfo_Wild", "TypeInfo_Inout" },
+ { "elements", NULL },
+ { "_arguments_typeinfo", NULL },
+ { "_arguments", NULL },
+ { "_argptr", NULL },
+ { "destroy", NULL },
+ { "xopEquals", "__xopEquals" },
+ { "xopCmp", "__xopCmp" },
+ { "xtoHash", "__xtoHash" },
+
+ { "LINE", "__LINE__" },
+ { "FILE", "__FILE__" },
+ { "MODULE", "__MODULE__" },
+ { "FUNCTION", "__FUNCTION__" },
+ { "PRETTY_FUNCTION", "__PRETTY_FUNCTION__" },
+ { "DATE", "__DATE__" },
+ { "TIME", "__TIME__" },
+ { "TIMESTAMP", "__TIMESTAMP__" },
+ { "VENDOR", "__VENDOR__" },
+ { "VERSIONX", "__VERSION__" },
+ { "EOFX", "__EOF__" },
+
+ { "nan", NULL },
+ { "infinity", NULL },
+ { "dig", NULL },
+ { "epsilon", NULL },
+ { "mant_dig", NULL },
+ { "max_10_exp", NULL },
+ { "max_exp", NULL },
+ { "min_10_exp", NULL },
+ { "min_exp", NULL },
+ { "min_normal", NULL },
+ { "re", NULL },
+ { "im", NULL },
+
+ { "C", NULL },
+ { "D", NULL },
+ { "Windows", NULL },
+ { "Pascal", NULL },
+ { "System", NULL },
+ { "Objective", NULL },
+
+ { "exit", NULL },
+ { "success", NULL },
+ { "failure", NULL },
+
+ { "keys", NULL },
+ { "values", NULL },
+ { "rehash", NULL },
+
+ { "future", "__future" },
+ { "property", NULL },
+ { "nogc", NULL },
+ { "safe", NULL },
+ { "trusted", NULL },
+ { "system", NULL },
+ { "disable", NULL },
+
+ // For inline assembler
+ { "___out", "out" },
+ { "___in", "in" },
+ { "__int", "int" },
+ { "_dollar", "$" },
+ { "__LOCAL_SIZE", NULL },
+
+ // For operator overloads
+ { "uadd", "opPos" },
+ { "neg", "opNeg" },
+ { "com", "opCom" },
+ { "add", "opAdd" },
+ { "add_r", "opAdd_r" },
+ { "sub", "opSub" },
+ { "sub_r", "opSub_r" },
+ { "mul", "opMul" },
+ { "mul_r", "opMul_r" },
+ { "div", "opDiv" },
+ { "div_r", "opDiv_r" },
+ { "mod", "opMod" },
+ { "mod_r", "opMod_r" },
+ { "eq", "opEquals" },
+ { "cmp", "opCmp" },
+ { "iand", "opAnd" },
+ { "iand_r", "opAnd_r" },
+ { "ior", "opOr" },
+ { "ior_r", "opOr_r" },
+ { "ixor", "opXor" },
+ { "ixor_r", "opXor_r" },
+ { "shl", "opShl" },
+ { "shl_r", "opShl_r" },
+ { "shr", "opShr" },
+ { "shr_r", "opShr_r" },
+ { "ushr", "opUShr" },
+ { "ushr_r", "opUShr_r" },
+ { "cat", "opCat" },
+ { "cat_r", "opCat_r" },
+ { "assign", "opAssign" },
+ { "addass", "opAddAssign" },
+ { "subass", "opSubAssign" },
+ { "mulass", "opMulAssign" },
+ { "divass", "opDivAssign" },
+ { "modass", "opModAssign" },
+ { "andass", "opAndAssign" },
+ { "orass", "opOrAssign" },
+ { "xorass", "opXorAssign" },
+ { "shlass", "opShlAssign" },
+ { "shrass", "opShrAssign" },
+ { "ushrass", "opUShrAssign" },
+ { "catass", "opCatAssign" },
+ { "postinc", "opPostInc" },
+ { "postdec", "opPostDec" },
+ { "index", "opIndex" },
+ { "indexass", "opIndexAssign" },
+ { "slice", "opSlice" },
+ { "sliceass", "opSliceAssign" },
+ { "call", "opCall" },
+ { "_cast", "opCast" },
+ { "opIn", NULL },
+ { "opIn_r", NULL },
+ { "opStar", NULL },
+ { "opDot", NULL },
+ { "opDispatch", NULL },
+ { "opDollar", NULL },
+ { "opUnary", NULL },
+ { "opIndexUnary", NULL },
+ { "opSliceUnary", NULL },
+ { "opBinary", NULL },
+ { "opBinaryRight", NULL },
+ { "opOpAssign", NULL },
+ { "opIndexOpAssign", NULL },
+ { "opSliceOpAssign", NULL },
+ { "pow", "opPow" },
+ { "pow_r", "opPow_r" },
+ { "powass", "opPowAssign" },
+
+ { "classNew", "new" },
+ { "classDelete", "delete" },
+
+ // For foreach
+ { "apply", "opApply" },
+ { "applyReverse", "opApplyReverse" },
+
+ // Ranges
+ { "Fempty", "empty" },
+ { "Ffront", "front" },
+ { "Fback", "back" },
+ { "FpopFront", "popFront" },
+ { "FpopBack", "popBack" },
+
+ // For internal functions
+ { "aaLen", "_aaLen" },
+ { "aaKeys", "_aaKeys" },
+ { "aaValues", "_aaValues" },
+ { "aaRehash", "_aaRehash" },
+ { "monitorenter", "_d_monitorenter" },
+ { "monitorexit", "_d_monitorexit" },
+ { "criticalenter", "_d_criticalenter" },
+ { "criticalexit", "_d_criticalexit" },
+ { "_ArrayEq", NULL },
+ { "_ArrayPostblit", NULL },
+ { "_ArrayDtor", NULL },
+
+ // For pragma's
+ { "Pinline", "inline" },
+ { "lib", NULL },
+ { "mangle", NULL },
+ { "msg", NULL },
+ { "startaddress", NULL },
+
+ // For special functions
+ { "tohash", "toHash" },
+ { "tostring", "toString" },
+ { "getmembers", "getMembers" },
+
+ // Special functions
+ { "__alloca", "alloca" },
+ { "main", NULL },
+ { "WinMain", NULL },
+ { "DllMain", NULL },
+ { "tls_get_addr", "___tls_get_addr" },
+ { "entrypoint", "__entrypoint" },
+
+ // varargs implementation
+ { "va_start", NULL },
+
+ // Builtin functions
+ { "std", NULL },
+ { "core", NULL },
+ { "attribute", NULL },
+ { "math", NULL },
+ { "sin", NULL },
+ { "cos", NULL },
+ { "tan", NULL },
+ { "_sqrt", "sqrt" },
+ { "_pow", "pow" },
+ { "atan2", NULL },
+ { "rndtol", NULL },
+ { "expm1", NULL },
+ { "exp2", NULL },
+ { "yl2x", NULL },
+ { "yl2xp1", NULL },
+ { "fabs", NULL },
+ { "bitop", NULL },
+ { "bsf", NULL },
+ { "bsr", NULL },
+ { "bswap", NULL },
+
+ // Traits
+ { "isAbstractClass", NULL },
+ { "isArithmetic", NULL },
+ { "isAssociativeArray", NULL },
+ { "isFinalClass", NULL },
+ { "isTemplate", NULL },
+ { "isPOD", NULL },
+ { "isNested", NULL },
+ { "isFloating", NULL },
+ { "isIntegral", NULL },
+ { "isScalar", NULL },
+ { "isStaticArray", NULL },
+ { "isUnsigned", NULL },
+ { "isVirtualFunction", NULL },
+ { "isVirtualMethod", NULL },
+ { "isAbstractFunction", NULL },
+ { "isFinalFunction", NULL },
+ { "isOverrideFunction", NULL },
+ { "isStaticFunction", NULL },
+ { "isRef", NULL },
+ { "isOut", NULL },
+ { "isLazy", NULL },
+ { "hasMember", NULL },
+ { "identifier", NULL },
+ { "getProtection", NULL },
+ { "parent", NULL },
+ { "getMember", NULL },
+ { "getOverloads", NULL },
+ { "getVirtualFunctions", NULL },
+ { "getVirtualMethods", NULL },
+ { "classInstanceSize", NULL },
+ { "allMembers", NULL },
+ { "derivedMembers", NULL },
+ { "isSame", NULL },
+ { "compiles", NULL },
+ { "parameters", NULL },
+ { "getAliasThis", NULL },
+ { "getAttributes", NULL },
+ { "getFunctionAttributes", NULL },
+ { "getFunctionVariadicStyle", NULL },
+ { "getParameterStorageClasses", NULL },
+ { "getLinkage", NULL },
+ { "getUnitTests", NULL },
+ { "getVirtualIndex", NULL },
+ { "getPointerBitmap", NULL },
+
+ // For C++ mangling
+ { "allocator", NULL },
+ { "basic_string", NULL },
+ { "basic_istream", NULL },
+ { "basic_ostream", NULL },
+ { "basic_iostream", NULL },
+ { "char_traits", NULL },
+
+ // Compiler recognized UDA's
+ { "udaSelector", "selector" },
+
+ // C names, for undefined identifier error messages
+ { "_NULL", "NULL" },
+ { "_TRUE", "TRUE" },
+ { "_FALSE", "FALSE" },
+ { "_unsigned", "unsigned" },
+};
+
+
+int main()
+{
+ {
+ FILE *fp = fopen("id.h","wb");
+ if (!fp)
+ {
+ printf("can't open id.h\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(fp, "// File generated by idgen.c\n");
+ fprintf(fp, "#ifndef DMD_ID_H\n");
+ fprintf(fp, "#define DMD_ID_H 1\n");
+ fprintf(fp, "class Identifier;\n");
+ fprintf(fp, "struct Id\n");
+ fprintf(fp, "{\n");
+
+ for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+ {
+ const char *id = msgtable[i].ident;
+ fprintf(fp," static Identifier *%s;\n", id);
+ }
+
+ fprintf(fp, " static void initialize();\n");
+ fprintf(fp, "};\n");
+ fprintf(fp, "#endif\n");
+
+ fclose(fp);
+ }
+
+ {
+ FILE *fp = fopen("id.c","wb");
+ if (!fp)
+ {
+ printf("can't open id.c\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(fp, "// File generated by idgen.c\n");
+ fprintf(fp, "#include \"identifier.h\"\n");
+ fprintf(fp, "#include \"id.h\"\n");
+ fprintf(fp, "#include \"mars.h\"\n");
+
+ for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+ {
+ const char *id = msgtable[i].ident;
+ const char *p = msgtable[i].name;
+
+ if (!p)
+ p = id;
+ fprintf(fp,"Identifier *Id::%s;\n", id);
+ }
+
+ fprintf(fp, "void Id::initialize()\n");
+ fprintf(fp, "{\n");
+
+ for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+ {
+ const char *id = msgtable[i].ident;
+ const char *p = msgtable[i].name;
+
+ if (!p)
+ p = id;
+ fprintf(fp," %s = Identifier::idPool(\"%s\");\n", id, p);
+ }
+
+ fprintf(fp, "}\n");
+
+ fclose(fp);
+ }
+
+ {
+ FILE *fp = fopen("id.d","wb");
+ if (!fp)
+ {
+ printf("can't open id.d\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(fp, "// File generated by idgen.c\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "module ddmd.id;\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "import ddmd.identifier, ddmd.tokens;\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "struct Id\n");
+ fprintf(fp, "{\n");
+
+ for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+ {
+ const char *id = msgtable[i].ident;
+ const char *p = msgtable[i].name;
+
+ if (!p)
+ p = id;
+ fprintf(fp, " extern (C++) static __gshared Identifier %s;\n", id);
+ }
+
+ fprintf(fp, "\n");
+ fprintf(fp, " extern (C++) static void initialize()\n");
+ fprintf(fp, " {\n");
+
+ for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
+ {
+ const char *id = msgtable[i].ident;
+ const char *p = msgtable[i].name;
+
+ if (!p)
+ p = id;
+ fprintf(fp," %s = Identifier.idPool(\"%s\");\n", id, p);
+ }
+
+ fprintf(fp, " }\n");
+ fprintf(fp, "}\n");
+
+ fclose(fp);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/gcc/d/dmd/impcnvgen.c b/gcc/d/dmd/impcnvgen.c
new file mode 100644
index 0000000..5b88e8e
--- /dev/null
+++ b/gcc/d/dmd/impcnvgen.c
@@ -0,0 +1,599 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/impcnvgen.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mtype.h"
+
+TY impcnvResultTab[TMAX][TMAX];
+TY impcnvType1Tab[TMAX][TMAX];
+TY impcnvType2Tab[TMAX][TMAX];
+int impcnvWarnTab[TMAX][TMAX];
+
+int integral_promotion(int t)
+{
+ switch (t)
+ {
+ case Tchar:
+ case Twchar:
+ case Tbool:
+ case Tint8:
+ case Tuns8:
+ case Tint16:
+ case Tuns16: return Tint32;
+ case Tdchar: return Tuns32;
+ default: return t;
+ }
+}
+
+void init()
+{ int i, j;
+
+ // Set conversion tables
+ for (i = 0; i < TMAX; i++)
+ for (j = 0; j < TMAX; j++)
+ { impcnvResultTab[i][j] = Terror;
+ impcnvType1Tab[i][j] = Terror;
+ impcnvType2Tab[i][j] = Terror;
+ impcnvWarnTab[i][j] = 0;
+ }
+
+#define X(t1,t2, nt1,nt2, rt) \
+ impcnvResultTab[t1][t2] = rt; \
+ impcnvType1Tab[t1][t2] = nt1; \
+ impcnvType2Tab[t1][t2] = nt2;
+
+
+ /* ======================= */
+
+ X(Tbool,Tbool, Tbool,Tbool, Tbool)
+ X(Tbool,Tint8, Tint32,Tint32, Tint32)
+ X(Tbool,Tuns8, Tint32,Tint32, Tint32)
+ X(Tbool,Tint16, Tint32,Tint32, Tint32)
+ X(Tbool,Tuns16, Tint32,Tint32, Tint32)
+ X(Tbool,Tint32, Tint32,Tint32, Tint32)
+ X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32)
+ X(Tbool,Tint64, Tint64,Tint64, Tint64)
+ X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tbool,Tint128, Tint128,Tint128, Tint128)
+ X(Tbool,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tint8,Tint8, Tint32,Tint32, Tint32)
+ X(Tint8,Tuns8, Tint32,Tint32, Tint32)
+ X(Tint8,Tint16, Tint32,Tint32, Tint32)
+ X(Tint8,Tuns16, Tint32,Tint32, Tint32)
+ X(Tint8,Tint32, Tint32,Tint32, Tint32)
+ X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32)
+ X(Tint8,Tint64, Tint64,Tint64, Tint64)
+ X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tint8,Tint128, Tint128,Tint128, Tint128)
+ X(Tint8,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tuns8,Tuns8, Tint32,Tint32, Tint32)
+ X(Tuns8,Tint16, Tint32,Tint32, Tint32)
+ X(Tuns8,Tuns16, Tint32,Tint32, Tint32)
+ X(Tuns8,Tint32, Tint32,Tint32, Tint32)
+ X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32)
+ X(Tuns8,Tint64, Tint64,Tint64, Tint64)
+ X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tuns8,Tint128, Tint128,Tint128, Tint128)
+ X(Tuns8,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tint16,Tint16, Tint32,Tint32, Tint32)
+ X(Tint16,Tuns16, Tint32,Tint32, Tint32)
+ X(Tint16,Tint32, Tint32,Tint32, Tint32)
+ X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32)
+ X(Tint16,Tint64, Tint64,Tint64, Tint64)
+ X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tint16,Tint128, Tint128,Tint128, Tint128)
+ X(Tint16,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tuns16,Tuns16, Tint32,Tint32, Tint32)
+ X(Tuns16,Tint32, Tint32,Tint32, Tint32)
+ X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32)
+ X(Tuns16,Tint64, Tint64,Tint64, Tint64)
+ X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tuns16,Tint128, Tint128,Tint128, Tint128)
+ X(Tuns16,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tint32,Tint32, Tint32,Tint32, Tint32)
+ X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32)
+ X(Tint32,Tint64, Tint64,Tint64, Tint64)
+ X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tint32,Tint128, Tint128,Tint128, Tint128)
+ X(Tint32,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32)
+ X(Tuns32,Tint64, Tint64,Tint64, Tint64)
+ X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tuns32,Tint128, Tint128,Tint128, Tint128)
+ X(Tuns32,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tint64,Tint64, Tint64,Tint64, Tint64)
+ X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tint64,Tint128, Tint128,Tint128, Tint128)
+ X(Tint64,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64)
+ X(Tuns64,Tint128, Tint128,Tint128, Tint128)
+ X(Tuns64,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tint128,Tint128, Tint128,Tint128, Tint128)
+ X(Tint128,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tint128,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tint128,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tint128,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tint128,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tint128,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tint128,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tint128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tint128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tint128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tuns128,Tuns128, Tuns128,Tuns128, Tuns128)
+
+ X(Tuns128,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tuns128,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tuns128,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+ X(Tuns128,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tuns128,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tuns128,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+ X(Tuns128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tuns128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tuns128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
+ X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+
+ X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
+ X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+
+ X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
+ X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
+ X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+
+ X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64)
+ X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
+ X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+
+ X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
+ X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
+
+ X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80)
+ X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80)
+ X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
+
+ X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80)
+ X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80)
+ X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32)
+ X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
+ X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
+
+ X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32)
+ X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
+ X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
+ X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
+
+ X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64)
+ X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
+ X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
+
+ X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80)
+ X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80)
+ X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32)
+ X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
+ X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
+ X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
+
+ /* ======================= */
+
+ X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
+
+#undef X
+
+#define Y(t1,t2) impcnvWarnTab[t1][t2] = 1;
+
+ Y(Tuns8, Tint8)
+ Y(Tint16, Tint8)
+ Y(Tuns16, Tint8)
+ Y(Tint32, Tint8)
+ Y(Tuns32, Tint8)
+ Y(Tint64, Tint8)
+ Y(Tuns64, Tint8)
+ Y(Tint128, Tint8)
+ Y(Tuns128, Tint8)
+
+ Y(Tint8, Tuns8)
+ Y(Tint16, Tuns8)
+ Y(Tuns16, Tuns8)
+ Y(Tint32, Tuns8)
+ Y(Tuns32, Tuns8)
+ Y(Tint64, Tuns8)
+ Y(Tuns64, Tuns8)
+ Y(Tint128, Tuns8)
+ Y(Tuns128, Tuns8)
+
+ Y(Tint8, Tchar)
+ Y(Tint16, Tchar)
+ Y(Tuns16, Tchar)
+ Y(Tint32, Tchar)
+ Y(Tuns32, Tchar)
+ Y(Tint64, Tchar)
+ Y(Tuns64, Tchar)
+ Y(Tint128, Tchar)
+ Y(Tuns128, Tchar)
+
+ Y(Tuns16, Tint16)
+ Y(Tint32, Tint16)
+ Y(Tuns32, Tint16)
+ Y(Tint64, Tint16)
+ Y(Tuns64, Tint16)
+ Y(Tint128, Tint16)
+ Y(Tuns128, Tint16)
+
+ Y(Tint16, Tuns16)
+ Y(Tint32, Tuns16)
+ Y(Tuns32, Tuns16)
+ Y(Tint64, Tuns16)
+ Y(Tuns64, Tuns16)
+ Y(Tint128, Tuns16)
+ Y(Tuns128, Tuns16)
+
+ Y(Tint16, Twchar)
+ Y(Tint32, Twchar)
+ Y(Tuns32, Twchar)
+ Y(Tint64, Twchar)
+ Y(Tuns64, Twchar)
+ Y(Tint128, Twchar)
+ Y(Tuns128, Twchar)
+
+// Y(Tuns32, Tint32)
+ Y(Tint64, Tint32)
+ Y(Tuns64, Tint32)
+ Y(Tint128, Tint32)
+ Y(Tuns128, Tint32)
+
+// Y(Tint32, Tuns32)
+ Y(Tint64, Tuns32)
+ Y(Tuns64, Tuns32)
+ Y(Tint128, Tuns32)
+ Y(Tuns128, Tuns32)
+
+ Y(Tint64, Tdchar)
+ Y(Tuns64, Tdchar)
+ Y(Tint128, Tdchar)
+ Y(Tuns128, Tdchar)
+
+// Y(Tint64, Tuns64)
+// Y(Tuns64, Tint64)
+ Y(Tint128, Tint64)
+ Y(Tuns128, Tint64)
+ Y(Tint128, Tuns64)
+ Y(Tuns128, Tuns64)
+
+// Y(Tint128, Tuns128)
+// Y(Tuns128, Tint128)
+
+ for (i = 0; i < TMAX; i++)
+ for (j = 0; j < TMAX; j++)
+ {
+ if (impcnvResultTab[i][j] == Terror)
+ {
+ impcnvResultTab[i][j] = impcnvResultTab[j][i];
+ impcnvType1Tab[i][j] = impcnvType2Tab[j][i];
+ impcnvType2Tab[i][j] = impcnvType1Tab[j][i];
+ }
+ }
+}
+
+int main()
+{
+ int i;
+ int j;
+
+ init();
+
+ {
+ FILE *fp = fopen("impcnvtab.c","wb");
+
+ fprintf(fp,"// This file is generated by impcnvgen.c\n");
+ fprintf(fp,"#include \"mtype.h\"\n");
+
+ fprintf(fp,"unsigned char impcnvResult[TMAX][TMAX] =\n{\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",");
+ fprintf(fp, "{");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d",impcnvResultTab[i][j]);
+ }
+ fprintf(fp, "}\n");
+ }
+ fprintf(fp,"};\n");
+
+ fprintf(fp,"unsigned char impcnvType1[TMAX][TMAX] =\n{\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",");
+ fprintf(fp, "{");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d",impcnvType1Tab[i][j]);
+ }
+ fprintf(fp, "}\n");
+ }
+ fprintf(fp,"};\n");
+
+ fprintf(fp,"unsigned char impcnvType2[TMAX][TMAX] =\n{\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",");
+ fprintf(fp, "{");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d",impcnvType2Tab[i][j]);
+ }
+ fprintf(fp, "}\n");
+ }
+ fprintf(fp,"};\n");
+
+ fprintf(fp,"unsigned char impcnvWarn[TMAX][TMAX] =\n{\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",");
+ fprintf(fp, "{");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d",impcnvWarnTab[i][j]);
+ }
+ fprintf(fp, "}\n");
+ }
+ fprintf(fp,"};\n");
+
+ fclose(fp);
+ }
+
+ {
+ FILE *fp = fopen("impcnvtab.d", "wb");
+
+ fprintf(fp, "// This file is generated by impcnvgen.c\n");
+ fprintf(fp, "module ddmd.impcnvtab;\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "import ddmd.mtype;\n");
+ fprintf(fp, "\n");
+
+ fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvResult =\n[\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",\n");
+ fprintf(fp, " [");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d", impcnvResultTab[i][j]);
+ }
+ fprintf(fp, "]");
+ }
+ fprintf(fp, "\n];\n");
+
+ fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvType1 =\n[\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",\n");
+ fprintf(fp, " [");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d", impcnvType1Tab[i][j]);
+ }
+ fprintf(fp, "]");
+ }
+ fprintf(fp, "\n];\n");
+
+ fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvType2 =\n[\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",\n");
+ fprintf(fp, " [");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d",impcnvType2Tab[i][j]);
+ }
+ fprintf(fp, "]");
+ }
+ fprintf(fp,"\n];\n");
+
+ fprintf(fp,"extern (C++) __gshared ubyte[TMAX][TMAX] impcnvWarn =\n[\n");
+ for (i = 0; i < TMAX; i++)
+ {
+ if (i)
+ fprintf(fp, ",\n");
+ fprintf(fp, " [");
+ for (j = 0; j < TMAX; j++)
+ {
+ if (j)
+ fprintf(fp, ",");
+ fprintf(fp, "%d", impcnvWarnTab[i][j]);
+ }
+ fprintf(fp, "]");
+ }
+ fprintf(fp, "\n];\n");
+
+ fclose(fp);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/gcc/d/dmd/imphint.c b/gcc/d/dmd/imphint.c
new file mode 100644
index 0000000..6d75603
--- /dev/null
+++ b/gcc/d/dmd/imphint.c
@@ -0,0 +1,56 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2010-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/imphint.c
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+
+#include "mars.h"
+
+/******************************************
+ * Looks for undefined identifier s to see
+ * if it might be undefined because an import
+ * was not specified.
+ * Not meant to be a comprehensive list of names in each module,
+ * just the most common ones.
+ */
+
+const char *importHint(const char *s)
+{
+ static const char *modules[] =
+ { "core.stdc.stdio",
+ "std.stdio",
+ "std.math",
+ NULL
+ };
+ static const char *names[] =
+ {
+ "printf", NULL,
+ "writeln", NULL,
+ "sin", "cos", "sqrt", "fabs", NULL,
+ };
+ int m = 0;
+ for (int n = 0; modules[m]; n++)
+ {
+ const char *p = names[n];
+ if (p == NULL)
+ {
+ m++;
+ continue;
+ }
+ assert(modules[m]);
+ if (strcmp(s, p) == 0)
+ return modules[m];
+ }
+ return NULL; // didn't find it
+}
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
new file mode 100644
index 0000000..e0fa14d
--- /dev/null
+++ b/gcc/d/dmd/import.h
@@ -0,0 +1,60 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/import.h
+ */
+
+#pragma once
+
+#include "dsymbol.h"
+
+class Identifier;
+struct Scope;
+class Module;
+class Package;
+class AliasDeclaration;
+
+class Import : public Dsymbol
+{
+public:
+ /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
+ */
+
+ Identifiers *packages; // array of Identifier's representing packages
+ Identifier *id; // module Identifier
+ Identifier *aliasId;
+ int isstatic; // !=0 if static import
+ Prot protection;
+
+ // Pairs of alias=name to bind into current namespace
+ Identifiers names;
+ Identifiers aliases;
+
+ Module *mod;
+ Package *pkg; // leftmost package/module
+
+ AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs
+
+ Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
+ int isstatic);
+ void addAlias(Identifier *name, Identifier *alias);
+ const char *kind();
+ Prot prot();
+ Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
+ void load(Scope *sc);
+ void importAll(Scope *sc);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ Dsymbol *toAlias();
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void setScope(Scope* sc);
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ bool overloadInsert(Dsymbol *s);
+
+ Import *isImport() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/init.c b/gcc/d/dmd/init.c
new file mode 100644
index 0000000..e619cb4
--- /dev/null
+++ b/gcc/d/dmd/init.c
@@ -0,0 +1,286 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/init.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "checkedint.h"
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "identifier.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "hdrgen.h"
+#include "template.h"
+#include "id.h"
+#include "tokens.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+/********************************** Initializer *******************************/
+
+Initializer::Initializer(Loc loc)
+{
+ this->loc = loc;
+}
+
+Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
+{
+ Initializers *a = NULL;
+ if (ai)
+ {
+ a = new Initializers();
+ a->setDim(ai->dim);
+ for (size_t i = 0; i < a->dim; i++)
+ (*a)[i] = (*ai)[i]->syntaxCopy();
+ }
+ return a;
+}
+
+const char *Initializer::toChars()
+{
+ OutBuffer buf;
+ HdrGenState hgs;
+ ::toCBuffer(this, &buf, &hgs);
+ return buf.extractString();
+}
+
+/********************************** ErrorInitializer ***************************/
+
+ErrorInitializer::ErrorInitializer()
+ : Initializer(Loc())
+{
+}
+
+Initializer *ErrorInitializer::syntaxCopy()
+{
+ return this;
+}
+
+/********************************** VoidInitializer ***************************/
+
+VoidInitializer::VoidInitializer(Loc loc)
+ : Initializer(loc)
+{
+ type = NULL;
+}
+
+Initializer *VoidInitializer::syntaxCopy()
+{
+ return new VoidInitializer(loc);
+}
+
+/********************************** StructInitializer *************************/
+
+StructInitializer::StructInitializer(Loc loc)
+ : Initializer(loc)
+{
+}
+
+Initializer *StructInitializer::syntaxCopy()
+{
+ StructInitializer *ai = new StructInitializer(loc);
+ assert(field.dim == value.dim);
+ ai->field.setDim(field.dim);
+ ai->value.setDim(value.dim);
+ for (size_t i = 0; i < field.dim; i++)
+ {
+ ai->field[i] = field[i];
+ ai->value[i] = value[i]->syntaxCopy();
+ }
+ return ai;
+}
+
+void StructInitializer::addInit(Identifier *field, Initializer *value)
+{
+ //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
+ this->field.push(field);
+ this->value.push(value);
+}
+
+/********************************** ArrayInitializer ************************************/
+
+ArrayInitializer::ArrayInitializer(Loc loc)
+ : Initializer(loc)
+{
+ dim = 0;
+ type = NULL;
+ sem = false;
+}
+
+Initializer *ArrayInitializer::syntaxCopy()
+{
+ //printf("ArrayInitializer::syntaxCopy()\n");
+ ArrayInitializer *ai = new ArrayInitializer(loc);
+ assert(index.dim == value.dim);
+ ai->index.setDim(index.dim);
+ ai->value.setDim(value.dim);
+ for (size_t i = 0; i < ai->value.dim; i++)
+ {
+ ai->index[i] = index[i] ? index[i]->syntaxCopy() : NULL;
+ ai->value[i] = value[i]->syntaxCopy();
+ }
+ return ai;
+}
+
+void ArrayInitializer::addInit(Expression *index, Initializer *value)
+{
+ this->index.push(index);
+ this->value.push(value);
+ dim = 0;
+ type = NULL;
+}
+
+bool ArrayInitializer::isAssociativeArray()
+{
+ for (size_t i = 0; i < value.dim; i++)
+ {
+ if (index[i])
+ return true;
+ }
+ return false;
+}
+
+/********************************
+ * If possible, convert array initializer to associative array initializer.
+ */
+
+Expression *ArrayInitializer::toAssocArrayLiteral()
+{
+ Expression *e;
+
+ //printf("ArrayInitializer::toAssocArrayInitializer()\n");
+ //static int i; if (++i == 2) halt();
+ Expressions *keys = new Expressions();
+ keys->setDim(value.dim);
+ Expressions *values = new Expressions();
+ values->setDim(value.dim);
+
+ for (size_t i = 0; i < value.dim; i++)
+ {
+ e = index[i];
+ if (!e)
+ goto Lno;
+ (*keys)[i] = e;
+
+ Initializer *iz = value[i];
+ if (!iz)
+ goto Lno;
+ e = initializerToExpression(iz);
+ if (!e)
+ goto Lno;
+ (*values)[i] = e;
+ }
+ e = new AssocArrayLiteralExp(loc, keys, values);
+ return e;
+
+Lno:
+ delete keys;
+ delete values;
+ error(loc, "not an associative array initializer");
+ return new ErrorExp();
+}
+
+/********************************** ExpInitializer ************************************/
+
+ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
+ : Initializer(loc)
+{
+ this->exp = exp;
+ this->expandTuples = false;
+}
+
+Initializer *ExpInitializer::syntaxCopy()
+{
+ return new ExpInitializer(loc, exp->syntaxCopy());
+}
+
+#if 1 // should be removed and rely on ctfeInterpreter()
+bool arrayHasNonConstPointers(Expressions *elems);
+
+bool hasNonConstPointers(Expression *e)
+{
+ if (e->type->ty == Terror)
+ return false;
+
+ if (e->op == TOKnull)
+ return false;
+ if (e->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ return arrayHasNonConstPointers(se->elements);
+ }
+ if (e->op == TOKarrayliteral)
+ {
+ if (!e->type->nextOf()->hasPointers())
+ return false;
+ ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
+ return arrayHasNonConstPointers(ae->elements);
+ }
+ if (e->op == TOKassocarrayliteral)
+ {
+ AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
+ if (ae->type->nextOf()->hasPointers() &&
+ arrayHasNonConstPointers(ae->values))
+ return true;
+ if (((TypeAArray *)ae->type)->index->hasPointers())
+ return arrayHasNonConstPointers(ae->keys);
+ return false;
+ }
+ if(e->op == TOKaddress)
+ {
+ AddrExp *ae = (AddrExp *)e;
+ if (ae->e1->op == TOKstructliteral)
+ {
+ StructLiteralExp *se = (StructLiteralExp *)ae->e1;
+ if (!(se->stageflags & stageSearchPointers))
+ {
+ int old = se->stageflags;
+ se->stageflags |= stageSearchPointers;
+ bool ret = arrayHasNonConstPointers(se->elements);
+ se->stageflags = old;
+ return ret;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
+ {
+ if (e->op == TOKsymoff) // address of a global is OK
+ return false;
+ if (e->op == TOKint64) // cast(void *)int is OK
+ return false;
+ if (e->op == TOKstring) // "abc".ptr is OK
+ return false;
+ return true;
+ }
+ return false;
+}
+
+bool arrayHasNonConstPointers(Expressions *elems)
+{
+ for (size_t i = 0; i < elems->dim; i++)
+ {
+ Expression *e = (*elems)[i];
+ if (e && hasNonConstPointers(e))
+ return true;
+ }
+ return false;
+}
+#endif
diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h
new file mode 100644
index 0000000..f4a150f
--- /dev/null
+++ b/gcc/d/dmd/init.h
@@ -0,0 +1,119 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/init.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+
+#include "globals.h"
+#include "arraytypes.h"
+#include "visitor.h"
+
+class Identifier;
+class Expression;
+struct Scope;
+class Type;
+class AggregateDeclaration;
+class ErrorInitializer;
+class VoidInitializer;
+class StructInitializer;
+class ArrayInitializer;
+class ExpInitializer;
+
+enum NeedInterpret { INITnointerpret, INITinterpret };
+
+class Initializer : public RootObject
+{
+public:
+ Loc loc;
+
+ Initializer(Loc loc);
+ virtual Initializer *syntaxCopy() = 0;
+ static Initializers *arraySyntaxCopy(Initializers *ai);
+
+ const char *toChars();
+
+ virtual ErrorInitializer *isErrorInitializer() { return NULL; }
+ virtual VoidInitializer *isVoidInitializer() { return NULL; }
+ virtual StructInitializer *isStructInitializer() { return NULL; }
+ virtual ArrayInitializer *isArrayInitializer() { return NULL; }
+ virtual ExpInitializer *isExpInitializer() { return NULL; }
+ virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class VoidInitializer : public Initializer
+{
+public:
+ Type *type; // type that this will initialize to
+
+ VoidInitializer(Loc loc);
+ Initializer *syntaxCopy();
+
+ virtual VoidInitializer *isVoidInitializer() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ErrorInitializer : public Initializer
+{
+public:
+ ErrorInitializer();
+ Initializer *syntaxCopy();
+
+ virtual ErrorInitializer *isErrorInitializer() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StructInitializer : public Initializer
+{
+public:
+ Identifiers field; // of Identifier *'s
+ Initializers value; // parallel array of Initializer *'s
+
+ StructInitializer(Loc loc);
+ Initializer *syntaxCopy();
+ void addInit(Identifier *field, Initializer *value);
+
+ StructInitializer *isStructInitializer() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ArrayInitializer : public Initializer
+{
+public:
+ Expressions index; // indices
+ Initializers value; // of Initializer *'s
+ unsigned dim; // length of array being initialized
+ Type *type; // type that array will be used to initialize
+ bool sem; // true if semantic() is run
+
+ ArrayInitializer(Loc loc);
+ Initializer *syntaxCopy();
+ void addInit(Expression *index, Initializer *value);
+ bool isAssociativeArray();
+ Expression *toAssocArrayLiteral();
+
+ ArrayInitializer *isArrayInitializer() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ExpInitializer : public Initializer
+{
+public:
+ Expression *exp;
+ bool expandTuples;
+
+ ExpInitializer(Loc loc, Expression *exp);
+ Initializer *syntaxCopy();
+
+ ExpInitializer *isExpInitializer() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+Expression *initializerToExpression(Initializer *init, Type *t = NULL);
diff --git a/gcc/d/dmd/initsem.c b/gcc/d/dmd/initsem.c
new file mode 100644
index 0000000..bdaf253
--- /dev/null
+++ b/gcc/d/dmd/initsem.c
@@ -0,0 +1,920 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include "checkedint.h"
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "mtype.h"
+#include "template.h"
+#include "id.h"
+
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+Expression *semantic(Expression *e, Scope *sc);
+Initializer *inferType(Initializer *init, Scope *sc);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+bool hasNonConstPointers(Expression *e);
+
+class InitializerSemanticVisitor : public Visitor
+{
+public:
+ Initializer *result;
+ Scope *sc;
+ Type *t;
+ NeedInterpret needInterpret;
+
+ InitializerSemanticVisitor(Scope *sc, Type *t, NeedInterpret needInterpret)
+ {
+ this->result = NULL;
+ this->sc = sc;
+ this->t = t;
+ this->needInterpret = needInterpret;
+ }
+
+ void visit(ErrorInitializer *i)
+ {
+ //printf("ErrorInitializer::semantic(t = %p)\n", t);
+ result = i;
+ }
+
+ void visit(VoidInitializer *i)
+ {
+ //printf("VoidInitializer::semantic(t = %p)\n", t);
+ i->type = t;
+ result = i;
+ }
+
+ void visit(StructInitializer *i)
+ {
+ //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
+ t = t->toBasetype();
+ if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct)
+ t = t->nextOf()->toBasetype();
+ if (t->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)t)->sym;
+ if (sd->ctor)
+ {
+ error(i->loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
+ sd->kind(), sd->toChars(), sd->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+ sd->size(i->loc);
+ if (sd->sizeok != SIZEOKdone)
+ {
+ result = new ErrorInitializer();
+ return;
+ }
+ size_t nfields = sd->fields.dim - sd->isNested();
+
+ //expandTuples for non-identity arguments?
+
+ Expressions *elements = new Expressions();
+ elements->setDim(nfields);
+ for (size_t j = 0; j < elements->dim; j++)
+ (*elements)[j] = NULL;
+
+ // Run semantic for explicitly given initializers
+ // TODO: this part is slightly different from StructLiteralExp::semantic.
+ bool errors = false;
+ for (size_t fieldi = 0, j = 0; j < i->field.dim; j++)
+ {
+ if (Identifier *id = i->field[j])
+ {
+ Dsymbol *s = sd->search(i->loc, id);
+ if (!s)
+ {
+ s = sd->search_correct(id);
+ if (s)
+ error(i->loc, "'%s' is not a member of '%s', did you mean %s '%s'?",
+ id->toChars(), sd->toChars(), s->kind(), s->toChars());
+ else
+ error(i->loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+ s = s->toAlias();
+
+ // Find out which field index it is
+ for (fieldi = 0; 1; fieldi++)
+ {
+ if (fieldi >= nfields)
+ {
+ error(i->loc, "%s.%s is not a per-instance initializable field",
+ sd->toChars(), s->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+ if (s == sd->fields[fieldi])
+ break;
+ }
+ }
+ else if (fieldi >= nfields)
+ {
+ error(i->loc, "too many initializers for %s", sd->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+
+ VarDeclaration *vd = sd->fields[fieldi];
+ if ((*elements)[fieldi])
+ {
+ error(i->loc, "duplicate initializer for field '%s'", vd->toChars());
+ errors = true;
+ continue;
+ }
+ for (size_t k = 0; k < nfields; k++)
+ {
+ VarDeclaration *v2 = sd->fields[k];
+ if (vd->isOverlappedWith(v2) && (*elements)[k])
+ {
+ error(i->loc, "overlapping initialization for field %s and %s",
+ v2->toChars(), vd->toChars());
+ errors = true;
+ continue;
+ }
+ }
+
+ assert(sc);
+ Initializer *iz = i->value[j];
+ iz = ::semantic(iz, sc, vd->type->addMod(t->mod), needInterpret);
+ Expression *ex = initializerToExpression(iz);
+ if (ex->op == TOKerror)
+ {
+ errors = true;
+ continue;
+ }
+ i->value[j] = iz;
+ (*elements)[fieldi] = doCopyOrMove(sc, ex);
+ ++fieldi;
+ }
+ if (errors)
+ {
+ result = new ErrorInitializer();
+ return;
+ }
+
+ StructLiteralExp *sle = new StructLiteralExp(i->loc, sd, elements, t);
+ if (!sd->fill(i->loc, elements, false))
+ {
+ result = new ErrorInitializer();
+ return;
+ }
+ sle->type = t;
+
+ ExpInitializer *ie = new ExpInitializer(i->loc, sle);
+ result = ::semantic(ie, sc, t, needInterpret);
+ return;
+ }
+ else if ((t->ty == Tdelegate || (t->ty == Tpointer && t->nextOf()->ty == Tfunction)) && i->value.dim == 0)
+ {
+ TOK tok = (t->ty == Tdelegate) ? TOKdelegate : TOKfunction;
+ /* Rewrite as empty delegate literal { }
+ */
+ Parameters *parameters = new Parameters;
+ Type *tf = new TypeFunction(parameters, NULL, 0, LINKd);
+ FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(i->loc, Loc(), tf, tok, NULL);
+ fd->fbody = new CompoundStatement(i->loc, new Statements());
+ fd->endloc = i->loc;
+ Expression *e = new FuncExp(i->loc, fd);
+ ExpInitializer *ie = new ExpInitializer(i->loc, e);
+ result = ::semantic(ie, sc, t, needInterpret);
+ return;
+ }
+
+ error(i->loc, "a struct is not a valid initializer for a %s", t->toChars());
+ result = new ErrorInitializer();
+ }
+
+ void visit(ArrayInitializer *i)
+ {
+ unsigned length;
+ const unsigned amax = 0x80000000;
+ bool errors = false;
+
+ //printf("ArrayInitializer::semantic(%s)\n", t->toChars());
+ if (i->sem) // if semantic() already run
+ {
+ result = i;
+ return;
+ }
+ i->sem = true;
+ t = t->toBasetype();
+ switch (t->ty)
+ {
+ case Tsarray:
+ case Tarray:
+ break;
+
+ case Tvector:
+ t = ((TypeVector *)t)->basetype;
+ break;
+
+ case Taarray:
+ case Tstruct: // consider implicit constructor call
+ {
+ Expression *e;
+ // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
+ if (t->ty == Taarray || i->isAssociativeArray())
+ e = i->toAssocArrayLiteral();
+ else
+ e = initializerToExpression(i);
+ if (!e) // Bugzilla 13987
+ {
+ error(i->loc, "cannot use array to initialize %s", t->toChars());
+ goto Lerr;
+ }
+ ExpInitializer *ei = new ExpInitializer(e->loc, e);
+ result = ::semantic(ei, sc, t, needInterpret);
+ return;
+ }
+ case Tpointer:
+ if (t->nextOf()->ty != Tfunction)
+ break;
+ /* fall through */
+
+ default:
+ error(i->loc, "cannot use array to initialize %s", t->toChars());
+ goto Lerr;
+ }
+
+ i->type = t;
+
+ length = 0;
+ for (size_t j = 0; j < i->index.dim; j++)
+ {
+ Expression *idx = i->index[j];
+ if (idx)
+ {
+ sc = sc->startCTFE();
+ idx = ::semantic(idx, sc);
+ sc = sc->endCTFE();
+ idx = idx->ctfeInterpret();
+ i->index[j] = idx;
+ const uinteger_t idxvalue = idx->toInteger();
+ if (idxvalue >= amax)
+ {
+ error(i->loc, "array index %llu overflow", (ulonglong)idxvalue);
+ errors = true;
+ }
+ length = (unsigned)idx->toInteger();
+ if (idx->op == TOKerror)
+ errors = true;
+ }
+
+ Initializer *val = i->value[j];
+ ExpInitializer *ei = val->isExpInitializer();
+ if (ei && !idx)
+ ei->expandTuples = true;
+ val = ::semantic(val, sc, t->nextOf(), needInterpret);
+ if (val->isErrorInitializer())
+ errors = true;
+
+ ei = val->isExpInitializer();
+ // found a tuple, expand it
+ if (ei && ei->exp->op == TOKtuple)
+ {
+ TupleExp *te = (TupleExp *)ei->exp;
+ i->index.remove(j);
+ i->value.remove(j);
+
+ for (size_t k = 0; k < te->exps->dim; ++k)
+ {
+ Expression *e = (*te->exps)[k];
+ i->index.insert(j + k, (Expression *)NULL);
+ i->value.insert(j + k, new ExpInitializer(e->loc, e));
+ }
+ j--;
+ continue;
+ }
+ else
+ {
+ i->value[j] = val;
+ }
+
+ length++;
+ if (length == 0)
+ {
+ error(i->loc, "array dimension overflow");
+ goto Lerr;
+ }
+ if (length > i->dim)
+ i->dim = length;
+ }
+ if (t->ty == Tsarray)
+ {
+ uinteger_t edim = ((TypeSArray *)t)->dim->toInteger();
+ if (i->dim > edim)
+ {
+ error(i->loc, "array initializer has %u elements, but array length is %llu", i->dim, (ulonglong)edim);
+ goto Lerr;
+ }
+ }
+ if (errors)
+ goto Lerr;
+ else
+ {
+ d_uns64 sz = t->nextOf()->size();
+ bool overflow = false;
+ const d_uns64 max = mulu((d_uns64)i->dim, sz, overflow);
+ if (overflow || max > amax)
+ {
+ error(i->loc, "array dimension %llu exceeds max of %llu", (ulonglong)i->dim, (ulonglong)(amax / sz));
+ goto Lerr;
+ }
+ result = i;
+ return;
+ }
+
+ Lerr:
+ result = new ErrorInitializer();
+ }
+
+ void visit(ExpInitializer *i)
+ {
+ //printf("ExpInitializer::semantic(%s), type = %s\n", i->exp->toChars(), t->toChars());
+ if (needInterpret) sc = sc->startCTFE();
+ i->exp = ::semantic(i->exp, sc);
+ i->exp = resolveProperties(sc, i->exp);
+ if (needInterpret) sc = sc->endCTFE();
+ if (i->exp->op == TOKerror)
+ {
+ result = new ErrorInitializer();
+ return;
+ }
+
+ unsigned int olderrors = global.errors;
+ if (needInterpret)
+ {
+ // If the result will be implicitly cast, move the cast into CTFE
+ // to avoid premature truncation of polysemous types.
+ // eg real [] x = [1.1, 2.2]; should use real precision.
+ if (i->exp->implicitConvTo(t))
+ {
+ i->exp = i->exp->implicitCastTo(sc, t);
+ }
+ if (!global.gag && olderrors != global.errors)
+ {
+ result = i;
+ return;
+ }
+ i->exp = i->exp->ctfeInterpret();
+ }
+ else
+ {
+ i->exp = i->exp->optimize(WANTvalue);
+ }
+ if (!global.gag && olderrors != global.errors)
+ {
+ result = i; // Failed, suppress duplicate error messages
+ return;
+ }
+
+ if (i->exp->type->ty == Ttuple && ((TypeTuple *)i->exp->type)->arguments->dim == 0)
+ {
+ Type *et = i->exp->type;
+ i->exp = new TupleExp(i->exp->loc, new Expressions());
+ i->exp->type = et;
+ }
+ if (i->exp->op == TOKtype)
+ {
+ i->exp->error("initializer must be an expression, not '%s'", i->exp->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+
+ // Make sure all pointers are constants
+ if (needInterpret && hasNonConstPointers(i->exp))
+ {
+ i->exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", i->exp->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+
+ Type *tb = t->toBasetype();
+ Type *ti = i->exp->type->toBasetype();
+
+ if (i->exp->op == TOKtuple && i->expandTuples && !i->exp->implicitConvTo(t))
+ {
+ result = new ExpInitializer(i->loc, i->exp);
+ return;
+ }
+
+ /* Look for case of initializing a static array with a too-short
+ * string literal, such as:
+ * char[5] foo = "abc";
+ * Allow this by doing an explicit cast, which will lengthen the string
+ * literal.
+ */
+ if (i->exp->op == TOKstring && tb->ty == Tsarray)
+ {
+ StringExp *se = (StringExp *)i->exp;
+ Type *typeb = se->type->toBasetype();
+ TY tynto = tb->nextOf()->ty;
+ if (!se->committed &&
+ (typeb->ty == Tarray || typeb->ty == Tsarray) &&
+ (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
+ se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
+ {
+ i->exp = se->castTo(sc, t);
+ goto L1;
+ }
+ }
+
+ // Look for implicit constructor call
+ if (tb->ty == Tstruct &&
+ !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) &&
+ !i->exp->implicitConvTo(t))
+ {
+ StructDeclaration *sd = ((TypeStruct *)tb)->sym;
+ if (sd->ctor)
+ {
+ // Rewrite as S().ctor(exp)
+ Expression *e;
+ e = new StructLiteralExp(i->loc, sd, NULL);
+ e = new DotIdExp(i->loc, e, Id::ctor);
+ e = new CallExp(i->loc, e, i->exp);
+ e = ::semantic(e, sc);
+ if (needInterpret)
+ i->exp = e->ctfeInterpret();
+ else
+ i->exp = e->optimize(WANTvalue);
+ }
+ }
+
+ // Look for the case of statically initializing an array
+ // with a single member.
+ if (tb->ty == Tsarray &&
+ !tb->nextOf()->equals(ti->toBasetype()->nextOf()) &&
+ i->exp->implicitConvTo(tb->nextOf())
+ )
+ {
+ /* If the variable is not actually used in compile time, array creation is
+ * redundant. So delay it until invocation of toExpression() or toDt().
+ */
+ t = tb->nextOf();
+ }
+
+ if (i->exp->implicitConvTo(t))
+ {
+ i->exp = i->exp->implicitCastTo(sc, t);
+ }
+ else
+ {
+ // Look for mismatch of compile-time known length to emit
+ // better diagnostic message, as same as AssignExp::semantic.
+ if (tb->ty == Tsarray &&
+ i->exp->implicitConvTo(tb->nextOf()->arrayOf()) > MATCHnomatch)
+ {
+ uinteger_t dim1 = ((TypeSArray *)tb)->dim->toInteger();
+ uinteger_t dim2 = dim1;
+ if (i->exp->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)i->exp;
+ dim2 = ale->elements ? ale->elements->dim : 0;
+ }
+ else if (i->exp->op == TOKslice)
+ {
+ Type *tx = toStaticArrayType((SliceExp *)i->exp);
+ if (tx)
+ dim2 = ((TypeSArray *)tx)->dim->toInteger();
+ }
+ if (dim1 != dim2)
+ {
+ i->exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
+ i->exp = new ErrorExp();
+ }
+ }
+ i->exp = i->exp->implicitCastTo(sc, t);
+ }
+ L1:
+ if (i->exp->op == TOKerror)
+ {
+ result = i;
+ return;
+ }
+ if (needInterpret)
+ i->exp = i->exp->ctfeInterpret();
+ else
+ i->exp = i->exp->optimize(WANTvalue);
+ //printf("-ExpInitializer::semantic(): "); i->exp->print();
+ result = i;
+ }
+};
+
+// Performs semantic analisys on Initializer AST nodes
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret)
+{
+ InitializerSemanticVisitor v = InitializerSemanticVisitor(sc, t, needInterpret);
+ init->accept(&v);
+ return v.result;
+}
+
+class InferTypeVisitor : public Visitor
+{
+public:
+ Initializer *result;
+ Scope *sc;
+
+ InferTypeVisitor(Scope *sc)
+ {
+ this->result = NULL;
+ this->sc = sc;
+ }
+
+ void visit(ErrorInitializer *i)
+ {
+ result = i;
+ }
+
+ void visit(VoidInitializer *i)
+ {
+ error(i->loc, "cannot infer type from void initializer");
+ result = new ErrorInitializer();
+ }
+
+ void visit(StructInitializer *i)
+ {
+ error(i->loc, "cannot infer type from struct initializer");
+ result = new ErrorInitializer();
+ }
+
+ void visit(ArrayInitializer *init)
+ {
+ //printf("ArrayInitializer::inferType() %s\n", init->toChars());
+ Expressions *keys = NULL;
+ Expressions *values;
+ if (init->isAssociativeArray())
+ {
+ keys = new Expressions();
+ keys->setDim(init->value.dim);
+ values = new Expressions();
+ values->setDim(init->value.dim);
+
+ for (size_t i = 0; i < init->value.dim; i++)
+ {
+ Expression *e = init->index[i];
+ if (!e)
+ goto Lno;
+ (*keys)[i] = e;
+
+ Initializer *iz = init->value[i];
+ if (!iz)
+ goto Lno;
+ iz = inferType(iz, sc);
+ if (iz->isErrorInitializer())
+ {
+ result = iz;
+ return;
+ }
+ assert(iz->isExpInitializer());
+ (*values)[i] = ((ExpInitializer *)iz)->exp;
+ assert((*values)[i]->op != TOKerror);
+ }
+
+ Expression *e = new AssocArrayLiteralExp(init->loc, keys, values);
+ ExpInitializer *ei = new ExpInitializer(init->loc, e);
+ result = inferType(ei, sc);
+ return;
+ }
+ else
+ {
+ Expressions *elements = new Expressions();
+ elements->setDim(init->value.dim);
+ elements->zero();
+
+ for (size_t i = 0; i < init->value.dim; i++)
+ {
+ assert(!init->index[i]); // already asserted by isAssociativeArray()
+
+ Initializer *iz = init->value[i];
+ if (!iz)
+ goto Lno;
+ iz = inferType(iz, sc);
+ if (iz->isErrorInitializer())
+ {
+ result = iz;
+ return;
+ }
+ assert(iz->isExpInitializer());
+ (*elements)[i] = ((ExpInitializer *)iz)->exp;
+ assert((*elements)[i]->op != TOKerror);
+ }
+
+ Expression *e = new ArrayLiteralExp(init->loc, elements);
+ ExpInitializer *ei = new ExpInitializer(init->loc, e);
+ result = inferType(ei, sc);
+ return;
+ }
+ Lno:
+ if (keys)
+ {
+ delete keys;
+ delete values;
+ error(init->loc, "not an associative array initializer");
+ }
+ else
+ {
+ error(init->loc, "cannot infer type from array initializer");
+ }
+ result = new ErrorInitializer();
+ }
+
+ void visit(ExpInitializer *init)
+ {
+ //printf("ExpInitializer::inferType() %s\n", init->toChars());
+ init->exp = ::semantic(init->exp, sc);
+ init->exp = resolveProperties(sc, init->exp);
+
+ if (init->exp->op == TOKscope)
+ {
+ ScopeExp *se = (ScopeExp *)init->exp;
+ TemplateInstance *ti = se->sds->isTemplateInstance();
+ if (ti && ti->semanticRun == PASSsemantic && !ti->aliasdecl)
+ se->error("cannot infer type from %s %s, possible circular dependency", se->sds->kind(), se->toChars());
+ else
+ se->error("cannot infer type from %s %s", se->sds->kind(), se->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+
+ // Give error for overloaded function addresses
+ bool hasOverloads = false;
+ if (FuncDeclaration *f = isFuncAddress(init->exp, &hasOverloads))
+ {
+ if (f->checkForwardRef(init->loc))
+ {
+ result = new ErrorInitializer();
+ return;
+ }
+
+ if (hasOverloads && !f->isUnique())
+ {
+ init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+ }
+ if (init->exp->op == TOKaddress)
+ {
+ AddrExp *ae = (AddrExp *)init->exp;
+ if (ae->e1->op == TOKoverloadset)
+ {
+ init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
+ result = new ErrorInitializer();
+ return;
+ }
+ }
+
+ if (init->exp->op == TOKerror)
+ {
+ result = new ErrorInitializer();
+ return;
+ }
+ if (!init->exp->type)
+ {
+ result = new ErrorInitializer();
+ return;
+ }
+ result = init;
+ }
+};
+
+/* Translates to an expression to infer type.
+ * Returns ExpInitializer or ErrorInitializer.
+ */
+Initializer *inferType(Initializer *init, Scope *sc)
+{
+ InferTypeVisitor v = InferTypeVisitor(sc);
+ init->accept(&v);
+ return v.result;
+}
+
+class InitToExpressionVisitor : public Visitor
+{
+public:
+ Expression *result;
+ Type *itype;
+
+ InitToExpressionVisitor(Type *itype)
+ {
+ this->result = NULL;
+ this->itype = itype;
+ }
+
+ void visit(ErrorInitializer *)
+ {
+ result = new ErrorExp();
+ }
+
+ void visit(VoidInitializer *)
+ {
+ result = NULL;
+ }
+
+ /***************************************
+ * This works by transforming a struct initializer into
+ * a struct literal. In the future, the two should be the
+ * same thing.
+ */
+ void visit(StructInitializer *)
+ {
+ // cannot convert to an expression without target 'ad'
+ result = NULL;
+ }
+
+ /********************************
+ * If possible, convert array initializer to array literal.
+ * Otherwise return NULL.
+ */
+
+ void visit(ArrayInitializer *init)
+ {
+ //printf("ArrayInitializer::toExpression(), dim = %d\n", init->dim);
+ //static int i; if (++i == 2) halt();
+
+ Expressions *elements;
+ unsigned edim;
+ const unsigned amax = 0x80000000;
+ Type *t = NULL;
+ if (init->type)
+ {
+ if (init->type == Type::terror)
+ {
+ result = new ErrorExp();
+ return;
+ }
+
+ t = init->type->toBasetype();
+ switch (t->ty)
+ {
+ case Tvector:
+ t = ((TypeVector *)t)->basetype;
+ /* fall through */
+
+ case Tsarray:
+ {
+ uinteger_t adim = ((TypeSArray *)t)->dim->toInteger();
+ if (adim >= amax)
+ goto Lno;
+ edim = (unsigned)adim;
+ break;
+ }
+
+ case Tpointer:
+ case Tarray:
+ edim = init->dim;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ else
+ {
+ edim = (unsigned)init->value.dim;
+ for (size_t i = 0, j = 0; i < init->value.dim; i++, j++)
+ {
+ if (init->index[i])
+ {
+ if (init->index[i]->op == TOKint64)
+ {
+ const uinteger_t idxval = init->index[i]->toInteger();
+ if (idxval >= amax)
+ goto Lno;
+ j = (size_t)idxval;
+ }
+ else
+ goto Lno;
+ }
+ if (j >= edim)
+ edim = (unsigned)(j + 1);
+ }
+ }
+
+ elements = new Expressions();
+ elements->setDim(edim);
+ elements->zero();
+ for (size_t i = 0, j = 0; i < init->value.dim; i++, j++)
+ {
+ if (init->index[i])
+ j = (size_t)(init->index[i])->toInteger();
+ assert(j < edim);
+ Initializer *iz = init->value[i];
+ if (!iz)
+ goto Lno;
+ Expression *ex = initializerToExpression(iz);
+ if (!ex)
+ {
+ goto Lno;
+ }
+ (*elements)[j] = ex;
+ }
+
+ /* Fill in any missing elements with the default initializer
+ */
+ {
+ Expression *_init = NULL;
+ for (size_t i = 0; i < edim; i++)
+ {
+ if (!(*elements)[i])
+ {
+ if (!init->type)
+ goto Lno;
+ if (!_init)
+ _init = ((TypeNext *)t)->next->defaultInit();
+ (*elements)[i] = _init;
+ }
+ }
+
+ /* Expand any static array initializers that are a single expression
+ * into an array of them
+ */
+ if (t)
+ {
+ Type *tn = t->nextOf()->toBasetype();
+ if (tn->ty == Tsarray)
+ {
+ size_t dim = ((TypeSArray *)tn)->dim->toInteger();
+ Type *te = tn->nextOf()->toBasetype();
+ for (size_t i = 0; i < elements->dim; i++)
+ {
+ Expression *e = (*elements)[i];
+ if (te->equals(e->type))
+ {
+ Expressions *elements2 = new Expressions();
+ elements2->setDim(dim);
+ for (size_t j = 0; j < dim; j++)
+ (*elements2)[j] = e;
+ e = new ArrayLiteralExp(e->loc, elements2);
+ e->type = tn;
+ (*elements)[i] = e;
+ }
+ }
+ }
+ }
+
+ /* If any elements are errors, then the whole thing is an error
+ */
+ for (size_t i = 0; i < edim; i++)
+ {
+ Expression *e = (*elements)[i];
+ if (e->op == TOKerror)
+ {
+ result = e;
+ return;
+ }
+ }
+
+ Expression *e = new ArrayLiteralExp(init->loc, elements);
+ e->type = init->type;
+ result = e;
+ return;
+ }
+
+ Lno:
+ result = NULL;
+ }
+
+ void visit(ExpInitializer *i)
+ {
+ if (itype)
+ {
+ //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype->toChars(), i->exp->toChars());
+ Type *tb = itype->toBasetype();
+ Expression *e = (i->exp->op == TOKconstruct || i->exp->op == TOKblit) ? ((AssignExp *)i->exp)->e2 : i->exp;
+ if (tb->ty == Tsarray && e->implicitConvTo(tb->nextOf()))
+ {
+ TypeSArray *tsa = (TypeSArray *)tb;
+ size_t d = (size_t)tsa->dim->toInteger();
+ Expressions *elements = new Expressions();
+ elements->setDim(d);
+ for (size_t i = 0; i < d; i++)
+ (*elements)[i] = e;
+ ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, elements);
+ ae->type = itype;
+ result = ae;
+ return;
+ }
+ }
+ result = i->exp;
+ }
+};
+
+Expression *initializerToExpression(Initializer *i, Type *t)
+{
+ InitToExpressionVisitor v = InitToExpressionVisitor(t);
+ i->accept(&v);
+ return v.result;
+}
diff --git a/gcc/d/dmd/intrange.c b/gcc/d/dmd/intrange.c
new file mode 100644
index 0000000..b4d54db
--- /dev/null
+++ b/gcc/d/dmd/intrange.c
@@ -0,0 +1,460 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by KennyTM
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/intrange.c
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "intrange.h"
+#include "mars.h"
+#include "mtype.h"
+#include "expression.h"
+
+// Copy the sign to the value *x*. Equivalent to `sign ? -x : x`.
+static uinteger_t copySign(uinteger_t x, bool sign)
+{
+ // return sign ? -x : x;
+ return (x - (uinteger_t)sign) ^ -(uinteger_t)sign;
+}
+
+#ifndef UINT64_MAX
+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
+#endif
+
+//==================== SignExtendedNumber ======================================
+
+SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_)
+{
+ return SignExtendedNumber(value_, value_ >> 63);
+}
+
+bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const
+{
+ return value == a.value && negative == a.negative;
+}
+
+bool SignExtendedNumber::operator<(const SignExtendedNumber& a) const
+{
+ return (negative && !a.negative)
+ || (negative == a.negative && value < a.value);
+}
+
+SignExtendedNumber SignExtendedNumber::extreme(bool minimum)
+{
+ return SignExtendedNumber(minimum-1, minimum);
+}
+
+SignExtendedNumber SignExtendedNumber::max()
+{
+ return SignExtendedNumber(UINT64_MAX, false);
+}
+
+SignExtendedNumber SignExtendedNumber::operator-() const
+{
+ if (value == 0)
+ return SignExtendedNumber(-negative);
+ else
+ return SignExtendedNumber(-value, !negative);
+}
+
+SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const
+{
+ uinteger_t sum = value + a.value;
+ bool carry = sum < value && sum < a.value;
+ if (negative != a.negative)
+ return SignExtendedNumber(sum, !carry);
+ else if (negative)
+ return SignExtendedNumber(carry ? sum : 0, true);
+ else
+ return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
+}
+
+SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const
+{
+ if (a.isMinimum())
+ return negative ? SignExtendedNumber(value, false) : max();
+ else
+ return *this + (-a);
+}
+
+
+SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const
+{
+ // perform *saturated* multiplication, otherwise we may get bogus ranges
+ // like 0x10 * 0x10 == 0x100 == 0.
+
+ /* Special handling for zeros:
+ INT65_MIN * 0 = 0
+ INT65_MIN * + = INT65_MIN
+ INT65_MIN * - = INT65_MAX
+ 0 * anything = 0
+ */
+ if (value == 0)
+ {
+ if (!negative)
+ return *this;
+ else if (a.negative)
+ return max();
+ else
+ return a.value == 0 ? a : *this;
+ }
+ else if (a.value == 0)
+ return a * *this; // don't duplicate the symmetric case.
+
+ SignExtendedNumber rv;
+ // these are != 0 now surely.
+ uinteger_t tAbs = copySign(value, negative);
+ uinteger_t aAbs = copySign(a.value, a.negative);
+ rv.negative = negative != a.negative;
+ if (UINT64_MAX / tAbs < aAbs)
+ rv.value = rv.negative-1;
+ else
+ rv.value = copySign(tAbs * aAbs, rv.negative);
+ return rv;
+}
+
+SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const
+{
+ /* special handling for zeros:
+ INT65_MIN / INT65_MIN = 1
+ anything / INT65_MIN = 0
+ + / 0 = INT65_MAX (eh?)
+ - / 0 = INT65_MIN (eh?)
+ */
+ if (a.value == 0)
+ {
+ if (a.negative)
+ return SignExtendedNumber(value == 0 && negative);
+ else
+ return extreme(negative);
+ }
+
+ uinteger_t aAbs = copySign(a.value, a.negative);
+ uinteger_t rvVal;
+
+ if (!isMinimum())
+ rvVal = copySign(value, negative) / aAbs;
+ // Special handling for INT65_MIN
+ // if the denominator is not a power of 2, it is same as UINT64_MAX / x.
+ else if (aAbs & (aAbs-1))
+ rvVal = UINT64_MAX / aAbs;
+ // otherwise, it's the same as reversing the bits of x.
+ else
+ {
+ if (aAbs == 1)
+ return extreme(!a.negative);
+ rvVal = 1ULL << 63;
+ aAbs >>= 1;
+ if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
+ if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2;
+ if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4;
+ if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8;
+ if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
+ if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
+ }
+ bool rvNeg = negative != a.negative;
+ rvVal = copySign(rvVal, rvNeg);
+
+ return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
+}
+
+SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) const
+{
+ if (a.value == 0)
+ return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this;
+
+ uinteger_t aAbs = copySign(a.value, a.negative);
+ uinteger_t rvVal;
+
+ // a % b == sgn(a) * abs(a) % abs(b).
+ if (!isMinimum())
+ rvVal = copySign(value, negative) % aAbs;
+ // Special handling for INT65_MIN
+ // if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1.
+ else if (aAbs & (aAbs - 1))
+ rvVal = UINT64_MAX % aAbs + 1;
+ // otherwise, the modulus is trivially zero.
+ else
+ rvVal = 0;
+
+ rvVal = copySign(rvVal, negative);
+ return SignExtendedNumber(rvVal, rvVal != 0 && negative);
+}
+
+SignExtendedNumber& SignExtendedNumber::operator++()
+{
+ if (value != UINT64_MAX)
+ ++ value;
+ else if (negative)
+ {
+ value = 0;
+ negative = false;
+ }
+ return *this;
+}
+
+SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) const
+{
+ // assume left-shift the shift-amount is always unsigned. Thus negative
+ // shifts will give huge result.
+ if (value == 0)
+ return *this;
+ else if (a.negative)
+ return extreme(negative);
+
+ uinteger_t v = copySign(value, negative);
+
+ // compute base-2 log of 'v' to determine the maximum allowed bits to shift.
+ // Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
+
+ // Why is this a size_t? Looks like a bug.
+ size_t r, s;
+
+ r = (v > 0xFFFFFFFFULL) << 5; v >>= r;
+ s = (v > 0xFFFFULL ) << 4; v >>= s; r |= s;
+ s = (v > 0xFFULL ) << 3; v >>= s; r |= s;
+ s = (v > 0xFULL ) << 2; v >>= s; r |= s;
+ s = (v > 0x3ULL ) << 1; v >>= s; r |= s;
+ r |= (v >> 1);
+
+ uinteger_t allowableShift = 63 - r;
+ if (a.value > allowableShift)
+ return extreme(negative);
+ else
+ return SignExtendedNumber(value << a.value, negative);
+}
+
+SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const
+{
+ if (a.negative || a.value > 64)
+ return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
+ else if (isMinimum())
+ return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true);
+
+ uinteger_t x = value ^ -negative;
+ x >>= a.value;
+ return SignExtendedNumber(x ^ -negative, negative);
+}
+
+
+//==================== IntRange ================================================
+
+IntRange IntRange::widest()
+{
+ return IntRange(SignExtendedNumber::min(), SignExtendedNumber::max());
+}
+
+IntRange IntRange::fromType(Type *type)
+{
+ return fromType(type, type->isunsigned());
+}
+
+IntRange IntRange::fromType(Type *type, bool isUnsigned)
+{
+ if (!type->isintegral())
+ return widest();
+
+ uinteger_t mask = type->sizemask();
+ SignExtendedNumber lower(0), upper(mask);
+ if (type->toBasetype()->ty == Tdchar)
+ upper.value = 0x10FFFFULL;
+ else if (!isUnsigned)
+ {
+ lower.value = ~(mask >> 1);
+ lower.negative = true;
+ upper.value = (mask >> 1);
+ }
+ return IntRange(lower, upper);
+}
+
+IntRange IntRange::fromNumbers2(const SignExtendedNumber numbers[2])
+{
+ if (numbers[0] < numbers[1])
+ return IntRange(numbers[0], numbers[1]);
+ else
+ return IntRange(numbers[1], numbers[0]);
+}
+IntRange IntRange::fromNumbers4(const SignExtendedNumber numbers[4])
+{
+ IntRange ab = fromNumbers2(numbers);
+ IntRange cd = fromNumbers2(numbers + 2);
+ if (cd.imin < ab.imin)
+ ab.imin = cd.imin;
+ if (cd.imax > ab.imax)
+ ab.imax = cd.imax;
+ return ab;
+}
+
+bool IntRange::contains(const IntRange& a) const
+{
+ return imin <= a.imin && imax >= a.imax;
+}
+
+bool IntRange::containsZero() const
+{
+ return (imin.negative && !imax.negative)
+ || (!imin.negative && imin.value == 0);
+}
+
+IntRange& IntRange::castUnsigned(uinteger_t mask)
+{
+ // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 ....
+ //
+ // regular unsigned type. We just need to see if ir steps across the
+ // boundary of validRange. If yes, ir will represent the whole validRange,
+ // otherwise, we just take the modulus.
+ // e.g. [0x105, 0x107] & 0xff == [5, 7]
+ // [0x105, 0x207] & 0xff == [0, 0xff]
+ uinteger_t minChunk = imin.value & ~mask;
+ uinteger_t maxChunk = imax.value & ~mask;
+ if (minChunk == maxChunk && imin.negative == imax.negative)
+ {
+ imin.value &= mask;
+ imax.value &= mask;
+ }
+ else
+ {
+ imin.value = 0;
+ imax.value = mask;
+ }
+ imin.negative = imax.negative = false;
+ return *this;
+}
+
+IntRange& IntRange::castSigned(uinteger_t mask)
+{
+ // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 ....
+ //
+ // regular signed type. We use a technique similar to the unsigned version,
+ // but the chunk has to be offset by 1/2 of the range.
+ uinteger_t halfChunkMask = mask >> 1;
+ uinteger_t minHalfChunk = imin.value & ~halfChunkMask;
+ uinteger_t maxHalfChunk = imax.value & ~halfChunkMask;
+ int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max
+ int maxHalfChunkNegativity = imax.negative;
+ if (minHalfChunk & mask)
+ {
+ minHalfChunk += halfChunkMask+1;
+ if (minHalfChunk == 0)
+ -- minHalfChunkNegativity;
+ }
+ if (maxHalfChunk & mask)
+ {
+ maxHalfChunk += halfChunkMask+1;
+ if (maxHalfChunk == 0)
+ -- maxHalfChunkNegativity;
+ }
+ if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity)
+ {
+ imin.value &= mask;
+ imax.value &= mask;
+ // sign extend if necessary.
+ imin.negative = imin.value & ~halfChunkMask;
+ imax.negative = imax.value & ~halfChunkMask;
+ halfChunkMask += 1;
+ imin.value = (imin.value ^ halfChunkMask) - halfChunkMask;
+ imax.value = (imax.value ^ halfChunkMask) - halfChunkMask;
+ }
+ else
+ {
+ imin = SignExtendedNumber(~halfChunkMask, true);
+ imax = SignExtendedNumber(halfChunkMask, false);
+ }
+ return *this;
+}
+
+IntRange& IntRange::castDchar()
+{
+ // special case for dchar. Casting to dchar means "I'll ignore all
+ // invalid characters."
+ castUnsigned(0xFFFFFFFFULL);
+ if (imin.value > 0x10FFFFULL) // ??
+ imin.value = 0x10FFFFULL; // ??
+ if (imax.value > 0x10FFFFULL)
+ imax.value = 0x10FFFFULL;
+ return *this;
+}
+
+IntRange& IntRange::cast(Type *type)
+{
+ if (!type->isintegral())
+ return *this;
+ else if (!type->isunsigned())
+ return castSigned(type->sizemask());
+ else if (type->toBasetype()->ty == Tdchar)
+ return castDchar();
+ else
+ return castUnsigned(type->sizemask());
+}
+
+IntRange& IntRange::castUnsigned(Type *type)
+{
+ if (!type->isintegral())
+ return castUnsigned(UINT64_MAX);
+ else if (type->toBasetype()->ty == Tdchar)
+ return castDchar();
+ else
+ return castUnsigned(type->sizemask());
+}
+
+IntRange IntRange::absNeg() const
+{
+ if (imax.negative)
+ return *this;
+ else if (!imin.negative)
+ return IntRange(-imax, -imin);
+ else
+ {
+ SignExtendedNumber imaxAbsNeg = -imax;
+ return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
+ SignExtendedNumber(0));
+ }
+}
+
+IntRange IntRange::unionWith(const IntRange& other) const
+{
+ return IntRange(imin < other.imin ? imin : other.imin,
+ imax > other.imax ? imax : other.imax);
+}
+
+void IntRange::unionOrAssign(const IntRange& other, bool& union_)
+{
+ if (!union_ || imin > other.imin)
+ imin = other.imin;
+ if (!union_ || imax < other.imax)
+ imax = other.imax;
+ union_ = true;
+}
+
+void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange,
+ IntRange& nonNegRange, bool& hasNonNegRange) const
+{
+ hasNegRange = imin.negative;
+ if (hasNegRange)
+ {
+ negRange.imin = imin;
+ negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true);
+ }
+ hasNonNegRange = !imax.negative;
+ if (hasNonNegRange)
+ {
+ nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin;
+ nonNegRange.imax = imax;
+ }
+}
+
+
+const IntRange& IntRange::dump(const char* funcName, Expression *e) const
+{
+ printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
+ imin.negative?'-':'+', (unsigned long long)imin.value,
+ imax.negative?'-':'+', (unsigned long long)imax.value,
+ funcName, e->toChars());
+ return *this;
+}
diff --git a/gcc/d/dmd/intrange.h b/gcc/d/dmd/intrange.h
new file mode 100644
index 0000000..6911158
--- /dev/null
+++ b/gcc/d/dmd/intrange.h
@@ -0,0 +1,149 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by KennyTM
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/intrange.h
+ */
+
+#pragma once
+
+#include "globals.h" // for uinteger_t
+class Type;
+class Expression;
+
+/**
+This class represents a "sign-extended number", i.e. a 65-bit number, which can
+represent all built-in integer types in D. This class is mainly used for
+performing value-range propagation only, therefore all arithmetic are done with
+saturation, not wrapping as usual.
+*/
+struct SignExtendedNumber
+{
+ /// The lower 64-bit of the number.
+ uinteger_t value;
+ /// The sign (i.e. the most significant bit) of the number.
+ bool negative;
+
+ /// Create an uninitialized sign-extended number.
+ SignExtendedNumber() {}
+
+ /// Create a sign-extended number from an unsigned 64-bit number.
+ SignExtendedNumber(uinteger_t value_)
+ : value(value_), negative(false) {}
+ /// Create a sign-extended number from the lower 64-bit and the sign bit.
+ SignExtendedNumber(uinteger_t value_, bool negative_)
+ : value(value_), negative(negative_) {}
+
+ /// Create a sign-extended number from a signed 64-bit number.
+ static SignExtendedNumber fromInteger(uinteger_t value_);
+
+ /// Get the minimum or maximum value of a sign-extended number.
+ static SignExtendedNumber extreme(bool minimum);
+
+ // These names probably shouldn't be used anyway, as they are common macros
+#undef max
+#undef min
+ static SignExtendedNumber max();
+ static SignExtendedNumber min() { return SignExtendedNumber(0, true); }
+
+ /// Check if the sign-extended number is minimum or zero.
+ bool isMinimum() const { return negative && value == 0; }
+
+ /// Compare two sign-extended number.
+ bool operator==(const SignExtendedNumber&) const;
+ bool operator!=(const SignExtendedNumber& a) const { return !(*this == a); }
+ bool operator<(const SignExtendedNumber&) const;
+ bool operator>(const SignExtendedNumber& a) const { return a < *this; }
+ bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
+ bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
+
+ /// Compute the saturated negation of a sign-extended number.
+ SignExtendedNumber operator-() const;
+
+ /// Compute the saturated sum of two sign-extended number.
+ SignExtendedNumber operator+(const SignExtendedNumber&) const;
+ /// Compute the saturated difference of two sign-extended number.
+ SignExtendedNumber operator-(const SignExtendedNumber& a) const;
+ /// Compute the saturated product of two sign-extended number.
+ SignExtendedNumber operator*(const SignExtendedNumber&) const;
+ /// Compute the saturated quotient of two sign-extended number.
+ SignExtendedNumber operator/(const SignExtendedNumber&) const;
+ /// Compute the saturated modulus of two sign-extended number.
+ SignExtendedNumber operator%(const SignExtendedNumber&) const;
+
+ /// Increase the sign-extended number by 1 (saturated).
+ SignExtendedNumber& operator++();
+
+ /// Compute the saturated shifts of two sign-extended number.
+ SignExtendedNumber operator<<(const SignExtendedNumber&) const;
+ SignExtendedNumber operator>>(const SignExtendedNumber&) const;
+};
+
+/**
+This class represents a range of integers, denoted by its lower and upper bounds
+(inclusive).
+*/
+struct IntRange
+{
+ SignExtendedNumber imin, imax;
+
+ /// Create an uninitialized range.
+ IntRange() {}
+
+ /// Create a range consisting of a single number.
+ IntRange(const SignExtendedNumber& a)
+ : imin(a), imax(a) {}
+ /// Create a range with the lower and upper bounds.
+ IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper)
+ : imin(lower), imax(upper) {}
+
+ /// Create the tightest range containing all valid integers in the specified
+ /// type.
+ static IntRange fromType(Type *type);
+ /// Create the tightest range containing all valid integers in the type with
+ /// a forced signedness.
+ static IntRange fromType(Type *type, bool isUnsigned);
+
+
+ /// Create the tightest range containing all specified numbers.
+ static IntRange fromNumbers2(const SignExtendedNumber numbers[2]);
+ static IntRange fromNumbers4(const SignExtendedNumber numbers[4]);
+
+ /// Create the widest range possible.
+ static IntRange widest();
+
+ /// Cast the integer range to a signed type with the given size mask.
+ IntRange& castSigned(uinteger_t mask);
+ /// Cast the integer range to an unsigned type with the given size mask.
+ IntRange& castUnsigned(uinteger_t mask);
+ /// Cast the integer range to the dchar type.
+ IntRange& castDchar();
+
+ /// Cast the integer range to a specific type.
+ IntRange& cast(Type *type);
+ /// Cast the integer range to a specific type, forcing it to be unsigned.
+ IntRange& castUnsigned(Type *type);
+
+ /// Check if this range contains another range.
+ bool contains(const IntRange& a) const;
+
+ /// Check if this range contains 0.
+ bool containsZero() const;
+
+ /// Compute the range of the negated absolute values of the original range.
+ IntRange absNeg() const;
+
+ /// Compute the union of two ranges.
+ IntRange unionWith(const IntRange& other) const;
+ void unionOrAssign(const IntRange& other, bool& union_);
+
+ /// Dump the content of the integer range to the console.
+ const IntRange& dump(const char* funcName, Expression *e) const;
+
+ /// Split the range into two nonnegative- and negative-only subintervals.
+ void splitBySign(IntRange& negRange, bool& hasNegRange,
+ IntRange& nonNegRange, bool& hasNonNegRange) const;
+};
diff --git a/gcc/d/dmd/json.c b/gcc/d/dmd/json.c
new file mode 100644
index 0000000..4c49023
--- /dev/null
+++ b/gcc/d/dmd/json.c
@@ -0,0 +1,890 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/json.c
+ */
+
+// This implements the JSON capability.
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "template.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "enum.h"
+#include "module.h"
+#include "json.h"
+#include "mtype.h"
+#include "attrib.h"
+#include "cond.h"
+#include "init.h"
+#include "import.h"
+#include "id.h"
+#include "hdrgen.h"
+
+class ToJsonVisitor : public Visitor
+{
+public:
+ OutBuffer *buf;
+ int indentLevel;
+ const char *filename;
+
+ ToJsonVisitor(OutBuffer *buf)
+ : buf(buf), indentLevel(0), filename(NULL)
+ {
+ }
+
+ void indent()
+ {
+ if (buf->offset >= 1 &&
+ buf->data[buf->offset - 1] == '\n')
+ for (int i = 0; i < indentLevel; i++)
+ buf->writeByte(' ');
+ }
+
+ void removeComma()
+ {
+ if (buf->offset >= 2 &&
+ buf->data[buf->offset - 2] == ',' &&
+ (buf->data[buf->offset - 1] == '\n' || buf->data[buf->offset - 1] == ' '))
+ buf->offset -= 2;
+ }
+
+ void comma()
+ {
+ if (indentLevel > 0)
+ buf->writestring(",\n");
+ }
+
+ void stringStart()
+ {
+ buf->writeByte('\"');
+ }
+
+ void stringEnd()
+ {
+ buf->writeByte('\"');
+ }
+
+ void stringPart(const char *s)
+ {
+ for (; *s; s++)
+ {
+ utf8_t c = (utf8_t) *s;
+ switch (c)
+ {
+ case '\n':
+ buf->writestring("\\n");
+ break;
+
+ case '\r':
+ buf->writestring("\\r");
+ break;
+
+ case '\t':
+ buf->writestring("\\t");
+ break;
+
+ case '\"':
+ buf->writestring("\\\"");
+ break;
+
+ case '\\':
+ buf->writestring("\\\\");
+ break;
+
+ case '\b':
+ buf->writestring("\\b");
+ break;
+
+ case '\f':
+ buf->writestring("\\f");
+ break;
+
+ default:
+ if (c < 0x20)
+ buf->printf("\\u%04x", c);
+ else
+ {
+ // Note that UTF-8 chars pass through here just fine
+ buf->writeByte(c);
+ }
+ break;
+ }
+ }
+ }
+
+ // Json value functions
+
+ /*********************************
+ * Encode string into buf, and wrap it in double quotes.
+ */
+ void value(const char *s)
+ {
+ stringStart();
+ stringPart(s);
+ stringEnd();
+ }
+
+ void value(int value)
+ {
+ buf->printf("%d", value);
+ }
+
+ void valueBool(bool value)
+ {
+ buf->writestring(value ? "true" : "false");
+ }
+
+ /*********************************
+ * Item is an intented value and a comma, for use in arrays
+ */
+ void item(const char *s)
+ {
+ indent();
+ value(s);
+ comma();
+ }
+
+ void item(int i)
+ {
+ indent();
+ value(i);
+ comma();
+ }
+
+ void itemBool(bool b)
+ {
+ indent();
+ valueBool(b);
+ comma();
+ }
+
+
+ // Json array functions
+
+ void arrayStart()
+ {
+ indent();
+ buf->writestring("[\n");
+ indentLevel++;
+ }
+
+ void arrayEnd()
+ {
+ indentLevel--;
+ removeComma();
+ if (buf->offset >= 2 &&
+ buf->data[buf->offset - 2] == '[' &&
+ buf->data[buf->offset - 1] == '\n')
+ buf->offset -= 1;
+ else if (!(buf->offset >= 1 &&
+ buf->data[buf->offset - 1] == '['))
+ {
+ buf->writestring("\n");
+ indent();
+ }
+ buf->writestring("]");
+ comma();
+ }
+
+
+ // Json object functions
+
+ void objectStart()
+ {
+ indent();
+ buf->writestring("{\n");
+ indentLevel++;
+ }
+
+ void objectEnd()
+ {
+ indentLevel--;
+ removeComma();
+ if (buf->offset >= 2 &&
+ buf->data[buf->offset - 2] == '{' &&
+ buf->data[buf->offset - 1] == '\n')
+ buf->offset -= 1;
+ else
+ {
+ buf->writestring("\n");
+ indent();
+ }
+ buf->writestring("}");
+ comma();
+ }
+
+ // Json object property functions
+
+ void propertyStart(const char *name)
+ {
+ indent();
+ value(name);
+ buf->writestring(" : ");
+ }
+
+ void property(const char *name, const char *s)
+ {
+ if (s == NULL) return;
+
+ propertyStart(name);
+ value(s);
+ comma();
+ }
+
+ void property(const char *name, int i)
+ {
+ propertyStart(name);
+ value(i);
+ comma();
+ }
+
+ void propertyBool(const char *name, bool b)
+ {
+ propertyStart(name);
+ valueBool(b);
+ comma();
+ }
+
+
+ void property(const char *name, TRUST trust)
+ {
+ switch (trust)
+ {
+ case TRUSTdefault:
+ // Should not be printed
+ //property(name, "default");
+ break;
+ case TRUSTsystem:
+ property(name, "system");
+ break;
+ case TRUSTtrusted:
+ property(name, "trusted");
+ break;
+ case TRUSTsafe:
+ property(name, "safe");
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ void property(const char *name, PURE purity)
+ {
+ switch (purity)
+ {
+ case PUREimpure:
+ // Should not be printed
+ //property(name, "impure");
+ break;
+ case PUREweak:
+ property(name, "weak");
+ break;
+ case PUREconst:
+ property(name, "const");
+ break;
+ case PUREstrong:
+ property(name, "strong");
+ break;
+ case PUREfwdref:
+ property(name, "fwdref");
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ void property(const char *name, LINK linkage)
+ {
+ switch (linkage)
+ {
+ case LINKdefault:
+ // Should not be printed
+ //property(name, "default");
+ break;
+ case LINKd:
+ // Should not be printed
+ //property(name, "d");
+ break;
+ case LINKc:
+ property(name, "c");
+ break;
+ case LINKcpp:
+ property(name, "cpp");
+ break;
+ case LINKwindows:
+ property(name, "windows");
+ break;
+ case LINKpascal:
+ property(name, "pascal");
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ void propertyStorageClass(const char *name, StorageClass stc)
+ {
+ stc &= STCStorageClass;
+ if (stc)
+ {
+ propertyStart(name);
+ arrayStart();
+
+ while (stc)
+ {
+ const char *p = stcToChars(stc);
+ assert(p);
+ item(p);
+ }
+
+ arrayEnd();
+ }
+ }
+
+ void property(const char *linename, const char *charname, Loc *loc)
+ {
+ if (loc)
+ {
+ const char *filename = loc->filename;
+ if (filename)
+ {
+ if (!this->filename || strcmp(filename, this->filename))
+ {
+ this->filename = filename;
+ property("file", filename);
+ }
+ }
+
+ if (loc->linnum)
+ {
+ property(linename, loc->linnum);
+ if (loc->charnum)
+ property(charname, loc->charnum);
+ }
+ }
+ }
+
+ void property(const char *name, Type *type)
+ {
+ if (type)
+ {
+ property(name, type->toChars());
+ }
+ }
+
+ void property(const char *name, const char *deconame, Type *type)
+ {
+ if (type)
+ {
+ if (type->deco)
+ property(deconame, type->deco);
+ else
+ property(name, type->toChars());
+ }
+ }
+
+ void property(const char *name, Parameters *parameters)
+ {
+ if (parameters == NULL || parameters->dim == 0)
+ return;
+
+ propertyStart(name);
+ arrayStart();
+
+ if (parameters)
+ {
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ Parameter *p = (*parameters)[i];
+ objectStart();
+
+ if (p->ident)
+ property("name", p->ident->toChars());
+
+ property("type", "deco", p->type);
+
+ propertyStorageClass("storageClass", p->storageClass);
+
+ if (p->defaultArg)
+ property("default", p->defaultArg->toChars());
+
+
+ objectEnd();
+ }
+ }
+
+ arrayEnd();
+ }
+
+ /* ========================================================================== */
+
+ void jsonProperties(Dsymbol *s)
+ {
+ if (s->isModule())
+ return;
+
+ if (!s->isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
+ {
+ property("name", s->toChars());
+ property("kind", s->kind());
+ }
+
+ if (s->prot().kind != PROTpublic) // TODO: How about package(names)?
+ property("protection", protectionToChars(s->prot().kind));
+
+ if (EnumMember *em = s->isEnumMember())
+ {
+ if (em->origValue)
+ property("value", em->origValue->toChars());
+ }
+
+ property("comment", (const char *)s->comment);
+
+ property("line", "char", &s->loc);
+ }
+
+ void jsonProperties(Declaration *d)
+ {
+ jsonProperties((Dsymbol *)d);
+
+ propertyStorageClass("storageClass", d->storage_class);
+
+ property("type", "deco", d->type);
+
+ // Emit originalType if it differs from type
+ if (d->type != d->originalType && d->originalType)
+ {
+ const char *ostr = d->originalType->toChars();
+ if (d->type)
+ {
+ const char *tstr = d->type->toChars();
+ if (strcmp(tstr, ostr))
+ {
+ //printf("tstr = %s, ostr = %s\n", tstr, ostr);
+ property("originalType", ostr);
+ }
+ }
+ else
+ property("originalType", ostr);
+ }
+ }
+
+ void jsonProperties(TemplateDeclaration *td)
+ {
+ jsonProperties((Dsymbol *)td);
+
+ if (td->onemember && td->onemember->isCtorDeclaration())
+ property("name", "this"); // __ctor -> this
+ else
+ property("name", td->ident->toChars()); // Foo(T) -> Foo
+ }
+
+ /* ========================================================================== */
+
+ void visit(Dsymbol *)
+ {
+ }
+
+ void visit(Module *s)
+ {
+ objectStart();
+
+ if (s->md)
+ property("name", s->md->toChars());
+
+ property("kind", s->kind());
+
+ filename = s->srcfile->toChars();
+ property("file", filename);
+
+ property("comment", (const char *)s->comment);
+
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < s->members->dim; i++)
+ {
+ (*s->members)[i]->accept(this);
+ }
+ arrayEnd();
+
+ objectEnd();
+ }
+
+ void visit(Import *s)
+ {
+ if (s->id == Id::object)
+ return;
+
+ objectStart();
+
+ propertyStart("name");
+ stringStart();
+ if (s->packages && s->packages->dim)
+ {
+ for (size_t i = 0; i < s->packages->dim; i++)
+ {
+ Identifier *pid = (*s->packages)[i];
+ stringPart(pid->toChars());
+ buf->writeByte('.');
+ }
+ }
+ stringPart(s->id->toChars());
+ stringEnd();
+ comma();
+
+ property("kind", s->kind());
+ property("comment", (const char *)s->comment);
+ property("line", "char", &s->loc);
+ if (s->prot().kind != PROTpublic)
+ property("protection", protectionToChars(s->prot().kind));
+ if (s->aliasId)
+ property("alias", s->aliasId->toChars());
+
+ bool hasRenamed = false;
+ bool hasSelective = false;
+ for (size_t i = 0; i < s->aliases.dim; i++)
+ {
+ // avoid empty "renamed" and "selective" sections
+ if (hasRenamed && hasSelective)
+ break;
+ else if (s->aliases[i])
+ hasRenamed = true;
+ else
+ hasSelective = true;
+ }
+
+ if (hasRenamed)
+ {
+ // import foo : alias1 = target1;
+ propertyStart("renamed");
+ objectStart();
+ for (size_t i = 0; i < s->aliases.dim; i++)
+ {
+ Identifier *name = s->names[i];
+ Identifier *alias = s->aliases[i];
+ if (alias) property(alias->toChars(), name->toChars());
+ }
+ objectEnd();
+ }
+
+ if (hasSelective)
+ {
+ // import foo : target1;
+ propertyStart("selective");
+ arrayStart();
+ for (size_t i = 0; i < s->names.dim; i++)
+ {
+ Identifier *name = s->names[i];
+ if (!s->aliases[i]) item(name->toChars());
+ }
+ arrayEnd();
+ }
+
+ objectEnd();
+ }
+
+ void visit(AttribDeclaration *d)
+ {
+ Dsymbols *ds = d->include(NULL, NULL);
+
+ if (ds)
+ {
+ for (size_t i = 0; i < ds->dim; i++)
+ {
+ Dsymbol *s = (*ds)[i];
+ s->accept(this);
+ }
+ }
+ }
+
+ void visit(ConditionalDeclaration *d)
+ {
+ if (d->condition->inc)
+ {
+ visit((AttribDeclaration *)d);
+ }
+ }
+
+ void visit(TypeInfoDeclaration *) {}
+ void visit(PostBlitDeclaration *) {}
+
+ void visit(Declaration *d)
+ {
+ objectStart();
+
+ //property("unknown", "declaration");
+
+ jsonProperties(d);
+
+ objectEnd();
+ }
+
+ void visit(AggregateDeclaration *d)
+ {
+ objectStart();
+
+ jsonProperties(d);
+
+ ClassDeclaration *cd = d->isClassDeclaration();
+ if (cd)
+ {
+ if (cd->baseClass && cd->baseClass->ident != Id::Object)
+ {
+ property("base", cd->baseClass->toPrettyChars(true));
+ }
+ if (cd->interfaces.length)
+ {
+ propertyStart("interfaces");
+ arrayStart();
+ for (size_t i = 0; i < cd->interfaces.length; i++)
+ {
+ BaseClass *b = cd->interfaces.ptr[i];
+ item(b->sym->toPrettyChars(true));
+ }
+ arrayEnd();
+ }
+ }
+
+ if (d->members)
+ {
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ arrayEnd();
+ }
+
+ objectEnd();
+ }
+
+ void visit(FuncDeclaration *d)
+ {
+ objectStart();
+
+ jsonProperties(d);
+
+ TypeFunction *tf = (TypeFunction *)d->type;
+ if (tf && tf->ty == Tfunction)
+ property("parameters", tf->parameters);
+
+ property("endline", "endchar", &d->endloc);
+
+ if (d->foverrides.dim)
+ {
+ propertyStart("overrides");
+ arrayStart();
+ for (size_t i = 0; i < d->foverrides.dim; i++)
+ {
+ FuncDeclaration *fd = d->foverrides[i];
+ item(fd->toPrettyChars());
+ }
+ arrayEnd();
+ }
+
+ if (d->fdrequire)
+ {
+ propertyStart("in");
+ d->fdrequire->accept(this);
+ }
+
+ if (d->fdensure)
+ {
+ propertyStart("out");
+ d->fdensure->accept(this);
+ }
+
+ objectEnd();
+ }
+
+ void visit(TemplateDeclaration *d)
+ {
+ objectStart();
+
+ // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
+ property("kind", "template");
+
+ jsonProperties(d);
+
+ propertyStart("parameters");
+ arrayStart();
+ for (size_t i = 0; i < d->parameters->dim; i++)
+ {
+ TemplateParameter *s = (*d->parameters)[i];
+ objectStart();
+
+ property("name", s->ident->toChars());
+
+ TemplateTypeParameter *type = s->isTemplateTypeParameter();
+ if (type)
+ {
+ if (s->isTemplateThisParameter())
+ property("kind", "this");
+ else
+ property("kind", "type");
+ property("type", "deco", type->specType);
+
+ property("default", "defaultDeco", type->defaultType);
+ }
+
+ TemplateValueParameter *value = s->isTemplateValueParameter();
+ if (value)
+ {
+ property("kind", "value");
+
+ property("type", "deco", value->valType);
+
+ if (value->specValue)
+ property("specValue", value->specValue->toChars());
+
+ if (value->defaultValue)
+ property("defaultValue", value->defaultValue->toChars());
+ }
+
+ TemplateAliasParameter *alias = s->isTemplateAliasParameter();
+ if (alias)
+ {
+ property("kind", "alias");
+
+ property("type", "deco", alias->specType);
+
+ if (alias->specAlias)
+ property("specAlias", alias->specAlias->toChars());
+
+ if (alias->defaultAlias)
+ property("defaultAlias", alias->defaultAlias->toChars());
+ }
+
+ TemplateTupleParameter *tuple = s->isTemplateTupleParameter();
+ if (tuple)
+ {
+ property("kind", "tuple");
+ }
+
+ objectEnd();
+ }
+ arrayEnd();
+
+ Expression *expression = d->constraint;
+ if (expression)
+ {
+ property("constraint", expression->toChars());
+ }
+
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ arrayEnd();
+
+ objectEnd();
+ }
+
+ void visit(EnumDeclaration *d)
+ {
+ if (d->isAnonymous())
+ {
+ if (d->members)
+ {
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ }
+ return;
+ }
+
+ objectStart();
+
+ jsonProperties(d);
+
+ property("base", "baseDeco", d->memtype);
+
+ if (d->members)
+ {
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < d->members->dim; i++)
+ {
+ Dsymbol *s = (*d->members)[i];
+ s->accept(this);
+ }
+ arrayEnd();
+ }
+
+ objectEnd();
+ }
+
+ void visit(EnumMember *s)
+ {
+ objectStart();
+
+ jsonProperties((Dsymbol*)s);
+
+ property("type", "deco", s->origType);
+
+ objectEnd();
+ }
+
+ void visit(VarDeclaration *d)
+ {
+ objectStart();
+
+ jsonProperties(d);
+
+ if (d->_init)
+ property("init", d->_init->toChars());
+
+ if (d->isField())
+ property("offset", d->offset);
+
+ if (d->alignment && d->alignment != STRUCTALIGN_DEFAULT)
+ property("align", d->alignment);
+
+ objectEnd();
+ }
+
+ void visit(TemplateMixin *d)
+ {
+ objectStart();
+
+ jsonProperties(d);
+
+ objectEnd();
+ }
+};
+
+
+void json_generate(OutBuffer *buf, Modules *modules)
+{
+ ToJsonVisitor json(buf);
+
+ json.arrayStart();
+ for (size_t i = 0; i < modules->dim; i++)
+ {
+ Module *m = (*modules)[i];
+ if (global.params.verbose)
+ message("json gen %s", m->toChars());
+ m->accept(&json);
+ }
+ json.arrayEnd();
+ json.removeComma();
+}
diff --git a/gcc/d/dmd/json.h b/gcc/d/dmd/json.h
new file mode 100644
index 0000000..7e4a512
--- /dev/null
+++ b/gcc/d/dmd/json.h
@@ -0,0 +1,17 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/json.h
+ */
+
+#pragma once
+
+#include "arraytypes.h"
+
+struct OutBuffer;
+
+void json_generate(OutBuffer *, Modules *);
diff --git a/gcc/d/dmd/lexer.c b/gcc/d/dmd/lexer.c
new file mode 100644
index 0000000..1fefe2b
--- /dev/null
+++ b/gcc/d/dmd/lexer.c
@@ -0,0 +1,2401 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.c
+ */
+
+/* Lexical Analyzer */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h> // for time() and ctime()
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "lexer.h"
+#include "utf.h"
+#include "identifier.h"
+#include "id.h"
+
+extern int HtmlNamedEntity(const utf8_t *p, size_t length);
+
+#define LS 0x2028 // UTF line separator
+#define PS 0x2029 // UTF paragraph separator
+
+/********************************************
+ * Do our own char maps
+ */
+
+static unsigned char cmtable[256];
+
+const int CMoctal = 0x1;
+const int CMhex = 0x2;
+const int CMidchar = 0x4;
+
+inline bool isoctal (utf8_t c) { return (cmtable[c] & CMoctal) != 0; }
+inline bool ishex (utf8_t c) { return (cmtable[c] & CMhex) != 0; }
+inline bool isidchar(utf8_t c) { return (cmtable[c] & CMidchar) != 0; }
+
+struct CMTableInitializer
+{
+ CMTableInitializer();
+};
+
+static CMTableInitializer cmtableinitializer;
+
+CMTableInitializer::CMTableInitializer()
+{
+ for (unsigned c = 0; c < 256; c++)
+ {
+ if ('0' <= c && c <= '7')
+ cmtable[c] |= CMoctal;
+ if (isxdigit(c))
+ cmtable[c] |= CMhex;
+ if (isalnum(c) || c == '_')
+ cmtable[c] |= CMidchar;
+ }
+}
+
+/*************************** Lexer ********************************************/
+
+OutBuffer Lexer::stringbuffer;
+
+Lexer::Lexer(const char *filename,
+ const utf8_t *base, size_t begoffset, size_t endoffset,
+ bool doDocComment, bool commentToken)
+{
+ scanloc = Loc(filename, 1, 1);
+ //printf("Lexer::Lexer(%p,%d)\n",base,length);
+ //printf("lexer.filename = %s\n", filename);
+ this->token = Token();
+ this->token.ptr = NULL;
+ this->token.value = TOKreserved;
+ this->token.blockComment = NULL;
+ this->token.lineComment = NULL;
+ this->base = base;
+ this->end = base + endoffset;
+ p = base + begoffset;
+ line = p;
+ this->doDocComment = doDocComment;
+ this->anyToken = 0;
+ this->commentToken = commentToken;
+ this->errors = false;
+ //initKeywords();
+
+ /* If first line starts with '#!', ignore the line
+ */
+
+ if (p[0] == '#' && p[1] =='!')
+ {
+ p += 2;
+ while (1)
+ {
+ utf8_t c = *p++;
+ switch (c)
+ {
+ case 0:
+ case 0x1A:
+ p--;
+ /* fall through */
+
+ case '\n':
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ }
+ endOfLine();
+ }
+}
+
+
+void Lexer::endOfLine()
+{
+ scanloc.linnum++;
+ line = p;
+}
+
+
+void Lexer::error(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::verror(token.loc, format, ap);
+ va_end(ap);
+ errors = true;
+}
+
+void Lexer::error(Loc loc, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::verror(loc, format, ap);
+ va_end(ap);
+ errors = true;
+}
+
+void Lexer::deprecation(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::vdeprecation(token.loc, format, ap);
+ va_end(ap);
+ if (global.params.useDeprecated == DIAGNOSTICerror)
+ errors = true;
+}
+
+TOK Lexer::nextToken()
+{
+ if (token.next)
+ {
+ Token *t = token.next;
+ memcpy(&token,t,sizeof(Token));
+ t->free();
+ }
+ else
+ {
+ scan(&token);
+ }
+ //token.print();
+ return token.value;
+}
+
+Token *Lexer::peek(Token *ct)
+{
+ Token *t;
+ if (ct->next)
+ t = ct->next;
+ else
+ {
+ t = Token::alloc();
+ scan(t);
+ ct->next = t;
+ }
+ return t;
+}
+
+/***********************
+ * Look ahead at next token's value.
+ */
+
+TOK Lexer::peekNext()
+{
+ return peek(&token)->value;
+}
+
+/***********************
+ * Look 2 tokens ahead at value.
+ */
+
+TOK Lexer::peekNext2()
+{
+ Token *t = peek(&token);
+ return peek(t)->value;
+}
+
+/*********************************
+ * tk is on the opening (.
+ * Look ahead and return token that is past the closing ).
+ */
+
+Token *Lexer::peekPastParen(Token *tk)
+{
+ //printf("peekPastParen()\n");
+ int parens = 1;
+ int curlynest = 0;
+ while (1)
+ {
+ tk = peek(tk);
+ //tk->print();
+ switch (tk->value)
+ {
+ case TOKlparen:
+ parens++;
+ continue;
+
+ case TOKrparen:
+ --parens;
+ if (parens)
+ continue;
+ tk = peek(tk);
+ break;
+
+ case TOKlcurly:
+ curlynest++;
+ continue;
+
+ case TOKrcurly:
+ if (--curlynest >= 0)
+ continue;
+ break;
+
+ case TOKsemicolon:
+ if (curlynest)
+ continue;
+ break;
+
+ case TOKeof:
+ break;
+
+ default:
+ continue;
+ }
+ return tk;
+ }
+}
+
+/****************************
+ * Turn next token in buffer into a token.
+ */
+
+void Lexer::scan(Token *t)
+{
+ unsigned lastLine = scanloc.linnum;
+ Loc startLoc;
+
+ t->blockComment = NULL;
+ t->lineComment = NULL;
+ while (1)
+ {
+ t->ptr = p;
+ //printf("p = %p, *p = '%c'\n",p,*p);
+ t->loc = loc();
+ switch (*p)
+ {
+ case 0:
+ case 0x1A:
+ t->value = TOKeof; // end of file
+ return;
+
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ p++;
+ continue; // skip white space
+
+ case '\r':
+ p++;
+ if (*p != '\n') // if CR stands by itself
+ endOfLine();
+ continue; // skip white space
+
+ case '\n':
+ p++;
+ endOfLine();
+ continue; // skip white space
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ t->value = number(t);
+ return;
+
+ case '\'':
+ t->value = charConstant(t);
+ return;
+
+ case 'r':
+ if (p[1] != '"')
+ goto case_ident;
+ p++;
+ /* fall through */
+ case '`':
+ t->value = wysiwygStringConstant(t, *p);
+ return;
+
+ case 'x':
+ if (p[1] != '"')
+ goto case_ident;
+ p++;
+ t->value = hexStringConstant(t);
+ return;
+
+ case 'q':
+ if (p[1] == '"')
+ {
+ p++;
+ t->value = delimitedStringConstant(t);
+ return;
+ }
+ else if (p[1] == '{')
+ {
+ p++;
+ t->value = tokenStringConstant(t);
+ return;
+ }
+ else
+ goto case_ident;
+
+ case '"':
+ t->value = escapeStringConstant(t);
+ return;
+
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': /*case 'q': case 'r':*/ case 's': case 't':
+ case 'u': case 'v': case 'w': /*case 'x':*/ case 'y':
+ case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z':
+ case '_':
+ case_ident:
+ { utf8_t c;
+
+ while (1)
+ {
+ c = *++p;
+ if (isidchar(c))
+ continue;
+ else if (c & 0x80)
+ { const utf8_t *s = p;
+ unsigned u = decodeUTF();
+ if (isUniAlpha(u))
+ continue;
+ error("char 0x%04x not allowed in identifier", u);
+ p = s;
+ }
+ break;
+ }
+
+ Identifier *id = Identifier::idPool((const char *)t->ptr, p - t->ptr);
+ t->ident = id;
+ t->value = (TOK) id->getValue();
+ anyToken = 1;
+ if (*t->ptr == '_') // if special identifier token
+ {
+ static bool initdone = false;
+ static char date[11+1];
+ static char time[8+1];
+ static char timestamp[24+1];
+
+ if (!initdone) // lazy evaluation
+ {
+ initdone = true;
+ time_t ct;
+ ::time(&ct);
+ char *p = ctime(&ct);
+ assert(p);
+ sprintf(&date[0], "%.6s %.4s", p + 4, p + 20);
+ sprintf(&time[0], "%.8s", p + 11);
+ sprintf(&timestamp[0], "%.24s", p);
+ }
+
+ if (id == Id::DATE)
+ {
+ t->ustring = (utf8_t *)date;
+ goto Lstr;
+ }
+ else if (id == Id::TIME)
+ {
+ t->ustring = (utf8_t *)time;
+ goto Lstr;
+ }
+ else if (id == Id::VENDOR)
+ {
+ t->ustring = (utf8_t *)const_cast<char *>(global.vendor);
+ goto Lstr;
+ }
+ else if (id == Id::TIMESTAMP)
+ {
+ t->ustring = (utf8_t *)timestamp;
+ Lstr:
+ t->value = TOKstring;
+ t->postfix = 0;
+ t->len = (unsigned)strlen((char *)t->ustring);
+ }
+ else if (id == Id::VERSIONX)
+ { unsigned major = 0;
+ unsigned minor = 0;
+ bool point = false;
+
+ for (const char *p = global.version + 1; 1; p++)
+ {
+ c = *p;
+ if (isdigit((utf8_t)c))
+ minor = minor * 10 + c - '0';
+ else if (c == '.')
+ {
+ if (point)
+ break; // ignore everything after second '.'
+ point = true;
+ major = minor;
+ minor = 0;
+ }
+ else
+ break;
+ }
+ t->value = TOKint64v;
+ t->uns64value = major * 1000 + minor;
+ }
+ else if (id == Id::EOFX)
+ {
+ t->value = TOKeof;
+ // Advance scanner to end of file
+ while (!(*p == 0 || *p == 0x1A))
+ p++;
+ }
+ }
+ //printf("t->value = %d\n",t->value);
+ return;
+ }
+
+ case '/':
+ p++;
+ switch (*p)
+ {
+ case '=':
+ p++;
+ t->value = TOKdivass;
+ return;
+
+ case '*':
+ p++;
+ startLoc = loc();
+ while (1)
+ {
+ while (1)
+ { utf8_t c = *p;
+ switch (c)
+ {
+ case '/':
+ break;
+
+ case '\n':
+ endOfLine();
+ p++;
+ continue;
+
+ case '\r':
+ p++;
+ if (*p != '\n')
+ endOfLine();
+ continue;
+
+ case 0:
+ case 0x1A:
+ error("unterminated /* */ comment");
+ p = end;
+ t->loc = loc();
+ t->value = TOKeof;
+ return;
+
+ default:
+ if (c & 0x80)
+ { unsigned u = decodeUTF();
+ if (u == PS || u == LS)
+ endOfLine();
+ }
+ p++;
+ continue;
+ }
+ break;
+ }
+ p++;
+ if (p[-2] == '*' && p - 3 != t->ptr)
+ break;
+ }
+ if (commentToken)
+ {
+ t->loc = startLoc;
+ t->value = TOKcomment;
+ return;
+ }
+ else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr)
+ { // if /** but not /**/
+ getDocComment(t, lastLine == startLoc.linnum);
+ }
+ continue;
+
+ case '/': // do // style comments
+ startLoc = loc();
+ while (1)
+ { utf8_t c = *++p;
+ switch (c)
+ {
+ case '\n':
+ break;
+
+ case '\r':
+ if (p[1] == '\n')
+ p++;
+ break;
+
+ case 0:
+ case 0x1A:
+ if (commentToken)
+ {
+ p = end;
+ t->loc = startLoc;
+ t->value = TOKcomment;
+ return;
+ }
+ if (doDocComment && t->ptr[2] == '/')
+ getDocComment(t, lastLine == startLoc.linnum);
+ p = end;
+ t->loc = loc();
+ t->value = TOKeof;
+ return;
+
+ default:
+ if (c & 0x80)
+ { unsigned u = decodeUTF();
+ if (u == PS || u == LS)
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+
+ if (commentToken)
+ {
+ p++;
+ endOfLine();
+ t->loc = startLoc;
+ t->value = TOKcomment;
+ return;
+ }
+ if (doDocComment && t->ptr[2] == '/')
+ getDocComment(t, lastLine == startLoc.linnum);
+
+ p++;
+ endOfLine();
+ continue;
+
+ case '+':
+ { int nest;
+
+ startLoc = loc();
+ p++;
+ nest = 1;
+ while (1)
+ { utf8_t c = *p;
+ switch (c)
+ {
+ case '/':
+ p++;
+ if (*p == '+')
+ {
+ p++;
+ nest++;
+ }
+ continue;
+
+ case '+':
+ p++;
+ if (*p == '/')
+ {
+ p++;
+ if (--nest == 0)
+ break;
+ }
+ continue;
+
+ case '\r':
+ p++;
+ if (*p != '\n')
+ endOfLine();
+ continue;
+
+ case '\n':
+ endOfLine();
+ p++;
+ continue;
+
+ case 0:
+ case 0x1A:
+ error("unterminated /+ +/ comment");
+ p = end;
+ t->loc = loc();
+ t->value = TOKeof;
+ return;
+
+ default:
+ if (c & 0x80)
+ { unsigned u = decodeUTF();
+ if (u == PS || u == LS)
+ endOfLine();
+ }
+ p++;
+ continue;
+ }
+ break;
+ }
+ if (commentToken)
+ {
+ t->loc = startLoc;
+ t->value = TOKcomment;
+ return;
+ }
+ if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr)
+ { // if /++ but not /++/
+ getDocComment(t, lastLine == startLoc.linnum);
+ }
+ continue;
+ }
+ default:
+ break;
+ }
+ t->value = TOKdiv;
+ return;
+
+ case '.':
+ p++;
+ if (isdigit(*p))
+ { /* Note that we don't allow ._1 and ._ as being
+ * valid floating point numbers.
+ */
+ p--;
+ t->value = inreal(t);
+ }
+ else if (p[0] == '.')
+ {
+ if (p[1] == '.')
+ { p += 2;
+ t->value = TOKdotdotdot;
+ }
+ else
+ { p++;
+ t->value = TOKslice;
+ }
+ }
+ else
+ t->value = TOKdot;
+ return;
+
+ case '&':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKandass;
+ }
+ else if (*p == '&')
+ { p++;
+ t->value = TOKandand;
+ }
+ else
+ t->value = TOKand;
+ return;
+
+ case '|':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKorass;
+ }
+ else if (*p == '|')
+ { p++;
+ t->value = TOKoror;
+ }
+ else
+ t->value = TOKor;
+ return;
+
+ case '-':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKminass;
+ }
+ else if (*p == '-')
+ { p++;
+ t->value = TOKminusminus;
+ }
+ else
+ t->value = TOKmin;
+ return;
+
+ case '+':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKaddass;
+ }
+ else if (*p == '+')
+ { p++;
+ t->value = TOKplusplus;
+ }
+ else
+ t->value = TOKadd;
+ return;
+
+ case '<':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKle; // <=
+ }
+ else if (*p == '<')
+ { p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKshlass; // <<=
+ }
+ else
+ t->value = TOKshl; // <<
+ }
+ else if (*p == '>')
+ { p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKleg; // <>=
+ }
+ else
+ t->value = TOKlg; // <>
+ }
+ else
+ t->value = TOKlt; // <
+ return;
+
+ case '>':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKge; // >=
+ }
+ else if (*p == '>')
+ { p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKshrass; // >>=
+ }
+ else if (*p == '>')
+ { p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKushrass; // >>>=
+ }
+ else
+ t->value = TOKushr; // >>>
+ }
+ else
+ t->value = TOKshr; // >>
+ }
+ else
+ t->value = TOKgt; // >
+ return;
+
+ case '!':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKnotequal; // !=
+ }
+ else if (*p == '<')
+ { p++;
+ if (*p == '>')
+ { p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKunord; // !<>=
+ }
+ else
+ t->value = TOKue; // !<>
+ }
+ else if (*p == '=')
+ { p++;
+ t->value = TOKug; // !<=
+ }
+ else
+ t->value = TOKuge; // !<
+ }
+ else if (*p == '>')
+ { p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKul; // !>=
+ }
+ else
+ t->value = TOKule; // !>
+ }
+ else
+ t->value = TOKnot; // !
+ return;
+
+ case '=':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKequal; // ==
+ }
+ else if (*p == '>')
+ { p++;
+ t->value = TOKgoesto; // =>
+ }
+ else
+ t->value = TOKassign; // =
+ return;
+
+ case '~':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKcatass; // ~=
+ }
+ else
+ t->value = TOKtilde; // ~
+ return;
+
+ case '^':
+ p++;
+ if (*p == '^')
+ { p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKpowass; // ^^=
+ }
+ else
+ t->value = TOKpow; // ^^
+ }
+ else if (*p == '=')
+ { p++;
+ t->value = TOKxorass; // ^=
+ }
+ else
+ t->value = TOKxor; // ^
+ return;
+
+ case '(': p++; t->value = TOKlparen; return;
+ case ')': p++; t->value = TOKrparen; return;
+ case '[': p++; t->value = TOKlbracket; return;
+ case ']': p++; t->value = TOKrbracket; return;
+ case '{': p++; t->value = TOKlcurly; return;
+ case '}': p++; t->value = TOKrcurly; return;
+ case '?': p++; t->value = TOKquestion; return;
+ case ',': p++; t->value = TOKcomma; return;
+ case ';': p++; t->value = TOKsemicolon; return;
+ case ':': p++; t->value = TOKcolon; return;
+ case '$': p++; t->value = TOKdollar; return;
+ case '@': p++; t->value = TOKat; return;
+
+ case '*':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKmulass;
+ }
+ else
+ t->value = TOKmul;
+ return;
+ case '%':
+ p++;
+ if (*p == '=')
+ { p++;
+ t->value = TOKmodass;
+ }
+ else
+ t->value = TOKmod;
+ return;
+
+ case '#':
+ {
+ p++;
+ Token n;
+ scan(&n);
+ if (n.value == TOKidentifier && n.ident == Id::line)
+ {
+ poundLine();
+ continue;
+ }
+ else
+ {
+ t->value = TOKpound;
+ return;
+ }
+ }
+
+ default:
+ { unsigned c = *p;
+
+ if (c & 0x80)
+ { c = decodeUTF();
+
+ // Check for start of unicode identifier
+ if (isUniAlpha(c))
+ goto case_ident;
+
+ if (c == PS || c == LS)
+ {
+ endOfLine();
+ p++;
+ continue;
+ }
+ }
+ if (c < 0x80 && isprint(c))
+ error("character '%c' is not a valid token", c);
+ else
+ error("character 0x%02x is not a valid token", c);
+ p++;
+ continue;
+ }
+ }
+ }
+}
+
+/*******************************************
+ * Parse escape sequence.
+ */
+
+unsigned Lexer::escapeSequence()
+{ unsigned c = *p;
+
+ int n;
+ int ndigits;
+
+ switch (c)
+ {
+ case '\'':
+ case '"':
+ case '?':
+ case '\\':
+ Lconsume:
+ p++;
+ break;
+
+ case 'a': c = 7; goto Lconsume;
+ case 'b': c = 8; goto Lconsume;
+ case 'f': c = 12; goto Lconsume;
+ case 'n': c = 10; goto Lconsume;
+ case 'r': c = 13; goto Lconsume;
+ case 't': c = 9; goto Lconsume;
+ case 'v': c = 11; goto Lconsume;
+
+ case 'u':
+ ndigits = 4;
+ goto Lhex;
+ case 'U':
+ ndigits = 8;
+ goto Lhex;
+ case 'x':
+ ndigits = 2;
+ Lhex:
+ p++;
+ c = *p;
+ if (ishex((utf8_t)c))
+ { unsigned v;
+
+ n = 0;
+ v = 0;
+ while (1)
+ {
+ if (isdigit((utf8_t)c))
+ c -= '0';
+ else if (islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ v = v * 16 + c;
+ c = *++p;
+ if (++n == ndigits)
+ break;
+ if (!ishex((utf8_t)c))
+ { error("escape hex sequence has %d hex digits instead of %d", n, ndigits);
+ break;
+ }
+ }
+ if (ndigits != 2 && !utf_isValidDchar(v))
+ { error("invalid UTF character \\U%08x", v);
+ v = '?'; // recover with valid UTF character
+ }
+ c = v;
+ }
+ else
+ error("undefined escape hex sequence \\%c",c);
+ break;
+
+ case '&': // named character entity
+ for (const utf8_t *idstart = ++p; 1; p++)
+ {
+ switch (*p)
+ {
+ case ';':
+ c = HtmlNamedEntity(idstart, p - idstart);
+ if (c == ~0U)
+ { error("unnamed character entity &%.*s;", (int)(p - idstart), idstart);
+ c = ' ';
+ }
+ p++;
+ break;
+
+ default:
+ if (isalpha(*p) ||
+ (p != idstart && isdigit(*p)))
+ continue;
+ error("unterminated named entity &%.*s;", (int)(p - idstart + 1), idstart);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 0:
+ case 0x1A: // end of file
+ c = '\\';
+ break;
+
+ default:
+ if (isoctal((utf8_t)c))
+ { unsigned v;
+
+ n = 0;
+ v = 0;
+ do
+ {
+ v = v * 8 + (c - '0');
+ c = *++p;
+ } while (++n < 3 && isoctal((utf8_t)c));
+ c = v;
+ if (c > 0xFF)
+ error("escape octal sequence \\%03o is larger than \\377", c);
+ }
+ else
+ error("undefined escape sequence \\%c",c);
+ break;
+ }
+ return c;
+}
+
+/**************************************
+ */
+
+TOK Lexer::wysiwygStringConstant(Token *t, int tc)
+{
+ int c;
+ Loc start = loc();
+
+ p++;
+ stringbuffer.reset();
+ while (1)
+ {
+ c = *p++;
+ switch (c)
+ {
+ case '\n':
+ endOfLine();
+ break;
+
+ case '\r':
+ if (*p == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ endOfLine();
+ break;
+
+ case 0:
+ case 0x1A:
+ error("unterminated string constant starting at %s", start.toChars());
+ t->ustring = (utf8_t *)const_cast<char *>("");
+ t->len = 0;
+ t->postfix = 0;
+ return TOKstring;
+
+ case '"':
+ case '`':
+ if (c == tc)
+ {
+ t->len = (unsigned)stringbuffer.offset;
+ stringbuffer.writeByte(0);
+ t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+ memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+ stringPostfix(t);
+ return TOKstring;
+ }
+ break;
+
+ default:
+ if (c & 0x80)
+ { p--;
+ unsigned u = decodeUTF();
+ p++;
+ if (u == PS || u == LS)
+ endOfLine();
+ stringbuffer.writeUTF8(u);
+ continue;
+ }
+ break;
+ }
+ stringbuffer.writeByte(c);
+ }
+}
+
+/**************************************
+ * Lex hex strings:
+ * x"0A ae 34FE BD"
+ */
+
+TOK Lexer::hexStringConstant(Token *t)
+{
+ unsigned c;
+ Loc start = loc();
+ unsigned n = 0;
+ unsigned v = ~0; // dead assignment, needed to suppress warning
+
+ p++;
+ stringbuffer.reset();
+ while (1)
+ {
+ c = *p++;
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ continue; // skip white space
+
+ case '\r':
+ if (*p == '\n')
+ continue; // ignore
+ // Treat isolated '\r' as if it were a '\n'
+ /* fall through */
+ case '\n':
+ endOfLine();
+ continue;
+
+ case 0:
+ case 0x1A:
+ error("unterminated string constant starting at %s", start.toChars());
+ t->ustring = (utf8_t *)const_cast<char *>("");
+ t->len = 0;
+ t->postfix = 0;
+ return TOKxstring;
+
+ case '"':
+ if (n & 1)
+ { error("odd number (%d) of hex characters in hex string", n);
+ stringbuffer.writeByte(v);
+ }
+ t->len = (unsigned)stringbuffer.offset;
+ stringbuffer.writeByte(0);
+ t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+ memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+ stringPostfix(t);
+ return TOKxstring;
+
+ default:
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c -= 'a' - 10;
+ else if (c >= 'A' && c <= 'F')
+ c -= 'A' - 10;
+ else if (c & 0x80)
+ { p--;
+ unsigned u = decodeUTF();
+ p++;
+ if (u == PS || u == LS)
+ endOfLine();
+ else
+ error("non-hex character \\u%04x in hex string", u);
+ }
+ else
+ error("non-hex character '%c' in hex string", c);
+ if (n & 1)
+ { v = (v << 4) | c;
+ stringbuffer.writeByte(v);
+ }
+ else
+ v = c;
+ n++;
+ break;
+ }
+ }
+}
+
+
+/**************************************
+ * Lex delimited strings:
+ * q"(foo(xxx))" // "foo(xxx)"
+ * q"[foo(]" // "foo("
+ * q"/foo]/" // "foo]"
+ * q"HERE
+ * foo
+ * HERE" // "foo\n"
+ * Input:
+ * p is on the "
+ */
+
+TOK Lexer::delimitedStringConstant(Token *t)
+{
+ unsigned c;
+ Loc start = loc();
+ unsigned delimleft = 0;
+ unsigned delimright = 0;
+ unsigned nest = 1;
+ unsigned nestcount = ~0; // dead assignment, needed to suppress warning
+ Identifier *hereid = NULL;
+ unsigned blankrol = 0;
+ unsigned startline = 0;
+
+ p++;
+ stringbuffer.reset();
+ while (1)
+ {
+ c = *p++;
+ //printf("c = '%c'\n", c);
+ switch (c)
+ {
+ case '\n':
+ Lnextline:
+ endOfLine();
+ startline = 1;
+ if (blankrol)
+ { blankrol = 0;
+ continue;
+ }
+ if (hereid)
+ {
+ stringbuffer.writeUTF8(c);
+ continue;
+ }
+ break;
+
+ case '\r':
+ if (*p == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ goto Lnextline;
+
+ case 0:
+ case 0x1A:
+ error("unterminated delimited string constant starting at %s", start.toChars());
+ t->ustring = (utf8_t *)const_cast<char *>("");
+ t->len = 0;
+ t->postfix = 0;
+ return TOKstring;
+
+ default:
+ if (c & 0x80)
+ { p--;
+ c = decodeUTF();
+ p++;
+ if (c == PS || c == LS)
+ goto Lnextline;
+ }
+ break;
+ }
+ if (delimleft == 0)
+ { delimleft = c;
+ nest = 1;
+ nestcount = 1;
+ if (c == '(')
+ delimright = ')';
+ else if (c == '{')
+ delimright = '}';
+ else if (c == '[')
+ delimright = ']';
+ else if (c == '<')
+ delimright = '>';
+ else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c)))
+ { // Start of identifier; must be a heredoc
+ Token tok;
+ p--;
+ scan(&tok); // read in heredoc identifier
+ if (tok.value != TOKidentifier)
+ { error("identifier expected for heredoc, not %s", tok.toChars());
+ delimright = c;
+ }
+ else
+ { hereid = tok.ident;
+ //printf("hereid = '%s'\n", hereid->toChars());
+ blankrol = 1;
+ }
+ nest = 0;
+ }
+ else
+ { delimright = c;
+ nest = 0;
+ if (isspace(c))
+ error("delimiter cannot be whitespace");
+ }
+ }
+ else
+ {
+ if (blankrol)
+ { error("heredoc rest of line should be blank");
+ blankrol = 0;
+ continue;
+ }
+ if (nest == 1)
+ {
+ if (c == delimleft)
+ nestcount++;
+ else if (c == delimright)
+ { nestcount--;
+ if (nestcount == 0)
+ goto Ldone;
+ }
+ }
+ else if (c == delimright)
+ goto Ldone;
+ if (startline && isalpha(c) && hereid)
+ { Token tok;
+ const utf8_t *psave = p;
+ p--;
+ scan(&tok); // read in possible heredoc identifier
+ //printf("endid = '%s'\n", tok.ident->toChars());
+ if (tok.value == TOKidentifier && tok.ident->equals(hereid))
+ { /* should check that rest of line is blank
+ */
+ goto Ldone;
+ }
+ p = psave;
+ }
+ stringbuffer.writeUTF8(c);
+ startline = 0;
+ }
+ }
+
+Ldone:
+ if (*p == '"')
+ p++;
+ else if (hereid)
+ error("delimited string must end in %s\"", hereid->toChars());
+ else
+ error("delimited string must end in %c\"", delimright);
+ t->len = (unsigned)stringbuffer.offset;
+ stringbuffer.writeByte(0);
+ t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+ memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+ stringPostfix(t);
+ return TOKstring;
+}
+
+/**************************************
+ * Lex delimited strings:
+ * q{ foo(xxx) } // " foo(xxx) "
+ * q{foo(} // "foo("
+ * q{{foo}"}"} // "{foo}"}""
+ * Input:
+ * p is on the q
+ */
+
+TOK Lexer::tokenStringConstant(Token *t)
+{
+ unsigned nest = 1;
+ Loc start = loc();
+ const utf8_t *pstart = ++p;
+
+ while (1)
+ { Token tok;
+
+ scan(&tok);
+ switch (tok.value)
+ {
+ case TOKlcurly:
+ nest++;
+ continue;
+
+ case TOKrcurly:
+ if (--nest == 0)
+ {
+ t->len = (unsigned)(p - 1 - pstart);
+ t->ustring = (utf8_t *)mem.xmalloc(t->len + 1);
+ memcpy(t->ustring, pstart, t->len);
+ t->ustring[t->len] = 0;
+ stringPostfix(t);
+ return TOKstring;
+ }
+ continue;
+
+ case TOKeof:
+ error("unterminated token string constant starting at %s", start.toChars());
+ t->ustring = (utf8_t *)const_cast<char *>("");
+ t->len = 0;
+ t->postfix = 0;
+ return TOKstring;
+
+ default:
+ continue;
+ }
+ }
+}
+
+
+
+/**************************************
+ */
+
+TOK Lexer::escapeStringConstant(Token *t)
+{
+ unsigned c;
+ Loc start = loc();
+
+ p++;
+ stringbuffer.reset();
+ while (1)
+ {
+ c = *p++;
+ switch (c)
+ {
+ case '\\':
+ switch (*p)
+ {
+ case 'u':
+ case 'U':
+ case '&':
+ c = escapeSequence();
+ stringbuffer.writeUTF8(c);
+ continue;
+
+ default:
+ c = escapeSequence();
+ break;
+ }
+ break;
+ case '\n':
+ endOfLine();
+ break;
+
+ case '\r':
+ if (*p == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ endOfLine();
+ break;
+
+ case '"':
+ t->len = (unsigned)stringbuffer.offset;
+ stringbuffer.writeByte(0);
+ t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.offset);
+ memcpy(t->ustring, stringbuffer.data, stringbuffer.offset);
+ stringPostfix(t);
+ return TOKstring;
+
+ case 0:
+ case 0x1A:
+ p--;
+ error("unterminated string constant starting at %s", start.toChars());
+ t->ustring = (utf8_t *)const_cast<char *>("");
+ t->len = 0;
+ t->postfix = 0;
+ return TOKstring;
+
+ default:
+ if (c & 0x80)
+ {
+ p--;
+ c = decodeUTF();
+ if (c == LS || c == PS)
+ { c = '\n';
+ endOfLine();
+ }
+ p++;
+ stringbuffer.writeUTF8(c);
+ continue;
+ }
+ break;
+ }
+ stringbuffer.writeByte(c);
+ }
+}
+
+/**************************************
+ */
+
+TOK Lexer::charConstant(Token *t)
+{
+ unsigned c;
+ TOK tk = TOKcharv;
+
+ //printf("Lexer::charConstant\n");
+ p++;
+ c = *p++;
+ switch (c)
+ {
+ case '\\':
+ switch (*p)
+ {
+ case 'u':
+ t->uns64value = escapeSequence();
+ tk = TOKwcharv;
+ break;
+
+ case 'U':
+ case '&':
+ t->uns64value = escapeSequence();
+ tk = TOKdcharv;
+ break;
+
+ default:
+ t->uns64value = escapeSequence();
+ break;
+ }
+ break;
+ case '\n':
+ L1:
+ endOfLine();
+ /* fall through */
+ case '\r':
+ case 0:
+ case 0x1A:
+ case '\'':
+ error("unterminated character constant");
+ t->uns64value = '?';
+ return tk;
+
+ default:
+ if (c & 0x80)
+ {
+ p--;
+ c = decodeUTF();
+ p++;
+ if (c == LS || c == PS)
+ goto L1;
+ if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE))
+ tk = TOKwcharv;
+ else
+ tk = TOKdcharv;
+ }
+ t->uns64value = c;
+ break;
+ }
+
+ if (*p != '\'')
+ {
+ error("unterminated character constant");
+ t->uns64value = '?';
+ return tk;
+ }
+ p++;
+ return tk;
+}
+
+/***************************************
+ * Get postfix of string literal.
+ */
+
+void Lexer::stringPostfix(Token *t)
+{
+ switch (*p)
+ {
+ case 'c':
+ case 'w':
+ case 'd':
+ t->postfix = *p;
+ p++;
+ break;
+
+ default:
+ t->postfix = 0;
+ break;
+ }
+}
+
+/**************************************
+ * Read in a number.
+ * If it's an integer, store it in tok.TKutok.Vlong.
+ * integers can be decimal, octal or hex
+ * Handle the suffixes U, UL, LU, L, etc.
+ * If it's double, store it in tok.TKutok.Vdouble.
+ * Returns:
+ * TKnum
+ * TKdouble,...
+ */
+
+TOK Lexer::number(Token *t)
+{
+ int base = 10;
+ const utf8_t *start = p;
+ unsigned c;
+ uinteger_t n = 0; // unsigned >=64 bit integer type
+ int d;
+ bool err = false;
+ bool overflow = false;
+
+ c = *p;
+ if (c == '0')
+ {
+ ++p;
+ c = *p;
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ n = c - '0';
+ ++p;
+ base = 8;
+ break;
+
+ case 'x':
+ case 'X':
+ ++p;
+ base = 16;
+ break;
+
+ case 'b':
+ case 'B':
+ ++p;
+ base = 2;
+ break;
+
+ case '.':
+ if (p[1] == '.')
+ goto Ldone; // if ".."
+ if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)
+ goto Ldone; // if ".identifier" or ".unicode"
+ goto Lreal; // '.' is part of current token
+
+ case 'i':
+ case 'f':
+ case 'F':
+ goto Lreal;
+
+ case '_':
+ ++p;
+ base = 8;
+ break;
+
+ case 'L':
+ if (p[1] == 'i')
+ goto Lreal;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ while (1)
+ {
+ c = *p;
+ switch (c)
+ {
+ case '0': case '1':
+ ++p;
+ d = c - '0';
+ break;
+
+ case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ if (base == 2 && !err)
+ {
+ error("binary digit expected");
+ err = true;
+ }
+ ++p;
+ d = c - '0';
+ break;
+
+ case '8': case '9':
+ ++p;
+ if (base < 10 && !err)
+ {
+ error("radix %d digit expected, not '%c'", base, c);
+ err = true;
+ }
+ d = c - '0';
+ break;
+
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ ++p;
+ if (base != 16)
+ {
+ if (c == 'e' || c == 'E' || c == 'f' || c == 'F')
+ goto Lreal;
+ if (!err)
+ {
+ error("radix %d digit expected, not '%c'", base, c);
+ err = true;
+ }
+ }
+ if (c >= 'a')
+ d = c + 10 - 'a';
+ else
+ d = c + 10 - 'A';
+ break;
+
+ case 'L':
+ if (p[1] == 'i')
+ goto Lreal;
+ goto Ldone;
+
+ case '.':
+ if (p[1] == '.')
+ goto Ldone; // if ".."
+ if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
+ goto Ldone; // if ".identifier" or ".unicode"
+ goto Lreal; // otherwise as part of a floating point literal
+
+ case 'p':
+ case 'P':
+ case 'i':
+ Lreal:
+ p = start;
+ return inreal(t);
+
+ case '_':
+ ++p;
+ continue;
+
+ default:
+ goto Ldone;
+ }
+
+ uinteger_t n2 = n * base;
+ if ((n2 / base != n || n2 + d < n))
+ {
+ overflow = true;
+ }
+ n = n2 + d;
+
+ // if n needs more than 64 bits
+ if (sizeof(n) > 8 &&
+ n > 0xFFFFFFFFFFFFFFFFULL)
+ {
+ overflow = true;
+ }
+ }
+
+Ldone:
+
+ if (overflow && !err)
+ {
+ error("integer overflow");
+ err = true;
+ }
+
+ enum FLAGS
+ {
+ FLAGS_none = 0,
+ FLAGS_decimal = 1, // decimal
+ FLAGS_unsigned = 2, // u or U suffix
+ FLAGS_long = 4, // L suffix
+ };
+
+ unsigned flags = (base == 10) ? FLAGS_decimal : FLAGS_none;
+
+ // Parse trailing 'u', 'U', 'l' or 'L' in any combination
+ const utf8_t *psuffix = p;
+ while (1)
+ {
+ utf8_t f;
+ switch (*p)
+ {
+ case 'U':
+ case 'u':
+ f = FLAGS_unsigned;
+ goto L1;
+
+ case 'l':
+ f = FLAGS_long;
+ error("lower case integer suffix 'l' is not allowed. Please use 'L' instead");
+ goto L1;
+
+ case 'L':
+ f = FLAGS_long;
+ L1:
+ p++;
+ if ((flags & f) && !err)
+ {
+ error("unrecognized token");
+ err = true;
+ }
+ flags = (FLAGS) (flags | f);
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (base == 8 && n >= 8)
+ error("octal literals 0%llo%.*s are no longer supported, use std.conv.octal!%llo%.*s instead",
+ n, p - psuffix, psuffix, n, p - psuffix, psuffix);
+
+ TOK result;
+ switch (flags)
+ {
+ case FLAGS_none:
+ /* Octal or Hexadecimal constant.
+ * First that fits: int, uint, long, ulong
+ */
+ if (n & 0x8000000000000000LL)
+ result = TOKuns64v;
+ else if (n & 0xFFFFFFFF00000000LL)
+ result = TOKint64v;
+ else if (n & 0x80000000)
+ result = TOKuns32v;
+ else
+ result = TOKint32v;
+ break;
+
+ case FLAGS_decimal:
+ /* First that fits: int, long, long long
+ */
+ if (n & 0x8000000000000000LL)
+ {
+ if (!err)
+ {
+ error("signed integer overflow");
+ err = true;
+ }
+ result = TOKuns64v;
+ }
+ else if (n & 0xFFFFFFFF80000000LL)
+ result = TOKint64v;
+ else
+ result = TOKint32v;
+ break;
+
+ case FLAGS_unsigned:
+ case FLAGS_decimal | FLAGS_unsigned:
+ /* First that fits: uint, ulong
+ */
+ if (n & 0xFFFFFFFF00000000LL)
+ result = TOKuns64v;
+ else
+ result = TOKuns32v;
+ break;
+
+ case FLAGS_decimal | FLAGS_long:
+ if (n & 0x8000000000000000LL)
+ {
+ if (!err)
+ {
+ error("signed integer overflow");
+ err = true;
+ }
+ result = TOKuns64v;
+ }
+ else
+ result = TOKint64v;
+ break;
+
+ case FLAGS_long:
+ if (n & 0x8000000000000000LL)
+ result = TOKuns64v;
+ else
+ result = TOKint64v;
+ break;
+
+ case FLAGS_unsigned | FLAGS_long:
+ case FLAGS_decimal | FLAGS_unsigned | FLAGS_long:
+ result = TOKuns64v;
+ break;
+
+ default:
+ assert(0);
+ }
+ t->uns64value = n;
+ return result;
+}
+
+/**************************************
+ * Read in characters, converting them to real.
+ * Bugs:
+ * Exponent overflow not detected.
+ * Too much requested precision is not detected.
+ */
+
+TOK Lexer::inreal(Token *t)
+{
+ //printf("Lexer::inreal()\n");
+ bool isWellformedString = true;
+ stringbuffer.reset();
+ const utf8_t *pstart = p;
+ char hex = 0;
+ unsigned c = *p++;
+
+ // Leading '0x'
+ if (c == '0')
+ {
+ c = *p++;
+ if (c == 'x' || c == 'X')
+ {
+ hex = true;
+ c = *p++;
+ }
+ }
+
+ // Digits to left of '.'
+ while (1)
+ {
+ if (c == '.')
+ {
+ c = *p++;
+ break;
+ }
+ if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
+ {
+ c = *p++;
+ continue;
+ }
+ break;
+ }
+
+ // Digits to right of '.'
+ while (1)
+ {
+ if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
+ {
+ c = *p++;
+ continue;
+ }
+ break;
+ }
+
+ if (c == 'e' || c == 'E' || (hex && (c == 'p' || c == 'P')))
+ {
+ c = *p++;
+ if (c == '-' || c == '+')
+ {
+ c = *p++;
+ }
+ bool anyexp = false;
+ while (1)
+ {
+ if (isdigit(c))
+ {
+ anyexp = true;
+ c = *p++;
+ continue;
+ }
+ if (c == '_')
+ {
+ c = *p++;
+ continue;
+ }
+ if (!anyexp)
+ {
+ error("missing exponent");
+ isWellformedString = false;
+ }
+ break;
+ }
+ }
+ else if (hex)
+ {
+ error("exponent required for hex float");
+ isWellformedString = false;
+ }
+ --p;
+ while (pstart < p)
+ {
+ if (*pstart != '_')
+ stringbuffer.writeByte(*pstart);
+ ++pstart;
+ }
+
+ stringbuffer.writeByte(0);
+ const char *sbufptr = (char *)stringbuffer.data;
+ TOK result;
+ bool isOutOfRange = false;
+ t->floatvalue = (isWellformedString ? CTFloat::parse(sbufptr, &isOutOfRange) : CTFloat::zero);
+ errno = 0;
+ switch (*p)
+ {
+ case 'F':
+ case 'f':
+ if (isWellformedString && !isOutOfRange)
+ isOutOfRange = Port::isFloat32LiteralOutOfRange(sbufptr);
+ result = TOKfloat32v;
+ p++;
+ break;
+
+ default:
+ if (isWellformedString && !isOutOfRange)
+ isOutOfRange = Port::isFloat64LiteralOutOfRange(sbufptr);
+ result = TOKfloat64v;
+ break;
+
+ case 'l':
+ error("use 'L' suffix instead of 'l'");
+ /* fall through */
+ case 'L':
+ result = TOKfloat80v;
+ p++;
+ break;
+ }
+ if (*p == 'i' || *p == 'I')
+ {
+ if (*p == 'I')
+ error("use 'i' suffix instead of 'I'");
+ p++;
+ switch (result)
+ {
+ case TOKfloat32v:
+ result = TOKimaginary32v;
+ break;
+ case TOKfloat64v:
+ result = TOKimaginary64v;
+ break;
+ case TOKfloat80v:
+ result = TOKimaginary80v;
+ break;
+ default: break;
+ }
+ }
+ const bool isLong = (result == TOKfloat80v || result == TOKimaginary80v);
+ if (isOutOfRange && !isLong)
+ {
+ const char *suffix = (result == TOKfloat32v || result == TOKimaginary32v) ? "f" : "";
+ error(scanloc, "number '%s%s' is not representable", (char *)stringbuffer.data, suffix);
+ }
+ return result;
+}
+
+/*********************************************
+ * parse:
+ * #line linnum [filespec]
+ * also allow __LINE__ for linnum, and __FILE__ for filespec
+ */
+
+void Lexer::poundLine()
+{
+ Token tok;
+ int linnum = this->scanloc.linnum;
+ char *filespec = NULL;
+ Loc loc = this->loc();
+
+ scan(&tok);
+ if (tok.value == TOKint32v || tok.value == TOKint64v)
+ {
+ int lin = (int)(tok.uns64value - 1);
+ if ((unsigned)lin != tok.uns64value - 1)
+ error("line number %lld out of range", (unsigned long long)tok.uns64value);
+ else
+ linnum = lin;
+ }
+ else if (tok.value == TOKline)
+ {
+ }
+ else
+ goto Lerr;
+
+ while (1)
+ {
+ switch (*p)
+ {
+ case 0:
+ case 0x1A:
+ case '\n':
+ Lnewline:
+ this->scanloc.linnum = linnum;
+ if (filespec)
+ this->scanloc.filename = filespec;
+ return;
+
+ case '\r':
+ p++;
+ if (*p != '\n')
+ { p--;
+ goto Lnewline;
+ }
+ continue;
+
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ p++;
+ continue; // skip white space
+
+ case '_':
+ if (memcmp(p, "__FILE__", 8) == 0)
+ {
+ p += 8;
+ filespec = mem.xstrdup(scanloc.filename);
+ continue;
+ }
+ goto Lerr;
+
+ case '"':
+ if (filespec)
+ goto Lerr;
+ stringbuffer.reset();
+ p++;
+ while (1)
+ { unsigned c;
+
+ c = *p;
+ switch (c)
+ {
+ case '\n':
+ case '\r':
+ case 0:
+ case 0x1A:
+ goto Lerr;
+
+ case '"':
+ stringbuffer.writeByte(0);
+ filespec = mem.xstrdup((char *)stringbuffer.data);
+ p++;
+ break;
+
+ default:
+ if (c & 0x80)
+ { unsigned u = decodeUTF();
+ if (u == PS || u == LS)
+ goto Lerr;
+ }
+ stringbuffer.writeByte(c);
+ p++;
+ continue;
+ }
+ break;
+ }
+ continue;
+
+ default:
+ if (*p & 0x80)
+ { unsigned u = decodeUTF();
+ if (u == PS || u == LS)
+ goto Lnewline;
+ }
+ goto Lerr;
+ }
+ }
+
+Lerr:
+ error(loc, "#line integer [\"filespec\"]\\n expected");
+}
+
+
+/********************************************
+ * Decode UTF character.
+ * Issue error messages for invalid sequences.
+ * Return decoded character, advance p to last character in UTF sequence.
+ */
+
+unsigned Lexer::decodeUTF()
+{
+ dchar_t u;
+ utf8_t c;
+ const utf8_t *s = p;
+ size_t len;
+ size_t idx;
+ const char *msg;
+
+ c = *s;
+ assert(c & 0x80);
+
+ // Check length of remaining string up to 6 UTF-8 characters
+ for (len = 1; len < 6 && s[len]; len++)
+ ;
+
+ idx = 0;
+ msg = utf_decodeChar(s, len, &idx, &u);
+ p += idx - 1;
+ if (msg)
+ {
+ error("%s", msg);
+ }
+ return u;
+}
+
+
+/***************************************************
+ * Parse doc comment embedded between t->ptr and p.
+ * Remove trailing blanks and tabs from lines.
+ * Replace all newlines with \n.
+ * Remove leading comment character from each line.
+ * Decide if it's a lineComment or a blockComment.
+ * Append to previous one for this token.
+ */
+
+void Lexer::getDocComment(Token *t, unsigned lineComment)
+{
+ /* ct tells us which kind of comment it is: '/', '*', or '+'
+ */
+ utf8_t ct = t->ptr[2];
+
+ /* Start of comment text skips over / * *, / + +, or / / /
+ */
+ const utf8_t *q = t->ptr + 3; // start of comment text
+
+ const utf8_t *qend = p;
+ if (ct == '*' || ct == '+')
+ qend -= 2;
+
+ /* Scan over initial row of ****'s or ++++'s or ////'s
+ */
+ for (; q < qend; q++)
+ {
+ if (*q != ct)
+ break;
+ }
+
+ /* Remove leading spaces until start of the comment
+ */
+ int linestart = 0;
+ if (ct == '/')
+ {
+ while (q < qend && (*q == ' ' || *q == '\t'))
+ ++q;
+ }
+ else if (q < qend)
+ {
+ if (*q == '\r')
+ {
+ ++q;
+ if (q < qend && *q == '\n')
+ ++q;
+ linestart = 1;
+ }
+ else if (*q == '\n')
+ {
+ ++q;
+ linestart = 1;
+ }
+ }
+
+ /* Remove trailing row of ****'s or ++++'s
+ */
+ if (ct != '/')
+ {
+ for (; q < qend; qend--)
+ {
+ if (qend[-1] != ct)
+ break;
+ }
+ }
+
+ /* Comment is now [q .. qend].
+ * Canonicalize it into buf[].
+ */
+ OutBuffer buf;
+
+ for (; q < qend; q++)
+ {
+ utf8_t c = *q;
+
+ switch (c)
+ {
+ case '*':
+ case '+':
+ if (linestart && c == ct)
+ { linestart = 0;
+ /* Trim preceding whitespace up to preceding \n
+ */
+ while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+ buf.offset--;
+ continue;
+ }
+ break;
+
+ case ' ':
+ case '\t':
+ break;
+
+ case '\r':
+ if (q[1] == '\n')
+ continue; // skip the \r
+ goto Lnewline;
+
+ default:
+ if (c == 226)
+ {
+ // If LS or PS
+ if (q[1] == 128 &&
+ (q[2] == 168 || q[2] == 169))
+ {
+ q += 2;
+ goto Lnewline;
+ }
+ }
+ linestart = 0;
+ break;
+
+ Lnewline:
+ c = '\n'; // replace all newlines with \n
+ /* fall through */
+ case '\n':
+ linestart = 1;
+
+ /* Trim trailing whitespace
+ */
+ while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+ buf.offset--;
+
+ break;
+ }
+ buf.writeByte(c);
+ }
+
+ /* Trim trailing whitespace (if the last line does not have newline)
+ */
+ if (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+ {
+ while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t'))
+ buf.offset--;
+ }
+
+ // Always end with a newline
+ if (!buf.offset || buf.data[buf.offset - 1] != '\n')
+ buf.writeByte('\n');
+
+ buf.writeByte(0);
+
+ // It's a line comment if the start of the doc comment comes
+ // after other non-whitespace on the same line.
+ const utf8_t** dc = (lineComment && anyToken)
+ ? &t->lineComment
+ : &t->blockComment;
+
+ // Combine with previous doc comment, if any
+ if (*dc)
+ *dc = combineComments(*dc, (utf8_t *)buf.data);
+ else
+ *dc = (utf8_t *)buf.extractData();
+}
+
+/********************************************
+ * Combine two document comments into one,
+ * separated by a newline.
+ */
+
+const utf8_t *Lexer::combineComments(const utf8_t *c1, const utf8_t *c2)
+{
+ //printf("Lexer::combineComments('%s', '%s')\n", c1, c2);
+
+ const utf8_t *c = c2;
+
+ if (c1)
+ {
+ c = c1;
+ if (c2)
+ {
+ size_t len1 = strlen((const char *)c1);
+ size_t len2 = strlen((const char *)c2);
+
+ int insertNewLine = 0;
+ if (len1 && c1[len1 - 1] != '\n')
+ {
+ ++len1;
+ insertNewLine = 1;
+ }
+
+ utf8_t *p = (utf8_t *)mem.xmalloc(len1 + 1 + len2 + 1);
+ memcpy(p, c1, len1 - insertNewLine);
+ if (insertNewLine)
+ p[len1 - 1] = '\n';
+
+ p[len1] = '\n';
+
+ memcpy(p + len1 + 1, c2, len2);
+ p[len1 + 1 + len2] = 0;
+ c = p;
+ }
+ }
+ return c;
+}
diff --git a/gcc/d/dmd/lexer.h b/gcc/d/dmd/lexer.h
new file mode 100644
index 0000000..988c06a
--- /dev/null
+++ b/gcc/d/dmd/lexer.h
@@ -0,0 +1,75 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "globals.h"
+#include "tokens.h"
+
+struct StringTable;
+class Identifier;
+
+class Lexer
+{
+public:
+ static OutBuffer stringbuffer;
+
+ Loc scanloc; // for error messages
+
+ const utf8_t *base; // pointer to start of buffer
+ const utf8_t *end; // past end of buffer
+ const utf8_t *p; // current character
+ const utf8_t *line; // start of current line
+ Token token;
+ bool doDocComment; // collect doc comment information
+ bool anyToken; // !=0 means seen at least one token
+ bool commentToken; // !=0 means comments are TOKcomment's
+ bool errors; // errors occurred during lexing or parsing
+
+ Lexer(const char *filename,
+ const utf8_t *base, size_t begoffset, size_t endoffset,
+ bool doDocComment, bool commentToken);
+
+ TOK nextToken();
+ TOK peekNext();
+ TOK peekNext2();
+ void scan(Token *t);
+ Token *peek(Token *t);
+ Token *peekPastParen(Token *t);
+ unsigned escapeSequence();
+ TOK wysiwygStringConstant(Token *t, int tc);
+ TOK hexStringConstant(Token *t);
+ TOK delimitedStringConstant(Token *t);
+ TOK tokenStringConstant(Token *t);
+ TOK escapeStringConstant(Token *t);
+ TOK charConstant(Token *t);
+ void stringPostfix(Token *t);
+ TOK number(Token *t);
+ TOK inreal(Token *t);
+
+ Loc loc()
+ {
+ scanloc.charnum = (unsigned)(1 + p-line);
+ return scanloc;
+ }
+
+ void error(const char *format, ...);
+ void error(Loc loc, const char *format, ...);
+ void deprecation(const char *format, ...);
+ void poundLine();
+ unsigned decodeUTF();
+ void getDocComment(Token *t, unsigned lineComment);
+
+ static const utf8_t *combineComments(const utf8_t *c1, const utf8_t *c2);
+
+private:
+ void endOfLine();
+};
diff --git a/gcc/d/dmd/macro.h b/gcc/d/dmd/macro.h
new file mode 100644
index 0000000..006f118
--- /dev/null
+++ b/gcc/d/dmd/macro.h
@@ -0,0 +1,42 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/macro.h
+ */
+
+#pragma once
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "root/root.h"
+
+
+struct Macro
+{
+ private:
+ Macro *next; // next in list
+
+ const utf8_t *name; // macro name
+ size_t namelen; // length of macro name
+
+ const utf8_t *text; // macro replacement text
+ size_t textlen; // length of replacement text
+
+ int inuse; // macro is in use (don't expand)
+
+ Macro(const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen);
+ Macro *search(const utf8_t *name, size_t namelen);
+
+ public:
+ static Macro *define(Macro **ptable, const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen);
+
+ void expand(OutBuffer *buf, size_t start, size_t *pend,
+ const utf8_t *arg, size_t arglen);
+};
diff --git a/gcc/d/dmd/mangle.h b/gcc/d/dmd/mangle.h
new file mode 100644
index 0000000..72fc89a
--- /dev/null
+++ b/gcc/d/dmd/mangle.h
@@ -0,0 +1,33 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/mangle.h
+ */
+
+#pragma once
+
+class Dsymbol;
+class Expression;
+class FuncDeclaration;
+class TemplateInstance;
+class Type;
+struct OutBuffer;
+
+// In cppmangle.c
+const char *toCppMangleItanium(Dsymbol *s);
+const char *cppTypeInfoMangleItanium(Dsymbol *s);
+
+// In cppmanglewin.c
+const char *toCppMangleMSVC(Dsymbol *s);
+const char *cppTypeInfoMangleMSVC(Dsymbol *s);
+
+// In dmangle.c
+const char *mangleExact(FuncDeclaration *fd);
+void mangleToBuffer(Type *s, OutBuffer *buf);
+void mangleToBuffer(Expression *s, OutBuffer *buf);
+void mangleToBuffer(Dsymbol *s, OutBuffer *buf);
+void mangleToBuffer(TemplateInstance *s, OutBuffer *buf);
diff --git a/gcc/d/dmd/mars.h b/gcc/d/dmd/mars.h
new file mode 100644
index 0000000..9cc5bb8
--- /dev/null
+++ b/gcc/d/dmd/mars.h
@@ -0,0 +1,95 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/mars.h
+ */
+
+#pragma once
+
+/*
+It is very important to use version control macros correctly - the
+idea is that host and target are independent. If these are done
+correctly, cross compilers can be built.
+The host compiler and host operating system are also different,
+and are predefined by the host compiler. The ones used in
+dmd are:
+
+Macros defined by the compiler, not the code:
+
+ Compiler:
+ __DMC__ Digital Mars compiler
+ _MSC_VER Microsoft compiler
+ __GNUC__ Gnu compiler
+ __clang__ Clang compiler
+
+ Host operating system:
+ _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s,
+ Windows 2000, Win XP, Vista
+ _WIN64 Windows for AMD64
+ __linux__ Linux
+ __APPLE__ Mac OSX
+ __FreeBSD__ FreeBSD
+ __OpenBSD__ OpenBSD
+ __sun Solaris, OpenSolaris, SunOS, OpenIndiana, etc
+
+For the target systems, there are the target operating system and
+the target object file format:
+
+ Target operating system:
+ TARGET_WINDOS Covers 32 bit windows and 64 bit windows
+ TARGET_LINUX Covers 32 and 64 bit linux
+ TARGET_OSX Covers 32 and 64 bit Mac OSX
+ TARGET_FREEBSD Covers 32 and 64 bit FreeBSD
+ TARGET_OPENBSD Covers 32 and 64 bit OpenBSD
+ TARGET_SOLARIS Covers 32 and 64 bit Solaris
+
+ It is expected that the compiler for each platform will be able
+ to generate 32 and 64 bit code from the same compiler binary.
+
+ There are currently no macros for byte endianness order.
+ */
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+#ifdef __DMC__
+#ifdef DEBUG
+#undef assert
+#define assert(e) (static_cast<void>((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt())))
+#endif
+#endif
+
+void unittests();
+
+struct OutBuffer;
+
+#include "globals.h"
+
+#include "root/ctfloat.h"
+
+#include "complex_t.h"
+
+#include "errors.h"
+
+class Dsymbol;
+class Library;
+struct File;
+void obj_start(char *srcfile);
+void obj_end(Library *library, File *objfile);
+void obj_append(Dsymbol *s);
+void obj_write_deferred(Library *library);
+
+/// Utility functions used by both main and frontend.
+void readFile(Loc loc, File *f);
+void writeFile(Loc loc, File *f);
+void ensurePathToNameExists(Loc loc, const char *name);
+
+const char *importHint(const char *s);
+/// Little helper function for writing out deps.
+void escapePath(OutBuffer *buf, const char *fname);
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
new file mode 100644
index 0000000..399b008
--- /dev/null
+++ b/gcc/d/dmd/module.h
@@ -0,0 +1,179 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/module.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "dsymbol.h"
+
+class ClassDeclaration;
+struct ModuleDeclaration;
+struct Macro;
+struct Escape;
+class VarDeclaration;
+class Library;
+
+enum PKG
+{
+ PKGunknown, // not yet determined whether it's a package.d or not
+ PKGmodule, // already determined that's an actual package.d
+ PKGpackage // already determined that's an actual package
+};
+
+class Package : public ScopeDsymbol
+{
+public:
+ PKG isPkgMod;
+ unsigned tag; // auto incremented tag, used to mask package tree in scopes
+ Module *mod; // != NULL if isPkgMod == PKGmodule
+
+ Package(Identifier *ident);
+ const char *kind();
+
+ static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg);
+
+ Package *isPackage() { return this; }
+
+ bool isAncestorPackageOf(const Package * const pkg) const;
+
+ void semantic(Scope *);
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ void accept(Visitor *v) { v->visit(this); }
+
+ Module *isPackageMod();
+};
+
+class Module : public Package
+{
+public:
+ static Module *rootModule;
+ static DsymbolTable *modules; // symbol table of all modules
+ static Modules amodules; // array of all modules
+ static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them
+ static Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them
+ static Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them
+ static unsigned dprogress; // progress resolving the deferred list
+ static void _init();
+
+ static AggregateDeclaration *moduleinfo;
+
+
+ const char *arg; // original argument name
+ ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
+ File *srcfile; // input source file
+ const char* srcfilePath; // the path prefix to the srcfile if it applies
+ File *objfile; // output .obj file
+ File *hdrfile; // 'header' file
+ File *docfile; // output documentation file
+ unsigned errors; // if any errors in file
+ unsigned numlines; // number of lines in source file
+ int isDocFile; // if it is a documentation input file, not D source
+ bool isPackageFile; // if it is a package.d
+ int needmoduleinfo;
+
+ int selfimports; // 0: don't know, 1: does not, 2: does
+ bool selfImports(); // returns true if module imports itself
+
+ int rootimports; // 0: don't know, 1: does not, 2: does
+ bool rootImports(); // returns true if module imports root module
+
+ int insearch;
+ Identifier *searchCacheIdent;
+ Dsymbol *searchCacheSymbol; // cached value of search
+ int searchCacheFlags; // cached flags
+
+ // module from command line we're imported from,
+ // i.e. a module that will be taken all the
+ // way to an object file
+ Module *importedFrom;
+
+ Dsymbols *decldefs; // top level declarations for this Module
+
+ Modules aimports; // all imported modules
+
+ unsigned debuglevel; // debug level
+ Strings *debugids; // debug identifiers
+ Strings *debugidsNot; // forward referenced debug identifiers
+
+ unsigned versionlevel; // version level
+ Strings *versionids; // version identifiers
+ Strings *versionidsNot; // forward referenced version identifiers
+
+ Macro *macrotable; // document comment macros
+ Escape *escapetable; // document comment escapes
+
+ size_t nameoffset; // offset of module name from start of ModuleInfo
+ size_t namelen; // length of module name in characters
+
+ Module(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
+ static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
+
+ static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
+
+ const char *kind();
+ File *setOutfile(const char *name, const char *dir, const char *arg, const char *ext);
+ void setDocfile();
+ bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise.
+ Module *parse(); // syntactic parse
+ void importAll(Scope *sc);
+ void semantic(Scope *); // semantic analysis
+ void semantic2(Scope *); // pass 2 semantic analysis
+ void semantic3(Scope *); // pass 3 semantic analysis
+ int needModuleInfo();
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ bool isPackageAccessible(Package *p, Prot protection, int flags = 0);
+ Dsymbol *symtabInsert(Dsymbol *s);
+ void deleteObjFile();
+ static void addDeferredSemantic(Dsymbol *s);
+ static void addDeferredSemantic2(Dsymbol *s);
+ static void addDeferredSemantic3(Dsymbol *s);
+ static void runDeferredSemantic();
+ static void runDeferredSemantic2();
+ static void runDeferredSemantic3();
+ static void clearCache();
+ int imports(Module *m);
+
+ bool isRoot() { return this->importedFrom == this; }
+ // true if the module source file is directly
+ // listed in command line.
+ bool isCoreModule(Identifier *ident);
+
+ // Back end
+
+ int doppelganger; // sub-module
+ Symbol *cov; // private uint[] __coverage;
+ unsigned *covb; // bit array of valid code line numbers
+
+ Symbol *sictor; // module order independent constructor
+ Symbol *sctor; // module constructor
+ Symbol *sdtor; // module destructor
+ Symbol *ssharedctor; // module shared constructor
+ Symbol *sshareddtor; // module shared destructor
+ Symbol *stest; // module unit test
+
+ Symbol *sfilename; // symbol for filename
+
+ Module *isModule() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+
+struct ModuleDeclaration
+{
+ Loc loc;
+ Identifier *id;
+ Identifiers *packages; // array of Identifier's representing packages
+ bool isdeprecated; // if it is a deprecated module
+ Expression *msg;
+
+ ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id);
+
+ const char *toChars();
+};
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
new file mode 100644
index 0000000..a4c38e8
--- /dev/null
+++ b/gcc/d/dmd/mtype.c
@@ -0,0 +1,9410 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/mtype.c
+ */
+
+#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more
+#define __USE_ISOC99 1 // so signbit() gets defined
+
+#include <math.h>
+#include <stdio.h>
+#include <assert.h>
+#include <float.h>
+
+#if _MSC_VER
+#include <malloc.h>
+#include <limits>
+#elif __MINGW32__
+#include <malloc.h>
+#endif
+
+#include "checkedint.h"
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "mangle.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "module.h"
+#include "import.h"
+#include "aggregate.h"
+#include "hdrgen.h"
+#include "target.h"
+
+bool symbolIsVisible(Scope *sc, Dsymbol *s);
+typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
+Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
+Expression *typeToExpression(Type *t);
+Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
+
+int Tsize_t = Tuns32;
+int Tptrdiff_t = Tint32;
+
+/***************************** Type *****************************/
+
+ClassDeclaration *Type::dtypeinfo;
+ClassDeclaration *Type::typeinfoclass;
+ClassDeclaration *Type::typeinfointerface;
+ClassDeclaration *Type::typeinfostruct;
+ClassDeclaration *Type::typeinfopointer;
+ClassDeclaration *Type::typeinfoarray;
+ClassDeclaration *Type::typeinfostaticarray;
+ClassDeclaration *Type::typeinfoassociativearray;
+ClassDeclaration *Type::typeinfovector;
+ClassDeclaration *Type::typeinfoenum;
+ClassDeclaration *Type::typeinfofunction;
+ClassDeclaration *Type::typeinfodelegate;
+ClassDeclaration *Type::typeinfotypelist;
+ClassDeclaration *Type::typeinfoconst;
+ClassDeclaration *Type::typeinfoinvariant;
+ClassDeclaration *Type::typeinfoshared;
+ClassDeclaration *Type::typeinfowild;
+
+TemplateDeclaration *Type::rtinfo;
+
+Type *Type::tvoid;
+Type *Type::tint8;
+Type *Type::tuns8;
+Type *Type::tint16;
+Type *Type::tuns16;
+Type *Type::tint32;
+Type *Type::tuns32;
+Type *Type::tint64;
+Type *Type::tuns64;
+Type *Type::tint128;
+Type *Type::tuns128;
+Type *Type::tfloat32;
+Type *Type::tfloat64;
+Type *Type::tfloat80;
+
+Type *Type::timaginary32;
+Type *Type::timaginary64;
+Type *Type::timaginary80;
+
+Type *Type::tcomplex32;
+Type *Type::tcomplex64;
+Type *Type::tcomplex80;
+
+Type *Type::tbool;
+Type *Type::tchar;
+Type *Type::twchar;
+Type *Type::tdchar;
+
+Type *Type::tshiftcnt;
+Type *Type::terror;
+Type *Type::tnull;
+
+Type *Type::tsize_t;
+Type *Type::tptrdiff_t;
+Type *Type::thash_t;
+
+Type *Type::tvoidptr;
+Type *Type::tstring;
+Type *Type::twstring;
+Type *Type::tdstring;
+Type *Type::tvalist;
+Type *Type::basic[TMAX];
+unsigned char Type::sizeTy[TMAX];
+StringTable Type::stringtable;
+
+void initTypeMangle();
+
+Type::Type(TY ty)
+{
+ this->ty = ty;
+ this->mod = 0;
+ this->deco = NULL;
+ this->cto = NULL;
+ this->ito = NULL;
+ this->sto = NULL;
+ this->scto = NULL;
+ this->wto = NULL;
+ this->wcto = NULL;
+ this->swto = NULL;
+ this->swcto = NULL;
+ this->pto = NULL;
+ this->rto = NULL;
+ this->arrayof = NULL;
+ this->vtinfo = NULL;
+ this->ctype = NULL;
+}
+
+const char *Type::kind()
+{
+ assert(false); // should be overridden
+ return NULL;
+}
+
+Type *Type::copy()
+{
+ void *pt = mem.xmalloc(sizeTy[ty]);
+ Type *t = (Type *)memcpy(pt, (void *)this, sizeTy[ty]);
+ return t;
+}
+
+Type *Type::syntaxCopy()
+{
+ print();
+ fprintf(stderr, "ty = %d\n", ty);
+ assert(0);
+ return this;
+}
+
+bool Type::equals(RootObject *o)
+{
+ Type *t = (Type *)o;
+ //printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
+ // deco strings are unique
+ // and semantic() has been run
+ if (this == o || ((t && deco == t->deco) && deco != NULL))
+ {
+ //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+ return true;
+ }
+ //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
+ return false;
+}
+
+bool Type::equivalent(Type *t)
+{
+ return immutableOf()->equals(t->immutableOf());
+}
+
+void Type::_init()
+{
+ stringtable._init(14000);
+
+ for (size_t i = 0; i < TMAX; i++)
+ sizeTy[i] = sizeof(TypeBasic);
+ sizeTy[Tsarray] = sizeof(TypeSArray);
+ sizeTy[Tarray] = sizeof(TypeDArray);
+ sizeTy[Taarray] = sizeof(TypeAArray);
+ sizeTy[Tpointer] = sizeof(TypePointer);
+ sizeTy[Treference] = sizeof(TypeReference);
+ sizeTy[Tfunction] = sizeof(TypeFunction);
+ sizeTy[Tdelegate] = sizeof(TypeDelegate);
+ sizeTy[Tident] = sizeof(TypeIdentifier);
+ sizeTy[Tinstance] = sizeof(TypeInstance);
+ sizeTy[Ttypeof] = sizeof(TypeTypeof);
+ sizeTy[Tenum] = sizeof(TypeEnum);
+ sizeTy[Tstruct] = sizeof(TypeStruct);
+ sizeTy[Tclass] = sizeof(TypeClass);
+ sizeTy[Ttuple] = sizeof(TypeTuple);
+ sizeTy[Tslice] = sizeof(TypeSlice);
+ sizeTy[Treturn] = sizeof(TypeReturn);
+ sizeTy[Terror] = sizeof(TypeError);
+ sizeTy[Tnull] = sizeof(TypeNull);
+ sizeTy[Tvector] = sizeof(TypeVector);
+
+ initTypeMangle();
+
+ // Set basic types
+ static TY basetab[] =
+ { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
+ Tint128, Tuns128,
+ Tfloat32, Tfloat64, Tfloat80,
+ Timaginary32, Timaginary64, Timaginary80,
+ Tcomplex32, Tcomplex64, Tcomplex80,
+ Tbool,
+ Tchar, Twchar, Tdchar, Terror };
+
+ for (size_t i = 0; basetab[i] != Terror; i++)
+ {
+ Type *t = new TypeBasic(basetab[i]);
+ t = t->merge();
+ basic[basetab[i]] = t;
+ }
+ basic[Terror] = new TypeError();
+
+ tvoid = basic[Tvoid];
+ tint8 = basic[Tint8];
+ tuns8 = basic[Tuns8];
+ tint16 = basic[Tint16];
+ tuns16 = basic[Tuns16];
+ tint32 = basic[Tint32];
+ tuns32 = basic[Tuns32];
+ tint64 = basic[Tint64];
+ tuns64 = basic[Tuns64];
+ tint128 = basic[Tint128];
+ tuns128 = basic[Tuns128];
+ tfloat32 = basic[Tfloat32];
+ tfloat64 = basic[Tfloat64];
+ tfloat80 = basic[Tfloat80];
+
+ timaginary32 = basic[Timaginary32];
+ timaginary64 = basic[Timaginary64];
+ timaginary80 = basic[Timaginary80];
+
+ tcomplex32 = basic[Tcomplex32];
+ tcomplex64 = basic[Tcomplex64];
+ tcomplex80 = basic[Tcomplex80];
+
+ tbool = basic[Tbool];
+ tchar = basic[Tchar];
+ twchar = basic[Twchar];
+ tdchar = basic[Tdchar];
+
+ tshiftcnt = tint32;
+ terror = basic[Terror];
+ tnull = basic[Tnull];
+ tnull = new TypeNull();
+ tnull->deco = tnull->merge()->deco;
+
+ tvoidptr = tvoid->pointerTo();
+ tstring = tchar->immutableOf()->arrayOf();
+ twstring = twchar->immutableOf()->arrayOf();
+ tdstring = tdchar->immutableOf()->arrayOf();
+ tvalist = Target::va_listType();
+
+ if (global.params.isLP64)
+ {
+ Tsize_t = Tuns64;
+ Tptrdiff_t = Tint64;
+ }
+ else
+ {
+ Tsize_t = Tuns32;
+ Tptrdiff_t = Tint32;
+ }
+
+ tsize_t = basic[Tsize_t];
+ tptrdiff_t = basic[Tptrdiff_t];
+ thash_t = tsize_t;
+}
+
+d_uns64 Type::size()
+{
+ return size(Loc());
+}
+
+d_uns64 Type::size(Loc loc)
+{
+ error(loc, "no size for type %s", toChars());
+ return SIZE_INVALID;
+}
+
+unsigned Type::alignsize()
+{
+ return (unsigned)size(Loc());
+}
+
+Type *Type::semantic(Loc loc, Scope *)
+{
+ if (ty == Tint128 || ty == Tuns128)
+ {
+ error(loc, "cent and ucent types not implemented");
+ return terror;
+ }
+
+ return merge();
+}
+
+Type *Type::trySemantic(Loc loc, Scope *sc)
+{
+ //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
+ unsigned errors = global.startGagging();
+ Type *t = semantic(loc, sc);
+ if (global.endGagging(errors) || t->ty == Terror) // if any errors happened
+ {
+ t = NULL;
+ }
+ //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
+ return t;
+}
+
+/********************************
+ * Return a copy of this type with all attributes null-initialized.
+ * Useful for creating a type with different modifiers.
+ */
+
+Type *Type::nullAttributes()
+{
+ unsigned sz = sizeTy[ty];
+ void *pt = mem.xmalloc(sz);
+ Type *t = (Type *)memcpy(pt, (void *)this, sz);
+ t->deco = NULL;
+ t->arrayof = NULL;
+ t->pto = NULL;
+ t->rto = NULL;
+ t->cto = NULL;
+ t->ito = NULL;
+ t->sto = NULL;
+ t->scto = NULL;
+ t->wto = NULL;
+ t->wcto = NULL;
+ t->swto = NULL;
+ t->swcto = NULL;
+ t->vtinfo = NULL;
+ t->ctype = NULL;
+ if (t->ty == Tstruct) ((TypeStruct *)t)->att = RECfwdref;
+ if (t->ty == Tclass) ((TypeClass *)t)->att = RECfwdref;
+ return t;
+}
+
+/********************************
+ * Convert to 'const'.
+ */
+
+Type *Type::constOf()
+{
+ //printf("Type::constOf() %p %s\n", this, toChars());
+ if (mod == MODconst)
+ return this;
+ if (cto)
+ {
+ assert(cto->mod == MODconst);
+ return cto;
+ }
+ Type *t = makeConst();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("-Type::constOf() %p %s\n", t, t->toChars());
+ return t;
+}
+
+/********************************
+ * Convert to 'immutable'.
+ */
+
+Type *Type::immutableOf()
+{
+ //printf("Type::immutableOf() %p %s\n", this, toChars());
+ if (isImmutable())
+ return this;
+ if (ito)
+ {
+ assert(ito->isImmutable());
+ return ito;
+ }
+ Type *t = makeImmutable();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("\t%p\n", t);
+ return t;
+}
+
+/********************************
+ * Make type mutable.
+ */
+
+Type *Type::mutableOf()
+{
+ //printf("Type::mutableOf() %p, %s\n", this, toChars());
+ Type *t = this;
+ if (isImmutable())
+ {
+ t = ito; // immutable => naked
+ assert(!t || (t->isMutable() && !t->isShared()));
+ }
+ else if (isConst())
+ {
+ if (isShared())
+ {
+ if (isWild())
+ t = swcto; // shared wild const -> shared
+ else
+ t = sto; // shared const => shared
+ }
+ else
+ {
+ if (isWild())
+ t = wcto; // wild const -> naked
+ else
+ t = cto; // const => naked
+ }
+ assert(!t || t->isMutable());
+ }
+ else if (isWild())
+ {
+ if (isShared())
+ t = sto; // shared wild => shared
+ else
+ t = wto; // wild => naked
+ assert(!t || t->isMutable());
+ }
+ if (!t)
+ {
+ t = makeMutable();
+ t = t->merge();
+ t->fixTo(this);
+ }
+ else
+ t = t->merge();
+ assert(t->isMutable());
+ return t;
+}
+
+Type *Type::sharedOf()
+{
+ //printf("Type::sharedOf() %p, %s\n", this, toChars());
+ if (mod == MODshared)
+ return this;
+ if (sto)
+ {
+ assert(sto->mod == MODshared);
+ return sto;
+ }
+ Type *t = makeShared();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("\t%p\n", t);
+ return t;
+}
+
+Type *Type::sharedConstOf()
+{
+ //printf("Type::sharedConstOf() %p, %s\n", this, toChars());
+ if (mod == (MODshared | MODconst))
+ return this;
+ if (scto)
+ {
+ assert(scto->mod == (MODshared | MODconst));
+ return scto;
+ }
+ Type *t = makeSharedConst();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("\t%p\n", t);
+ return t;
+}
+
+
+/********************************
+ * Make type unshared.
+ * 0 => 0
+ * const => const
+ * immutable => immutable
+ * shared => 0
+ * shared const => const
+ * wild => wild
+ * wild const => wild const
+ * shared wild => wild
+ * shared wild const => wild const
+ */
+
+Type *Type::unSharedOf()
+{
+ //printf("Type::unSharedOf() %p, %s\n", this, toChars());
+ Type *t = this;
+
+ if (isShared())
+ {
+ if (isWild())
+ {
+ if (isConst())
+ t = wcto; // shared wild const => wild const
+ else
+ t = wto; // shared wild => wild
+ }
+ else
+ {
+ if (isConst())
+ t = cto; // shared const => const
+ else
+ t = sto; // shared => naked
+ }
+ assert(!t || !t->isShared());
+ }
+
+ if (!t)
+ {
+ t = this->nullAttributes();
+ t->mod = mod & ~MODshared;
+ t->ctype = ctype;
+ t = t->merge();
+
+ t->fixTo(this);
+ }
+ else
+ t = t->merge();
+ assert(!t->isShared());
+ return t;
+}
+
+/********************************
+ * Convert to 'wild'.
+ */
+
+Type *Type::wildOf()
+{
+ //printf("Type::wildOf() %p %s\n", this, toChars());
+ if (mod == MODwild)
+ return this;
+ if (wto)
+ {
+ assert(wto->mod == MODwild);
+ return wto;
+ }
+ Type *t = makeWild();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("\t%p %s\n", t, t->toChars());
+ return t;
+}
+
+Type *Type::wildConstOf()
+{
+ //printf("Type::wildConstOf() %p %s\n", this, toChars());
+ if (mod == MODwildconst)
+ return this;
+ if (wcto)
+ {
+ assert(wcto->mod == MODwildconst);
+ return wcto;
+ }
+ Type *t = makeWildConst();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("\t%p %s\n", t, t->toChars());
+ return t;
+}
+
+Type *Type::sharedWildOf()
+{
+ //printf("Type::sharedWildOf() %p, %s\n", this, toChars());
+ if (mod == (MODshared | MODwild))
+ return this;
+ if (swto)
+ {
+ assert(swto->mod == (MODshared | MODwild));
+ return swto;
+ }
+ Type *t = makeSharedWild();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("\t%p %s\n", t, t->toChars());
+ return t;
+}
+
+Type *Type::sharedWildConstOf()
+{
+ //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars());
+ if (mod == (MODshared | MODwildconst))
+ return this;
+ if (swcto)
+ {
+ assert(swcto->mod == (MODshared | MODwildconst));
+ return swcto;
+ }
+ Type *t = makeSharedWildConst();
+ t = t->merge();
+ t->fixTo(this);
+ //printf("\t%p %s\n", t, t->toChars());
+ return t;
+}
+
+/**********************************
+ * For our new type 'this', which is type-constructed from t,
+ * fill in the cto, ito, sto, scto, wto shortcuts.
+ */
+
+void Type::fixTo(Type *t)
+{
+ // If fixing this: immutable(T*) by t: immutable(T)*,
+ // cache t to this->xto won't break transitivity.
+ Type *mto = NULL;
+ Type *tn = nextOf();
+ if (!tn || (ty != Tsarray && tn->mod == t->nextOf()->mod))
+ {
+ switch (t->mod)
+ {
+ case 0: mto = t; break;
+ case MODconst: cto = t; break;
+ case MODwild: wto = t; break;
+ case MODwildconst: wcto = t; break;
+ case MODshared: sto = t; break;
+ case MODshared | MODconst: scto = t; break;
+ case MODshared | MODwild: swto = t; break;
+ case MODshared | MODwildconst: swcto = t; break;
+ case MODimmutable: ito = t; break;
+ }
+ }
+
+ assert(mod != t->mod);
+#define X(m, n) (((m) << 4) | (n))
+ switch (mod)
+ {
+ case 0:
+ break;
+
+ case MODconst:
+ cto = mto;
+ t->cto = this;
+ break;
+
+ case MODwild:
+ wto = mto;
+ t->wto = this;
+ break;
+
+ case MODwildconst:
+ wcto = mto;
+ t->wcto = this;
+ break;
+
+ case MODshared:
+ sto = mto;
+ t->sto = this;
+ break;
+
+ case MODshared | MODconst:
+ scto = mto;
+ t->scto = this;
+ break;
+
+ case MODshared | MODwild:
+ swto = mto;
+ t->swto = this;
+ break;
+
+ case MODshared | MODwildconst:
+ swcto = mto;
+ t->swcto = this;
+ break;
+
+ case MODimmutable:
+ t->ito = this;
+ if (t-> cto) t-> cto->ito = this;
+ if (t-> sto) t-> sto->ito = this;
+ if (t-> scto) t-> scto->ito = this;
+ if (t-> wto) t-> wto->ito = this;
+ if (t-> wcto) t-> wcto->ito = this;
+ if (t-> swto) t-> swto->ito = this;
+ if (t->swcto) t->swcto->ito = this;
+ break;
+
+ default:
+ assert(0);
+ }
+#undef X
+
+ check();
+ t->check();
+ //printf("fixTo: %s, %s\n", toChars(), t->toChars());
+}
+
+/***************************
+ * Look for bugs in constructing types.
+ */
+
+void Type::check()
+{
+ switch (mod)
+ {
+ case 0:
+ if (cto) assert(cto->mod == MODconst);
+ if (ito) assert(ito->mod == MODimmutable);
+ if (sto) assert(sto->mod == MODshared);
+ if (scto) assert(scto->mod == (MODshared | MODconst));
+ if (wto) assert(wto->mod == MODwild);
+ if (wcto) assert(wcto->mod == MODwildconst);
+ if (swto) assert(swto->mod == (MODshared | MODwild));
+ if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ case MODconst:
+ if (cto) assert(cto->mod == 0);
+ if (ito) assert(ito->mod == MODimmutable);
+ if (sto) assert(sto->mod == MODshared);
+ if (scto) assert(scto->mod == (MODshared | MODconst));
+ if (wto) assert(wto->mod == MODwild);
+ if (wcto) assert(wcto->mod == MODwildconst);
+ if (swto) assert(swto->mod == (MODshared | MODwild));
+ if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ case MODwild:
+ if (cto) assert(cto->mod == MODconst);
+ if (ito) assert(ito->mod == MODimmutable);
+ if (sto) assert(sto->mod == MODshared);
+ if (scto) assert(scto->mod == (MODshared | MODconst));
+ if (wto) assert(wto->mod == 0);
+ if (wcto) assert(wcto->mod == MODwildconst);
+ if (swto) assert(swto->mod == (MODshared | MODwild));
+ if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ case MODwildconst:
+ assert(! cto || cto->mod == MODconst);
+ assert(! ito || ito->mod == MODimmutable);
+ assert(! sto || sto->mod == MODshared);
+ assert(! scto || scto->mod == (MODshared | MODconst));
+ assert(! wto || wto->mod == MODwild);
+ assert(! wcto || wcto->mod == 0);
+ assert(! swto || swto->mod == (MODshared | MODwild));
+ assert(!swcto || swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ case MODshared:
+ if (cto) assert(cto->mod == MODconst);
+ if (ito) assert(ito->mod == MODimmutable);
+ if (sto) assert(sto->mod == 0);
+ if (scto) assert(scto->mod == (MODshared | MODconst));
+ if (wto) assert(wto->mod == MODwild);
+ if (wcto) assert(wcto->mod == MODwildconst);
+ if (swto) assert(swto->mod == (MODshared | MODwild));
+ if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ case MODshared | MODconst:
+ if (cto) assert(cto->mod == MODconst);
+ if (ito) assert(ito->mod == MODimmutable);
+ if (sto) assert(sto->mod == MODshared);
+ if (scto) assert(scto->mod == 0);
+ if (wto) assert(wto->mod == MODwild);
+ if (wcto) assert(wcto->mod == MODwildconst);
+ if (swto) assert(swto->mod == (MODshared | MODwild));
+ if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ case MODshared | MODwild:
+ if (cto) assert(cto->mod == MODconst);
+ if (ito) assert(ito->mod == MODimmutable);
+ if (sto) assert(sto->mod == MODshared);
+ if (scto) assert(scto->mod == (MODshared | MODconst));
+ if (wto) assert(wto->mod == MODwild);
+ if (wcto) assert(wcto->mod == MODwildconst);
+ if (swto) assert(swto->mod == 0);
+ if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ case MODshared | MODwildconst:
+ assert(! cto || cto->mod == MODconst);
+ assert(! ito || ito->mod == MODimmutable);
+ assert(! sto || sto->mod == MODshared);
+ assert(! scto || scto->mod == (MODshared | MODconst));
+ assert(! wto || wto->mod == MODwild);
+ assert(! wcto || wcto->mod == MODwildconst);
+ assert(! swto || swto->mod == (MODshared | MODwild));
+ assert(!swcto || swcto->mod == 0);
+ break;
+
+ case MODimmutable:
+ if (cto) assert(cto->mod == MODconst);
+ if (ito) assert(ito->mod == 0);
+ if (sto) assert(sto->mod == MODshared);
+ if (scto) assert(scto->mod == (MODshared | MODconst));
+ if (wto) assert(wto->mod == MODwild);
+ if (wcto) assert(wcto->mod == MODwildconst);
+ if (swto) assert(swto->mod == (MODshared | MODwild));
+ if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
+ break;
+
+ default:
+ assert(0);
+ }
+
+ Type *tn = nextOf();
+ if (tn && ty != Tfunction && tn->ty != Tfunction && ty != Tenum)
+ {
+ // Verify transitivity
+ switch (mod)
+ {
+ case 0:
+ case MODconst:
+ case MODwild:
+ case MODwildconst:
+ case MODshared:
+ case MODshared | MODconst:
+ case MODshared | MODwild:
+ case MODshared | MODwildconst:
+ case MODimmutable:
+ assert(tn->mod == MODimmutable || (tn->mod & mod) == mod);
+ break;
+
+ default:
+ assert(0);
+ }
+ tn->check();
+ }
+}
+
+Type *Type::makeConst()
+{
+ //printf("Type::makeConst() %p, %s\n", this, toChars());
+ if (cto) return cto;
+ Type *t = this->nullAttributes();
+ t->mod = MODconst;
+ //printf("-Type::makeConst() %p, %s\n", t, toChars());
+ return t;
+}
+
+Type *Type::makeImmutable()
+{
+ if (ito) return ito;
+ Type *t = this->nullAttributes();
+ t->mod = MODimmutable;
+ return t;
+}
+
+Type *Type::makeShared()
+{
+ if (sto) return sto;
+ Type *t = this->nullAttributes();
+ t->mod = MODshared;
+ return t;
+}
+
+Type *Type::makeSharedConst()
+{
+ if (scto) return scto;
+ Type *t = this->nullAttributes();
+ t->mod = MODshared | MODconst;
+ return t;
+}
+
+Type *Type::makeWild()
+{
+ if (wto) return wto;
+ Type *t = this->nullAttributes();
+ t->mod = MODwild;
+ return t;
+}
+
+Type *Type::makeWildConst()
+{
+ if (wcto) return wcto;
+ Type *t = this->nullAttributes();
+ t->mod = MODwildconst;
+ return t;
+}
+
+Type *Type::makeSharedWild()
+{
+ if (swto) return swto;
+ Type *t = this->nullAttributes();
+ t->mod = MODshared | MODwild;
+ return t;
+}
+
+Type *Type::makeSharedWildConst()
+{
+ if (swcto) return swcto;
+ Type *t = this->nullAttributes();
+ t->mod = MODshared | MODwildconst;
+ return t;
+}
+
+Type *Type::makeMutable()
+{
+ Type *t = this->nullAttributes();
+ t->mod = mod & MODshared;
+ return t;
+}
+
+/*************************************
+ * Apply STCxxxx bits to existing type.
+ * Use *before* semantic analysis is run.
+ */
+
+Type *Type::addSTC(StorageClass stc)
+{
+ Type *t = this;
+ if (t->isImmutable())
+ ;
+ else if (stc & STCimmutable)
+ {
+ t = t->makeImmutable();
+ }
+ else
+ {
+ if ((stc & STCshared) && !t->isShared())
+ {
+ if (t->isWild())
+ {
+ if (t->isConst())
+ t = t->makeSharedWildConst();
+ else
+ t = t->makeSharedWild();
+ }
+ else
+ {
+ if (t->isConst())
+ t = t->makeSharedConst();
+ else
+ t = t->makeShared();
+ }
+ }
+ if ((stc & STCconst) && !t->isConst())
+ {
+ if (t->isShared())
+ {
+ if (t->isWild())
+ t = t->makeSharedWildConst();
+ else
+ t = t->makeSharedConst();
+ }
+ else
+ {
+ if (t->isWild())
+ t = t->makeWildConst();
+ else
+ t = t->makeConst();
+ }
+ }
+ if ((stc & STCwild) && !t->isWild())
+ {
+ if (t->isShared())
+ {
+ if (t->isConst())
+ t = t->makeSharedWildConst();
+ else
+ t = t->makeSharedWild();
+ }
+ else
+ {
+ if (t->isConst())
+ t = t->makeWildConst();
+ else
+ t = t->makeWild();
+ }
+ }
+ }
+ return t;
+}
+
+/************************************
+ * Convert MODxxxx to STCxxx
+ */
+
+StorageClass ModToStc(unsigned mod)
+{
+ StorageClass stc = 0;
+ if (mod & MODimmutable) stc |= STCimmutable;
+ if (mod & MODconst) stc |= STCconst;
+ if (mod & MODwild) stc |= STCwild;
+ if (mod & MODshared) stc |= STCshared;
+ return stc;
+}
+
+/************************************
+ * Apply MODxxxx bits to existing type.
+ */
+
+Type *Type::castMod(MOD mod)
+{ Type *t;
+
+ switch (mod)
+ {
+ case 0:
+ t = unSharedOf()->mutableOf();
+ break;
+
+ case MODconst:
+ t = unSharedOf()->constOf();
+ break;
+
+ case MODwild:
+ t = unSharedOf()->wildOf();
+ break;
+
+ case MODwildconst:
+ t = unSharedOf()->wildConstOf();
+ break;
+
+ case MODshared:
+ t = mutableOf()->sharedOf();
+ break;
+
+ case MODshared | MODconst:
+ t = sharedConstOf();
+ break;
+
+ case MODshared | MODwild:
+ t = sharedWildOf();
+ break;
+
+ case MODshared | MODwildconst:
+ t = sharedWildConstOf();
+ break;
+
+ case MODimmutable:
+ t = immutableOf();
+ break;
+
+ default:
+ assert(0);
+ }
+ return t;
+}
+
+/************************************
+ * Add MODxxxx bits to existing type.
+ * We're adding, not replacing, so adding const to
+ * a shared type => "shared const"
+ */
+
+Type *Type::addMod(MOD mod)
+{
+ /* Add anything to immutable, and it remains immutable
+ */
+ Type *t = this;
+ if (!t->isImmutable())
+ {
+ //printf("addMod(%x) %s\n", mod, toChars());
+ switch (mod)
+ {
+ case 0:
+ break;
+
+ case MODconst:
+ if (isShared())
+ {
+ if (isWild())
+ t = sharedWildConstOf();
+ else
+ t = sharedConstOf();
+ }
+ else
+ {
+ if (isWild())
+ t = wildConstOf();
+ else
+ t = constOf();
+ }
+ break;
+
+ case MODwild:
+ if (isShared())
+ {
+ if (isConst())
+ t = sharedWildConstOf();
+ else
+ t = sharedWildOf();
+ }
+ else
+ {
+ if (isConst())
+ t = wildConstOf();
+ else
+ t = wildOf();
+ }
+ break;
+
+ case MODwildconst:
+ if (isShared())
+ t = sharedWildConstOf();
+ else
+ t = wildConstOf();
+ break;
+
+ case MODshared:
+ if (isWild())
+ {
+ if (isConst())
+ t = sharedWildConstOf();
+ else
+ t = sharedWildOf();
+ }
+ else
+ {
+ if (isConst())
+ t = sharedConstOf();
+ else
+ t = sharedOf();
+ }
+ break;
+
+ case MODshared | MODconst:
+ if (isWild())
+ t = sharedWildConstOf();
+ else
+ t = sharedConstOf();
+ break;
+
+ case MODshared | MODwild:
+ if (isConst())
+ t = sharedWildConstOf();
+ else
+ t = sharedWildOf();
+ break;
+
+ case MODshared | MODwildconst:
+ t = sharedWildConstOf();
+ break;
+
+ case MODimmutable:
+ t = immutableOf();
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ return t;
+}
+
+/************************************
+ * Add storage class modifiers to type.
+ */
+
+Type *Type::addStorageClass(StorageClass stc)
+{
+ /* Just translate to MOD bits and let addMod() do the work
+ */
+ MOD mod = 0;
+
+ if (stc & STCimmutable)
+ mod = MODimmutable;
+ else
+ {
+ if (stc & (STCconst | STCin))
+ mod |= MODconst;
+ if (stc & STCwild)
+ mod |= MODwild;
+ if (stc & STCshared)
+ mod |= MODshared;
+ }
+ return addMod(mod);
+}
+
+Type *Type::pointerTo()
+{
+ if (ty == Terror)
+ return this;
+ if (!pto)
+ {
+ Type *t = new TypePointer(this);
+ if (ty == Tfunction)
+ {
+ t->deco = t->merge()->deco;
+ pto = t;
+ }
+ else
+ pto = t->merge();
+ }
+ return pto;
+}
+
+Type *Type::referenceTo()
+{
+ if (ty == Terror)
+ return this;
+ if (!rto)
+ {
+ Type *t = new TypeReference(this);
+ rto = t->merge();
+ }
+ return rto;
+}
+
+Type *Type::arrayOf()
+{
+ if (ty == Terror)
+ return this;
+ if (!arrayof)
+ {
+ Type *t = new TypeDArray(this);
+ arrayof = t->merge();
+ }
+ return arrayof;
+}
+
+// Make corresponding static array type without semantic
+Type *Type::sarrayOf(dinteger_t dim)
+{
+ assert(deco);
+ Type *t = new TypeSArray(this, new IntegerExp(Loc(), dim, Type::tsize_t));
+
+ // according to TypeSArray::semantic()
+ t = t->addMod(mod);
+ t = t->merge();
+
+ return t;
+}
+
+Type *Type::aliasthisOf()
+{
+ AggregateDeclaration *ad = isAggregate(this);
+ if (ad && ad->aliasthis)
+ {
+ Dsymbol *s = ad->aliasthis;
+ if (s->isAliasDeclaration())
+ s = s->toAlias();
+ Declaration *d = s->isDeclaration();
+ if (d && !d->isTupleDeclaration())
+ {
+ assert(d->type);
+ Type *t = d->type;
+ if (d->isVarDeclaration() && d->needThis())
+ {
+ t = t->addMod(this->mod);
+ }
+ else if (d->isFuncDeclaration())
+ {
+ FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, d, NULL, this, NULL, 1);
+ if (fd && fd->errors)
+ return Type::terror;
+ if (fd && !fd->type->nextOf() && !fd->functionSemantic())
+ fd = NULL;
+ if (fd)
+ {
+ t = fd->type->nextOf();
+ if (!t) // issue 14185
+ return Type::terror;
+ t = t->substWildTo(mod == 0 ? MODmutable : (MODFlags)mod);
+ }
+ else
+ return Type::terror;
+ }
+ return t;
+ }
+ EnumDeclaration *ed = s->isEnumDeclaration();
+ if (ed)
+ {
+ Type *t = ed->type;
+ return t;
+ }
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (td)
+ {
+ assert(td->_scope);
+ FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, td, NULL, this, NULL, 1);
+ if (fd && fd->errors)
+ return Type::terror;
+ if (fd && fd->functionSemantic())
+ {
+ Type *t = fd->type->nextOf();
+ t = t->substWildTo(mod == 0 ? MODmutable : (MODFlags)mod);
+ return t;
+ }
+ else
+ return Type::terror;
+ }
+ //printf("%s\n", s->kind());
+ }
+ return NULL;
+}
+
+bool Type::checkAliasThisRec()
+{
+ Type *tb = toBasetype();
+ AliasThisRec* pflag;
+ if (tb->ty == Tstruct)
+ pflag = &((TypeStruct *)tb)->att;
+ else if (tb->ty == Tclass)
+ pflag = &((TypeClass *)tb)->att;
+ else
+ return false;
+
+ AliasThisRec flag = (AliasThisRec)(*pflag & RECtypeMask);
+ if (flag == RECfwdref)
+ {
+ Type *att = aliasthisOf();
+ flag = att && att->implicitConvTo(this) ? RECyes : RECno;
+ }
+ *pflag = (AliasThisRec)(flag | (*pflag & ~RECtypeMask));
+ return flag == RECyes;
+}
+
+Dsymbol *Type::toDsymbol(Scope *)
+{
+ return NULL;
+}
+
+/*******************************
+ * If this is a shell around another type,
+ * get that other type.
+ */
+
+Type *Type::toBasetype()
+{
+ return this;
+}
+
+/***************************
+ * Return !=0 if modfrom can be implicitly converted to modto
+ */
+bool MODimplicitConv(MOD modfrom, MOD modto)
+{
+ if (modfrom == modto)
+ return true;
+
+ //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
+ #define X(m, n) (((m) << 4) | (n))
+ switch (X(modfrom & ~MODshared, modto & ~MODshared))
+ {
+ case X(0, MODconst):
+ case X(MODwild, MODconst):
+ case X(MODwild, MODwildconst):
+ case X(MODwildconst, MODconst):
+ return (modfrom & MODshared) == (modto & MODshared);
+
+ case X(MODimmutable, MODconst):
+ case X(MODimmutable, MODwildconst):
+ return true;
+
+ default:
+ return false;
+ }
+ #undef X
+}
+
+/***************************
+ * Return MATCHexact or MATCHconst if a method of type '() modfrom' can call a method of type '() modto'.
+ */
+MATCH MODmethodConv(MOD modfrom, MOD modto)
+{
+ if (modfrom == modto)
+ return MATCHexact;
+ if (MODimplicitConv(modfrom, modto))
+ return MATCHconst;
+
+ #define X(m, n) (((m) << 4) | (n))
+ switch (X(modfrom, modto))
+ {
+ case X(0, MODwild):
+ case X(MODimmutable, MODwild):
+ case X(MODconst, MODwild):
+ case X(MODwildconst, MODwild):
+ case X(MODshared, MODshared|MODwild):
+ case X(MODshared|MODimmutable, MODshared|MODwild):
+ case X(MODshared|MODconst, MODshared|MODwild):
+ case X(MODshared|MODwildconst, MODshared|MODwild):
+ return MATCHconst;
+
+ default:
+ return MATCHnomatch;
+ }
+ #undef X
+}
+
+/***************************
+ * Merge mod bits to form common mod.
+ */
+MOD MODmerge(MOD mod1, MOD mod2)
+{
+ if (mod1 == mod2)
+ return mod1;
+
+ //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2);
+ MOD result = 0;
+ if ((mod1 | mod2) & MODshared)
+ {
+ // If either type is shared, the result will be shared
+ result |= MODshared;
+ mod1 &= ~MODshared;
+ mod2 &= ~MODshared;
+ }
+ if (mod1 == 0 || mod1 == MODmutable || mod1 == MODconst ||
+ mod2 == 0 || mod2 == MODmutable || mod2 == MODconst)
+ {
+ // If either type is mutable or const, the result will be const.
+ result |= MODconst;
+ }
+ else
+ {
+ // MODimmutable vs MODwild
+ // MODimmutable vs MODwildconst
+ // MODwild vs MODwildconst
+ assert(mod1 & MODwild || mod2 & MODwild);
+ result |= MODwildconst;
+ }
+ return result;
+}
+
+/*********************************
+ * Store modifier name into buf.
+ */
+void MODtoBuffer(OutBuffer *buf, MOD mod)
+{
+ switch (mod)
+ {
+ case 0:
+ break;
+
+ case MODimmutable:
+ buf->writestring(Token::tochars[TOKimmutable]);
+ break;
+
+ case MODshared:
+ buf->writestring(Token::tochars[TOKshared]);
+ break;
+
+ case MODshared | MODconst:
+ buf->writestring(Token::tochars[TOKshared]);
+ buf->writeByte(' ');
+ /* fall through */
+ case MODconst:
+ buf->writestring(Token::tochars[TOKconst]);
+ break;
+
+ case MODshared | MODwild:
+ buf->writestring(Token::tochars[TOKshared]);
+ buf->writeByte(' ');
+ /* fall through */
+ case MODwild:
+ buf->writestring(Token::tochars[TOKwild]);
+ break;
+
+ case MODshared | MODwildconst:
+ buf->writestring(Token::tochars[TOKshared]);
+ buf->writeByte(' ');
+ /* fall through */
+ case MODwildconst:
+ buf->writestring(Token::tochars[TOKwild]);
+ buf->writeByte(' ');
+ buf->writestring(Token::tochars[TOKconst]);
+ break;
+
+ default:
+ assert(0);
+ }
+}
+
+
+/*********************************
+ * Return modifier name.
+ */
+char *MODtoChars(MOD mod)
+{
+ OutBuffer buf;
+ buf.reserve(16);
+ MODtoBuffer(&buf, mod);
+ return buf.extractString();
+}
+
+/********************************
+ * For pretty-printing a type.
+ */
+
+const char *Type::toChars()
+{
+ OutBuffer buf;
+ buf.reserve(16);
+ HdrGenState hgs;
+ hgs.fullQual = (ty == Tclass && !mod);
+
+ ::toCBuffer(this, &buf, NULL, &hgs);
+ return buf.extractString();
+}
+
+char *Type::toPrettyChars(bool QualifyTypes)
+{
+ OutBuffer buf;
+ buf.reserve(16);
+ HdrGenState hgs;
+ hgs.fullQual = QualifyTypes;
+
+ ::toCBuffer(this, &buf, NULL, &hgs);
+ return buf.extractString();
+}
+
+/*********************************
+ * Store this type's modifier name into buf.
+ */
+void Type::modToBuffer(OutBuffer *buf)
+{
+ if (mod)
+ {
+ buf->writeByte(' ');
+ MODtoBuffer(buf, mod);
+ }
+}
+
+/*********************************
+ * Return this type's modifier name.
+ */
+char *Type::modToChars()
+{
+ OutBuffer buf;
+ buf.reserve(16);
+ modToBuffer(&buf);
+ return buf.extractString();
+}
+
+/** For each active modifier (MODconst, MODimmutable, etc) call fp with a
+void* for the work param and a string representation of the attribute. */
+int Type::modifiersApply(void *param, int (*fp)(void *, const char *))
+{
+ static unsigned char modsArr[] = { MODconst, MODimmutable, MODwild, MODshared };
+
+ for (size_t idx = 0; idx < 4; ++idx)
+ {
+ if (mod & modsArr[idx])
+ {
+ if (int res = fp(param, MODtoChars(modsArr[idx])))
+ return res;
+ }
+ }
+ return 0;
+}
+
+/************************************
+ * Strip all parameter's idenfiers and their default arguments for merging types.
+ * If some of parameter types or return type are function pointer, delegate, or
+ * the types which contains either, then strip also from them.
+ */
+
+Type *stripDefaultArgs(Type *t)
+{
+ struct N
+ {
+ static Parameters *stripParams(Parameters *parameters)
+ {
+ Parameters *params = parameters;
+ if (params && params->dim > 0)
+ {
+ for (size_t i = 0; i < params->dim; i++)
+ {
+ Parameter *p = (*params)[i];
+ Type *ta = stripDefaultArgs(p->type);
+ if (ta != p->type || p->defaultArg || p->ident)
+ {
+ if (params == parameters)
+ {
+ params = new Parameters();
+ params->setDim(parameters->dim);
+ for (size_t j = 0; j < params->dim; j++)
+ (*params)[j] = (*parameters)[j];
+ }
+ (*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL);
+ }
+ }
+ }
+ return params;
+ }
+ };
+
+ if (t == NULL)
+ return t;
+
+ if (t->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)t;
+ Type *tret = stripDefaultArgs(tf->next);
+ Parameters *params = N::stripParams(tf->parameters);
+ if (tret == tf->next && params == tf->parameters)
+ goto Lnot;
+ tf = (TypeFunction *)tf->copy();
+ tf->parameters = params;
+ tf->next = tret;
+ //printf("strip %s\n <- %s\n", tf->toChars(), t->toChars());
+ t = tf;
+ }
+ else if (t->ty == Ttuple)
+ {
+ TypeTuple *tt = (TypeTuple *)t;
+ Parameters *args = N::stripParams(tt->arguments);
+ if (args == tt->arguments)
+ goto Lnot;
+ t = t->copy();
+ ((TypeTuple *)t)->arguments = args;
+ }
+ else if (t->ty == Tenum)
+ {
+ // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
+ goto Lnot;
+ }
+ else
+ {
+ Type *tn = t->nextOf();
+ Type *n = stripDefaultArgs(tn);
+ if (n == tn)
+ goto Lnot;
+ t = t->copy();
+ ((TypeNext *)t)->next = n;
+ }
+ //printf("strip %s\n", t->toChars());
+Lnot:
+ return t;
+}
+
+/************************************
+ */
+
+Type *Type::merge()
+{
+ if (ty == Terror) return this;
+ if (ty == Ttypeof) return this;
+ if (ty == Tident) return this;
+ if (ty == Tinstance) return this;
+ if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco)
+ return this;
+ if (ty != Tenum && nextOf() && !nextOf()->deco)
+ return this;
+
+ //printf("merge(%s)\n", toChars());
+ Type *t = this;
+ assert(t);
+ if (!deco)
+ {
+ OutBuffer buf;
+ buf.reserve(32);
+
+ mangleToBuffer(this, &buf);
+
+ StringValue *sv = stringtable.update((char *)buf.data, buf.offset);
+ if (sv->ptrvalue)
+ {
+ t = (Type *) sv->ptrvalue;
+ assert(t->deco);
+ //printf("old value, deco = '%s' %p\n", t->deco, t->deco);
+ }
+ else
+ {
+ sv->ptrvalue = (char *)(t = stripDefaultArgs(t));
+ deco = t->deco = const_cast<char *>(sv->toDchars());
+ //printf("new value, deco = '%s' %p\n", t->deco, t->deco);
+ }
+ }
+ return t;
+}
+
+/*************************************
+ * This version does a merge even if the deco is already computed.
+ * Necessary for types that have a deco, but are not merged.
+ */
+Type *Type::merge2()
+{
+ //printf("merge2(%s)\n", toChars());
+ Type *t = this;
+ assert(t);
+ if (!t->deco)
+ return t->merge();
+
+ StringValue *sv = stringtable.lookup((char *)t->deco, strlen(t->deco));
+ if (sv && sv->ptrvalue)
+ { t = (Type *) sv->ptrvalue;
+ assert(t->deco);
+ }
+ else
+ assert(0);
+ return t;
+}
+
+bool Type::isintegral()
+{
+ return false;
+}
+
+bool Type::isfloating()
+{
+ return false;
+}
+
+bool Type::isreal()
+{
+ return false;
+}
+
+bool Type::isimaginary()
+{
+ return false;
+}
+
+bool Type::iscomplex()
+{
+ return false;
+}
+
+bool Type::isscalar()
+{
+ return false;
+}
+
+bool Type::isunsigned()
+{
+ return false;
+}
+
+ClassDeclaration *Type::isClassHandle()
+{
+ return NULL;
+}
+
+bool Type::isscope()
+{
+ return false;
+}
+
+bool Type::isString()
+{
+ return false;
+}
+
+/**************************
+ * When T is mutable,
+ * Given:
+ * T a, b;
+ * Can we bitwise assign:
+ * a = b;
+ * ?
+ */
+bool Type::isAssignable()
+{
+ return true;
+}
+
+/**************************
+ * Returns true if T can be converted to boolean value.
+ */
+bool Type::isBoolean()
+{
+ return isscalar();
+}
+
+/********************************
+ * true if when type goes out of scope, it needs a destructor applied.
+ * Only applies to value types, not ref types.
+ */
+bool Type::needsDestruction()
+{
+ return false;
+}
+
+/*********************************
+ *
+ */
+
+bool Type::needsNested()
+{
+ return false;
+}
+
+/*********************************
+ * Check type to see if it is based on a deprecated symbol.
+ */
+
+void Type::checkDeprecated(Loc loc, Scope *sc)
+{
+ Dsymbol *s = toDsymbol(sc);
+
+ if (s)
+ s->checkDeprecated(loc, sc);
+}
+
+
+Expression *Type::defaultInit(Loc)
+{
+ return NULL;
+}
+
+/***************************************
+ * Use when we prefer the default initializer to be a literal,
+ * rather than a global immutable variable.
+ */
+Expression *Type::defaultInitLiteral(Loc loc)
+{
+ return defaultInit(loc);
+}
+
+bool Type::isZeroInit(Loc)
+{
+ return false; // assume not
+}
+
+bool Type::isBaseOf(Type *, int *)
+{
+ return 0; // assume not
+}
+
+/********************************
+ * Determine if 'this' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ * MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact
+ */
+
+MATCH Type::implicitConvTo(Type *to)
+{
+ //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to->toChars());
+ if (this->equals(to))
+ return MATCHexact;
+ return MATCHnomatch;
+}
+
+/*******************************
+ * Determine if converting 'this' to 'to' is an identity operation,
+ * a conversion to const operation, or the types aren't the same.
+ * Returns:
+ * MATCHexact 'this' == 'to'
+ * MATCHconst 'to' is const
+ * MATCHnomatch conversion to mutable or invariant
+ */
+
+MATCH Type::constConv(Type *to)
+{
+ //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to->toChars());
+ if (equals(to))
+ return MATCHexact;
+ if (ty == to->ty && MODimplicitConv(mod, to->mod))
+ return MATCHconst;
+ return MATCHnomatch;
+}
+
+/***************************************
+ * Return MOD bits matching this type to wild parameter type (tprm).
+ */
+
+unsigned char Type::deduceWild(Type *t, bool)
+{
+ //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm->toChars());
+
+ if (t->isWild())
+ {
+ if (isImmutable())
+ return MODimmutable;
+ else if (isWildConst())
+ {
+ if (t->isWildConst())
+ return MODwild;
+ else
+ return MODwildconst;
+ }
+ else if (isWild())
+ return MODwild;
+ else if (isConst())
+ return MODconst;
+ else if (isMutable())
+ return MODmutable;
+ else
+ assert(0);
+ }
+ return 0;
+}
+
+Type *Type::unqualify(unsigned m)
+{
+ Type *t = mutableOf()->unSharedOf();
+
+ Type *tn = ty == Tenum ? NULL : nextOf();
+ if (tn && tn->ty != Tfunction)
+ {
+ Type *utn = tn->unqualify(m);
+ if (utn != tn)
+ {
+ if (ty == Tpointer)
+ t = utn->pointerTo();
+ else if (ty == Tarray)
+ t = utn->arrayOf();
+ else if (ty == Tsarray)
+ t = new TypeSArray(utn, ((TypeSArray *)this)->dim);
+ else if (ty == Taarray)
+ {
+ t = new TypeAArray(utn, ((TypeAArray *)this)->index);
+ ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope
+ }
+ else
+ assert(0);
+
+ t = t->merge();
+ }
+ }
+ t = t->addMod(mod & ~m);
+ return t;
+}
+
+Type *Type::substWildTo(unsigned mod)
+{
+ //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
+ Type *t;
+
+ if (Type *tn = nextOf())
+ {
+ // substitution has no effect on function pointer type.
+ if (ty == Tpointer && tn->ty == Tfunction)
+ {
+ t = this;
+ goto L1;
+ }
+
+ t = tn->substWildTo(mod);
+ if (t == tn)
+ t = this;
+ else
+ {
+ if (ty == Tpointer)
+ t = t->pointerTo();
+ else if (ty == Tarray)
+ t = t->arrayOf();
+ else if (ty == Tsarray)
+ t = new TypeSArray(t, ((TypeSArray *)this)->dim->syntaxCopy());
+ else if (ty == Taarray)
+ {
+ t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy());
+ ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope
+ }
+ else if (ty == Tdelegate)
+ {
+ t = new TypeDelegate(t);
+ }
+ else
+ assert(0);
+
+ t = t->merge();
+ }
+ }
+ else
+ t = this;
+
+L1:
+ if (isWild())
+ {
+ if (mod == MODimmutable)
+ {
+ t = t->immutableOf();
+ }
+ else if (mod == MODwildconst)
+ {
+ t = t->wildConstOf();
+ }
+ else if (mod == MODwild)
+ {
+ if (isWildConst())
+ t = t->wildConstOf();
+ else
+ t = t->wildOf();
+ }
+ else if (mod == MODconst)
+ {
+ t = t->constOf();
+ }
+ else
+ {
+ if (isWildConst())
+ t = t->constOf();
+ else
+ t = t->mutableOf();
+ }
+ }
+ if (isConst())
+ t = t->addMod(MODconst);
+ if (isShared())
+ t = t->addMod(MODshared);
+
+ //printf("-Type::substWildTo t = %s\n", t->toChars());
+ return t;
+}
+
+Type *TypeFunction::substWildTo(unsigned)
+{
+ if (!iswild && !(mod & MODwild))
+ return this;
+
+ // Substitude inout qualifier of function type to mutable or immutable
+ // would break type system. Instead substitude inout to the most weak
+ // qualifer - const.
+ unsigned m = MODconst;
+
+ assert(next);
+ Type *tret = next->substWildTo(m);
+ Parameters *params = parameters;
+ if (mod & MODwild)
+ params = parameters->copy();
+ for (size_t i = 0; i < params->dim; i++)
+ {
+ Parameter *p = (*params)[i];
+ Type *t = p->type->substWildTo(m);
+ if (t == p->type)
+ continue;
+ if (params == parameters)
+ params = parameters->copy();
+ (*params)[i] = new Parameter(p->storageClass, t, NULL, NULL);
+ }
+ if (next == tret && params == parameters)
+ return this;
+
+ // Similar to TypeFunction::syntaxCopy;
+ TypeFunction *t = new TypeFunction(params, tret, varargs, linkage);
+ t->mod = ((mod & MODwild) ? (mod & ~MODwild) | MODconst : mod);
+ t->isnothrow = isnothrow;
+ t->isnogc = isnogc;
+ t->purity = purity;
+ t->isproperty = isproperty;
+ t->isref = isref;
+ t->isreturn = isreturn;
+ t->isscope = isscope;
+ t->isscopeinferred = isscopeinferred;
+ t->iswild = 0;
+ t->trust = trust;
+ t->fargs = fargs;
+ return t->merge();
+}
+
+/**************************
+ * Return type with the top level of it being mutable.
+ */
+Type *Type::toHeadMutable()
+{
+ if (!mod)
+ return this;
+ return mutableOf();
+}
+
+/***************************************
+ * Calculate built-in properties which just the type is necessary.
+ *
+ * If flag & 1, don't report "not a property" error and just return NULL.
+ */
+Expression *Type::getProperty(Loc loc, Identifier *ident, int flag)
+{
+ Expression *e;
+
+ if (ident == Id::__sizeof)
+ {
+ d_uns64 sz = size(loc);
+ if (sz == SIZE_INVALID)
+ return new ErrorExp();
+ e = new IntegerExp(loc, sz, Type::tsize_t);
+ }
+ else if (ident == Id::__xalignof)
+ {
+ e = new IntegerExp(loc, alignsize(), Type::tsize_t);
+ }
+ else if (ident == Id::_init)
+ {
+ Type *tb = toBasetype();
+ e = defaultInitLiteral(loc);
+ if (tb->ty == Tstruct && tb->needsNested())
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ se->useStaticInit = true;
+ }
+ }
+ else if (ident == Id::_mangleof)
+ {
+ if (!deco)
+ {
+ error(loc, "forward reference of type %s.mangleof", toChars());
+ e = new ErrorExp();
+ }
+ else
+ {
+ e = new StringExp(loc, (char *)deco, strlen(deco));
+ Scope sc;
+ e = ::semantic(e, &sc);
+ }
+ }
+ else if (ident == Id::stringof)
+ {
+ const char *s = toChars();
+ e = new StringExp(loc, const_cast<char *>(s), strlen(s));
+ Scope sc;
+ e = ::semantic(e, &sc);
+ }
+ else if (flag && this != Type::terror)
+ {
+ return NULL;
+ }
+ else
+ {
+ Dsymbol *s = NULL;
+ if (ty == Tstruct || ty == Tclass || ty == Tenum)
+ s = toDsymbol(NULL);
+ if (s)
+ s = s->search_correct(ident);
+ if (this != Type::terror)
+ {
+ if (s)
+ error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars());
+ else
+ error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
+ }
+ e = new ErrorExp();
+ }
+ return e;
+}
+
+/***************************************
+ * Access the members of the object e. This type is same as e->type.
+ *
+ * If flag & 1, don't report "not a property" error and just return NULL.
+ */
+Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ VarDeclaration *v = NULL;
+
+ Expression *ex = e;
+ while (ex->op == TOKcomma)
+ ex = ((CommaExp *)ex)->e2;
+ if (ex->op == TOKdotvar)
+ {
+ DotVarExp *dv = (DotVarExp *)ex;
+ v = dv->var->isVarDeclaration();
+ }
+ else if (ex->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)ex;
+ v = ve->var->isVarDeclaration();
+ }
+ if (v)
+ {
+ if (ident == Id::offsetof)
+ {
+ if (v->isField())
+ {
+ AggregateDeclaration *ad = v->toParent()->isAggregateDeclaration();
+ ad->size(e->loc);
+ if (ad->sizeok != SIZEOKdone)
+ return new ErrorExp();
+ e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
+ return e;
+ }
+ }
+ else if (ident == Id::_init)
+ {
+ Type *tb = toBasetype();
+ e = defaultInitLiteral(e->loc);
+ if (tb->ty == Tstruct && tb->needsNested())
+ {
+ StructLiteralExp *se = (StructLiteralExp *)e;
+ se->useStaticInit = true;
+ }
+ goto Lreturn;
+ }
+ }
+ if (ident == Id::stringof)
+ {
+ /* Bugzilla 3796: this should demangle e->type->deco rather than
+ * pretty-printing the type.
+ */
+ const char *s = e->toChars();
+ e = new StringExp(e->loc, const_cast<char *>(s), strlen(s));
+ }
+ else
+ e = getProperty(e->loc, ident, flag & 1);
+
+Lreturn:
+ if (e)
+ e = ::semantic(e, sc);
+ return e;
+}
+
+/************************************
+ * Return alignment to use for this type.
+ */
+
+structalign_t Type::alignment()
+{
+ return STRUCTALIGN_DEFAULT;
+}
+
+/***************************************
+ * Figures out what to do with an undefined member reference
+ * for classes and structs.
+ *
+ * If flag & 1, don't report "not a property" error and just return NULL.
+ */
+Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ //printf("Type::noMember(e: %s ident: %s flag: %d)\n", e->toChars(), ident->toChars(), flag);
+
+ static int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
+
+ if (++nest > 500)
+ {
+ ::error(e->loc, "cannot resolve identifier `%s`", ident->toChars());
+ --nest;
+ return (flag & 1) ? NULL : new ErrorExp();
+ }
+
+ assert(ty == Tstruct || ty == Tclass);
+ AggregateDeclaration *sym = toDsymbol(sc)->isAggregateDeclaration();
+ assert(sym);
+
+ if (ident != Id::__sizeof &&
+ ident != Id::__xalignof &&
+ ident != Id::_init &&
+ ident != Id::_mangleof &&
+ ident != Id::stringof &&
+ ident != Id::offsetof &&
+ // Bugzilla 15045: Don't forward special built-in member functions.
+ ident != Id::ctor &&
+ ident != Id::dtor &&
+ ident != Id::__xdtor &&
+ ident != Id::postblit &&
+ ident != Id::__xpostblit)
+ {
+ /* Look for overloaded opDot() to see if we should forward request
+ * to it.
+ */
+ if (Dsymbol *fd = search_function(sym, Id::opDot))
+ {
+ /* Rewrite e.ident as:
+ * e.opDot().ident
+ */
+ e = build_overload(e->loc, sc, e, NULL, fd);
+ e = new DotIdExp(e->loc, e, ident);
+ e = ::semantic(e, sc);
+ --nest;
+ return e;
+ }
+
+ /* Look for overloaded opDispatch to see if we should forward request
+ * to it.
+ */
+ if (Dsymbol *fd = search_function(sym, Id::opDispatch))
+ {
+ /* Rewrite e.ident as:
+ * e.opDispatch!("ident")
+ */
+ TemplateDeclaration *td = fd->isTemplateDeclaration();
+ if (!td)
+ {
+ fd->error("must be a template opDispatch(string s), not a %s", fd->kind());
+ --nest;
+ return new ErrorExp();
+ }
+ StringExp *se = new StringExp(e->loc, const_cast<char *>(ident->toChars()));
+ Objects *tiargs = new Objects();
+ tiargs->push(se);
+ DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs);
+ dti->ti->tempdecl = td;
+
+ /* opDispatch, which doesn't need IFTI, may occur instantiate error.
+ * It should be gagged if flag & 1.
+ * e.g.
+ * template opDispatch(name) if (isValid!name) { ... }
+ */
+ unsigned errors = flag & 1 ? global.startGagging() : 0;
+ e = semanticY(dti, sc, 0);
+ if (flag & 1 && global.endGagging(errors))
+ e = NULL;
+ --nest;
+ return e;
+ }
+
+ /* See if we should forward to the alias this.
+ */
+ if (sym->aliasthis)
+ { /* Rewrite e.ident as:
+ * e.aliasthis.ident
+ */
+ e = resolveAliasThis(sc, e);
+ DotIdExp *die = new DotIdExp(e->loc, e, ident);
+ e = semanticY(die, sc, flag & 1);
+ --nest;
+ return e;
+ }
+ }
+
+ e = Type::dotExp(sc, e, ident, flag);
+ --nest;
+ return e;
+}
+
+void Type::error(Loc loc, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::verror(loc, format, ap);
+ va_end( ap );
+}
+
+void Type::warning(Loc loc, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::vwarning(loc, format, ap);
+ va_end( ap );
+}
+
+Identifier *Type::getTypeInfoIdent()
+{
+ // _init_10TypeInfo_%s
+ OutBuffer buf;
+ buf.reserve(32);
+ mangleToBuffer(this, &buf);
+
+ size_t len = buf.offset;
+ buf.writeByte(0);
+
+ // Allocate buffer on stack, fail over to using malloc()
+ char namebuf[128];
+ size_t namelen = 19 + sizeof(len) * 3 + len + 1;
+ char *name = namelen <= sizeof(namebuf) ? namebuf : (char *)malloc(namelen);
+ assert(name);
+
+ sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned long long) 9 + len, buf.data);
+ //printf("%p, deco = %s, name = %s\n", this, deco, name);
+ assert(strlen(name) < namelen); // don't overflow the buffer
+
+ size_t off = 0;
+#ifndef IN_GCC
+ if (global.params.isOSX || (global.params.isWindows && !global.params.is64bit))
+ ++off; // C mangling will add '_' back in
+#endif
+ Identifier *id = Identifier::idPool(name + off);
+
+ if (name != namebuf)
+ free(name);
+ return id;
+}
+
+TypeBasic *Type::isTypeBasic()
+{
+ return NULL;
+}
+
+
+/***************************************
+ * Resolve 'this' type to either type, symbol, or expression.
+ * If errors happened, resolved to Type.terror.
+ */
+void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
+{
+ //printf("Type::resolve() %s, %d\n", toChars(), ty);
+ Type *t = semantic(loc, sc);
+ *pt = t;
+ *pe = NULL;
+ *ps = NULL;
+}
+
+/***************************************
+ * Normalize `e` as the result of Type::resolve() process.
+ */
+void Type::resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps)
+{
+ *pt = NULL;
+ *pe = NULL;
+ *ps = NULL;
+
+ Dsymbol *s;
+ switch (e->op)
+ {
+ case TOKerror:
+ *pt = Type::terror;
+ return;
+
+ case TOKtype:
+ *pt = e->type;
+ return;
+
+ case TOKvar:
+ s = ((VarExp *)e)->var;
+ if (s->isVarDeclaration())
+ goto Ldefault;
+ //if (s->isOverDeclaration())
+ // todo;
+ break;
+
+ case TOKtemplate:
+ // TemplateDeclaration
+ s = ((TemplateExp *)e)->td;
+ break;
+
+ case TOKimport:
+ s = ((ScopeExp *)e)->sds;
+ // TemplateDeclaration, TemplateInstance, Import, Package, Module
+ break;
+
+ case TOKfunction:
+ s = getDsymbol(e);
+ break;
+
+ //case TOKthis:
+ //case TOKsuper:
+
+ //case TOKtuple:
+
+ //case TOKoverloadset:
+
+ //case TOKdotvar:
+ //case TOKdottd:
+ //case TOKdotti:
+ //case TOKdottype:
+ //case TOKdot:
+
+ default:
+ Ldefault:
+ *pe = e;
+ return;
+ }
+
+ *ps = s;
+}
+
+/***************************************
+ * Return !=0 if the type or any of its subtypes is wild.
+ */
+
+int Type::hasWild() const
+{
+ return mod & MODwild;
+}
+
+/***************************************
+ * Return !=0 if type has pointers that need to
+ * be scanned by the GC during a collection cycle.
+ */
+bool Type::hasPointers()
+{
+ //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
+ return false;
+}
+
+/*************************************
+ * Detect if type has pointer fields that are initialized to void.
+ * Local stack variables with such void fields can remain uninitialized,
+ * leading to pointer bugs.
+ * Returns:
+ * true if so
+ */
+bool Type::hasVoidInitPointers()
+{
+ return false;
+}
+
+/*************************************
+ * If this is a type of something, return that something.
+ */
+
+Type *Type::nextOf()
+{
+ return NULL;
+}
+
+/*************************************
+ * If this is a type of static array, return its base element type.
+ */
+
+Type *Type::baseElemOf()
+{
+ Type *t = toBasetype();
+ while (t->ty == Tsarray)
+ t = ((TypeSArray *)t)->next->toBasetype();
+ return t;
+}
+
+/*************************************
+ * Bugzilla 14488: Check if the inner most base type is complex or imaginary.
+ * Should only give alerts when set to emit transitional messages.
+ */
+
+void Type::checkComplexTransition(Loc loc)
+{
+ Type *t = baseElemOf();
+ while (t->ty == Tpointer || t->ty == Tarray)
+ t = t->nextOf()->baseElemOf();
+
+ if (t->isimaginary() || t->iscomplex())
+ {
+ Type *rt;
+ switch (t->ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ rt = Type::tfloat32; break;
+ case Tcomplex64:
+ case Timaginary64:
+ rt = Type::tfloat64; break;
+ case Tcomplex80:
+ case Timaginary80:
+ rt = Type::tfloat80; break;
+ default:
+ assert(0);
+ }
+ if (t->iscomplex())
+ {
+ message(loc, "use of complex type `%s` is scheduled for deprecation, "
+ "use `std.complex.Complex!(%s)` instead", toChars(), rt->toChars());
+ }
+ else
+ {
+ message(loc, "use of imaginary type `%s` is scheduled for deprecation, "
+ "use `%s` instead\n", toChars(), rt->toChars());
+ }
+ }
+}
+
+/****************************************
+ * Return the mask that an integral type will
+ * fit into.
+ */
+uinteger_t Type::sizemask()
+{ uinteger_t m;
+
+ switch (toBasetype()->ty)
+ {
+ case Tbool: m = 1; break;
+ case Tchar:
+ case Tint8:
+ case Tuns8: m = 0xFF; break;
+ case Twchar:
+ case Tint16:
+ case Tuns16: m = 0xFFFFUL; break;
+ case Tdchar:
+ case Tint32:
+ case Tuns32: m = 0xFFFFFFFFUL; break;
+ case Tint64:
+ case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break;
+ default:
+ assert(0);
+ }
+ return m;
+}
+
+/* ============================= TypeError =========================== */
+
+TypeError::TypeError()
+ : Type(Terror)
+{
+}
+
+Type *TypeError::syntaxCopy()
+{
+ // No semantic analysis done, no need to copy
+ return this;
+}
+
+d_uns64 TypeError::size(Loc) { return SIZE_INVALID; }
+Expression *TypeError::getProperty(Loc, Identifier *, int) { return new ErrorExp(); }
+Expression *TypeError::dotExp(Scope *, Expression *, Identifier *, int) { return new ErrorExp(); }
+Expression *TypeError::defaultInit(Loc) { return new ErrorExp(); }
+Expression *TypeError::defaultInitLiteral(Loc) { return new ErrorExp(); }
+
+/* ============================= TypeNext =========================== */
+
+TypeNext::TypeNext(TY ty, Type *next)
+ : Type(ty)
+{
+ this->next = next;
+}
+
+void TypeNext::checkDeprecated(Loc loc, Scope *sc)
+{
+ Type::checkDeprecated(loc, sc);
+ if (next) // next can be NULL if TypeFunction and auto return type
+ next->checkDeprecated(loc, sc);
+}
+
+int TypeNext::hasWild() const
+{
+ if (ty == Tfunction)
+ return 0;
+ if (ty == Tdelegate)
+ return Type::hasWild();
+ return mod & MODwild || (next && next->hasWild());
+}
+
+
+/*******************************
+ * For TypeFunction, nextOf() can return NULL if the function return
+ * type is meant to be inferred, and semantic() hasn't yet ben run
+ * on the function. After semantic(), it must no longer be NULL.
+ */
+
+Type *TypeNext::nextOf()
+{
+ return next;
+}
+
+Type *TypeNext::makeConst()
+{
+ //printf("TypeNext::makeConst() %p, %s\n", this, toChars());
+ if (cto)
+ {
+ assert(cto->mod == MODconst);
+ return cto;
+ }
+ TypeNext *t = (TypeNext *)Type::makeConst();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ if (next->isShared())
+ {
+ if (next->isWild())
+ t->next = next->sharedWildConstOf();
+ else
+ t->next = next->sharedConstOf();
+ }
+ else
+ {
+ if (next->isWild())
+ t->next = next->wildConstOf();
+ else
+ t->next = next->constOf();
+ }
+ }
+ //printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+Type *TypeNext::makeImmutable()
+{
+ //printf("TypeNext::makeImmutable() %s\n", toChars());
+ if (ito)
+ {
+ assert(ito->isImmutable());
+ return ito;
+ }
+ TypeNext *t = (TypeNext *)Type::makeImmutable();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ t->next = next->immutableOf();
+ }
+ return t;
+}
+
+Type *TypeNext::makeShared()
+{
+ //printf("TypeNext::makeShared() %s\n", toChars());
+ if (sto)
+ {
+ assert(sto->mod == MODshared);
+ return sto;
+ }
+ TypeNext *t = (TypeNext *)Type::makeShared();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ if (next->isWild())
+ {
+ if (next->isConst())
+ t->next = next->sharedWildConstOf();
+ else
+ t->next = next->sharedWildOf();
+ }
+ else
+ {
+ if (next->isConst())
+ t->next = next->sharedConstOf();
+ else
+ t->next = next->sharedOf();
+ }
+ }
+ //printf("TypeNext::makeShared() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+Type *TypeNext::makeSharedConst()
+{
+ //printf("TypeNext::makeSharedConst() %s\n", toChars());
+ if (scto)
+ {
+ assert(scto->mod == (MODshared | MODconst));
+ return scto;
+ }
+ TypeNext *t = (TypeNext *)Type::makeSharedConst();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ if (next->isWild())
+ t->next = next->sharedWildConstOf();
+ else
+ t->next = next->sharedConstOf();
+ }
+ //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+Type *TypeNext::makeWild()
+{
+ //printf("TypeNext::makeWild() %s\n", toChars());
+ if (wto)
+ {
+ assert(wto->mod == MODwild);
+ return wto;
+ }
+ TypeNext *t = (TypeNext *)Type::makeWild();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ if (next->isShared())
+ {
+ if (next->isConst())
+ t->next = next->sharedWildConstOf();
+ else
+ t->next = next->sharedWildOf();
+ }
+ else
+ {
+ if (next->isConst())
+ t->next = next->wildConstOf();
+ else
+ t->next = next->wildOf();
+ }
+ }
+ //printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+Type *TypeNext::makeWildConst()
+{
+ //printf("TypeNext::makeWildConst() %s\n", toChars());
+ if (wcto)
+ {
+ assert(wcto->mod == MODwildconst);
+ return wcto;
+ }
+ TypeNext *t = (TypeNext *)Type::makeWildConst();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ if (next->isShared())
+ t->next = next->sharedWildConstOf();
+ else
+ t->next = next->wildConstOf();
+ }
+ //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+Type *TypeNext::makeSharedWild()
+{
+ //printf("TypeNext::makeSharedWild() %s\n", toChars());
+ if (swto)
+ {
+ assert(swto->isSharedWild());
+ return swto;
+ }
+ TypeNext *t = (TypeNext *)Type::makeSharedWild();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ if (next->isConst())
+ t->next = next->sharedWildConstOf();
+ else
+ t->next = next->sharedWildOf();
+ }
+ //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+Type *TypeNext::makeSharedWildConst()
+{
+ //printf("TypeNext::makeSharedWildConst() %s\n", toChars());
+ if (swcto)
+ {
+ assert(swcto->mod == (MODshared | MODwildconst));
+ return swcto;
+ }
+ TypeNext *t = (TypeNext *)Type::makeSharedWildConst();
+ if (ty != Tfunction && next->ty != Tfunction &&
+ !next->isImmutable())
+ {
+ t->next = next->sharedWildConstOf();
+ }
+ //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+Type *TypeNext::makeMutable()
+{
+ //printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
+ TypeNext *t = (TypeNext *)Type::makeMutable();
+ if (ty == Tsarray)
+ {
+ t->next = next->mutableOf();
+ }
+ //printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars());
+ return t;
+}
+
+MATCH TypeNext::constConv(Type *to)
+{
+ //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to->toChars());
+ if (equals(to))
+ return MATCHexact;
+
+ if (!(ty == to->ty && MODimplicitConv(mod, to->mod)))
+ return MATCHnomatch;
+
+ Type *tn = to->nextOf();
+ if (!(tn && next->ty == tn->ty))
+ return MATCHnomatch;
+
+ MATCH m;
+ if (to->isConst()) // whole tail const conversion
+ { // Recursive shared level check
+ m = next->constConv(tn);
+ if (m == MATCHexact)
+ m = MATCHconst;
+ }
+ else
+ { //printf("\tnext => %s, to->next => %s\n", next->toChars(), tn->toChars());
+ m = next->equals(tn) ? MATCHconst : MATCHnomatch;
+ }
+ return m;
+}
+
+unsigned char TypeNext::deduceWild(Type *t, bool isRef)
+{
+ if (ty == Tfunction)
+ return 0;
+
+ unsigned char wm;
+
+ Type *tn = t->nextOf();
+ if (!isRef && (ty == Tarray || ty == Tpointer) && tn)
+ {
+ wm = next->deduceWild(tn, true);
+ if (!wm)
+ wm = Type::deduceWild(t, true);
+ }
+ else
+ {
+ wm = Type::deduceWild(t, isRef);
+ if (!wm && tn)
+ wm = next->deduceWild(tn, true);
+ }
+
+ return wm;
+}
+
+
+void TypeNext::transitive()
+{
+ /* Invoke transitivity of type attributes
+ */
+ next = next->addMod(mod);
+}
+
+/* ============================= TypeBasic =========================== */
+
+#define TFLAGSintegral 1
+#define TFLAGSfloating 2
+#define TFLAGSunsigned 4
+#define TFLAGSreal 8
+#define TFLAGSimaginary 0x10
+#define TFLAGScomplex 0x20
+
+TypeBasic::TypeBasic(TY ty)
+ : Type(ty)
+{ const char *d;
+ unsigned flags;
+
+ flags = 0;
+ switch (ty)
+ {
+ case Tvoid: d = Token::toChars(TOKvoid);
+ break;
+
+ case Tint8: d = Token::toChars(TOKint8);
+ flags |= TFLAGSintegral;
+ break;
+
+ case Tuns8: d = Token::toChars(TOKuns8);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Tint16: d = Token::toChars(TOKint16);
+ flags |= TFLAGSintegral;
+ break;
+
+ case Tuns16: d = Token::toChars(TOKuns16);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Tint32: d = Token::toChars(TOKint32);
+ flags |= TFLAGSintegral;
+ break;
+
+ case Tuns32: d = Token::toChars(TOKuns32);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Tfloat32: d = Token::toChars(TOKfloat32);
+ flags |= TFLAGSfloating | TFLAGSreal;
+ break;
+
+ case Tint64: d = Token::toChars(TOKint64);
+ flags |= TFLAGSintegral;
+ break;
+
+ case Tuns64: d = Token::toChars(TOKuns64);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Tint128: d = Token::toChars(TOKint128);
+ flags |= TFLAGSintegral;
+ break;
+
+ case Tuns128: d = Token::toChars(TOKuns128);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Tfloat64: d = Token::toChars(TOKfloat64);
+ flags |= TFLAGSfloating | TFLAGSreal;
+ break;
+
+ case Tfloat80: d = Token::toChars(TOKfloat80);
+ flags |= TFLAGSfloating | TFLAGSreal;
+ break;
+
+ case Timaginary32: d = Token::toChars(TOKimaginary32);
+ flags |= TFLAGSfloating | TFLAGSimaginary;
+ break;
+
+ case Timaginary64: d = Token::toChars(TOKimaginary64);
+ flags |= TFLAGSfloating | TFLAGSimaginary;
+ break;
+
+ case Timaginary80: d = Token::toChars(TOKimaginary80);
+ flags |= TFLAGSfloating | TFLAGSimaginary;
+ break;
+
+ case Tcomplex32: d = Token::toChars(TOKcomplex32);
+ flags |= TFLAGSfloating | TFLAGScomplex;
+ break;
+
+ case Tcomplex64: d = Token::toChars(TOKcomplex64);
+ flags |= TFLAGSfloating | TFLAGScomplex;
+ break;
+
+ case Tcomplex80: d = Token::toChars(TOKcomplex80);
+ flags |= TFLAGSfloating | TFLAGScomplex;
+ break;
+
+ case Tbool: d = "bool";
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Tchar: d = Token::toChars(TOKchar);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Twchar: d = Token::toChars(TOKwchar);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ case Tdchar: d = Token::toChars(TOKdchar);
+ flags |= TFLAGSintegral | TFLAGSunsigned;
+ break;
+
+ default: assert(0);
+ }
+ this->dstring = d;
+ this->flags = flags;
+ merge();
+}
+
+const char *TypeBasic::kind()
+{
+ return dstring;
+}
+
+Type *TypeBasic::syntaxCopy()
+{
+ // No semantic analysis done on basic types, no need to copy
+ return this;
+}
+
+d_uns64 TypeBasic::size(Loc)
+{ unsigned size;
+
+ //printf("TypeBasic::size()\n");
+ switch (ty)
+ {
+ case Tint8:
+ case Tuns8: size = 1; break;
+ case Tint16:
+ case Tuns16: size = 2; break;
+ case Tint32:
+ case Tuns32:
+ case Tfloat32:
+ case Timaginary32:
+ size = 4; break;
+ case Tint64:
+ case Tuns64:
+ case Tfloat64:
+ case Timaginary64:
+ size = 8; break;
+ case Tfloat80:
+ case Timaginary80:
+ size = Target::realsize; break;
+ case Tcomplex32:
+ size = 8; break;
+ case Tcomplex64:
+ case Tint128:
+ case Tuns128:
+ size = 16; break;
+ case Tcomplex80:
+ size = Target::realsize * 2; break;
+
+ case Tvoid:
+ //size = Type::size(); // error message
+ size = 1;
+ break;
+
+ case Tbool: size = 1; break;
+ case Tchar: size = 1; break;
+ case Twchar: size = 2; break;
+ case Tdchar: size = 4; break;
+
+ default:
+ assert(0);
+ break;
+ }
+ //printf("TypeBasic::size() = %d\n", size);
+ return size;
+}
+
+unsigned TypeBasic::alignsize()
+{
+ return Target::alignsize(this);
+}
+
+
+Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag)
+{
+ Expression *e;
+ dinteger_t ivalue;
+ real_t fvalue;
+
+ //printf("TypeBasic::getProperty('%s')\n", ident->toChars());
+ if (ident == Id::max)
+ {
+ switch (ty)
+ {
+ case Tint8:
+ ivalue = 0x7F;
+ goto Livalue;
+ case Tuns8:
+ ivalue = 0xFF;
+ goto Livalue;
+ case Tint16:
+ ivalue = 0x7FFFUL;
+ goto Livalue;
+ case Tuns16:
+ ivalue = 0xFFFFUL;
+ goto Livalue;
+ case Tint32:
+ ivalue = 0x7FFFFFFFUL;
+ goto Livalue;
+ case Tuns32:
+ ivalue = 0xFFFFFFFFUL;
+ goto Livalue;
+ case Tint64:
+ ivalue = 0x7FFFFFFFFFFFFFFFLL;
+ goto Livalue;
+ case Tuns64:
+ ivalue = 0xFFFFFFFFFFFFFFFFULL;
+ goto Livalue;
+ case Tbool:
+ ivalue = 1;
+ goto Livalue;
+ case Tchar:
+ ivalue = 0xFF;
+ goto Livalue;
+ case Twchar:
+ ivalue = 0xFFFFUL;
+ goto Livalue;
+ case Tdchar:
+ ivalue = 0x10FFFFUL;
+ goto Livalue;
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ fvalue = Target::FloatProperties::max;
+ goto Lfvalue;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ fvalue = Target::DoubleProperties::max;
+ goto Lfvalue;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ fvalue = Target::RealProperties::max;
+ goto Lfvalue;
+ }
+ }
+ else if (ident == Id::min)
+ {
+ switch (ty)
+ {
+ case Tint8:
+ ivalue = -128;
+ goto Livalue;
+ case Tuns8:
+ ivalue = 0;
+ goto Livalue;
+ case Tint16:
+ ivalue = -32768;
+ goto Livalue;
+ case Tuns16:
+ ivalue = 0;
+ goto Livalue;
+ case Tint32:
+ ivalue = -2147483647L - 1;
+ goto Livalue;
+ case Tuns32:
+ ivalue = 0;
+ goto Livalue;
+ case Tint64:
+ ivalue = (-9223372036854775807LL-1LL);
+ goto Livalue;
+ case Tuns64:
+ ivalue = 0;
+ goto Livalue;
+ case Tbool:
+ ivalue = 0;
+ goto Livalue;
+ case Tchar:
+ ivalue = 0;
+ goto Livalue;
+ case Twchar:
+ ivalue = 0;
+ goto Livalue;
+ case Tdchar:
+ ivalue = 0;
+ goto Livalue;
+
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ error(loc, "use .min_normal property instead of .min");
+ return new ErrorExp();
+ }
+ }
+ else if (ident == Id::min_normal)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ fvalue = Target::FloatProperties::min_normal;
+ goto Lfvalue;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ fvalue = Target::DoubleProperties::min_normal;
+ goto Lfvalue;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ fvalue = Target::RealProperties::min_normal;
+ goto Lfvalue;
+ }
+ }
+ else if (ident == Id::nan)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ fvalue = Target::RealProperties::nan;
+ goto Lfvalue;
+ }
+ }
+ else if (ident == Id::infinity)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ fvalue = Target::RealProperties::infinity;
+ goto Lfvalue;
+ }
+ }
+ else if (ident == Id::dig)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ ivalue = Target::FloatProperties::dig;
+ goto Lint;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ ivalue = Target::DoubleProperties::dig;
+ goto Lint;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ ivalue = Target::RealProperties::dig;
+ goto Lint;
+ }
+ }
+ else if (ident == Id::epsilon)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ fvalue = Target::FloatProperties::epsilon;
+ goto Lfvalue;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ fvalue = Target::DoubleProperties::epsilon;
+ goto Lfvalue;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ fvalue = Target::RealProperties::epsilon;
+ goto Lfvalue;
+ }
+ }
+ else if (ident == Id::mant_dig)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ ivalue = Target::FloatProperties::mant_dig;
+ goto Lint;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ ivalue = Target::DoubleProperties::mant_dig;
+ goto Lint;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ ivalue = Target::RealProperties::mant_dig;
+ goto Lint;
+ }
+ }
+ else if (ident == Id::max_10_exp)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ ivalue = Target::FloatProperties::max_10_exp;
+ goto Lint;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ ivalue = Target::DoubleProperties::max_10_exp;
+ goto Lint;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ ivalue = Target::RealProperties::max_10_exp;
+ goto Lint;
+ }
+ }
+ else if (ident == Id::max_exp)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ ivalue = Target::FloatProperties::max_exp;
+ goto Lint;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ ivalue = Target::DoubleProperties::max_exp;
+ goto Lint;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ ivalue = Target::RealProperties::max_exp;
+ goto Lint;
+ }
+ }
+ else if (ident == Id::min_10_exp)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ ivalue = Target::FloatProperties::min_10_exp;
+ goto Lint;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ ivalue = Target::DoubleProperties::min_10_exp;
+ goto Lint;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ ivalue = Target::RealProperties::min_10_exp;
+ goto Lint;
+ }
+ }
+ else if (ident == Id::min_exp)
+ {
+ switch (ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32:
+ ivalue = Target::FloatProperties::min_exp;
+ goto Lint;
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64:
+ ivalue = Target::DoubleProperties::min_exp;
+ goto Lint;
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80:
+ ivalue = Target::RealProperties::min_exp;
+ goto Lint;
+ }
+ }
+
+ return Type::getProperty(loc, ident, flag);
+
+Livalue:
+ e = new IntegerExp(loc, ivalue, this);
+ return e;
+
+Lfvalue:
+ if (isreal() || isimaginary())
+ e = new RealExp(loc, fvalue, this);
+ else
+ {
+ complex_t cvalue = complex_t(fvalue, fvalue);
+ //for (int i = 0; i < 20; i++)
+ // printf("%02x ", ((unsigned char *)&cvalue)[i]);
+ //printf("\n");
+ e = new ComplexExp(loc, cvalue, this);
+ }
+ return e;
+
+Lint:
+ e = new IntegerExp(loc, ivalue, Type::tint32);
+ return e;
+}
+
+Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ Type *t;
+
+ if (ident == Id::re)
+ {
+ switch (ty)
+ {
+ case Tcomplex32: t = tfloat32; goto L1;
+ case Tcomplex64: t = tfloat64; goto L1;
+ case Tcomplex80: t = tfloat80; goto L1;
+ L1:
+ e = e->castTo(sc, t);
+ break;
+
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ break;
+
+ case Timaginary32: t = tfloat32; goto L2;
+ case Timaginary64: t = tfloat64; goto L2;
+ case Timaginary80: t = tfloat80; goto L2;
+ L2:
+ e = new RealExp(e->loc, CTFloat::zero, t);
+ break;
+
+ default:
+ e = Type::getProperty(e->loc, ident, flag);
+ break;
+ }
+ }
+ else if (ident == Id::im)
+ { Type *t2;
+
+ switch (ty)
+ {
+ case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3;
+ case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3;
+ case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3;
+ L3:
+ e = e->castTo(sc, t);
+ e->type = t2;
+ break;
+
+ case Timaginary32: t = tfloat32; goto L4;
+ case Timaginary64: t = tfloat64; goto L4;
+ case Timaginary80: t = tfloat80; goto L4;
+ L4:
+ e = e->copy();
+ e->type = t;
+ break;
+
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ e = new RealExp(e->loc, CTFloat::zero, this);
+ break;
+
+ default:
+ e = Type::getProperty(e->loc, ident, flag);
+ break;
+ }
+ }
+ else
+ {
+ return Type::dotExp(sc, e, ident, flag);
+ }
+ if (!(flag & 1) || e)
+ e = ::semantic(e, sc);
+ return e;
+}
+
+Expression *TypeBasic::defaultInit(Loc loc)
+{
+ dinteger_t value = 0;
+
+ switch (ty)
+ {
+ case Tchar:
+ value = 0xFF;
+ break;
+
+ case Twchar:
+ case Tdchar:
+ value = 0xFFFF;
+ break;
+
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ return new RealExp(loc, Target::RealProperties::snan, this);
+
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
+ complex_t cvalue = complex_t(Target::RealProperties::snan, Target::RealProperties::snan);
+ return new ComplexExp(loc, cvalue, this);
+ }
+
+ case Tvoid:
+ error(loc, "void does not have a default initializer");
+ return new ErrorExp();
+ }
+ return new IntegerExp(loc, value, this);
+}
+
+bool TypeBasic::isZeroInit(Loc)
+{
+ switch (ty)
+ {
+ case Tchar:
+ case Twchar:
+ case Tdchar:
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ return false; // no
+ default:
+ return true; // yes
+ }
+}
+
+bool TypeBasic::isintegral()
+{
+ //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
+ return (flags & TFLAGSintegral) != 0;
+}
+
+bool TypeBasic::isfloating()
+{
+ return (flags & TFLAGSfloating) != 0;
+}
+
+bool TypeBasic::isreal()
+{
+ return (flags & TFLAGSreal) != 0;
+}
+
+bool TypeBasic::isimaginary()
+{
+ return (flags & TFLAGSimaginary) != 0;
+}
+
+bool TypeBasic::iscomplex()
+{
+ return (flags & TFLAGScomplex) != 0;
+}
+
+bool TypeBasic::isunsigned()
+{
+ return (flags & TFLAGSunsigned) != 0;
+}
+
+bool TypeBasic::isscalar()
+{
+ return (flags & (TFLAGSintegral | TFLAGSfloating)) != 0;
+}
+
+MATCH TypeBasic::implicitConvTo(Type *to)
+{
+ //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
+ if (this == to)
+ return MATCHexact;
+
+ if (ty == to->ty)
+ {
+ if (mod == to->mod)
+ return MATCHexact;
+ else if (MODimplicitConv(mod, to->mod))
+ return MATCHconst;
+ else if (!((mod ^ to->mod) & MODshared)) // for wild matching
+ return MATCHconst;
+ else
+ return MATCHconvert;
+ }
+
+ if (ty == Tvoid || to->ty == Tvoid)
+ return MATCHnomatch;
+ if (to->ty == Tbool)
+ return MATCHnomatch;
+
+ TypeBasic *tob;
+ if (to->ty == Tvector && to->deco)
+ {
+ TypeVector *tv = (TypeVector *)to;
+ tob = tv->elementType();
+ }
+ else if (to->ty == Tenum)
+ {
+ EnumDeclaration *ed = ((TypeEnum *)to)->sym;
+ if (ed->isSpecial())
+ {
+ /* Special enums that allow implicit conversions to them. */
+ tob = to->toBasetype()->isTypeBasic();
+ if (tob)
+ return implicitConvTo(tob);
+ }
+ else
+ return MATCHnomatch;
+ }
+ else
+ tob = to->isTypeBasic();
+ if (!tob)
+ return MATCHnomatch;
+
+ if (flags & TFLAGSintegral)
+ {
+ // Disallow implicit conversion of integers to imaginary or complex
+ if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
+ return MATCHnomatch;
+
+ // If converting from integral to integral
+ if (tob->flags & TFLAGSintegral)
+ { d_uns64 sz = size(Loc());
+ d_uns64 tosz = tob->size(Loc());
+
+ /* Can't convert to smaller size
+ */
+ if (sz > tosz)
+ return MATCHnomatch;
+
+ /* Can't change sign if same size
+ */
+ /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
+ return MATCHnomatch;*/
+ }
+ }
+ else if (flags & TFLAGSfloating)
+ {
+ // Disallow implicit conversion of floating point to integer
+ if (tob->flags & TFLAGSintegral)
+ return MATCHnomatch;
+
+ assert(tob->flags & TFLAGSfloating || to->ty == Tvector);
+
+ // Disallow implicit conversion from complex to non-complex
+ if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
+ return MATCHnomatch;
+
+ // Disallow implicit conversion of real or imaginary to complex
+ if (flags & (TFLAGSreal | TFLAGSimaginary) &&
+ tob->flags & TFLAGScomplex)
+ return MATCHnomatch;
+
+ // Disallow implicit conversion to-from real and imaginary
+ if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
+ (tob->flags & (TFLAGSreal | TFLAGSimaginary)))
+ return MATCHnomatch;
+ }
+ return MATCHconvert;
+}
+
+TypeBasic *TypeBasic::isTypeBasic()
+{
+ return (TypeBasic *)this;
+}
+
+/* ============================= TypeVector =========================== */
+
+/* The basetype must be one of:
+ * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
+ * For AVX:
+ * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4]
+ */
+TypeVector::TypeVector(Type *basetype)
+ : Type(Tvector)
+{
+ this->basetype = basetype;
+}
+
+TypeVector *TypeVector::create(Loc, Type *basetype)
+{
+ return new TypeVector(basetype);
+}
+
+const char *TypeVector::kind()
+{
+ return "vector";
+}
+
+Type *TypeVector::syntaxCopy()
+{
+ return new TypeVector(basetype->syntaxCopy());
+}
+
+Type *TypeVector::semantic(Loc loc, Scope *sc)
+{
+ unsigned int errors = global.errors;
+ basetype = basetype->semantic(loc, sc);
+ if (errors != global.errors)
+ return terror;
+ basetype = basetype->toBasetype()->mutableOf();
+ if (basetype->ty != Tsarray)
+ {
+ error(loc, "T in __vector(T) must be a static array, not %s", basetype->toChars());
+ return terror;
+ }
+ TypeSArray *t = (TypeSArray *)basetype;
+ int sz = (int)t->size(loc);
+ switch (Target::isVectorTypeSupported(sz, t->nextOf()))
+ {
+ case 0: // valid
+ break;
+ case 1: // no support at all
+ error(loc, "SIMD vector types not supported on this platform");
+ return terror;
+ case 2: // invalid size
+ error(loc, "%d byte vector type %s is not supported on this platform", sz, toChars());
+ return terror;
+ case 3: // invalid base type
+ error(loc, "vector type %s is not supported on this platform", toChars());
+ return terror;
+ default:
+ assert(0);
+ }
+ return merge();
+}
+
+TypeBasic *TypeVector::elementType()
+{
+ assert(basetype->ty == Tsarray);
+ TypeSArray *t = (TypeSArray *)basetype;
+ TypeBasic *tb = t->nextOf()->isTypeBasic();
+ assert(tb);
+ return tb;
+}
+
+bool TypeVector::isBoolean()
+{
+ return false;
+}
+
+d_uns64 TypeVector::size(Loc)
+{
+ return basetype->size();
+}
+
+unsigned TypeVector::alignsize()
+{
+ return (unsigned)basetype->size();
+}
+
+Expression *TypeVector::getProperty(Loc loc, Identifier *ident, int flag)
+{
+ return Type::getProperty(loc, ident, flag);
+}
+
+Expression *TypeVector::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ if (ident == Id::ptr && e->op == TOKcall)
+ {
+ /* The trouble with TOKcall is the return ABI for float[4] is different from
+ * __vector(float[4]), and a type paint won't do.
+ */
+ e = new AddrExp(e->loc, e);
+ e = ::semantic(e, sc);
+ e = e->castTo(sc, basetype->nextOf()->pointerTo());
+ return e;
+ }
+ if (ident == Id::array)
+ {
+ //e = e->castTo(sc, basetype);
+ // Keep lvalue-ness
+ e = e->copy();
+ e->type = basetype;
+ return e;
+ }
+ if (ident == Id::_init || ident == Id::offsetof || ident == Id::stringof || ident == Id::__xalignof)
+ {
+ // init should return a new VectorExp (Bugzilla 12776)
+ // offsetof does not work on a cast expression, so use e directly
+ // stringof should not add a cast to the output
+ return Type::dotExp(sc, e, ident, flag);
+ }
+ return basetype->dotExp(sc, e->castTo(sc, basetype), ident, flag);
+}
+
+Expression *TypeVector::defaultInit(Loc loc)
+{
+ //printf("TypeVector::defaultInit()\n");
+ assert(basetype->ty == Tsarray);
+ Expression *e = basetype->defaultInit(loc);
+ VectorExp *ve = new VectorExp(loc, e, this);
+ ve->type = this;
+ ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
+ return ve;
+}
+
+Expression *TypeVector::defaultInitLiteral(Loc loc)
+{
+ //printf("TypeVector::defaultInitLiteral()\n");
+ assert(basetype->ty == Tsarray);
+ Expression *e = basetype->defaultInitLiteral(loc);
+ VectorExp *ve = new VectorExp(loc, e, this);
+ ve->type = this;
+ ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
+ return ve;
+}
+
+bool TypeVector::isZeroInit(Loc loc)
+{
+ return basetype->isZeroInit(loc);
+}
+
+bool TypeVector::isintegral()
+{
+ //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
+ return basetype->nextOf()->isintegral();
+}
+
+bool TypeVector::isfloating()
+{
+ return basetype->nextOf()->isfloating();
+}
+
+bool TypeVector::isunsigned()
+{
+ return basetype->nextOf()->isunsigned();
+}
+
+bool TypeVector::isscalar()
+{
+ return basetype->nextOf()->isscalar();
+}
+
+MATCH TypeVector::implicitConvTo(Type *to)
+{
+ //printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
+ if (this == to)
+ return MATCHexact;
+ if (to->ty == Tvector)
+ {
+ TypeVector *tv = (TypeVector *)to;
+ assert(basetype->ty == Tsarray && tv->basetype->ty == Tsarray);
+
+ // Can't convert to a vector which has different size.
+ if (basetype->size() != tv->basetype->size())
+ return MATCHnomatch;
+
+ // Allow conversion to void[]
+ if (tv->basetype->nextOf()->ty == Tvoid)
+ return MATCHconvert;
+
+ // Otherwise implicitly convertible only if basetypes are.
+ return basetype->implicitConvTo(tv->basetype);
+ }
+ return MATCHnomatch;
+}
+
+/***************************** TypeArray *****************************/
+
+TypeArray::TypeArray(TY ty, Type *next)
+ : TypeNext(ty, next)
+{
+}
+
+Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ e = Type::dotExp(sc, e, ident, flag);
+
+ if (!(flag & 1) || e)
+ e = ::semantic(e, sc);
+ return e;
+}
+
+
+/***************************** TypeSArray *****************************/
+
+TypeSArray::TypeSArray(Type *t, Expression *dim)
+ : TypeArray(Tsarray, t)
+{
+ //printf("TypeSArray(%s)\n", dim->toChars());
+ this->dim = dim;
+}
+
+const char *TypeSArray::kind()
+{
+ return "sarray";
+}
+
+Type *TypeSArray::syntaxCopy()
+{
+ Type *t = next->syntaxCopy();
+ Expression *e = dim->syntaxCopy();
+ t = new TypeSArray(t, e);
+ t->mod = mod;
+ return t;
+}
+
+d_uns64 TypeSArray::size(Loc loc)
+{
+ //printf("TypeSArray::size()\n");
+ dinteger_t sz;
+ if (!dim)
+ return Type::size(loc);
+ sz = dim->toInteger();
+
+ {
+ bool overflow = false;
+
+ sz = mulu(next->size(), sz, overflow);
+ if (overflow)
+ goto Loverflow;
+ }
+ if (sz > UINT32_MAX)
+ goto Loverflow;
+ return sz;
+
+Loverflow:
+ error(loc, "static array %s size overflowed to %lld", toChars(), (long long)sz);
+ return SIZE_INVALID;
+}
+
+unsigned TypeSArray::alignsize()
+{
+ return next->alignsize();
+}
+
+/**************************
+ * This evaluates exp while setting length to be the number
+ * of elements in the tuple t.
+ */
+Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
+{
+ if (t->ty == Ttuple)
+ {
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+
+ sc = sc->startCTFE();
+ exp = ::semantic(exp, sc);
+ sc = sc->endCTFE();
+
+ sc->pop();
+ }
+ else
+ {
+ sc = sc->startCTFE();
+ exp = ::semantic(exp, sc);
+ sc = sc->endCTFE();
+ }
+
+ return exp;
+}
+
+Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
+{
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+
+ sc = sc->startCTFE();
+ exp = ::semantic(exp, sc);
+ sc = sc->endCTFE();
+
+ sc->pop();
+ return exp;
+}
+
+void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ //printf("TypeSArray::resolve() %s\n", toChars());
+ next->resolve(loc, sc, pe, pt, ps, intypeid);
+ //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
+ if (*pe)
+ {
+ // It's really an index expression
+ if (Dsymbol *s = getDsymbol(*pe))
+ *pe = new DsymbolExp(loc, s);
+ *pe = new ArrayExp(loc, *pe, dim);
+ }
+ else if (*ps)
+ {
+ Dsymbol *s = *ps;
+ TupleDeclaration *td = s->isTupleDeclaration();
+ if (td)
+ {
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+ sc = sc->startCTFE();
+ dim = ::semantic(dim, sc);
+ sc = sc->endCTFE();
+ sc = sc->pop();
+
+ dim = dim->ctfeInterpret();
+ uinteger_t d = dim->toUInteger();
+
+ if (d >= td->objects->dim)
+ {
+ error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim);
+ *ps = NULL;
+ *pt = Type::terror;
+ return;
+ }
+ RootObject *o = (*td->objects)[(size_t)d];
+ if (o->dyncast() == DYNCAST_DSYMBOL)
+ {
+ *ps = (Dsymbol *)o;
+ return;
+ }
+ if (o->dyncast() == DYNCAST_EXPRESSION)
+ {
+ Expression *e = (Expression *)o;
+ if (e->op == TOKdsymbol)
+ {
+ *ps = ((DsymbolExp *)e)->s;
+ *pe = NULL;
+ }
+ else
+ {
+ *ps = NULL;
+ *pe = e;
+ }
+ return;
+ }
+ if (o->dyncast() == DYNCAST_TYPE)
+ {
+ *ps = NULL;
+ *pt = ((Type *)o)->addMod(this->mod);
+ return;
+ }
+
+ /* Create a new TupleDeclaration which
+ * is a slice [d..d+1] out of the old one.
+ * Do it this way because TemplateInstance::semanticTiargs()
+ * can handle unresolved Objects this way.
+ */
+ Objects *objects = new Objects;
+ objects->setDim(1);
+ (*objects)[0] = o;
+
+ TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+ *ps = tds;
+ }
+ else
+ goto Ldefault;
+ }
+ else
+ {
+ if ((*pt)->ty != Terror)
+ next = *pt; // prevent re-running semantic() on 'next'
+ Ldefault:
+ Type::resolve(loc, sc, pe, pt, ps, intypeid);
+ }
+}
+
+Type *TypeSArray::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypeSArray::semantic() %s\n", toChars());
+
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+ next->resolve(loc, sc, &e, &t, &s);
+ if (dim && s && s->isTupleDeclaration())
+ { TupleDeclaration *sd = s->isTupleDeclaration();
+
+ dim = semanticLength(sc, sd, dim);
+ dim = dim->ctfeInterpret();
+ uinteger_t d = dim->toUInteger();
+
+ if (d >= sd->objects->dim)
+ { error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim);
+ return Type::terror;
+ }
+ RootObject *o = (*sd->objects)[(size_t)d];
+ if (o->dyncast() != DYNCAST_TYPE)
+ { error(loc, "%s is not a type", toChars());
+ return Type::terror;
+ }
+ t = ((Type *)o)->addMod(this->mod);
+ return t;
+ }
+
+ Type *tn = next->semantic(loc, sc);
+ if (tn->ty == Terror)
+ return terror;
+
+ Type *tbn = tn->toBasetype();
+
+ if (dim)
+ {
+ unsigned int errors = global.errors;
+ dim = semanticLength(sc, tbn, dim);
+ if (errors != global.errors)
+ goto Lerror;
+
+ dim = dim->optimize(WANTvalue);
+ dim = dim->ctfeInterpret();
+ if (dim->op == TOKerror)
+ goto Lerror;
+ errors = global.errors;
+ dinteger_t d1 = dim->toInteger();
+ if (errors != global.errors)
+ goto Lerror;
+
+ dim = dim->implicitCastTo(sc, tsize_t);
+ dim = dim->optimize(WANTvalue);
+ if (dim->op == TOKerror)
+ goto Lerror;
+ errors = global.errors;
+ dinteger_t d2 = dim->toInteger();
+ if (errors != global.errors)
+ goto Lerror;
+
+ if (dim->op == TOKerror)
+ goto Lerror;
+
+ if (d1 != d2)
+ {
+ Loverflow:
+ error(loc, "%s size %llu * %llu exceeds 0x%llx size limit for static array",
+ toChars(), (unsigned long long)tbn->size(loc), (unsigned long long)d1, Target::maxStaticDataSize);
+ goto Lerror;
+ }
+
+ Type *tbx = tbn->baseElemOf();
+ if ((tbx->ty == Tstruct && !((TypeStruct *)tbx)->sym->members) ||
+ (tbx->ty == Tenum && !((TypeEnum *)tbx)->sym->members))
+ {
+ /* To avoid meaningless error message, skip the total size limit check
+ * when the bottom of element type is opaque.
+ */
+ }
+ else if (tbn->isintegral() ||
+ tbn->isfloating() ||
+ tbn->ty == Tpointer ||
+ tbn->ty == Tarray ||
+ tbn->ty == Tsarray ||
+ tbn->ty == Taarray ||
+ (tbn->ty == Tstruct && (((TypeStruct *)tbn)->sym->sizeok == SIZEOKdone)) ||
+ tbn->ty == Tclass)
+ {
+ /* Only do this for types that don't need to have semantic()
+ * run on them for the size, since they may be forward referenced.
+ */
+ bool overflow = false;
+ if (mulu(tbn->size(loc), d2, overflow) >= Target::maxStaticDataSize || overflow)
+ goto Loverflow;
+ }
+ }
+ switch (tbn->ty)
+ {
+ case Ttuple:
+ { // Index the tuple to get the type
+ assert(dim);
+ TypeTuple *tt = (TypeTuple *)tbn;
+ uinteger_t d = dim->toUInteger();
+
+ if (d >= tt->arguments->dim)
+ { error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim);
+ goto Lerror;
+ }
+ Type *telem = (*tt->arguments)[(size_t)d]->type;
+ return telem->addMod(this->mod);
+ }
+ case Tfunction:
+ case Tnone:
+ error(loc, "can't have array of %s", tbn->toChars());
+ goto Lerror;
+ default:
+ break;
+ }
+ if (tbn->isscope())
+ { error(loc, "cannot have array of scope %s", tbn->toChars());
+ goto Lerror;
+ }
+
+ /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
+ * and const(T)[3] become const(T[3])
+ */
+ next = tn;
+ transitive();
+ t = addMod(tn->mod);
+
+ return t->merge();
+
+Lerror:
+ return Type::terror;
+}
+
+Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ if (ident == Id::length)
+ {
+ Loc oldLoc = e->loc;
+ e = dim->copy();
+ e->loc = oldLoc;
+ }
+ else if (ident == Id::ptr)
+ {
+ if (e->op == TOKtype)
+ {
+ e->error("%s is not an expression", e->toChars());
+ return new ErrorExp();
+ }
+ else if (!(flag & 2) && sc->func && !sc->intypeof && sc->func->setUnsafe())
+ {
+ e->deprecation("%s.ptr cannot be used in @safe code, use &%s[0] instead", e->toChars(), e->toChars());
+ // return new ErrorExp();
+ }
+ e = e->castTo(sc, e->type->nextOf()->pointerTo());
+ }
+ else
+ {
+ e = TypeArray::dotExp(sc, e, ident, flag);
+ }
+ if (!(flag & 1) || e)
+ e = ::semantic(e, sc);
+ return e;
+}
+
+structalign_t TypeSArray::alignment()
+{
+ return next->alignment();
+}
+
+bool TypeSArray::isString()
+{
+ TY nty = next->toBasetype()->ty;
+ return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+MATCH TypeSArray::constConv(Type *to)
+{
+ if (to->ty == Tsarray)
+ {
+ TypeSArray *tsa = (TypeSArray *)to;
+ if (!dim->equals(tsa->dim))
+ return MATCHnomatch;
+ }
+ return TypeNext::constConv(to);
+}
+
+MATCH TypeSArray::implicitConvTo(Type *to)
+{
+ //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+
+ if (to->ty == Tarray)
+ {
+ TypeDArray *ta = (TypeDArray *)to;
+
+ if (!MODimplicitConv(next->mod, ta->next->mod))
+ return MATCHnomatch;
+
+ /* Allow conversion to void[]
+ */
+ if (ta->next->ty == Tvoid)
+ {
+ return MATCHconvert;
+ }
+
+ MATCH m = next->constConv(ta->next);
+ if (m > MATCHnomatch)
+ {
+ return MATCHconvert;
+ }
+ return MATCHnomatch;
+ }
+
+ if (to->ty == Tsarray)
+ {
+ if (this == to)
+ return MATCHexact;
+
+ TypeSArray *tsa = (TypeSArray *)to;
+
+ if (dim->equals(tsa->dim))
+ {
+ /* Since static arrays are value types, allow
+ * conversions from const elements to non-const
+ * ones, just like we allow conversion from const int
+ * to int.
+ */
+ MATCH m = next->implicitConvTo(tsa->next);
+ if (m >= MATCHconst)
+ {
+ if (mod != to->mod)
+ m = MATCHconst;
+ return m;
+ }
+ }
+ }
+ return MATCHnomatch;
+}
+
+Expression *TypeSArray::defaultInit(Loc loc)
+{
+ if (next->ty == Tvoid)
+ return tuns8->defaultInit(loc);
+ else
+ return next->defaultInit(loc);
+}
+
+bool TypeSArray::isZeroInit(Loc loc)
+{
+ return next->isZeroInit(loc);
+}
+
+bool TypeSArray::needsDestruction()
+{
+ return next->needsDestruction();
+}
+
+/*********************************
+ *
+ */
+
+bool TypeSArray::needsNested()
+{
+ return next->needsNested();
+}
+
+Expression *TypeSArray::defaultInitLiteral(Loc loc)
+{
+ size_t d = (size_t)dim->toInteger();
+ Expression *elementinit;
+ if (next->ty == Tvoid)
+ elementinit = tuns8->defaultInitLiteral(loc);
+ else
+ elementinit = next->defaultInitLiteral(loc);
+ Expressions *elements = new Expressions();
+ elements->setDim(d);
+ for (size_t i = 0; i < d; i++)
+ (*elements)[i] = NULL;
+ ArrayLiteralExp *ae = new ArrayLiteralExp(Loc(), elementinit, elements);
+ ae->type = this;
+ return ae;
+}
+
+bool TypeSArray::hasPointers()
+{
+ /* Don't want to do this, because:
+ * struct S { T* array[0]; }
+ * may be a variable length struct.
+ */
+ //if (dim->toInteger() == 0)
+ // return false;
+
+ if (next->ty == Tvoid)
+ {
+ // Arrays of void contain arbitrary data, which may include pointers
+ return true;
+ }
+ else
+ return next->hasPointers();
+}
+
+/***************************** TypeDArray *****************************/
+
+TypeDArray::TypeDArray(Type *t)
+ : TypeArray(Tarray, t)
+{
+ //printf("TypeDArray(t = %p)\n", t);
+}
+
+const char *TypeDArray::kind()
+{
+ return "darray";
+}
+
+Type *TypeDArray::syntaxCopy()
+{
+ Type *t = next->syntaxCopy();
+ if (t == next)
+ t = this;
+ else
+ {
+ t = new TypeDArray(t);
+ t->mod = mod;
+ }
+ return t;
+}
+
+d_uns64 TypeDArray::size(Loc)
+{
+ //printf("TypeDArray::size()\n");
+ return Target::ptrsize * 2;
+}
+
+unsigned TypeDArray::alignsize()
+{
+ // A DArray consists of two ptr-sized values, so align it on pointer size
+ // boundary
+ return Target::ptrsize;
+}
+
+Type *TypeDArray::semantic(Loc loc, Scope *sc)
+{
+ Type *tn = next->semantic(loc,sc);
+ Type *tbn = tn->toBasetype();
+ switch (tbn->ty)
+ {
+ case Ttuple:
+ return tbn;
+ case Tfunction:
+ case Tnone:
+ error(loc, "can't have array of %s", tbn->toChars());
+ return Type::terror;
+ case Terror:
+ return Type::terror;
+ default:
+ break;
+ }
+ if (tn->isscope())
+ { error(loc, "cannot have array of scope %s", tn->toChars());
+ return Type::terror;
+ }
+ next = tn;
+ transitive();
+ return merge();
+}
+
+void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ //printf("TypeDArray::resolve() %s\n", toChars());
+ next->resolve(loc, sc, pe, pt, ps, intypeid);
+ //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
+ if (*pe)
+ {
+ // It's really a slice expression
+ if (Dsymbol *s = getDsymbol(*pe))
+ *pe = new DsymbolExp(loc, s);
+ *pe = new ArrayExp(loc, *pe);
+ }
+ else if (*ps)
+ {
+ TupleDeclaration *td = (*ps)->isTupleDeclaration();
+ if (td)
+ ; // keep *ps
+ else
+ goto Ldefault;
+ }
+ else
+ {
+ if ((*pt)->ty != Terror)
+ next = *pt; // prevent re-running semantic() on 'next'
+ Ldefault:
+ Type::resolve(loc, sc, pe, pt, ps, intypeid);
+ }
+}
+
+Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ if (e->op == TOKtype &&
+ (ident == Id::length || ident == Id::ptr))
+ {
+ e->error("%s is not an expression", e->toChars());
+ return new ErrorExp();
+ }
+ if (ident == Id::length)
+ {
+ if (e->op == TOKstring)
+ {
+ StringExp *se = (StringExp *)e;
+ return new IntegerExp(se->loc, se->len, Type::tsize_t);
+ }
+ if (e->op == TOKnull)
+ return new IntegerExp(e->loc, 0, Type::tsize_t);
+ e = new ArrayLengthExp(e->loc, e);
+ e->type = Type::tsize_t;
+ return e;
+ }
+ else if (ident == Id::ptr)
+ {
+ if (!(flag & 2) && sc->func && !sc->intypeof && sc->func->setUnsafe())
+ {
+ e->deprecation("%s.ptr cannot be used in @safe code, use &%s[0] instead", e->toChars(), e->toChars());
+ // return new ErrorExp();
+ }
+ e = e->castTo(sc, next->pointerTo());
+ return e;
+ }
+ else
+ {
+ e = TypeArray::dotExp(sc, e, ident, flag);
+ }
+ return e;
+}
+
+bool TypeDArray::isString()
+{
+ TY nty = next->toBasetype()->ty;
+ return nty == Tchar || nty == Twchar || nty == Tdchar;
+}
+
+MATCH TypeDArray::implicitConvTo(Type *to)
+{
+ //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+ if (equals(to))
+ return MATCHexact;
+
+ if (to->ty == Tarray)
+ {
+ TypeDArray *ta = (TypeDArray *)to;
+
+ if (!MODimplicitConv(next->mod, ta->next->mod))
+ return MATCHnomatch; // not const-compatible
+
+ /* Allow conversion to void[]
+ */
+ if (next->ty != Tvoid && ta->next->ty == Tvoid)
+ {
+ return MATCHconvert;
+ }
+
+ MATCH m = next->constConv(ta->next);
+ if (m > MATCHnomatch)
+ {
+ if (m == MATCHexact && mod != to->mod)
+ m = MATCHconst;
+ return m;
+ }
+ }
+ return Type::implicitConvTo(to);
+}
+
+Expression *TypeDArray::defaultInit(Loc loc)
+{
+ return new NullExp(loc, this);
+}
+
+bool TypeDArray::isZeroInit(Loc)
+{
+ return true;
+}
+
+bool TypeDArray::isBoolean()
+{
+ return true;
+}
+
+bool TypeDArray::hasPointers()
+{
+ return true;
+}
+
+
+/***************************** TypeAArray *****************************/
+
+TypeAArray::TypeAArray(Type *t, Type *index)
+ : TypeArray(Taarray, t)
+{
+ this->index = index;
+ this->loc = Loc();
+ this->sc = NULL;
+}
+
+TypeAArray *TypeAArray::create(Type *t, Type *index)
+{
+ return new TypeAArray(t, index);
+}
+
+const char *TypeAArray::kind()
+{
+ return "aarray";
+}
+
+Type *TypeAArray::syntaxCopy()
+{
+ Type *t = next->syntaxCopy();
+ Type *ti = index->syntaxCopy();
+ if (t == next && ti == index)
+ t = this;
+ else
+ {
+ t = new TypeAArray(t, ti);
+ t->mod = mod;
+ }
+ return t;
+}
+
+d_uns64 TypeAArray::size(Loc)
+{
+ return Target::ptrsize;
+}
+
+Type *TypeAArray::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty);
+ if (deco)
+ return this;
+
+ this->loc = loc;
+ this->sc = sc;
+ if (sc)
+ sc->setNoFree();
+
+ // Deal with the case where we thought the index was a type, but
+ // in reality it was an expression.
+ if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray ||
+ index->ty == Ttypeof || index->ty == Treturn)
+ {
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+
+ index->resolve(loc, sc, &e, &t, &s);
+ if (e)
+ {
+ // It was an expression -
+ // Rewrite as a static array
+ TypeSArray *tsa = new TypeSArray(next, e);
+ return tsa->semantic(loc, sc);
+ }
+ else if (t)
+ index = t->semantic(loc, sc);
+ else
+ {
+ index->error(loc, "index is not a type or an expression");
+ return Type::terror;
+ }
+ }
+ else
+ index = index->semantic(loc,sc);
+ index = index->merge2();
+
+ if (index->nextOf() && !index->nextOf()->isImmutable())
+ {
+ index = index->constOf()->mutableOf();
+ }
+
+ switch (index->toBasetype()->ty)
+ {
+ case Tfunction:
+ case Tvoid:
+ case Tnone:
+ case Ttuple:
+ error(loc, "can't have associative array key of %s", index->toBasetype()->toChars());
+ /* fall through */
+ case Terror:
+ return Type::terror;
+ default:
+ break;
+ }
+ Type *tbase = index->baseElemOf();
+ while (tbase->ty == Tarray)
+ tbase = tbase->nextOf()->baseElemOf();
+ if (tbase->ty == Tstruct)
+ {
+ /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
+ */
+ StructDeclaration *sd = ((TypeStruct *)tbase)->sym;
+ if (sd->_scope)
+ sd->semantic(NULL);
+
+ // duplicate a part of StructDeclaration::semanticTypeInfoMembers
+ //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd->xeq, sd->xerreq, sd->xhash);
+ if (sd->xeq &&
+ sd->xeq->_scope &&
+ sd->xeq->semanticRun < PASSsemantic3done)
+ {
+ unsigned errors = global.startGagging();
+ sd->xeq->semantic3(sd->xeq->_scope);
+ if (global.endGagging(errors))
+ sd->xeq = sd->xerreq;
+ }
+
+ const char *s = (index->toBasetype()->ty != Tstruct) ? "bottom of " : "";
+ if (!sd->xeq)
+ {
+ // If sd->xhash != NULL:
+ // sd or its fields have user-defined toHash.
+ // AA assumes that its result is consistent with bitwise equality.
+ // else:
+ // bitwise equality & hashing
+ }
+ else if (sd->xeq == sd->xerreq)
+ {
+ if (search_function(sd, Id::eq))
+ {
+ error(loc, "%sAA key type %s does not have 'bool opEquals(ref const %s) const'",
+ s, sd->toChars(), sd->toChars());
+ }
+ else
+ {
+ error(loc, "%sAA key type %s does not support const equality",
+ s, sd->toChars());
+ }
+ return Type::terror;
+ }
+ else if (!sd->xhash)
+ {
+ if (search_function(sd, Id::eq))
+ {
+ error(loc, "%sAA key type %s should have 'size_t toHash() const nothrow @safe' if opEquals defined",
+ s, sd->toChars());
+ }
+ else
+ {
+ error(loc, "%sAA key type %s supports const equality but doesn't support const hashing",
+ s, sd->toChars());
+ }
+ return Type::terror;
+ }
+ else
+ {
+ // defined equality & hashing
+ assert(sd->xeq && sd->xhash);
+
+ /* xeq and xhash may be implicitly defined by compiler. For example:
+ * struct S { int[] arr; }
+ * With 'arr' field equality and hashing, compiler will implicitly
+ * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
+ */
+ }
+ }
+ else if (tbase->ty == Tclass && !((TypeClass *)tbase)->sym->isInterfaceDeclaration())
+ {
+ ClassDeclaration *cd = ((TypeClass *)tbase)->sym;
+ if (cd->_scope)
+ cd->semantic(NULL);
+
+ if (!ClassDeclaration::object)
+ {
+ error(Loc(), "missing or corrupt object.d");
+ fatal();
+ }
+
+ static FuncDeclaration *feq = NULL;
+ static FuncDeclaration *fcmp = NULL;
+ static FuncDeclaration *fhash = NULL;
+ if (!feq) feq = search_function(ClassDeclaration::object, Id::eq)->isFuncDeclaration();
+ if (!fcmp) fcmp = search_function(ClassDeclaration::object, Id::cmp)->isFuncDeclaration();
+ if (!fhash) fhash = search_function(ClassDeclaration::object, Id::tohash)->isFuncDeclaration();
+ assert(fcmp && feq && fhash);
+
+ if (feq->vtblIndex < (int)cd->vtbl.dim && cd->vtbl[feq ->vtblIndex] == feq)
+ {
+ if (fcmp->vtblIndex < (int)cd->vtbl.dim && cd->vtbl[fcmp->vtblIndex] != fcmp)
+ {
+ const char *s = (index->toBasetype()->ty != Tclass) ? "bottom of " : "";
+ error(loc, "%sAA key type %s now requires equality rather than comparison",
+ s, cd->toChars());
+ errorSupplemental(loc, "Please override Object.opEquals and toHash.");
+ }
+ }
+ }
+ next = next->semantic(loc,sc)->merge2();
+ transitive();
+
+ switch (next->toBasetype()->ty)
+ {
+ case Tfunction:
+ case Tvoid:
+ case Tnone:
+ case Ttuple:
+ error(loc, "can't have associative array of %s", next->toChars());
+ /* fall through */
+ case Terror:
+ return Type::terror;
+ }
+ if (next->isscope())
+ { error(loc, "cannot have array of scope %s", next->toChars());
+ return Type::terror;
+ }
+ return merge();
+}
+
+void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ //printf("TypeAArray::resolve() %s\n", toChars());
+
+ // Deal with the case where we thought the index was a type, but
+ // in reality it was an expression.
+ if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
+ {
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+
+ index->resolve(loc, sc, &e, &t, &s, intypeid);
+ if (e)
+ {
+ // It was an expression -
+ // Rewrite as a static array
+ TypeSArray *tsa = new TypeSArray(next, e);
+ tsa->mod = this->mod; // just copy mod field so tsa's semantic is not yet done
+ return tsa->resolve(loc, sc, pe, pt, ps, intypeid);
+ }
+ else if (t)
+ index = t;
+ else
+ index->error(loc, "index is not a type or an expression");
+ }
+ Type::resolve(loc, sc, pe, pt, ps, intypeid);
+}
+
+
+Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ if (ident == Id::length)
+ {
+ static FuncDeclaration *fd_aaLen = NULL;
+ if (fd_aaLen == NULL)
+ {
+ Parameters *fparams = new Parameters();
+ fparams->push(new Parameter(STCin, this, NULL, NULL));
+ fd_aaLen = FuncDeclaration::genCfunc(fparams, Type::tsize_t, Id::aaLen);
+ TypeFunction *tf = (TypeFunction *)fd_aaLen->type;
+ tf->purity = PUREconst;
+ tf->isnothrow = true;
+ tf->isnogc = false;
+ }
+ Expression *ev = new VarExp(e->loc, fd_aaLen, false);
+ e = new CallExp(e->loc, ev, e);
+ e->type = ((TypeFunction *)fd_aaLen->type)->next;
+ }
+ else
+ e = Type::dotExp(sc, e, ident, flag);
+ return e;
+}
+
+Expression *TypeAArray::defaultInit(Loc loc)
+{
+ return new NullExp(loc, this);
+}
+
+bool TypeAArray::isZeroInit(Loc)
+{
+ return true;
+}
+
+bool TypeAArray::isBoolean()
+{
+ return true;
+}
+
+bool TypeAArray::hasPointers()
+{
+ return true;
+}
+
+MATCH TypeAArray::implicitConvTo(Type *to)
+{
+ //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
+ if (equals(to))
+ return MATCHexact;
+
+ if (to->ty == Taarray)
+ { TypeAArray *ta = (TypeAArray *)to;
+
+ if (!MODimplicitConv(next->mod, ta->next->mod))
+ return MATCHnomatch; // not const-compatible
+
+ if (!MODimplicitConv(index->mod, ta->index->mod))
+ return MATCHnomatch; // not const-compatible
+
+ MATCH m = next->constConv(ta->next);
+ MATCH mi = index->constConv(ta->index);
+ if (m > MATCHnomatch && mi > MATCHnomatch)
+ {
+ return MODimplicitConv(mod, to->mod) ? MATCHconst : MATCHnomatch;
+ }
+ }
+ return Type::implicitConvTo(to);
+}
+
+MATCH TypeAArray::constConv(Type *to)
+{
+ if (to->ty == Taarray)
+ {
+ TypeAArray *taa = (TypeAArray *)to;
+ MATCH mindex = index->constConv(taa->index);
+ MATCH mkey = next->constConv(taa->next);
+ // Pick the worst match
+ return mkey < mindex ? mkey : mindex;
+ }
+ return Type::constConv(to);
+}
+
+/***************************** TypePointer *****************************/
+
+TypePointer::TypePointer(Type *t)
+ : TypeNext(Tpointer, t)
+{
+}
+
+TypePointer *TypePointer::create(Type *t)
+{
+ return new TypePointer(t);
+}
+
+const char *TypePointer::kind()
+{
+ return "pointer";
+}
+
+Type *TypePointer::syntaxCopy()
+{
+ Type *t = next->syntaxCopy();
+ if (t == next)
+ t = this;
+ else
+ {
+ t = new TypePointer(t);
+ t->mod = mod;
+ }
+ return t;
+}
+
+Type *TypePointer::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypePointer::semantic() %s\n", toChars());
+ if (deco)
+ return this;
+ Type *n = next->semantic(loc, sc);
+ switch (n->toBasetype()->ty)
+ {
+ case Ttuple:
+ error(loc, "can't have pointer to %s", n->toChars());
+ /* fall through */
+ case Terror:
+ return Type::terror;
+ default:
+ break;
+ }
+ if (n != next)
+ {
+ deco = NULL;
+ }
+ next = n;
+ if (next->ty != Tfunction)
+ { transitive();
+ return merge();
+ }
+ deco = merge()->deco;
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ return this;
+}
+
+
+d_uns64 TypePointer::size(Loc)
+{
+ return Target::ptrsize;
+}
+
+MATCH TypePointer::implicitConvTo(Type *to)
+{
+ //printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
+
+ if (equals(to))
+ return MATCHexact;
+ if (next->ty == Tfunction)
+ {
+ if (to->ty == Tpointer)
+ {
+ TypePointer *tp = (TypePointer *)to;
+ if (tp->next->ty == Tfunction)
+ {
+ if (next->equals(tp->next))
+ return MATCHconst;
+
+ if (next->covariant(tp->next) == 1)
+ {
+ Type *tret = this->next->nextOf();
+ Type *toret = tp->next->nextOf();
+ if (tret->ty == Tclass && toret->ty == Tclass)
+ {
+ /* Bugzilla 10219: Check covariant interface return with offset tweaking.
+ * interface I {}
+ * class C : Object, I {}
+ * I function() dg = function C() {} // should be error
+ */
+ int offset = 0;
+ if (toret->isBaseOf(tret, &offset) && offset != 0)
+ return MATCHnomatch;
+ }
+ return MATCHconvert;
+ }
+ }
+ else if (tp->next->ty == Tvoid)
+ {
+ // Allow conversions to void*
+ return MATCHconvert;
+ }
+ }
+ return MATCHnomatch;
+ }
+ else if (to->ty == Tpointer)
+ {
+ TypePointer *tp = (TypePointer *)to;
+ assert(tp->next);
+
+ if (!MODimplicitConv(next->mod, tp->next->mod))
+ return MATCHnomatch; // not const-compatible
+
+ /* Alloc conversion to void*
+ */
+ if (next->ty != Tvoid && tp->next->ty == Tvoid)
+ {
+ return MATCHconvert;
+ }
+
+ MATCH m = next->constConv(tp->next);
+ if (m > MATCHnomatch)
+ {
+ if (m == MATCHexact && mod != to->mod)
+ m = MATCHconst;
+ return m;
+ }
+ }
+ return MATCHnomatch;
+}
+
+MATCH TypePointer::constConv(Type *to)
+{
+ if (next->ty == Tfunction)
+ {
+ if (to->nextOf() && next->equals(((TypeNext *)to)->next))
+ return Type::constConv(to);
+ else
+ return MATCHnomatch;
+ }
+ return TypeNext::constConv(to);
+}
+
+bool TypePointer::isscalar()
+{
+ return true;
+}
+
+Expression *TypePointer::defaultInit(Loc loc)
+{
+ return new NullExp(loc, this);
+}
+
+bool TypePointer::isZeroInit(Loc)
+{
+ return true;
+}
+
+bool TypePointer::hasPointers()
+{
+ return true;
+}
+
+
+/***************************** TypeReference *****************************/
+
+TypeReference::TypeReference(Type *t)
+ : TypeNext(Treference, t)
+{
+ // BUG: what about references to static arrays?
+}
+
+const char *TypeReference::kind()
+{
+ return "reference";
+}
+
+Type *TypeReference::syntaxCopy()
+{
+ Type *t = next->syntaxCopy();
+ if (t == next)
+ t = this;
+ else
+ {
+ t = new TypeReference(t);
+ t->mod = mod;
+ }
+ return t;
+}
+
+Type *TypeReference::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypeReference::semantic()\n");
+ Type *n = next->semantic(loc, sc);
+ if (n != next)
+ deco = NULL;
+ next = n;
+ transitive();
+ return merge();
+}
+
+
+d_uns64 TypeReference::size(Loc)
+{
+ return Target::ptrsize;
+}
+
+Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ // References just forward things along
+ return next->dotExp(sc, e, ident, flag);
+}
+
+Expression *TypeReference::defaultInit(Loc loc)
+{
+ return new NullExp(loc, this);
+}
+
+bool TypeReference::isZeroInit(Loc)
+{
+ return true;
+}
+
+
+/***************************** TypeFunction *****************************/
+
+TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc)
+ : TypeNext(Tfunction, treturn)
+{
+//if (!treturn) *(char*)0=0;
+// assert(treturn);
+ assert(0 <= varargs && varargs <= 2);
+ this->parameters = parameters;
+ this->varargs = varargs;
+ this->linkage = linkage;
+ this->inuse = 0;
+ this->isnothrow = false;
+ this->isnogc = false;
+ this->purity = PUREimpure;
+ this->isproperty = false;
+ this->isref = false;
+ this->isreturn = false;
+ this->isscope = false;
+ this->isscopeinferred = false;
+ this->iswild = 0;
+ this->fargs = NULL;
+
+ if (stc & STCpure)
+ this->purity = PUREfwdref;
+ if (stc & STCnothrow)
+ this->isnothrow = true;
+ if (stc & STCnogc)
+ this->isnogc = true;
+ if (stc & STCproperty)
+ this->isproperty = true;
+
+ if (stc & STCref)
+ this->isref = true;
+ if (stc & STCreturn)
+ this->isreturn = true;
+ if (stc & STCscope)
+ this->isscope = true;
+ if (stc & STCscopeinferred)
+ this->isscopeinferred = true;
+
+ this->trust = TRUSTdefault;
+ if (stc & STCsafe)
+ this->trust = TRUSTsafe;
+ if (stc & STCsystem)
+ this->trust = TRUSTsystem;
+ if (stc & STCtrusted)
+ this->trust = TRUSTtrusted;
+}
+
+TypeFunction *TypeFunction::create(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc)
+{
+ return new TypeFunction(parameters, treturn, varargs, linkage, stc);
+}
+
+const char *TypeFunction::kind()
+{
+ return "function";
+}
+
+Type *TypeFunction::syntaxCopy()
+{
+ Type *treturn = next ? next->syntaxCopy() : NULL;
+ Parameters *params = Parameter::arraySyntaxCopy(parameters);
+ TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
+ t->mod = mod;
+ t->isnothrow = isnothrow;
+ t->isnogc = isnogc;
+ t->purity = purity;
+ t->isproperty = isproperty;
+ t->isref = isref;
+ t->isreturn = isreturn;
+ t->isscope = isscope;
+ t->isscopeinferred = isscopeinferred;
+ t->iswild = iswild;
+ t->trust = trust;
+ t->fargs = fargs;
+ return t;
+}
+
+/*******************************
+ * Covariant means that 'this' can substitute for 't',
+ * i.e. a pure function is a match for an impure type.
+ * Params:
+ * t = type 'this' is covariant with
+ * pstc = if not null, store STCxxxx which would make it covariant
+ * fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
+ * Returns:
+ * 0 types are distinct
+ * 1 this is covariant with t
+ * 2 arguments match as far as overloading goes,
+ * but types are not covariant
+ * 3 cannot determine covariance because of forward references
+ * *pstc STCxxxx which would make it covariant
+ */
+
+int Type::covariant(Type *t, StorageClass *pstc, bool fix17349)
+{
+ if (pstc)
+ *pstc = 0;
+ StorageClass stc = 0;
+
+ bool notcovariant = false;
+
+ TypeFunction *t1;
+ TypeFunction *t2;
+
+ if (equals(t))
+ return 1; // covariant
+
+ if (ty != Tfunction || t->ty != Tfunction)
+ goto Ldistinct;
+
+ t1 = (TypeFunction *)this;
+ t2 = (TypeFunction *)t;
+
+ if (t1->varargs != t2->varargs)
+ goto Ldistinct;
+
+ if (t1->parameters && t2->parameters)
+ {
+ size_t dim = Parameter::dim(t1->parameters);
+ if (dim != Parameter::dim(t2->parameters))
+ goto Ldistinct;
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam1 = Parameter::getNth(t1->parameters, i);
+ Parameter *fparam2 = Parameter::getNth(t2->parameters, i);
+
+ if (!fparam1->type->equals(fparam2->type))
+ {
+ if (!fix17349)
+ goto Ldistinct;
+ Type *tp1 = fparam1->type;
+ Type *tp2 = fparam2->type;
+ if (tp1->ty == tp2->ty)
+ {
+ if (tp1->ty == Tclass)
+ {
+ if (((TypeClass *)tp1)->sym == ((TypeClass *)tp2)->sym && MODimplicitConv(tp2->mod, tp1->mod))
+ goto Lcov;
+ }
+ else if (tp1->ty == Tstruct)
+ {
+ if (((TypeStruct *)tp1)->sym == ((TypeStruct *)tp2)->sym && MODimplicitConv(tp2->mod, tp1->mod))
+ goto Lcov;
+ }
+ else if (tp1->ty == Tpointer)
+ {
+ if (tp2->implicitConvTo(tp1))
+ goto Lcov;
+ }
+ else if (tp1->ty == Tarray)
+ {
+ if (tp2->implicitConvTo(tp1))
+ goto Lcov;
+ }
+ else if (tp1->ty == Tdelegate)
+ {
+ if (tp1->implicitConvTo(tp2))
+ goto Lcov;
+ }
+ }
+ goto Ldistinct;
+ }
+ Lcov:
+ notcovariant |= !fparam1->isCovariant(t1->isref, fparam2);
+ }
+ }
+ else if (t1->parameters != t2->parameters)
+ {
+ size_t dim1 = !t1->parameters ? 0 : t1->parameters->dim;
+ size_t dim2 = !t2->parameters ? 0 : t2->parameters->dim;
+ if (dim1 || dim2)
+ goto Ldistinct;
+ }
+
+ // The argument lists match
+ if (notcovariant)
+ goto Lnotcovariant;
+ if (t1->linkage != t2->linkage)
+ goto Lnotcovariant;
+
+ {
+ // Return types
+ Type *t1n = t1->next;
+ Type *t2n = t2->next;
+
+ if (!t1n || !t2n) // happens with return type inference
+ goto Lnotcovariant;
+
+ if (t1n->equals(t2n))
+ goto Lcovariant;
+ if (t1n->ty == Tclass && t2n->ty == Tclass)
+ {
+ /* If same class type, but t2n is const, then it's
+ * covariant. Do this test first because it can work on
+ * forward references.
+ */
+ if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym &&
+ MODimplicitConv(t1n->mod, t2n->mod))
+ goto Lcovariant;
+
+ // If t1n is forward referenced:
+ ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
+ if (cd->_scope)
+ cd->semantic(NULL);
+ if (!cd->isBaseInfoComplete())
+ {
+ return 3; // forward references
+ }
+ }
+ if (t1n->ty == Tstruct && t2n->ty == Tstruct)
+ {
+ if (((TypeStruct *)t1n)->sym == ((TypeStruct *)t2n)->sym &&
+ MODimplicitConv(t1n->mod, t2n->mod))
+ goto Lcovariant;
+ }
+ else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n))
+ goto Lcovariant;
+ else if (t1n->ty == Tnull && t1n->implicitConvTo(t2n) &&
+ t1n->size() == t2n->size())
+ goto Lcovariant;
+ }
+ goto Lnotcovariant;
+
+Lcovariant:
+ if (t1->isref != t2->isref)
+ goto Lnotcovariant;
+
+ if (!t1->isref && (t1->isscope || t2->isscope))
+ {
+ StorageClass stc1 = t1->isscope ? STCscope : 0;
+ StorageClass stc2 = t2->isscope ? STCscope : 0;
+ if (t1->isreturn)
+ {
+ stc1 |= STCreturn;
+ if (!t1->isscope)
+ stc1 |= STCref;
+ }
+ if (t2->isreturn)
+ {
+ stc2 |= STCreturn;
+ if (!t2->isscope)
+ stc2 |= STCref;
+ }
+ if (!Parameter::isCovariantScope(t1->isref, stc1, stc2))
+ goto Lnotcovariant;
+ }
+
+ // We can subtract 'return ref' from 'this', but cannot add it
+ else if (t1->isreturn && !t2->isreturn)
+ goto Lnotcovariant;
+
+ /* Can convert mutable to const
+ */
+ if (!MODimplicitConv(t2->mod, t1->mod))
+ {
+ goto Ldistinct;
+ }
+
+ /* Can convert pure to impure, nothrow to throw, and nogc to gc
+ */
+ if (!t1->purity && t2->purity)
+ stc |= STCpure;
+
+ if (!t1->isnothrow && t2->isnothrow)
+ stc |= STCnothrow;
+
+ if (!t1->isnogc && t2->isnogc)
+ stc |= STCnogc;
+
+ /* Can convert safe/trusted to system
+ */
+ if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted)
+ {
+ // Should we infer trusted or safe? Go with safe.
+ stc |= STCsafe;
+ }
+
+ if (stc)
+ { if (pstc)
+ *pstc = stc;
+ goto Lnotcovariant;
+ }
+
+ //printf("\tcovaraint: 1\n");
+ return 1;
+
+Ldistinct:
+ //printf("\tcovaraint: 0\n");
+ return 0;
+
+Lnotcovariant:
+ //printf("\tcovaraint: 2\n");
+ return 2;
+}
+
+Type *TypeFunction::semantic(Loc loc, Scope *sc)
+{
+ if (deco) // if semantic() already run
+ {
+ //printf("already done\n");
+ return this;
+ }
+ //printf("TypeFunction::semantic() this = %p\n", this);
+ //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs);
+
+ bool errors = false;
+
+ /* Copy in order to not mess up original.
+ * This can produce redundant copies if inferring return type,
+ * as semantic() will get called again on this.
+ */
+ TypeFunction *tf = (TypeFunction *)copy();
+ if (parameters)
+ {
+ tf->parameters = parameters->copy();
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ void *pp = mem.xmalloc(sizeof(Parameter));
+ Parameter *p = (Parameter *)memcpy(pp, (void *)(*parameters)[i], sizeof(Parameter));
+ (*tf->parameters)[i] = p;
+ }
+ }
+
+ if (sc->stc & STCpure)
+ tf->purity = PUREfwdref;
+ if (sc->stc & STCnothrow)
+ tf->isnothrow = true;
+ if (sc->stc & STCnogc)
+ tf->isnogc = true;
+ if (sc->stc & STCref)
+ tf->isref = true;
+ if (sc->stc & STCreturn)
+ tf->isreturn = true;
+ if (sc->stc & STCscope)
+ tf->isscope = true;
+ if (sc->stc & STCscopeinferred)
+ tf->isscopeinferred = true;
+
+// if ((sc->stc & (STCreturn | STCref)) == STCreturn)
+// tf->isscope = true; // return by itself means 'return scope'
+
+ if (tf->trust == TRUSTdefault)
+ {
+ if (sc->stc & STCsafe)
+ tf->trust = TRUSTsafe;
+ if (sc->stc & STCsystem)
+ tf->trust = TRUSTsystem;
+ if (sc->stc & STCtrusted)
+ tf->trust = TRUSTtrusted;
+ }
+
+ if (sc->stc & STCproperty)
+ tf->isproperty = true;
+
+ tf->linkage = sc->linkage;
+ bool wildreturn = false;
+ if (tf->next)
+ {
+ sc = sc->push();
+ sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
+ tf->next = tf->next->semantic(loc, sc);
+ sc = sc->pop();
+ errors |= tf->checkRetType(loc);
+ if (tf->next->isscope() && !(sc->flags & SCOPEctor))
+ {
+ error(loc, "functions cannot return scope %s", tf->next->toChars());
+ errors = true;
+ }
+ if (tf->next->hasWild())
+ wildreturn = true;
+
+ if (tf->isreturn && !tf->isref && !tf->next->hasPointers())
+ {
+ error(loc, "function type '%s' has 'return' but does not return any indirections", tf->toChars());
+ }
+ }
+
+ unsigned char wildparams = 0;
+ if (tf->parameters)
+ {
+ /* Create a scope for evaluating the default arguments for the parameters
+ */
+ Scope *argsc = sc->push();
+ argsc->stc = 0; // don't inherit storage class
+ argsc->protection = Prot(PROTpublic);
+ argsc->func = NULL;
+
+ size_t dim = Parameter::dim(tf->parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam = Parameter::getNth(tf->parameters, i);
+ tf->inuse++;
+ fparam->type = fparam->type->semantic(loc, argsc);
+ if (tf->inuse == 1) tf->inuse--;
+
+ if (fparam->type->ty == Terror)
+ {
+ errors = true;
+ continue;
+ }
+
+ fparam->type = fparam->type->addStorageClass(fparam->storageClass);
+
+ if (fparam->storageClass & (STCauto | STCalias | STCstatic))
+ {
+ if (!fparam->type)
+ continue;
+ }
+
+ Type *t = fparam->type->toBasetype();
+
+ if (t->ty == Tfunction)
+ {
+ error(loc, "cannot have parameter of function type %s", fparam->type->toChars());
+ errors = true;
+ }
+ else if (!(fparam->storageClass & (STCref | STCout)) &&
+ (t->ty == Tstruct || t->ty == Tsarray || t->ty == Tenum))
+ {
+ Type *tb2 = t->baseElemOf();
+ if ((tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members) ||
+ (tb2->ty == Tenum && !((TypeEnum *)tb2)->sym->memtype))
+ {
+ error(loc, "cannot have parameter of opaque type %s by value", fparam->type->toChars());
+ errors = true;
+ }
+ }
+ else if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
+ {
+ error(loc, "cannot have parameter of type %s", fparam->type->toChars());
+ errors = true;
+ }
+
+ if ((fparam->storageClass & (STCref | STCwild)) == (STCref | STCwild))
+ {
+ // 'ref inout' implies 'return'
+ fparam->storageClass |= STCreturn;
+ }
+
+ if (fparam->storageClass & STCreturn)
+ {
+ if (fparam->storageClass & (STCref | STCout))
+ {
+ // Disabled for the moment awaiting improvement to allow return by ref
+ // to be transformed into return by scope.
+ if (0 && !tf->isref)
+ {
+ StorageClass stc = fparam->storageClass & (STCref | STCout);
+ error(loc, "parameter %s is 'return %s' but function does not return by ref",
+ fparam->ident ? fparam->ident->toChars() : "",
+ stcToChars(stc));
+ errors = true;
+ }
+ }
+ else
+ {
+ fparam->storageClass |= STCscope; // 'return' implies 'scope'
+ if (tf->isref)
+ {
+ }
+ else if (!tf->isref && tf->next && !tf->next->hasPointers())
+ {
+ error(loc, "parameter %s is 'return' but function does not return any indirections",
+ fparam->ident ? fparam->ident->toChars() : "");
+ errors = true;
+ }
+ }
+ }
+
+ if (fparam->storageClass & (STCref | STClazy))
+ {
+ }
+ else if (fparam->storageClass & STCout)
+ {
+ if (unsigned char m = fparam->type->mod & (MODimmutable | MODconst | MODwild))
+ {
+ error(loc, "cannot have %s out parameter of type %s", MODtoChars(m), t->toChars());
+ errors = true;
+ }
+ else
+ {
+ Type *tv = t;
+ while (tv->ty == Tsarray)
+ tv = tv->nextOf()->toBasetype();
+ if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->noDefaultCtor)
+ {
+ error(loc, "cannot have out parameter of type %s because the default construction is disabled",
+ fparam->type->toChars());
+ errors = true;
+ }
+ }
+ }
+
+ if (fparam->storageClass & STCscope && !fparam->type->hasPointers() && fparam->type->ty != Ttuple)
+ {
+ fparam->storageClass &= ~STCscope;
+ if (!(fparam->storageClass & STCref))
+ fparam->storageClass &= ~STCreturn;
+ }
+
+ if (t->hasWild())
+ {
+ wildparams |= 1;
+ //if (tf->next && !wildreturn)
+ // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')");
+ }
+
+ if (fparam->defaultArg)
+ {
+ Expression *e = fparam->defaultArg;
+ if (fparam->storageClass & (STCref | STCout))
+ {
+ e = ::semantic(e, argsc);
+ e = resolveProperties(argsc, e);
+ }
+ else
+ {
+ e = inferType(e, fparam->type);
+ Initializer *iz = new ExpInitializer(e->loc, e);
+ iz = ::semantic(iz, argsc, fparam->type, INITnointerpret);
+ e = initializerToExpression(iz);
+ }
+ if (e->op == TOKfunction) // see Bugzilla 4820
+ {
+ FuncExp *fe = (FuncExp *)e;
+ // Replace function literal with a function symbol,
+ // since default arg expression must be copied when used
+ // and copying the literal itself is wrong.
+ e = new VarExp(e->loc, fe->fd, false);
+ e = new AddrExp(e->loc, e);
+ e = ::semantic(e, argsc);
+ }
+ e = e->implicitCastTo(argsc, fparam->type);
+
+ // default arg must be an lvalue
+ if (fparam->storageClass & (STCout | STCref))
+ e = e->toLvalue(argsc, e);
+
+ fparam->defaultArg = e;
+ if (e->op == TOKerror)
+ errors = true;
+ }
+
+ /* If fparam after semantic() turns out to be a tuple, the number of parameters may
+ * change.
+ */
+ if (t->ty == Ttuple)
+ {
+ /* TypeFunction::parameter also is used as the storage of
+ * Parameter objects for FuncDeclaration. So we should copy
+ * the elements of TypeTuple::arguments to avoid unintended
+ * sharing of Parameter object among other functions.
+ */
+ TypeTuple *tt = (TypeTuple *)t;
+ if (tt->arguments && tt->arguments->dim)
+ {
+ /* Propagate additional storage class from tuple parameters to their
+ * element-parameters.
+ * Make a copy, as original may be referenced elsewhere.
+ */
+ size_t tdim = tt->arguments->dim;
+ Parameters *newparams = new Parameters();
+ newparams->setDim(tdim);
+ for (size_t j = 0; j < tdim; j++)
+ {
+ Parameter *narg = (*tt->arguments)[j];
+
+ // Bugzilla 12744: If the storage classes of narg
+ // conflict with the ones in fparam, it's ignored.
+ StorageClass stc = fparam->storageClass | narg->storageClass;
+ StorageClass stc1 = fparam->storageClass & (STCref | STCout | STClazy);
+ StorageClass stc2 = narg->storageClass & (STCref | STCout | STClazy);
+ if (stc1 && stc2 && stc1 != stc2)
+ {
+ OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STCref) ? (fparam->storageClass & STCauto) : 0));
+ OutBuffer buf2; stcToBuffer(&buf2, stc2);
+
+ error(loc, "incompatible parameter storage classes '%s' and '%s'",
+ buf1.peekString(), buf2.peekString());
+ errors = true;
+ stc = stc1 | (stc & ~(STCref | STCout | STClazy));
+ }
+
+ (*newparams)[j] = new Parameter(
+ stc, narg->type, narg->ident, narg->defaultArg);
+ }
+ fparam->type = new TypeTuple(newparams);
+ }
+ fparam->storageClass = 0;
+
+ /* Reset number of parameters, and back up one to do this fparam again,
+ * now that it is a tuple
+ */
+ dim = Parameter::dim(tf->parameters);
+ i--;
+ continue;
+ }
+
+ /* Resolve "auto ref" storage class to be either ref or value,
+ * based on the argument matching the parameter
+ */
+ if (fparam->storageClass & STCauto)
+ {
+ if (fargs && i < fargs->dim && (fparam->storageClass & STCref))
+ {
+ Expression *farg = (*fargs)[i];
+ if (farg->isLvalue())
+ ; // ref parameter
+ else
+ fparam->storageClass &= ~STCref; // value parameter
+ fparam->storageClass &= ~STCauto; // Bugzilla 14656
+ fparam->storageClass |= STCautoref;
+ }
+ else
+ {
+ error(loc, "'auto' can only be used as part of 'auto ref' for template function parameters");
+ errors = true;
+ }
+ }
+
+ // Remove redundant storage classes for type, they are already applied
+ fparam->storageClass &= ~(STC_TYPECTOR | STCin);
+ }
+ argsc->pop();
+ }
+ if (tf->isWild())
+ wildparams |= 2;
+
+ if (wildreturn && !wildparams)
+ {
+ error(loc, "inout on return means inout must be on a parameter as well for %s", toChars());
+ errors = true;
+ }
+ tf->iswild = wildparams;
+
+ if (tf->inuse)
+ {
+ error(loc, "recursive type");
+ tf->inuse = 0;
+ errors = true;
+ }
+
+ if (tf->isproperty && (tf->varargs || Parameter::dim(tf->parameters) > 2))
+ {
+ error(loc, "properties can only have zero, one, or two parameter");
+ errors = true;
+ }
+
+ if (tf->varargs == 1 && tf->linkage != LINKd && Parameter::dim(tf->parameters) == 0)
+ {
+ error(loc, "variadic functions with non-D linkage must have at least one parameter");
+ errors = true;
+ }
+
+ if (errors)
+ return terror;
+
+ if (tf->next)
+ tf->deco = tf->merge()->deco;
+
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ return tf;
+}
+
+bool TypeFunction::checkRetType(Loc loc)
+{
+ Type *tb = next->toBasetype();
+ if (tb->ty == Tfunction)
+ {
+ error(loc, "functions cannot return a function");
+ next = Type::terror;
+ }
+ if (tb->ty == Ttuple)
+ {
+ error(loc, "functions cannot return a tuple");
+ next = Type::terror;
+ }
+ if (!isref && (tb->ty == Tstruct || tb->ty == Tsarray))
+ {
+ Type *tb2 = tb->baseElemOf();
+ if (tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members)
+ {
+ error(loc, "functions cannot return opaque type %s by value", tb->toChars());
+ next = Type::terror;
+ }
+ }
+ if (tb->ty == Terror)
+ return true;
+
+ return false;
+}
+
+/* Determine purity level based on mutability of t
+ * and whether it is a 'ref' type or not.
+ */
+static PURE purityOfType(bool isref, Type *t)
+{
+ if (isref)
+ {
+ if (t->mod & MODimmutable)
+ return PUREstrong;
+ if (t->mod & (MODconst | MODwild))
+ return PUREconst;
+ return PUREweak;
+ }
+
+ t = t->baseElemOf();
+
+ if (!t->hasPointers() || t->mod & MODimmutable)
+ return PUREstrong;
+
+ /* Accept immutable(T)[] and immutable(T)* as being strongly pure
+ */
+ if (t->ty == Tarray || t->ty == Tpointer)
+ {
+ Type *tn = t->nextOf()->toBasetype();
+ if (tn->mod & MODimmutable)
+ return PUREstrong;
+ if (tn->mod & (MODconst | MODwild))
+ return PUREconst;
+ }
+
+ /* The rest of this is too strict; fix later.
+ * For example, the only pointer members of a struct may be immutable,
+ * which would maintain strong purity.
+ * (Just like for dynamic arrays and pointers above.)
+ */
+ if (t->mod & (MODconst | MODwild))
+ return PUREconst;
+
+ /* Should catch delegates and function pointers, and fold in their purity
+ */
+ return PUREweak;
+}
+
+/********************************************
+ * Set 'purity' field of 'this'.
+ * Do this lazily, as the parameter types might be forward referenced.
+ */
+void TypeFunction::purityLevel()
+{
+ TypeFunction *tf = this;
+ if (tf->purity != PUREfwdref)
+ return;
+
+ purity = PUREstrong; // assume strong until something weakens it
+
+ /* Evaluate what kind of purity based on the modifiers for the parameters
+ */
+ const size_t dim = Parameter::dim(tf->parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam = Parameter::getNth(tf->parameters, i);
+ Type *t = fparam->type;
+ if (!t)
+ continue;
+
+ if (fparam->storageClass & (STClazy | STCout))
+ {
+ purity = PUREweak;
+ break;
+ }
+ switch (purityOfType((fparam->storageClass & STCref) != 0, t))
+ {
+ case PUREweak:
+ purity = PUREweak;
+ break;
+
+ case PUREconst:
+ purity = PUREconst;
+ continue;
+
+ case PUREstrong:
+ continue;
+
+ default:
+ assert(0);
+ }
+ break; // since PUREweak, no need to check further
+ }
+
+ if (purity > PUREweak && tf->nextOf())
+ {
+ /* Adjust purity based on mutability of return type.
+ * https://issues.dlang.org/show_bug.cgi?id=15862
+ */
+ const PURE purity2 = purityOfType(tf->isref, tf->nextOf());
+ if (purity2 < purity)
+ purity = purity2;
+ }
+ tf->purity = purity;
+}
+
+/********************************
+ * 'args' are being matched to function 'this'
+ * Determine match level.
+ * Input:
+ * flag 1 performing a partial ordering match
+ * Returns:
+ * MATCHxxxx
+ */
+
+MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
+{
+ //printf("TypeFunction::callMatch() %s\n", toChars());
+ MATCH match = MATCHexact; // assume exact match
+ unsigned char wildmatch = 0;
+
+ if (tthis)
+ {
+ Type *t = tthis;
+ if (t->toBasetype()->ty == Tpointer)
+ t = t->toBasetype()->nextOf(); // change struct* to struct
+ if (t->mod != mod)
+ {
+ if (MODimplicitConv(t->mod, mod))
+ match = MATCHconst;
+ else if ((mod & MODwild) && MODimplicitConv(t->mod, (mod & ~MODwild) | MODconst))
+ {
+ match = MATCHconst;
+ }
+ else
+ return MATCHnomatch;
+ }
+ if (isWild())
+ {
+ if (t->isWild())
+ wildmatch |= MODwild;
+ else if (t->isConst())
+ wildmatch |= MODconst;
+ else if (t->isImmutable())
+ wildmatch |= MODimmutable;
+ else
+ wildmatch |= MODmutable;
+ }
+ }
+
+ size_t nparams = Parameter::dim(parameters);
+ size_t nargs = args ? args->dim : 0;
+ if (nparams == nargs)
+ ;
+ else if (nargs > nparams)
+ {
+ if (varargs == 0)
+ goto Nomatch; // too many args; no match
+ match = MATCHconvert; // match ... with a "conversion" match level
+ }
+
+ for (size_t u = 0; u < nargs; u++)
+ {
+ if (u >= nparams)
+ break;
+ Parameter *p = Parameter::getNth(parameters, u);
+ Expression *arg = (*args)[u];
+ assert(arg);
+ Type *tprm = p->type;
+ Type *targ = arg->type;
+
+ if (!(p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid))
+ {
+ bool isRef = (p->storageClass & (STCref | STCout)) != 0;
+ wildmatch |= targ->deduceWild(tprm, isRef);
+ }
+ }
+ if (wildmatch)
+ {
+ /* Calculate wild matching modifier
+ */
+ if (wildmatch & MODconst || wildmatch & (wildmatch - 1))
+ wildmatch = MODconst;
+ else if (wildmatch & MODimmutable)
+ wildmatch = MODimmutable;
+ else if (wildmatch & MODwild)
+ wildmatch = MODwild;
+ else
+ {
+ assert(wildmatch & MODmutable);
+ wildmatch = MODmutable;
+ }
+ }
+
+ for (size_t u = 0; u < nparams; u++)
+ {
+ MATCH m;
+
+ Parameter *p = Parameter::getNth(parameters, u);
+ assert(p);
+ if (u >= nargs)
+ {
+ if (p->defaultArg)
+ continue;
+ goto L1; // try typesafe variadics
+ }
+ {
+ Expression *arg = (*args)[u];
+ assert(arg);
+ //printf("arg: %s, type: %s\n", arg->toChars(), arg->type->toChars());
+
+ Type *targ = arg->type;
+ Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type;
+
+ if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid)
+ m = MATCHconvert;
+ else
+ {
+ //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars());
+ if (flag)
+ {
+ // for partial ordering, value is an irrelevant mockup, just look at the type
+ m = targ->implicitConvTo(tprm);
+ }
+ else
+ m = arg->implicitConvTo(tprm);
+ //printf("match %d\n", m);
+ }
+
+ // Non-lvalues do not match ref or out parameters
+ if (p->storageClass & (STCref | STCout))
+ {
+ // Bugzilla 13783: Don't use toBasetype() to handle enum types.
+ Type *ta = targ;
+ Type *tp = tprm;
+ //printf("fparam[%d] ta = %s, tp = %s\n", u, ta->toChars(), tp->toChars());
+
+ if (m && !arg->isLvalue())
+ {
+ if (p->storageClass & STCout)
+ goto Nomatch;
+
+ if (arg->op == TOKstring && tp->ty == Tsarray)
+ {
+ if (ta->ty != Tsarray)
+ {
+ Type *tn = tp->nextOf()->castMod(ta->nextOf()->mod);
+ dinteger_t dim = ((StringExp *)arg)->len;
+ ta = tn->sarrayOf(dim);
+ }
+ }
+ else if (arg->op == TOKslice && tp->ty == Tsarray)
+ {
+ // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+ if (ta->ty != Tsarray)
+ {
+ Type *tn = ta->nextOf();
+ dinteger_t dim = ((TypeSArray *)tp)->dim->toUInteger();
+ ta = tn->sarrayOf(dim);
+ }
+ }
+ else
+ goto Nomatch;
+ }
+
+ /* Find most derived alias this type being matched.
+ * Bugzilla 15674: Allow on both ref and out parameters.
+ */
+ while (1)
+ {
+ Type *tat = ta->toBasetype()->aliasthisOf();
+ if (!tat || !tat->implicitConvTo(tprm))
+ break;
+ ta = tat;
+ }
+
+ /* A ref variable should work like a head-const reference.
+ * e.g. disallows:
+ * ref T <- an lvalue of const(T) argument
+ * ref T[dim] <- an lvalue of const(T[dim]) argument
+ */
+ if (!ta->constConv(tp))
+ goto Nomatch;
+ }
+ }
+
+ /* prefer matching the element type rather than the array
+ * type when more arguments are present with T[]...
+ */
+ if (varargs == 2 && u + 1 == nparams && nargs > nparams)
+ goto L1;
+
+ //printf("\tm = %d\n", m);
+ if (m == MATCHnomatch) // if no match
+ {
+ L1:
+ if (varargs == 2 && u + 1 == nparams) // if last varargs param
+ {
+ Type *tb = p->type->toBasetype();
+ TypeSArray *tsa;
+ dinteger_t sz;
+
+ switch (tb->ty)
+ {
+ case Tsarray:
+ tsa = (TypeSArray *)tb;
+ sz = tsa->dim->toInteger();
+ if (sz != nargs - u)
+ goto Nomatch;
+ /* fall through */
+ case Tarray:
+ {
+ TypeArray *ta = (TypeArray *)tb;
+ for (; u < nargs; u++)
+ {
+ Expression *arg = (*args)[u];
+ assert(arg);
+
+ /* If lazy array of delegates,
+ * convert arg(s) to delegate(s)
+ */
+ Type *tret = p->isLazyArray();
+ if (tret)
+ {
+ if (ta->next->equals(arg->type))
+ m = MATCHexact;
+ else if (tret->toBasetype()->ty == Tvoid)
+ m = MATCHconvert;
+ else
+ {
+ m = arg->implicitConvTo(tret);
+ if (m == MATCHnomatch)
+ m = arg->implicitConvTo(ta->next);
+ }
+ }
+ else
+ m = arg->implicitConvTo(ta->next);
+
+ if (m == MATCHnomatch)
+ goto Nomatch;
+ if (m < match)
+ match = m;
+ }
+ goto Ldone;
+ }
+ case Tclass:
+ // Should see if there's a constructor match?
+ // Or just leave it ambiguous?
+ goto Ldone;
+
+ default:
+ goto Nomatch;
+ }
+ }
+ goto Nomatch;
+ }
+ if (m < match)
+ match = m; // pick worst match
+ }
+
+Ldone:
+ //printf("match = %d\n", match);
+ return match;
+
+Nomatch:
+ //printf("no match\n");
+ return MATCHnomatch;
+}
+
+/********************************************
+ * Return true if there are lazy parameters.
+ */
+bool TypeFunction::hasLazyParameters()
+{
+ size_t dim = Parameter::dim(parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam = Parameter::getNth(parameters, i);
+ if (fparam->storageClass & STClazy)
+ return true;
+ }
+ return false;
+}
+
+/***************************
+ * Examine function signature for parameter p and see if
+ * the value of p can 'escape' the scope of the function.
+ * This is useful to minimize the needed annotations for the parameters.
+ * Params:
+ * p = parameter to this function
+ * Returns:
+ * true if escapes via assignment to global or through a parameter
+ */
+
+bool TypeFunction::parameterEscapes(Parameter *p)
+{
+ /* Scope parameters do not escape.
+ * Allow 'lazy' to imply 'scope' -
+ * lazy parameters can be passed along
+ * as lazy parameters to the next function, but that isn't
+ * escaping.
+ */
+ if (parameterStorageClass(p) & (STCscope | STClazy))
+ return false;
+ return true;
+}
+
+/************************************
+ * Take the specified storage class for p,
+ * and use the function signature to infer whether
+ * STCscope and STCreturn should be OR'd in.
+ * (This will not affect the name mangling.)
+ * Params:
+ * p = one of the parameters to 'this'
+ * Returns:
+ * storage class with STCscope or STCreturn OR'd in
+ */
+StorageClass TypeFunction::parameterStorageClass(Parameter *p)
+{
+ StorageClass stc = p->storageClass;
+ if (!global.params.vsafe)
+ return stc;
+
+ if (stc & (STCscope | STCreturn | STClazy) || purity == PUREimpure)
+ return stc;
+
+ /* If haven't inferred the return type yet, can't infer storage classes
+ */
+ if (!nextOf())
+ return stc;
+
+ purityLevel();
+
+ // See if p can escape via any of the other parameters
+ if (purity == PUREweak)
+ {
+ const size_t dim = Parameter::dim(parameters);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *fparam = Parameter::getNth(parameters, i);
+ Type *t = fparam->type;
+ if (!t)
+ continue;
+ t = t->baseElemOf();
+ if (t->isMutable() && t->hasPointers())
+ {
+ if (fparam->storageClass & (STCref | STCout))
+ {
+ }
+ else if (t->ty == Tarray || t->ty == Tpointer)
+ {
+ Type *tn = t->nextOf()->toBasetype();
+ if (!(tn->isMutable() && tn->hasPointers()))
+ continue;
+ }
+ return stc;
+ }
+ }
+ }
+
+ stc |= STCscope;
+
+ /* Inferring STCreturn here has false positives
+ * for pure functions, producing spurious error messages
+ * about escaping references.
+ * Give up on it for now.
+ */
+ return stc;
+}
+
+Expression *TypeFunction::defaultInit(Loc loc)
+{
+ error(loc, "function does not have a default initializer");
+ return new ErrorExp();
+}
+
+Type *TypeFunction::addStorageClass(StorageClass stc)
+{
+ //printf("addStorageClass(%llx) %d\n", stc, (stc & STCscope) != 0);
+ TypeFunction *t = (TypeFunction *)Type::addStorageClass(stc);
+ if ((stc & STCpure && !t->purity) ||
+ (stc & STCnothrow && !t->isnothrow) ||
+ (stc & STCnogc && !t->isnogc) ||
+ (stc & STCscope && !t->isscope) ||
+ (stc & STCsafe && t->trust < TRUSTtrusted))
+ {
+ // Klunky to change these
+ TypeFunction *tf = new TypeFunction(t->parameters, t->next, t->varargs, t->linkage, 0);
+ tf->mod = t->mod;
+ tf->fargs = fargs;
+ tf->purity = t->purity;
+ tf->isnothrow = t->isnothrow;
+ tf->isnogc = t->isnogc;
+ tf->isproperty = t->isproperty;
+ tf->isref = t->isref;
+ tf->isreturn = t->isreturn;
+ tf->isscope = t->isscope;
+ tf->isscopeinferred = t->isscopeinferred;
+ tf->trust = t->trust;
+ tf->iswild = t->iswild;
+
+ if (stc & STCpure)
+ tf->purity = PUREfwdref;
+ if (stc & STCnothrow)
+ tf->isnothrow = true;
+ if (stc & STCnogc)
+ tf->isnogc = true;
+ if (stc & STCsafe)
+ tf->trust = TRUSTsafe;
+ if (stc & STCscope)
+ {
+ tf->isscope = true;
+ if (stc & STCscopeinferred)
+ tf->isscopeinferred = true;
+ }
+
+ tf->deco = tf->merge()->deco;
+ t = tf;
+ }
+ return t;
+}
+
+/** For each active attribute (ref/const/nogc/etc) call fp with a void* for the
+work param and a string representation of the attribute. */
+int TypeFunction::attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat)
+{
+ int res = 0;
+
+ if (purity) res = fp(param, "pure");
+ if (res) return res;
+
+ if (isnothrow) res = fp(param, "nothrow");
+ if (res) return res;
+
+ if (isnogc) res = fp(param, "@nogc");
+ if (res) return res;
+
+ if (isproperty) res = fp(param, "@property");
+ if (res) return res;
+
+ if (isref) res = fp(param, "ref");
+ if (res) return res;
+
+ if (isreturn) res = fp(param, "return");
+ if (res) return res;
+
+ if (isscope && !isscopeinferred) res = fp(param, "scope");
+ if (res) return res;
+
+ TRUST trustAttrib = trust;
+
+ if (trustAttrib == TRUSTdefault)
+ {
+ // Print out "@system" when trust equals TRUSTdefault (if desired).
+ if (trustFormat == TRUSTformatSystem)
+ trustAttrib = TRUSTsystem;
+ else
+ return res; // avoid calling with an empty string
+ }
+
+ return fp(param, trustToChars(trustAttrib));
+}
+
+/***************************** TypeDelegate *****************************/
+
+TypeDelegate::TypeDelegate(Type *t)
+ : TypeNext(Tfunction, t)
+{
+ ty = Tdelegate;
+}
+
+TypeDelegate *TypeDelegate::create(Type *t)
+{
+ return new TypeDelegate(t);
+}
+
+const char *TypeDelegate::kind()
+{
+ return "delegate";
+}
+
+Type *TypeDelegate::syntaxCopy()
+{
+ Type *t = next->syntaxCopy();
+ if (t == next)
+ t = this;
+ else
+ {
+ t = new TypeDelegate(t);
+ t->mod = mod;
+ }
+ return t;
+}
+
+Type *TypeDelegate::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypeDelegate::semantic() %s\n", toChars());
+ if (deco) // if semantic() already run
+ {
+ //printf("already done\n");
+ return this;
+ }
+ next = next->semantic(loc,sc);
+ if (next->ty != Tfunction)
+ return terror;
+
+ /* In order to deal with Bugzilla 4028, perhaps default arguments should
+ * be removed from next before the merge.
+ */
+
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ deco = merge()->deco;
+ return this;
+}
+
+Type *TypeDelegate::addStorageClass(StorageClass stc)
+{
+ TypeDelegate *t = (TypeDelegate*)Type::addStorageClass(stc);
+ if (!global.params.vsafe)
+ return t;
+
+ /* The rest is meant to add 'scope' to a delegate declaration if it is of the form:
+ * alias dg_t = void* delegate();
+ * scope dg_t dg = ...;
+ */
+ if(stc & STCscope)
+ {
+ Type *n = t->next->addStorageClass(STCscope | STCscopeinferred);
+ if (n != t->next)
+ {
+ t->next = n;
+ t->deco = t->merge()->deco; // mangling supposed to not be changed due to STCscopeinferrred
+ }
+ }
+ return t;
+}
+
+d_uns64 TypeDelegate::size(Loc)
+{
+ return Target::ptrsize * 2;
+}
+
+unsigned TypeDelegate::alignsize()
+{
+ return Target::ptrsize;
+}
+
+MATCH TypeDelegate::implicitConvTo(Type *to)
+{
+ //printf("TypeDelegate::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to->toChars());
+ if (this == to)
+ return MATCHexact;
+#if 1 // not allowing covariant conversions because it interferes with overriding
+ if (to->ty == Tdelegate && this->nextOf()->covariant(to->nextOf()) == 1)
+ {
+ Type *tret = this->next->nextOf();
+ Type *toret = ((TypeDelegate *)to)->next->nextOf();
+ if (tret->ty == Tclass && toret->ty == Tclass)
+ {
+ /* Bugzilla 10219: Check covariant interface return with offset tweaking.
+ * interface I {}
+ * class C : Object, I {}
+ * I delegate() dg = delegate C() {} // should be error
+ */
+ int offset = 0;
+ if (toret->isBaseOf(tret, &offset) && offset != 0)
+ return MATCHnomatch;
+ }
+ return MATCHconvert;
+ }
+#endif
+ return MATCHnomatch;
+}
+
+Expression *TypeDelegate::defaultInit(Loc loc)
+{
+ return new NullExp(loc, this);
+}
+
+bool TypeDelegate::isZeroInit(Loc)
+{
+ return true;
+}
+
+bool TypeDelegate::isBoolean()
+{
+ return true;
+}
+
+Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ if (ident == Id::ptr)
+ {
+ e = new DelegatePtrExp(e->loc, e);
+ e = ::semantic(e, sc);
+ }
+ else if (ident == Id::funcptr)
+ {
+ if (!(flag & 2) && sc->func && !sc->intypeof && sc->func->setUnsafe())
+ {
+ e->error("%s.funcptr cannot be used in @safe code", e->toChars());
+ return new ErrorExp();
+ }
+ e = new DelegateFuncptrExp(e->loc, e);
+ e = ::semantic(e, sc);
+ }
+ else
+ {
+ e = Type::dotExp(sc, e, ident, flag);
+ }
+ return e;
+}
+
+bool TypeDelegate::hasPointers()
+{
+ return true;
+}
+
+
+
+/***************************** TypeQualified *****************************/
+
+TypeQualified::TypeQualified(TY ty, Loc loc)
+ : Type(ty)
+{
+ this->loc = loc;
+}
+
+void TypeQualified::syntaxCopyHelper(TypeQualified *t)
+{
+ //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars());
+ idents.setDim(t->idents.dim);
+ for (size_t i = 0; i < idents.dim; i++)
+ {
+ RootObject *id = t->idents[i];
+ if (id->dyncast() == DYNCAST_DSYMBOL)
+ {
+ TemplateInstance *ti = (TemplateInstance *)id;
+
+ ti = (TemplateInstance *)ti->syntaxCopy(NULL);
+ id = ti;
+ }
+ else if (id->dyncast() == DYNCAST_EXPRESSION)
+ {
+ Expression *e = (Expression *)id;
+ e = e->syntaxCopy();
+ id = e;
+ }
+ else if (id->dyncast() == DYNCAST_TYPE)
+ {
+ Type *tx = (Type *)id;
+ tx = tx->syntaxCopy();
+ id = tx;
+ }
+ idents[i] = id;
+ }
+}
+
+void TypeQualified::addIdent(Identifier *ident)
+{
+ idents.push(ident);
+}
+
+void TypeQualified::addInst(TemplateInstance *inst)
+{
+ idents.push(inst);
+}
+
+void TypeQualified::addIndex(RootObject *e)
+{
+ idents.push(e);
+}
+
+d_uns64 TypeQualified::size(Loc)
+{
+ error(this->loc, "size of type %s is not known", toChars());
+ return SIZE_INVALID;
+}
+
+/*************************************
+ * Resolve a tuple index.
+ */
+void TypeQualified::resolveTupleIndex(Loc loc, Scope *sc, Dsymbol *s,
+ Expression **pe, Type **pt, Dsymbol **ps, RootObject *oindex)
+{
+ *pt = NULL;
+ *ps = NULL;
+ *pe = NULL;
+
+ TupleDeclaration *td = s->isTupleDeclaration();
+
+ Expression *eindex = isExpression(oindex);
+ Type *tindex = isType(oindex);
+ Dsymbol *sindex = isDsymbol(oindex);
+
+ if (!td)
+ {
+ // It's really an index expression
+ if (tindex)
+ eindex = new TypeExp(loc, tindex);
+ else if (sindex)
+ eindex = ::resolve(loc, sc, sindex, false);
+ Expression *e = new IndexExp(loc, ::resolve(loc, sc, s, false), eindex);
+ e = ::semantic(e, sc);
+ resolveExp(e, pt, pe, ps);
+ return;
+ }
+
+ // Convert oindex to Expression, then try to resolve to constant.
+ if (tindex)
+ tindex->resolve(loc, sc, &eindex, &tindex, &sindex);
+ if (sindex)
+ eindex = ::resolve(loc, sc, sindex, false);
+ if (!eindex)
+ {
+ ::error(loc, "index is %s not an expression", oindex->toChars());
+ *pt = Type::terror;
+ return;
+ }
+ sc = sc->startCTFE();
+ eindex = ::semantic(eindex, sc);
+ sc = sc->endCTFE();
+
+ eindex = eindex->ctfeInterpret();
+ if (eindex->op == TOKerror)
+ {
+ *pt = Type::terror;
+ return;
+ }
+
+ const uinteger_t d = eindex->toUInteger();
+ if (d >= td->objects->dim)
+ {
+ ::error(loc, "tuple index %llu exceeds length %u", (ulonglong)d, (unsigned)td->objects->dim);
+ *pt = Type::terror;
+ return;
+ }
+
+ RootObject *o = (*td->objects)[(size_t)d];
+ *pt = isType(o);
+ *ps = isDsymbol(o);
+ *pe = isExpression(o);
+
+ if (*pt)
+ *pt = (*pt)->semantic(loc, sc);
+ if (*pe)
+ resolveExp(*pe, pt, pe, ps);
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ * if expression, *pe is set
+ * if type, *pt is set
+ */
+void TypeQualified::resolveHelper(Loc loc, Scope *sc,
+ Dsymbol *s, Dsymbol *,
+ Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ *pe = NULL;
+ *pt = NULL;
+ *ps = NULL;
+ if (s)
+ {
+ //printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+ Declaration *d = s->isDeclaration();
+ if (d && (d->storage_class & STCtemplateparameter))
+ s = s->toAlias();
+ else
+ s->checkDeprecated(loc, sc); // check for deprecated aliases
+
+ s = s->toAlias();
+ //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
+ for (size_t i = 0; i < idents.dim; i++)
+ {
+ RootObject *id = idents[i];
+
+ if (id->dyncast() == DYNCAST_EXPRESSION ||
+ id->dyncast() == DYNCAST_TYPE)
+ {
+ Type *tx;
+ Expression *ex;
+ Dsymbol *sx;
+ resolveTupleIndex(loc, sc, s, &ex, &tx, &sx, id);
+ if (sx)
+ {
+ s = sx->toAlias();
+ continue;
+ }
+ if (tx)
+ ex = new TypeExp(loc, tx);
+ assert(ex);
+
+ ex = typeToExpressionHelper(this, ex, i + 1);
+ ex = ::semantic(ex, sc);
+ resolveExp(ex, pt, pe, ps);
+ return;
+ }
+
+ Type *t = s->getType(); // type symbol, type alias, or type tuple?
+ unsigned errorsave = global.errors;
+ Dsymbol *sm = s->searchX(loc, sc, id);
+ if (sm && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+ {
+ ::deprecation(loc, "%s is not visible from module %s", sm->toPrettyChars(), sc->_module->toChars());
+ // sm = NULL;
+ }
+ if (global.errors != errorsave)
+ {
+ *pt = Type::terror;
+ return;
+ }
+ //printf("\t3: s = %p %s %s, sm = %p\n", s, s->kind(), s->toChars(), sm);
+ if (intypeid && !t && sm && sm->needThis())
+ goto L3;
+ if (VarDeclaration *v = s->isVarDeclaration())
+ {
+ if (v->storage_class & (STCconst | STCimmutable | STCmanifest) ||
+ v->type->isConst() || v->type->isImmutable())
+ {
+ // Bugzilla 13087: this.field is not constant always
+ if (!v->isThisDeclaration())
+ goto L3;
+ }
+ }
+ if (!sm)
+ {
+ if (!t)
+ {
+ if (s->isDeclaration()) // var, func, or tuple declaration?
+ {
+ t = s->isDeclaration()->type;
+ if (!t && s->isTupleDeclaration()) // expression tuple?
+ goto L3;
+ }
+ else if (s->isTemplateInstance() ||
+ s->isImport() || s->isPackage() || s->isModule())
+ {
+ goto L3;
+ }
+ }
+ if (t)
+ {
+ sm = t->toDsymbol(sc);
+ if (sm && id->dyncast() == DYNCAST_IDENTIFIER)
+ {
+ sm = sm->search(loc, (Identifier *)id);
+ if (sm)
+ goto L2;
+ }
+ L3:
+ Expression *e;
+ VarDeclaration *v = s->isVarDeclaration();
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (intypeid || (!v && !f))
+ e = ::resolve(loc, sc, s, true);
+ else
+ e = new VarExp(loc, s->isDeclaration(), true);
+
+ e = typeToExpressionHelper(this, e, i);
+ e = ::semantic(e, sc);
+ resolveExp(e, pt, pe, ps);
+ return;
+ }
+ else
+ {
+ if (id->dyncast() == DYNCAST_DSYMBOL)
+ {
+ // searchX already handles errors for template instances
+ assert(global.errors);
+ }
+ else
+ {
+ assert(id->dyncast() == DYNCAST_IDENTIFIER);
+ sm = s->search_correct((Identifier *)id);
+ if (sm)
+ error(loc, "identifier '%s' of '%s' is not defined, did you mean %s '%s'?",
+ id->toChars(), toChars(), sm->kind(), sm->toChars());
+ else
+ error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars());
+ }
+ *pe = new ErrorExp();
+ }
+ return;
+ }
+ L2:
+ s = sm->toAlias();
+ }
+
+ if (EnumMember *em = s->isEnumMember())
+ {
+ // It's not a type, it's an expression
+ *pe = em->getVarExp(loc, sc);
+ return;
+ }
+ if (VarDeclaration *v = s->isVarDeclaration())
+ {
+ /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
+ * because some variables used in type context need to prevent lowering
+ * to a literal or contextful expression. For example:
+ *
+ * enum a = 1; alias b = a;
+ * template X(alias e){ alias v = e; } alias x = X!(1);
+ * struct S { int v; alias w = v; }
+ * // TypeIdentifier 'a', 'e', and 'v' should be TOKvar,
+ * // because getDsymbol() need to work in AliasDeclaration::semantic().
+ */
+ if (!v->type ||
+ (!v->type->deco && v->inuse))
+ {
+ if (v->inuse) // Bugzilla 9494
+ error(loc, "circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ else
+ error(loc, "forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ *pt = Type::terror;
+ return;
+ }
+ if (v->type->ty == Terror)
+ *pt = Type::terror;
+ else
+ *pe = new VarExp(loc, v);
+ return;
+ }
+ if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
+ {
+ //printf("'%s' is a function literal\n", fld->toChars());
+ *pe = new FuncExp(loc, fld);
+ *pe = ::semantic(*pe, sc);
+ return;
+ }
+L1:
+ Type *t = s->getType();
+ if (!t)
+ {
+ // If the symbol is an import, try looking inside the import
+ if (Import *si = s->isImport())
+ {
+ s = si->search(loc, s->ident);
+ if (s && s != si)
+ goto L1;
+ s = si;
+ }
+ *ps = s;
+ return;
+ }
+ if (t->ty == Tinstance && t != this && !t->deco)
+ {
+ if (!((TypeInstance *)t)->tempinst->errors)
+ error(loc, "forward reference to '%s'", t->toChars());
+ *pt = Type::terror;
+ return;
+ }
+
+ if (t->ty == Ttuple)
+ *pt = t;
+ else
+ *pt = t->merge();
+ }
+ if (!s)
+ {
+ /* Look for what user might have intended
+ */
+ const char *p = mutableOf()->unSharedOf()->toChars();
+ Identifier *id = Identifier::idPool(p, strlen(p));
+ if (const char *n = importHint(p))
+ error(loc, "`%s` is not defined, perhaps `import %s;` ?", p, n);
+ else if (Dsymbol *s2 = sc->search_correct(id))
+ error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2->kind(), s2->toChars());
+ else if (const char *q = Scope::search_correct_C(id))
+ error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
+ else
+ error(loc, "undefined identifier `%s`", p);
+
+ *pt = Type::terror;
+ }
+}
+
+/***************************** TypeIdentifier *****************************/
+
+TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident)
+ : TypeQualified(Tident, loc)
+{
+ this->ident = ident;
+}
+
+const char *TypeIdentifier::kind()
+{
+ return "identifier";
+}
+
+Type *TypeIdentifier::syntaxCopy()
+{
+ TypeIdentifier *t = new TypeIdentifier(loc, ident);
+ t->syntaxCopyHelper(this);
+ t->mod = mod;
+ return t;
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ * if expression, *pe is set
+ * if type, *pt is set
+ */
+
+void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+
+ if ((ident->equals(Id::_super) || ident->equals(Id::This)) && !hasThis(sc))
+ {
+ AggregateDeclaration *ad = sc->getStructClassScope();
+ if (ad)
+ {
+ ClassDeclaration *cd = ad->isClassDeclaration();
+ if (cd)
+ {
+ if (ident->equals(Id::This))
+ ident = cd->ident;
+ else if (cd->baseClass && ident->equals(Id::_super))
+ ident = cd->baseClass->ident;
+ }
+ else
+ {
+ StructDeclaration *sd = ad->isStructDeclaration();
+ if (sd && ident->equals(Id::This))
+ ident = sd->ident;
+ }
+ }
+ }
+ if (ident == Id::ctfe)
+ {
+ error(loc, "variable __ctfe cannot be read at compile time");
+ *pe = NULL;
+ *ps = NULL;
+ *pt = Type::terror;
+ return;
+ }
+
+ Dsymbol *scopesym;
+ Dsymbol *s = sc->search(loc, ident, &scopesym);
+ resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
+ if (*pt)
+ (*pt) = (*pt)->addMod(mod);
+}
+
+/*****************************************
+ * See if type resolves to a symbol, if so,
+ * return that symbol.
+ */
+
+Dsymbol *TypeIdentifier::toDsymbol(Scope *sc)
+{
+ //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+ if (!sc)
+ return NULL;
+
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+
+ resolve(loc, sc, &e, &t, &s);
+ if (t && t->ty != Tident)
+ s = t->toDsymbol(sc);
+ if (e)
+ s = getDsymbol(e);
+
+ return s;
+}
+
+Type *TypeIdentifier::semantic(Loc loc, Scope *sc)
+{
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+
+ //printf("TypeIdentifier::semantic(%s)\n", toChars());
+ resolve(loc, sc, &e, &t, &s);
+ if (t)
+ {
+ //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
+ t = t->addMod(mod);
+ }
+ else
+ {
+ if (s)
+ {
+ s->error(loc, "is used as a type");
+ //halt();
+ }
+ else
+ error(loc, "%s is used as a type", toChars());
+ t = terror;
+ }
+ //t->print();
+ return t;
+}
+
+/***************************** TypeInstance *****************************/
+
+TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
+ : TypeQualified(Tinstance, loc)
+{
+ this->tempinst = tempinst;
+}
+
+const char *TypeInstance::kind()
+{
+ return "instance";
+}
+
+Type *TypeInstance::syntaxCopy()
+{
+ //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim);
+ TypeInstance *t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL));
+ t->syntaxCopyHelper(this);
+ t->mod = mod;
+ return t;
+}
+
+void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ // Note close similarity to TypeIdentifier::resolve()
+ *pe = NULL;
+ *pt = NULL;
+ *ps = NULL;
+ //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, tempinst->toChars());
+ tempinst->semantic(sc);
+ if (!global.gag && tempinst->errors)
+ {
+ *pt = terror;
+ return;
+ }
+
+ resolveHelper(loc, sc, tempinst, NULL, pe, pt, ps, intypeid);
+ if (*pt)
+ *pt = (*pt)->addMod(mod);
+ //if (*pt) printf("pt = '%s'\n", (*pt)->toChars());
+}
+
+Type *TypeInstance::semantic(Loc loc, Scope *sc)
+{
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+
+ //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
+ {
+ unsigned errors = global.errors;
+ resolve(loc, sc, &e, &t, &s);
+ // if we had an error evaluating the symbol, suppress further errors
+ if (!t && errors != global.errors)
+ return terror;
+ }
+
+ if (!t)
+ {
+ if (!e && s && s->errors)
+ {
+ // if there was an error evaluating the symbol, it might actually
+ // be a type. Avoid misleading error messages.
+ error(loc, "%s had previous errors", toChars());
+ }
+ else
+ error(loc, "%s is used as a type", toChars());
+ t = terror;
+ }
+ return t;
+}
+
+Dsymbol *TypeInstance::toDsymbol(Scope *sc)
+{
+ Type *t;
+ Expression *e;
+ Dsymbol *s;
+
+ //printf("TypeInstance::semantic(%s)\n", toChars());
+ resolve(loc, sc, &e, &t, &s);
+ if (t && t->ty != Tinstance)
+ s = t->toDsymbol(sc);
+
+ return s;
+}
+
+
+/***************************** TypeTypeof *****************************/
+
+TypeTypeof::TypeTypeof(Loc loc, Expression *exp)
+ : TypeQualified(Ttypeof, loc)
+{
+ this->exp = exp;
+ inuse = 0;
+}
+
+const char *TypeTypeof::kind()
+{
+ return "typeof";
+}
+
+Type *TypeTypeof::syntaxCopy()
+{
+ //printf("TypeTypeof::syntaxCopy() %s\n", toChars());
+ TypeTypeof *t = new TypeTypeof(loc, exp->syntaxCopy());
+ t->syntaxCopyHelper(this);
+ t->mod = mod;
+ return t;
+}
+
+Dsymbol *TypeTypeof::toDsymbol(Scope *sc)
+{
+ //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ resolve(loc, sc, &e, &t, &s);
+
+ return s;
+}
+
+void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ *pe = NULL;
+ *pt = NULL;
+ *ps = NULL;
+
+ //printf("TypeTypeof::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+ //static int nest; if (++nest == 50) *(char*)0=0;
+ if (inuse)
+ {
+ inuse = 2;
+ error(loc, "circular typeof definition");
+ Lerr:
+ *pt = Type::terror;
+ inuse--;
+ return;
+ }
+ inuse++;
+
+ Type *t;
+ {
+ /* Currently we cannot evalute 'exp' in speculative context, because
+ * the type implementation may leak to the final execution. Consider:
+ *
+ * struct S(T) {
+ * string toString() const { return "x"; }
+ * }
+ * void main() {
+ * alias X = typeof(S!int());
+ * assert(typeid(X).xtoString(null) == "x");
+ * }
+ */
+ Scope *sc2 = sc->push();
+ sc2->intypeof = 1;
+ Expression *exp2 = ::semantic(exp, sc2);
+ exp2 = resolvePropertiesOnly(sc2, exp2);
+ sc2->pop();
+
+ if (exp2->op == TOKerror)
+ {
+ if (!global.gag)
+ exp = exp2;
+ goto Lerr;
+ }
+ exp = exp2;
+
+ if (exp->op == TOKtype ||
+ exp->op == TOKscope)
+ {
+ if (exp->checkType())
+ goto Lerr;
+
+ /* Today, 'typeof(func)' returns void if func is a
+ * function template (TemplateExp), or
+ * template lambda (FuncExp).
+ * It's actually used in Phobos as an idiom, to branch code for
+ * template functions.
+ */
+ }
+ if (FuncDeclaration *f = exp->op == TOKvar ? (( VarExp *)exp)->var->isFuncDeclaration()
+ : exp->op == TOKdotvar ? ((DotVarExp *)exp)->var->isFuncDeclaration() : NULL)
+ {
+ if (f->checkForwardRef(loc))
+ goto Lerr;
+ }
+ if (FuncDeclaration *f = isFuncAddress(exp))
+ {
+ if (f->checkForwardRef(loc))
+ goto Lerr;
+ }
+
+ t = exp->type;
+ if (!t)
+ {
+ error(loc, "expression (%s) has no type", exp->toChars());
+ goto Lerr;
+ }
+ if (t->ty == Ttypeof)
+ {
+ error(loc, "forward reference to %s", toChars());
+ goto Lerr;
+ }
+ }
+ if (idents.dim == 0)
+ *pt = t;
+ else
+ {
+ if (Dsymbol *s = t->toDsymbol(sc))
+ resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid);
+ else
+ {
+ Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
+ e = ::semantic(e, sc);
+ resolveExp(e, pt, pe, ps);
+ }
+ }
+ if (*pt)
+ (*pt) = (*pt)->addMod(mod);
+ inuse--;
+ return;
+}
+
+Type *TypeTypeof::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypeTypeof::semantic() %s\n", toChars());
+
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ resolve(loc, sc, &e, &t, &s);
+ if (s && (t = s->getType()) != NULL)
+ t = t->addMod(mod);
+ if (!t)
+ {
+ error(loc, "%s is used as a type", toChars());
+ t = Type::terror;
+ }
+ return t;
+}
+
+d_uns64 TypeTypeof::size(Loc loc)
+{
+ if (exp->type)
+ return exp->type->size(loc);
+ else
+ return TypeQualified::size(loc);
+}
+
+
+
+/***************************** TypeReturn *****************************/
+
+TypeReturn::TypeReturn(Loc loc)
+ : TypeQualified(Treturn, loc)
+{
+}
+
+const char *TypeReturn::kind()
+{
+ return "return";
+}
+
+Type *TypeReturn::syntaxCopy()
+{
+ TypeReturn *t = new TypeReturn(loc);
+ t->syntaxCopyHelper(this);
+ t->mod = mod;
+ return t;
+}
+
+Dsymbol *TypeReturn::toDsymbol(Scope *sc)
+{
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ resolve(loc, sc, &e, &t, &s);
+
+ return s;
+}
+
+void TypeReturn::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ *pe = NULL;
+ *pt = NULL;
+ *ps = NULL;
+
+ //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, toChars());
+ Type *t;
+ {
+ FuncDeclaration *func = sc->func;
+ if (!func)
+ {
+ error(loc, "typeof(return) must be inside function");
+ goto Lerr;
+ }
+ if (func->fes)
+ func = func->fes->func;
+
+ t = func->type->nextOf();
+ if (!t)
+ {
+ error(loc, "cannot use typeof(return) inside function %s with inferred return type", sc->func->toChars());
+ goto Lerr;
+ }
+ }
+ if (idents.dim == 0)
+ *pt = t;
+ else
+ {
+ if (Dsymbol *s = t->toDsymbol(sc))
+ resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid);
+ else
+ {
+ Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
+ e = ::semantic(e, sc);
+ resolveExp(e, pt, pe, ps);
+ }
+ }
+ if (*pt)
+ (*pt) = (*pt)->addMod(mod);
+ return;
+
+Lerr:
+ *pt = Type::terror;
+ return;
+}
+
+Type *TypeReturn::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypeReturn::semantic() %s\n", toChars());
+
+ Expression *e;
+ Type *t;
+ Dsymbol *s;
+ resolve(loc, sc, &e, &t, &s);
+ if (s && (t = s->getType()) != NULL)
+ t = t->addMod(mod);
+ if (!t)
+ {
+ error(loc, "%s is used as a type", toChars());
+ t = Type::terror;
+ }
+ return t;
+}
+
+/***************************** TypeEnum *****************************/
+
+TypeEnum::TypeEnum(EnumDeclaration *sym)
+ : Type(Tenum)
+{
+ this->sym = sym;
+}
+
+const char *TypeEnum::kind()
+{
+ return "enum";
+}
+
+Type *TypeEnum::syntaxCopy()
+{
+ return this;
+}
+
+Type *TypeEnum::semantic(Loc, Scope *)
+{
+ //printf("TypeEnum::semantic() %s\n", toChars());
+ if (deco)
+ return this;
+ return merge();
+}
+
+d_uns64 TypeEnum::size(Loc loc)
+{
+ return sym->getMemtype(loc)->size(loc);
+}
+
+unsigned TypeEnum::alignsize()
+{
+ Type *t = sym->getMemtype(Loc());
+ if (t->ty == Terror)
+ return 4;
+ return t->alignsize();
+}
+
+Dsymbol *TypeEnum::toDsymbol(Scope *)
+{
+ return sym;
+}
+
+Type *TypeEnum::toBasetype()
+{
+ if (!sym->members && !sym->memtype)
+ return this;
+ Type *tb = sym->getMemtype(Loc())->toBasetype();
+ return tb->castMod(mod); // retain modifier bits from 'this'
+}
+
+Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ // Bugzilla 14010
+ if (ident == Id::_mangleof)
+ return getProperty(e->loc, ident, flag & 1);
+
+ if (sym->_scope)
+ sym->semantic(sym->_scope);
+ if (!sym->members)
+ {
+ if (sym->isSpecial())
+ {
+ /* Special enums forward to the base type
+ */
+ e = sym->memtype->dotExp(sc, e, ident, flag);
+ }
+ else if (!(flag & 1))
+ {
+ sym->error("is forward referenced when looking for '%s'", ident->toChars());
+ e = new ErrorExp();
+ }
+ else
+ e = NULL;
+ return e;
+ }
+
+ Dsymbol *s = sym->search(e->loc, ident);
+ if (!s)
+ {
+ if (ident == Id::max ||
+ ident == Id::min ||
+ ident == Id::_init)
+ {
+ return getProperty(e->loc, ident, flag & 1);
+ }
+ Expression *res = sym->getMemtype(Loc())->dotExp(sc, e, ident, 1);
+ if (!(flag & 1) && !res)
+ {
+ if (Dsymbol *ns = sym->search_correct(ident))
+ e->error("no property '%s' for type '%s'. Did you mean '%s.%s' ?",
+ ident->toChars(), toChars(), toChars(), ns->toChars());
+ else
+ e->error("no property '%s' for type '%s'",
+ ident->toChars(), toChars());
+
+ return new ErrorExp();
+ }
+ return res;
+ }
+ EnumMember *m = s->isEnumMember();
+ return m->getVarExp(e->loc, sc);
+}
+
+Expression *TypeEnum::getProperty(Loc loc, Identifier *ident, int flag)
+{
+ Expression *e;
+ if (ident == Id::max || ident == Id::min)
+ {
+ return sym->getMaxMinValue(loc, ident);
+ }
+ else if (ident == Id::_init)
+ {
+ e = defaultInitLiteral(loc);
+ }
+ else if (ident == Id::stringof)
+ {
+ const char *s = toChars();
+ e = new StringExp(loc, const_cast<char *>(s), strlen(s));
+ Scope sc;
+ e = ::semantic(e, &sc);
+ }
+ else if (ident == Id::_mangleof)
+ {
+ e = Type::getProperty(loc, ident, flag);
+ }
+ else
+ {
+ e = toBasetype()->getProperty(loc, ident, flag);
+ }
+ return e;
+}
+
+bool TypeEnum::isintegral()
+{
+ return sym->getMemtype(Loc())->isintegral();
+}
+
+bool TypeEnum::isfloating()
+{
+ return sym->getMemtype(Loc())->isfloating();
+}
+
+bool TypeEnum::isreal()
+{
+ return sym->getMemtype(Loc())->isreal();
+}
+
+bool TypeEnum::isimaginary()
+{
+ return sym->getMemtype(Loc())->isimaginary();
+}
+
+bool TypeEnum::iscomplex()
+{
+ return sym->getMemtype(Loc())->iscomplex();
+}
+
+bool TypeEnum::isunsigned()
+{
+ return sym->getMemtype(Loc())->isunsigned();
+}
+
+bool TypeEnum::isscalar()
+{
+ return sym->getMemtype(Loc())->isscalar();
+}
+
+bool TypeEnum::isString()
+{
+ return sym->getMemtype(Loc())->isString();
+}
+
+bool TypeEnum::isAssignable()
+{
+ return sym->getMemtype(Loc())->isAssignable();
+}
+
+bool TypeEnum::isBoolean()
+{
+ return sym->getMemtype(Loc())->isBoolean();
+}
+
+bool TypeEnum::needsDestruction()
+{
+ return sym->getMemtype(Loc())->needsDestruction();
+}
+
+bool TypeEnum::needsNested()
+{
+ return sym->getMemtype(Loc())->needsNested();
+}
+
+MATCH TypeEnum::implicitConvTo(Type *to)
+{
+ MATCH m;
+
+ //printf("TypeEnum::implicitConvTo()\n");
+ if (ty == to->ty && sym == ((TypeEnum *)to)->sym)
+ m = (mod == to->mod) ? MATCHexact : MATCHconst;
+ else if (sym->getMemtype(Loc())->implicitConvTo(to))
+ m = MATCHconvert; // match with conversions
+ else
+ m = MATCHnomatch; // no match
+ return m;
+}
+
+MATCH TypeEnum::constConv(Type *to)
+{
+ if (equals(to))
+ return MATCHexact;
+ if (ty == to->ty && sym == ((TypeEnum *)to)->sym &&
+ MODimplicitConv(mod, to->mod))
+ return MATCHconst;
+ return MATCHnomatch;
+}
+
+
+Expression *TypeEnum::defaultInit(Loc loc)
+{
+ // Initialize to first member of enum
+ Expression *e = sym->getDefaultValue(loc);
+ e = e->copy();
+ e->loc = loc;
+ e->type = this; // to deal with const, immutable, etc., variants
+ return e;
+}
+
+bool TypeEnum::isZeroInit(Loc loc)
+{
+ return sym->getDefaultValue(loc)->isBool(false);
+}
+
+bool TypeEnum::hasPointers()
+{
+ return sym->getMemtype(Loc())->hasPointers();
+}
+
+bool TypeEnum::hasVoidInitPointers()
+{
+ return sym->getMemtype(Loc())->hasVoidInitPointers();
+}
+
+Type *TypeEnum::nextOf()
+{
+ return sym->getMemtype(Loc())->nextOf();
+}
+
+/***************************** TypeStruct *****************************/
+
+TypeStruct::TypeStruct(StructDeclaration *sym)
+ : Type(Tstruct)
+{
+ this->sym = sym;
+ this->att = RECfwdref;
+ this->cppmangle = CPPMANGLEdefault;
+}
+
+TypeStruct *TypeStruct::create(StructDeclaration *sym)
+{
+ return new TypeStruct(sym);
+}
+
+const char *TypeStruct::kind()
+{
+ return "struct";
+}
+
+Type *TypeStruct::syntaxCopy()
+{
+ return this;
+}
+
+Type *TypeStruct::semantic(Loc, Scope *sc)
+{
+ //printf("TypeStruct::semantic('%s')\n", sym->toChars());
+ if (deco)
+ {
+ if (sc && sc->cppmangle != CPPMANGLEdefault)
+ {
+ if (this->cppmangle == CPPMANGLEdefault)
+ this->cppmangle = sc->cppmangle;
+ else
+ assert(this->cppmangle == sc->cppmangle);
+ }
+ return this;
+ }
+
+ /* Don't semantic for sym because it should be deferred until
+ * sizeof needed or its members accessed.
+ */
+ // instead, parent should be set correctly
+ assert(sym->parent);
+
+ if (sym->type->ty == Terror)
+ return Type::terror;
+ if (sc)
+ this->cppmangle = sc->cppmangle;
+ return merge();
+}
+
+d_uns64 TypeStruct::size(Loc loc)
+{
+ return sym->size(loc);
+}
+
+unsigned TypeStruct::alignsize()
+{
+ sym->size(Loc()); // give error for forward references
+ return sym->alignsize;
+}
+
+Dsymbol *TypeStruct::toDsymbol(Scope *)
+{
+ return sym;
+}
+
+static Dsymbol *searchSymStruct(Scope *sc, Dsymbol *sym, Expression *e, Identifier *ident)
+{
+ int flags = sc->flags & SCOPEignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
+ Dsymbol *sold = NULL;
+ if (global.params.bug10378 || global.params.check10378)
+ {
+ sold = sym->search(e->loc, ident, flags);
+ if (!global.params.check10378)
+ return sold;
+ }
+
+ Dsymbol *s = sym->search(e->loc, ident, flags | SearchLocalsOnly);
+ if (global.params.check10378)
+ {
+ Dsymbol *snew = s;
+ if (sold != snew)
+ Scope::deprecation10378(e->loc, sold, snew);
+ if (global.params.bug10378)
+ s = sold;
+ }
+ return s;
+}
+
+Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ Dsymbol *s;
+
+ assert(e->op != TOKdot);
+
+ // Bugzilla 14010
+ if (ident == Id::_mangleof)
+ return getProperty(e->loc, ident, flag & 1);
+
+ /* If e.tupleof
+ */
+ if (ident == Id::_tupleof)
+ {
+ /* Create a TupleExp out of the fields of the struct e:
+ * (e.field0, e.field1, e.field2, ...)
+ */
+ e = ::semantic(e, sc); // do this before turning on noaccesscheck
+
+ sym->size(e->loc); // do semantic of type
+
+ Expression *e0 = NULL;
+ Expression *ev = e->op == TOKtype ? NULL : e;
+ if (ev)
+ ev = extractSideEffect(sc, "__tup", &e0, ev);
+
+ Expressions *exps = new Expressions;
+ exps->reserve(sym->fields.dim);
+ for (size_t i = 0; i < sym->fields.dim; i++)
+ {
+ VarDeclaration *v = sym->fields[i];
+ Expression *ex;
+ if (ev)
+ ex = new DotVarExp(e->loc, ev, v);
+ else
+ {
+ ex = new VarExp(e->loc, v);
+ ex->type = ex->type->addMod(e->type->mod);
+ }
+ exps->push(ex);
+ }
+
+ e = new TupleExp(e->loc, e0, exps);
+ Scope *sc2 = sc->push();
+ sc2->flags = sc->flags | SCOPEnoaccesscheck;
+ e = ::semantic(e, sc2);
+ sc2->pop();
+ return e;
+ }
+
+ s = searchSymStruct(sc, sym, e, ident);
+L1:
+ if (!s)
+ {
+ return noMember(sc, e, ident, flag);
+ }
+ if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, s))
+ {
+ ::deprecation(e->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toPrettyChars());
+ // return noMember(sc, e, ident, flag);
+ }
+ if (!s->isFuncDeclaration()) // because of overloading
+ s->checkDeprecated(e->loc, sc);
+ s = s->toAlias();
+
+ EnumMember *em = s->isEnumMember();
+ if (em)
+ {
+ return em->getVarExp(e->loc, sc);
+ }
+
+ if (VarDeclaration *v = s->isVarDeclaration())
+ {
+ if (!v->type ||
+ (!v->type->deco && v->inuse))
+ {
+ if (v->inuse) // Bugzilla 9494
+ e->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ else
+ e->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+ if (v->type->ty == Terror)
+ return new ErrorExp();
+
+ if ((v->storage_class & STCmanifest) && v->_init)
+ {
+ if (v->inuse)
+ {
+ e->error("circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+ checkAccess(e->loc, sc, NULL, v);
+ Expression *ve = new VarExp(e->loc, v);
+ ve = ::semantic(ve, sc);
+ return ve;
+ }
+ }
+
+ if (Type *t = s->getType())
+ {
+ return ::semantic(new TypeExp(e->loc, t), sc);
+ }
+
+ TemplateMixin *tm = s->isTemplateMixin();
+ if (tm)
+ {
+ Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+ de->type = e->type;
+ return de;
+ }
+
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (td)
+ {
+ if (e->op == TOKtype)
+ e = new TemplateExp(e->loc, td);
+ else
+ e = new DotTemplateExp(e->loc, e, td);
+ e = ::semantic(e, sc);
+ return e;
+ }
+
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti)
+ {
+ if (!ti->semanticRun)
+ {
+ ti->semantic(sc);
+ if (!ti->inst || ti->errors) // if template failed to expand
+ return new ErrorExp();
+ }
+ s = ti->inst->toAlias();
+ if (!s->isTemplateInstance())
+ goto L1;
+ if (e->op == TOKtype)
+ e = new ScopeExp(e->loc, ti);
+ else
+ e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
+ return ::semantic(e, sc);
+ }
+
+ if (s->isImport() || s->isModule() || s->isPackage())
+ {
+ e = ::resolve(e->loc, sc, s, false);
+ return e;
+ }
+
+ OverloadSet *o = s->isOverloadSet();
+ if (o)
+ {
+ OverExp *oe = new OverExp(e->loc, o);
+ if (e->op == TOKtype)
+ return oe;
+ return new DotExp(e->loc, e, oe);
+ }
+
+ Declaration *d = s->isDeclaration();
+ if (!d)
+ {
+ e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
+ return new ErrorExp();
+ }
+
+ if (e->op == TOKtype)
+ {
+ /* It's:
+ * Struct.d
+ */
+ if (TupleDeclaration *tup = d->isTupleDeclaration())
+ {
+ e = new TupleExp(e->loc, tup);
+ e = ::semantic(e, sc);
+ return e;
+ }
+ if (d->needThis() && sc->intypeof != 1)
+ {
+ /* Rewrite as:
+ * this.d
+ */
+ if (hasThis(sc))
+ {
+ e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
+ e = ::semantic(e, sc);
+ return e;
+ }
+ }
+ if (d->semanticRun == PASSinit && d->_scope)
+ d->semantic(d->_scope);
+ checkAccess(e->loc, sc, e, d);
+ VarExp *ve = new VarExp(e->loc, d);
+ if (d->isVarDeclaration() && d->needThis())
+ ve->type = d->type->addMod(e->type->mod);
+ return ve;
+ }
+
+ bool unreal = e->op == TOKvar && ((VarExp *)e)->var->isField();
+ if (d->isDataseg() || (unreal && d->isField()))
+ {
+ // (e, d)
+ checkAccess(e->loc, sc, e, d);
+ Expression *ve = new VarExp(e->loc, d);
+ e = unreal ? ve : new CommaExp(e->loc, e, ve);
+ e = ::semantic(e, sc);
+ return e;
+ }
+
+ e = new DotVarExp(e->loc, e, d);
+ e = ::semantic(e, sc);
+ return e;
+}
+
+structalign_t TypeStruct::alignment()
+{
+ if (sym->alignment == 0)
+ sym->size(sym->loc);
+ return sym->alignment;
+}
+
+Expression *TypeStruct::defaultInit(Loc)
+{
+ Declaration *d = new SymbolDeclaration(sym->loc, sym);
+ assert(d);
+ d->type = this;
+ d->storage_class |= STCrvalue; // Bugzilla 14398
+ return new VarExp(sym->loc, d);
+}
+
+/***************************************
+ * Use when we prefer the default initializer to be a literal,
+ * rather than a global immutable variable.
+ */
+Expression *TypeStruct::defaultInitLiteral(Loc loc)
+{
+ sym->size(loc);
+ if (sym->sizeok != SIZEOKdone)
+ return new ErrorExp();
+ Expressions *structelems = new Expressions();
+ structelems->setDim(sym->fields.dim - sym->isNested());
+ unsigned offset = 0;
+ for (size_t j = 0; j < structelems->dim; j++)
+ {
+ VarDeclaration *vd = sym->fields[j];
+ Expression *e;
+ if (vd->inuse)
+ {
+ error(loc, "circular reference to '%s'", vd->toPrettyChars());
+ return new ErrorExp();
+ }
+ if (vd->offset < offset || vd->type->size() == 0)
+ e = NULL;
+ else if (vd->_init)
+ {
+ if (vd->_init->isVoidInitializer())
+ e = NULL;
+ else
+ e = vd->getConstInitializer(false);
+ }
+ else
+ e = vd->type->defaultInitLiteral(loc);
+ if (e && e->op == TOKerror)
+ return e;
+ if (e)
+ offset = vd->offset + (unsigned)vd->type->size();
+ (*structelems)[j] = e;
+ }
+ StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems);
+
+ /* Copy from the initializer symbol for larger symbols,
+ * otherwise the literals expressed as code get excessively large.
+ */
+ if (size(loc) > Target::ptrsize * 4U && !needsNested())
+ structinit->useStaticInit = true;
+
+ structinit->type = this;
+ return structinit;
+}
+
+
+bool TypeStruct::isZeroInit(Loc)
+{
+ return sym->zeroInit != 0;
+}
+
+bool TypeStruct::isBoolean()
+{
+ return false;
+}
+
+bool TypeStruct::needsDestruction()
+{
+ return sym->dtor != NULL;
+}
+
+bool TypeStruct::needsNested()
+{
+ if (sym->isNested())
+ return true;
+
+ for (size_t i = 0; i < sym->fields.dim; i++)
+ {
+ VarDeclaration *v = sym->fields[i];
+ if (!v->isDataseg() && v->type->needsNested())
+ return true;
+ }
+ return false;
+}
+
+bool TypeStruct::isAssignable()
+{
+ bool assignable = true;
+ unsigned offset = ~0; // dead-store initialize to prevent spurious warning
+
+ /* If any of the fields are const or immutable,
+ * then one cannot assign this struct.
+ */
+ for (size_t i = 0; i < sym->fields.dim; i++)
+ {
+ VarDeclaration *v = sym->fields[i];
+ //printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind());
+ if (i == 0)
+ ;
+ else if (v->offset == offset)
+ {
+ /* If any fields of anonymous union are assignable,
+ * then regard union as assignable.
+ * This is to support unsafe things like Rebindable templates.
+ */
+ if (assignable)
+ continue;
+ }
+ else
+ {
+ if (!assignable)
+ return false;
+ }
+ assignable = v->type->isMutable() && v->type->isAssignable();
+ offset = v->offset;
+ //printf(" -> assignable = %d\n", assignable);
+ }
+
+ return assignable;
+}
+
+bool TypeStruct::hasPointers()
+{
+ // Probably should cache this information in sym rather than recompute
+ StructDeclaration *s = sym;
+
+ sym->size(Loc()); // give error for forward references
+ for (size_t i = 0; i < s->fields.dim; i++)
+ {
+ Declaration *d = s->fields[i];
+ if (d->storage_class & STCref || d->hasPointers())
+ return true;
+ }
+ return false;
+}
+
+bool TypeStruct::hasVoidInitPointers()
+{
+ // Probably should cache this information in sym rather than recompute
+ StructDeclaration *s = sym;
+
+ sym->size(Loc()); // give error for forward references
+ for (size_t i = 0; i < s->fields.dim; i++)
+ {
+ VarDeclaration *v = s->fields[i];
+ if (v->_init && v->_init->isVoidInitializer() && v->type->hasPointers())
+ return true;
+ if (!v->_init && v->type->hasVoidInitPointers())
+ return true;
+ }
+ return false;
+}
+
+MATCH TypeStruct::implicitConvTo(Type *to)
+{ MATCH m;
+
+ //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars());
+
+ if (ty == to->ty && sym == ((TypeStruct *)to)->sym)
+ {
+ m = MATCHexact; // exact match
+ if (mod != to->mod)
+ {
+ m = MATCHconst;
+ if (MODimplicitConv(mod, to->mod))
+ ;
+ else
+ {
+ /* Check all the fields. If they can all be converted,
+ * allow the conversion.
+ */
+ unsigned offset = ~0; // dead-store to prevent spurious warning
+ for (size_t i = 0; i < sym->fields.dim; i++)
+ {
+ VarDeclaration *v = sym->fields[i];
+ if (i == 0)
+ ;
+ else if (v->offset == offset)
+ {
+ if (m > MATCHnomatch)
+ continue;
+ }
+ else
+ {
+ if (m <= MATCHnomatch)
+ return m;
+ }
+
+ // 'from' type
+ Type *tvf = v->type->addMod(mod);
+
+ // 'to' type
+ Type *tv = v->type->addMod(to->mod);
+
+ // field match
+ MATCH mf = tvf->implicitConvTo(tv);
+ //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), mf);
+
+ if (mf <= MATCHnomatch)
+ return mf;
+ if (mf < m) // if field match is worse
+ m = mf;
+ offset = v->offset;
+ }
+ }
+ }
+ }
+ else if (sym->aliasthis && !(att & RECtracing))
+ {
+ att = (AliasThisRec)(att | RECtracing);
+ m = aliasthisOf()->implicitConvTo(to);
+ att = (AliasThisRec)(att & ~RECtracing);
+ }
+ else
+ m = MATCHnomatch; // no match
+ return m;
+}
+
+MATCH TypeStruct::constConv(Type *to)
+{
+ if (equals(to))
+ return MATCHexact;
+ if (ty == to->ty && sym == ((TypeStruct *)to)->sym &&
+ MODimplicitConv(mod, to->mod))
+ return MATCHconst;
+ return MATCHnomatch;
+}
+
+unsigned char TypeStruct::deduceWild(Type *t, bool isRef)
+{
+ if (ty == t->ty && sym == ((TypeStruct *)t)->sym)
+ return Type::deduceWild(t, isRef);
+
+ unsigned char wm = 0;
+
+ if (t->hasWild() && sym->aliasthis && !(att & RECtracing))
+ {
+ att = (AliasThisRec)(att | RECtracing);
+ wm = aliasthisOf()->deduceWild(t, isRef);
+ att = (AliasThisRec)(att & ~RECtracing);
+ }
+
+ return wm;
+}
+
+Type *TypeStruct::toHeadMutable()
+{
+ return this;
+}
+
+
+/***************************** TypeClass *****************************/
+
+TypeClass::TypeClass(ClassDeclaration *sym)
+ : Type(Tclass)
+{
+ this->sym = sym;
+ this->att = RECfwdref;
+ this->cppmangle = CPPMANGLEdefault;
+}
+
+const char *TypeClass::kind()
+{
+ return "class";
+}
+
+Type *TypeClass::syntaxCopy()
+{
+ return this;
+}
+
+Type *TypeClass::semantic(Loc, Scope *sc)
+{
+ //printf("TypeClass::semantic(%s)\n", sym->toChars());
+ if (deco)
+ {
+ if (sc && sc->cppmangle != CPPMANGLEdefault)
+ {
+ if (this->cppmangle == CPPMANGLEdefault)
+ this->cppmangle = sc->cppmangle;
+ else
+ assert(this->cppmangle == sc->cppmangle);
+ }
+ return this;
+ }
+
+ /* Don't semantic for sym because it should be deferred until
+ * sizeof needed or its members accessed.
+ */
+ // instead, parent should be set correctly
+ assert(sym->parent);
+
+ if (sym->type->ty == Terror)
+ return Type::terror;
+ if (sc)
+ this->cppmangle = sc->cppmangle;
+ return merge();
+}
+
+d_uns64 TypeClass::size(Loc)
+{
+ return Target::ptrsize;
+}
+
+Dsymbol *TypeClass::toDsymbol(Scope *)
+{
+ return sym;
+}
+
+static Dsymbol *searchSymClass(Scope *sc, Dsymbol *sym, Expression *e, Identifier *ident)
+{
+ int flags = sc->flags & SCOPEignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
+ Dsymbol *sold = NULL;
+ if (global.params.bug10378 || global.params.check10378)
+ {
+ sold = sym->search(e->loc, ident, flags | IgnoreSymbolVisibility);
+ if (!global.params.check10378)
+ return sold;
+ }
+
+ Dsymbol *s = sym->search(e->loc, ident, flags | SearchLocalsOnly);
+ if (!s && !(flags & IgnoreSymbolVisibility))
+ {
+ s = sym->search(e->loc, ident, flags | SearchLocalsOnly | IgnoreSymbolVisibility);
+ if (s && !(flags & IgnoreErrors))
+ ::deprecation(e->loc, "%s is not visible from class %s", s->toPrettyChars(), sym->toChars());
+ }
+ if (global.params.check10378)
+ {
+ Dsymbol *snew = s;
+ if (sold != snew)
+ Scope::deprecation10378(e->loc, sold, snew);
+ if (global.params.bug10378)
+ s = sold;
+ }
+ return s;
+}
+
+Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
+{
+ Dsymbol *s;
+ assert(e->op != TOKdot);
+
+ // Bugzilla 12543
+ if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof)
+ {
+ return Type::getProperty(e->loc, ident, 0);
+ }
+
+ /* If e.tupleof
+ */
+ if (ident == Id::_tupleof)
+ {
+ /* Create a TupleExp
+ */
+ e = ::semantic(e, sc); // do this before turning on noaccesscheck
+
+ sym->size(e->loc); // do semantic of type
+
+ Expression *e0 = NULL;
+ Expression *ev = e->op == TOKtype ? NULL : e;
+ if (ev)
+ ev = extractSideEffect(sc, "__tup", &e0, ev);
+
+ Expressions *exps = new Expressions;
+ exps->reserve(sym->fields.dim);
+ for (size_t i = 0; i < sym->fields.dim; i++)
+ {
+ VarDeclaration *v = sym->fields[i];
+ // Don't include hidden 'this' pointer
+ if (v->isThisDeclaration())
+ continue;
+ Expression *ex;
+ if (ev)
+ ex = new DotVarExp(e->loc, ev, v);
+ else
+ {
+ ex = new VarExp(e->loc, v);
+ ex->type = ex->type->addMod(e->type->mod);
+ }
+ exps->push(ex);
+ }
+
+ e = new TupleExp(e->loc, e0, exps);
+ Scope *sc2 = sc->push();
+ sc2->flags = sc->flags | SCOPEnoaccesscheck;
+ e = ::semantic(e, sc2);
+ sc2->pop();
+ return e;
+ }
+
+ s = searchSymClass(sc, sym, e, ident);
+L1:
+ if (!s)
+ {
+ // See if it's 'this' class or a base class
+ if (sym->ident == ident)
+ {
+ if (e->op == TOKtype)
+ return Type::getProperty(e->loc, ident, 0);
+ e = new DotTypeExp(e->loc, e, sym);
+ e = ::semantic(e, sc);
+ return e;
+ }
+ if (ClassDeclaration *cbase = sym->searchBase(ident))
+ {
+ if (e->op == TOKtype)
+ return Type::getProperty(e->loc, ident, 0);
+ if (InterfaceDeclaration *ifbase = cbase->isInterfaceDeclaration())
+ e = new CastExp(e->loc, e, ifbase->type);
+ else
+ e = new DotTypeExp(e->loc, e, cbase);
+ e = ::semantic(e, sc);
+ return e;
+ }
+
+ if (ident == Id::classinfo)
+ {
+ assert(Type::typeinfoclass);
+ Type *t = Type::typeinfoclass->type;
+ if (e->op == TOKtype || e->op == TOKdottype)
+ {
+ /* For type.classinfo, we know the classinfo
+ * at compile time.
+ */
+ if (!sym->vclassinfo)
+ sym->vclassinfo = new TypeInfoClassDeclaration(sym->type);
+ e = new VarExp(e->loc, sym->vclassinfo);
+ e = e->addressOf();
+ e->type = t; // do this so we don't get redundant dereference
+ }
+ else
+ {
+ /* For class objects, the classinfo reference is the first
+ * entry in the vtbl[]
+ */
+ e = new PtrExp(e->loc, e);
+ e->type = t->pointerTo();
+ if (sym->isInterfaceDeclaration())
+ {
+ if (sym->isCPPinterface())
+ {
+ /* C++ interface vtbl[]s are different in that the
+ * first entry is always pointer to the first virtual
+ * function, not classinfo.
+ * We can't get a .classinfo for it.
+ */
+ error(e->loc, "no .classinfo for C++ interface objects");
+ }
+ /* For an interface, the first entry in the vtbl[]
+ * is actually a pointer to an instance of struct Interface.
+ * The first member of Interface is the .classinfo,
+ * so add an extra pointer indirection.
+ */
+ e->type = e->type->pointerTo();
+ e = new PtrExp(e->loc, e);
+ e->type = t->pointerTo();
+ }
+ e = new PtrExp(e->loc, e, t);
+ }
+ return e;
+ }
+
+ if (ident == Id::__vptr)
+ {
+ /* The pointer to the vtbl[]
+ * *cast(immutable(void*)**)e
+ */
+ e = e->castTo(sc, tvoidptr->immutableOf()->pointerTo()->pointerTo());
+ e = new PtrExp(e->loc, e);
+ e = ::semantic(e, sc);
+ return e;
+ }
+
+ if (ident == Id::__monitor)
+ {
+ /* The handle to the monitor (call it a void*)
+ * *(cast(void**)e + 1)
+ */
+ e = e->castTo(sc, tvoidptr->pointerTo());
+ e = new AddExp(e->loc, e, new IntegerExp(1));
+ e = new PtrExp(e->loc, e);
+ e = ::semantic(e, sc);
+ return e;
+ }
+
+ if (ident == Id::outer && sym->vthis)
+ {
+ if (sym->vthis->_scope)
+ sym->vthis->semantic(NULL);
+
+ if (ClassDeclaration *cdp = sym->toParent2()->isClassDeclaration())
+ {
+ DotVarExp *dve = new DotVarExp(e->loc, e, sym->vthis);
+ dve->type = cdp->type->addMod(e->type->mod);
+ return dve;
+ }
+
+ /* Bugzilla 15839: Find closest parent class through nested functions.
+ */
+ for (Dsymbol *p = sym->toParent2(); p; p = p->toParent2())
+ {
+ FuncDeclaration *fd = p->isFuncDeclaration();
+ if (!fd)
+ break;
+ if (fd->isNested())
+ continue;
+ AggregateDeclaration *ad = fd->isThis();
+ if (!ad)
+ break;
+ if (ad->isClassDeclaration())
+ {
+ ThisExp *ve = new ThisExp(e->loc);
+
+ ve->var = fd->vthis;
+ const bool nestedError = fd->vthis->checkNestedReference(sc, e->loc);
+ assert(!nestedError);
+
+ ve->type = fd->vthis->type->addMod(e->type->mod);
+ return ve;
+ }
+ break;
+ }
+
+ // Continue to show enclosing function's frame (stack or closure).
+ DotVarExp *dve = new DotVarExp(e->loc, e, sym->vthis);
+ dve->type = sym->vthis->type->addMod(e->type->mod);
+ return dve;
+ }
+
+ return noMember(sc, e, ident, flag & 1);
+ }
+ if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, s))
+ {
+ ::deprecation(e->loc, "%s is not visible from module %s", s->toPrettyChars(), sc->_module->toPrettyChars());
+ // return noMember(sc, e, ident, flag);
+ }
+ if (!s->isFuncDeclaration()) // because of overloading
+ s->checkDeprecated(e->loc, sc);
+ s = s->toAlias();
+
+ EnumMember *em = s->isEnumMember();
+ if (em)
+ {
+ return em->getVarExp(e->loc, sc);
+ }
+
+ if (VarDeclaration *v = s->isVarDeclaration())
+ {
+ if (!v->type ||
+ (!v->type->deco && v->inuse))
+ {
+ if (v->inuse) // Bugzilla 9494
+ e->error("circular reference to %s '%s'", v->kind(), v->toPrettyChars());
+ else
+ e->error("forward reference to %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+ if (v->type->ty == Terror)
+ return new ErrorExp();
+
+ if ((v->storage_class & STCmanifest) && v->_init)
+ {
+ if (v->inuse)
+ {
+ e->error("circular initialization of %s '%s'", v->kind(), v->toPrettyChars());
+ return new ErrorExp();
+ }
+ checkAccess(e->loc, sc, NULL, v);
+ Expression *ve = new VarExp(e->loc, v);
+ ve = ::semantic(ve, sc);
+ return ve;
+ }
+ }
+
+ if (Type *t = s->getType())
+ {
+ return ::semantic(new TypeExp(e->loc, t), sc);
+ }
+
+ TemplateMixin *tm = s->isTemplateMixin();
+ if (tm)
+ {
+ Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
+ de->type = e->type;
+ return de;
+ }
+
+ TemplateDeclaration *td = s->isTemplateDeclaration();
+ if (td)
+ {
+ if (e->op == TOKtype)
+ e = new TemplateExp(e->loc, td);
+ else
+ e = new DotTemplateExp(e->loc, e, td);
+ e = ::semantic(e, sc);
+ return e;
+ }
+
+ TemplateInstance *ti = s->isTemplateInstance();
+ if (ti)
+ {
+ if (!ti->semanticRun)
+ {
+ ti->semantic(sc);
+ if (!ti->inst || ti->errors) // if template failed to expand
+ return new ErrorExp();
+ }
+ s = ti->inst->toAlias();
+ if (!s->isTemplateInstance())
+ goto L1;
+ if (e->op == TOKtype)
+ e = new ScopeExp(e->loc, ti);
+ else
+ e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
+ return ::semantic(e, sc);
+ }
+
+ if (s->isImport() || s->isModule() || s->isPackage())
+ {
+ e = ::resolve(e->loc, sc, s, false);
+ return e;
+ }
+
+ OverloadSet *o = s->isOverloadSet();
+ if (o)
+ {
+ OverExp *oe = new OverExp(e->loc, o);
+ if (e->op == TOKtype)
+ return oe;
+ return new DotExp(e->loc, e, oe);
+ }
+
+ Declaration *d = s->isDeclaration();
+ if (!d)
+ {
+ e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
+ return new ErrorExp();
+ }
+
+ if (e->op == TOKtype)
+ {
+ /* It's:
+ * Class.d
+ */
+ if (TupleDeclaration *tup = d->isTupleDeclaration())
+ {
+ e = new TupleExp(e->loc, tup);
+ e = ::semantic(e, sc);
+ return e;
+ }
+ if (d->needThis() && sc->intypeof != 1)
+ {
+ /* Rewrite as:
+ * this.d
+ */
+ if (hasThis(sc))
+ {
+ // This is almost same as getRightThis() in expression.c
+ Expression *e1 = new ThisExp(e->loc);
+ e1 = ::semantic(e1, sc);
+ L2:
+ Type *t = e1->type->toBasetype();
+ ClassDeclaration *cd = e->type->isClassHandle();
+ ClassDeclaration *tcd = t->isClassHandle();
+ if (cd && tcd && (tcd == cd || cd->isBaseOf(tcd, NULL)))
+ {
+ e = new DotTypeExp(e1->loc, e1, cd);
+ e = new DotVarExp(e->loc, e, d);
+ e = ::semantic(e, sc);
+ return e;
+ }
+ if (tcd && tcd->isNested())
+ { /* e1 is the 'this' pointer for an inner class: tcd.
+ * Rewrite it as the 'this' pointer for the outer class.
+ */
+
+ e1 = new DotVarExp(e->loc, e1, tcd->vthis);
+ e1->type = tcd->vthis->type;
+ e1->type = e1->type->addMod(t->mod);
+ // Do not call checkNestedRef()
+ //e1 = ::semantic(e1, sc);
+
+ // Skip up over nested functions, and get the enclosing
+ // class type.
+ int n = 0;
+ for (s = tcd->toParent();
+ s && s->isFuncDeclaration();
+ s = s->toParent())
+ { FuncDeclaration *f = s->isFuncDeclaration();
+ if (f->vthis)
+ {
+ //printf("rewriting e1 to %s's this\n", f->toChars());
+ n++;
+ e1 = new VarExp(e->loc, f->vthis);
+ }
+ else
+ {
+ e = new VarExp(e->loc, d);
+ return e;
+ }
+ }
+ if (s && s->isClassDeclaration())
+ { e1->type = s->isClassDeclaration()->type;
+ e1->type = e1->type->addMod(t->mod);
+ if (n > 1)
+ e1 = ::semantic(e1, sc);
+ }
+ else
+ e1 = ::semantic(e1, sc);
+ goto L2;
+ }
+ }
+ }
+ //printf("e = %s, d = %s\n", e->toChars(), d->toChars());
+ if (d->semanticRun == PASSinit && d->_scope)
+ d->semantic(d->_scope);
+ checkAccess(e->loc, sc, e, d);
+ VarExp *ve = new VarExp(e->loc, d);
+ if (d->isVarDeclaration() && d->needThis())
+ ve->type = d->type->addMod(e->type->mod);
+ return ve;
+ }
+
+ bool unreal = e->op == TOKvar && ((VarExp *)e)->var->isField();
+ if (d->isDataseg() || (unreal && d->isField()))
+ {
+ // (e, d)
+ checkAccess(e->loc, sc, e, d);
+ Expression *ve = new VarExp(e->loc, d);
+ e = unreal ? ve : new CommaExp(e->loc, e, ve);
+ e = ::semantic(e, sc);
+ return e;
+ }
+
+ e = new DotVarExp(e->loc, e, d);
+ e = ::semantic(e, sc);
+ return e;
+}
+
+ClassDeclaration *TypeClass::isClassHandle()
+{
+ return sym;
+}
+
+bool TypeClass::isscope()
+{
+ return sym->isscope;
+}
+
+bool TypeClass::isBaseOf(Type *t, int *poffset)
+{
+ if (t && t->ty == Tclass)
+ {
+ ClassDeclaration *cd = ((TypeClass *)t)->sym;
+ if (sym->isBaseOf(cd, poffset))
+ return true;
+ }
+ return false;
+}
+
+MATCH TypeClass::implicitConvTo(Type *to)
+{
+ //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars());
+ MATCH m = constConv(to);
+ if (m > MATCHnomatch)
+ return m;
+
+ ClassDeclaration *cdto = to->isClassHandle();
+ if (cdto)
+ {
+ //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to->toChars(), toChars(), cdto->isBaseInfoComplete(), sym->isBaseInfoComplete());
+ if (cdto->_scope && !cdto->isBaseInfoComplete())
+ cdto->semantic(NULL);
+ if (sym->_scope && !sym->isBaseInfoComplete())
+ sym->semantic(NULL);
+ if (cdto->isBaseOf(sym, NULL) && MODimplicitConv(mod, to->mod))
+ {
+ //printf("'to' is base\n");
+ return MATCHconvert;
+ }
+ }
+
+ m = MATCHnomatch;
+ if (sym->aliasthis && !(att & RECtracing))
+ {
+ att = (AliasThisRec)(att | RECtracing);
+ m = aliasthisOf()->implicitConvTo(to);
+ att = (AliasThisRec)(att & ~RECtracing);
+ }
+
+ return m;
+}
+
+MATCH TypeClass::constConv(Type *to)
+{
+ if (equals(to))
+ return MATCHexact;
+ if (ty == to->ty && sym == ((TypeClass *)to)->sym &&
+ MODimplicitConv(mod, to->mod))
+ return MATCHconst;
+
+ /* Conversion derived to const(base)
+ */
+ int offset = 0;
+ if (to->isBaseOf(this, &offset) && offset == 0 &&
+ MODimplicitConv(mod, to->mod))
+ {
+ // Disallow:
+ // derived to base
+ // inout(derived) to inout(base)
+ if (!to->isMutable() && !to->isWild())
+ return MATCHconvert;
+ }
+
+ return MATCHnomatch;
+}
+
+unsigned char TypeClass::deduceWild(Type *t, bool isRef)
+{
+ ClassDeclaration *cd = t->isClassHandle();
+ if (cd && (sym == cd || cd->isBaseOf(sym, NULL)))
+ return Type::deduceWild(t, isRef);
+
+ unsigned char wm = 0;
+
+ if (t->hasWild() && sym->aliasthis && !(att & RECtracing))
+ {
+ att = (AliasThisRec)(att | RECtracing);
+ wm = aliasthisOf()->deduceWild(t, isRef);
+ att = (AliasThisRec)(att & ~RECtracing);
+ }
+
+ return wm;
+}
+
+Type *TypeClass::toHeadMutable()
+{
+ return this;
+}
+
+Expression *TypeClass::defaultInit(Loc loc)
+{
+ return new NullExp(loc, this);
+}
+
+bool TypeClass::isZeroInit(Loc)
+{
+ return true;
+}
+
+bool TypeClass::isBoolean()
+{
+ return true;
+}
+
+bool TypeClass::hasPointers()
+{
+ return true;
+}
+
+/***************************** TypeTuple *****************************/
+
+TypeTuple::TypeTuple(Parameters *arguments)
+ : Type(Ttuple)
+{
+ //printf("TypeTuple(this = %p)\n", this);
+ this->arguments = arguments;
+ //printf("TypeTuple() %p, %s\n", this, toChars());
+}
+
+/****************
+ * Form TypeTuple from the types of the expressions.
+ * Assume exps[] is already tuple expanded.
+ */
+
+TypeTuple::TypeTuple(Expressions *exps)
+ : Type(Ttuple)
+{
+ Parameters *arguments = new Parameters;
+ if (exps)
+ {
+ arguments->setDim(exps->dim);
+ for (size_t i = 0; i < exps->dim; i++)
+ { Expression *e = (*exps)[i];
+ if (e->type->ty == Ttuple)
+ e->error("cannot form tuple of tuples");
+ Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL);
+ (*arguments)[i] = arg;
+ }
+ }
+ this->arguments = arguments;
+ //printf("TypeTuple() %p, %s\n", this, toChars());
+}
+
+TypeTuple *TypeTuple::create(Parameters *arguments)
+{
+ return new TypeTuple(arguments);
+}
+
+/*******************************************
+ * Type tuple with 0, 1 or 2 types in it.
+ */
+TypeTuple::TypeTuple()
+ : Type(Ttuple)
+{
+ arguments = new Parameters();
+}
+
+TypeTuple::TypeTuple(Type *t1)
+ : Type(Ttuple)
+{
+ arguments = new Parameters();
+ arguments->push(new Parameter(0, t1, NULL, NULL));
+}
+
+TypeTuple::TypeTuple(Type *t1, Type *t2)
+ : Type(Ttuple)
+{
+ arguments = new Parameters();
+ arguments->push(new Parameter(0, t1, NULL, NULL));
+ arguments->push(new Parameter(0, t2, NULL, NULL));
+}
+
+const char *TypeTuple::kind()
+{
+ return "tuple";
+}
+
+Type *TypeTuple::syntaxCopy()
+{
+ Parameters *args = Parameter::arraySyntaxCopy(arguments);
+ Type *t = new TypeTuple(args);
+ t->mod = mod;
+ return t;
+}
+
+Type *TypeTuple::semantic(Loc, Scope *)
+{
+ //printf("TypeTuple::semantic(this = %p)\n", this);
+ //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
+ if (!deco)
+ deco = merge()->deco;
+
+ /* Don't return merge(), because a tuple with one type has the
+ * same deco as that type.
+ */
+ return this;
+}
+
+bool TypeTuple::equals(RootObject *o)
+{
+ Type *t = (Type *)o;
+ //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars());
+ if (this == t)
+ return true;
+ if (t->ty == Ttuple)
+ {
+ TypeTuple *tt = (TypeTuple *)t;
+ if (arguments->dim == tt->arguments->dim)
+ {
+ for (size_t i = 0; i < tt->arguments->dim; i++)
+ {
+ Parameter *arg1 = (*arguments)[i];
+ Parameter *arg2 = (*tt->arguments)[i];
+ if (!arg1->type->equals(arg2->type))
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+Expression *TypeTuple::getProperty(Loc loc, Identifier *ident, int flag)
+{
+ Expression *e;
+
+ if (ident == Id::length)
+ {
+ e = new IntegerExp(loc, arguments->dim, Type::tsize_t);
+ }
+ else if (ident == Id::_init)
+ {
+ e = defaultInitLiteral(loc);
+ }
+ else if (flag)
+ {
+ e = NULL;
+ }
+ else
+ {
+ error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars());
+ e = new ErrorExp();
+ }
+ return e;
+}
+
+Expression *TypeTuple::defaultInit(Loc loc)
+{
+ Expressions *exps = new Expressions();
+ exps->setDim(arguments->dim);
+ for (size_t i = 0; i < arguments->dim; i++)
+ {
+ Parameter *p = (*arguments)[i];
+ assert(p->type);
+ Expression *e = p->type->defaultInitLiteral(loc);
+ if (e->op == TOKerror)
+ return e;
+ (*exps)[i] = e;
+ }
+ return new TupleExp(loc, exps);
+}
+
+/***************************** TypeSlice *****************************/
+
+/* This is so we can slice a TypeTuple */
+
+TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr)
+ : TypeNext(Tslice, next)
+{
+ //printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars());
+ this->lwr = lwr;
+ this->upr = upr;
+}
+
+const char *TypeSlice::kind()
+{
+ return "slice";
+}
+
+Type *TypeSlice::syntaxCopy()
+{
+ Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy());
+ t->mod = mod;
+ return t;
+}
+
+Type *TypeSlice::semantic(Loc loc, Scope *sc)
+{
+ //printf("TypeSlice::semantic() %s\n", toChars());
+ Type *tn = next->semantic(loc, sc);
+ //printf("next: %s\n", tn->toChars());
+
+ Type *tbn = tn->toBasetype();
+ if (tbn->ty != Ttuple)
+ {
+ error(loc, "can only slice tuple types, not %s", tbn->toChars());
+ return Type::terror;
+ }
+ TypeTuple *tt = (TypeTuple *)tbn;
+
+ lwr = semanticLength(sc, tbn, lwr);
+ lwr = lwr->ctfeInterpret();
+ uinteger_t i1 = lwr->toUInteger();
+
+ upr = semanticLength(sc, tbn, upr);
+ upr = upr->ctfeInterpret();
+ uinteger_t i2 = upr->toUInteger();
+
+ if (!(i1 <= i2 && i2 <= tt->arguments->dim))
+ {
+ error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, tt->arguments->dim);
+ return Type::terror;
+ }
+
+ next = tn;
+ transitive();
+
+ Parameters *args = new Parameters;
+ args->reserve((size_t)(i2 - i1));
+ for (size_t i = (size_t)i1; i < (size_t)i2; i++)
+ {
+ Parameter *arg = (*tt->arguments)[i];
+ args->push(arg);
+ }
+ Type *t = new TypeTuple(args);
+ return t->semantic(loc, sc);
+}
+
+void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+ next->resolve(loc, sc, pe, pt, ps, intypeid);
+ if (*pe)
+ {
+ // It's really a slice expression
+ if (Dsymbol *s = getDsymbol(*pe))
+ *pe = new DsymbolExp(loc, s);
+ *pe = new ArrayExp(loc, *pe, new IntervalExp(loc, lwr, upr));
+ }
+ else if (*ps)
+ {
+ Dsymbol *s = *ps;
+ TupleDeclaration *td = s->isTupleDeclaration();
+ if (td)
+ {
+ /* It's a slice of a TupleDeclaration
+ */
+ ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+ sc = sc->startCTFE();
+ lwr = ::semantic(lwr, sc);
+ upr = ::semantic(upr, sc);
+ sc = sc->endCTFE();
+ sc = sc->pop();
+
+ lwr = lwr->ctfeInterpret();
+ upr = upr->ctfeInterpret();
+ uinteger_t i1 = lwr->toUInteger();
+ uinteger_t i2 = upr->toUInteger();
+
+ if (!(i1 <= i2 && i2 <= td->objects->dim))
+ {
+ error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->dim);
+ *ps = NULL;
+ *pt = Type::terror;
+ return;
+ }
+
+ if (i1 == 0 && i2 == td->objects->dim)
+ {
+ *ps = td;
+ return;
+ }
+
+ /* Create a new TupleDeclaration which
+ * is a slice [i1..i2] out of the old one.
+ */
+ Objects *objects = new Objects;
+ objects->setDim((size_t)(i2 - i1));
+ for (size_t i = 0; i < objects->dim; i++)
+ {
+ (*objects)[i] = (*td->objects)[(size_t)i1 + i];
+ }
+
+ TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
+ *ps = tds;
+ }
+ else
+ goto Ldefault;
+ }
+ else
+ {
+ if ((*pt)->ty != Terror)
+ next = *pt; // prevent re-running semantic() on 'next'
+ Ldefault:
+ Type::resolve(loc, sc, pe, pt, ps, intypeid);
+ }
+}
+
+/***************************** TypeNull *****************************/
+
+TypeNull::TypeNull()
+ : Type(Tnull)
+{
+}
+
+const char *TypeNull::kind()
+{
+ return "null";
+}
+
+Type *TypeNull::syntaxCopy()
+{
+ // No semantic analysis done, no need to copy
+ return this;
+}
+
+MATCH TypeNull::implicitConvTo(Type *to)
+{
+ //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to->toChars());
+ MATCH m = Type::implicitConvTo(to);
+ if (m != MATCHnomatch)
+ return m;
+
+ // NULL implicitly converts to any pointer type or dynamic array
+ //if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
+ {
+ Type *tb = to->toBasetype();
+ if (tb->ty == Tnull ||
+ tb->ty == Tpointer || tb->ty == Tarray ||
+ tb->ty == Taarray || tb->ty == Tclass ||
+ tb->ty == Tdelegate)
+ return MATCHconst;
+ }
+
+ return MATCHnomatch;
+}
+
+bool TypeNull::isBoolean()
+{
+ return true;
+}
+
+d_uns64 TypeNull::size(Loc loc)
+{
+ return tvoidptr->size(loc);
+}
+
+Expression *TypeNull::defaultInit(Loc)
+{
+ return new NullExp(Loc(), Type::tnull);
+}
+
+/***************************** Parameter *****************************/
+
+Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+{
+ this->type = type;
+ this->ident = ident;
+ this->storageClass = storageClass;
+ this->defaultArg = defaultArg;
+}
+
+Parameter *Parameter::create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg)
+{
+ return new Parameter(storageClass, type, ident, defaultArg);
+}
+
+Parameter *Parameter::syntaxCopy()
+{
+ return new Parameter(storageClass,
+ type ? type->syntaxCopy() : NULL,
+ ident,
+ defaultArg ? defaultArg->syntaxCopy() : NULL);
+}
+
+Parameters *Parameter::arraySyntaxCopy(Parameters *parameters)
+{
+ Parameters *params = NULL;
+ if (parameters)
+ {
+ params = new Parameters();
+ params->setDim(parameters->dim);
+ for (size_t i = 0; i < params->dim; i++)
+ (*params)[i] = (*parameters)[i]->syntaxCopy();
+ }
+ return params;
+}
+
+/****************************************************
+ * Determine if parameter is a lazy array of delegates.
+ * If so, return the return type of those delegates.
+ * If not, return NULL.
+ *
+ * Returns T if the type is one of the following forms:
+ * T delegate()[]
+ * T delegate()[dim]
+ */
+
+Type *Parameter::isLazyArray()
+{
+ Type *tb = type->toBasetype();
+ if (tb->ty == Tsarray || tb->ty == Tarray)
+ {
+ Type *tel = ((TypeArray *)tb)->next->toBasetype();
+ if (tel->ty == Tdelegate)
+ {
+ TypeDelegate *td = (TypeDelegate *)tel;
+ TypeFunction *tf = (TypeFunction *)td->next;
+
+ if (!tf->varargs && Parameter::dim(tf->parameters) == 0)
+ {
+ return tf->next; // return type of delegate
+ }
+ }
+ }
+ return NULL;
+}
+
+/***************************************
+ * Determine number of arguments, folding in tuples.
+ */
+
+static int dimDg(void *ctx, size_t, Parameter *)
+{
+ ++*(size_t *)ctx;
+ return 0;
+}
+
+size_t Parameter::dim(Parameters *parameters)
+{
+ size_t n = 0;
+ Parameter_foreach(parameters, &dimDg, &n);
+ return n;
+}
+
+/***************************************
+ * Get nth Parameter, folding in tuples.
+ * Returns:
+ * Parameter* nth Parameter
+ * NULL not found, *pn gets incremented by the number
+ * of Parameters
+ */
+
+struct GetNthParamCtx
+{
+ size_t nth;
+ Parameter *param;
+};
+
+static int getNthParamDg(void *ctx, size_t n, Parameter *p)
+{
+ GetNthParamCtx *c = (GetNthParamCtx *)ctx;
+ if (n == c->nth)
+ {
+ c->param = p;
+ return 1;
+ }
+ return 0;
+}
+
+Parameter *Parameter::getNth(Parameters *parameters, size_t nth, size_t *)
+{
+ GetNthParamCtx ctx = { nth, NULL };
+ int res = Parameter_foreach(parameters, &getNthParamDg, &ctx);
+ return res ? ctx.param : NULL;
+}
+
+/***************************************
+ * Expands tuples in args in depth first order. Calls
+ * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ */
+
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn)
+{
+ assert(dg);
+ if (!parameters)
+ return 0;
+
+ size_t n = pn ? *pn : 0; // take over index
+ int result = 0;
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ Parameter *p = (*parameters)[i];
+ Type *t = p->type->toBasetype();
+
+ if (t->ty == Ttuple)
+ {
+ TypeTuple *tu = (TypeTuple *)t;
+ result = Parameter_foreach(tu->arguments, dg, ctx, &n);
+ }
+ else
+ result = dg(ctx, n++, p);
+
+ if (result)
+ break;
+ }
+
+ if (pn)
+ *pn = n; // update index
+ return result;
+}
+
+
+const char *Parameter::toChars()
+{
+ return ident ? ident->toChars() : "__anonymous_param";
+}
+
+/*********************************
+ * Compute covariance of parameters `this` and `p`
+ * as determined by the storage classes of both.
+ * Params:
+ * p = Parameter to compare with
+ * Returns:
+ * true = `this` can be used in place of `p`
+ * false = nope
+ */
+bool Parameter::isCovariant(bool returnByRef, const Parameter *p) const
+{
+ const StorageClass stc = STCref | STCin | STCout | STClazy;
+ if ((this->storageClass & stc) != (p->storageClass & stc))
+ return false;
+
+ return isCovariantScope(returnByRef, this->storageClass, p->storageClass);
+}
+
+bool Parameter::isCovariantScope(bool returnByRef, StorageClass from, StorageClass to)
+{
+ if (from == to)
+ return true;
+
+ struct SR
+ {
+ /* Classification of 'scope-return-ref' possibilities
+ */
+ enum
+ {
+ SRNone,
+ SRScope,
+ SRReturnScope,
+ SRRef,
+ SRReturnRef,
+ SRRefScope,
+ SRReturnRef_Scope,
+ SRRef_ReturnScope,
+ SRMAX,
+ };
+
+ /* Shrinking the representation is necessary because StorageClass is so wide
+ * Params:
+ * returnByRef = true if the function returns by ref
+ * stc = storage class of parameter
+ */
+ static unsigned buildSR(bool returnByRef, StorageClass stc)
+ {
+ unsigned result;
+ switch (stc & (STCref | STCscope | STCreturn))
+ {
+ case 0: result = SRNone; break;
+ case STCref: result = SRRef; break;
+ case STCscope: result = SRScope; break;
+ case STCreturn | STCref: result = SRReturnRef; break;
+ case STCreturn | STCscope: result = SRReturnScope; break;
+ case STCref | STCscope: result = SRRefScope; break;
+ case STCreturn | STCref | STCscope:
+ result = returnByRef ? SRReturnRef_Scope : SRRef_ReturnScope;
+ break;
+ default:
+ assert(0);
+ }
+ return result;
+ }
+
+ static void covariantInit(bool covariant[SRMAX][SRMAX])
+ {
+ /* Initialize covariant[][] with this:
+
+ From\To n rs s
+ None X
+ ReturnScope X X
+ Scope X X X
+
+ From\To r rr rs rr-s r-rs
+ Ref X X
+ ReturnRef X
+ RefScope X X X X X
+ ReturnRef-Scope X X
+ Ref-ReturnScope X X X
+ */
+ for (int i = 0; i < SRMAX; i++)
+ {
+ covariant[i][i] = true;
+ covariant[SRRefScope][i] = true;
+ }
+ covariant[SRReturnScope][SRNone] = true;
+ covariant[SRScope ][SRNone] = true;
+ covariant[SRScope ][SRReturnScope] = true;
+
+ covariant[SRRef ][SRReturnRef] = true;
+ covariant[SRReturnRef_Scope][SRReturnRef] = true;
+ covariant[SRRef_ReturnScope][SRRef ] = true;
+ covariant[SRRef_ReturnScope][SRReturnRef] = true;
+ }
+ };
+
+ /* result is true if the 'from' can be used as a 'to'
+ */
+
+ if ((from ^ to) & STCref) // differing in 'ref' means no covariance
+ return false;
+
+ static bool covariant[SR::SRMAX][SR::SRMAX];
+ static bool init = false;
+ if (!init)
+ {
+ SR::covariantInit(covariant);
+ init = true;
+ }
+
+ return covariant[SR::buildSR(returnByRef, from)][SR::buildSR(returnByRef, to)];
+}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
new file mode 100644
index 0000000..c3b8a97
--- /dev/null
+++ b/gcc/d/dmd/mtype.h
@@ -0,0 +1,934 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/mtype.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "root/stringtable.h"
+#include "root/rmem.h" // for d_size_t
+
+#include "arraytypes.h"
+#include "expression.h"
+#include "visitor.h"
+
+struct Scope;
+class Identifier;
+class Expression;
+class StructDeclaration;
+class ClassDeclaration;
+class EnumDeclaration;
+class TypeInfoDeclaration;
+class Dsymbol;
+class TemplateInstance;
+class TemplateDeclaration;
+enum LINK;
+
+class TypeBasic;
+class Parameter;
+
+// Back end
+#ifdef IN_GCC
+typedef union tree_node type;
+#else
+typedef struct TYPE type;
+#endif
+
+void semanticTypeInfo(Scope *sc, Type *t);
+MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm = NULL, size_t inferStart = 0);
+StorageClass ModToStc(unsigned mod);
+
+enum ENUMTY
+{
+ Tarray, // slice array, aka T[]
+ Tsarray, // static array, aka T[dimension]
+ Taarray, // associative array, aka T[type]
+ Tpointer,
+ Treference,
+ Tfunction,
+ Tident,
+ Tclass,
+ Tstruct,
+ Tenum,
+
+ Tdelegate,
+ Tnone,
+ Tvoid,
+ Tint8,
+ Tuns8,
+ Tint16,
+ Tuns16,
+ Tint32,
+ Tuns32,
+ Tint64,
+
+ Tuns64,
+ Tfloat32,
+ Tfloat64,
+ Tfloat80,
+ Timaginary32,
+ Timaginary64,
+ Timaginary80,
+ Tcomplex32,
+ Tcomplex64,
+ Tcomplex80,
+
+ Tbool,
+ Tchar,
+ Twchar,
+ Tdchar,
+ Terror,
+ Tinstance,
+ Ttypeof,
+ Ttuple,
+ Tslice,
+ Treturn,
+
+ Tnull,
+ Tvector,
+ Tint128,
+ Tuns128,
+ TMAX
+};
+typedef unsigned char TY; // ENUMTY
+
+extern int Tsize_t;
+extern int Tptrdiff_t;
+
+#define SIZE_INVALID (~(d_uns64)0) // error return from size() functions
+
+
+/**
+ * type modifiers
+ * pick this order of numbers so switch statements work better
+ */
+enum MODFlags
+{
+ MODconst = 1, // type is const
+ MODimmutable = 4, // type is immutable
+ MODshared = 2, // type is shared
+ MODwild = 8, // type is wild
+ MODwildconst = (MODwild | MODconst), // type is wild const
+ MODmutable = 0x10 // type is mutable (only used in wildcard matching)
+};
+typedef unsigned char MOD;
+
+// These tables are for implicit conversion of binary ops;
+// the indices are the type of operand one, followed by operand two.
+extern unsigned char impcnvResult[TMAX][TMAX];
+extern unsigned char impcnvType1[TMAX][TMAX];
+extern unsigned char impcnvType2[TMAX][TMAX];
+
+// If !=0, give warning on implicit conversion
+extern unsigned char impcnvWarn[TMAX][TMAX];
+
+class Type : public RootObject
+{
+public:
+ TY ty;
+ MOD mod; // modifiers MODxxxx
+ char *deco;
+
+ /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc.
+ * They should not be referenced by anybody but mtype.c.
+ * They can be NULL if not lazily evaluated yet.
+ * Note that there is no "shared immutable", because that is just immutable
+ * Naked == no MOD bits
+ */
+
+ Type *cto; // MODconst ? naked version of this type : const version
+ Type *ito; // MODimmutable ? naked version of this type : immutable version
+ Type *sto; // MODshared ? naked version of this type : shared mutable version
+ Type *scto; // MODshared | MODconst ? naked version of this type : shared const version
+ Type *wto; // MODwild ? naked version of this type : wild version
+ Type *wcto; // MODwildconst ? naked version of this type : wild const version
+ Type *swto; // MODshared | MODwild ? naked version of this type : shared wild version
+ Type *swcto; // MODshared | MODwildconst ? naked version of this type : shared wild const version
+
+ Type *pto; // merged pointer to this type
+ Type *rto; // reference to this type
+ Type *arrayof; // array of this type
+ TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type
+
+ type *ctype; // for back end
+
+ static Type *tvoid;
+ static Type *tint8;
+ static Type *tuns8;
+ static Type *tint16;
+ static Type *tuns16;
+ static Type *tint32;
+ static Type *tuns32;
+ static Type *tint64;
+ static Type *tuns64;
+ static Type *tint128;
+ static Type *tuns128;
+ static Type *tfloat32;
+ static Type *tfloat64;
+ static Type *tfloat80;
+
+ static Type *timaginary32;
+ static Type *timaginary64;
+ static Type *timaginary80;
+
+ static Type *tcomplex32;
+ static Type *tcomplex64;
+ static Type *tcomplex80;
+
+ static Type *tbool;
+ static Type *tchar;
+ static Type *twchar;
+ static Type *tdchar;
+
+ // Some special types
+ static Type *tshiftcnt;
+ static Type *tvoidptr; // void*
+ static Type *tstring; // immutable(char)[]
+ static Type *twstring; // immutable(wchar)[]
+ static Type *tdstring; // immutable(dchar)[]
+ static Type *tvalist; // va_list alias
+ static Type *terror; // for error recovery
+ static Type *tnull; // for null type
+
+ static Type *tsize_t; // matches size_t alias
+ static Type *tptrdiff_t; // matches ptrdiff_t alias
+ static Type *thash_t; // matches hash_t alias
+
+ static ClassDeclaration *dtypeinfo;
+ static ClassDeclaration *typeinfoclass;
+ static ClassDeclaration *typeinfointerface;
+ static ClassDeclaration *typeinfostruct;
+ static ClassDeclaration *typeinfopointer;
+ static ClassDeclaration *typeinfoarray;
+ static ClassDeclaration *typeinfostaticarray;
+ static ClassDeclaration *typeinfoassociativearray;
+ static ClassDeclaration *typeinfovector;
+ static ClassDeclaration *typeinfoenum;
+ static ClassDeclaration *typeinfofunction;
+ static ClassDeclaration *typeinfodelegate;
+ static ClassDeclaration *typeinfotypelist;
+ static ClassDeclaration *typeinfoconst;
+ static ClassDeclaration *typeinfoinvariant;
+ static ClassDeclaration *typeinfoshared;
+ static ClassDeclaration *typeinfowild;
+
+ static TemplateDeclaration *rtinfo;
+
+ static Type *basic[TMAX];
+ static unsigned char sizeTy[TMAX];
+ static StringTable stringtable;
+
+ Type(TY ty);
+ virtual const char *kind();
+ Type *copy();
+ virtual Type *syntaxCopy();
+ bool equals(RootObject *o);
+ bool equivalent(Type *t);
+ // kludge for template.isType()
+ int dyncast() const { return DYNCAST_TYPE; }
+ int covariant(Type *t, StorageClass *pstc = NULL, bool fix17349 = true);
+ const char *toChars();
+ char *toPrettyChars(bool QualifyTypes = false);
+ static void _init();
+
+ d_uns64 size();
+ virtual d_uns64 size(Loc loc);
+ virtual unsigned alignsize();
+ virtual Type *semantic(Loc loc, Scope *sc);
+ Type *trySemantic(Loc loc, Scope *sc);
+ Type *merge();
+ Type *merge2();
+ void modToBuffer(OutBuffer *buf);
+ char *modToChars();
+
+ /** For each active modifier (MODconst, MODimmutable, etc) call fp with a
+ void* for the work param and a string representation of the attribute. */
+ int modifiersApply(void *param, int (*fp)(void *, const char *));
+
+ virtual bool isintegral();
+ virtual bool isfloating(); // real, imaginary, or complex
+ virtual bool isreal();
+ virtual bool isimaginary();
+ virtual bool iscomplex();
+ virtual bool isscalar();
+ virtual bool isunsigned();
+ virtual bool isscope();
+ virtual bool isString();
+ virtual bool isAssignable();
+ virtual bool isBoolean();
+ virtual void checkDeprecated(Loc loc, Scope *sc);
+ bool isConst() const { return (mod & MODconst) != 0; }
+ bool isImmutable() const { return (mod & MODimmutable) != 0; }
+ bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; }
+ bool isShared() const { return (mod & MODshared) != 0; }
+ bool isSharedConst() const { return (mod & (MODshared | MODconst)) == (MODshared | MODconst); }
+ bool isWild() const { return (mod & MODwild) != 0; }
+ bool isWildConst() const { return (mod & MODwildconst) == MODwildconst; }
+ bool isSharedWild() const { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); }
+ bool isNaked() const { return mod == 0; }
+ Type *nullAttributes();
+ Type *constOf();
+ Type *immutableOf();
+ Type *mutableOf();
+ Type *sharedOf();
+ Type *sharedConstOf();
+ Type *unSharedOf();
+ Type *wildOf();
+ Type *wildConstOf();
+ Type *sharedWildOf();
+ Type *sharedWildConstOf();
+ void fixTo(Type *t);
+ void check();
+ Type *addSTC(StorageClass stc);
+ Type *castMod(MOD mod);
+ Type *addMod(MOD mod);
+ virtual Type *addStorageClass(StorageClass stc);
+ Type *pointerTo();
+ Type *referenceTo();
+ Type *arrayOf();
+ Type *sarrayOf(dinteger_t dim);
+ Type *aliasthisOf();
+ bool checkAliasThisRec();
+ virtual Type *makeConst();
+ virtual Type *makeImmutable();
+ virtual Type *makeShared();
+ virtual Type *makeSharedConst();
+ virtual Type *makeWild();
+ virtual Type *makeWildConst();
+ virtual Type *makeSharedWild();
+ virtual Type *makeSharedWildConst();
+ virtual Type *makeMutable();
+ virtual Dsymbol *toDsymbol(Scope *sc);
+ virtual Type *toBasetype();
+ virtual bool isBaseOf(Type *t, int *poffset);
+ virtual MATCH implicitConvTo(Type *to);
+ virtual MATCH constConv(Type *to);
+ virtual unsigned char deduceWild(Type *t, bool isRef);
+ virtual Type *substWildTo(unsigned mod);
+
+ Type *unqualify(unsigned m);
+
+ virtual Type *toHeadMutable();
+ virtual ClassDeclaration *isClassHandle();
+ virtual Expression *getProperty(Loc loc, Identifier *ident, int flag);
+ virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ virtual structalign_t alignment();
+ Expression *noMember(Scope *sc, Expression *e, Identifier *ident, int flag);
+ virtual Expression *defaultInit(Loc loc = Loc());
+ virtual Expression *defaultInitLiteral(Loc loc);
+ virtual bool isZeroInit(Loc loc = Loc()); // if initializer is 0
+ Identifier *getTypeInfoIdent();
+ virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ void resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps);
+ virtual int hasWild() const;
+ virtual bool hasPointers();
+ virtual bool hasVoidInitPointers();
+ virtual Type *nextOf();
+ Type *baseElemOf();
+ uinteger_t sizemask();
+ virtual bool needsDestruction();
+ virtual bool needsNested();
+ void checkComplexTransition(Loc loc);
+
+ static void error(Loc loc, const char *format, ...);
+ static void warning(Loc loc, const char *format, ...);
+
+ // For eliminating dynamic_cast
+ virtual TypeBasic *isTypeBasic();
+ virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeError : public Type
+{
+public:
+ TypeError();
+ Type *syntaxCopy();
+
+ d_uns64 size(Loc loc);
+ Expression *getProperty(Loc loc, Identifier *ident, int flag);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ Expression *defaultInit(Loc loc);
+ Expression *defaultInitLiteral(Loc loc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeNext : public Type
+{
+public:
+ Type *next;
+
+ TypeNext(TY ty, Type *next);
+ void checkDeprecated(Loc loc, Scope *sc);
+ int hasWild() const;
+ Type *nextOf();
+ Type *makeConst();
+ Type *makeImmutable();
+ Type *makeShared();
+ Type *makeSharedConst();
+ Type *makeWild();
+ Type *makeWildConst();
+ Type *makeSharedWild();
+ Type *makeSharedWildConst();
+ Type *makeMutable();
+ MATCH constConv(Type *to);
+ unsigned char deduceWild(Type *t, bool isRef);
+ void transitive();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeBasic : public Type
+{
+public:
+ const char *dstring;
+ unsigned flags;
+
+ TypeBasic(TY ty);
+ const char *kind();
+ Type *syntaxCopy();
+ d_uns64 size(Loc loc) /*const*/;
+ unsigned alignsize();
+ Expression *getProperty(Loc loc, Identifier *ident, int flag);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ bool isintegral();
+ bool isfloating() /*const*/;
+ bool isreal() /*const*/;
+ bool isimaginary() /*const*/;
+ bool iscomplex() /*const*/;
+ bool isscalar() /*const*/;
+ bool isunsigned() /*const*/;
+ MATCH implicitConvTo(Type *to);
+ Expression *defaultInit(Loc loc);
+ bool isZeroInit(Loc loc) /*const*/;
+
+ // For eliminating dynamic_cast
+ TypeBasic *isTypeBasic();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeVector : public Type
+{
+public:
+ Type *basetype;
+
+ TypeVector(Type *basetype);
+ static TypeVector *create(Loc loc, Type *basetype);
+ const char *kind();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ d_uns64 size(Loc loc);
+ unsigned alignsize();
+ Expression *getProperty(Loc loc, Identifier *ident, int flag);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ bool isintegral();
+ bool isfloating();
+ bool isscalar();
+ bool isunsigned();
+ bool isBoolean() /*const*/;
+ MATCH implicitConvTo(Type *to);
+ Expression *defaultInit(Loc loc);
+ Expression *defaultInitLiteral(Loc loc);
+ TypeBasic *elementType();
+ bool isZeroInit(Loc loc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeArray : public TypeNext
+{
+public:
+ TypeArray(TY ty, Type *next);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Static array, one with a fixed dimension
+class TypeSArray : public TypeArray
+{
+public:
+ Expression *dim;
+
+ TypeSArray(Type *t, Expression *dim);
+ const char *kind();
+ Type *syntaxCopy();
+ d_uns64 size(Loc loc);
+ unsigned alignsize();
+ Type *semantic(Loc loc, Scope *sc);
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ bool isString();
+ bool isZeroInit(Loc loc);
+ structalign_t alignment();
+ MATCH constConv(Type *to);
+ MATCH implicitConvTo(Type *to);
+ Expression *defaultInit(Loc loc);
+ Expression *defaultInitLiteral(Loc loc);
+ bool hasPointers();
+ bool needsDestruction();
+ bool needsNested();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Dynamic array, no dimension
+class TypeDArray : public TypeArray
+{
+public:
+ TypeDArray(Type *t);
+ const char *kind();
+ Type *syntaxCopy();
+ d_uns64 size(Loc loc) /*const*/;
+ unsigned alignsize() /*const*/;
+ Type *semantic(Loc loc, Scope *sc);
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ bool isString();
+ bool isZeroInit(Loc loc) /*const*/;
+ bool isBoolean() /*const*/;
+ MATCH implicitConvTo(Type *to);
+ Expression *defaultInit(Loc loc);
+ bool hasPointers() /*const*/;
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeAArray : public TypeArray
+{
+public:
+ Type *index; // key type
+ Loc loc;
+ Scope *sc;
+
+ TypeAArray(Type *t, Type *index);
+ static TypeAArray *create(Type *t, Type *index);
+ const char *kind();
+ Type *syntaxCopy();
+ d_uns64 size(Loc loc);
+ Type *semantic(Loc loc, Scope *sc);
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ Expression *defaultInit(Loc loc);
+ bool isZeroInit(Loc loc) /*const*/;
+ bool isBoolean() /*const*/;
+ bool hasPointers() /*const*/;
+ MATCH implicitConvTo(Type *to);
+ MATCH constConv(Type *to);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypePointer : public TypeNext
+{
+public:
+ TypePointer(Type *t);
+ static TypePointer *create(Type *t);
+ const char *kind();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ d_uns64 size(Loc loc) /*const*/;
+ MATCH implicitConvTo(Type *to);
+ MATCH constConv(Type *to);
+ bool isscalar() /*const*/;
+ Expression *defaultInit(Loc loc);
+ bool isZeroInit(Loc loc) /*const*/;
+ bool hasPointers() /*const*/;
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeReference : public TypeNext
+{
+public:
+ TypeReference(Type *t);
+ const char *kind();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ d_uns64 size(Loc loc) /*const*/;
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ Expression *defaultInit(Loc loc);
+ bool isZeroInit(Loc loc) /*const*/;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+enum RET
+{
+ RETregs = 1, // returned in registers
+ RETstack = 2 // returned on stack
+};
+
+enum TRUST
+{
+ TRUSTdefault = 0,
+ TRUSTsystem = 1, // @system (same as TRUSTdefault)
+ TRUSTtrusted = 2, // @trusted
+ TRUSTsafe = 3 // @safe
+};
+
+// in hdrgen.c
+void trustToBuffer(OutBuffer *buf, TRUST trust);
+const char *trustToChars(TRUST trust);
+
+enum TRUSTformat
+{
+ TRUSTformatDefault, // do not emit @system when trust == TRUSTdefault
+ TRUSTformatSystem // emit @system when trust == TRUSTdefault
+};
+
+enum PURE
+{
+ PUREimpure = 0, // not pure at all
+ PUREfwdref = 1, // it's pure, but not known which level yet
+ PUREweak = 2, // no mutable globals are read or written
+ PUREconst = 3, // parameters are values or const
+ PUREstrong = 4 // parameters are values or immutable
+};
+
+class TypeFunction : public TypeNext
+{
+public:
+ // .next is the return type
+
+ Parameters *parameters; // function parameters
+ int varargs; // 1: T t, ...) style for variable number of arguments
+ // 2: T t ...) style for variable number of arguments
+ bool isnothrow; // true: nothrow
+ bool isnogc; // true: is @nogc
+ bool isproperty; // can be called without parentheses
+ bool isref; // true: returns a reference
+ bool isreturn; // true: 'this' is returned by ref
+ bool isscope; // true: 'this' is scope
+ bool isscopeinferred; // true: 'this' is scope from inference
+ LINK linkage; // calling convention
+ TRUST trust; // level of trust
+ PURE purity; // PURExxxx
+ unsigned char iswild; // bit0: inout on params, bit1: inout on qualifier
+ Expressions *fargs; // function arguments
+
+ int inuse;
+
+ TypeFunction(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc = 0);
+ static TypeFunction *create(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc = 0);
+ const char *kind();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ void purityLevel();
+ bool hasLazyParameters();
+ bool parameterEscapes(Parameter *p);
+ StorageClass parameterStorageClass(Parameter *p);
+ Type *addStorageClass(StorageClass stc);
+
+ /** For each active attribute (ref/const/nogc/etc) call fp with a void* for the
+ work param and a string representation of the attribute. */
+ int attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat = TRUSTformatDefault);
+
+ Type *substWildTo(unsigned mod);
+ MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0);
+ bool checkRetType(Loc loc);
+
+ Expression *defaultInit(Loc loc) /*const*/;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeDelegate : public TypeNext
+{
+public:
+ // .next is a TypeFunction
+
+ TypeDelegate(Type *t);
+ static TypeDelegate *create(Type *t);
+ const char *kind();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ Type *addStorageClass(StorageClass stc);
+ d_uns64 size(Loc loc) /*const*/;
+ unsigned alignsize() /*const*/;
+ MATCH implicitConvTo(Type *to);
+ Expression *defaultInit(Loc loc);
+ bool isZeroInit(Loc loc) /*const*/;
+ bool isBoolean() /*const*/;
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ bool hasPointers() /*const*/;
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeQualified : public Type
+{
+public:
+ Loc loc;
+ // array of Identifier and TypeInstance,
+ // representing ident.ident!tiargs.ident. ... etc.
+ Objects idents;
+
+ TypeQualified(TY ty, Loc loc);
+ void syntaxCopyHelper(TypeQualified *t);
+ void addIdent(Identifier *ident);
+ void addInst(TemplateInstance *inst);
+ void addIndex(RootObject *expr);
+ d_uns64 size(Loc loc);
+
+ void resolveTupleIndex(Loc loc, Scope *sc, Dsymbol *s,
+ Expression **pe, Type **pt, Dsymbol **ps, RootObject *oindex);
+ void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym,
+ Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeIdentifier : public TypeQualified
+{
+public:
+ Identifier *ident;
+ Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
+
+ TypeIdentifier(Loc loc, Identifier *ident);
+ const char *kind();
+ Type *syntaxCopy();
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ Dsymbol *toDsymbol(Scope *sc);
+ Type *semantic(Loc loc, Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Similar to TypeIdentifier, but with a TemplateInstance as the root
+ */
+class TypeInstance : public TypeQualified
+{
+public:
+ TemplateInstance *tempinst;
+
+ TypeInstance(Loc loc, TemplateInstance *tempinst);
+ const char *kind();
+ Type *syntaxCopy();
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ Type *semantic(Loc loc, Scope *sc);
+ Dsymbol *toDsymbol(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeTypeof : public TypeQualified
+{
+public:
+ Expression *exp;
+ int inuse;
+
+ TypeTypeof(Loc loc, Expression *exp);
+ const char *kind();
+ Type *syntaxCopy();
+ Dsymbol *toDsymbol(Scope *sc);
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ Type *semantic(Loc loc, Scope *sc);
+ d_uns64 size(Loc loc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeReturn : public TypeQualified
+{
+public:
+ TypeReturn(Loc loc);
+ const char *kind();
+ Type *syntaxCopy();
+ Dsymbol *toDsymbol(Scope *sc);
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ Type *semantic(Loc loc, Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// Whether alias this dependency is recursive or not.
+enum AliasThisRec
+{
+ RECno = 0, // no alias this recursion
+ RECyes = 1, // alias this has recursive dependency
+ RECfwdref = 2, // not yet known
+ RECtypeMask = 3,// mask to read no/yes/fwdref
+
+ RECtracing = 0x4, // mark in progress of implicitConvTo/deduceWild
+ RECtracingDT = 0x8 // mark in progress of deduceType
+};
+
+class TypeStruct : public Type
+{
+public:
+ StructDeclaration *sym;
+ AliasThisRec att;
+ CPPMANGLE cppmangle;
+
+ TypeStruct(StructDeclaration *sym);
+ static TypeStruct *create(StructDeclaration *sym);
+ const char *kind();
+ d_uns64 size(Loc loc);
+ unsigned alignsize();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ Dsymbol *toDsymbol(Scope *sc);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ structalign_t alignment();
+ Expression *defaultInit(Loc loc);
+ Expression *defaultInitLiteral(Loc loc);
+ bool isZeroInit(Loc loc) /*const*/;
+ bool isAssignable();
+ bool isBoolean() /*const*/;
+ bool needsDestruction() /*const*/;
+ bool needsNested();
+ bool hasPointers();
+ bool hasVoidInitPointers();
+ MATCH implicitConvTo(Type *to);
+ MATCH constConv(Type *to);
+ unsigned char deduceWild(Type *t, bool isRef);
+ Type *toHeadMutable();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeEnum : public Type
+{
+public:
+ EnumDeclaration *sym;
+
+ TypeEnum(EnumDeclaration *sym);
+ const char *kind();
+ Type *syntaxCopy();
+ d_uns64 size(Loc loc);
+ unsigned alignsize();
+ Type *semantic(Loc loc, Scope *sc);
+ Dsymbol *toDsymbol(Scope *sc);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ Expression *getProperty(Loc loc, Identifier *ident, int flag);
+ bool isintegral();
+ bool isfloating();
+ bool isreal();
+ bool isimaginary();
+ bool iscomplex();
+ bool isscalar();
+ bool isunsigned();
+ bool isBoolean();
+ bool isString();
+ bool isAssignable();
+ bool needsDestruction();
+ bool needsNested();
+ MATCH implicitConvTo(Type *to);
+ MATCH constConv(Type *to);
+ Type *toBasetype();
+ Expression *defaultInit(Loc loc);
+ bool isZeroInit(Loc loc);
+ bool hasPointers();
+ bool hasVoidInitPointers();
+ Type *nextOf();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeClass : public Type
+{
+public:
+ ClassDeclaration *sym;
+ AliasThisRec att;
+ CPPMANGLE cppmangle;
+
+ TypeClass(ClassDeclaration *sym);
+ const char *kind();
+ d_uns64 size(Loc loc) /*const*/;
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ Dsymbol *toDsymbol(Scope *sc);
+ Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
+ ClassDeclaration *isClassHandle();
+ bool isBaseOf(Type *t, int *poffset);
+ MATCH implicitConvTo(Type *to);
+ MATCH constConv(Type *to);
+ unsigned char deduceWild(Type *t, bool isRef);
+ Type *toHeadMutable();
+ Expression *defaultInit(Loc loc);
+ bool isZeroInit(Loc loc) /*const*/;
+ bool isscope() /*const*/;
+ bool isBoolean() /*const*/;
+ bool hasPointers() /*const*/;
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeTuple : public Type
+{
+public:
+ Parameters *arguments; // types making up the tuple
+
+ TypeTuple(Parameters *arguments);
+ TypeTuple(Expressions *exps);
+ static TypeTuple *create(Parameters *arguments);
+ TypeTuple();
+ TypeTuple(Type *t1);
+ TypeTuple(Type *t1, Type *t2);
+ const char *kind();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ bool equals(RootObject *o);
+ Expression *getProperty(Loc loc, Identifier *ident, int flag);
+ Expression *defaultInit(Loc loc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeSlice : public TypeNext
+{
+public:
+ Expression *lwr;
+ Expression *upr;
+
+ TypeSlice(Type *next, Expression *lwr, Expression *upr);
+ const char *kind();
+ Type *syntaxCopy();
+ Type *semantic(Loc loc, Scope *sc);
+ void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeNull : public Type
+{
+public:
+ TypeNull();
+ const char *kind();
+
+ Type *syntaxCopy();
+ MATCH implicitConvTo(Type *to);
+ bool isBoolean() /*const*/;
+
+ d_uns64 size(Loc loc) /*const*/;
+ Expression *defaultInit(Loc loc) /*const*/;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
+//enum InOut { None, In, Out, InOut, Lazy };
+
+class Parameter : public RootObject
+{
+public:
+ //enum InOut inout;
+ StorageClass storageClass;
+ Type *type;
+ Identifier *ident;
+ Expression *defaultArg;
+
+ Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg);
+ static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg);
+ Parameter *syntaxCopy();
+ Type *isLazyArray();
+ // kludge for template.isType()
+ int dyncast() const { return DYNCAST_PARAMETER; }
+ virtual void accept(Visitor *v) { v->visit(this); }
+
+ static Parameters *arraySyntaxCopy(Parameters *parameters);
+ static size_t dim(Parameters *parameters);
+ static Parameter *getNth(Parameters *parameters, d_size_t nth, d_size_t *pn = NULL);
+ const char *toChars();
+ bool isCovariant(bool returnByRef, const Parameter *p) const;
+ static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to);
+};
+
+bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2);
+bool arrayTypeCompatibleWithoutCasting(Type *t1, Type *t2);
diff --git a/gcc/d/dmd/nogc.c b/gcc/d/dmd/nogc.c
new file mode 100644
index 0000000..2b8255e
--- /dev/null
+++ b/gcc/d/dmd/nogc.c
@@ -0,0 +1,241 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/nogc.c
+ */
+
+#include "mars.h"
+#include "init.h"
+#include "visitor.h"
+#include "expression.h"
+#include "statement.h"
+#include "declaration.h"
+#include "id.h"
+#include "module.h"
+#include "scope.h"
+#include "tokens.h"
+#include "aggregate.h"
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+
+void FuncDeclaration::printGCUsage(Loc loc, const char* warn)
+{
+ if (!global.params.vgc)
+ return;
+
+ Module *m = getModule();
+ if (m && m->isRoot() && !inUnittest())
+ {
+ message(loc, "vgc: %s", warn);
+ }
+}
+
+/**************************************
+ * Look for GC-allocations
+ */
+class NOGCVisitor : public StoppableVisitor
+{
+public:
+ FuncDeclaration *f;
+ bool err;
+
+ NOGCVisitor(FuncDeclaration *f)
+ {
+ this->f = f;
+ this->err = false;
+ }
+
+ void doCond(Expression *exp)
+ {
+ if (exp)
+ walkPostorder(exp, this);
+ }
+
+ void visit(Expression *)
+ {
+ }
+
+ void visit(DeclarationExp *e)
+ {
+ // Note that, walkPostorder does not support DeclarationExp today.
+ VarDeclaration *v = e->declaration->isVarDeclaration();
+ if (v && !(v->storage_class & STCmanifest) && !v->isDataseg() && v->_init)
+ {
+ if (ExpInitializer *ei = v->_init->isExpInitializer())
+ {
+ doCond(ei->exp);
+ }
+ }
+ }
+
+ void visit(CallExp *)
+ {
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ if (e->type->ty != Tarray || !e->elements || !e->elements->dim)
+ return;
+
+ if (f->setGC())
+ {
+ e->error("array literal in @nogc %s '%s' may cause GC allocation",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "array literal may cause GC allocation");
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ if (!e->keys->dim)
+ return;
+
+ if (f->setGC())
+ {
+ e->error("associative array literal in @nogc %s '%s' may cause GC allocation",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "associative array literal may cause GC allocation");
+ }
+
+ void visit(NewExp *e)
+ {
+ if (e->member && !e->member->isNogc() && f->setGC())
+ {
+ // @nogc-ness is already checked in NewExp::semantic
+ return;
+ }
+ if (e->onstack)
+ return;
+ if (e->allocator)
+ return;
+
+ if (f->setGC())
+ {
+ e->error("cannot use 'new' in @nogc %s '%s'",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "'new' causes GC allocation");
+ }
+
+ void visit(DeleteExp *e)
+ {
+ if (e->e1->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
+ if (v && v->onstack)
+ return; // delete for scope allocated class object
+ }
+
+ Type *tb = e->e1->type->toBasetype();
+ AggregateDeclaration *ad = NULL;
+ switch (tb->ty)
+ {
+ case Tclass:
+ ad = ((TypeClass *)tb)->sym;
+ break;
+
+ case Tpointer:
+ tb = ((TypePointer *)tb)->next->toBasetype();
+ if (tb->ty == Tstruct)
+ ad = ((TypeStruct *)tb)->sym;
+ break;
+
+ default:
+ break;
+ }
+ if (ad && ad->aggDelete)
+ return;
+
+ if (f->setGC())
+ {
+ e->error("cannot use 'delete' in @nogc %s '%s'",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "'delete' requires GC");
+ }
+
+ void visit(IndexExp* e)
+ {
+ Type *t1b = e->e1->type->toBasetype();
+ if (t1b->ty == Taarray)
+ {
+ if (f->setGC())
+ {
+ e->error("indexing an associative array in @nogc %s '%s' may cause GC allocation",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "indexing an associative array may cause GC allocation");
+ }
+ }
+
+ void visit(AssignExp *e)
+ {
+ if (e->e1->op == TOKarraylength)
+ {
+ if (f->setGC())
+ {
+ e->error("setting 'length' in @nogc %s '%s' may cause GC allocation",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "setting 'length' may cause GC allocation");
+ }
+ }
+
+ void visit(CatAssignExp *e)
+ {
+ if (f->setGC())
+ {
+ e->error("cannot use operator ~= in @nogc %s '%s'",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "operator ~= may cause GC allocation");
+ }
+
+ void visit(CatExp *e)
+ {
+ if (f->setGC())
+ {
+ e->error("cannot use operator ~ in @nogc %s '%s'",
+ f->kind(), f->toPrettyChars());
+ err = true;
+ return;
+ }
+ f->printGCUsage(e->loc, "operator ~ may cause GC allocation");
+ }
+};
+
+Expression *checkGC(Scope *sc, Expression *e)
+{
+ FuncDeclaration *f = sc->func;
+ if (e && e->op != TOKerror &&
+ f && sc->intypeof != 1 && !(sc->flags & SCOPEctfe) &&
+ ((f->type->ty == Tfunction && ((TypeFunction *)f->type)->isnogc) ||
+ (f->flags & FUNCFLAGnogcInprocess) ||
+ global.params.vgc))
+ {
+ NOGCVisitor gcv(f);
+ walkPostorder(e, &gcv);
+ if (gcv.err)
+ return new ErrorExp();
+ }
+ return e;
+}
diff --git a/gcc/d/dmd/nspace.c b/gcc/d/dmd/nspace.c
new file mode 100644
index 0000000..2bd6b96
--- /dev/null
+++ b/gcc/d/dmd/nspace.c
@@ -0,0 +1,234 @@
+
+// Compiler implementation of the D programming language
+// Copyright: Copyright (C) 2014-2018 by The D Language Foundation, All Rights Reserved
+// Authors: Walter Bright, http://www.digitalmars.com
+// License: http://boost.org/LICENSE_1_0.txt
+// Source: https://github.com/D-Programming-Language/dmd/blob/master/src/nspace.c
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "nspace.h"
+#include "identifier.h"
+#include "scope.h"
+
+/* This implements namespaces.
+ */
+
+Nspace::Nspace(Loc loc, Identifier *ident, Dsymbols *members)
+ : ScopeDsymbol(ident)
+{
+ //printf("Nspace::Nspace(ident = %s)\n", ident->toChars());
+ this->loc = loc;
+ this->members = members;
+}
+
+Dsymbol *Nspace::syntaxCopy(Dsymbol *)
+{
+ Nspace *ns = new Nspace(loc, ident, NULL);
+ return ScopeDsymbol::syntaxCopy(ns);
+}
+
+void Nspace::addMember(Scope *sc, ScopeDsymbol *sds)
+{
+ ScopeDsymbol::addMember(sc, sds);
+ if (members)
+ {
+ if (!symtab)
+ symtab = new DsymbolTable();
+ // The namespace becomes 'imported' into the enclosing scope
+ for (Scope *sce = sc; 1; sce = sce->enclosing)
+ {
+ ScopeDsymbol *sds2 = sce->scopesym;
+ if (sds2)
+ {
+ sds2->importScope(this, Prot(PROTpublic));
+ break;
+ }
+ }
+ assert(sc);
+ sc = sc->push(this);
+ sc->linkage = LINKcpp; // namespaces default to C++ linkage
+ sc->parent = this;
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("add %s to scope %s\n", s->toChars(), toChars());
+ s->addMember(sc, this);
+ }
+ sc->pop();
+ }
+}
+
+void Nspace::setScope(Scope *sc)
+{
+ ScopeDsymbol::setScope(sc);
+ if (members)
+ {
+ assert(sc);
+ sc = sc->push(this);
+ sc->linkage = LINKcpp; // namespaces default to C++ linkage
+ sc->parent = this;
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->setScope(sc);
+ }
+ sc->pop();
+ }
+}
+
+void Nspace::semantic(Scope *sc)
+{
+ if (semanticRun != PASSinit)
+ return;
+ if (_scope)
+ {
+ sc = _scope;
+ _scope = NULL;
+ }
+ if (!sc)
+ return;
+
+ semanticRun = PASSsemantic;
+ parent = sc->parent;
+ if (members)
+ {
+ assert(sc);
+ sc = sc->push(this);
+ sc->linkage = LINKcpp; // note that namespaces imply C++ linkage
+ sc->parent = this;
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->importAll(sc);
+ }
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic(sc);
+ }
+ sc->pop();
+ }
+ semanticRun = PASSsemanticdone;
+}
+
+void Nspace::semantic2(Scope *sc)
+{
+ if (semanticRun >= PASSsemantic2)
+ return;
+ semanticRun = PASSsemantic2;
+ if (members)
+ {
+ assert(sc);
+ sc = sc->push(this);
+ sc->linkage = LINKcpp;
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic2(sc);
+ }
+ sc->pop();
+ }
+}
+
+void Nspace::semantic3(Scope *sc)
+{
+ if (semanticRun >= PASSsemantic3)
+ return;
+ semanticRun = PASSsemantic3;
+ if (members)
+ {
+ sc = sc->push(this);
+ sc->linkage = LINKcpp;
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ s->semantic3(sc);
+ }
+ sc->pop();
+ }
+}
+
+const char *Nspace::kind()
+{
+ return "namespace";
+}
+
+bool Nspace::oneMember(Dsymbol **ps, Identifier *ident)
+{
+ return Dsymbol::oneMember(ps, ident);
+}
+
+Dsymbol *Nspace::search(const Loc &loc, Identifier *ident, int flags)
+{
+ //printf("%s::Nspace::search('%s')\n", toChars(), ident->toChars());
+ if (_scope && !symtab)
+ semantic(_scope);
+
+ if (!members || !symtab) // opaque or semantic() is not yet called
+ {
+ error("is forward referenced when looking for '%s'", ident->toChars());
+ return NULL;
+ }
+
+ return ScopeDsymbol::search(loc, ident, flags);
+}
+
+int Nspace::apply(Dsymbol_apply_ft_t fp, void *param)
+{
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ if (s)
+ {
+ if (s->apply(fp, param))
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+bool Nspace::hasPointers()
+{
+ //printf("Nspace::hasPointers() %s\n", toChars());
+
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf(" s = %s %s\n", s->kind(), s->toChars());
+ if (s->hasPointers())
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void Nspace::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
+{
+ //printf("Nspace::setFieldOffset() %s\n", toChars());
+ if (_scope) // if fwd reference
+ semantic(NULL); // try to resolve it
+ if (members)
+ {
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *s = (*members)[i];
+ //printf("\t%s\n", s->toChars());
+ s->setFieldOffset(ad, poffset, isunion);
+ }
+ }
+}
diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h
new file mode 100644
index 0000000..8ca01ae
--- /dev/null
+++ b/gcc/d/dmd/nspace.h
@@ -0,0 +1,38 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/nspace.h
+ */
+
+#pragma once
+
+#include "dsymbol.h"
+
+/* A namespace corresponding to a C++ namespace.
+ * Implies extern(C++).
+ */
+
+class Nspace : public ScopeDsymbol
+{
+ public:
+ Nspace(Loc loc, Identifier *ident, Dsymbols *members);
+
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void setScope(Scope *sc);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ void semantic3(Scope *sc);
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+ int apply(Dsymbol_apply_ft_t fp, void *param);
+ bool hasPointers();
+ void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ const char *kind();
+ Nspace *isNspace() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/objc.c b/gcc/d/dmd/objc.c
new file mode 100644
index 0000000..e12523d
--- /dev/null
+++ b/gcc/d/dmd/objc.c
@@ -0,0 +1,84 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2015-2018 by The D Language Foundation, All Rights Reserved
+ * written by Michel Fortin
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/objc_stubs.c
+ */
+
+#include "objc.h"
+#include "aggregate.h"
+#include "scope.h"
+
+class FuncDeclaration;
+
+// MARK: ObjcSelector
+
+ObjcSelector::ObjcSelector(const char *, size_t, size_t)
+{
+ printf("Should never be called when D_OBJC is false\n");
+ assert(0);
+}
+
+ObjcSelector *ObjcSelector::lookup(const char *)
+{
+ printf("Should never be called when D_OBJC is false\n");
+ assert(0);
+ return NULL;
+}
+
+ObjcSelector *ObjcSelector::lookup(const char *, size_t, size_t)
+{
+ printf("Should never be called when D_OBJC is false\n");
+ assert(0);
+ return NULL;
+}
+
+ObjcSelector *ObjcSelector::create(FuncDeclaration *)
+{
+ printf("Should never be called when D_OBJC is false\n");
+ assert(0);
+ return NULL;
+}
+
+class UnsupportedObjc : public Objc
+{
+ void setObjc(ClassDeclaration *cd)
+ {
+ cd->error("Objective-C classes not supported");
+ }
+
+ void setObjc(InterfaceDeclaration *id)
+ {
+ id->error("Objective-C interfaces not supported");
+ }
+
+ void setSelector(FuncDeclaration *, Scope *)
+ {
+ // noop
+ }
+
+ void validateSelector(FuncDeclaration *)
+ {
+ // noop
+ }
+
+ void checkLinkage(FuncDeclaration *)
+ {
+ // noop
+ }
+};
+
+static Objc *_objc;
+
+Objc *objc()
+{
+ return _objc;
+}
+
+void Objc::_init()
+{
+ _objc = new UnsupportedObjc();
+}
diff --git a/gcc/d/dmd/objc.h b/gcc/d/dmd/objc.h
new file mode 100644
index 0000000..cc1f098
--- /dev/null
+++ b/gcc/d/dmd/objc.h
@@ -0,0 +1,53 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2015-2018 by The D Language Foundation, All Rights Reserved
+ * written by Michel Fortin
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/objc.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "root/stringtable.h"
+
+class Identifier;
+class FuncDeclaration;
+class ClassDeclaration;
+class InterfaceDeclaration;
+struct Scope;
+class StructDeclaration;
+
+struct ObjcSelector
+{
+ static StringTable stringtable;
+ static StringTable vTableDispatchSelectors;
+ static int incnum;
+
+ const char *stringvalue;
+ size_t stringlen;
+ size_t paramCount;
+
+ static void _init();
+
+ ObjcSelector(const char *sv, size_t len, size_t pcount);
+
+ static ObjcSelector *lookup(const char *s);
+ static ObjcSelector *lookup(const char *s, size_t len, size_t pcount);
+
+ static ObjcSelector *create(FuncDeclaration *fdecl);
+};
+
+class Objc
+{
+public:
+ static void _init();
+
+ virtual void setObjc(ClassDeclaration* cd) = 0;
+ virtual void setObjc(InterfaceDeclaration*) = 0;
+ virtual void setSelector(FuncDeclaration*, Scope* sc) = 0;
+ virtual void validateSelector(FuncDeclaration* fd) = 0;
+ virtual void checkLinkage(FuncDeclaration* fd) = 0;
+};
diff --git a/gcc/d/dmd/opover.c b/gcc/d/dmd/opover.c
new file mode 100644
index 0000000..be6fd78
--- /dev/null
+++ b/gcc/d/dmd/opover.c
@@ -0,0 +1,1966 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/opover.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h> // memset()
+
+#include "root/rmem.h"
+
+#include "mars.h"
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "statement.h"
+#include "scope.h"
+#include "id.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "template.h"
+#include "tokens.h"
+
+static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters);
+static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags = 0);
+Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id);
+bool MODimplicitConv(MOD modfrom, MOD modto);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *binSemanticProp(BinExp *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+
+/******************************** Expression **************************/
+
+
+/***********************************
+ * Determine if operands of binary op can be reversed
+ * to fit operator overload.
+ */
+
+bool isCommutative(TOK op)
+{
+ switch (op)
+ {
+ case TOKadd:
+ case TOKmul:
+ case TOKand:
+ case TOKor:
+ case TOKxor:
+
+ // EqualExp
+ case TOKequal:
+ case TOKnotequal:
+
+ // CmpExp
+ case TOKlt:
+ case TOKle:
+ case TOKgt:
+ case TOKge:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************
+ * Get Identifier for operator overload.
+ */
+
+static Identifier *opId(Expression *e)
+{
+ class OpIdVisitor : public Visitor
+ {
+ public:
+ Identifier *id;
+ void visit(Expression *) { assert(0); }
+ void visit(UAddExp *) { id = Id::uadd; }
+ void visit(NegExp *) { id = Id::neg; }
+ void visit(ComExp *) { id = Id::com; }
+ void visit(CastExp *) { id = Id::_cast; }
+ void visit(InExp *) { id = Id::opIn; }
+ void visit(PostExp *e) { id = (e->op == TOKplusplus) ? Id::postinc : Id::postdec; }
+ void visit(AddExp *) { id = Id::add; }
+ void visit(MinExp *) { id = Id::sub; }
+ void visit(MulExp *) { id = Id::mul; }
+ void visit(DivExp *) { id = Id::div; }
+ void visit(ModExp *) { id = Id::mod; }
+ void visit(PowExp *) { id = Id::pow; }
+ void visit(ShlExp *) { id = Id::shl; }
+ void visit(ShrExp *) { id = Id::shr; }
+ void visit(UshrExp *) { id = Id::ushr; }
+ void visit(AndExp *) { id = Id::iand; }
+ void visit(OrExp *) { id = Id::ior; }
+ void visit(XorExp *) { id = Id::ixor; }
+ void visit(CatExp *) { id = Id::cat; }
+ void visit(AssignExp *) { id = Id::assign; }
+ void visit(AddAssignExp *) { id = Id::addass; }
+ void visit(MinAssignExp *) { id = Id::subass; }
+ void visit(MulAssignExp *) { id = Id::mulass; }
+ void visit(DivAssignExp *) { id = Id::divass; }
+ void visit(ModAssignExp *) { id = Id::modass; }
+ void visit(AndAssignExp *) { id = Id::andass; }
+ void visit(OrAssignExp *) { id = Id::orass; }
+ void visit(XorAssignExp *) { id = Id::xorass; }
+ void visit(ShlAssignExp *) { id = Id::shlass; }
+ void visit(ShrAssignExp *) { id = Id::shrass; }
+ void visit(UshrAssignExp *) { id = Id::ushrass; }
+ void visit(CatAssignExp *) { id = Id::catass; }
+ void visit(PowAssignExp *) { id = Id::powass; }
+ void visit(EqualExp *) { id = Id::eq; }
+ void visit(CmpExp *) { id = Id::cmp; }
+ void visit(ArrayExp *) { id = Id::index; }
+ void visit(PtrExp *) { id = Id::opStar; }
+ };
+ OpIdVisitor v;
+ e->accept(&v);
+ return v.id;
+}
+
+/***********************************
+ * Get Identifier for reverse operator overload,
+ * NULL if not supported for this operator.
+ */
+
+static Identifier *opId_r(Expression *e)
+{
+ class OpIdRVisitor : public Visitor
+ {
+ public:
+ Identifier *id;
+ void visit(Expression *) { id = NULL; }
+ void visit(InExp *) { id = Id::opIn_r; }
+ void visit(AddExp *) { id = Id::add_r; }
+ void visit(MinExp *) { id = Id::sub_r; }
+ void visit(MulExp *) { id = Id::mul_r; }
+ void visit(DivExp *) { id = Id::div_r; }
+ void visit(ModExp *) { id = Id::mod_r; }
+ void visit(PowExp *) { id = Id::pow_r; }
+ void visit(ShlExp *) { id = Id::shl_r; }
+ void visit(ShrExp *) { id = Id::shr_r; }
+ void visit(UshrExp *) { id = Id::ushr_r; }
+ void visit(AndExp *) { id = Id::iand_r; }
+ void visit(OrExp *) { id = Id::ior_r; }
+ void visit(XorExp *) { id = Id::ixor_r; }
+ void visit(CatExp *) { id = Id::cat_r; }
+ };
+ OpIdRVisitor v;
+ e->accept(&v);
+ return v.id;
+}
+
+/************************************
+ * If type is a class or struct, return the symbol for it,
+ * else NULL
+ */
+AggregateDeclaration *isAggregate(Type *t)
+{
+ t = t->toBasetype();
+ if (t->ty == Tclass)
+ {
+ return ((TypeClass *)t)->sym;
+ }
+ else if (t->ty == Tstruct)
+ {
+ return ((TypeStruct *)t)->sym;
+ }
+ return NULL;
+}
+
+/*******************************************
+ * Helper function to turn operator into template argument list
+ */
+Objects *opToArg(Scope *sc, TOK op)
+{
+ /* Remove the = from op=
+ */
+ switch (op)
+ {
+ case TOKaddass: op = TOKadd; break;
+ case TOKminass: op = TOKmin; break;
+ case TOKmulass: op = TOKmul; break;
+ case TOKdivass: op = TOKdiv; break;
+ case TOKmodass: op = TOKmod; break;
+ case TOKandass: op = TOKand; break;
+ case TOKorass: op = TOKor; break;
+ case TOKxorass: op = TOKxor; break;
+ case TOKshlass: op = TOKshl; break;
+ case TOKshrass: op = TOKshr; break;
+ case TOKushrass: op = TOKushr; break;
+ case TOKcatass: op = TOKcat; break;
+ case TOKpowass: op = TOKpow; break;
+ default: break;
+ }
+ Expression *e = new StringExp(Loc(), const_cast<char *>(Token::toChars(op)));
+ e = semantic(e, sc);
+ Objects *tiargs = new Objects();
+ tiargs->push(e);
+ return tiargs;
+}
+
+/************************************
+ * Operator overload.
+ * Check for operator overload, if so, replace
+ * with function call.
+ * Return NULL if not an operator overload.
+ */
+
+Expression *op_overload(Expression *e, Scope *sc)
+{
+ class OpOverload : public Visitor
+ {
+ public:
+ Scope *sc;
+ Expression *result;
+
+ OpOverload(Scope *sc)
+ : sc(sc)
+ {
+ result = NULL;
+ }
+
+ void visit(Expression *)
+ {
+ assert(0);
+ }
+
+ void visit(UnaExp *e)
+ {
+ //printf("UnaExp::op_overload() (%s)\n", e->toChars());
+
+ if (e->e1->op == TOKarray)
+ {
+ ArrayExp *ae = (ArrayExp *)e->e1;
+ ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = resolveProperties(sc, ae->e1);
+ Expression *ae1old = ae->e1;
+
+ const bool maybeSlice =
+ (ae->arguments->dim == 0 ||
+ (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval));
+ IntervalExp *ie = NULL;
+ if (maybeSlice && ae->arguments->dim)
+ {
+ assert((*ae->arguments)[0]->op == TOKinterval);
+ ie = (IntervalExp *)(*ae->arguments)[0];
+ }
+
+ while (true)
+ {
+ if (ae->e1->op == TOKerror)
+ {
+ result = ae->e1;
+ return;
+ }
+ Expression *e0 = NULL;
+ Expression *ae1save = ae->e1;
+ ae->lengthVar = NULL;
+
+ Type *t1b = ae->e1->type->toBasetype();
+ AggregateDeclaration *ad = isAggregate(t1b);
+ if (!ad)
+ break;
+ if (search_function(ad, Id::opIndexUnary))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, &e0);
+ if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
+ goto Lfallback;
+ if (result->op == TOKerror)
+ return;
+
+ /* Rewrite op(a[arguments]) as:
+ * a.opIndexUnary!(op)(arguments)
+ */
+ Expressions *a = (Expressions *)ae->arguments->copy();
+ Objects *tiargs = opToArg(sc, e->op);
+ result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexUnary, tiargs);
+ result = new CallExp(e->loc, result, a);
+ if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
+ result = trySemantic(result, sc);
+ else
+ result = semantic(result, sc);
+ if (result)
+ {
+ result = Expression::combine(e0, result);
+ return;
+ }
+ }
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id::opSliceUnary))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, ie, &e0);
+ if (result->op == TOKerror)
+ return;
+
+ /* Rewrite op(a[i..j]) as:
+ * a.opSliceUnary!(op)(i, j)
+ */
+ Expressions *a = new Expressions();
+ if (ie)
+ {
+ a->push(ie->lwr);
+ a->push(ie->upr);
+ }
+ Objects *tiargs = opToArg(sc, e->op);
+ result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceUnary, tiargs);
+ result = new CallExp(e->loc, result, a);
+ result = semantic(result, sc);
+ result = Expression::combine(e0, result);
+ return;
+ }
+
+ // Didn't find it. Forward to aliasthis
+ if (ad->aliasthis && t1b != ae->att1)
+ {
+ if (!ae->att1 && t1b->checkAliasThisRec())
+ ae->att1 = t1b;
+
+ /* Rewrite op(a[arguments]) as:
+ * op(a.aliasthis[arguments])
+ */
+ ae->e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae->e1)
+ continue;
+ }
+ break;
+ }
+ ae->e1 = ae1old; // recovery
+ ae->lengthVar = NULL;
+ }
+
+ e->e1 = semantic(e->e1, sc);
+ e->e1 = resolveProperties(sc, e->e1);
+ if (e->e1->op == TOKerror)
+ {
+ result = e->e1;
+ return;
+ }
+
+ AggregateDeclaration *ad = isAggregate(e->e1->type);
+ if (ad)
+ {
+ Dsymbol *fd = NULL;
+ #if 1 // Old way, kept for compatibility with D1
+ if (e->op != TOKpreplusplus && e->op != TOKpreminusminus)
+ {
+ fd = search_function(ad, opId(e));
+ if (fd)
+ {
+ // Rewrite +e1 as e1.add()
+ result = build_overload(e->loc, sc, e->e1, NULL, fd);
+ return;
+ }
+ }
+ #endif
+
+ /* Rewrite as:
+ * e1.opUnary!(op)()
+ */
+ fd = search_function(ad, Id::opUnary);
+ if (fd)
+ {
+ Objects *tiargs = opToArg(sc, e->op);
+ result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
+ result = new CallExp(e->loc, result);
+ result = semantic(result, sc);
+ return;
+ }
+
+ // Didn't find it. Forward to aliasthis
+ if (ad->aliasthis && e->e1->type != e->att1)
+ {
+ /* Rewrite op(e1) as:
+ * op(e1.aliasthis)
+ */
+ //printf("att una %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars());
+ Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
+ UnaExp *ue = (UnaExp *)e->copy();
+ if (!ue->att1 && e->e1->type->checkAliasThisRec())
+ ue->att1 = e->e1->type;
+ ue->e1 = e1;
+ result = trySemantic(ue, sc);
+ return;
+ }
+ }
+ }
+
+ void visit(ArrayExp *ae)
+ {
+ //printf("ArrayExp::op_overload() (%s)\n", ae->toChars());
+ ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = resolveProperties(sc, ae->e1);
+ Expression *ae1old = ae->e1;
+
+ const bool maybeSlice =
+ (ae->arguments->dim == 0 ||
+ (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval));
+ IntervalExp *ie = NULL;
+ if (maybeSlice && ae->arguments->dim)
+ {
+ assert((*ae->arguments)[0]->op == TOKinterval);
+ ie = (IntervalExp *)(*ae->arguments)[0];
+ }
+
+ while (true)
+ {
+ if (ae->e1->op == TOKerror)
+ {
+ result = ae->e1;
+ return;
+ }
+ Expression *e0 = NULL;
+ Expression *ae1save = ae->e1;
+ ae->lengthVar = NULL;
+
+ Type *t1b = ae->e1->type->toBasetype();
+ AggregateDeclaration *ad = isAggregate(t1b);
+ if (!ad)
+ {
+ // If the non-aggregate expression ae->e1 is indexable or sliceable,
+ // convert it to the corresponding concrete expression.
+ if (t1b->ty == Tpointer ||
+ t1b->ty == Tsarray ||
+ t1b->ty == Tarray ||
+ t1b->ty == Taarray ||
+ t1b->ty == Ttuple ||
+ t1b->ty == Tvector ||
+ ae->e1->op == TOKtype)
+ {
+ // Convert to SliceExp
+ if (maybeSlice)
+ {
+ result = new SliceExp(ae->loc, ae->e1, ie);
+ result = semantic(result, sc);
+ return;
+ }
+ // Convert to IndexExp
+ if (ae->arguments->dim == 1)
+ {
+ result = new IndexExp(ae->loc, ae->e1, (*ae->arguments)[0]);
+ result = semantic(result, sc);
+ return;
+ }
+ }
+ break;
+ }
+ if (search_function(ad, Id::index))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, &e0);
+ if (!result) // a[i..j] might be: a.opSlice(i, j)
+ goto Lfallback;
+ if (result->op == TOKerror)
+ return;
+
+ /* Rewrite e1[arguments] as:
+ * e1.opIndex(arguments)
+ */
+ Expressions *a = (Expressions *)ae->arguments->copy();
+ result = new DotIdExp(ae->loc, ae->e1, Id::index);
+ result = new CallExp(ae->loc, result, a);
+ if (maybeSlice) // a[] might be: a.opSlice()
+ result = trySemantic(result, sc);
+ else
+ result = semantic(result, sc);
+ if (result)
+ {
+ result = Expression::combine(e0, result);
+ return;
+ }
+ }
+ Lfallback:
+ if (maybeSlice && ae->e1->op == TOKtype)
+ {
+ result = new SliceExp(ae->loc, ae->e1, ie);
+ result = semantic(result, sc);
+ result = Expression::combine(e0, result);
+ return;
+ }
+ if (maybeSlice && search_function(ad, Id::slice))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, ie, &e0);
+ if (result->op == TOKerror)
+ return;
+
+ /* Rewrite a[i..j] as:
+ * a.opSlice(i, j)
+ */
+ Expressions *a = new Expressions();
+ if (ie)
+ {
+ a->push(ie->lwr);
+ a->push(ie->upr);
+ }
+ result = new DotIdExp(ae->loc, ae->e1, Id::slice);
+ result = new CallExp(ae->loc, result, a);
+ result = semantic(result, sc);
+ result = Expression::combine(e0, result);
+ return;
+ }
+
+ // Didn't find it. Forward to aliasthis
+ if (ad->aliasthis && t1b != ae->att1)
+ {
+ if (!ae->att1 && t1b->checkAliasThisRec())
+ ae->att1 = t1b;
+ //printf("att arr e1 = %s\n", this->e1->type->toChars());
+
+ /* Rewrite op(a[arguments]) as:
+ * op(a.aliasthis[arguments])
+ */
+ ae->e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae->e1)
+ continue;
+ }
+ break;
+ }
+ ae->e1 = ae1old; // recovery
+ ae->lengthVar = NULL;
+ }
+
+ /***********************************************
+ * This is mostly the same as UnaryExp::op_overload(), but has
+ * a different rewrite.
+ */
+ void visit(CastExp *e)
+ {
+ //printf("CastExp::op_overload() (%s)\n", e->toChars());
+ AggregateDeclaration *ad = isAggregate(e->e1->type);
+ if (ad)
+ {
+ Dsymbol *fd = NULL;
+ /* Rewrite as:
+ * e1.opCast!(T)()
+ */
+ fd = search_function(ad, Id::_cast);
+ if (fd)
+ {
+ #if 1 // Backwards compatibility with D1 if opCast is a function, not a template
+ if (fd->isFuncDeclaration())
+ {
+ // Rewrite as: e1.opCast()
+ result = build_overload(e->loc, sc, e->e1, NULL, fd);
+ return;
+ }
+ #endif
+ Objects *tiargs = new Objects();
+ tiargs->push(e->to);
+ result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
+ result = new CallExp(e->loc, result);
+ result = semantic(result, sc);
+ return;
+ }
+
+ // Didn't find it. Forward to aliasthis
+ if (ad->aliasthis)
+ {
+ /* Rewrite op(e1) as:
+ * op(e1.aliasthis)
+ */
+ Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
+ result = e->copy();
+ ((UnaExp *)result)->e1 = e1;
+ result = trySemantic(result, sc);
+ return;
+ }
+ }
+ }
+
+ void visit(BinExp *e)
+ {
+ //printf("BinExp::op_overload() (%s)\n", e->toChars());
+
+ Identifier *id = opId(e);
+ Identifier *id_r = opId_r(e);
+
+ Expressions args1;
+ Expressions args2;
+ int argsset = 0;
+
+ AggregateDeclaration *ad1 = isAggregate(e->e1->type);
+ AggregateDeclaration *ad2 = isAggregate(e->e2->type);
+
+ if (e->op == TOKassign && ad1 == ad2)
+ {
+ StructDeclaration *sd = ad1->isStructDeclaration();
+ if (sd && !sd->hasIdentityAssign)
+ {
+ /* This is bitwise struct assignment. */
+ return;
+ }
+ }
+
+ Dsymbol *s = NULL;
+ Dsymbol *s_r = NULL;
+
+ #if 1 // the old D1 scheme
+ if (ad1 && id)
+ {
+ s = search_function(ad1, id);
+ }
+ if (ad2 && id_r)
+ {
+ s_r = search_function(ad2, id_r);
+
+ // Bugzilla 12778: If both x.opBinary(y) and y.opBinaryRight(x) found,
+ // and they are exactly same symbol, x.opBinary(y) should be preferred.
+ if (s_r && s_r == s)
+ s_r = NULL;
+ }
+ #endif
+
+ Objects *tiargs = NULL;
+ if (e->op == TOKplusplus || e->op == TOKminusminus)
+ {
+ // Bug4099 fix
+ if (ad1 && search_function(ad1, Id::opUnary))
+ return;
+ }
+ if (!s && !s_r && e->op != TOKequal && e->op != TOKnotequal && e->op != TOKassign &&
+ e->op != TOKplusplus && e->op != TOKminusminus)
+ {
+ /* Try the new D2 scheme, opBinary and opBinaryRight
+ */
+ if (ad1)
+ {
+ s = search_function(ad1, Id::opBinary);
+ if (s && !s->isTemplateDeclaration())
+ {
+ e->e1->error("%s.opBinary isn't a template", e->e1->toChars());
+ result = new ErrorExp();
+ return;
+ }
+ }
+ if (ad2)
+ {
+ s_r = search_function(ad2, Id::opBinaryRight);
+ if (s_r && !s_r->isTemplateDeclaration())
+ {
+ e->e2->error("%s.opBinaryRight isn't a template", e->e2->toChars());
+ result = new ErrorExp();
+ return;
+ }
+ if (s_r && s_r == s) // Bugzilla 12778
+ s_r = NULL;
+ }
+
+ // Set tiargs, the template argument list, which will be the operator string
+ if (s || s_r)
+ {
+ id = Id::opBinary;
+ id_r = Id::opBinaryRight;
+ tiargs = opToArg(sc, e->op);
+ }
+ }
+
+ if (s || s_r)
+ {
+ /* Try:
+ * a.opfunc(b)
+ * b.opfunc_r(a)
+ * and see which is better.
+ */
+
+ args1.setDim(1);
+ args1[0] = e->e1;
+ expandTuples(&args1);
+ args2.setDim(1);
+ args2[0] = e->e2;
+ expandTuples(&args2);
+ argsset = 1;
+
+ Match m;
+ memset(&m, 0, sizeof(m));
+ m.last = MATCHnomatch;
+
+ if (s)
+ {
+ functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
+ if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ FuncDeclaration *lastf = m.lastf;
+
+ if (s_r)
+ {
+ functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
+ if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ if (m.count > 1)
+ {
+ // Error, ambiguous
+ e->error("overloads %s and %s both match argument list for %s",
+ m.lastf->type->toChars(),
+ m.nextf->type->toChars(),
+ m.lastf->toChars());
+ }
+ else if (m.last <= MATCHnomatch)
+ {
+ m.lastf = m.anyf;
+ if (tiargs)
+ goto L1;
+ }
+
+ if (e->op == TOKplusplus || e->op == TOKminusminus)
+ {
+ // Kludge because operator overloading regards e++ and e--
+ // as unary, but it's implemented as a binary.
+ // Rewrite (e1 ++ e2) as e1.postinc()
+ // Rewrite (e1 -- e2) as e1.postdec()
+ result = build_overload(e->loc, sc, e->e1, NULL, m.lastf ? m.lastf : s);
+ }
+ else if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch))
+ {
+ // Rewrite (e1 op e2) as e1.opfunc(e2)
+ result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
+ }
+ else
+ {
+ // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+ result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
+ }
+ return;
+ }
+
+ L1:
+ #if 1 // Retained for D1 compatibility
+ if (isCommutative(e->op) && !tiargs)
+ {
+ s = NULL;
+ s_r = NULL;
+ if (ad1 && id_r)
+ {
+ s_r = search_function(ad1, id_r);
+ }
+ if (ad2 && id)
+ {
+ s = search_function(ad2, id);
+ if (s && s == s_r) // Bugzilla 12778
+ s = NULL;
+ }
+
+ if (s || s_r)
+ {
+ /* Try:
+ * a.opfunc_r(b)
+ * b.opfunc(a)
+ * and see which is better.
+ */
+
+ if (!argsset)
+ {
+ args1.setDim(1);
+ args1[0] = e->e1;
+ expandTuples(&args1);
+ args2.setDim(1);
+ args2[0] = e->e2;
+ expandTuples(&args2);
+ }
+
+ Match m;
+ memset(&m, 0, sizeof(m));
+ m.last = MATCHnomatch;
+
+ if (s_r)
+ {
+ functionResolve(&m, s_r, e->loc, sc, tiargs, e->e1->type, &args2);
+ if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ FuncDeclaration *lastf = m.lastf;
+
+ if (s)
+ {
+ functionResolve(&m, s, e->loc, sc, tiargs, e->e2->type, &args1);
+ if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ if (m.count > 1)
+ {
+ // Error, ambiguous
+ e->error("overloads %s and %s both match argument list for %s",
+ m.lastf->type->toChars(),
+ m.nextf->type->toChars(),
+ m.lastf->toChars());
+ }
+ else if (m.last <= MATCHnomatch)
+ {
+ m.lastf = m.anyf;
+ }
+
+ if ((lastf && m.lastf == lastf) || (!s && m.last <= MATCHnomatch))
+ {
+ // Rewrite (e1 op e2) as e1.opfunc_r(e2)
+ result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s_r);
+ }
+ else
+ {
+ // Rewrite (e1 op e2) as e2.opfunc(e1)
+ result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s);
+ }
+
+ // When reversing operands of comparison operators,
+ // need to reverse the sense of the op
+ switch (e->op)
+ {
+ case TOKlt: e->op = TOKgt; break;
+ case TOKgt: e->op = TOKlt; break;
+ case TOKle: e->op = TOKge; break;
+ case TOKge: e->op = TOKle; break;
+ default: break;
+ }
+
+ return;
+ }
+ }
+ #endif
+
+ // Try alias this on first operand
+ if (ad1 && ad1->aliasthis &&
+ !(e->op == TOKassign && ad2 && ad1 == ad2)) // See Bugzilla 2943
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1.aliasthis op e2)
+ */
+ if (e->att1 && e->e1->type == e->att1)
+ return;
+ //printf("att bin e1 = %s\n", this->e1->type->toChars());
+ Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
+ BinExp *be = (BinExp *)e->copy();
+ if (!be->att1 && e->e1->type->checkAliasThisRec())
+ be->att1 = e->e1->type;
+ be->e1 = e1;
+ result = trySemantic(be, sc);
+ return;
+ }
+
+ // Try alias this on second operand
+ /* Bugzilla 2943: make sure that when we're copying the struct, we don't
+ * just copy the alias this member
+ */
+ if (ad2 && ad2->aliasthis &&
+ !(e->op == TOKassign && ad1 && ad1 == ad2))
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ if (e->att2 && e->e2->type == e->att2)
+ return;
+ //printf("att bin e2 = %s\n", e->e2->type->toChars());
+ Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
+ BinExp *be = (BinExp *)e->copy();
+ if (!be->att2 && e->e2->type->checkAliasThisRec())
+ be->att2 = e->e2->type;
+ be->e2 = e2;
+ result = trySemantic(be, sc);
+ return;
+ }
+ return;
+ }
+
+ static bool needsDirectEq(Type *t1, Type *t2, Scope *sc)
+ {
+ Type *t1n = t1->nextOf()->toBasetype();
+ Type *t2n = t2->nextOf()->toBasetype();
+ if (((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) &&
+ (t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) ||
+ (t1n->ty == Tvoid || t2n->ty == Tvoid))
+ {
+ return false;
+ }
+ if (t1n->constOf() != t2n->constOf())
+ return true;
+
+ Type *t = t1n;
+ while (t->toBasetype()->nextOf())
+ t = t->nextOf()->toBasetype();
+ if (t->ty != Tstruct)
+ return false;
+
+ semanticTypeInfo(sc, t);
+ return ((TypeStruct *)t)->sym->hasIdentityEquals;
+ }
+
+ void visit(EqualExp *e)
+ {
+ //printf("EqualExp::op_overload() (%s)\n", e->toChars());
+
+ Type *t1 = e->e1->type->toBasetype();
+ Type *t2 = e->e2->type->toBasetype();
+
+ /* Check for array equality.
+ */
+ if ((t1->ty == Tarray || t1->ty == Tsarray) &&
+ (t2->ty == Tarray || t2->ty == Tsarray))
+ {
+ if (needsDirectEq(t1, t2, sc))
+ {
+ /* Rewrite as:
+ * _ArrayEq(e1, e2)
+ */
+ Expression *eeq = new IdentifierExp(e->loc, Id::_ArrayEq);
+ result = new CallExp(e->loc, eeq, e->e1, e->e2);
+ if (e->op == TOKnotequal)
+ result = new NotExp(e->loc, result);
+ result = trySemantic(result, sc); // for better error message
+ if (!result)
+ {
+ e->error("cannot compare %s and %s", t1->toChars(), t2->toChars());
+ result = new ErrorExp();
+ }
+ return;
+ }
+ }
+
+ /* Check for class equality with null literal or typeof(null).
+ */
+ if ((t1->ty == Tclass && e->e2->op == TOKnull) ||
+ (t2->ty == Tclass && e->e1->op == TOKnull))
+ {
+ e->error("use '%s' instead of '%s' when comparing with null",
+ Token::toChars(e->op == TOKequal ? TOKidentity : TOKnotidentity),
+ Token::toChars(e->op));
+ result = new ErrorExp();
+ return;
+ }
+ if ((t1->ty == Tclass && t2->ty == Tnull) ||
+ (t1->ty == Tnull && t2->ty == Tclass))
+ {
+ // Comparing a class with typeof(null) should not call opEquals
+ return;
+ }
+
+ /* Check for class equality.
+ */
+ if (t1->ty == Tclass && t2->ty == Tclass)
+ {
+ ClassDeclaration *cd1 = t1->isClassHandle();
+ ClassDeclaration *cd2 = t2->isClassHandle();
+
+ if (!(cd1->cpp || cd2->cpp))
+ {
+ /* Rewrite as:
+ * .object.opEquals(e1, e2)
+ */
+ Expression *e1x = e->e1;
+ Expression *e2x = e->e2;
+
+ /* The explicit cast is necessary for interfaces,
+ * see Bugzilla 4088.
+ */
+ Type *to = ClassDeclaration::object->getType();
+ if (cd1->isInterfaceDeclaration())
+ e1x = new CastExp(e->loc, e->e1, t1->isMutable() ? to : to->constOf());
+ if (cd2->isInterfaceDeclaration())
+ e2x = new CastExp(e->loc, e->e2, t2->isMutable() ? to : to->constOf());
+
+ result = new IdentifierExp(e->loc, Id::empty);
+ result = new DotIdExp(e->loc, result, Id::object);
+ result = new DotIdExp(e->loc, result, Id::eq);
+ result = new CallExp(e->loc, result, e1x, e2x);
+ if (e->op == TOKnotequal)
+ result = new NotExp(e->loc, result);
+ result = semantic(result, sc);
+ return;
+ }
+ }
+
+ result = compare_overload(e, sc, Id::eq);
+ if (result)
+ {
+ if (result->op == TOKcall && e->op == TOKnotequal)
+ {
+ result = new NotExp(result->loc, result);
+ result = semantic(result, sc);
+ }
+ return;
+ }
+
+ /* Check for pointer equality.
+ */
+ if (t1->ty == Tpointer || t2->ty == Tpointer)
+ {
+ /* Rewrite:
+ * ptr1 == ptr2
+ * as:
+ * ptr1 is ptr2
+ *
+ * This is just a rewriting for deterministic AST representation
+ * as the backend input.
+ */
+ TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
+ result = new IdentityExp(op2, e->loc, e->e1, e->e2);
+ result = semantic(result, sc);
+ return;
+ }
+
+ /* Check for struct equality without opEquals.
+ */
+ if (t1->ty == Tstruct && t2->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *)t1)->sym;
+ if (sd != ((TypeStruct *)t2)->sym)
+ return;
+
+ if (!needOpEquals(sd))
+ {
+ // Use bitwise equality.
+ TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
+ result = new IdentityExp(op2, e->loc, e->e1, e->e2);
+ result = semantic(result, sc);
+ return;
+ }
+
+ /* Do memberwise equality.
+ * Rewrite:
+ * e1 == e2
+ * as:
+ * e1.tupleof == e2.tupleof
+ *
+ * If sd is a nested struct, and if it's nested in a class, it will
+ * also compare the parent class's equality. Otherwise, compares
+ * the identity of parent context through void*.
+ */
+ if (e->att1 && t1 == e->att1)
+ return;
+ if (e->att2 && t2 == e->att2)
+ return;
+
+ e = (EqualExp *)e->copy();
+ if (!e->att1)
+ e->att1 = t1;
+ if (!e->att2)
+ e->att2 = t2;
+ e->e1 = new DotIdExp(e->loc, e->e1, Id::_tupleof);
+ e->e2 = new DotIdExp(e->loc, e->e2, Id::_tupleof);
+ result = semantic(e, sc);
+
+ /* Bugzilla 15292, if the rewrite result is same with the original,
+ * the equality is unresolvable because it has recursive definition.
+ */
+ if (result->op == e->op &&
+ ((EqualExp *)result)->e1->type->toBasetype() == t1)
+ {
+ e->error("cannot compare %s because its auto generated member-wise equality has recursive definition",
+ t1->toChars());
+ result = new ErrorExp();
+ }
+ return;
+ }
+
+ /* Check for tuple equality.
+ */
+ if (e->e1->op == TOKtuple && e->e2->op == TOKtuple)
+ {
+ TupleExp *tup1 = (TupleExp *)e->e1;
+ TupleExp *tup2 = (TupleExp *)e->e2;
+ size_t dim = tup1->exps->dim;
+ if (dim != tup2->exps->dim)
+ {
+ e->error("mismatched tuple lengths, %d and %d",
+ (int)dim, (int)tup2->exps->dim);
+ result = new ErrorExp();
+ return;
+ }
+
+ if (dim == 0)
+ {
+ // zero-length tuple comparison should always return true or false.
+ result = new IntegerExp(e->loc, (e->op == TOKequal), Type::tbool);
+ }
+ else
+ {
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression *ex1 = (*tup1->exps)[i];
+ Expression *ex2 = (*tup2->exps)[i];
+ EqualExp *eeq = new EqualExp(e->op, e->loc, ex1, ex2);
+ eeq->att1 = e->att1;
+ eeq->att2 = e->att2;
+
+ if (!result)
+ result = eeq;
+ else if (e->op == TOKequal)
+ result = new AndAndExp(e->loc, result, eeq);
+ else
+ result = new OrOrExp(e->loc, result, eeq);
+ }
+ assert(result);
+ }
+ result = Expression::combine(Expression::combine(tup1->e0, tup2->e0), result);
+ result = semantic(result, sc);
+ return;
+ }
+ }
+
+ void visit(CmpExp *e)
+ {
+ //printf("CmpExp::op_overload() (%s)\n", e->toChars());
+
+ result = compare_overload(e, sc, Id::cmp);
+ }
+
+ /*********************************
+ * Operator overloading for op=
+ */
+ void visit(BinAssignExp *e)
+ {
+ //printf("BinAssignExp::op_overload() (%s)\n", e->toChars());
+
+ if (e->e1->op == TOKarray)
+ {
+ ArrayExp *ae = (ArrayExp *)e->e1;
+ ae->e1 = semantic(ae->e1, sc);
+ ae->e1 = resolveProperties(sc, ae->e1);
+ Expression *ae1old = ae->e1;
+
+ const bool maybeSlice =
+ (ae->arguments->dim == 0 ||
+ (ae->arguments->dim == 1 && (*ae->arguments)[0]->op == TOKinterval));
+ IntervalExp *ie = NULL;
+ if (maybeSlice && ae->arguments->dim)
+ {
+ assert((*ae->arguments)[0]->op == TOKinterval);
+ ie = (IntervalExp *)(*ae->arguments)[0];
+ }
+
+ while (true)
+ {
+ if (ae->e1->op == TOKerror)
+ {
+ result = ae->e1;
+ return;
+ }
+ Expression *e0 = NULL;
+ Expression *ae1save = ae->e1;
+ ae->lengthVar = NULL;
+
+ Type *t1b = ae->e1->type->toBasetype();
+ AggregateDeclaration *ad = isAggregate(t1b);
+ if (!ad)
+ break;
+ if (search_function(ad, Id::opIndexOpAssign))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, &e0);
+ if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
+ goto Lfallback;
+ if (result->op == TOKerror)
+ return;
+
+ result = semantic(e->e2, sc);
+ if (result->op == TOKerror)
+ return;
+ e->e2 = result;
+
+ /* Rewrite a[arguments] op= e2 as:
+ * a.opIndexOpAssign!(op)(e2, arguments)
+ */
+ Expressions *a = (Expressions *)ae->arguments->copy();
+ a->insert(0, e->e2);
+ Objects *tiargs = opToArg(sc, e->op);
+ result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexOpAssign, tiargs);
+ result = new CallExp(e->loc, result, a);
+ if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
+ result = trySemantic(result, sc);
+ else
+ result = semantic(result, sc);
+ if (result)
+ {
+ result = Expression::combine(e0, result);
+ return;
+ }
+ }
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id::opSliceOpAssign))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, ie, &e0);
+ if (result->op == TOKerror)
+ return;
+
+ result = semantic(e->e2, sc);
+ if (result->op == TOKerror)
+ return;
+ e->e2 = result;
+
+ /* Rewrite (a[i..j] op= e2) as:
+ * a.opSliceOpAssign!(op)(e2, i, j)
+ */
+ Expressions *a = new Expressions();
+ a->push(e->e2);
+ if (ie)
+ {
+ a->push(ie->lwr);
+ a->push(ie->upr);
+ }
+ Objects *tiargs = opToArg(sc, e->op);
+ result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceOpAssign, tiargs);
+ result = new CallExp(e->loc, result, a);
+ result = semantic(result, sc);
+ result = Expression::combine(e0, result);
+ return;
+ }
+
+ // Didn't find it. Forward to aliasthis
+ if (ad->aliasthis && t1b != ae->att1)
+ {
+ if (!ae->att1 && t1b->checkAliasThisRec())
+ ae->att1 = t1b;
+
+ /* Rewrite (a[arguments] op= e2) as:
+ * a.aliasthis[arguments] op= e2
+ */
+ ae->e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae->e1)
+ continue;
+ }
+ break;
+ }
+ ae->e1 = ae1old; // recovery
+ ae->lengthVar = NULL;
+ }
+
+ result = binSemanticProp(e, sc);
+ if (result)
+ return;
+
+ // Don't attempt 'alias this' if an error occured
+ if (e->e1->type->ty == Terror || e->e2->type->ty == Terror)
+ {
+ result = new ErrorExp();
+ return;
+ }
+
+ Identifier *id = opId(e);
+
+ Expressions args2;
+
+ AggregateDeclaration *ad1 = isAggregate(e->e1->type);
+
+ Dsymbol *s = NULL;
+
+ #if 1 // the old D1 scheme
+ if (ad1 && id)
+ {
+ s = search_function(ad1, id);
+ }
+ #endif
+
+ Objects *tiargs = NULL;
+ if (!s)
+ {
+ /* Try the new D2 scheme, opOpAssign
+ */
+ if (ad1)
+ {
+ s = search_function(ad1, Id::opOpAssign);
+ if (s && !s->isTemplateDeclaration())
+ {
+ e->error("%s.opOpAssign isn't a template", e->e1->toChars());
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ // Set tiargs, the template argument list, which will be the operator string
+ if (s)
+ {
+ id = Id::opOpAssign;
+ tiargs = opToArg(sc, e->op);
+ }
+ }
+
+ if (s)
+ {
+ /* Try:
+ * a.opOpAssign(b)
+ */
+
+ args2.setDim(1);
+ args2[0] = e->e2;
+ expandTuples(&args2);
+
+ Match m;
+ memset(&m, 0, sizeof(m));
+ m.last = MATCHnomatch;
+
+ if (s)
+ {
+ functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
+ if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+ {
+ result = new ErrorExp();
+ return;
+ }
+ }
+
+ if (m.count > 1)
+ {
+ // Error, ambiguous
+ e->error("overloads %s and %s both match argument list for %s",
+ m.lastf->type->toChars(),
+ m.nextf->type->toChars(),
+ m.lastf->toChars());
+ }
+ else if (m.last <= MATCHnomatch)
+ {
+ m.lastf = m.anyf;
+ if (tiargs)
+ goto L1;
+ }
+
+ // Rewrite (e1 op e2) as e1.opOpAssign(e2)
+ result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
+ return;
+ }
+
+ L1:
+
+ // Try alias this on first operand
+ if (ad1 && ad1->aliasthis)
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1.aliasthis op e2)
+ */
+ if (e->att1 && e->e1->type == e->att1)
+ return;
+ //printf("att %s e1 = %s\n", Token::toChars(e->op), e->e1->type->toChars());
+ Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
+ BinExp *be = (BinExp *)e->copy();
+ if (!be->att1 && e->e1->type->checkAliasThisRec())
+ be->att1 = e->e1->type;
+ be->e1 = e1;
+ result = trySemantic(be, sc);
+ return;
+ }
+
+ // Try alias this on second operand
+ AggregateDeclaration *ad2 = isAggregate(e->e2->type);
+ if (ad2 && ad2->aliasthis)
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ if (e->att2 && e->e2->type == e->att2)
+ return;
+ //printf("att %s e2 = %s\n", Token::toChars(e->op), e->e2->type->toChars());
+ Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
+ BinExp *be = (BinExp *)e->copy();
+ if (!be->att2 && e->e2->type->checkAliasThisRec())
+ be->att2 = e->e2->type;
+ be->e2 = e2;
+ result = trySemantic(be, sc);
+ return;
+ }
+ }
+ };
+
+ OpOverload v(sc);
+ e->accept(&v);
+ return v.result;
+}
+
+/******************************************
+ * Common code for overloading of EqualExp and CmpExp
+ */
+Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id)
+{
+ //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), e->toChars());
+
+ AggregateDeclaration *ad1 = isAggregate(e->e1->type);
+ AggregateDeclaration *ad2 = isAggregate(e->e2->type);
+
+ Dsymbol *s = NULL;
+ Dsymbol *s_r = NULL;
+
+ if (ad1)
+ {
+ s = search_function(ad1, id);
+ }
+ if (ad2)
+ {
+ s_r = search_function(ad2, id);
+ if (s == s_r)
+ s_r = NULL;
+ }
+
+ Objects *tiargs = NULL;
+
+ if (s || s_r)
+ {
+ /* Try:
+ * a.opEquals(b)
+ * b.opEquals(a)
+ * and see which is better.
+ */
+
+ Expressions args1;
+ Expressions args2;
+
+ args1.setDim(1);
+ args1[0] = e->e1;
+ expandTuples(&args1);
+ args2.setDim(1);
+ args2[0] = e->e2;
+ expandTuples(&args2);
+
+ Match m;
+ memset(&m, 0, sizeof(m));
+ m.last = MATCHnomatch;
+
+ if (0 && s && s_r)
+ {
+ printf("s : %s\n", s->toPrettyChars());
+ printf("s_r: %s\n", s_r->toPrettyChars());
+ }
+
+ if (s)
+ {
+ functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
+ if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+ return new ErrorExp();
+ }
+
+ FuncDeclaration *lastf = m.lastf;
+ int count = m.count;
+
+ if (s_r)
+ {
+ functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
+ if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
+ return new ErrorExp();
+ }
+
+ if (m.count > 1)
+ {
+ /* The following if says "not ambiguous" if there's one match
+ * from s and one from s_r, in which case we pick s.
+ * This doesn't follow the spec, but is a workaround for the case
+ * where opEquals was generated from templates and we cannot figure
+ * out if both s and s_r came from the same declaration or not.
+ * The test case is:
+ * import std.typecons;
+ * void main() {
+ * assert(tuple("has a", 2u) == tuple("has a", 1));
+ * }
+ */
+ if (!(m.lastf == lastf && m.count == 2 && count == 1))
+ {
+ // Error, ambiguous
+ e->error("overloads %s and %s both match argument list for %s",
+ m.lastf->type->toChars(),
+ m.nextf->type->toChars(),
+ m.lastf->toChars());
+ }
+ }
+ else if (m.last <= MATCHnomatch)
+ {
+ m.lastf = m.anyf;
+ }
+
+ Expression *result;
+ if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch))
+ {
+ // Rewrite (e1 op e2) as e1.opfunc(e2)
+ result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
+ }
+ else
+ {
+ // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+ result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
+
+ // When reversing operands of comparison operators,
+ // need to reverse the sense of the op
+ switch (e->op)
+ {
+ case TOKlt: e->op = TOKgt; break;
+ case TOKgt: e->op = TOKlt; break;
+ case TOKle: e->op = TOKge; break;
+ case TOKge: e->op = TOKle; break;
+
+ // The rest are symmetric
+ default:
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ // Try alias this on first operand
+ if (ad1 && ad1->aliasthis)
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1.aliasthis op e2)
+ */
+ if (e->att1 && e->e1->type == e->att1)
+ return NULL;
+ //printf("att cmp_bin e1 = %s\n", e->e1->type->toChars());
+ Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
+ BinExp *be = (BinExp *)e->copy();
+ if (!be->att1 && e->e1->type->checkAliasThisRec())
+ be->att1 = e->e1->type;
+ be->e1 = e1;
+ return trySemantic(be, sc);
+ }
+
+ // Try alias this on second operand
+ if (ad2 && ad2->aliasthis)
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ if (e->att2 && e->e2->type == e->att2)
+ return NULL;
+ //printf("att cmp_bin e2 = %s\n", e->e2->type->toChars());
+ Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
+ BinExp *be = (BinExp *)e->copy();
+ if (!be->att2 && e->e2->type->checkAliasThisRec())
+ be->att2 = e->e2->type;
+ be->e2 = e2;
+ return trySemantic(be, sc);
+ }
+
+ return NULL;
+}
+
+/***********************************
+ * Utility to build a function call out of this reference and argument.
+ */
+
+Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg,
+ Dsymbol *d)
+{
+ assert(d);
+ Expression *e;
+
+ //printf("build_overload(id = '%s')\n", id->toChars());
+ //earg->print();
+ //earg->type->print();
+ Declaration *decl = d->isDeclaration();
+ if (decl)
+ e = new DotVarExp(loc, ethis, decl, false);
+ else
+ e = new DotIdExp(loc, ethis, d->ident);
+ e = new CallExp(loc, e, earg);
+
+ e = semantic(e, sc);
+ return e;
+}
+
+/***************************************
+ * Search for function funcid in aggregate ad.
+ */
+
+Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid)
+{
+ Dsymbol *s = ad->search(Loc(), funcid);
+ if (s)
+ {
+ //printf("search_function: s = '%s'\n", s->kind());
+ Dsymbol *s2 = s->toAlias();
+ //printf("search_function: s2 = '%s'\n", s2->kind());
+ FuncDeclaration *fd = s2->isFuncDeclaration();
+ if (fd && fd->type->ty == Tfunction)
+ return fd;
+
+ TemplateDeclaration *td = s2->isTemplateDeclaration();
+ if (td)
+ return td;
+ }
+ return NULL;
+}
+
+
+bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
+{
+ //printf("inferAggregate(%s)\n", fes->aggr->toChars());
+ Identifier *idapply = (fes->op == TOKforeach) ? Id::apply : Id::applyReverse;
+ Identifier *idfront = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
+ int sliced = 0;
+ Type *tab;
+ Type *att = NULL;
+ Expression *aggr = fes->aggr;
+ AggregateDeclaration *ad;
+
+ while (1)
+ {
+ aggr = semantic(aggr, sc);
+ aggr = resolveProperties(sc, aggr);
+ aggr = aggr->optimize(WANTvalue);
+ if (!aggr->type || aggr->op == TOKerror)
+ goto Lerr;
+
+ tab = aggr->type->toBasetype();
+ switch (tab->ty)
+ {
+ case Tarray:
+ case Tsarray:
+ case Ttuple:
+ case Taarray:
+ break;
+
+ case Tclass:
+ ad = ((TypeClass *)tab)->sym;
+ goto Laggr;
+
+ case Tstruct:
+ ad = ((TypeStruct *)tab)->sym;
+ goto Laggr;
+
+ Laggr:
+ if (!sliced)
+ {
+ sapply = search_function(ad, idapply);
+ if (sapply)
+ {
+ // opApply aggregate
+ break;
+ }
+
+ if (fes->aggr->op != TOKtype)
+ {
+ Expression *rinit = new ArrayExp(fes->aggr->loc, fes->aggr);
+ rinit = trySemantic(rinit, sc);
+ if (rinit) // if application of [] succeeded
+ {
+ aggr = rinit;
+ sliced = 1;
+ continue;
+ }
+ }
+ }
+
+ if (ad->search(Loc(), idfront))
+ {
+ // range aggregate
+ break;
+ }
+
+ if (ad->aliasthis)
+ {
+ if (att == tab)
+ goto Lerr;
+ if (!att && tab->checkAliasThisRec())
+ att = tab;
+ aggr = resolveAliasThis(sc, aggr);
+ continue;
+ }
+ goto Lerr;
+
+ case Tdelegate:
+ if (aggr->op == TOKdelegate)
+ {
+ sapply = ((DelegateExp *)aggr)->func;
+ }
+ break;
+
+ case Terror:
+ break;
+
+ default:
+ goto Lerr;
+ }
+ break;
+ }
+ fes->aggr = aggr;
+ return true;
+
+Lerr:
+ return false;
+}
+
+/*****************************************
+ * Given array of parameters and an aggregate type,
+ * if any of the parameter types are missing, attempt to infer
+ * them from the aggregate type.
+ */
+
+bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
+{
+ if (!fes->parameters || !fes->parameters->dim)
+ return false;
+
+ if (sapply) // prefer opApply
+ {
+ for (size_t u = 0; u < fes->parameters->dim; u++)
+ {
+ Parameter *p = (*fes->parameters)[u];
+ if (p->type)
+ {
+ p->type = p->type->semantic(fes->loc, sc);
+ p->type = p->type->addStorageClass(p->storageClass);
+ }
+ }
+
+ Expression *ethis;
+ Type *tab = fes->aggr->type->toBasetype();
+ if (tab->ty == Tclass || tab->ty == Tstruct)
+ ethis = fes->aggr;
+ else
+ { assert(tab->ty == Tdelegate && fes->aggr->op == TOKdelegate);
+ ethis = ((DelegateExp *)fes->aggr)->e1;
+ }
+
+ /* Look for like an
+ * int opApply(int delegate(ref Type [, ...]) dg);
+ * overload
+ */
+ FuncDeclaration *fd = sapply->isFuncDeclaration();
+ if (fd)
+ {
+ sapply = inferApplyArgTypesX(ethis, fd, fes->parameters);
+ }
+ return sapply != NULL;
+ }
+
+ /* Return if no parameters need types.
+ */
+ for (size_t u = 0; u < fes->parameters->dim; u++)
+ {
+ Parameter *p = (*fes->parameters)[u];
+ if (!p->type)
+ break;
+ }
+
+ AggregateDeclaration *ad;
+
+ Parameter *p = (*fes->parameters)[0];
+ Type *taggr = fes->aggr->type;
+ assert(taggr);
+ Type *tab = taggr->toBasetype();
+ switch (tab->ty)
+ {
+ case Tarray:
+ case Tsarray:
+ case Ttuple:
+ if (fes->parameters->dim == 2)
+ {
+ if (!p->type)
+ {
+ p->type = Type::tsize_t; // key type
+ p->type = p->type->addStorageClass(p->storageClass);
+ }
+ p = (*fes->parameters)[1];
+ }
+ if (!p->type && tab->ty != Ttuple)
+ {
+ p->type = tab->nextOf(); // value type
+ p->type = p->type->addStorageClass(p->storageClass);
+ }
+ break;
+
+ case Taarray:
+ {
+ TypeAArray *taa = (TypeAArray *)tab;
+
+ if (fes->parameters->dim == 2)
+ {
+ if (!p->type)
+ {
+ p->type = taa->index; // key type
+ p->type = p->type->addStorageClass(p->storageClass);
+ if (p->storageClass & STCref) // key must not be mutated via ref
+ p->type = p->type->addMod(MODconst);
+ }
+ p = (*fes->parameters)[1];
+ }
+ if (!p->type)
+ {
+ p->type = taa->next; // value type
+ p->type = p->type->addStorageClass(p->storageClass);
+ }
+ break;
+ }
+
+ case Tclass:
+ ad = ((TypeClass *)tab)->sym;
+ goto Laggr;
+
+ case Tstruct:
+ ad = ((TypeStruct *)tab)->sym;
+ goto Laggr;
+
+ Laggr:
+ if (fes->parameters->dim == 1)
+ {
+ if (!p->type)
+ {
+ /* Look for a front() or back() overload
+ */
+ Identifier *id = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
+ Dsymbol *s = ad->search(Loc(), id);
+ FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
+ if (fd)
+ {
+ // Resolve inout qualifier of front type
+ p->type = fd->type->nextOf();
+ if (p->type)
+ {
+ p->type = p->type->substWildTo(tab->mod);
+ p->type = p->type->addStorageClass(p->storageClass);
+ }
+ }
+ else if (s && s->isTemplateDeclaration())
+ ;
+ else if (s && s->isDeclaration())
+ p->type = ((Declaration *)s)->type;
+ else
+ break;
+ }
+ break;
+ }
+ break;
+
+ case Tdelegate:
+ {
+ if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), fes->parameters))
+ return false;
+ break;
+ }
+
+ default:
+ break; // ignore error, caught later
+ }
+ return true;
+}
+
+static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters)
+{
+ struct ParamOpOver
+ {
+ Parameters *parameters;
+ MOD mod;
+ MATCH match;
+ FuncDeclaration *fd_best;
+ FuncDeclaration *fd_ambig;
+
+ static int fp(void *param, Dsymbol *s)
+ {
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (!f)
+ return 0;
+ ParamOpOver *p = (ParamOpOver *)param;
+ TypeFunction *tf = (TypeFunction *)f->type;
+ MATCH m = MATCHexact;
+
+ if (f->isThis())
+ {
+ if (!MODimplicitConv(p->mod, tf->mod))
+ m = MATCHnomatch;
+ else if (p->mod != tf->mod)
+ m = MATCHconst;
+ }
+ if (!inferApplyArgTypesY(tf, p->parameters, 1))
+ m = MATCHnomatch;
+
+ if (m > p->match)
+ {
+ p->fd_best = f;
+ p->fd_ambig = NULL;
+ p->match = m;
+ }
+ else if (m == p->match)
+ p->fd_ambig = f;
+ return 0;
+ }
+ };
+ ParamOpOver p;
+ p.parameters = parameters;
+ p.mod = ethis->type->mod;
+ p.match = MATCHnomatch;
+ p.fd_best = NULL;
+ p.fd_ambig = NULL;
+ overloadApply(fstart, &p, &ParamOpOver::fp);
+ if (p.fd_best)
+ {
+ inferApplyArgTypesY((TypeFunction *)p.fd_best->type, parameters);
+ if (p.fd_ambig)
+ { ::error(ethis->loc, "%s.%s matches more than one declaration:\n%s: %s\nand:\n%s: %s",
+ ethis->toChars(), fstart->ident->toChars(),
+ p.fd_best ->loc.toChars(), p.fd_best ->type->toChars(),
+ p.fd_ambig->loc.toChars(), p.fd_ambig->type->toChars());
+ p.fd_best = NULL;
+ }
+ }
+ return p.fd_best;
+}
+
+/******************************
+ * Infer parameters from type of function.
+ * Returns:
+ * 1 match for this function
+ * 0 no match for this function
+ */
+
+static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags)
+{ size_t nparams;
+ Parameter *p;
+
+ if (Parameter::dim(tf->parameters) != 1)
+ goto Lnomatch;
+ p = Parameter::getNth(tf->parameters, 0);
+ if (p->type->ty != Tdelegate)
+ goto Lnomatch;
+ tf = (TypeFunction *)p->type->nextOf();
+ assert(tf->ty == Tfunction);
+
+ /* We now have tf, the type of the delegate. Match it against
+ * the parameters, filling in missing parameter types.
+ */
+ nparams = Parameter::dim(tf->parameters);
+ if (nparams == 0 || tf->varargs)
+ goto Lnomatch; // not enough parameters
+ if (parameters->dim != nparams)
+ goto Lnomatch; // not enough parameters
+
+ for (size_t u = 0; u < nparams; u++)
+ {
+ p = (*parameters)[u];
+ Parameter *param = Parameter::getNth(tf->parameters, u);
+ if (p->type)
+ {
+ if (!p->type->equals(param->type))
+ goto Lnomatch;
+ }
+ else if (!flags)
+ {
+ p->type = param->type;
+ p->type = p->type->addStorageClass(p->storageClass);
+ }
+ }
+ return 1;
+
+Lnomatch:
+ return 0;
+}
+
diff --git a/gcc/d/dmd/optimize.c b/gcc/d/dmd/optimize.c
new file mode 100644
index 0000000..12224fa
--- /dev/null
+++ b/gcc/d/dmd/optimize.c
@@ -0,0 +1,1268 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/optimize.c
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+#include "checkedint.h"
+#include "lexer.h"
+#include "mtype.h"
+#include "expression.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "init.h"
+#include "enum.h"
+#include "ctfe.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/*************************************
+ * If variable has a const initializer,
+ * return that initializer.
+ */
+
+Expression *expandVar(int result, VarDeclaration *v)
+{
+ //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null");
+
+ Expression *e = NULL;
+ if (!v)
+ return e;
+ if (!v->originalType && v->_scope) // semantic() not yet run
+ v->semantic (v->_scope);
+
+ if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest)
+ {
+ if (!v->type)
+ {
+ return e;
+ }
+ Type *tb = v->type->toBasetype();
+ if (v->storage_class & STCmanifest ||
+ v->type->toBasetype()->isscalar() ||
+ ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct))
+ )
+ {
+ if (v->_init)
+ {
+ if (v->inuse)
+ {
+ if (v->storage_class & STCmanifest)
+ {
+ v->error("recursive initialization of constant");
+ goto Lerror;
+ }
+ goto L1;
+ }
+ Expression *ei = v->getConstInitializer();
+ if (!ei)
+ {
+ if (v->storage_class & STCmanifest)
+ {
+ v->error("enum cannot be initialized with %s", v->_init->toChars());
+ goto Lerror;
+ }
+ goto L1;
+ }
+ if (ei->op == TOKconstruct || ei->op == TOKblit)
+ {
+ AssignExp *ae = (AssignExp *)ei;
+ ei = ae->e2;
+ if (ei->isConst() == 1)
+ {
+ }
+ else if (ei->op == TOKstring)
+ {
+ // Bugzilla 14459: We should not constfold the string literal
+ // if it's typed as a C string, because the value expansion
+ // will drop the pointer identity.
+ if (!(result & WANTexpand) && ei->type->toBasetype()->ty == Tpointer)
+ goto L1;
+ }
+ else
+ goto L1;
+
+ if (ei->type == v->type)
+ {
+ // const variable initialized with const expression
+ }
+ else if (ei->implicitConvTo(v->type) >= MATCHconst)
+ {
+ // const var initialized with non-const expression
+ ei = ei->implicitCastTo(NULL, v->type);
+ ei = semantic(ei, NULL);
+ }
+ else
+ goto L1;
+ }
+ else if (!(v->storage_class & STCmanifest) &&
+ ei->isConst() != 1 && ei->op != TOKstring &&
+ ei->op != TOKaddress)
+ {
+ goto L1;
+ }
+ if (!ei->type)
+ {
+ goto L1;
+ }
+ else
+ {
+ // Should remove the copy() operation by
+ // making all mods to expressions copy-on-write
+ e = ei->copy();
+ }
+ }
+ else
+ {
+ goto L1;
+ }
+ if (e->type != v->type)
+ {
+ e = e->castTo(NULL, v->type);
+ }
+ v->inuse++;
+ e = e->optimize(result);
+ v->inuse--;
+ }
+ }
+L1:
+ //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars());
+ return e;
+
+Lerror:
+ return new ErrorExp();
+}
+
+
+Expression *fromConstInitializer(int result, Expression *e1)
+{
+ //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars());
+ //static int xx; if (xx++ == 10) assert(0);
+ Expression *e = e1;
+ if (e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e1;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ e = expandVar(result, v);
+ if (e)
+ {
+ // If it is a comma expression involving a declaration, we mustn't
+ // perform a copy -- we'd get two declarations of the same variable.
+ // See bugzilla 4465.
+ if (e->op == TOKcomma && ((CommaExp *)e)->e1->op == TOKdeclaration)
+ e = e1;
+ else
+
+ if (e->type != e1->type && e1->type && e1->type->ty != Tident)
+ {
+ // Type 'paint' operation
+ e = e->copy();
+ e->type = e1->type;
+ }
+ e->loc = e1->loc;
+ }
+ else
+ {
+ e = e1;
+ }
+ }
+ return e;
+}
+
+Expression *Expression_optimize(Expression *e, int result, bool keepLvalue)
+{
+ class OptimizeVisitor : public Visitor
+ {
+ public:
+ int result;
+ bool keepLvalue;
+ Expression *ret;
+
+ OptimizeVisitor(int result, bool keepLvalue)
+ : result(result), keepLvalue(keepLvalue)
+ {
+ }
+
+ void error()
+ {
+ ret = new ErrorExp();
+ }
+
+ bool expOptimize(Expression *&e, int flags, bool keepLvalue = false)
+ {
+ if (!e)
+ return false;
+ Expression *ex = e->optimize(flags, keepLvalue);
+ if (ex->op == TOKerror)
+ {
+ ret = ex; // store error result
+ return true;
+ }
+ else
+ {
+ e = ex; // modify original
+ return false;
+ }
+ }
+
+ bool unaOptimize(UnaExp *e, int flags)
+ {
+ return expOptimize(e->e1, flags);
+ }
+
+ bool binOptimize(BinExp *e, int flags)
+ {
+ expOptimize(e->e1, flags);
+ expOptimize(e->e2, flags);
+ return ret->op == TOKerror;
+ }
+
+ void visit(Expression *)
+ {
+ //printf("Expression::optimize(result = x%x) %s\n", result, e->toChars());
+ }
+
+ void visit(VarExp *e)
+ {
+ if (keepLvalue)
+ {
+ VarDeclaration *v = e->var->isVarDeclaration();
+ if (v && !(v->storage_class & STCmanifest))
+ return;
+ }
+ ret = fromConstInitializer(result, e);
+ }
+
+ void visit(TupleExp *e)
+ {
+ expOptimize(e->e0, WANTvalue);
+ for (size_t i = 0; i < e->exps->dim; i++)
+ {
+ expOptimize((*e->exps)[i], WANTvalue);
+ }
+ }
+
+ void visit(ArrayLiteralExp *e)
+ {
+ if (e->elements)
+ {
+ expOptimize(e->basis, result & WANTexpand);
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ expOptimize((*e->elements)[i], result & WANTexpand);
+ }
+ }
+ }
+
+ void visit(AssocArrayLiteralExp *e)
+ {
+ assert(e->keys->dim == e->values->dim);
+ for (size_t i = 0; i < e->keys->dim; i++)
+ {
+ expOptimize((*e->keys)[i], result & WANTexpand);
+ expOptimize((*e->values)[i], result & WANTexpand);
+ }
+ }
+
+ void visit(StructLiteralExp *e)
+ {
+ if (e->stageflags & stageOptimize) return;
+ int old = e->stageflags;
+ e->stageflags |= stageOptimize;
+ if (e->elements)
+ {
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ expOptimize((*e->elements)[i], result & WANTexpand);
+ }
+ }
+ e->stageflags = old;
+ }
+
+ void visit(UnaExp *e)
+ {
+ //printf("UnaExp::optimize() %s\n", e->toChars());
+ if (unaOptimize(e, result))
+ return;
+ }
+
+ void visit(NegExp *e)
+ {
+ if (unaOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1)
+ {
+ ret = Neg(e->type, e->e1).copy();
+ }
+ }
+
+ void visit(ComExp *e)
+ {
+ if (unaOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1)
+ {
+ ret = Com(e->type, e->e1).copy();
+ }
+ }
+
+ void visit(NotExp *e)
+ {
+ if (unaOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1)
+ {
+ ret = Not(e->type, e->e1).copy();
+ }
+ }
+
+ void visit(SymOffExp *e)
+ {
+ assert(e->var);
+ }
+
+ void visit(AddrExp *e)
+ {
+ //printf("AddrExp::optimize(result = %d) %s\n", result, e->toChars());
+
+ /* Rewrite &(a,b) as (a,&b)
+ */
+ if (e->e1->op == TOKcomma)
+ {
+ CommaExp *ce = (CommaExp *)e->e1;
+ AddrExp *ae = new AddrExp(e->loc, ce->e2, e->type);
+ ret = new CommaExp(ce->loc, ce->e1, ae);
+ ret->type = e->type;
+ return;
+ }
+
+ // Keep lvalue-ness
+ if (expOptimize(e->e1, result, true))
+ return;
+
+ // Convert &*ex to ex
+ if (e->e1->op == TOKstar)
+ {
+ Expression *ex = ((PtrExp *)e->e1)->e1;
+ if (e->type->equals(ex->type))
+ ret = ex;
+ else if (e->type->toBasetype()->equivalent(ex->type->toBasetype()))
+ {
+ ret = ex->copy();
+ ret->type = e->type;
+ }
+ return;
+ }
+ if (e->e1->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e->e1;
+ if (!ve->var->isOut() && !ve->var->isRef() &&
+ !ve->var->isImportedSymbol())
+ {
+ ret = new SymOffExp(e->loc, ve->var, 0, ve->hasOverloads);
+ ret->type = e->type;
+ return;
+ }
+ }
+ if (e->e1->op == TOKindex)
+ {
+ // Convert &array[n] to &array+n
+ IndexExp *ae = (IndexExp *)e->e1;
+
+ if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
+ {
+ sinteger_t index = ae->e2->toInteger();
+ VarExp *ve = (VarExp *)ae->e1;
+ if (ve->type->ty == Tsarray
+ && !ve->var->isImportedSymbol())
+ {
+ TypeSArray *ts = (TypeSArray *)ve->type;
+ sinteger_t dim = ts->dim->toInteger();
+ if (index < 0 || index >= dim)
+ {
+ e->error("array index %lld is out of bounds [0..%lld]", index, dim);
+ return error();
+ }
+
+ bool overflow = false;
+ const d_uns64 offset = mulu(index, ts->nextOf()->size(e->loc), overflow);
+ if (overflow)
+ {
+ e->error("array offset overflow");
+ return error();
+ }
+
+ ret = new SymOffExp(e->loc, ve->var, offset);
+ ret->type = e->type;
+ return;
+ }
+ }
+ }
+ }
+
+ void visit(PtrExp *e)
+ {
+ //printf("PtrExp::optimize(result = x%x) %s\n", result, e->toChars());
+ if (expOptimize(e->e1, result))
+ return;
+ // Convert *&ex to ex
+ // But only if there is no type punning involved
+ if (e->e1->op == TOKaddress)
+ {
+ Expression *ex = ((AddrExp *)e->e1)->e1;
+ if (e->type->equals(ex->type))
+ ret = ex;
+ else if (e->type->toBasetype()->equivalent(ex->type->toBasetype()))
+ {
+ ret = ex->copy();
+ ret->type = e->type;
+ }
+ }
+ if (keepLvalue)
+ return;
+
+ // Constant fold *(&structliteral + offset)
+ if (e->e1->op == TOKadd)
+ {
+ Expression *ex = Ptr(e->type, e->e1).copy();
+ if (!CTFEExp::isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+
+ if (e->e1->op == TOKsymoff)
+ {
+ SymOffExp *se = (SymOffExp *)e->e1;
+ VarDeclaration *v = se->var->isVarDeclaration();
+ Expression *ex = expandVar(result, v);
+ if (ex && ex->op == TOKstructliteral)
+ {
+ StructLiteralExp *sle = (StructLiteralExp *)ex;
+ ex = sle->getField(e->type, (unsigned)se->offset);
+ if (ex && !CTFEExp::isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+ }
+ }
+
+ void visit(DotVarExp *e)
+ {
+ //printf("DotVarExp::optimize(result = x%x) %s\n", result, e->toChars());
+ if (expOptimize(e->e1, result))
+ return;
+ if (keepLvalue)
+ return;
+
+ Expression *ex = e->e1;
+
+ if (ex->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)ex;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ ex = expandVar(result, v);
+ }
+
+ if (ex && ex->op == TOKstructliteral)
+ {
+ StructLiteralExp *sle = (StructLiteralExp *)ex;
+ VarDeclaration *vf = e->var->isVarDeclaration();
+ if (vf && !vf->overlapped)
+ {
+ /* Bugzilla 13021: Prevent optimization if vf has overlapped fields.
+ */
+ ex = sle->getField(e->type, vf->offset);
+ if (ex && !CTFEExp::isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+ }
+ }
+
+ void visit(NewExp *e)
+ {
+ expOptimize(e->thisexp, WANTvalue);
+
+ // Optimize parameters
+ if (e->newargs)
+ {
+ for (size_t i = 0; i < e->newargs->dim; i++)
+ {
+ expOptimize((*e->newargs)[i], WANTvalue);
+ }
+ }
+
+ if (e->arguments)
+ {
+ for (size_t i = 0; i < e->arguments->dim; i++)
+ {
+ expOptimize((*e->arguments)[i], WANTvalue);
+ }
+ }
+ }
+
+ void visit(CallExp *e)
+ {
+ //printf("CallExp::optimize(result = %d) %s\n", result, e->toChars());
+
+ // Optimize parameters with keeping lvalue-ness
+ if (expOptimize(e->e1, result))
+ return;
+ if (e->arguments)
+ {
+ Type *t1 = e->e1->type->toBasetype();
+ if (t1->ty == Tdelegate) t1 = t1->nextOf();
+ assert(t1->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)t1;
+ for (size_t i = 0; i < e->arguments->dim; i++)
+ {
+ Parameter *p = Parameter::getNth(tf->parameters, i);
+ bool keep = p && (p->storageClass & (STCref | STCout)) != 0;
+ expOptimize((*e->arguments)[i], WANTvalue, keep);
+ }
+ }
+ }
+
+ void visit(CastExp *e)
+ {
+ //printf("CastExp::optimize(result = %d) %s\n", result, e->toChars());
+ //printf("from %s to %s\n", e->type->toChars(), e->to->toChars());
+ //printf("from %s\n", e->type->toChars());
+ //printf("e1->type %s\n", e->e1->type->toChars());
+ //printf("type = %p\n", e->type);
+ assert(e->type);
+ TOK op1 = e->e1->op;
+
+ Expression *e1old = e->e1;
+ if (expOptimize(e->e1, result))
+ return;
+ e->e1 = fromConstInitializer(result, e->e1);
+
+ if (e->e1 == e1old &&
+ e->e1->op == TOKarrayliteral &&
+ e->type->toBasetype()->ty == Tpointer &&
+ e->e1->type->toBasetype()->ty != Tsarray)
+ {
+ // Casting this will result in the same expression, and
+ // infinite loop because of Expression::implicitCastTo()
+ return; // no change
+ }
+
+ if ((e->e1->op == TOKstring || e->e1->op == TOKarrayliteral) &&
+ (e->type->ty == Tpointer || e->type->ty == Tarray))
+ {
+ const d_uns64 esz = e->type->nextOf()->size(e->loc);
+ const d_uns64 e1sz = e->e1->type->toBasetype()->nextOf()->size(e->e1->loc);
+ if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
+ return error();
+
+ if (e1sz == esz)
+ {
+ // Bugzilla 12937: If target type is void array, trying to paint
+ // e->e1 with that type will cause infinite recursive optimization.
+ if (e->type->nextOf()->ty == Tvoid)
+ return;
+
+ ret = e->e1->castTo(NULL, e->type);
+ //printf(" returning1 %s\n", ret->toChars());
+ return;
+ }
+ }
+
+ if (e->e1->op == TOKstructliteral &&
+ e->e1->type->implicitConvTo(e->type) >= MATCHconst)
+ {
+ //printf(" returning2 %s\n", e->e1->toChars());
+ L1: // Returning e1 with changing its type
+ ret = (e1old == e->e1 ? e->e1->copy() : e->e1);
+ ret->type = e->type;
+ return;
+ }
+
+ /* The first test here is to prevent infinite loops
+ */
+ if (op1 != TOKarrayliteral && e->e1->op == TOKarrayliteral)
+ {
+ ret = e->e1->castTo(NULL, e->to);
+ return;
+ }
+ if (e->e1->op == TOKnull &&
+ (e->type->ty == Tpointer || e->type->ty == Tclass || e->type->ty == Tarray))
+ {
+ //printf(" returning3 %s\n", e->e1->toChars());
+ goto L1;
+ }
+
+ if (e->type->ty == Tclass && e->e1->type->ty == Tclass)
+ {
+ // See if we can remove an unnecessary cast
+ ClassDeclaration *cdfrom = e->e1->type->isClassHandle();
+ ClassDeclaration *cdto = e->type->isClassHandle();
+ if (cdto == ClassDeclaration::object && !cdfrom->isInterfaceDeclaration())
+ goto L1; // can always convert a class to Object
+ // Need to determine correct offset before optimizing away the cast.
+ // https://issues.dlang.org/show_bug.cgi?id=16980
+ cdfrom->size(e->loc);
+ assert(cdfrom->sizeok == SIZEOKdone);
+ assert(cdto->sizeok == SIZEOKdone || !cdto->isBaseOf(cdfrom, NULL));
+ int offset;
+ if (cdto->isBaseOf(cdfrom, &offset) && offset == 0)
+ {
+ //printf(" returning4 %s\n", e->e1->toChars());
+ goto L1;
+ }
+ }
+
+ // We can convert 'head const' to mutable
+ if (e->to->mutableOf()->constOf()->equals(e->e1->type->mutableOf()->constOf()))
+ {
+ //printf(" returning5 %s\n", e->e1->toChars());
+ goto L1;
+ }
+
+ if (e->e1->isConst())
+ {
+ if (e->e1->op == TOKsymoff)
+ {
+ if (e->type->toBasetype()->ty != Tsarray)
+ {
+ const d_uns64 esz = e->type->size(e->loc);
+ const d_uns64 e1sz = e->e1->type->size(e->e1->loc);
+ if (esz == SIZE_INVALID ||
+ e1sz == SIZE_INVALID)
+ return error();
+
+ if (esz == e1sz)
+ goto L1;
+ }
+ return;
+ }
+ if (e->to->toBasetype()->ty != Tvoid)
+ {
+ if (e->e1->type->equals(e->type) && e->type->equals(e->to))
+ ret = e->e1;
+ else
+ ret = Cast(e->loc, e->type, e->to, e->e1).copy();
+ }
+ }
+ //printf(" returning6 %s\n", ret->toChars());
+ }
+
+ void visit(BinExp *e)
+ {
+ //printf("BinExp::optimize(result = %d) %s\n", result, e->toChars());
+ // don't replace const variable with its initializer in e1
+ bool e2only = (e->op == TOKconstruct || e->op == TOKblit);
+ if (e2only ? expOptimize(e->e2, result) : binOptimize(e, result))
+ return;
+
+ if (e->op == TOKshlass || e->op == TOKshrass || e->op == TOKushrass)
+ {
+ if (e->e2->isConst() == 1)
+ {
+ sinteger_t i2 = e->e2->toInteger();
+ d_uns64 sz = e->e1->type->size(e->e1->loc);
+ assert(sz != SIZE_INVALID);
+ sz *= 8;
+ if (i2 < 0 || (d_uns64)i2 >= sz)
+ {
+ e->error("shift assign by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
+ return error();
+ }
+ }
+ }
+ }
+
+ void visit(AddExp *e)
+ {
+ //printf("AddExp::optimize(%s)\n", e->toChars());
+
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() && e->e2->isConst())
+ {
+ if (e->e1->op == TOKsymoff && e->e2->op == TOKsymoff)
+ return;
+ ret = Add(e->loc, e->type, e->e1, e->e2).copy();
+ }
+ }
+
+ void visit(MinExp *e)
+ {
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() && e->e2->isConst())
+ {
+ if (e->e2->op == TOKsymoff)
+ return;
+ ret = Min(e->loc, e->type, e->e1, e->e2).copy();
+ }
+ }
+
+ void visit(MulExp *e)
+ {
+ //printf("MulExp::optimize(result = %d) %s\n", result, e->toChars());
+
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+ {
+ ret = Mul(e->loc, e->type, e->e1, e->e2).copy();
+ }
+ }
+
+ void visit(DivExp *e)
+ {
+ //printf("DivExp::optimize(%s)\n", e->toChars());
+
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+ {
+ ret = Div(e->loc, e->type, e->e1, e->e2).copy();
+ }
+ }
+
+ void visit(ModExp *e)
+ {
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+ {
+ ret = Mod(e->loc, e->type, e->e1, e->e2).copy();
+ }
+ }
+
+ void shift_optimize(BinExp *e, UnionExp (*shift)(Loc, Type *, Expression *, Expression *))
+ {
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e2->isConst() == 1)
+ {
+ sinteger_t i2 = e->e2->toInteger();
+ d_uns64 sz = e->e1->type->size();
+ assert(sz != SIZE_INVALID);
+ sz *= 8;
+ if (i2 < 0 || (d_uns64)i2 >= sz)
+ {
+ e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
+ return error();
+ }
+ if (e->e1->isConst() == 1)
+ ret = (*shift)(e->loc, e->type, e->e1, e->e2).copy();
+ }
+ }
+
+ void visit(ShlExp *e)
+ {
+ //printf("ShlExp::optimize(result = %d) %s\n", result, e->toChars());
+ shift_optimize(e, &Shl);
+ }
+
+ void visit(ShrExp *e)
+ {
+ //printf("ShrExp::optimize(result = %d) %s\n", result, e->toChars());
+ shift_optimize(e, &Shr);
+ }
+
+ void visit(UshrExp *e)
+ {
+ //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
+ shift_optimize(e, &Ushr);
+ }
+
+ void visit(AndExp *e)
+ {
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+ ret = And(e->loc, e->type, e->e1, e->e2).copy();
+ }
+
+ void visit(OrExp *e)
+ {
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+ ret = Or(e->loc, e->type, e->e1, e->e2).copy();
+ }
+
+ void visit(XorExp *e)
+ {
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+ ret = Xor(e->loc, e->type, e->e1, e->e2).copy();
+ }
+
+ void visit(PowExp *e)
+ {
+ if (binOptimize(e, result))
+ return;
+
+ // Replace 1 ^^ x or 1.0^^x by (x, 1)
+ if ((e->e1->op == TOKint64 && e->e1->toInteger() == 1) ||
+ (e->e1->op == TOKfloat64 && e->e1->toReal() == CTFloat::one))
+ {
+ ret = new CommaExp(e->loc, e->e2, e->e1);
+ ret->type = e->type;
+ return;
+ }
+
+ // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
+ if (e->e2->type->isintegral() && e->e1->op == TOKint64 && (sinteger_t)e->e1->toInteger() == -1L)
+ {
+ ret = new AndExp(e->loc, e->e2, new IntegerExp(e->loc, 1, e->e2->type));
+ ret->type = e->e2->type;
+ ret = new CondExp(e->loc, ret, new IntegerExp(e->loc, -1L, e->type), new IntegerExp(e->loc, 1L, e->type));
+ ret->type = e->type;
+ return;
+ }
+
+ // Replace x ^^ 0 or x^^0.0 by (x, 1)
+ if ((e->e2->op == TOKint64 && e->e2->toInteger() == 0) ||
+ (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::zero))
+ {
+ if (e->e1->type->isintegral())
+ ret = new IntegerExp(e->loc, 1, e->e1->type);
+ else
+ ret = new RealExp(e->loc, CTFloat::one, e->e1->type);
+
+ ret = new CommaExp(e->loc, e->e1, ret);
+ ret->type = e->type;
+ return;
+ }
+
+ // Replace x ^^ 1 or x^^1.0 by (x)
+ if ((e->e2->op == TOKint64 && e->e2->toInteger() == 1) ||
+ (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::one))
+ {
+ ret = e->e1;
+ return;
+ }
+
+ // Replace x ^^ -1.0 by (1.0 / x)
+ if ((e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::minusone))
+ {
+ ret = new DivExp(e->loc, new RealExp(e->loc, CTFloat::one, e->e2->type), e->e1);
+ ret->type = e->type;
+ return;
+ }
+
+ // All other negative integral powers are illegal
+ if ((e->e1->type->isintegral()) && (e->e2->op == TOKint64) && (sinteger_t)e->e2->toInteger() < 0)
+ {
+ e->error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
+ e->e1->type->toBasetype()->toChars(), e->e1->toChars(), e->e2->toChars());
+ return error();
+ }
+
+ // If e2 *could* have been an integer, make it one.
+ if (e->e2->op == TOKfloat64 && (e->e2->toReal() == ldouble((sinteger_t)e->e2->toReal())))
+ e->e2 = new IntegerExp(e->loc, e->e2->toInteger(), Type::tint64);
+
+ if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
+ {
+ Expression *ex = Pow(e->loc, e->type, e->e1, e->e2).copy();
+ if (!CTFEExp::isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+
+ // (2 ^^ n) ^^ p -> 1 << n * p
+ if (e->e1->op == TOKint64 && e->e1->toInteger() > 0 &&
+ !((e->e1->toInteger() - 1) & e->e1->toInteger()) &&
+ e->e2->type->isintegral() && e->e2->type->isunsigned())
+ {
+ dinteger_t i = e->e1->toInteger();
+ dinteger_t mul = 1;
+ while ((i >>= 1) > 1)
+ mul++;
+ Expression *shift = new MulExp(e->loc, e->e2, new IntegerExp(e->loc, mul, e->e2->type));
+ shift->type = e->e2->type;
+ shift = shift->castTo(NULL, Type::tshiftcnt);
+ ret = new ShlExp(e->loc, new IntegerExp(e->loc, 1, e->e1->type), shift);
+ ret->type = e->type;
+ return;
+ }
+ }
+
+ void visit(CommaExp *e)
+ {
+ //printf("CommaExp::optimize(result = %d) %s\n", result, e->toChars());
+ // Comma needs special treatment, because it may
+ // contain compiler-generated declarations. We can interpret them, but
+ // otherwise we must NOT attempt to constant-fold them.
+ // In particular, if the comma returns a temporary variable, it needs
+ // to be an lvalue (this is particularly important for struct constructors)
+
+ expOptimize(e->e1, WANTvalue);
+ expOptimize(e->e2, result, keepLvalue);
+ if (ret->op == TOKerror)
+ return;
+
+ if (!e->e1 || e->e1->op == TOKint64 || e->e1->op == TOKfloat64 || !hasSideEffect(e->e1))
+ {
+ ret = e->e2;
+ if (ret)
+ ret->type = e->type;
+ }
+
+ //printf("-CommaExp::optimize(result = %d) %s\n", result, e->e->toChars());
+ }
+
+ void visit(ArrayLengthExp *e)
+ {
+ //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e->toChars());
+
+ if (unaOptimize(e, WANTexpand))
+ return;
+
+ // CTFE interpret static immutable arrays (to get better diagnostics)
+ if (e->e1->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
+ if (v && (v->storage_class & STCstatic) && (v->storage_class & STCimmutable) && v->_init)
+ {
+ if (Expression *ci = v->getConstInitializer())
+ e->e1 = ci;
+ }
+ }
+
+ if (e->e1->op == TOKstring || e->e1->op == TOKarrayliteral || e->e1->op == TOKassocarrayliteral ||
+ e->e1->type->toBasetype()->ty == Tsarray)
+ {
+ ret = ArrayLength(e->type, e->e1).copy();
+ }
+ }
+
+ void visit(EqualExp *e)
+ {
+ //printf("EqualExp::optimize(result = %x) %s\n", result, e->toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+
+ Expression *e1 = fromConstInitializer(result, e->e1);
+ Expression *e2 = fromConstInitializer(result, e->e2);
+ if (e1->op == TOKerror)
+ {
+ ret = e1;
+ return;
+ }
+ if (e2->op == TOKerror)
+ {
+ ret = e2;
+ return;
+ }
+
+ ret = Equal(e->op, e->loc, e->type, e1, e2).copy();
+ if (CTFEExp::isCantExp(ret))
+ ret = e;
+ }
+
+ void visit(IdentityExp *e)
+ {
+ //printf("IdentityExp::optimize(result = %d) %s\n", result, e->toChars());
+
+ if (binOptimize(e, WANTvalue))
+ return;
+
+ if ((e->e1->isConst() && e->e2->isConst()) ||
+ (e->e1->op == TOKnull && e->e2->op == TOKnull)
+ )
+ {
+ ret = Identity(e->op, e->loc, e->type, e->e1, e->e2).copy();
+ if (CTFEExp::isCantExp(ret))
+ ret = e;
+ }
+ }
+
+ /* It is possible for constant folding to change an array expression of
+ * unknown length, into one where the length is known.
+ * If the expression 'arr' is a literal, set lengthVar to be its length.
+ */
+ static void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr)
+ {
+ if (!lengthVar)
+ return;
+ if (lengthVar->_init && !lengthVar->_init->isVoidInitializer())
+ return; // we have previously calculated the length
+ size_t len;
+ if (arr->op == TOKstring)
+ len = ((StringExp *)arr)->len;
+ else if (arr->op == TOKarrayliteral)
+ len = ((ArrayLiteralExp *)arr)->elements->dim;
+ else
+ {
+ Type *t = arr->type->toBasetype();
+ if (t->ty == Tsarray)
+ len = (size_t)((TypeSArray *)t)->dim->toInteger();
+ else
+ return; // we don't know the length yet
+ }
+
+ Expression *dollar = new IntegerExp(Loc(), len, Type::tsize_t);
+ lengthVar->_init = new ExpInitializer(Loc(), dollar);
+ lengthVar->storage_class |= STCstatic | STCconst;
+ }
+
+ void visit(IndexExp *e)
+ {
+ //printf("IndexExp::optimize(result = %d) %s\n", result, e->toChars());
+ if (expOptimize(e->e1, result & WANTexpand))
+ return;
+
+ Expression *ex = fromConstInitializer(result, e->e1);
+
+ // We might know $ now
+ setLengthVarIfKnown(e->lengthVar, ex);
+
+ if (expOptimize(e->e2, WANTvalue))
+ return;
+ if (keepLvalue)
+ return;
+ ret = Index(e->type, ex, e->e2).copy();
+ if (CTFEExp::isCantExp(ret))
+ ret = e;
+ }
+
+ void visit(SliceExp *e)
+ {
+ //printf("SliceExp::optimize(result = %d) %s\n", result, e->toChars());
+ if (expOptimize(e->e1, result & WANTexpand))
+ return;
+ if (!e->lwr)
+ {
+ if (e->e1->op == TOKstring)
+ {
+ // Convert slice of string literal into dynamic array
+ Type *t = e->e1->type->toBasetype();
+ if (Type *tn = t->nextOf())
+ ret = e->e1->castTo(NULL, tn->arrayOf());
+ }
+ }
+ else
+ {
+ e->e1 = fromConstInitializer(result, e->e1);
+ // We might know $ now
+ setLengthVarIfKnown(e->lengthVar, e->e1);
+ expOptimize(e->lwr, WANTvalue);
+ expOptimize(e->upr, WANTvalue);
+ if (ret->op == TOKerror)
+ return;
+ ret = Slice(e->type, e->e1, e->lwr, e->upr).copy();
+ if (CTFEExp::isCantExp(ret))
+ ret = e;
+ }
+
+ // Bugzilla 14649: We need to leave the slice form so it might be
+ // a part of array operation.
+ // Assume that the backend codegen will handle the form `e[]`
+ // as an equal to `e` itself.
+ if (ret->op == TOKstring)
+ {
+ e->e1 = ret;
+ e->lwr = NULL;
+ e->upr = NULL;
+ ret = e;
+ }
+ //printf("-SliceExp::optimize() %s\n", ret->toChars());
+ }
+
+ void visit(AndAndExp *e)
+ {
+ //printf("AndAndExp::optimize(%d) %s\n", result, e->toChars());
+ if (expOptimize(e->e1, WANTvalue))
+ return;
+
+ if (e->e1->isBool(false))
+ {
+ // Replace with (e1, false)
+ ret = new IntegerExp(e->loc, 0, Type::tbool);
+ ret = Expression::combine(e->e1, ret);
+ if (e->type->toBasetype()->ty == Tvoid)
+ {
+ ret = new CastExp(e->loc, ret, Type::tvoid);
+ ret->type = e->type;
+ }
+ return;
+ }
+
+ if (expOptimize(e->e2, WANTvalue))
+ return;
+
+ if (e->e1->isConst())
+ {
+ if (e->e2->isConst())
+ {
+ bool n1 = e->e1->isBool(true);
+ bool n2 = e->e2->isBool(true);
+ ret = new IntegerExp(e->loc, n1 && n2, e->type);
+ }
+ else if (e->e1->isBool(true))
+ {
+ if (e->type->toBasetype()->ty == Tvoid)
+ ret = e->e2;
+ else
+ {
+ ret = new CastExp(e->loc, e->e2, e->type);
+ ret->type = e->type;
+ }
+ }
+ }
+ }
+
+ void visit(OrOrExp *e)
+ {
+ //printf("OrOrExp::optimize(%d) %s\n", result, e->toChars());
+ if (expOptimize(e->e1, WANTvalue))
+ return;
+
+ if (e->e1->isBool(true))
+ {
+ // Replace with (e1, true)
+ ret = new IntegerExp(e->loc, 1, Type::tbool);
+ ret = Expression::combine(e->e1, ret);
+ if (e->type->toBasetype()->ty == Tvoid)
+ {
+ ret = new CastExp(e->loc, ret, Type::tvoid);
+ ret->type = e->type;
+ }
+ return;
+ }
+
+ if (expOptimize(e->e2, WANTvalue))
+ return;
+
+ if (e->e1->isConst())
+ {
+ if (e->e2->isConst())
+ {
+ bool n1 = e->e1->isBool(true);
+ bool n2 = e->e2->isBool(true);
+ ret = new IntegerExp(e->loc, n1 || n2, e->type);
+ }
+ else if (e->e1->isBool(false))
+ {
+ if (e->type->toBasetype()->ty == Tvoid)
+ ret = e->e2;
+ else
+ {
+ ret = new CastExp(e->loc, e->e2, e->type);
+ ret->type = e->type;
+ }
+ }
+ }
+ }
+
+ void visit(CmpExp *e)
+ {
+ //printf("CmpExp::optimize() %s\n", e->toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+
+ Expression *e1 = fromConstInitializer(result, e->e1);
+ Expression *e2 = fromConstInitializer(result, e->e2);
+
+ ret = Cmp(e->op, e->loc, e->type, e1, e2).copy();
+ if (CTFEExp::isCantExp(ret))
+ ret = e;
+ }
+
+ void visit(CatExp *e)
+ {
+ //printf("CatExp::optimize(%d) %s\n", result, e->toChars());
+
+ if (binOptimize(e, result))
+ return;
+
+ if (e->e1->op == TOKcat)
+ {
+ // Bugzilla 12798: optimize ((expr ~ str1) ~ str2)
+ CatExp *ce1 = (CatExp *)e->e1;
+ CatExp cex(e->loc, ce1->e2, e->e2);
+ cex.type = e->type;
+ Expression *ex = cex.optimize(result);
+ if (ex != &cex)
+ {
+ e->e1 = ce1->e1;
+ e->e2 = ex;
+ }
+ }
+
+ // optimize "str"[] -> "str"
+ if (e->e1->op == TOKslice)
+ {
+ SliceExp *se1 = (SliceExp *)e->e1;
+ if (se1->e1->op == TOKstring && !se1->lwr)
+ e->e1 = se1->e1;
+ }
+ if (e->e2->op == TOKslice)
+ {
+ SliceExp *se2 = (SliceExp *)e->e2;
+ if (se2->e1->op == TOKstring && !se2->lwr)
+ e->e2 = se2->e1;
+ }
+
+ ret = Cat(e->type, e->e1, e->e2).copy();
+ if (CTFEExp::isCantExp(ret))
+ ret = e;
+ }
+
+ void visit(CondExp *e)
+ {
+ if (expOptimize(e->econd, WANTvalue))
+ return;
+ if (e->econd->isBool(true))
+ ret = e->e1->optimize(result, keepLvalue);
+ else if (e->econd->isBool(false))
+ ret = e->e2->optimize(result, keepLvalue);
+ else
+ {
+ expOptimize(e->e1, result, keepLvalue);
+ expOptimize(e->e2, result, keepLvalue);
+ }
+ }
+ };
+
+ OptimizeVisitor v(result, keepLvalue);
+ Expression *ex = NULL;
+ v.ret = e;
+
+ // Optimize the expression until it can no longer be simplified.
+ while (ex != v.ret)
+ {
+ ex = v.ret;
+ ex->accept(&v);
+ }
+ return ex;
+}
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c
new file mode 100644
index 0000000..9ee2f08
--- /dev/null
+++ b/gcc/d/dmd/parse.c
@@ -0,0 +1,7992 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c
+ */
+
+// This is the D parser
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h> // strlen(),memcpy()
+
+#include "root/rmem.h"
+#include "mars.h"
+#include "lexer.h"
+#include "parse.h"
+#include "init.h"
+#include "attrib.h"
+#include "cond.h"
+#include "mtype.h"
+#include "template.h"
+#include "staticassert.h"
+#include "expression.h"
+#include "statement.h"
+#include "module.h"
+#include "dsymbol.h"
+#include "import.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "enum.h"
+#include "id.h"
+#include "version.h"
+#include "aliasthis.h"
+#include "nspace.h"
+#include "hdrgen.h"
+
+Expression *typeToExpression(Type *t);
+
+// Support C cast syntax:
+// (type)(expression)
+#define CCASTSYNTAX 1
+
+// Support postfix C array declarations, such as
+// int a[3][4];
+#define CARRAYDECL 1
+
+Parser::Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment)
+ : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
+{
+ //printf("Parser::Parser()\n");
+ mod = module;
+ md = NULL;
+ linkage = LINKd;
+ endloc = Loc();
+ inBrackets = 0;
+ lookingForElse = Loc();
+ //nextToken(); // start up the scanner
+}
+
+/*********************
+ * Use this constructor for string mixins.
+ * Input:
+ * loc location in source file of mixin
+ */
+Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment)
+ : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
+{
+ //printf("Parser::Parser()\n");
+ scanloc = loc;
+
+#ifndef IN_GCC
+ if (loc.filename)
+ {
+ /* Create a pseudo-filename for the mixin string, as it may not even exist
+ * in the source file.
+ */
+ char *filename = (char *)mem.xmalloc(strlen(loc.filename) + 7 + sizeof(loc.linnum) * 3 + 1);
+ sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum);
+ scanloc.filename = filename;
+ }
+#endif
+
+ mod = module;
+ md = NULL;
+ linkage = LINKd;
+ endloc = Loc();
+ inBrackets = 0;
+ lookingForElse = Loc();
+ //nextToken(); // start up the scanner
+}
+
+Dsymbols *Parser::parseModule()
+{
+ const utf8_t *comment = token.blockComment;
+ bool isdeprecated = false;
+ Expression *msg = NULL;
+ Expressions *udas = NULL;
+ Dsymbols *decldefs;
+
+ Token *tk;
+ if (skipAttributes(&token, &tk) && tk->value == TOKmodule)
+ {
+ while (token.value != TOKmodule)
+ {
+ switch (token.value)
+ {
+ case TOKdeprecated:
+ {
+ // deprecated (...) module ...
+ if (isdeprecated)
+ {
+ error("there is only one deprecation attribute allowed for module declaration");
+ }
+ else
+ {
+ isdeprecated = true;
+ }
+ nextToken();
+ if (token.value == TOKlparen)
+ {
+ check(TOKlparen);
+ msg = parseAssignExp();
+ check(TOKrparen);
+ }
+ break;
+ }
+ case TOKat:
+ {
+ Expressions *exps = NULL;
+ StorageClass stc = parseAttribute(&exps);
+
+ if (stc == STCproperty || stc == STCnogc || stc == STCdisable ||
+ stc == STCsafe || stc == STCtrusted || stc == STCsystem)
+ {
+ error("@%s attribute for module declaration is not supported", token.toChars());
+ }
+ else
+ {
+ udas = UserAttributeDeclaration::concat(udas, exps);
+ }
+ if (stc)
+ nextToken();
+ break;
+ }
+ default:
+ {
+ error("'module' expected instead of %s", token.toChars());
+ nextToken();
+ break;
+ }
+ }
+ }
+ }
+
+ if (udas)
+ {
+ Dsymbols *a = new Dsymbols();
+ UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
+ mod->userAttribDecl = udad;
+ }
+
+ // ModuleDeclation leads off
+ if (token.value == TOKmodule)
+ {
+ Loc loc = token.loc;
+
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following module");
+ goto Lerr;
+ }
+ else
+ {
+ Identifiers *a = NULL;
+ Identifier *id;
+
+ id = token.ident;
+ while (nextToken() == TOKdot)
+ {
+ if (!a)
+ a = new Identifiers();
+ a->push(id);
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following package");
+ goto Lerr;
+ }
+ id = token.ident;
+ }
+
+ md = new ModuleDeclaration(loc, a, id);
+ md->isdeprecated = isdeprecated;
+ md->msg = msg;
+
+ if (token.value != TOKsemicolon)
+ error("';' expected following module declaration instead of %s", token.toChars());
+ nextToken();
+ addComment(mod, comment);
+ }
+ }
+
+ decldefs = parseDeclDefs(0);
+ if (token.value != TOKeof)
+ {
+ error(token.loc, "unrecognized declaration");
+ goto Lerr;
+ }
+ return decldefs;
+
+Lerr:
+ while (token.value != TOKsemicolon && token.value != TOKeof)
+ nextToken();
+ nextToken();
+ return new Dsymbols();
+}
+
+struct PrefixAttributes
+{
+ StorageClass storageClass;
+ Expression *depmsg;
+ LINK link;
+ Prot protection;
+ bool setAlignment;
+ Expression *ealign;
+ Expressions *udas;
+ const utf8_t *comment;
+
+ PrefixAttributes()
+ : storageClass(STCundefined),
+ depmsg(NULL),
+ link(LINKdefault),
+ protection(PROTundefined),
+ setAlignment(false),
+ ealign(NULL),
+ udas(NULL),
+ comment(NULL)
+ {
+ }
+};
+
+Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
+{
+ Dsymbol *lastDecl = NULL; // used to link unittest to its previous declaration
+ if (!pLastDecl)
+ pLastDecl = &lastDecl;
+
+ LINK linksave = linkage; // save global state
+
+ //printf("Parser::parseDeclDefs()\n");
+ Dsymbols *decldefs = new Dsymbols();
+ do
+ {
+ // parse result
+ Dsymbol *s = NULL;
+ Dsymbols *a = NULL;
+
+ PrefixAttributes attrs;
+ if (!once || !pAttrs)
+ {
+ pAttrs = &attrs;
+ pAttrs->comment = token.blockComment;
+ }
+ PROTKIND prot;
+ StorageClass stc;
+ Condition *condition;
+
+ linkage = linksave;
+
+ switch (token.value)
+ {
+ case TOKenum:
+ {
+ /* Determine if this is a manifest constant declaration,
+ * or a conventional enum.
+ */
+ Token *t = peek(&token);
+ if (t->value == TOKlcurly || t->value == TOKcolon)
+ s = parseEnum();
+ else if (t->value != TOKidentifier)
+ goto Ldeclaration;
+ else
+ {
+ t = peek(t);
+ if (t->value == TOKlcurly || t->value == TOKcolon ||
+ t->value == TOKsemicolon)
+ s = parseEnum();
+ else
+ goto Ldeclaration;
+ }
+ break;
+ }
+
+ case TOKimport:
+ a = parseImport();
+ // keep pLastDecl
+ break;
+
+ case TOKtemplate:
+ s = (Dsymbol *)parseTemplateDeclaration();
+ break;
+
+ case TOKmixin:
+ {
+ Loc loc = token.loc;
+ switch (peekNext())
+ {
+ case TOKlparen:
+ {
+ // mixin(string)
+ nextToken();
+ check(TOKlparen, "mixin");
+ Expression *e = parseAssignExp();
+ check(TOKrparen);
+ check(TOKsemicolon);
+ s = new CompileDeclaration(loc, e);
+ break;
+ }
+ case TOKtemplate:
+ // mixin template
+ nextToken();
+ s = (Dsymbol *)parseTemplateDeclaration(true);
+ break;
+
+ default:
+ s = parseMixin();
+ break;
+ }
+ break;
+ }
+
+ case TOKwchar: case TOKdchar:
+ case TOKbool: case TOKchar:
+ case TOKint8: case TOKuns8:
+ case TOKint16: case TOKuns16:
+ case TOKint32: case TOKuns32:
+ case TOKint64: case TOKuns64:
+ case TOKint128: case TOKuns128:
+ case TOKfloat32: case TOKfloat64: case TOKfloat80:
+ case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+ case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+ case TOKvoid:
+ case TOKalias:
+ case TOKidentifier:
+ case TOKsuper:
+ case TOKtypeof:
+ case TOKdot:
+ case TOKvector:
+ case TOKstruct:
+ case TOKunion:
+ case TOKclass:
+ case TOKinterface:
+ Ldeclaration:
+ a = parseDeclarations(false, pAttrs, pAttrs->comment);
+ if (a && a->dim)
+ *pLastDecl = (*a)[a->dim-1];
+ break;
+
+ case TOKthis:
+ if (peekNext() == TOKdot)
+ goto Ldeclaration;
+ else
+ s = parseCtor(pAttrs);
+ break;
+
+ case TOKtilde:
+ s = parseDtor(pAttrs);
+ break;
+
+ case TOKinvariant:
+ {
+ Token *t = peek(&token);
+ if ((t->value == TOKlparen && peek(t)->value == TOKrparen) ||
+ t->value == TOKlcurly)
+ {
+ // invariant {}
+ // invariant() {}
+ s = parseInvariant(pAttrs);
+ }
+ else
+ {
+ error("invariant body expected, not '%s'", token.toChars());
+ goto Lerror;
+ }
+ break;
+ }
+
+ case TOKunittest:
+ if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
+ {
+ s = parseUnitTest(pAttrs);
+ if (*pLastDecl)
+ (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s;
+ }
+ else
+ {
+ // Skip over unittest block by counting { }
+ Loc loc = token.loc;
+ int braces = 0;
+ while (1)
+ {
+ nextToken();
+ switch (token.value)
+ {
+ case TOKlcurly:
+ ++braces;
+ continue;
+
+ case TOKrcurly:
+ if (--braces)
+ continue;
+ nextToken();
+ break;
+
+ case TOKeof:
+ /* { */
+ error(loc, "closing } of unittest not found before end of file");
+ goto Lerror;
+
+ default:
+ continue;
+ }
+ break;
+ }
+ // Workaround 14894. Add an empty unittest declaration to keep
+ // the number of symbols in this scope independent of -unittest.
+ s = new UnitTestDeclaration(loc, token.loc, STCundefined, NULL);
+ }
+ break;
+
+ case TOKnew:
+ s = parseNew(pAttrs);
+ break;
+
+ case TOKdelete:
+ s = parseDelete(pAttrs);
+ break;
+
+ case TOKcolon:
+ case TOKlcurly:
+ error("declaration expected, not '%s'",token.toChars());
+ goto Lerror;
+
+ case TOKrcurly:
+ case TOKeof:
+ if (once)
+ error("declaration expected, not '%s'", token.toChars());
+ return decldefs;
+
+ case TOKstatic:
+ {
+ TOK next = peekNext();
+ if (next == TOKthis)
+ s = parseStaticCtor(pAttrs);
+ else if (next == TOKtilde)
+ s = parseStaticDtor(pAttrs);
+ else if (next == TOKassert)
+ s = parseStaticAssert();
+ else if (next == TOKif)
+ {
+ condition = parseStaticIfCondition();
+ Dsymbols *athen;
+ if (token.value == TOKcolon)
+ athen = parseBlock(pLastDecl);
+ else
+ {
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = token.loc;
+ athen = parseBlock(pLastDecl);
+ lookingForElse = lookingForElseSave;
+ }
+ Dsymbols *aelse = NULL;
+ if (token.value == TOKelse)
+ {
+ Loc elseloc = token.loc;
+ nextToken();
+ aelse = parseBlock(pLastDecl);
+ checkDanglingElse(elseloc);
+ }
+ s = new StaticIfDeclaration(condition, athen, aelse);
+ }
+ else if (next == TOKimport)
+ {
+ a = parseImport();
+ // keep pLastDecl
+ }
+ else
+ {
+ stc = STCstatic;
+ goto Lstc;
+ }
+ break;
+ }
+
+ case TOKconst:
+ if (peekNext() == TOKlparen)
+ goto Ldeclaration;
+ stc = STCconst;
+ goto Lstc;
+
+ case TOKimmutable:
+ if (peekNext() == TOKlparen)
+ goto Ldeclaration;
+ stc = STCimmutable;
+ goto Lstc;
+
+ case TOKshared:
+ {
+ TOK next = peekNext();
+ if (next == TOKlparen)
+ goto Ldeclaration;
+ if (next == TOKstatic)
+ {
+ TOK next2 = peekNext2();
+ if (next2 == TOKthis)
+ {
+ s = parseSharedStaticCtor(pAttrs);
+ break;
+ }
+ if (next2 == TOKtilde)
+ {
+ s = parseSharedStaticDtor(pAttrs);
+ break;
+ }
+ }
+ stc = STCshared;
+ goto Lstc;
+ }
+
+ case TOKwild:
+ if (peekNext() == TOKlparen)
+ goto Ldeclaration;
+ stc = STCwild;
+ goto Lstc;
+
+ case TOKfinal: stc = STCfinal; goto Lstc;
+ case TOKauto: stc = STCauto; goto Lstc;
+ case TOKscope: stc = STCscope; goto Lstc;
+ case TOKoverride: stc = STCoverride; goto Lstc;
+ case TOKabstract: stc = STCabstract; goto Lstc;
+ case TOKsynchronized: stc = STCsynchronized; goto Lstc;
+ case TOKnothrow: stc = STCnothrow; goto Lstc;
+ case TOKpure: stc = STCpure; goto Lstc;
+ case TOKref: stc = STCref; goto Lstc;
+ case TOKgshared: stc = STCgshared; goto Lstc;
+ //case TOKmanifest: stc = STCmanifest; goto Lstc;
+ case TOKat:
+ {
+ Expressions *exps = NULL;
+ stc = parseAttribute(&exps);
+ if (stc)
+ goto Lstc; // it's a predefined attribute
+ // no redundant/conflicting check for UDAs
+ pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
+ goto Lautodecl;
+ }
+ Lstc:
+ pAttrs->storageClass = appendStorageClass(pAttrs->storageClass, stc);
+ nextToken();
+
+ Lautodecl:
+ Token *tk;
+
+ /* Look for auto initializers:
+ * storage_class identifier = initializer;
+ * storage_class identifier(...) = initializer;
+ */
+ if (token.value == TOKidentifier &&
+ skipParensIf(peek(&token), &tk) &&
+ tk->value == TOKassign)
+ {
+ a = parseAutoDeclarations(pAttrs->storageClass, pAttrs->comment);
+ pAttrs->storageClass = STCundefined;
+ if (a && a->dim)
+ *pLastDecl = (*a)[a->dim-1];
+ if (pAttrs->udas)
+ {
+ s = new UserAttributeDeclaration(pAttrs->udas, a);
+ pAttrs->udas = NULL;
+ }
+ break;
+ }
+
+ /* Look for return type inference for template functions.
+ */
+ if (token.value == TOKidentifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) &&
+ (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin ||
+ tk->value == TOKout || tk->value == TOKdo ||
+ (tk->value == TOKidentifier && tk->ident == Id::_body))
+ )
+ {
+ a = parseDeclarations(true, pAttrs, pAttrs->comment);
+ if (a && a->dim)
+ *pLastDecl = (*a)[a->dim-1];
+ if (pAttrs->udas)
+ {
+ s = new UserAttributeDeclaration(pAttrs->udas, a);
+ pAttrs->udas = NULL;
+ }
+ break;
+ }
+
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs->storageClass != STCundefined)
+ {
+ s = new StorageClassDeclaration(pAttrs->storageClass, a);
+ pAttrs->storageClass = STCundefined;
+ }
+ if (pAttrs->udas)
+ {
+ if (s)
+ {
+ a = new Dsymbols();
+ a->push(s);
+ }
+ s = new UserAttributeDeclaration(pAttrs->udas, a);
+ pAttrs->udas = NULL;
+ }
+ break;
+
+ case TOKdeprecated:
+ {
+ if (peek(&token)->value != TOKlparen)
+ {
+ stc = STCdeprecated;
+ goto Lstc;
+ }
+ nextToken();
+ check(TOKlparen);
+ Expression *e = parseAssignExp();
+ check(TOKrparen);
+ if (pAttrs->depmsg)
+ {
+ error("conflicting storage class 'deprecated(%s)' and 'deprecated(%s)'",
+ pAttrs->depmsg->toChars(), e->toChars());
+ }
+ pAttrs->depmsg = e;
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs->depmsg)
+ {
+ s = new DeprecatedDeclaration(pAttrs->depmsg, a);
+ pAttrs->depmsg = NULL;
+ }
+ break;
+ }
+
+ case TOKlbracket:
+ {
+ if (peekNext() == TOKrbracket)
+ error("empty attribute list is not allowed");
+ error("use @(attributes) instead of [attributes]");
+ Expressions *exps = parseArguments();
+ // no redundant/conflicting check for UDAs
+
+ pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs->udas)
+ {
+ s = new UserAttributeDeclaration(pAttrs->udas, a);
+ pAttrs->udas = NULL;
+ }
+ break;
+ }
+
+ case TOKextern:
+ {
+ if (peek(&token)->value != TOKlparen)
+ {
+ stc = STCextern;
+ goto Lstc;
+ }
+
+ Loc linkLoc = token.loc;
+ Identifiers *idents = NULL;
+ CPPMANGLE cppmangle = CPPMANGLEdefault;
+ LINK link = parseLinkage(&idents, &cppmangle);
+ if (pAttrs->link != LINKdefault)
+ {
+ if (pAttrs->link != link)
+ {
+ error("conflicting linkage extern (%s) and extern (%s)",
+ linkageToChars(pAttrs->link), linkageToChars(link));
+ }
+ else if (idents)
+ {
+ // Allow:
+ // extern(C++, foo) extern(C++, bar) void foo();
+ // to be equivalent with:
+ // extern(C++, foo.bar) void foo();
+ }
+ else
+ error("redundant linkage extern (%s)", linkageToChars(pAttrs->link));
+ }
+ pAttrs->link = link;
+ this->linkage = link;
+ a = parseBlock(pLastDecl, pAttrs);
+ if (idents)
+ {
+ assert(link == LINKcpp);
+ assert(idents->dim);
+ for (size_t i = idents->dim; i;)
+ {
+ Identifier *id = (*idents)[--i];
+ if (s)
+ {
+ a = new Dsymbols();
+ a->push(s);
+ }
+ s = new Nspace(linkLoc, id, a);
+ }
+ delete idents;
+ pAttrs->link = LINKdefault;
+ }
+ else if (pAttrs->link != LINKdefault)
+ {
+ s = new LinkDeclaration(pAttrs->link, a);
+ pAttrs->link = LINKdefault;
+ }
+ else if (cppmangle != CPPMANGLEdefault)
+ {
+ assert(link == LINKcpp);
+ s = new CPPMangleDeclaration(cppmangle, a);
+ }
+ break;
+ }
+
+ case TOKprivate: prot = PROTprivate; goto Lprot;
+ case TOKpackage: prot = PROTpackage; goto Lprot;
+ case TOKprotected: prot = PROTprotected; goto Lprot;
+ case TOKpublic: prot = PROTpublic; goto Lprot;
+ case TOKexport: prot = PROTexport; goto Lprot;
+ Lprot:
+ {
+ if (pAttrs->protection.kind != PROTundefined)
+ {
+ if (pAttrs->protection.kind != prot)
+ error("conflicting protection attribute '%s' and '%s'",
+ protectionToChars(pAttrs->protection.kind), protectionToChars(prot));
+ else
+ error("redundant protection attribute '%s'", protectionToChars(prot));
+ }
+ pAttrs->protection.kind = prot;
+
+ nextToken();
+
+ // optional qualified package identifier to bind
+ // protection to
+ Identifiers *pkg_prot_idents = NULL;
+ if (pAttrs->protection.kind == PROTpackage && token.value == TOKlparen)
+ {
+ pkg_prot_idents = parseQualifiedIdentifier("protection package");
+
+ if (pkg_prot_idents)
+ check(TOKrparen);
+ else
+ {
+ while (token.value != TOKsemicolon && token.value != TOKeof)
+ nextToken();
+ nextToken();
+ break;
+ }
+ }
+
+ Loc attrloc = token.loc;
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs->protection.kind != PROTundefined)
+ {
+ if (pAttrs->protection.kind == PROTpackage && pkg_prot_idents)
+ s = new ProtDeclaration(attrloc, pkg_prot_idents, a);
+ else
+ s = new ProtDeclaration(attrloc, pAttrs->protection, a);
+
+ pAttrs->protection = Prot(PROTundefined);
+ }
+ break;
+ }
+
+ case TOKalign:
+ {
+ const Loc attrLoc = token.loc;
+
+ nextToken();
+
+ Expression *e = NULL; // default
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ e = parseAssignExp();
+ check(TOKrparen);
+ }
+
+ if (pAttrs->setAlignment)
+ {
+ const char *s1 = "";
+ OutBuffer buf1;
+ if (e)
+ {
+ buf1.printf("(%s)", e->toChars());
+ s1 = buf1.peekString();
+ }
+ error("redundant alignment attribute align%s", s1);
+ }
+
+ pAttrs->setAlignment = true;
+ pAttrs->ealign = e;
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs->setAlignment)
+ {
+ s = new AlignDeclaration(attrLoc, pAttrs->ealign, a);
+ pAttrs->setAlignment = false;
+ pAttrs->ealign = NULL;
+ }
+ break;
+ }
+
+ case TOKpragma:
+ {
+ Expressions *args = NULL;
+ Loc loc = token.loc;
+
+ nextToken();
+ check(TOKlparen);
+ if (token.value != TOKidentifier)
+ {
+ error("pragma(identifier) expected");
+ goto Lerror;
+ }
+ Identifier *ident = token.ident;
+ nextToken();
+ if (token.value == TOKcomma && peekNext() != TOKrparen)
+ args = parseArguments(); // pragma(identifier, args...)
+ else
+ check(TOKrparen); // pragma(identifier)
+
+ Dsymbols *a2 = NULL;
+ if (token.value == TOKsemicolon)
+ {
+ /* Bugzilla 2354: Accept single semicolon as an empty
+ * DeclarationBlock following attribute.
+ *
+ * Attribute DeclarationBlock
+ * Pragma DeclDef
+ * ;
+ */
+ nextToken();
+ }
+ else
+ a2 = parseBlock(pLastDecl);
+ s = new PragmaDeclaration(loc, ident, args, a2);
+ break;
+ }
+
+ case TOKdebug:
+ nextToken();
+ if (token.value == TOKassign)
+ {
+ nextToken();
+ if (token.value == TOKidentifier)
+ s = new DebugSymbol(token.loc, token.ident);
+ else if (token.value == TOKint32v || token.value == TOKint64v)
+ s = new DebugSymbol(token.loc, (unsigned)token.uns64value);
+ else
+ {
+ error("identifier or integer expected, not %s", token.toChars());
+ s = NULL;
+ }
+ nextToken();
+ if (token.value != TOKsemicolon)
+ error("semicolon expected");
+ nextToken();
+ break;
+ }
+
+ condition = parseDebugCondition();
+ goto Lcondition;
+
+ case TOKversion:
+ nextToken();
+ if (token.value == TOKassign)
+ {
+ nextToken();
+ if (token.value == TOKidentifier)
+ s = new VersionSymbol(token.loc, token.ident);
+ else if (token.value == TOKint32v || token.value == TOKint64v)
+ s = new VersionSymbol(token.loc, (unsigned)token.uns64value);
+ else
+ {
+ error("identifier or integer expected, not %s", token.toChars());
+ s = NULL;
+ }
+ nextToken();
+ if (token.value != TOKsemicolon)
+ error("semicolon expected");
+ nextToken();
+ break;
+ }
+ condition = parseVersionCondition();
+ goto Lcondition;
+
+ Lcondition:
+ {
+ Dsymbols *athen;
+ if (token.value == TOKcolon)
+ athen = parseBlock(pLastDecl);
+ else
+ {
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = token.loc;
+ athen = parseBlock(pLastDecl);
+ lookingForElse = lookingForElseSave;
+ }
+ Dsymbols *aelse = NULL;
+ if (token.value == TOKelse)
+ {
+ Loc elseloc = token.loc;
+ nextToken();
+ aelse = parseBlock(pLastDecl);
+ checkDanglingElse(elseloc);
+ }
+ s = new ConditionalDeclaration(condition, athen, aelse);
+ break;
+ }
+
+ case TOKsemicolon: // empty declaration
+ //error("empty declaration");
+ nextToken();
+ continue;
+
+ default:
+ error("declaration expected, not '%s'",token.toChars());
+ Lerror:
+ while (token.value != TOKsemicolon && token.value != TOKeof)
+ nextToken();
+ nextToken();
+ s = NULL;
+ continue;
+ }
+
+ if (s)
+ {
+ if (!s->isAttribDeclaration())
+ *pLastDecl = s;
+ decldefs->push(s);
+ addComment(s, pAttrs->comment);
+ }
+ else if (a && a->dim)
+ {
+ decldefs->append(a);
+ }
+ } while (!once);
+
+ linkage = linksave;
+
+ return decldefs;
+}
+
+/*********************************************
+ * Give error on redundant/conflicting storage class.
+ *
+ * TODO: remove deprecation in 2.068 and keep only error
+ */
+
+StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass stc,
+ bool deprec)
+{
+ if ((storageClass & stc) ||
+ (storageClass & STCin && stc & (STCconst | STCscope)) ||
+ (stc & STCin && storageClass & (STCconst | STCscope)))
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, stc);
+ if (deprec)
+ deprecation("redundant attribute '%s'", buf.peekString());
+ else
+ error("redundant attribute '%s'", buf.peekString());
+ return storageClass | stc;
+ }
+
+ storageClass |= stc;
+
+ if (stc & (STCconst | STCimmutable | STCmanifest))
+ {
+ StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest);
+ if (u & (u - 1))
+ error("conflicting attribute '%s'", Token::toChars(token.value));
+ }
+ if (stc & (STCgshared | STCshared | STCtls))
+ {
+ StorageClass u = storageClass & (STCgshared | STCshared | STCtls);
+ if (u & (u - 1))
+ error("conflicting attribute '%s'", Token::toChars(token.value));
+ }
+ if (stc & (STCsafe | STCsystem | STCtrusted))
+ {
+ StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted);
+ if (u & (u - 1))
+ error("conflicting attribute '@%s'", token.toChars());
+ }
+
+ return storageClass;
+}
+
+/***********************************************
+ * Parse attribute, lexer is on '@'.
+ * Input:
+ * pudas array of UDAs to append to
+ * Returns:
+ * storage class if a predefined attribute; also scanner remains on identifier.
+ * 0 if not a predefined attribute
+ * *pudas set if user defined attribute, scanner is past UDA
+ * *pudas NULL if not a user defined attribute
+ */
+
+StorageClass Parser::parseAttribute(Expressions **pudas)
+{
+ nextToken();
+ Expressions *udas = NULL;
+ StorageClass stc = 0;
+ if (token.value == TOKidentifier)
+ {
+ if (token.ident == Id::property)
+ stc = STCproperty;
+ else if (token.ident == Id::nogc)
+ stc = STCnogc;
+ else if (token.ident == Id::safe)
+ stc = STCsafe;
+ else if (token.ident == Id::trusted)
+ stc = STCtrusted;
+ else if (token.ident == Id::system)
+ stc = STCsystem;
+ else if (token.ident == Id::disable)
+ stc = STCdisable;
+ else if (token.ident == Id::future)
+ stc = STCfuture;
+ else
+ {
+ // Allow identifier, template instantiation, or function call
+ Expression *exp = parsePrimaryExp();
+ if (token.value == TOKlparen)
+ {
+ Loc loc = token.loc;
+ exp = new CallExp(loc, exp, parseArguments());
+ }
+
+ udas = new Expressions();
+ udas->push(exp);
+ }
+ }
+ else if (token.value == TOKlparen)
+ {
+ // @( ArgumentList )
+ // Concatenate with existing
+ if (peekNext() == TOKrparen)
+ error("empty attribute list is not allowed");
+ udas = parseArguments();
+ }
+ else
+ {
+ error("@identifier or @(ArgumentList) expected, not @%s", token.toChars());
+ }
+
+ if (stc)
+ {
+ }
+ else if (udas)
+ {
+ *pudas = UserAttributeDeclaration::concat(*pudas, udas);
+ }
+ else
+ error("valid attributes are @property, @safe, @trusted, @system, @disable");
+ return stc;
+}
+
+/***********************************************
+ * Parse const/immutable/shared/inout/nothrow/pure postfix
+ */
+
+StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas)
+{
+ while (1)
+ {
+ StorageClass stc;
+ switch (token.value)
+ {
+ case TOKconst: stc = STCconst; break;
+ case TOKimmutable: stc = STCimmutable; break;
+ case TOKshared: stc = STCshared; break;
+ case TOKwild: stc = STCwild; break;
+ case TOKnothrow: stc = STCnothrow; break;
+ case TOKpure: stc = STCpure; break;
+ case TOKreturn: stc = STCreturn; break;
+ case TOKscope: stc = STCscope; break;
+ case TOKat:
+ {
+ Expressions *udas = NULL;
+ stc = parseAttribute(&udas);
+ if (udas)
+ {
+ if (pudas)
+ *pudas = UserAttributeDeclaration::concat(*pudas, udas);
+ else
+ {
+ // Disallow:
+ // void function() @uda fp;
+ // () @uda { return 1; }
+ error("user defined attributes cannot appear as postfixes");
+ }
+ continue;
+ }
+ break;
+ }
+
+ default:
+ return storageClass;
+ }
+ storageClass = appendStorageClass(storageClass, stc, true);
+ nextToken();
+ }
+}
+
+StorageClass Parser::parseTypeCtor()
+{
+ StorageClass storageClass = STCundefined;
+
+ while (1)
+ {
+ if (peek(&token)->value == TOKlparen)
+ return storageClass;
+
+ StorageClass stc;
+ switch (token.value)
+ {
+ case TOKconst: stc = STCconst; break;
+ case TOKimmutable: stc = STCimmutable; break;
+ case TOKshared: stc = STCshared; break;
+ case TOKwild: stc = STCwild; break;
+
+ default:
+ return storageClass;
+ }
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+}
+
+/********************************************
+ * Parse declarations after an align, protection, or extern decl.
+ */
+
+Dsymbols *Parser::parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
+{
+ Dsymbols *a = NULL;
+
+ //printf("parseBlock()\n");
+ switch (token.value)
+ {
+ case TOKsemicolon:
+ error("declaration expected following attribute, not ';'");
+ nextToken();
+ break;
+
+ case TOKeof:
+ error("declaration expected following attribute, not EOF");
+ break;
+
+ case TOKlcurly:
+ {
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+
+ nextToken();
+ a = parseDeclDefs(0, pLastDecl);
+ if (token.value != TOKrcurly)
+ {
+ /* { */
+ error("matching '}' expected, not %s", token.toChars());
+ }
+ else
+ nextToken();
+ lookingForElse = lookingForElseSave;
+ break;
+ }
+
+ case TOKcolon:
+ nextToken();
+ a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
+ break;
+
+ default:
+ a = parseDeclDefs(1, pLastDecl, pAttrs);
+ break;
+ }
+ return a;
+}
+
+/**********************************
+ * Parse a static assertion.
+ * Current token is 'static'.
+ */
+
+StaticAssert *Parser::parseStaticAssert()
+{
+ Loc loc = token.loc;
+ Expression *exp;
+ Expression *msg = NULL;
+
+ //printf("parseStaticAssert()\n");
+ nextToken();
+ nextToken();
+ check(TOKlparen);
+ exp = parseAssignExp();
+ if (token.value == TOKcomma)
+ {
+ nextToken();
+ if (token.value != TOKrparen)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOKcomma)
+ nextToken();
+ }
+ }
+ check(TOKrparen);
+ check(TOKsemicolon);
+ return new StaticAssert(loc, exp, msg);
+}
+
+/***********************************
+ * Parse typeof(expression).
+ * Current token is on the 'typeof'.
+ */
+
+TypeQualified *Parser::parseTypeof()
+{
+ TypeQualified *t;
+ Loc loc = token.loc;
+
+ nextToken();
+ check(TOKlparen);
+ if (token.value == TOKreturn) // typeof(return)
+ {
+ nextToken();
+ t = new TypeReturn(loc);
+ }
+ else
+ {
+ Expression *exp = parseExpression(); // typeof(expression)
+ t = new TypeTypeof(loc, exp);
+ }
+ check(TOKrparen);
+ return t;
+}
+
+/***********************************
+ * Parse __vector(type).
+ * Current token is on the '__vector'.
+ */
+
+Type *Parser::parseVector()
+{
+ nextToken();
+ check(TOKlparen);
+ Type *tb = parseType();
+ check(TOKrparen);
+ return new TypeVector(tb);
+}
+
+/***********************************
+ * Parse:
+ * extern (linkage)
+ * extern (C++, namespaces)
+ * The parser is on the 'extern' token.
+ */
+
+LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle)
+{
+ Identifiers *idents = NULL;
+ CPPMANGLE cppmangle = CPPMANGLEdefault;
+ LINK link = LINKdefault;
+ nextToken();
+ assert(token.value == TOKlparen);
+ nextToken();
+ if (token.value == TOKidentifier)
+ { Identifier *id = token.ident;
+
+ nextToken();
+ if (id == Id::Windows)
+ link = LINKwindows;
+ else if (id == Id::Pascal)
+ link = LINKpascal;
+ else if (id == Id::D)
+ link = LINKd;
+ else if (id == Id::C)
+ {
+ link = LINKc;
+ if (token.value == TOKplusplus)
+ {
+ link = LINKcpp;
+ nextToken();
+ if (token.value == TOKcomma) // , namespaces or class or struct
+ {
+ nextToken();
+ if (token.value == TOKclass || token.value == TOKstruct)
+ {
+ cppmangle = token.value == TOKclass ? CPPMANGLEclass : CPPMANGLEstruct;
+ nextToken();
+ }
+ else
+ {
+ idents = new Identifiers();
+ while (1)
+ {
+ if (token.value == TOKidentifier)
+ {
+ Identifier *idn = token.ident;
+ idents->push(idn);
+ nextToken();
+ if (token.value == TOKdot)
+ {
+ nextToken();
+ continue;
+ }
+ }
+ else
+ {
+ error("identifier expected for C++ namespace");
+ idents = NULL; // error occurred, invalidate list of elements.
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (id == Id::Objective) // Looking for tokens "Objective-C"
+ {
+ if (token.value == TOKmin)
+ {
+ nextToken();
+ if (token.ident == Id::C)
+ {
+ link = LINKobjc;
+ nextToken();
+ }
+ else
+ goto LinvalidLinkage;
+ }
+ else
+ goto LinvalidLinkage;
+ }
+ else if (id == Id::System)
+ {
+ link = LINKsystem;
+ }
+ else
+ {
+ LinvalidLinkage:
+ error("valid linkage identifiers are D, C, C++, Objective-C, Pascal, Windows, System");
+ link = LINKd;
+ }
+ }
+ else
+ {
+ link = LINKd; // default
+ }
+ check(TOKrparen);
+ *pidents = idents;
+ *pcppmangle = cppmangle;
+ return link;
+}
+
+/***********************************
+ * Parse ident1.ident2.ident3
+ *
+ * Params:
+ * entity = what qualified identifier is expected to resolve into.
+ * Used only for better error message
+ *
+ * Returns:
+ * array of identifiers with actual qualified one stored last
+ */
+Identifiers *Parser::parseQualifiedIdentifier(const char *entity)
+{
+ Identifiers *qualified = NULL;
+
+ do
+ {
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("%s expected as dot-separated identifiers, got '%s'",
+ entity, token.toChars());
+ return NULL;
+ }
+
+ Identifier *id = token.ident;
+ if (!qualified)
+ qualified = new Identifiers();
+ qualified->push(id);
+
+ nextToken();
+ } while (token.value == TOKdot);
+
+ return qualified;
+}
+
+/**************************************
+ * Parse a debug conditional
+ */
+
+Condition *Parser::parseDebugCondition()
+{
+ Condition *c;
+
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ unsigned level = 1;
+ Identifier *id = NULL;
+
+ if (token.value == TOKidentifier)
+ id = token.ident;
+ else if (token.value == TOKint32v || token.value == TOKint64v)
+ level = (unsigned)token.uns64value;
+ else
+ error("identifier or integer expected, not %s", token.toChars());
+ nextToken();
+ check(TOKrparen);
+ c = new DebugCondition(mod, level, id);
+ }
+ else
+ c = new DebugCondition(mod, 1, NULL);
+ return c;
+
+}
+
+/**************************************
+ * Parse a version conditional
+ */
+
+Condition *Parser::parseVersionCondition()
+{
+ Condition *c;
+ unsigned level = 1;
+ Identifier *id = NULL;
+
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ /* Allow:
+ * version (unittest)
+ * version (assert)
+ * even though they are keywords
+ */
+ if (token.value == TOKidentifier)
+ id = token.ident;
+ else if (token.value == TOKint32v || token.value == TOKint64v)
+ level = (unsigned)token.uns64value;
+ else if (token.value == TOKunittest)
+ id = Identifier::idPool(Token::toChars(TOKunittest));
+ else if (token.value == TOKassert)
+ id = Identifier::idPool(Token::toChars(TOKassert));
+ else
+ error("identifier or integer expected, not %s", token.toChars());
+ nextToken();
+ check(TOKrparen);
+
+ }
+ else
+ error("(condition) expected following version");
+ c = new VersionCondition(mod, level, id);
+ return c;
+
+}
+
+/***********************************************
+ * static if (expression)
+ * body
+ * else
+ * body
+ * Current token is 'static'.
+ */
+
+Condition *Parser::parseStaticIfCondition()
+{
+ Expression *exp;
+ Condition *condition;
+ Loc loc = token.loc;
+
+ nextToken();
+ nextToken();
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ exp = parseAssignExp();
+ check(TOKrparen);
+ }
+ else
+ {
+ error("(expression) expected following static if");
+ exp = NULL;
+ }
+ condition = new StaticIfCondition(loc, exp);
+ return condition;
+}
+
+
+/*****************************************
+ * Parse a constructor definition:
+ * this(parameters) { body }
+ * or postblit:
+ * this(this) { body }
+ * or constructor template:
+ * this(templateparameters)(parameters) { body }
+ * Current token is 'this'.
+ */
+
+Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs)
+{
+ Expressions *udas = NULL;
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+ if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen)
+ {
+ // this(this) { ... }
+ nextToken();
+ nextToken();
+ check(TOKrparen);
+
+ stc = parsePostfix(stc, &udas);
+ if (stc & STCstatic)
+ error(loc, "postblit cannot be static");
+
+ PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ if (udas)
+ {
+ Dsymbols *a = new Dsymbols();
+ a->push(f);
+ s = new UserAttributeDeclaration(udas, a);
+ }
+ return s;
+ }
+
+ /* Look ahead to see if:
+ * this(...)(...)
+ * which is a constructor template
+ */
+ TemplateParameters *tpl = NULL;
+ if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
+ {
+ tpl = parseTemplateParameterList();
+ }
+
+ /* Just a regular constructor
+ */
+ int varargs;
+ Parameters *parameters = parseParameters(&varargs);
+ stc = parsePostfix(stc, &udas);
+ if (varargs != 0 || Parameter::dim(parameters) != 0)
+ {
+ if (stc & STCstatic)
+ error(loc, "constructor cannot be static");
+ }
+ else if (StorageClass ss = stc & (STCshared | STCstatic)) // this()
+ {
+ if (ss == STCstatic)
+ error(loc, "use 'static this()' to declare a static constructor");
+ else if (ss == (STCshared | STCstatic))
+ error(loc, "use 'shared static this()' to declare a shared static constructor");
+ }
+
+ Expression *constraint = tpl ? parseConstraint() : NULL;
+
+ Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
+ tf = tf->addSTC(stc);
+
+ CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ if (udas)
+ {
+ Dsymbols *a = new Dsymbols();
+ a->push(f);
+ s = new UserAttributeDeclaration(udas, a);
+ }
+
+ if (tpl)
+ {
+ // Wrap a template around it
+ Dsymbols *decldefs = new Dsymbols();
+ decldefs->push(s);
+ s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs);
+ }
+
+ return s;
+}
+
+/*****************************************
+ * Parse a destructor definition:
+ * ~this() { body }
+ * Current token is '~'.
+ */
+
+Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs)
+{
+ Expressions *udas = NULL;
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+ check(TOKthis);
+ check(TOKlparen);
+ check(TOKrparen);
+
+ stc = parsePostfix(stc, &udas);
+ if (StorageClass ss = stc & (STCshared | STCstatic))
+ {
+ if (ss == STCstatic)
+ error(loc, "use 'static ~this()' to declare a static destructor");
+ else if (ss == (STCshared | STCstatic))
+ error(loc, "use 'shared static ~this()' to declare a shared static destructor");
+ }
+
+ DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ if (udas)
+ {
+ Dsymbols *a = new Dsymbols();
+ a->push(f);
+ s = new UserAttributeDeclaration(udas, a);
+ }
+ return s;
+}
+
+/*****************************************
+ * Parse a static constructor definition:
+ * static this() { body }
+ * Current token is 'static'.
+ */
+
+Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs)
+{
+ //Expressions *udas = NULL;
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+ nextToken();
+ check(TOKlparen);
+ check(TOKrparen);
+
+ stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
+ if (stc & STCshared)
+ error(loc, "use 'shared static this()' to declare a shared static constructor");
+ else if (stc & STCstatic)
+ appendStorageClass(stc, STCstatic); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC_TYPECTOR)
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, modStc);
+ error(loc, "static constructor cannot be %s", buf.peekString());
+ }
+ stc &= ~(STCstatic | STC_TYPECTOR);
+
+ StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ return s;
+}
+
+/*****************************************
+ * Parse a static destructor definition:
+ * static ~this() { body }
+ * Current token is 'static'.
+ */
+
+Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs)
+{
+ Expressions *udas = NULL;
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+ nextToken();
+ check(TOKthis);
+ check(TOKlparen);
+ check(TOKrparen);
+
+ stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
+ if (stc & STCshared)
+ error(loc, "use 'shared static ~this()' to declare a shared static destructor");
+ else if (stc & STCstatic)
+ appendStorageClass(stc, STCstatic); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC_TYPECTOR)
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, modStc);
+ error(loc, "static destructor cannot be %s", buf.peekString());
+ }
+ stc &= ~(STCstatic | STC_TYPECTOR);
+
+ StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ if (udas)
+ {
+ Dsymbols *a = new Dsymbols();
+ a->push(f);
+ s = new UserAttributeDeclaration(udas, a);
+ }
+ return s;
+}
+
+/*****************************************
+ * Parse a shared static constructor definition:
+ * shared static this() { body }
+ * Current token is 'shared'.
+ */
+
+Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs)
+{
+ //Expressions *udas = NULL;
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+ nextToken();
+ nextToken();
+ check(TOKlparen);
+ check(TOKrparen);
+
+ stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
+ if (StorageClass ss = stc & (STCshared | STCstatic))
+ appendStorageClass(stc, ss); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC_TYPECTOR)
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, modStc);
+ error(loc, "shared static constructor cannot be %s", buf.peekString());
+ }
+ stc &= ~(STCstatic | STC_TYPECTOR);
+
+ SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ return s;
+}
+
+/*****************************************
+ * Parse a shared static destructor definition:
+ * shared static ~this() { body }
+ * Current token is 'shared'.
+ */
+
+Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
+{
+ Expressions *udas = NULL;
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+ nextToken();
+ nextToken();
+ check(TOKthis);
+ check(TOKlparen);
+ check(TOKrparen);
+
+ stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
+ if (StorageClass ss = stc & (STCshared | STCstatic))
+ appendStorageClass(stc, ss); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC_TYPECTOR)
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, modStc);
+ error(loc, "shared static destructor cannot be %s", buf.peekString());
+ }
+ stc &= ~(STCstatic | STC_TYPECTOR);
+
+ SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ if (udas)
+ {
+ Dsymbols *a = new Dsymbols();
+ a->push(f);
+ s = new UserAttributeDeclaration(udas, a);
+ }
+ return s;
+}
+
+/*****************************************
+ * Parse an invariant definition:
+ * invariant() { body }
+ * Current token is 'invariant'.
+ */
+
+Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs)
+{
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+ if (token.value == TOKlparen) // optional ()
+ {
+ nextToken();
+ check(TOKrparen);
+ }
+
+ InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ f->fbody = parseStatement(PScurly);
+ return f;
+}
+
+/*****************************************
+ * Parse a unittest definition:
+ * unittest { body }
+ * Current token is 'unittest'.
+ */
+
+Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs)
+{
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+
+ const utf8_t *begPtr = token.ptr + 1; // skip '{'
+ const utf8_t *endPtr = NULL;
+ Statement *sbody = parseStatement(PScurly, &endPtr);
+
+ /** Extract unittest body as a string. Must be done eagerly since memory
+ will be released by the lexer before doc gen. */
+ char *docline = NULL;
+ if (global.params.doDocComments && endPtr > begPtr)
+ {
+ /* Remove trailing whitespaces */
+ for (const utf8_t *p = endPtr - 1;
+ begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
+ {
+ endPtr = p;
+ }
+
+ size_t len = endPtr - begPtr;
+ if (len > 0)
+ {
+ docline = (char *)mem.xmalloc(len + 2);
+ memcpy(docline, begPtr, len);
+ docline[len ] = '\n'; // Terminate all lines by LF
+ docline[len+1] = '\0';
+ }
+ }
+
+ UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ f->fbody = sbody;
+ return f;
+}
+
+/*****************************************
+ * Parse a new definition:
+ * new(parameters) { body }
+ * Current token is 'new'.
+ */
+
+Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs)
+{
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+
+ int varargs;
+ Parameters *parameters = parseParameters(&varargs);
+ NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, parameters, varargs);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ return s;
+}
+
+/*****************************************
+ * Parse a delete definition:
+ * delete(parameters) { body }
+ * Current token is 'delete'.
+ */
+
+Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs)
+{
+ Loc loc = token.loc;
+ StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
+
+ nextToken();
+
+ int varargs;
+ Parameters *parameters = parseParameters(&varargs);
+ if (varargs)
+ error("... not allowed in delete function parameter list");
+ DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, parameters);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ Dsymbol *s = parseContracts(f);
+ return s;
+}
+
+/**********************************************
+ * Parse parameter list.
+ */
+
+Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl)
+{
+ Parameters *parameters = new Parameters();
+ int varargs = 0;
+ int hasdefault = 0;
+
+ check(TOKlparen);
+ while (1)
+ {
+ Identifier *ai = NULL;
+ Type *at;
+ StorageClass storageClass = 0;
+ StorageClass stc;
+ Expression *ae;
+
+ for (;1; nextToken())
+ {
+ switch (token.value)
+ {
+ case TOKrparen:
+ break;
+
+ case TOKdotdotdot:
+ varargs = 1;
+ nextToken();
+ break;
+
+ case TOKconst:
+ if (peek(&token)->value == TOKlparen)
+ goto Ldefault;
+ stc = STCconst;
+ goto L2;
+
+ case TOKimmutable:
+ if (peek(&token)->value == TOKlparen)
+ goto Ldefault;
+ stc = STCimmutable;
+ goto L2;
+
+ case TOKshared:
+ if (peek(&token)->value == TOKlparen)
+ goto Ldefault;
+ stc = STCshared;
+ goto L2;
+
+ case TOKwild:
+ if (peek(&token)->value == TOKlparen)
+ goto Ldefault;
+ stc = STCwild;
+ goto L2;
+
+ case TOKin: stc = STCin; goto L2;
+ case TOKout: stc = STCout; goto L2;
+ case TOKref: stc = STCref; goto L2;
+ case TOKlazy: stc = STClazy; goto L2;
+ case TOKscope: stc = STCscope; goto L2;
+ case TOKfinal: stc = STCfinal; goto L2;
+ case TOKauto: stc = STCauto; goto L2;
+ case TOKreturn: stc = STCreturn; goto L2;
+ L2:
+ storageClass = appendStorageClass(storageClass, stc);
+ continue;
+
+ default:
+ Ldefault:
+ { stc = storageClass & (STCin | STCout | STCref | STClazy);
+ // if stc is not a power of 2
+ if (stc & (stc - 1) &&
+ !(stc == (STCin | STCref)))
+ error("incompatible parameter storage classes");
+ //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
+ //error("scope cannot be ref or out");
+
+ Token *t;
+ if (tpl && token.value == TOKidentifier &&
+ (t = peek(&token), (t->value == TOKcomma ||
+ t->value == TOKrparen ||
+ t->value == TOKdotdotdot)))
+ {
+ Identifier *id = Identifier::generateId("__T");
+ Loc loc = token.loc;
+ at = new TypeIdentifier(loc, id);
+ if (!*tpl)
+ *tpl = new TemplateParameters();
+ TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
+ (*tpl)->push(tp);
+
+ ai = token.ident;
+ nextToken();
+ }
+ else
+ at = parseType(&ai);
+ ae = NULL;
+ if (token.value == TOKassign) // = defaultArg
+ { nextToken();
+ ae = parseDefaultInitExp();
+ hasdefault = 1;
+ }
+ else
+ { if (hasdefault)
+ error("default argument expected for %s",
+ ai ? ai->toChars() : at->toChars());
+ }
+ if (token.value == TOKdotdotdot)
+ { /* This is:
+ * at ai ...
+ */
+
+ if (storageClass & (STCout | STCref))
+ error("variadic argument cannot be out or ref");
+ varargs = 2;
+ parameters->push(new Parameter(storageClass, at, ai, ae));
+ nextToken();
+ break;
+ }
+ parameters->push(new Parameter(storageClass, at, ai, ae));
+ if (token.value == TOKcomma)
+ { nextToken();
+ goto L1;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+
+ L1: ;
+ }
+ check(TOKrparen);
+ *pvarargs = varargs;
+ return parameters;
+}
+
+
+/*************************************
+ */
+
+EnumDeclaration *Parser::parseEnum()
+{
+ EnumDeclaration *e;
+ Identifier *id;
+ Type *memtype;
+ Loc loc = token.loc;
+
+ //printf("Parser::parseEnum()\n");
+ nextToken();
+ if (token.value == TOKidentifier)
+ {
+ id = token.ident;
+ nextToken();
+ }
+ else
+ id = NULL;
+
+ if (token.value == TOKcolon)
+ {
+ nextToken();
+
+ int alt = 0;
+ Loc typeLoc = token.loc;
+ memtype = parseBasicType();
+ memtype = parseDeclarator(memtype, &alt, NULL);
+ checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL);
+ }
+ else
+ memtype = NULL;
+
+ e = new EnumDeclaration(loc, id, memtype);
+ if (token.value == TOKsemicolon && id)
+ nextToken();
+ else if (token.value == TOKlcurly)
+ {
+ //printf("enum definition\n");
+ e->members = new Dsymbols();
+ nextToken();
+ const utf8_t *comment = token.blockComment;
+ while (token.value != TOKrcurly)
+ {
+ /* Can take the following forms:
+ * 1. ident
+ * 2. ident = value
+ * 3. type ident = value
+ */
+
+ loc = token.loc;
+
+ Type *type = NULL;
+ Identifier *ident = NULL;
+ Token *tp = peek(&token);
+ if (token.value == TOKidentifier &&
+ (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
+ {
+ ident = token.ident;
+ type = NULL;
+ nextToken();
+ }
+ else
+ {
+ type = parseType(&ident, NULL);
+ if (!ident)
+ error("no identifier for declarator %s", type->toChars());
+ if (id || memtype)
+ error("type only allowed if anonymous enum and no enum type");
+ }
+
+ Expression *value;
+ if (token.value == TOKassign)
+ {
+ nextToken();
+ value = parseAssignExp();
+ }
+ else
+ {
+ value = NULL;
+ if (type)
+ error("if type, there must be an initializer");
+ }
+
+ EnumMember *em = new EnumMember(loc, ident, value, type);
+ e->members->push(em);
+
+ if (token.value == TOKrcurly)
+ ;
+ else
+ {
+ addComment(em, comment);
+ comment = NULL;
+ check(TOKcomma);
+ }
+ addComment(em, comment);
+ comment = token.blockComment;
+
+ if (token.value == TOKeof)
+ {
+ error("premature end of file");
+ break;
+ }
+ }
+ nextToken();
+ }
+ else
+ error("enum declaration is invalid");
+
+ //printf("-parseEnum() %s\n", e->toChars());
+ return e;
+}
+
+/********************************
+ * Parse struct, union, interface, class.
+ */
+
+Dsymbol *Parser::parseAggregate()
+{
+ AggregateDeclaration *a = NULL;
+ int anon = 0;
+ Identifier *id;
+ TemplateParameters *tpl = NULL;
+ Expression *constraint = NULL;
+ Loc loc = token.loc;
+ TOK tok = token.value;
+
+ //printf("Parser::parseAggregate()\n");
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ id = NULL;
+ }
+ else
+ {
+ id = token.ident;
+ nextToken();
+
+ if (token.value == TOKlparen)
+ {
+ // Class template declaration.
+ // Gather template parameter list
+ tpl = parseTemplateParameterList();
+ constraint = parseConstraint();
+ }
+ }
+
+ switch (tok)
+ {
+ case TOKclass:
+ case TOKinterface:
+ {
+ if (!id)
+ error(loc, "anonymous classes not allowed");
+
+ // Collect base class(es)
+ BaseClasses *baseclasses = NULL;
+ if (token.value == TOKcolon)
+ {
+ nextToken();
+ baseclasses = parseBaseClasses();
+
+ if (tpl)
+ {
+ Expression *tempCons = parseConstraint();
+ if (tempCons)
+ {
+ if (constraint)
+ error("members expected");
+ else
+ constraint = tempCons;
+ }
+ }
+
+ if (token.value != TOKlcurly)
+ error("members expected");
+ }
+
+ if (tok == TOKclass)
+ {
+ bool inObject = md && !md->packages && md->id == Id::object;
+ a = new ClassDeclaration(loc, id, baseclasses, NULL, inObject);
+ }
+ else
+ a = new InterfaceDeclaration(loc, id, baseclasses);
+ break;
+ }
+
+ case TOKstruct:
+ if (id)
+ {
+ bool inObject = md && !md->packages && md->id == Id::object;
+ a = new StructDeclaration(loc, id, inObject);
+ }
+ else
+ anon = 1;
+ break;
+
+ case TOKunion:
+ if (id)
+ a = new UnionDeclaration(loc, id);
+ else
+ anon = 2;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ if (a && token.value == TOKsemicolon)
+ {
+ nextToken();
+ }
+ else if (token.value == TOKlcurly)
+ {
+ const Loc lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+ //printf("aggregate definition\n");
+ nextToken();
+ Dsymbols *decl = parseDeclDefs(0);
+ lookingForElse = lookingForElseSave;
+ if (token.value != TOKrcurly)
+ error("} expected following members in %s declaration at %s",
+ Token::toChars(tok), loc.toChars());
+ nextToken();
+ if (anon)
+ {
+ /* Anonymous structs/unions are more like attributes.
+ */
+ return new AnonDeclaration(loc, anon == 2, decl);
+ }
+ else
+ a->members = decl;
+ }
+ else
+ {
+ error("{ } expected following %s declaration", Token::toChars(tok));
+ a = new StructDeclaration(loc, NULL, false);
+ }
+
+ if (tpl)
+ {
+ // Wrap a template around the aggregate declaration
+ Dsymbols *decldefs = new Dsymbols();
+ decldefs->push(a);
+ TemplateDeclaration *tempdecl =
+ new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
+ return tempdecl;
+ }
+
+ return a;
+}
+
+/*******************************************
+ */
+
+BaseClasses *Parser::parseBaseClasses()
+{
+ BaseClasses *baseclasses = new BaseClasses();
+
+ for (; 1; nextToken())
+ {
+ bool prot = false;
+ Prot protection = Prot(PROTpublic);
+ switch (token.value)
+ {
+ case TOKprivate:
+ prot = true;
+ protection = Prot(PROTprivate);
+ nextToken();
+ break;
+ case TOKpackage:
+ prot = true;
+ protection = Prot(PROTpackage);
+ nextToken();
+ break;
+ case TOKprotected:
+ prot = true;
+ protection = Prot(PROTprotected);
+ nextToken();
+ break;
+ case TOKpublic:
+ prot = true;
+ protection = Prot(PROTpublic);
+ nextToken();
+ break;
+ default: break;
+ }
+ if (prot)
+ error("use of base class protection is no longer supported");
+ BaseClass *b = new BaseClass(parseBasicType());
+ baseclasses->push(b);
+ if (token.value != TOKcomma)
+ break;
+ }
+ return baseclasses;
+}
+
+/**************************************
+ * Parse constraint.
+ * Constraint is of the form:
+ * if ( ConstraintExpression )
+ */
+
+Expression *Parser::parseConstraint()
+{ Expression *e = NULL;
+
+ if (token.value == TOKif)
+ {
+ nextToken(); // skip over 'if'
+ check(TOKlparen);
+ e = parseExpression();
+ check(TOKrparen);
+ }
+ return e;
+}
+
+/**************************************
+ * Parse a TemplateDeclaration.
+ */
+
+TemplateDeclaration *Parser::parseTemplateDeclaration(bool ismixin)
+{
+ TemplateDeclaration *tempdecl;
+ Identifier *id;
+ TemplateParameters *tpl;
+ Dsymbols *decldefs;
+ Expression *constraint = NULL;
+ Loc loc = token.loc;
+
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following template");
+ goto Lerr;
+ }
+ id = token.ident;
+ nextToken();
+ tpl = parseTemplateParameterList();
+ if (!tpl)
+ goto Lerr;
+
+ constraint = parseConstraint();
+
+ if (token.value != TOKlcurly)
+ {
+ error("members of template declaration expected");
+ goto Lerr;
+ }
+ else
+ decldefs = parseBlock(NULL);
+
+ tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
+ return tempdecl;
+
+Lerr:
+ return NULL;
+}
+
+/******************************************
+ * Parse template parameter list.
+ * Input:
+ * flag 0: parsing "( list )"
+ * 1: parsing non-empty "list )"
+ */
+
+TemplateParameters *Parser::parseTemplateParameterList(int flag)
+{
+ TemplateParameters *tpl = new TemplateParameters();
+
+ if (!flag && token.value != TOKlparen)
+ { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
+ goto Lerr;
+ }
+ nextToken();
+
+ // Get array of TemplateParameters
+ if (flag || token.value != TOKrparen)
+ {
+ int isvariadic = 0;
+ while (token.value != TOKrparen)
+ {
+ TemplateParameter *tp;
+ Loc loc;
+ Identifier *tp_ident = NULL;
+ Type *tp_spectype = NULL;
+ Type *tp_valtype = NULL;
+ Type *tp_defaulttype = NULL;
+ Expression *tp_specvalue = NULL;
+ Expression *tp_defaultvalue = NULL;
+ Token *t;
+
+ // Get TemplateParameter
+
+ // First, look ahead to see if it is a TypeParameter or a ValueParameter
+ t = peek(&token);
+ if (token.value == TOKalias)
+ { // AliasParameter
+ nextToken();
+ loc = token.loc; // todo
+ Type *spectype = NULL;
+ if (isDeclaration(&token, 2, TOKreserved, NULL))
+ {
+ spectype = parseType(&tp_ident);
+ }
+ else
+ {
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected for template alias parameter");
+ goto Lerr;
+ }
+ tp_ident = token.ident;
+ nextToken();
+ }
+ RootObject *spec = NULL;
+ if (token.value == TOKcolon) // : Type
+ {
+ nextToken();
+ if (isDeclaration(&token, 0, TOKreserved, NULL))
+ spec = parseType();
+ else
+ spec = parseCondExp();
+ }
+ RootObject *def = NULL;
+ if (token.value == TOKassign) // = Type
+ {
+ nextToken();
+ if (isDeclaration(&token, 0, TOKreserved, NULL))
+ def = parseType();
+ else
+ def = parseCondExp();
+ }
+ tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
+ }
+ else if (t->value == TOKcolon || t->value == TOKassign ||
+ t->value == TOKcomma || t->value == TOKrparen)
+ {
+ // TypeParameter
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected for template type parameter");
+ goto Lerr;
+ }
+ loc = token.loc;
+ tp_ident = token.ident;
+ nextToken();
+ if (token.value == TOKcolon) // : Type
+ {
+ nextToken();
+ tp_spectype = parseType();
+ }
+ if (token.value == TOKassign) // = Type
+ {
+ nextToken();
+ tp_defaulttype = parseType();
+ }
+ tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+ }
+ else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
+ {
+ // ident...
+ if (isvariadic)
+ error("variadic template parameter must be last");
+ isvariadic = 1;
+ loc = token.loc;
+ tp_ident = token.ident;
+ nextToken();
+ nextToken();
+ tp = new TemplateTupleParameter(loc, tp_ident);
+ }
+ else if (token.value == TOKthis)
+ {
+ // ThisParameter
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected for template this parameter");
+ goto Lerr;
+ }
+ loc = token.loc;
+ tp_ident = token.ident;
+ nextToken();
+ if (token.value == TOKcolon) // : Type
+ {
+ nextToken();
+ tp_spectype = parseType();
+ }
+ if (token.value == TOKassign) // = Type
+ {
+ nextToken();
+ tp_defaulttype = parseType();
+ }
+ tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+ }
+ else
+ {
+ // ValueParameter
+ loc = token.loc; // todo
+ tp_valtype = parseType(&tp_ident);
+ if (!tp_ident)
+ {
+ error("identifier expected for template value parameter");
+ tp_ident = Identifier::idPool("error");
+ }
+ if (token.value == TOKcolon) // : CondExpression
+ {
+ nextToken();
+ tp_specvalue = parseCondExp();
+ }
+ if (token.value == TOKassign) // = CondExpression
+ {
+ nextToken();
+ tp_defaultvalue = parseDefaultInitExp();
+ }
+ tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
+ }
+ tpl->push(tp);
+ if (token.value != TOKcomma)
+ break;
+ nextToken();
+ }
+ }
+ check(TOKrparen);
+Lerr:
+ return tpl;
+}
+
+/******************************************
+ * Parse template mixin.
+ * mixin Foo;
+ * mixin Foo!(args);
+ * mixin a.b.c!(args).Foo!(args);
+ * mixin Foo!(args) identifier;
+ * mixin typeof(expr).identifier!(args);
+ */
+
+Dsymbol *Parser::parseMixin()
+{
+ TemplateMixin *tm;
+ Identifier *id;
+ Objects *tiargs;
+
+ //printf("parseMixin()\n");
+ Loc locMixin = token.loc;
+ nextToken(); // skip 'mixin'
+
+ Loc loc = token.loc;
+ TypeQualified *tqual = NULL;
+ if (token.value == TOKdot)
+ {
+ id = Id::empty;
+ }
+ else
+ {
+ if (token.value == TOKtypeof)
+ {
+ tqual = parseTypeof();
+ check(TOKdot);
+ }
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected, not %s", token.toChars());
+ id = Id::empty;
+ }
+ else
+ id = token.ident;
+ nextToken();
+ }
+
+ while (1)
+ {
+ tiargs = NULL;
+ if (token.value == TOKnot)
+ {
+ tiargs = parseTemplateArguments();
+ }
+
+ if (tiargs && token.value == TOKdot)
+ {
+ TemplateInstance *tempinst = new TemplateInstance(loc, id);
+ tempinst->tiargs = tiargs;
+ if (!tqual)
+ tqual = new TypeInstance(loc, tempinst);
+ else
+ tqual->addInst(tempinst);
+ tiargs = NULL;
+ }
+ else
+ {
+ if (!tqual)
+ tqual = new TypeIdentifier(loc, id);
+ else
+ tqual->addIdent(id);
+ }
+
+ if (token.value != TOKdot)
+ break;
+
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following '.' instead of '%s'", token.toChars());
+ break;
+ }
+ loc = token.loc;
+ id = token.ident;
+ nextToken();
+ }
+
+ if (token.value == TOKidentifier)
+ {
+ id = token.ident;
+ nextToken();
+ }
+ else
+ id = NULL;
+
+ tm = new TemplateMixin(locMixin, id, tqual, tiargs);
+ if (token.value != TOKsemicolon)
+ error("';' expected after mixin");
+ nextToken();
+
+ return tm;
+}
+
+/******************************************
+ * Parse template arguments.
+ * Input:
+ * current token is opening '!'
+ * Output:
+ * current token is one after closing ')'
+ */
+
+Objects *Parser::parseTemplateArguments()
+{
+ Objects *tiargs;
+
+ nextToken();
+ if (token.value == TOKlparen)
+ {
+ // ident!(template_arguments)
+ tiargs = parseTemplateArgumentList();
+ }
+ else
+ {
+ // ident!template_argument
+ tiargs = parseTemplateSingleArgument();
+ }
+ if (token.value == TOKnot)
+ {
+ TOK tok = peekNext();
+ if (tok != TOKis && tok != TOKin)
+ {
+ error("multiple ! arguments are not allowed");
+ Lagain:
+ nextToken();
+ if (token.value == TOKlparen)
+ parseTemplateArgumentList();
+ else
+ parseTemplateSingleArgument();
+ if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin)
+ goto Lagain;
+ }
+ }
+ return tiargs;
+}
+
+/******************************************
+ * Parse template argument list.
+ * Input:
+ * current token is opening '(',
+ * or ',' for __traits
+ * Output:
+ * current token is one after closing ')'
+ */
+
+Objects *Parser::parseTemplateArgumentList()
+{
+ //printf("Parser::parseTemplateArgumentList()\n");
+ Objects *tiargs = new Objects();
+ TOK endtok = TOKrparen;
+ assert(token.value == TOKlparen || token.value == TOKcomma);
+ nextToken();
+
+ // Get TemplateArgumentList
+ while (token.value != endtok)
+ {
+ // See if it is an Expression or a Type
+ if (isDeclaration(&token, 0, TOKreserved, NULL))
+ { // Template argument is a type
+ Type *ta = parseType();
+ tiargs->push(ta);
+ }
+ else
+ { // Template argument is an expression
+ Expression *ea = parseAssignExp();
+ tiargs->push(ea);
+ }
+ if (token.value != TOKcomma)
+ break;
+ nextToken();
+ }
+ check(endtok, "template argument list");
+ return tiargs;
+}
+
+/*****************************
+ * Parse single template argument, to support the syntax:
+ * foo!arg
+ * Input:
+ * current token is the arg
+ */
+
+Objects *Parser::parseTemplateSingleArgument()
+{
+ //printf("parseTemplateSingleArgument()\n");
+ Objects *tiargs = new Objects();
+ Type *ta;
+ switch (token.value)
+ {
+ case TOKidentifier:
+ ta = new TypeIdentifier(token.loc, token.ident);
+ goto LabelX;
+
+ case TOKvector:
+ ta = parseVector();
+ goto LabelX;
+
+ case TOKvoid: ta = Type::tvoid; goto LabelX;
+ case TOKint8: ta = Type::tint8; goto LabelX;
+ case TOKuns8: ta = Type::tuns8; goto LabelX;
+ case TOKint16: ta = Type::tint16; goto LabelX;
+ case TOKuns16: ta = Type::tuns16; goto LabelX;
+ case TOKint32: ta = Type::tint32; goto LabelX;
+ case TOKuns32: ta = Type::tuns32; goto LabelX;
+ case TOKint64: ta = Type::tint64; goto LabelX;
+ case TOKuns64: ta = Type::tuns64; goto LabelX;
+ case TOKint128: ta = Type::tint128; goto LabelX;
+ case TOKuns128: ta = Type::tuns128; goto LabelX;
+ case TOKfloat32: ta = Type::tfloat32; goto LabelX;
+ case TOKfloat64: ta = Type::tfloat64; goto LabelX;
+ case TOKfloat80: ta = Type::tfloat80; goto LabelX;
+ case TOKimaginary32: ta = Type::timaginary32; goto LabelX;
+ case TOKimaginary64: ta = Type::timaginary64; goto LabelX;
+ case TOKimaginary80: ta = Type::timaginary80; goto LabelX;
+ case TOKcomplex32: ta = Type::tcomplex32; goto LabelX;
+ case TOKcomplex64: ta = Type::tcomplex64; goto LabelX;
+ case TOKcomplex80: ta = Type::tcomplex80; goto LabelX;
+ case TOKbool: ta = Type::tbool; goto LabelX;
+ case TOKchar: ta = Type::tchar; goto LabelX;
+ case TOKwchar: ta = Type::twchar; goto LabelX;
+ case TOKdchar: ta = Type::tdchar; goto LabelX;
+ LabelX:
+ tiargs->push(ta);
+ nextToken();
+ break;
+
+ case TOKint32v:
+ case TOKuns32v:
+ case TOKint64v:
+ case TOKuns64v:
+ case TOKint128v:
+ case TOKuns128v:
+ case TOKfloat32v:
+ case TOKfloat64v:
+ case TOKfloat80v:
+ case TOKimaginary32v:
+ case TOKimaginary64v:
+ case TOKimaginary80v:
+ case TOKnull:
+ case TOKtrue:
+ case TOKfalse:
+ case TOKcharv:
+ case TOKwcharv:
+ case TOKdcharv:
+ case TOKstring:
+ case TOKxstring:
+ case TOKfile:
+ case TOKfilefullpath:
+ case TOKline:
+ case TOKmodulestring:
+ case TOKfuncstring:
+ case TOKprettyfunc:
+ case TOKthis:
+ { // Template argument is an expression
+ Expression *ea = parsePrimaryExp();
+ tiargs->push(ea);
+ break;
+ }
+
+ default:
+ error("template argument expected following !");
+ break;
+ }
+ return tiargs;
+}
+
+Dsymbols *Parser::parseImport()
+{
+ Dsymbols *decldefs = new Dsymbols();
+ Identifier *aliasid = NULL;
+
+ int isstatic = token.value == TOKstatic;
+ if (isstatic)
+ nextToken();
+
+ //printf("Parser::parseImport()\n");
+ do
+ {
+ L1:
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following import");
+ break;
+ }
+
+ Loc loc = token.loc;
+ Identifier *id = token.ident;
+ Identifiers *a = NULL;
+ nextToken();
+ if (!aliasid && token.value == TOKassign)
+ {
+ aliasid = id;
+ goto L1;
+ }
+ while (token.value == TOKdot)
+ {
+ if (!a)
+ a = new Identifiers();
+ a->push(id);
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following package");
+ break;
+ }
+ id = token.ident;
+ nextToken();
+ }
+
+ Import *s = new Import(loc, a, id, aliasid, isstatic);
+ decldefs->push(s);
+
+ /* Look for
+ * : alias=name, alias=name;
+ * syntax.
+ */
+ if (token.value == TOKcolon)
+ {
+ do
+ {
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following :");
+ break;
+ }
+ Identifier *alias = token.ident;
+ Identifier *name;
+ nextToken();
+ if (token.value == TOKassign)
+ {
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following %s=", alias->toChars());
+ break;
+ }
+ name = token.ident;
+ nextToken();
+ }
+ else
+ {
+ name = alias;
+ alias = NULL;
+ }
+ s->addAlias(name, alias);
+ } while (token.value == TOKcomma);
+ break; // no comma-separated imports of this form
+ }
+
+ aliasid = NULL;
+ } while (token.value == TOKcomma);
+
+ if (token.value == TOKsemicolon)
+ nextToken();
+ else
+ {
+ error("';' expected");
+ nextToken();
+ }
+
+ return decldefs;
+}
+
+Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl)
+{
+ /* Take care of the storage class prefixes that
+ * serve as type attributes:
+ * const type
+ * immutable type
+ * shared type
+ * inout type
+ * inout const type
+ * shared const type
+ * shared inout type
+ * shared inout const type
+ */
+ StorageClass stc = 0;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKconst:
+ if (peekNext() == TOKlparen)
+ break; // const as type constructor
+ stc |= STCconst; // const as storage class
+ nextToken();
+ continue;
+
+ case TOKimmutable:
+ if (peekNext() == TOKlparen)
+ break;
+ stc |= STCimmutable;
+ nextToken();
+ continue;
+
+ case TOKshared:
+ if (peekNext() == TOKlparen)
+ break;
+ stc |= STCshared;
+ nextToken();
+ continue;
+
+ case TOKwild:
+ if (peekNext() == TOKlparen)
+ break;
+ stc |= STCwild;
+ nextToken();
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ Loc typeLoc = token.loc;
+
+ Type *t;
+ t = parseBasicType();
+
+ int alt = 0;
+ t = parseDeclarator(t, &alt, pident, ptpl);
+ checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL);
+
+ t = t->addSTC(stc);
+ return t;
+}
+
+Type *Parser::parseBasicType(bool dontLookDotIdents)
+{
+ Type *t;
+ Loc loc;
+ Identifier *id;
+
+ //printf("parseBasicType()\n");
+ switch (token.value)
+ {
+ case TOKvoid: t = Type::tvoid; goto LabelX;
+ case TOKint8: t = Type::tint8; goto LabelX;
+ case TOKuns8: t = Type::tuns8; goto LabelX;
+ case TOKint16: t = Type::tint16; goto LabelX;
+ case TOKuns16: t = Type::tuns16; goto LabelX;
+ case TOKint32: t = Type::tint32; goto LabelX;
+ case TOKuns32: t = Type::tuns32; goto LabelX;
+ case TOKint64: t = Type::tint64; goto LabelX;
+ case TOKuns64: t = Type::tuns64; goto LabelX;
+ case TOKint128: t = Type::tint128; goto LabelX;
+ case TOKuns128: t = Type::tuns128; goto LabelX;
+ case TOKfloat32: t = Type::tfloat32; goto LabelX;
+ case TOKfloat64: t = Type::tfloat64; goto LabelX;
+ case TOKfloat80: t = Type::tfloat80; goto LabelX;
+ case TOKimaginary32: t = Type::timaginary32; goto LabelX;
+ case TOKimaginary64: t = Type::timaginary64; goto LabelX;
+ case TOKimaginary80: t = Type::timaginary80; goto LabelX;
+ case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
+ case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
+ case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
+ case TOKbool: t = Type::tbool; goto LabelX;
+ case TOKchar: t = Type::tchar; goto LabelX;
+ case TOKwchar: t = Type::twchar; goto LabelX;
+ case TOKdchar: t = Type::tdchar; goto LabelX;
+ LabelX:
+ nextToken();
+ break;
+
+ case TOKthis:
+ case TOKsuper:
+ case TOKidentifier:
+ loc = token.loc;
+ id = token.ident;
+ nextToken();
+ if (token.value == TOKnot)
+ {
+ // ident!(template_arguments)
+ TemplateInstance *tempinst = new TemplateInstance(loc, id);
+ tempinst->tiargs = parseTemplateArguments();
+ t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents);
+ }
+ else
+ {
+ t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents);
+ }
+ break;
+
+ case TOKdot:
+ // Leading . as in .foo
+ t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
+ break;
+
+ case TOKtypeof:
+ // typeof(expression)
+ t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
+ break;
+
+ case TOKvector:
+ t = parseVector();
+ break;
+
+ case TOKconst:
+ // const(type)
+ nextToken();
+ check(TOKlparen);
+ t = parseType()->addSTC(STCconst);
+ check(TOKrparen);
+ break;
+
+ case TOKimmutable:
+ // immutable(type)
+ nextToken();
+ check(TOKlparen);
+ t = parseType()->addSTC(STCimmutable);
+ check(TOKrparen);
+ break;
+
+ case TOKshared:
+ // shared(type)
+ nextToken();
+ check(TOKlparen);
+ t = parseType()->addSTC(STCshared);
+ check(TOKrparen);
+ break;
+
+ case TOKwild:
+ // wild(type)
+ nextToken();
+ check(TOKlparen);
+ t = parseType()->addSTC(STCwild);
+ check(TOKrparen);
+ break;
+
+ default:
+ error("basic type expected, not %s", token.toChars());
+ t = Type::terror;
+ break;
+ }
+ return t;
+}
+
+Type *Parser::parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents)
+{
+ Type *maybeArray = NULL;
+ // See https://issues.dlang.org/show_bug.cgi?id=1215
+ // A basic type can look like MyType (typical case), but also:
+ // MyType.T -> A type
+ // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
+ // MyType[expr].T -> A type.
+ // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
+ // (iif MyType[expr].T is a Ttuple)
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKdot:
+ {
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following '.' instead of '%s'", token.toChars());
+ break;
+ }
+ if (maybeArray)
+ {
+ // This is actually a TypeTuple index, not an {a/s}array.
+ // We need to have a while loop to unwind all index taking:
+ // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
+ Objects dimStack;
+ Type *t = maybeArray;
+ while (true)
+ {
+ if (t->ty == Tsarray)
+ {
+ // The index expression is an Expression.
+ TypeSArray *a = (TypeSArray *)t;
+ dimStack.push(a->dim->syntaxCopy());
+ t = a->next->syntaxCopy();
+ }
+ else if (t->ty == Taarray)
+ {
+ // The index expression is a Type. It will be interpreted as an expression at semantic time.
+ TypeAArray *a = (TypeAArray *)t;
+ dimStack.push(a->index->syntaxCopy());
+ t = a->next->syntaxCopy();
+ }
+ else
+ {
+ break;
+ }
+ }
+ assert(dimStack.dim > 0);
+ // We're good. Replay indices in the reverse order.
+ tid = (TypeQualified *)t;
+ while (dimStack.dim)
+ {
+ tid->addIndex(dimStack.pop());
+ }
+ maybeArray = NULL;
+ }
+ Loc loc = token.loc;
+ Identifier *id = token.ident;
+ nextToken();
+ if (token.value == TOKnot)
+ {
+ TemplateInstance *tempinst = new TemplateInstance(loc, id);
+ tempinst->tiargs = parseTemplateArguments();
+ tid->addInst(tempinst);
+ }
+ else
+ tid->addIdent(id);
+ continue;
+ }
+ case TOKlbracket:
+ {
+ if (dontLookDotIdents) // workaround for Bugzilla 14911
+ goto Lend;
+
+ nextToken();
+ Type *t = maybeArray ? maybeArray : (Type *)tid;
+ if (token.value == TOKrbracket)
+ {
+ // It's a dynamic array, and we're done:
+ // T[].U does not make sense.
+ t = new TypeDArray(t);
+ nextToken();
+ return t;
+ }
+ else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+ {
+ // This can be one of two things:
+ // 1 - an associative array declaration, T[type]
+ // 2 - an associative array declaration, T[expr]
+ // These can only be disambiguated later.
+ Type *index = parseType(); // [ type ]
+ maybeArray = new TypeAArray(t, index);
+ check(TOKrbracket);
+ }
+ else
+ {
+ // This can be one of three things:
+ // 1 - an static array declaration, T[expr]
+ // 2 - a slice, T[expr .. expr]
+ // 3 - a template parameter pack index expression, T[expr].U
+ // 1 and 3 can only be disambiguated later.
+ //printf("it's type[expression]\n");
+ inBrackets++;
+ Expression *e = parseAssignExp(); // [ expression ]
+ if (token.value == TOKslice)
+ {
+ // It's a slice, and we're done.
+ nextToken();
+ Expression *e2 = parseAssignExp(); // [ exp .. exp ]
+ t = new TypeSlice(t, e, e2);
+ inBrackets--;
+ check(TOKrbracket);
+ return t;
+ }
+ else
+ {
+ maybeArray = new TypeSArray(t, e);
+ inBrackets--;
+ check(TOKrbracket);
+ continue;
+ }
+ }
+ break;
+ }
+ default:
+ goto Lend;
+ }
+ }
+Lend:
+ return maybeArray ? maybeArray : (Type *)tid;
+}
+
+/******************************************
+ * Parse things that follow the initial type t.
+ * t *
+ * t []
+ * t [type]
+ * t [expression]
+ * t [expression .. expression]
+ * t function
+ * t delegate
+ */
+
+Type *Parser::parseBasicType2(Type *t)
+{
+ //printf("parseBasicType2()\n");
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKmul:
+ t = new TypePointer(t);
+ nextToken();
+ continue;
+
+ case TOKlbracket:
+ // Handle []. Make sure things like
+ // int[3][1] a;
+ // is (array[1] of array[3] of int)
+ nextToken();
+ if (token.value == TOKrbracket)
+ {
+ t = new TypeDArray(t); // []
+ nextToken();
+ }
+ else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+ {
+ // It's an associative array declaration
+ //printf("it's an associative array\n");
+ Type *index = parseType(); // [ type ]
+ t = new TypeAArray(t, index);
+ check(TOKrbracket);
+ }
+ else
+ {
+ //printf("it's type[expression]\n");
+ inBrackets++;
+ Expression *e = parseAssignExp(); // [ expression ]
+ if (token.value == TOKslice)
+ {
+ nextToken();
+ Expression *e2 = parseAssignExp(); // [ exp .. exp ]
+ t = new TypeSlice(t, e, e2);
+ }
+ else
+ {
+ t = new TypeSArray(t,e);
+ }
+ inBrackets--;
+ check(TOKrbracket);
+ }
+ continue;
+
+ case TOKdelegate:
+ case TOKfunction:
+ {
+ // Handle delegate declaration:
+ // t delegate(parameter list) nothrow pure
+ // t function(parameter list) nothrow pure
+ TOK save = token.value;
+ nextToken();
+
+ int varargs;
+ Parameters *parameters = parseParameters(&varargs);
+
+ StorageClass stc = parsePostfix(STCundefined, NULL);
+ TypeFunction *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
+ if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn))
+ {
+ if (save == TOKfunction)
+ error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
+ else
+ tf = (TypeFunction *)tf->addSTC(stc);
+ }
+
+ if (save == TOKdelegate)
+ t = new TypeDelegate(tf);
+ else
+ t = new TypePointer(tf); // pointer to function
+ continue;
+ }
+
+ default:
+ return t;
+ }
+ assert(0);
+ }
+ assert(0);
+ return NULL;
+}
+
+Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
+ TemplateParameters **tpl, StorageClass storageClass, int *pdisable, Expressions **pudas)
+{
+ //printf("parseDeclarator(tpl = %p)\n", tpl);
+ t = parseBasicType2(t);
+
+ Type *ts;
+ switch (token.value)
+ {
+ case TOKidentifier:
+ if (pident)
+ *pident = token.ident;
+ else
+ error("unexpected identifer '%s' in declarator", token.ident->toChars());
+ ts = t;
+ nextToken();
+ break;
+
+ case TOKlparen:
+ {
+ // like: T (*fp)();
+ // like: T ((*fp))();
+ if (peekNext() == TOKmul ||
+ peekNext() == TOKlparen)
+ {
+ /* Parse things with parentheses around the identifier, like:
+ * int (*ident[3])[]
+ * although the D style would be:
+ * int[]*[3] ident
+ */
+ *palt |= 1;
+ nextToken();
+ ts = parseDeclarator(t, palt, pident);
+ check(TOKrparen);
+ break;
+ }
+ ts = t;
+
+ Token *peekt = &token;
+ /* Completely disallow C-style things like:
+ * T (a);
+ * Improve error messages for the common bug of a missing return type
+ * by looking to see if (a) looks like a parameter list.
+ */
+ if (isParameters(&peekt))
+ {
+ error("function declaration without return type. (Note that constructors are always named 'this')");
+ }
+ else
+ error("unexpected ( in declarator");
+ break;
+ }
+
+ default:
+ ts = t;
+ break;
+ }
+
+ // parse DeclaratorSuffixes
+ while (1)
+ {
+ switch (token.value)
+ {
+#if CARRAYDECL
+ /* Support C style array syntax:
+ * int ident[]
+ * as opposed to D-style:
+ * int[] ident
+ */
+ case TOKlbracket:
+ {
+ // This is the old C-style post [] syntax.
+ TypeNext *ta;
+ nextToken();
+ if (token.value == TOKrbracket)
+ {
+ // It's a dynamic array
+ ta = new TypeDArray(t); // []
+ nextToken();
+ *palt |= 2;
+ }
+ else if (isDeclaration(&token, 0, TOKrbracket, NULL))
+ {
+ // It's an associative array
+ //printf("it's an associative array\n");
+ Type *index = parseType(); // [ type ]
+ check(TOKrbracket);
+ ta = new TypeAArray(t, index);
+ *palt |= 2;
+ }
+ else
+ {
+ //printf("It's a static array\n");
+ Expression *e = parseAssignExp(); // [ expression ]
+ ta = new TypeSArray(t, e);
+ check(TOKrbracket);
+ *palt |= 2;
+ }
+
+ /* Insert ta into
+ * ts -> ... -> t
+ * so that
+ * ts -> ... -> ta -> t
+ */
+ Type **pt;
+ for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
+ ;
+ *pt = ta;
+ continue;
+ }
+#endif
+ case TOKlparen:
+ {
+ if (tpl)
+ {
+ Token *tk = peekPastParen(&token);
+ if (tk->value == TOKlparen)
+ {
+ /* Look ahead to see if this is (...)(...),
+ * i.e. a function template declaration
+ */
+ //printf("function template declaration\n");
+
+ // Gather template parameter list
+ *tpl = parseTemplateParameterList();
+ }
+ else if (tk->value == TOKassign)
+ {
+ /* or (...) =,
+ * i.e. a variable template declaration
+ */
+ //printf("variable template declaration\n");
+ *tpl = parseTemplateParameterList();
+ break;
+ }
+ }
+
+ int varargs;
+ Parameters *parameters = parseParameters(&varargs);
+
+ /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
+ */
+ StorageClass stc = parsePostfix(storageClass, pudas);
+ // merge prefix storage classes
+ Type *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
+ tf = tf->addSTC(stc);
+ if (pdisable)
+ *pdisable = stc & STCdisable ? 1 : 0;
+
+ /* Insert tf into
+ * ts -> ... -> t
+ * so that
+ * ts -> ... -> tf -> t
+ */
+ Type **pt;
+ for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
+ ;
+ *pt = tf;
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+
+ return ts;
+}
+
+void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
+ bool &setAlignment, Expression *&ealign, Expressions *&udas)
+{
+ StorageClass stc;
+ bool sawLinkage = false; // seen a linkage declaration
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKconst:
+ if (peek(&token)->value == TOKlparen)
+ break; // const as type constructor
+ stc = STCconst; // const as storage class
+ goto L1;
+
+ case TOKimmutable:
+ if (peek(&token)->value == TOKlparen)
+ break;
+ stc = STCimmutable;
+ goto L1;
+
+ case TOKshared:
+ if (peek(&token)->value == TOKlparen)
+ break;
+ stc = STCshared;
+ goto L1;
+
+ case TOKwild:
+ if (peek(&token)->value == TOKlparen)
+ break;
+ stc = STCwild;
+ goto L1;
+
+ case TOKstatic: stc = STCstatic; goto L1;
+ case TOKfinal: stc = STCfinal; goto L1;
+ case TOKauto: stc = STCauto; goto L1;
+ case TOKscope: stc = STCscope; goto L1;
+ case TOKoverride: stc = STCoverride; goto L1;
+ case TOKabstract: stc = STCabstract; goto L1;
+ case TOKsynchronized: stc = STCsynchronized; goto L1;
+ case TOKdeprecated: stc = STCdeprecated; goto L1;
+ case TOKnothrow: stc = STCnothrow; goto L1;
+ case TOKpure: stc = STCpure; goto L1;
+ case TOKref: stc = STCref; goto L1;
+ case TOKgshared: stc = STCgshared; goto L1;
+ case TOKenum: stc = STCmanifest; goto L1;
+ case TOKat:
+ {
+ stc = parseAttribute(&udas);
+ if (stc)
+ goto L1;
+ continue;
+ }
+ L1:
+ storage_class = appendStorageClass(storage_class, stc);
+ nextToken();
+ continue;
+
+ case TOKextern:
+ {
+ if (peek(&token)->value != TOKlparen)
+ {
+ stc = STCextern;
+ goto L1;
+ }
+
+ if (sawLinkage)
+ error("redundant linkage declaration");
+ sawLinkage = true;
+ Identifiers *idents = NULL;
+ CPPMANGLE cppmangle = CPPMANGLEdefault;
+ link = parseLinkage(&idents, &cppmangle);
+ if (idents)
+ {
+ error("C++ name spaces not allowed here");
+ delete idents;
+ }
+ if (cppmangle != CPPMANGLEdefault)
+ {
+ error("C++ mangle declaration not allowed here");
+ }
+ continue;
+ }
+
+ case TOKalign:
+ {
+ nextToken();
+ setAlignment = true;
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ ealign = parseExpression();
+ check(TOKrparen);
+ }
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+/**********************************
+ * Parse Declarations.
+ * These can be:
+ * 1. declarations at global/class level
+ * 2. declarations at statement level
+ * Return array of Declaration *'s.
+ */
+
+Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment)
+{
+ StorageClass storage_class = STCundefined;
+ Type *ts;
+ Type *t;
+ Type *tfirst;
+ Identifier *ident;
+ TOK tok = TOKreserved;
+ LINK link = linkage;
+ bool setAlignment = false;
+ Expression *ealign = NULL;
+ Loc loc = token.loc;
+ Expressions *udas = NULL;
+ Token *tk;
+
+ //printf("parseDeclarations() %s\n", token.toChars());
+ if (!comment)
+ comment = token.blockComment;
+
+ if (autodecl)
+ {
+ ts = NULL; // infer type
+ goto L2;
+ }
+
+ if (token.value == TOKalias)
+ {
+ tok = token.value;
+ nextToken();
+
+ /* Look for:
+ * alias identifier this;
+ */
+ if (token.value == TOKidentifier && peekNext() == TOKthis)
+ {
+ AliasThis *s = new AliasThis(loc, token.ident);
+ nextToken();
+ check(TOKthis);
+ check(TOKsemicolon);
+ Dsymbols *a = new Dsymbols();
+ a->push(s);
+ addComment(s, comment);
+ return a;
+ }
+ /* Look for:
+ * alias identifier = type;
+ * alias identifier(...) = type;
+ */
+ if (token.value == TOKidentifier &&
+ skipParensIf(peek(&token), &tk) &&
+ tk->value == TOKassign)
+ {
+ Dsymbols *a = new Dsymbols();
+ while (1)
+ {
+ ident = token.ident;
+ nextToken();
+ TemplateParameters *tpl = NULL;
+ if (token.value == TOKlparen)
+ tpl = parseTemplateParameterList();
+ check(TOKassign);
+
+ Declaration *v;
+ if (token.value == TOKfunction ||
+ token.value == TOKdelegate ||
+ (token.value == TOKlparen &&
+ skipAttributes(peekPastParen(&token), &tk) &&
+ (tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
+ token.value == TOKlcurly ||
+ (token.value == TOKidentifier && peekNext() == TOKgoesto))
+ {
+ // function (parameters) { statements... }
+ // delegate (parameters) { statements... }
+ // (parameters) { statements... }
+ // (parameters) => expression
+ // { statements... }
+ // identifier => expression
+
+ Dsymbol *s = parseFunctionLiteral();
+ v = new AliasDeclaration(loc, ident, s);
+ }
+ else
+ {
+ // StorageClasses type
+
+ storage_class = STCundefined;
+ link = linkage;
+ setAlignment = false;
+ ealign = NULL;
+ udas = NULL;
+ parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+
+ if (udas)
+ error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
+
+ t = parseType();
+ v = new AliasDeclaration(loc, ident, t);
+ }
+ v->storage_class = storage_class;
+
+ Dsymbol *s = v;
+ if (tpl)
+ {
+ Dsymbols *a2 = new Dsymbols();
+ a2->push(s);
+ TemplateDeclaration *tempdecl =
+ new TemplateDeclaration(loc, ident, tpl, NULL, a2);
+ s = tempdecl;
+ }
+ if (setAlignment)
+ {
+ Dsymbols *ax = new Dsymbols();
+ ax->push(s);
+ s = new AlignDeclaration(v->loc, ealign, ax);
+ }
+ if (link != linkage)
+ {
+ Dsymbols *a2 = new Dsymbols();
+ a2->push(s);
+ s = new LinkDeclaration(link, a2);
+ }
+ a->push(s);
+
+ switch (token.value)
+ {
+ case TOKsemicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+ case TOKcomma:
+ nextToken();
+ addComment(s, comment);
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following comma, not %s", token.toChars());
+ break;
+ }
+ if (peekNext() != TOKassign && peekNext() != TOKlparen)
+ {
+ error("= expected following identifier");
+ nextToken();
+ break;
+ }
+ continue;
+ default:
+ error("semicolon expected to close %s declaration", Token::toChars(tok));
+ break;
+ }
+ break;
+ }
+ return a;
+ }
+
+ // alias StorageClasses type ident;
+ }
+
+ parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+
+ if (token.value == TOKstruct ||
+ token.value == TOKunion ||
+ token.value == TOKclass ||
+ token.value == TOKinterface)
+ {
+ Dsymbol *s = parseAggregate();
+ Dsymbols *a = new Dsymbols();
+ a->push(s);
+
+ if (storage_class)
+ {
+ s = new StorageClassDeclaration(storage_class, a);
+ a = new Dsymbols();
+ a->push(s);
+ }
+ if (setAlignment)
+ {
+ s = new AlignDeclaration(s->loc, ealign, a);
+ a = new Dsymbols();
+ a->push(s);
+ }
+ if (link != linkage)
+ {
+ s = new LinkDeclaration(link, a);
+ a = new Dsymbols();
+ a->push(s);
+ }
+ if (udas)
+ {
+ s = new UserAttributeDeclaration(udas, a);
+ a = new Dsymbols();
+ a->push(s);
+ }
+
+ addComment(s, comment);
+ return a;
+ }
+
+ /* Look for auto initializers:
+ * storage_class identifier = initializer;
+ * storage_class identifier(...) = initializer;
+ */
+ if ((storage_class || udas) &&
+ token.value == TOKidentifier &&
+ skipParensIf(peek(&token), &tk) &&
+ tk->value == TOKassign)
+ {
+ Dsymbols *a = parseAutoDeclarations(storage_class, comment);
+ if (udas)
+ {
+ Dsymbol *s = new UserAttributeDeclaration(udas, a);
+ a = new Dsymbols();
+ a->push(s);
+ }
+ return a;
+ }
+
+ /* Look for return type inference for template functions.
+ */
+ if ((storage_class || udas) && token.value == TOKidentifier && skipParens(peek(&token), &tk) &&
+ skipAttributes(tk, &tk) &&
+ (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin || tk->value == TOKout ||
+ tk->value == TOKdo || (tk->value == TOKidentifier && tk->ident == Id::_body)))
+ {
+ ts = NULL;
+ }
+ else
+ {
+ ts = parseBasicType();
+ ts = parseBasicType2(ts);
+ }
+
+L2:
+ tfirst = NULL;
+ Dsymbols *a = new Dsymbols();
+
+ if (pAttrs)
+ {
+ storage_class |= pAttrs->storageClass;
+ //pAttrs->storageClass = STCundefined;
+ }
+
+ while (1)
+ {
+ TemplateParameters *tpl = NULL;
+ int disable;
+ int alt = 0;
+
+ loc = token.loc;
+ ident = NULL;
+ t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas);
+ assert(t);
+ if (!tfirst)
+ tfirst = t;
+ else if (t != tfirst)
+ error("multiple declarations must have the same type, not %s and %s",
+ tfirst->toChars(), t->toChars());
+ bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This && token.value == TOKassign);
+ if (ident)
+ checkCstyleTypeSyntax(loc, t, alt, ident);
+ else if (!isThis)
+ error("no identifier for declarator %s", t->toChars());
+
+ if (tok == TOKalias)
+ {
+ Declaration *v;
+ Initializer *init = NULL;
+
+ /* Aliases can no longer have multiple declarators, storage classes,
+ * linkages, or auto declarations.
+ * These never made any sense, anyway.
+ * The code below needs to be fixed to reject them.
+ * The grammar has already been fixed to preclude them.
+ */
+
+ if (udas)
+ error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
+
+ if (token.value == TOKassign)
+ {
+ nextToken();
+ init = parseInitializer();
+ }
+ if (init)
+ {
+ if (isThis)
+ error("cannot use syntax 'alias this = %s', use 'alias %s this' instead",
+ init->toChars(), init->toChars());
+ else
+ error("alias cannot have initializer");
+ }
+ v = new AliasDeclaration(loc, ident, t);
+
+ v->storage_class = storage_class;
+ if (pAttrs)
+ {
+ /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
+ * on prefix and postfix.
+ * @safe alias void function() FP1;
+ * alias @safe void function() FP2; // FP2 is not @safe
+ * alias void function() @safe FP3;
+ */
+ pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted);
+ }
+ Dsymbol *s = v;
+
+ if (link != linkage)
+ {
+ Dsymbols *ax = new Dsymbols();
+ ax->push(v);
+ s = new LinkDeclaration(link, ax);
+ }
+ a->push(s);
+ switch (token.value)
+ {
+ case TOKsemicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+
+ case TOKcomma:
+ nextToken();
+ addComment(s, comment);
+ continue;
+
+ default:
+ error("semicolon expected to close %s declaration", Token::toChars(tok));
+ break;
+ }
+ }
+ else if (t->ty == Tfunction)
+ {
+ Expression *constraint = NULL;
+
+ //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
+ FuncDeclaration *f =
+ new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t);
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+ if (tpl)
+ constraint = parseConstraint();
+ Dsymbol *s = parseContracts(f);
+ Identifier *tplIdent = s->ident;
+ if (link != linkage)
+ {
+ Dsymbols *ax = new Dsymbols();
+ ax->push(s);
+ s = new LinkDeclaration(link, ax);
+ }
+ if (udas)
+ {
+ Dsymbols *ax = new Dsymbols();
+ ax->push(s);
+ s = new UserAttributeDeclaration(udas, ax);
+ }
+
+ /* A template parameter list means it's a function template
+ */
+ if (tpl)
+ {
+ // Wrap a template around the function declaration
+ Dsymbols *decldefs = new Dsymbols();
+ decldefs->push(s);
+ TemplateDeclaration *tempdecl =
+ new TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
+ s = tempdecl;
+
+ if (storage_class & STCstatic)
+ {
+ assert(f->storage_class & STCstatic);
+ f->storage_class &= ~STCstatic;
+
+ Dsymbols *ax = new Dsymbols();
+ ax->push(s);
+ s = new StorageClassDeclaration(STCstatic, ax);
+ }
+ }
+ a->push(s);
+ addComment(s, comment);
+ }
+ else if (ident)
+ {
+ Initializer *init = NULL;
+ if (token.value == TOKassign)
+ {
+ nextToken();
+ init = parseInitializer();
+ }
+
+ VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
+ v->storage_class = storage_class;
+ if (pAttrs)
+ pAttrs->storageClass = STCundefined;
+
+ Dsymbol *s = v;
+
+ if (tpl && init)
+ {
+ Dsymbols *a2 = new Dsymbols();
+ a2->push(s);
+ TemplateDeclaration *tempdecl =
+ new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
+ s = tempdecl;
+ }
+ if (link != linkage)
+ {
+ Dsymbols *ax = new Dsymbols();
+ ax->push(s);
+ s = new LinkDeclaration(link, ax);
+ }
+ if (udas)
+ {
+ Dsymbols *ax = new Dsymbols();
+ ax->push(s);
+ s = new UserAttributeDeclaration(udas, ax);
+ }
+ a->push(s);
+ switch (token.value)
+ {
+ case TOKsemicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+
+ case TOKcomma:
+ nextToken();
+ addComment(s, comment);
+ continue;
+
+ default:
+ error("semicolon expected, not '%s'", token.toChars());
+ break;
+ }
+ }
+ break;
+ }
+ return a;
+}
+
+Dsymbol *Parser::parseFunctionLiteral()
+{
+ Loc loc = token.loc;
+
+ TemplateParameters *tpl = NULL;
+ Parameters *parameters = NULL;
+ int varargs = 0;
+ Type *tret = NULL;
+ StorageClass stc = 0;
+ TOK save = TOKreserved;
+
+ switch (token.value)
+ {
+ case TOKfunction:
+ case TOKdelegate:
+ save = token.value;
+ nextToken();
+ if (token.value != TOKlparen && token.value != TOKlcurly)
+ {
+ // function type (parameters) { statements... }
+ // delegate type (parameters) { statements... }
+ tret = parseBasicType();
+ tret = parseBasicType2(tret); // function return type
+ }
+
+ if (token.value == TOKlparen)
+ {
+ // function (parameters) { statements... }
+ // delegate (parameters) { statements... }
+ }
+ else
+ {
+ // function { statements... }
+ // delegate { statements... }
+ break;
+ }
+ /* fall through */
+
+ case TOKlparen:
+ {
+ // (parameters) => expression
+ // (parameters) { statements... }
+ parameters = parseParameters(&varargs, &tpl);
+ stc = parsePostfix(STCundefined, NULL);
+ if (StorageClass modStc = stc & STC_TYPECTOR)
+ {
+ if (save == TOKfunction)
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, modStc);
+ error("function literal cannot be %s", buf.peekString());
+ }
+ else
+ save = TOKdelegate;
+ }
+ break;
+ }
+ case TOKlcurly:
+ // { statements... }
+ break;
+
+ case TOKidentifier:
+ {
+ // identifier => expression
+ parameters = new Parameters();
+ Identifier *id = Identifier::generateId("__T");
+ Type *t = new TypeIdentifier(loc, id);
+ parameters->push(new Parameter(0, t, token.ident, NULL));
+
+ tpl = new TemplateParameters();
+ TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
+ tpl->push(tp);
+
+ nextToken();
+ break;
+ }
+ default:
+ assert(0);
+ }
+
+ if (!parameters)
+ parameters = new Parameters();
+ TypeFunction *tf = new TypeFunction(parameters, tret, varargs, linkage, stc);
+ tf = (TypeFunction *)tf->addSTC(stc);
+ FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, NULL);
+
+ if (token.value == TOKgoesto)
+ {
+ check(TOKgoesto);
+ Loc returnloc = token.loc;
+ Expression *ae = parseAssignExp();
+ fd->fbody = new ReturnStatement(returnloc, ae);
+ fd->endloc = token.loc;
+ }
+ else
+ {
+ parseContracts(fd);
+ }
+
+ if (tpl)
+ {
+ // Wrap a template around function fd
+ Dsymbols *decldefs = new Dsymbols();
+ decldefs->push(fd);
+ return new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, false, true);
+ }
+ else
+ return fd;
+}
+
+/*****************************************
+ * Parse auto declarations of the form:
+ * storageClass ident = init, ident = init, ... ;
+ * and return the array of them.
+ * Starts with token on the first ident.
+ * Ends with scanner past closing ';'
+ */
+
+Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment)
+{
+ //printf("parseAutoDeclarations\n");
+ Token *tk;
+ Dsymbols *a = new Dsymbols;
+
+ while (1)
+ {
+ Loc loc = token.loc;
+ Identifier *ident = token.ident;
+ nextToken(); // skip over ident
+
+ TemplateParameters *tpl = NULL;
+ if (token.value == TOKlparen)
+ tpl = parseTemplateParameterList();
+
+ check(TOKassign); // skip over '='
+ Initializer *init = parseInitializer();
+ VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
+ v->storage_class = storageClass;
+
+ Dsymbol *s = v;
+ if (tpl)
+ {
+ Dsymbols *a2 = new Dsymbols();
+ a2->push(v);
+ TemplateDeclaration *tempdecl =
+ new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
+ s = tempdecl;
+ }
+ a->push(s);
+ switch (token.value)
+ {
+ case TOKsemicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+
+ case TOKcomma:
+ nextToken();
+ if (!(token.value == TOKidentifier &&
+ skipParensIf(peek(&token), &tk) &&
+ tk->value == TOKassign))
+ {
+ error("identifier expected following comma");
+ break;
+ }
+ addComment(s, comment);
+ continue;
+
+ default:
+ error("semicolon expected following auto declaration, not '%s'", token.toChars());
+ break;
+ }
+ break;
+ }
+ return a;
+}
+
+/*****************************************
+ * Parse contracts following function declaration.
+ */
+
+FuncDeclaration *Parser::parseContracts(FuncDeclaration *f)
+{
+ LINK linksave = linkage;
+
+ bool literal = f->isFuncLiteralDeclaration() != NULL;
+
+ // The following is irrelevant, as it is overridden by sc->linkage in
+ // TypeFunction::semantic
+ linkage = LINKd; // nested functions have D linkage
+L1:
+ switch (token.value)
+ {
+ case TOKlcurly:
+ if (f->frequire || f->fensure)
+ error("missing body { ... } after in or out");
+ f->fbody = parseStatement(PSsemi);
+ f->endloc = endloc;
+ break;
+
+ case TOKidentifier:
+ if (token.ident != Id::_body)
+ goto Ldefault;
+ /* fall through */
+
+ case TOKdo:
+ nextToken();
+ f->fbody = parseStatement(PScurly);
+ f->endloc = endloc;
+ break;
+
+ case TOKin:
+ nextToken();
+ if (f->frequire)
+ error("redundant 'in' statement");
+ f->frequire = parseStatement(PScurly | PSscope);
+ goto L1;
+
+ case TOKout:
+ // parse: out (identifier) { statement }
+ nextToken();
+ if (token.value != TOKlcurly)
+ {
+ check(TOKlparen);
+ if (token.value != TOKidentifier)
+ error("(identifier) following 'out' expected, not %s", token.toChars());
+ f->outId = token.ident;
+ nextToken();
+ check(TOKrparen);
+ }
+ if (f->fensure)
+ error("redundant 'out' statement");
+ f->fensure = parseStatement(PScurly | PSscope);
+ goto L1;
+
+ case TOKsemicolon:
+ if (!literal)
+ {
+ // Bugzilla 15799: Semicolon becomes a part of function declaration
+ // only when neither of contracts exists.
+ if (!f->frequire && !f->fensure)
+ nextToken();
+ break;
+ }
+ /* fall through */
+
+ default:
+ Ldefault:
+ if (literal)
+ {
+ const char *sbody = (f->frequire || f->fensure) ? "body " : "";
+ error("missing %s{ ... } for function literal", sbody);
+ }
+ else if (!f->frequire && !f->fensure) // allow these even with no body
+ {
+ error("semicolon expected following function declaration");
+ }
+ break;
+ }
+ if (literal && !f->fbody)
+ {
+ // Set empty function body for error recovery
+ f->fbody = new CompoundStatement(Loc(), (Statement *)NULL);
+ }
+
+ linkage = linksave;
+
+ return f;
+}
+
+/*****************************************
+ * Parse initializer for variable declaration.
+ */
+
+Initializer *Parser::parseInitializer()
+{
+ StructInitializer *is;
+ ArrayInitializer *ia;
+ ExpInitializer *ie;
+ Expression *e;
+ Identifier *id;
+ Initializer *value;
+ int comma;
+ Loc loc = token.loc;
+ Token *t;
+ int braces;
+ int brackets;
+
+ switch (token.value)
+ {
+ case TOKlcurly:
+ /* Scan ahead to see if it is a struct initializer or
+ * a function literal.
+ * If it contains a ';', it is a function literal.
+ * Treat { } as a struct initializer.
+ */
+ braces = 1;
+ for (t = peek(&token); 1; t = peek(t))
+ {
+ switch (t->value)
+ {
+ case TOKsemicolon:
+ case TOKreturn:
+ goto Lexpression;
+
+ case TOKlcurly:
+ braces++;
+ continue;
+
+ case TOKrcurly:
+ if (--braces == 0)
+ break;
+ continue;
+
+ case TOKeof:
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ }
+
+ is = new StructInitializer(loc);
+ nextToken();
+ comma = 2;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKidentifier:
+ if (comma == 1)
+ error("comma expected separating field initializers");
+ t = peek(&token);
+ if (t->value == TOKcolon)
+ {
+ id = token.ident;
+ nextToken();
+ nextToken(); // skip over ':'
+ }
+ else
+ { id = NULL;
+ }
+ value = parseInitializer();
+ is->addInit(id, value);
+ comma = 1;
+ continue;
+
+ case TOKcomma:
+ if (comma == 2)
+ error("expression expected, not ','");
+ nextToken();
+ comma = 2;
+ continue;
+
+ case TOKrcurly: // allow trailing comma's
+ nextToken();
+ break;
+
+ case TOKeof:
+ error("found EOF instead of initializer");
+ break;
+
+ default:
+ if (comma == 1)
+ error("comma expected separating field initializers");
+ value = parseInitializer();
+ is->addInit(NULL, value);
+ comma = 1;
+ continue;
+ //error("found '%s' instead of field initializer", token.toChars());
+ //break;
+ }
+ break;
+ }
+ return is;
+
+ case TOKlbracket:
+ /* Scan ahead to see if it is an array initializer or
+ * an expression.
+ * If it ends with a ';' ',' or '}', it is an array initializer.
+ */
+ brackets = 1;
+ for (t = peek(&token); 1; t = peek(t))
+ {
+ switch (t->value)
+ {
+ case TOKlbracket:
+ brackets++;
+ continue;
+
+ case TOKrbracket:
+ if (--brackets == 0)
+ { t = peek(t);
+ if (t->value != TOKsemicolon &&
+ t->value != TOKcomma &&
+ t->value != TOKrbracket &&
+ t->value != TOKrcurly)
+ goto Lexpression;
+ break;
+ }
+ continue;
+
+ case TOKeof:
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ }
+
+ ia = new ArrayInitializer(loc);
+ nextToken();
+ comma = 2;
+ while (1)
+ {
+ switch (token.value)
+ {
+ default:
+ if (comma == 1)
+ { error("comma expected separating array initializers, not %s", token.toChars());
+ nextToken();
+ break;
+ }
+ e = parseAssignExp();
+ if (!e)
+ break;
+ if (token.value == TOKcolon)
+ {
+ nextToken();
+ value = parseInitializer();
+ }
+ else
+ { value = new ExpInitializer(e->loc, e);
+ e = NULL;
+ }
+ ia->addInit(e, value);
+ comma = 1;
+ continue;
+
+ case TOKlcurly:
+ case TOKlbracket:
+ if (comma == 1)
+ error("comma expected separating array initializers, not %s", token.toChars());
+ value = parseInitializer();
+ if (token.value == TOKcolon)
+ {
+ nextToken();
+ e = initializerToExpression(value);
+ value = parseInitializer();
+ }
+ else
+ e = NULL;
+ ia->addInit(e, value);
+ comma = 1;
+ continue;
+
+ case TOKcomma:
+ if (comma == 2)
+ error("expression expected, not ','");
+ nextToken();
+ comma = 2;
+ continue;
+
+ case TOKrbracket: // allow trailing comma's
+ nextToken();
+ break;
+
+ case TOKeof:
+ error("found '%s' instead of array initializer", token.toChars());
+ break;
+ }
+ break;
+ }
+ return ia;
+
+ case TOKvoid:
+ t = peek(&token);
+ if (t->value == TOKsemicolon || t->value == TOKcomma)
+ {
+ nextToken();
+ return new VoidInitializer(loc);
+ }
+ goto Lexpression;
+
+ default:
+ Lexpression:
+ e = parseAssignExp();
+ ie = new ExpInitializer(loc, e);
+ return ie;
+ }
+}
+
+/*****************************************
+ * Parses default argument initializer expression that is an assign expression,
+ * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
+ */
+
+Expression *Parser::parseDefaultInitExp()
+{
+ if (token.value == TOKfile ||
+ token.value == TOKfilefullpath ||
+ token.value == TOKline ||
+ token.value == TOKmodulestring ||
+ token.value == TOKfuncstring ||
+ token.value == TOKprettyfunc)
+ {
+ Token *t = peek(&token);
+ if (t->value == TOKcomma || t->value == TOKrparen)
+ {
+ Expression *e = NULL;
+ if (token.value == TOKfile)
+ e = new FileInitExp(token.loc, TOKfile);
+ else if (token.value == TOKfilefullpath)
+ e = new FileInitExp(token.loc, TOKfilefullpath);
+ else if (token.value == TOKline)
+ e = new LineInitExp(token.loc);
+ else if (token.value == TOKmodulestring)
+ e = new ModuleInitExp(token.loc);
+ else if (token.value == TOKfuncstring)
+ e = new FuncInitExp(token.loc);
+ else if (token.value == TOKprettyfunc)
+ e = new PrettyFuncInitExp(token.loc);
+ else
+ assert(0);
+ nextToken();
+ return e;
+ }
+ }
+
+ Expression *e = parseAssignExp();
+ return e;
+}
+
+/*****************************************
+ */
+
+void Parser::checkDanglingElse(Loc elseloc)
+{
+ if (token.value != TOKelse &&
+ token.value != TOKcatch &&
+ token.value != TOKfinally &&
+ lookingForElse.linnum != 0)
+ {
+ warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
+ }
+}
+
+void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident)
+{
+ if (!alt)
+ return;
+
+ const char *sp = !ident ? "" : " ";
+ const char *s = !ident ? "" : ident->toChars();
+ if (alt & 1) // contains C-style function pointer syntax
+ error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t->toChars(), sp, s);
+ else
+ ::warning(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t->toChars(), sp, s);
+
+}
+
+/*****************************************
+ * Input:
+ * flags PSxxxx
+ * Output:
+ * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
+ */
+
+Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc)
+{
+ Statement *s = NULL;
+ Condition *cond;
+ Statement *ifbody;
+ Statement *elsebody;
+ bool isfinal;
+ Loc loc = token.loc;
+
+ //printf("parseStatement()\n");
+
+ if (flags & PScurly && token.value != TOKlcurly)
+ error("statement expected to be { }, not %s", token.toChars());
+
+ switch (token.value)
+ {
+ case TOKidentifier:
+ { /* A leading identifier can be a declaration, label, or expression.
+ * The easiest case to check first is label:
+ */
+ Token *t = peek(&token);
+ if (t->value == TOKcolon)
+ {
+ Token *nt = peek(t);
+ if (nt->value == TOKcolon)
+ {
+ // skip ident::
+ nextToken();
+ nextToken();
+ nextToken();
+ error("use `.` for member lookup, not `::`");
+ break;
+ }
+ // It's a label
+ Identifier *ident = token.ident;
+ nextToken();
+ nextToken();
+ if (token.value == TOKrcurly)
+ s = NULL;
+ else if (token.value == TOKlcurly)
+ s = parseStatement(PScurly | PSscope);
+ else
+ s = parseStatement(PSsemi_ok);
+ s = new LabelStatement(loc, ident, s);
+ break;
+ }
+ }
+ /* fall through */
+ case TOKdot:
+ case TOKtypeof:
+ case TOKvector:
+ /* Bugzilla 15163: If tokens can be handled as
+ * old C-style declaration or D expression, prefer the latter.
+ */
+ if (isDeclaration(&token, 3, TOKreserved, NULL))
+ goto Ldeclaration;
+ else
+ goto Lexp;
+ break;
+
+ case TOKassert:
+ case TOKthis:
+ case TOKsuper:
+ case TOKint32v:
+ case TOKuns32v:
+ case TOKint64v:
+ case TOKuns64v:
+ case TOKint128v:
+ case TOKuns128v:
+ case TOKfloat32v:
+ case TOKfloat64v:
+ case TOKfloat80v:
+ case TOKimaginary32v:
+ case TOKimaginary64v:
+ case TOKimaginary80v:
+ case TOKcharv:
+ case TOKwcharv:
+ case TOKdcharv:
+ case TOKnull:
+ case TOKtrue:
+ case TOKfalse:
+ case TOKstring:
+ case TOKxstring:
+ case TOKlparen:
+ case TOKcast:
+ case TOKmul:
+ case TOKmin:
+ case TOKadd:
+ case TOKtilde:
+ case TOKnot:
+ case TOKplusplus:
+ case TOKminusminus:
+ case TOKnew:
+ case TOKdelete:
+ case TOKdelegate:
+ case TOKfunction:
+ case TOKtypeid:
+ case TOKis:
+ case TOKlbracket:
+ case TOKtraits:
+ case TOKfile:
+ case TOKfilefullpath:
+ case TOKline:
+ case TOKmodulestring:
+ case TOKfuncstring:
+ case TOKprettyfunc:
+ Lexp:
+ {
+ Expression *exp = parseExpression();
+ check(TOKsemicolon, "statement");
+ s = new ExpStatement(loc, exp);
+ break;
+ }
+
+ case TOKstatic:
+ { // Look ahead to see if it's static assert() or static if()
+
+ Token *t = peek(&token);
+ if (t->value == TOKassert)
+ {
+ s = new StaticAssertStatement(parseStaticAssert());
+ break;
+ }
+ if (t->value == TOKif)
+ {
+ cond = parseStaticIfCondition();
+ goto Lcondition;
+ }
+ if (t->value == TOKimport)
+ {
+ Dsymbols *imports = parseImport();
+ s = new ImportStatement(loc, imports);
+ if (flags & PSscope)
+ s = new ScopeStatement(loc, s, token.loc);
+ break;
+ }
+ goto Ldeclaration;
+ }
+
+ case TOKfinal:
+ if (peekNext() == TOKswitch)
+ {
+ nextToken();
+ isfinal = true;
+ goto Lswitch;
+ }
+ goto Ldeclaration;
+
+ case TOKwchar: case TOKdchar:
+ case TOKbool: case TOKchar:
+ case TOKint8: case TOKuns8:
+ case TOKint16: case TOKuns16:
+ case TOKint32: case TOKuns32:
+ case TOKint64: case TOKuns64:
+ case TOKint128: case TOKuns128:
+ case TOKfloat32: case TOKfloat64: case TOKfloat80:
+ case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+ case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+ case TOKvoid:
+ // bug 7773: int.max is always a part of expression
+ if (peekNext() == TOKdot)
+ goto Lexp;
+ if (peekNext() == TOKlparen)
+ goto Lexp;
+ /* fall through */
+
+ case TOKalias:
+ case TOKconst:
+ case TOKauto:
+ case TOKabstract:
+ case TOKextern:
+ case TOKalign:
+ case TOKimmutable:
+ case TOKshared:
+ case TOKwild:
+ case TOKdeprecated:
+ case TOKnothrow:
+ case TOKpure:
+ case TOKref:
+ case TOKgshared:
+ case TOKat:
+ case TOKstruct:
+ case TOKunion:
+ case TOKclass:
+ case TOKinterface:
+ Ldeclaration:
+ {
+ Dsymbols *a = parseDeclarations(false, NULL, NULL);
+ if (a->dim > 1)
+ {
+ Statements *as = new Statements();
+ as->reserve(a->dim);
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ Dsymbol *d = (*a)[i];
+ s = new ExpStatement(loc, d);
+ as->push(s);
+ }
+ s = new CompoundDeclarationStatement(loc, as);
+ }
+ else if (a->dim == 1)
+ {
+ Dsymbol *d = (*a)[0];
+ s = new ExpStatement(loc, d);
+ }
+ else
+ s = new ExpStatement(loc, (Expression *)NULL);
+ if (flags & PSscope)
+ s = new ScopeStatement(loc, s, token.loc);
+ break;
+ }
+
+ case TOKenum:
+ { /* Determine if this is a manifest constant declaration,
+ * or a conventional enum.
+ */
+ Dsymbol *d;
+ Token *t = peek(&token);
+ if (t->value == TOKlcurly || t->value == TOKcolon)
+ d = parseEnum();
+ else if (t->value != TOKidentifier)
+ goto Ldeclaration;
+ else
+ {
+ t = peek(t);
+ if (t->value == TOKlcurly || t->value == TOKcolon ||
+ t->value == TOKsemicolon)
+ d = parseEnum();
+ else
+ goto Ldeclaration;
+ }
+ s = new ExpStatement(loc, d);
+ if (flags & PSscope)
+ s = new ScopeStatement(loc, s, token.loc);
+ break;
+ }
+
+ case TOKmixin:
+ { Token *t = peek(&token);
+ if (t->value == TOKlparen)
+ { // mixin(string)
+ Expression *e = parseAssignExp();
+ check(TOKsemicolon);
+ if (e->op == TOKmixin)
+ {
+ CompileExp *cpe = (CompileExp *)e;
+ s = new CompileStatement(loc, cpe->e1);
+ }
+ else
+ {
+ s = new ExpStatement(loc, e);
+ }
+ break;
+ }
+ Dsymbol *d = parseMixin();
+ s = new ExpStatement(loc, d);
+ if (flags & PSscope)
+ s = new ScopeStatement(loc, s, token.loc);
+ break;
+ }
+
+ case TOKlcurly:
+ {
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+
+ nextToken();
+ //if (token.value == TOKsemicolon)
+ //error("use '{ }' for an empty statement, not a ';'");
+ Statements *statements = new Statements();
+ while (token.value != TOKrcurly && token.value != TOKeof)
+ {
+ statements->push(parseStatement(PSsemi | PScurlyscope));
+ }
+ if (endPtr) *endPtr = token.ptr;
+ endloc = token.loc;
+ if (pEndloc)
+ {
+ *pEndloc = token.loc;
+ pEndloc = NULL; // don't set it again
+ }
+ s = new CompoundStatement(loc, statements);
+ if (flags & (PSscope | PScurlyscope))
+ s = new ScopeStatement(loc, s, token.loc);
+ check(TOKrcurly, "compound statement");
+ lookingForElse = lookingForElseSave;
+ break;
+ }
+
+ case TOKwhile:
+ {
+ nextToken();
+ check(TOKlparen);
+ Expression *condition = parseExpression();
+ check(TOKrparen);
+ Loc endloc;
+ Statement *body = parseStatement(PSscope, NULL, &endloc);
+ s = new WhileStatement(loc, condition, body, endloc);
+ break;
+ }
+
+ case TOKsemicolon:
+ if (!(flags & PSsemi_ok))
+ {
+ if (flags & PSsemi)
+ deprecation("use '{ }' for an empty statement, not a ';'");
+ else
+ error("use '{ }' for an empty statement, not a ';'");
+ }
+ nextToken();
+ s = new ExpStatement(loc, (Expression *)NULL);
+ break;
+
+ case TOKdo:
+ { Statement *body;
+ Expression *condition;
+
+ nextToken();
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+ body = parseStatement(PSscope);
+ lookingForElse = lookingForElseSave;
+ check(TOKwhile);
+ check(TOKlparen);
+ condition = parseExpression();
+ check(TOKrparen);
+ if (token.value == TOKsemicolon)
+ nextToken();
+ else
+ error("terminating ';' required after do-while statement");
+ s = new DoStatement(loc, body, condition, token.loc);
+ break;
+ }
+
+ case TOKfor:
+ {
+ Statement *init;
+ Expression *condition;
+ Expression *increment;
+
+ nextToken();
+ check(TOKlparen);
+ if (token.value == TOKsemicolon)
+ { init = NULL;
+ nextToken();
+ }
+ else
+ {
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+ init = parseStatement(0);
+ lookingForElse = lookingForElseSave;
+ }
+ if (token.value == TOKsemicolon)
+ {
+ condition = NULL;
+ nextToken();
+ }
+ else
+ {
+ condition = parseExpression();
+ check(TOKsemicolon, "for condition");
+ }
+ if (token.value == TOKrparen)
+ { increment = NULL;
+ nextToken();
+ }
+ else
+ { increment = parseExpression();
+ check(TOKrparen);
+ }
+ Loc endloc;
+ Statement *body = parseStatement(PSscope, NULL, &endloc);
+ s = new ForStatement(loc, init, condition, increment, body, endloc);
+ break;
+ }
+
+ case TOKforeach:
+ case TOKforeach_reverse:
+ {
+ TOK op = token.value;
+
+ nextToken();
+ check(TOKlparen);
+
+ Parameters *parameters = new Parameters();
+
+ while (1)
+ {
+ Identifier *ai = NULL;
+ Type *at;
+
+ StorageClass storageClass = 0;
+ StorageClass stc = 0;
+ Lagain:
+ if (stc)
+ {
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+ switch (token.value)
+ {
+ case TOKref:
+ stc = STCref;
+ goto Lagain;
+
+ case TOKconst:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCconst;
+ goto Lagain;
+ }
+ break;
+ case TOKimmutable:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCimmutable;
+ goto Lagain;
+ }
+ break;
+ case TOKshared:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCshared;
+ goto Lagain;
+ }
+ break;
+ case TOKwild:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCwild;
+ goto Lagain;
+ }
+ break;
+ default:
+ break;
+ }
+ if (token.value == TOKidentifier)
+ {
+ Token *t = peek(&token);
+ if (t->value == TOKcomma || t->value == TOKsemicolon)
+ { ai = token.ident;
+ at = NULL; // infer argument type
+ nextToken();
+ goto Larg;
+ }
+ }
+ at = parseType(&ai);
+ if (!ai)
+ error("no identifier for declarator %s", at->toChars());
+ Larg:
+ Parameter *p = new Parameter(storageClass, at, ai, NULL);
+ parameters->push(p);
+ if (token.value == TOKcomma)
+ { nextToken();
+ continue;
+ }
+ break;
+ }
+ check(TOKsemicolon);
+
+ Expression *aggr = parseExpression();
+ if (token.value == TOKslice && parameters->dim == 1)
+ {
+ Parameter *p = (*parameters)[0];
+ delete parameters;
+ nextToken();
+ Expression *upr = parseExpression();
+ check(TOKrparen);
+ Loc endloc;
+ Statement *body = parseStatement(0, NULL, &endloc);
+ s = new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
+ }
+ else
+ {
+ check(TOKrparen);
+ Loc endloc;
+ Statement *body = parseStatement(0, NULL, &endloc);
+ s = new ForeachStatement(loc, op, parameters, aggr, body, endloc);
+ }
+ break;
+ }
+
+ case TOKif:
+ {
+ Parameter *param = NULL;
+ Expression *condition;
+
+ nextToken();
+ check(TOKlparen);
+
+ StorageClass storageClass = 0;
+ StorageClass stc = 0;
+ LagainStc:
+ if (stc)
+ {
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+ switch (token.value)
+ {
+ case TOKref:
+ stc = STCref;
+ goto LagainStc;
+ case TOKauto:
+ stc = STCauto;
+ goto LagainStc;
+ case TOKconst:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCconst;
+ goto LagainStc;
+ }
+ break;
+ case TOKimmutable:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCimmutable;
+ goto LagainStc;
+ }
+ break;
+ case TOKshared:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCshared;
+ goto LagainStc;
+ }
+ break;
+ case TOKwild:
+ if (peekNext() != TOKlparen)
+ {
+ stc = STCwild;
+ goto LagainStc;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (storageClass != 0 &&
+ token.value == TOKidentifier &&
+ peek(&token)->value == TOKassign)
+ {
+ Identifier *ai = token.ident;
+ Type *at = NULL; // infer parameter type
+ nextToken();
+ check(TOKassign);
+ param = new Parameter(storageClass, at, ai, NULL);
+ }
+ else if (isDeclaration(&token, 2, TOKassign, NULL))
+ {
+ Identifier *ai;
+ Type *at = parseType(&ai);
+ check(TOKassign);
+ param = new Parameter(storageClass, at, ai, NULL);
+ }
+
+ condition = parseExpression();
+ check(TOKrparen);
+ {
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = loc;
+ ifbody = parseStatement(PSscope);
+ lookingForElse = lookingForElseSave;
+ }
+ if (token.value == TOKelse)
+ {
+ Loc elseloc = token.loc;
+ nextToken();
+ elsebody = parseStatement(PSscope);
+ checkDanglingElse(elseloc);
+ }
+ else
+ elsebody = NULL;
+ if (condition && ifbody)
+ s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
+ else
+ s = NULL; // don't propagate parsing errors
+ break;
+ }
+
+ case TOKscope:
+ if (peek(&token)->value != TOKlparen)
+ goto Ldeclaration; // scope used as storage class
+ nextToken();
+ check(TOKlparen);
+ if (token.value != TOKidentifier)
+ { error("scope identifier expected");
+ goto Lerror;
+ }
+ else
+ { TOK t = TOKon_scope_exit;
+ Identifier *id = token.ident;
+
+ if (id == Id::exit)
+ t = TOKon_scope_exit;
+ else if (id == Id::failure)
+ t = TOKon_scope_failure;
+ else if (id == Id::success)
+ t = TOKon_scope_success;
+ else
+ error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
+ nextToken();
+ check(TOKrparen);
+ Statement *st = parseStatement(PSscope);
+ s = new OnScopeStatement(loc, t, st);
+ break;
+ }
+
+ case TOKdebug:
+ nextToken();
+ if (token.value == TOKassign)
+ {
+ error("debug conditions can only be declared at module scope");
+ nextToken();
+ nextToken();
+ goto Lerror;
+ }
+ cond = parseDebugCondition();
+ goto Lcondition;
+
+ case TOKversion:
+ nextToken();
+ if (token.value == TOKassign)
+ {
+ error("version conditions can only be declared at module scope");
+ nextToken();
+ nextToken();
+ goto Lerror;
+ }
+ cond = parseVersionCondition();
+ goto Lcondition;
+
+ Lcondition:
+ {
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = loc;
+ ifbody = parseStatement(0);
+ lookingForElse = lookingForElseSave;
+ }
+ elsebody = NULL;
+ if (token.value == TOKelse)
+ {
+ Loc elseloc = token.loc;
+ nextToken();
+ elsebody = parseStatement(0);
+ checkDanglingElse(elseloc);
+ }
+ s = new ConditionalStatement(loc, cond, ifbody, elsebody);
+ if (flags & PSscope)
+ s = new ScopeStatement(loc, s, token.loc);
+ break;
+
+ case TOKpragma:
+ { Identifier *ident;
+ Expressions *args = NULL;
+ Statement *body;
+
+ nextToken();
+ check(TOKlparen);
+ if (token.value != TOKidentifier)
+ { error("pragma(identifier expected");
+ goto Lerror;
+ }
+ ident = token.ident;
+ nextToken();
+ if (token.value == TOKcomma && peekNext() != TOKrparen)
+ args = parseArguments(); // pragma(identifier, args...);
+ else
+ check(TOKrparen); // pragma(identifier);
+ if (token.value == TOKsemicolon)
+ { nextToken();
+ body = NULL;
+ }
+ else
+ body = parseStatement(PSsemi);
+ s = new PragmaStatement(loc, ident, args, body);
+ break;
+ }
+
+ case TOKswitch:
+ isfinal = false;
+ goto Lswitch;
+
+ Lswitch:
+ {
+ nextToken();
+ check(TOKlparen);
+ Expression *condition = parseExpression();
+ check(TOKrparen);
+ Statement *body = parseStatement(PSscope);
+ s = new SwitchStatement(loc, condition, body, isfinal);
+ break;
+ }
+
+ case TOKcase:
+ { Expression *exp;
+ Expressions cases; // array of Expression's
+ Expression *last = NULL;
+
+ while (1)
+ {
+ nextToken();
+ exp = parseAssignExp();
+ cases.push(exp);
+ if (token.value != TOKcomma)
+ break;
+ }
+ check(TOKcolon);
+
+ /* case exp: .. case last:
+ */
+ if (token.value == TOKslice)
+ {
+ if (cases.dim > 1)
+ error("only one case allowed for start of case range");
+ nextToken();
+ check(TOKcase);
+ last = parseAssignExp();
+ check(TOKcolon);
+ }
+
+ if (flags & PScurlyscope)
+ {
+ Statements *statements = new Statements();
+ while (token.value != TOKcase &&
+ token.value != TOKdefault &&
+ token.value != TOKeof &&
+ token.value != TOKrcurly)
+ {
+ statements->push(parseStatement(PSsemi | PScurlyscope));
+ }
+ s = new CompoundStatement(loc, statements);
+ }
+ else
+ s = parseStatement(PSsemi | PScurlyscope);
+ s = new ScopeStatement(loc, s, token.loc);
+
+ if (last)
+ {
+ s = new CaseRangeStatement(loc, exp, last, s);
+ }
+ else
+ {
+ // Keep cases in order by building the case statements backwards
+ for (size_t i = cases.dim; i; i--)
+ {
+ exp = cases[i - 1];
+ s = new CaseStatement(loc, exp, s);
+ }
+ }
+ break;
+ }
+
+ case TOKdefault:
+ {
+ nextToken();
+ check(TOKcolon);
+
+ if (flags & PScurlyscope)
+ {
+ Statements *statements = new Statements();
+ while (token.value != TOKcase &&
+ token.value != TOKdefault &&
+ token.value != TOKeof &&
+ token.value != TOKrcurly)
+ {
+ statements->push(parseStatement(PSsemi | PScurlyscope));
+ }
+ s = new CompoundStatement(loc, statements);
+ }
+ else
+ s = parseStatement(PSsemi | PScurlyscope);
+ s = new ScopeStatement(loc, s, token.loc);
+ s = new DefaultStatement(loc, s);
+ break;
+ }
+
+ case TOKreturn:
+ { Expression *exp;
+
+ nextToken();
+ if (token.value == TOKsemicolon)
+ exp = NULL;
+ else
+ exp = parseExpression();
+ check(TOKsemicolon, "return statement");
+ s = new ReturnStatement(loc, exp);
+ break;
+ }
+
+ case TOKbreak:
+ { Identifier *ident;
+
+ nextToken();
+ if (token.value == TOKidentifier)
+ { ident = token.ident;
+ nextToken();
+ }
+ else
+ ident = NULL;
+ check(TOKsemicolon, "break statement");
+ s = new BreakStatement(loc, ident);
+ break;
+ }
+
+ case TOKcontinue:
+ { Identifier *ident;
+
+ nextToken();
+ if (token.value == TOKidentifier)
+ { ident = token.ident;
+ nextToken();
+ }
+ else
+ ident = NULL;
+ check(TOKsemicolon, "continue statement");
+ s = new ContinueStatement(loc, ident);
+ break;
+ }
+
+ case TOKgoto:
+ { Identifier *ident;
+
+ nextToken();
+ if (token.value == TOKdefault)
+ {
+ nextToken();
+ s = new GotoDefaultStatement(loc);
+ }
+ else if (token.value == TOKcase)
+ {
+ Expression *exp = NULL;
+
+ nextToken();
+ if (token.value != TOKsemicolon)
+ exp = parseExpression();
+ s = new GotoCaseStatement(loc, exp);
+ }
+ else
+ {
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following goto");
+ ident = NULL;
+ }
+ else
+ {
+ ident = token.ident;
+ nextToken();
+ }
+ s = new GotoStatement(loc, ident);
+ }
+ check(TOKsemicolon, "goto statement");
+ break;
+ }
+
+ case TOKsynchronized:
+ { Expression *exp;
+ Statement *body;
+
+ Token *t = peek(&token);
+ if (skipAttributes(t, &t) && t->value == TOKclass)
+ goto Ldeclaration;
+
+ nextToken();
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ exp = parseExpression();
+ check(TOKrparen);
+ }
+ else
+ exp = NULL;
+ body = parseStatement(PSscope);
+ s = new SynchronizedStatement(loc, exp, body);
+ break;
+ }
+
+ case TOKwith:
+ { Expression *exp;
+ Statement *body;
+
+ nextToken();
+ check(TOKlparen);
+ exp = parseExpression();
+ check(TOKrparen);
+ body = parseStatement(PSscope);
+ s = new WithStatement(loc, exp, body, token.loc);
+ break;
+ }
+
+ case TOKtry:
+ { Statement *body;
+ Catches *catches = NULL;
+ Statement *finalbody = NULL;
+
+ nextToken();
+ Loc lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+ body = parseStatement(PSscope);
+ lookingForElse = lookingForElseSave;
+ while (token.value == TOKcatch)
+ {
+ Statement *handler;
+ Catch *c;
+ Type *t;
+ Identifier *id;
+ Loc catchloc = token.loc;
+
+ nextToken();
+ if (token.value == TOKlcurly || token.value != TOKlparen)
+ {
+ t = NULL;
+ id = NULL;
+ }
+ else
+ {
+ check(TOKlparen);
+ id = NULL;
+ t = parseType(&id);
+ check(TOKrparen);
+ }
+ handler = parseStatement(0);
+ c = new Catch(catchloc, t, id, handler);
+ if (!catches)
+ catches = new Catches();
+ catches->push(c);
+ }
+
+ if (token.value == TOKfinally)
+ {
+ nextToken();
+ finalbody = parseStatement(PSscope);
+ }
+
+ s = body;
+ if (!catches && !finalbody)
+ error("catch or finally expected following try");
+ else
+ { if (catches)
+ s = new TryCatchStatement(loc, body, catches);
+ if (finalbody)
+ s = new TryFinallyStatement(loc, s, finalbody);
+ }
+ break;
+ }
+
+ case TOKthrow:
+ { Expression *exp;
+
+ nextToken();
+ exp = parseExpression();
+ check(TOKsemicolon, "throw statement");
+ s = new ThrowStatement(loc, exp);
+ break;
+ }
+
+ case TOKasm:
+ {
+ // Parse the asm block into a sequence of AsmStatements,
+ // each AsmStatement is one instruction.
+ // Separate out labels.
+ // Defer parsing of AsmStatements until semantic processing.
+
+ Loc labelloc;
+
+ nextToken();
+ StorageClass stc = parsePostfix(STCundefined, NULL);
+ if (stc & (STCconst | STCimmutable | STCshared | STCwild))
+ error("const/immutable/shared/inout attributes are not allowed on asm blocks");
+
+ check(TOKlcurly);
+ Token *toklist = NULL;
+ Token **ptoklist = &toklist;
+ Identifier *label = NULL;
+ Statements *statements = new Statements();
+ size_t nestlevel = 0;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKidentifier:
+ if (!toklist)
+ {
+ // Look ahead to see if it is a label
+ Token *t = peek(&token);
+ if (t->value == TOKcolon)
+ { // It's a label
+ label = token.ident;
+ labelloc = token.loc;
+ nextToken();
+ nextToken();
+ continue;
+ }
+ }
+ goto Ldefault;
+
+ case TOKlcurly:
+ ++nestlevel;
+ goto Ldefault;
+
+ case TOKrcurly:
+ if (nestlevel > 0)
+ {
+ --nestlevel;
+ goto Ldefault;
+ }
+
+ if (toklist || label)
+ {
+ error("asm statements must end in ';'");
+ }
+ break;
+
+ case TOKsemicolon:
+ if (nestlevel != 0)
+ error("mismatched number of curly brackets");
+
+ s = NULL;
+ if (toklist || label)
+ {
+ // Create AsmStatement from list of tokens we've saved
+ s = new AsmStatement(token.loc, toklist);
+ toklist = NULL;
+ ptoklist = &toklist;
+ if (label)
+ { s = new LabelStatement(labelloc, label, s);
+ label = NULL;
+ }
+ statements->push(s);
+ }
+ nextToken();
+ continue;
+
+ case TOKeof:
+ /* { */
+ error("matching '}' expected, not end of file");
+ goto Lerror;
+ /* fall through */
+
+ default:
+ Ldefault:
+ *ptoklist = Token::alloc();
+ memcpy(*ptoklist, &token, sizeof(Token));
+ ptoklist = &(*ptoklist)->next;
+ *ptoklist = NULL;
+
+ nextToken();
+ continue;
+ }
+ break;
+ }
+ s = new CompoundAsmStatement(loc, statements, stc);
+ nextToken();
+ break;
+ }
+
+ case TOKimport:
+ {
+ Dsymbols *imports = parseImport();
+ s = new ImportStatement(loc, imports);
+ if (flags & PSscope)
+ s = new ScopeStatement(loc, s, token.loc);
+ break;
+ }
+
+ case TOKtemplate:
+ {
+ Dsymbol *d = parseTemplateDeclaration();
+ s = new ExpStatement(loc, d);
+ break;
+ }
+
+ default:
+ error("found '%s' instead of statement", token.toChars());
+ goto Lerror;
+
+ Lerror:
+ while (token.value != TOKrcurly &&
+ token.value != TOKsemicolon &&
+ token.value != TOKeof)
+ nextToken();
+ if (token.value == TOKsemicolon)
+ nextToken();
+ s = NULL;
+ break;
+ }
+ if (pEndloc)
+ *pEndloc = token.loc;
+ return s;
+}
+
+void Parser::check(TOK value)
+{
+ check(token.loc, value);
+}
+
+void Parser::check(Loc loc, TOK value)
+{
+ if (token.value != value)
+ error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
+ nextToken();
+}
+
+void Parser::check(TOK value, const char *string)
+{
+ if (token.value != value)
+ error("found '%s' when expecting '%s' following %s",
+ token.toChars(), Token::toChars(value), string);
+ nextToken();
+}
+
+void Parser::checkParens(TOK value, Expression *e)
+{
+ if (precedence[e->op] == PREC_rel && !e->parens)
+ error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
+}
+
+/************************************
+ * Determine if the scanner is sitting on the start of a declaration.
+ * Input:
+ * needId 0 no identifier
+ * 1 identifier optional
+ * 2 must have identifier
+ * 3 must have identifier, but don't recognize old C-style syntax.
+ * Output:
+ * if *pt is not NULL, it is set to the ending token, which would be endtok
+ */
+
+bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt)
+{
+ //printf("isDeclaration(needId = %d)\n", needId);
+ int haveId = 0;
+ int haveTpl = 0;
+
+ while (1)
+ {
+ if ((t->value == TOKconst ||
+ t->value == TOKimmutable ||
+ t->value == TOKwild ||
+ t->value == TOKshared) &&
+ peek(t)->value != TOKlparen)
+ {
+ /* const type
+ * immutable type
+ * shared type
+ * wild type
+ */
+ t = peek(t);
+ continue;
+ }
+ break;
+ }
+
+ if (!isBasicType(&t))
+ {
+ goto Lisnot;
+ }
+ if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3))
+ goto Lisnot;
+ if (needId == 1 || (needId == 0 && !haveId) || ((needId == 2 || needId == 3) && haveId))
+ {
+ if (pt)
+ *pt = t;
+ goto Lis;
+ }
+ else
+ goto Lisnot;
+
+Lis:
+ //printf("\tis declaration, t = %s\n", t->toChars());
+ return true;
+
+Lisnot:
+ //printf("\tis not declaration\n");
+ return false;
+}
+
+bool Parser::isBasicType(Token **pt)
+{
+ // This code parallels parseBasicType()
+ Token *t = *pt;
+
+ switch (t->value)
+ {
+ case TOKwchar: case TOKdchar:
+ case TOKbool: case TOKchar:
+ case TOKint8: case TOKuns8:
+ case TOKint16: case TOKuns16:
+ case TOKint32: case TOKuns32:
+ case TOKint64: case TOKuns64:
+ case TOKint128: case TOKuns128:
+ case TOKfloat32: case TOKfloat64: case TOKfloat80:
+ case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+ case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+ case TOKvoid:
+ t = peek(t);
+ break;
+
+ case TOKidentifier:
+ L5:
+ t = peek(t);
+ if (t->value == TOKnot)
+ {
+ goto L4;
+ }
+ goto L3;
+ while (1)
+ {
+ L2:
+ t = peek(t);
+ L3:
+ if (t->value == TOKdot)
+ {
+ Ldot:
+ t = peek(t);
+ if (t->value != TOKidentifier)
+ goto Lfalse;
+ t = peek(t);
+ if (t->value != TOKnot)
+ goto L3;
+ L4:
+ /* Seen a !
+ * Look for:
+ * !( args ), !identifier, etc.
+ */
+ t = peek(t);
+ switch (t->value)
+ {
+ case TOKidentifier:
+ goto L5;
+ case TOKlparen:
+ if (!skipParens(t, &t))
+ goto Lfalse;
+ goto L3;
+ case TOKwchar: case TOKdchar:
+ case TOKbool: case TOKchar:
+ case TOKint8: case TOKuns8:
+ case TOKint16: case TOKuns16:
+ case TOKint32: case TOKuns32:
+ case TOKint64: case TOKuns64:
+ case TOKint128: case TOKuns128:
+ case TOKfloat32: case TOKfloat64: case TOKfloat80:
+ case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+ case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+ case TOKvoid:
+ case TOKint32v:
+ case TOKuns32v:
+ case TOKint64v:
+ case TOKuns64v:
+ case TOKint128v:
+ case TOKuns128v:
+ case TOKfloat32v:
+ case TOKfloat64v:
+ case TOKfloat80v:
+ case TOKimaginary32v:
+ case TOKimaginary64v:
+ case TOKimaginary80v:
+ case TOKnull:
+ case TOKtrue:
+ case TOKfalse:
+ case TOKcharv:
+ case TOKwcharv:
+ case TOKdcharv:
+ case TOKstring:
+ case TOKxstring:
+ case TOKfile:
+ case TOKfilefullpath:
+ case TOKline:
+ case TOKmodulestring:
+ case TOKfuncstring:
+ case TOKprettyfunc:
+ goto L2;
+ default:
+ goto Lfalse;
+ }
+ }
+ else
+ break;
+ }
+ break;
+
+ case TOKdot:
+ goto Ldot;
+
+ case TOKtypeof:
+ case TOKvector:
+ /* typeof(exp).identifier...
+ */
+ t = peek(t);
+ if (!skipParens(t, &t))
+ goto Lfalse;
+ goto L3;
+
+ case TOKconst:
+ case TOKimmutable:
+ case TOKshared:
+ case TOKwild:
+ // const(type) or immutable(type) or shared(type) or wild(type)
+ t = peek(t);
+ if (t->value != TOKlparen)
+ goto Lfalse;
+ t = peek(t);
+ if (!isDeclaration(t, 0, TOKrparen, &t))
+ {
+ goto Lfalse;
+ }
+ t = peek(t);
+ break;
+
+ default:
+ goto Lfalse;
+ }
+ *pt = t;
+ //printf("is\n");
+ return true;
+
+Lfalse:
+ //printf("is not\n");
+ return false;
+}
+
+bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax)
+{ // This code parallels parseDeclarator()
+ Token *t = *pt;
+ int parens;
+
+ //printf("Parser::isDeclarator() %s\n", t->toChars());
+ if (t->value == TOKassign)
+ return false;
+
+ while (1)
+ {
+ parens = false;
+ switch (t->value)
+ {
+ case TOKmul:
+ //case TOKand:
+ t = peek(t);
+ continue;
+
+ case TOKlbracket:
+ t = peek(t);
+ if (t->value == TOKrbracket)
+ {
+ t = peek(t);
+ }
+ else if (isDeclaration(t, 0, TOKrbracket, &t))
+ {
+ // It's an associative array declaration
+ t = peek(t);
+
+ // ...[type].ident
+ if (t->value == TOKdot && peek(t)->value == TOKidentifier)
+ {
+ t = peek(t);
+ t = peek(t);
+ }
+ }
+ else
+ {
+ // [ expression ]
+ // [ expression .. expression ]
+ if (!isExpression(&t))
+ return false;
+ if (t->value == TOKslice)
+ {
+ t = peek(t);
+ if (!isExpression(&t))
+ return false;
+ if (t->value != TOKrbracket)
+ return false;
+ t = peek(t);
+ }
+ else
+ {
+ if (t->value != TOKrbracket)
+ return false;
+ t = peek(t);
+
+ // ...[index].ident
+ if (t->value == TOKdot && peek(t)->value == TOKidentifier)
+ {
+ t = peek(t);
+ t = peek(t);
+ }
+ }
+ }
+ continue;
+
+ case TOKidentifier:
+ if (*haveId)
+ return false;
+ *haveId = true;
+ t = peek(t);
+ break;
+
+ case TOKlparen:
+ if (!allowAltSyntax)
+ return false; // Do not recognize C-style declarations.
+
+ t = peek(t);
+
+ if (t->value == TOKrparen)
+ return false; // () is not a declarator
+
+ /* Regard ( identifier ) as not a declarator
+ * BUG: what about ( *identifier ) in
+ * f(*p)(x);
+ * where f is a class instance with overloaded () ?
+ * Should we just disallow C-style function pointer declarations?
+ */
+ if (t->value == TOKidentifier)
+ { Token *t2 = peek(t);
+ if (t2->value == TOKrparen)
+ return false;
+ }
+
+
+ if (!isDeclarator(&t, haveId, NULL, TOKrparen))
+ return false;
+ t = peek(t);
+ parens = true;
+ break;
+
+ case TOKdelegate:
+ case TOKfunction:
+ t = peek(t);
+ if (!isParameters(&t))
+ return false;
+ skipAttributes(t, &t);
+ continue;
+ default: break;
+ }
+ break;
+ }
+
+ while (1)
+ {
+ switch (t->value)
+ {
+#if CARRAYDECL
+ case TOKlbracket:
+ parens = false;
+ t = peek(t);
+ if (t->value == TOKrbracket)
+ {
+ t = peek(t);
+ }
+ else if (isDeclaration(t, 0, TOKrbracket, &t))
+ { // It's an associative array declaration
+ t = peek(t);
+ }
+ else
+ {
+ // [ expression ]
+ if (!isExpression(&t))
+ return false;
+ if (t->value != TOKrbracket)
+ return false;
+ t = peek(t);
+ }
+ continue;
+#endif
+
+ case TOKlparen:
+ parens = false;
+ if (Token *tk = peekPastParen(t))
+ {
+ if (tk->value == TOKlparen)
+ {
+ if (!haveTpl) return false;
+ *haveTpl = 1;
+ t = tk;
+ }
+ else if (tk->value == TOKassign)
+ {
+ if (!haveTpl) return false;
+ *haveTpl = 1;
+ *pt = tk;
+ return true;
+ }
+ }
+ if (!isParameters(&t))
+ return false;
+ while (1)
+ {
+ switch (t->value)
+ {
+ case TOKconst:
+ case TOKimmutable:
+ case TOKshared:
+ case TOKwild:
+ case TOKpure:
+ case TOKnothrow:
+ case TOKreturn:
+ case TOKscope:
+ t = peek(t);
+ continue;
+ case TOKat:
+ t = peek(t); // skip '@'
+ t = peek(t); // skip identifier
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ continue;
+
+ case TOKidentifier:
+ if (t->ident != Id::_body)
+ goto Ldefault;
+ /* fall through */
+
+ // Valid tokens that follow a declaration
+ case TOKrparen:
+ case TOKrbracket:
+ case TOKassign:
+ case TOKcomma:
+ case TOKdotdotdot:
+ case TOKsemicolon:
+ case TOKlcurly:
+ case TOKin:
+ case TOKout:
+ case TOKdo:
+ // The !parens is to disallow unnecessary parentheses
+ if (!parens && (endtok == TOKreserved || endtok == t->value))
+ { *pt = t;
+ return true;
+ }
+ return false;
+
+ case TOKif:
+ return haveTpl ? true : false;
+
+ default:
+ Ldefault:
+ return false;
+ }
+ }
+ assert(0);
+}
+
+
+bool Parser::isParameters(Token **pt)
+{ // This code parallels parseParameters()
+ Token *t = *pt;
+
+ //printf("isParameters()\n");
+ if (t->value != TOKlparen)
+ return false;
+
+ t = peek(t);
+ for (;1; t = peek(t))
+ {
+ L1:
+ switch (t->value)
+ {
+ case TOKrparen:
+ break;
+
+ case TOKdotdotdot:
+ t = peek(t);
+ break;
+
+ case TOKin:
+ case TOKout:
+ case TOKref:
+ case TOKlazy:
+ case TOKscope:
+ case TOKfinal:
+ case TOKauto:
+ case TOKreturn:
+ continue;
+
+ case TOKconst:
+ case TOKimmutable:
+ case TOKshared:
+ case TOKwild:
+ t = peek(t);
+ if (t->value == TOKlparen)
+ {
+ t = peek(t);
+ if (!isDeclaration(t, 0, TOKrparen, &t))
+ return false;
+ t = peek(t); // skip past closing ')'
+ goto L2;
+ }
+ goto L1;
+
+ default:
+ { if (!isBasicType(&t))
+ return false;
+ L2:
+ int tmp = false;
+ if (t->value != TOKdotdotdot &&
+ !isDeclarator(&t, &tmp, NULL, TOKreserved))
+ return false;
+ if (t->value == TOKassign)
+ { t = peek(t);
+ if (!isExpression(&t))
+ return false;
+ }
+ if (t->value == TOKdotdotdot)
+ {
+ t = peek(t);
+ break;
+ }
+ }
+ if (t->value == TOKcomma)
+ {
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+ if (t->value != TOKrparen)
+ return false;
+ t = peek(t);
+ *pt = t;
+ return true;
+}
+
+bool Parser::isExpression(Token **pt)
+{
+ // This is supposed to determine if something is an expression.
+ // What it actually does is scan until a closing right bracket
+ // is found.
+
+ Token *t = *pt;
+ int brnest = 0;
+ int panest = 0;
+ int curlynest = 0;
+
+ for (;; t = peek(t))
+ {
+ switch (t->value)
+ {
+ case TOKlbracket:
+ brnest++;
+ continue;
+
+ case TOKrbracket:
+ if (--brnest >= 0)
+ continue;
+ break;
+
+ case TOKlparen:
+ panest++;
+ continue;
+
+ case TOKcomma:
+ if (brnest || panest)
+ continue;
+ break;
+
+ case TOKrparen:
+ if (--panest >= 0)
+ continue;
+ break;
+
+ case TOKlcurly:
+ curlynest++;
+ continue;
+
+ case TOKrcurly:
+ if (--curlynest >= 0)
+ continue;
+ return false;
+
+ case TOKslice:
+ if (brnest)
+ continue;
+ break;
+
+ case TOKsemicolon:
+ if (curlynest)
+ continue;
+ return false;
+
+ case TOKeof:
+ return false;
+
+ default:
+ continue;
+ }
+ break;
+ }
+
+ *pt = t;
+ return true;
+}
+
+/*******************************************
+ * Skip parens, brackets.
+ * Input:
+ * t is on opening (
+ * Output:
+ * *pt is set to closing token, which is ')' on success
+ * Returns:
+ * true successful
+ * false some parsing error
+ */
+
+bool Parser::skipParens(Token *t, Token **pt)
+{
+ if (t->value != TOKlparen)
+ return false;
+
+ int parens = 0;
+
+ while (1)
+ {
+ switch (t->value)
+ {
+ case TOKlparen:
+ parens++;
+ break;
+
+ case TOKrparen:
+ parens--;
+ if (parens < 0)
+ goto Lfalse;
+ if (parens == 0)
+ goto Ldone;
+ break;
+
+ case TOKeof:
+ goto Lfalse;
+
+ default:
+ break;
+ }
+ t = peek(t);
+ }
+
+ Ldone:
+ if (pt)
+ *pt = peek(t); // skip found rparen
+ return true;
+
+ Lfalse:
+ return false;
+}
+
+bool Parser::skipParensIf(Token *t, Token **pt)
+{
+ if (t->value != TOKlparen)
+ {
+ if (pt)
+ *pt = t;
+ return true;
+ }
+ return skipParens(t, pt);
+}
+
+/*******************************************
+ * Skip attributes.
+ * Input:
+ * t is on a candidate attribute
+ * Output:
+ * *pt is set to first non-attribute token on success
+ * Returns:
+ * true successful
+ * false some parsing error
+ */
+
+bool Parser::skipAttributes(Token *t, Token **pt)
+{
+ while (1)
+ {
+ switch (t->value)
+ {
+ case TOKconst:
+ case TOKimmutable:
+ case TOKshared:
+ case TOKwild:
+ case TOKfinal:
+ case TOKauto:
+ case TOKscope:
+ case TOKoverride:
+ case TOKabstract:
+ case TOKsynchronized:
+ break;
+ case TOKdeprecated:
+ if (peek(t)->value == TOKlparen)
+ {
+ t = peek(t);
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ continue;
+ }
+ break;
+ case TOKnothrow:
+ case TOKpure:
+ case TOKref:
+ case TOKgshared:
+ case TOKreturn:
+ //case TOKmanifest:
+ break;
+ case TOKat:
+ t = peek(t);
+ if (t->value == TOKidentifier)
+ {
+ /* @identifier
+ * @identifier!arg
+ * @identifier!(arglist)
+ * any of the above followed by (arglist)
+ * @predefined_attribute
+ */
+ if (t->ident == Id::property ||
+ t->ident == Id::nogc ||
+ t->ident == Id::safe ||
+ t->ident == Id::trusted ||
+ t->ident == Id::system ||
+ t->ident == Id::disable)
+ break;
+ t = peek(t);
+ if (t->value == TOKnot)
+ {
+ t = peek(t);
+ if (t->value == TOKlparen)
+ {
+ // @identifier!(arglist)
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ }
+ else
+ {
+ // @identifier!arg
+ // Do low rent skipTemplateArgument
+ if (t->value == TOKvector)
+ {
+ // identifier!__vector(type)
+ t = peek(t);
+ if (!skipParens(t, &t))
+ goto Lerror;
+ }
+ else
+ t = peek(t);
+ }
+ }
+ if (t->value == TOKlparen)
+ {
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ continue;
+ }
+ continue;
+ }
+ if (t->value == TOKlparen)
+ {
+ // @( ArgumentList )
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ continue;
+ }
+ goto Lerror;
+ default:
+ goto Ldone;
+ }
+ t = peek(t);
+ }
+
+ Ldone:
+ if (pt)
+ *pt = t;
+ return true;
+
+ Lerror:
+ return false;
+}
+
+/********************************* Expression Parser ***************************/
+
+Expression *Parser::parsePrimaryExp()
+{
+ Expression *e;
+ Type *t;
+ Identifier *id;
+ Loc loc = token.loc;
+
+ //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
+ switch (token.value)
+ {
+ case TOKidentifier:
+ {
+ Token *t1 = peek(&token);
+ Token *t2 = peek(t1);
+ if (t1->value == TOKmin && t2->value == TOKgt)
+ {
+ // skip ident.
+ nextToken();
+ nextToken();
+ nextToken();
+ error("use `.` for member lookup, not `->`");
+ goto Lerr;
+ }
+
+ if (peekNext() == TOKgoesto)
+ goto case_delegate;
+
+ id = token.ident;
+ nextToken();
+ TOK save;
+ if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
+ {
+ // identifier!(template-argument-list)
+ TemplateInstance *tempinst;
+ tempinst = new TemplateInstance(loc, id);
+ tempinst->tiargs = parseTemplateArguments();
+ e = new ScopeExp(loc, tempinst);
+ }
+ else
+ e = new IdentifierExp(loc, id);
+ break;
+ }
+
+ case TOKdollar:
+ if (!inBrackets)
+ error("'$' is valid only inside [] of index or slice");
+ e = new DollarExp(loc);
+ nextToken();
+ break;
+
+ case TOKdot:
+ // Signal global scope '.' operator with "" identifier
+ e = new IdentifierExp(loc, Id::empty);
+ break;
+
+ case TOKthis:
+ e = new ThisExp(loc);
+ nextToken();
+ break;
+
+ case TOKsuper:
+ e = new SuperExp(loc);
+ nextToken();
+ break;
+
+ case TOKint32v:
+ e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
+ nextToken();
+ break;
+
+ case TOKuns32v:
+ e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
+ nextToken();
+ break;
+
+ case TOKint64v:
+ e = new IntegerExp(loc, token.int64value, Type::tint64);
+ nextToken();
+ break;
+
+ case TOKuns64v:
+ e = new IntegerExp(loc, token.uns64value, Type::tuns64);
+ nextToken();
+ break;
+
+ case TOKfloat32v:
+ e = new RealExp(loc, token.floatvalue, Type::tfloat32);
+ nextToken();
+ break;
+
+ case TOKfloat64v:
+ e = new RealExp(loc, token.floatvalue, Type::tfloat64);
+ nextToken();
+ break;
+
+ case TOKfloat80v:
+ e = new RealExp(loc, token.floatvalue, Type::tfloat80);
+ nextToken();
+ break;
+
+ case TOKimaginary32v:
+ e = new RealExp(loc, token.floatvalue, Type::timaginary32);
+ nextToken();
+ break;
+
+ case TOKimaginary64v:
+ e = new RealExp(loc, token.floatvalue, Type::timaginary64);
+ nextToken();
+ break;
+
+ case TOKimaginary80v:
+ e = new RealExp(loc, token.floatvalue, Type::timaginary80);
+ nextToken();
+ break;
+
+ case TOKnull:
+ e = new NullExp(loc);
+ nextToken();
+ break;
+
+ case TOKfile:
+ {
+ const char *s = loc.filename ? loc.filename : mod->ident->toChars();
+ e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
+ nextToken();
+ break;
+ }
+
+ case TOKfilefullpath:
+ {
+ const char *srcfile = mod->srcfile->name->toChars();
+ const char *s;
+ if (loc.filename && !FileName::equals(loc.filename, srcfile))
+ s = loc.filename;
+ else
+ s = FileName::combine(mod->srcfilePath, srcfile);
+ e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
+ nextToken();
+ break;
+ }
+
+ case TOKline:
+ e = new IntegerExp(loc, loc.linnum, Type::tint32);
+ nextToken();
+ break;
+
+ case TOKmodulestring:
+ {
+ const char *s = md ? md->toChars() : mod->toChars();
+ e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
+ nextToken();
+ break;
+ }
+
+ case TOKfuncstring:
+ e = new FuncInitExp(loc);
+ nextToken();
+ break;
+
+ case TOKprettyfunc:
+ e = new PrettyFuncInitExp(loc);
+ nextToken();
+ break;
+
+ case TOKtrue:
+ e = new IntegerExp(loc, 1, Type::tbool);
+ nextToken();
+ break;
+
+ case TOKfalse:
+ e = new IntegerExp(loc, 0, Type::tbool);
+ nextToken();
+ break;
+
+ case TOKcharv:
+ e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar);
+ nextToken();
+ break;
+
+ case TOKwcharv:
+ e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar);
+ nextToken();
+ break;
+
+ case TOKdcharv:
+ e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
+ nextToken();
+ break;
+
+ case TOKstring:
+ case TOKxstring:
+ {
+ // cat adjacent strings
+ utf8_t *s = token.ustring;
+ size_t len = token.len;
+ unsigned char postfix = token.postfix;
+ while (1)
+ {
+ const Token prev = token;
+ nextToken();
+ if (token.value == TOKstring ||
+ token.value == TOKxstring)
+ {
+ if (token.postfix)
+ { if (token.postfix != postfix)
+ error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
+ postfix = token.postfix;
+ }
+
+ deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead",
+ prev.toChars(), token.toChars());
+
+ size_t len1 = len;
+ size_t len2 = token.len;
+ len = len1 + len2;
+ utf8_t *s2 = (utf8_t *)mem.xmalloc((len + 1) * sizeof(utf8_t));
+ memcpy(s2, s, len1 * sizeof(utf8_t));
+ memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t));
+ s = s2;
+ }
+ else
+ break;
+ }
+ e = new StringExp(loc, s, len, postfix);
+ break;
+ }
+
+ case TOKvoid: t = Type::tvoid; goto LabelX;
+ case TOKint8: t = Type::tint8; goto LabelX;
+ case TOKuns8: t = Type::tuns8; goto LabelX;
+ case TOKint16: t = Type::tint16; goto LabelX;
+ case TOKuns16: t = Type::tuns16; goto LabelX;
+ case TOKint32: t = Type::tint32; goto LabelX;
+ case TOKuns32: t = Type::tuns32; goto LabelX;
+ case TOKint64: t = Type::tint64; goto LabelX;
+ case TOKuns64: t = Type::tuns64; goto LabelX;
+ case TOKint128: t = Type::tint128; goto LabelX;
+ case TOKuns128: t = Type::tuns128; goto LabelX;
+ case TOKfloat32: t = Type::tfloat32; goto LabelX;
+ case TOKfloat64: t = Type::tfloat64; goto LabelX;
+ case TOKfloat80: t = Type::tfloat80; goto LabelX;
+ case TOKimaginary32: t = Type::timaginary32; goto LabelX;
+ case TOKimaginary64: t = Type::timaginary64; goto LabelX;
+ case TOKimaginary80: t = Type::timaginary80; goto LabelX;
+ case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
+ case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
+ case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
+ case TOKbool: t = Type::tbool; goto LabelX;
+ case TOKchar: t = Type::tchar; goto LabelX;
+ case TOKwchar: t = Type::twchar; goto LabelX;
+ case TOKdchar: t = Type::tdchar; goto LabelX;
+ LabelX:
+ nextToken();
+ if (token.value == TOKlparen)
+ {
+ e = new TypeExp(loc, t);
+ e = new CallExp(loc, e, parseArguments());
+ break;
+ }
+ check(TOKdot, t->toChars());
+ if (token.value != TOKidentifier)
+ { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
+ goto Lerr;
+ }
+ e = typeDotIdExp(loc, t, token.ident);
+ nextToken();
+ break;
+
+ case TOKtypeof:
+ {
+ t = parseTypeof();
+ e = new TypeExp(loc, t);
+ break;
+ }
+
+ case TOKvector:
+ {
+ t = parseVector();
+ e = new TypeExp(loc, t);
+ break;
+ }
+
+ case TOKtypeid:
+ {
+ nextToken();
+ check(TOKlparen, "typeid");
+ RootObject *o;
+ if (isDeclaration(&token, 0, TOKreserved, NULL))
+ { // argument is a type
+ o = parseType();
+ }
+ else
+ { // argument is an expression
+ o = parseAssignExp();
+ }
+ check(TOKrparen);
+ e = new TypeidExp(loc, o);
+ break;
+ }
+
+ case TOKtraits:
+ { /* __traits(identifier, args...)
+ */
+ Identifier *ident;
+ Objects *args = NULL;
+
+ nextToken();
+ check(TOKlparen);
+ if (token.value != TOKidentifier)
+ { error("__traits(identifier, args...) expected");
+ goto Lerr;
+ }
+ ident = token.ident;
+ nextToken();
+ if (token.value == TOKcomma)
+ args = parseTemplateArgumentList(); // __traits(identifier, args...)
+ else
+ check(TOKrparen); // __traits(identifier)
+
+ e = new TraitsExp(loc, ident, args);
+ break;
+ }
+
+ case TOKis:
+ {
+ Type *targ;
+ Identifier *ident = NULL;
+ Type *tspec = NULL;
+ TOK tok = TOKreserved;
+ TOK tok2 = TOKreserved;
+ TemplateParameters *tpl = NULL;
+
+ nextToken();
+ if (token.value == TOKlparen)
+ {
+ nextToken();
+ targ = parseType(&ident);
+ if (token.value == TOKcolon || token.value == TOKequal)
+ {
+ tok = token.value;
+ nextToken();
+ if (tok == TOKequal &&
+ (token.value == TOKstruct ||
+ token.value == TOKunion ||
+ token.value == TOKclass ||
+ token.value == TOKsuper ||
+ token.value == TOKenum ||
+ token.value == TOKinterface ||
+ token.value == TOKargTypes ||
+ token.value == TOKparameters ||
+ (token.value == TOKconst && peek(&token)->value == TOKrparen) ||
+ (token.value == TOKimmutable && peek(&token)->value == TOKrparen) ||
+ (token.value == TOKshared && peek(&token)->value == TOKrparen) ||
+ (token.value == TOKwild && peek(&token)->value == TOKrparen) ||
+ token.value == TOKfunction ||
+ token.value == TOKdelegate ||
+ token.value == TOKreturn ||
+ (token.value == TOKvector && peek(&token)->value == TOKrparen)))
+ {
+ tok2 = token.value;
+ nextToken();
+ }
+ else
+ {
+ tspec = parseType();
+ }
+ }
+ if (tspec)
+ {
+ if (token.value == TOKcomma)
+ tpl = parseTemplateParameterList(1);
+ else
+ {
+ tpl = new TemplateParameters();
+ check(TOKrparen);
+ }
+ }
+ else
+ check(TOKrparen);
+ }
+ else
+ {
+ error("(type identifier : specialization) expected following is");
+ goto Lerr;
+ }
+ e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
+ break;
+ }
+
+ case TOKassert:
+ { Expression *msg = NULL;
+
+ nextToken();
+ check(TOKlparen, "assert");
+ e = parseAssignExp();
+ if (token.value == TOKcomma)
+ {
+ nextToken();
+ if (token.value != TOKrparen)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOKcomma)
+ nextToken();
+ }
+ }
+ check(TOKrparen);
+ e = new AssertExp(loc, e, msg);
+ break;
+ }
+
+ case TOKmixin:
+ {
+ nextToken();
+ check(TOKlparen, "mixin");
+ e = parseAssignExp();
+ check(TOKrparen);
+ e = new CompileExp(loc, e);
+ break;
+ }
+
+ case TOKimport:
+ {
+ nextToken();
+ check(TOKlparen, "import");
+ e = parseAssignExp();
+ check(TOKrparen);
+ e = new ImportExp(loc, e);
+ break;
+ }
+
+ case TOKnew:
+ e = parseNewExp(NULL);
+ break;
+
+ case TOKlparen:
+ {
+ Token *tk = peekPastParen(&token);
+ if (skipAttributes(tk, &tk) &&
+ (tk->value == TOKgoesto || tk->value == TOKlcurly))
+ {
+ // (arguments) => expression
+ // (arguments) { statements... }
+ goto case_delegate;
+ }
+
+ // ( expression )
+ nextToken();
+ e = parseExpression();
+ e->parens = 1;
+ check(loc, TOKrparen);
+ break;
+ }
+
+ case TOKlbracket:
+ { /* Parse array literals and associative array literals:
+ * [ value, value, value ... ]
+ * [ key:value, key:value, key:value ... ]
+ */
+ Expressions *values = new Expressions();
+ Expressions *keys = NULL;
+
+ nextToken();
+ while (token.value != TOKrbracket && token.value != TOKeof)
+ {
+ e = parseAssignExp();
+ if (token.value == TOKcolon && (keys || values->dim == 0))
+ { nextToken();
+ if (!keys)
+ keys = new Expressions();
+ keys->push(e);
+ e = parseAssignExp();
+ }
+ else if (keys)
+ { error("'key:value' expected for associative array literal");
+ delete keys;
+ keys = NULL;
+ }
+ values->push(e);
+ if (token.value == TOKrbracket)
+ break;
+ check(TOKcomma);
+ }
+ check(loc, TOKrbracket);
+
+ if (keys)
+ e = new AssocArrayLiteralExp(loc, keys, values);
+ else
+ e = new ArrayLiteralExp(loc, values);
+ break;
+ }
+
+ case TOKlcurly:
+ case TOKfunction:
+ case TOKdelegate:
+ case_delegate:
+ {
+ Dsymbol *s = parseFunctionLiteral();
+ e = new FuncExp(loc, s);
+ break;
+ }
+
+ default:
+ error("expression expected, not '%s'", token.toChars());
+ Lerr:
+ // Anything for e, as long as it's not NULL
+ e = new IntegerExp(loc, 0, Type::tint32);
+ nextToken();
+ break;
+ }
+ return e;
+}
+
+Expression *Parser::parsePostExp(Expression *e)
+{
+ Loc loc;
+
+ while (1)
+ {
+ loc = token.loc;
+ switch (token.value)
+ {
+ case TOKdot:
+ nextToken();
+ if (token.value == TOKidentifier)
+ { Identifier *id = token.ident;
+
+ nextToken();
+ if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin)
+ {
+ Objects *tiargs = parseTemplateArguments();
+ e = new DotTemplateInstanceExp(loc, e, id, tiargs);
+ }
+ else
+ e = new DotIdExp(loc, e, id);
+ continue;
+ }
+ else if (token.value == TOKnew)
+ {
+ e = parseNewExp(e);
+ continue;
+ }
+ else
+ error("identifier expected following '.', not '%s'", token.toChars());
+ break;
+
+ case TOKplusplus:
+ e = new PostExp(TOKplusplus, loc, e);
+ break;
+
+ case TOKminusminus:
+ e = new PostExp(TOKminusminus, loc, e);
+ break;
+
+ case TOKlparen:
+ e = new CallExp(loc, e, parseArguments());
+ continue;
+
+ case TOKlbracket:
+ { // array dereferences:
+ // array[index]
+ // array[]
+ // array[lwr .. upr]
+ Expression *index;
+ Expression *upr;
+ Expressions *arguments = new Expressions();
+
+ inBrackets++;
+ nextToken();
+ while (token.value != TOKrbracket && token.value != TOKeof)
+ {
+ index = parseAssignExp();
+ if (token.value == TOKslice)
+ {
+ // array[..., lwr..upr, ...]
+ nextToken();
+ upr = parseAssignExp();
+ arguments->push(new IntervalExp(loc, index, upr));
+ }
+ else
+ arguments->push(index);
+ if (token.value == TOKrbracket)
+ break;
+ check(TOKcomma);
+ }
+ check(TOKrbracket);
+ inBrackets--;
+ e = new ArrayExp(loc, e, arguments);
+ continue;
+ }
+
+ default:
+ return e;
+ }
+ nextToken();
+ }
+}
+
+Expression *Parser::parseUnaryExp()
+{
+ Expression *e;
+ Loc loc = token.loc;
+
+ switch (token.value)
+ {
+ case TOKand:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AddrExp(loc, e);
+ break;
+
+ case TOKplusplus:
+ nextToken();
+ e = parseUnaryExp();
+ //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+ e = new PreExp(TOKpreplusplus, loc, e);
+ break;
+
+ case TOKminusminus:
+ nextToken();
+ e = parseUnaryExp();
+ //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+ e = new PreExp(TOKpreminusminus, loc, e);
+ break;
+
+ case TOKmul:
+ nextToken();
+ e = parseUnaryExp();
+ e = new PtrExp(loc, e);
+ break;
+
+ case TOKmin:
+ nextToken();
+ e = parseUnaryExp();
+ e = new NegExp(loc, e);
+ break;
+
+ case TOKadd:
+ nextToken();
+ e = parseUnaryExp();
+ e = new UAddExp(loc, e);
+ break;
+
+ case TOKnot:
+ nextToken();
+ e = parseUnaryExp();
+ e = new NotExp(loc, e);
+ break;
+
+ case TOKtilde:
+ nextToken();
+ e = parseUnaryExp();
+ e = new ComExp(loc, e);
+ break;
+
+ case TOKdelete:
+ nextToken();
+ e = parseUnaryExp();
+ e = new DeleteExp(loc, e, false);
+ break;
+
+ case TOKcast: // cast(type) expression
+ {
+ nextToken();
+ check(TOKlparen);
+ /* Look for cast(), cast(const), cast(immutable),
+ * cast(shared), cast(shared const), cast(wild), cast(shared wild)
+ */
+ unsigned char m = 0;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKconst:
+ if (peekNext() == TOKlparen)
+ break; // const as type constructor
+ m |= MODconst; // const as storage class
+ nextToken();
+ continue;
+
+ case TOKimmutable:
+ if (peekNext() == TOKlparen)
+ break;
+ m |= MODimmutable;
+ nextToken();
+ continue;
+
+ case TOKshared:
+ if (peekNext() == TOKlparen)
+ break;
+ m |= MODshared;
+ nextToken();
+ continue;
+
+ case TOKwild:
+ if (peekNext() == TOKlparen)
+ break;
+ m |= MODwild;
+ nextToken();
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ if (token.value == TOKrparen)
+ {
+ nextToken();
+ e = parseUnaryExp();
+ e = new CastExp(loc, e, m);
+ }
+ else
+ {
+ Type *t = parseType(); // cast( type )
+ t = t->addMod(m); // cast( const type )
+ check(TOKrparen);
+ e = parseUnaryExp();
+ e = new CastExp(loc, e, t);
+ }
+ break;
+ }
+
+ case TOKwild:
+ case TOKshared:
+ case TOKconst:
+ case TOKimmutable: // immutable(type)(arguments) / immutable(type).init
+ {
+ StorageClass stc = parseTypeCtor();
+ Type *t = parseBasicType();
+ t = t->addSTC(stc);
+ e = new TypeExp(loc, t);
+ if (stc == 0 && token.value == TOKdot)
+ {
+ nextToken();
+ if (token.value != TOKidentifier)
+ {
+ error("identifier expected following (type).");
+ return NULL;
+ }
+ e = typeDotIdExp(loc, t, token.ident);
+ nextToken();
+ e = parsePostExp(e);
+ break;
+ }
+ else if (token.value != TOKlparen)
+ {
+ error("(arguments) expected following %s", t->toChars());
+ return e;
+ }
+ e = new CallExp(loc, e, parseArguments());
+ break;
+ }
+
+
+ case TOKlparen:
+ { Token *tk;
+
+ tk = peek(&token);
+#if CCASTSYNTAX
+ // If cast
+ if (isDeclaration(tk, 0, TOKrparen, &tk))
+ {
+ tk = peek(tk); // skip over right parenthesis
+ switch (tk->value)
+ {
+ case TOKnot:
+ tk = peek(tk);
+ if (tk->value == TOKis || tk->value == TOKin) // !is or !in
+ break;
+ /* fall through */
+
+ case TOKdot:
+ case TOKplusplus:
+ case TOKminusminus:
+ case TOKdelete:
+ case TOKnew:
+ case TOKlparen:
+ case TOKidentifier:
+ case TOKthis:
+ case TOKsuper:
+ case TOKint32v:
+ case TOKuns32v:
+ case TOKint64v:
+ case TOKuns64v:
+ case TOKint128v:
+ case TOKuns128v:
+ case TOKfloat32v:
+ case TOKfloat64v:
+ case TOKfloat80v:
+ case TOKimaginary32v:
+ case TOKimaginary64v:
+ case TOKimaginary80v:
+ case TOKnull:
+ case TOKtrue:
+ case TOKfalse:
+ case TOKcharv:
+ case TOKwcharv:
+ case TOKdcharv:
+ case TOKstring:
+ case TOKfunction:
+ case TOKdelegate:
+ case TOKtypeof:
+ case TOKvector:
+ case TOKfile:
+ case TOKfilefullpath:
+ case TOKline:
+ case TOKmodulestring:
+ case TOKfuncstring:
+ case TOKprettyfunc:
+ case TOKwchar: case TOKdchar:
+ case TOKbool: case TOKchar:
+ case TOKint8: case TOKuns8:
+ case TOKint16: case TOKuns16:
+ case TOKint32: case TOKuns32:
+ case TOKint64: case TOKuns64:
+ case TOKint128: case TOKuns128:
+ case TOKfloat32: case TOKfloat64: case TOKfloat80:
+ case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+ case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+ case TOKvoid:
+ { // (type) una_exp
+ Type *t;
+
+ nextToken();
+ t = parseType();
+ check(TOKrparen);
+
+ // if .identifier
+ // or .identifier!( ... )
+ if (token.value == TOKdot)
+ {
+ if (peekNext() != TOKidentifier && peekNext() != TOKnew)
+ {
+ error("identifier or new keyword expected following (...).");
+ return NULL;
+ }
+ e = new TypeExp(loc, t);
+ e = parsePostExp(e);
+ }
+ else
+ {
+ e = parseUnaryExp();
+ e = new CastExp(loc, e, t);
+ error("C style cast illegal, use %s", e->toChars());
+ }
+ return e;
+ }
+ default:
+ break;
+ }
+ }
+#endif
+ e = parsePrimaryExp();
+ e = parsePostExp(e);
+ break;
+ }
+ default:
+ e = parsePrimaryExp();
+ e = parsePostExp(e);
+ break;
+ }
+ assert(e);
+
+ // ^^ is right associative and has higher precedence than the unary operators
+ while (token.value == TOKpow)
+ {
+ nextToken();
+ Expression *e2 = parseUnaryExp();
+ e = new PowExp(loc, e, e2);
+ }
+
+ return e;
+}
+
+Expression *Parser::parseMulExp()
+{
+ Expression *e;
+ Expression *e2;
+ Loc loc = token.loc;
+
+ e = parseUnaryExp();
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
+ case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
+ case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+}
+
+Expression *Parser::parseAddExp()
+{
+ Expression *e;
+ Expression *e2;
+ Loc loc = token.loc;
+
+ e = parseMulExp();
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
+ case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
+ case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+}
+
+Expression *Parser::parseShiftExp()
+{
+ Expression *e;
+ Expression *e2;
+ Loc loc = token.loc;
+
+ e = parseAddExp();
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
+ case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
+ case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+}
+
+Expression *Parser::parseCmpExp()
+{
+ Expression *e;
+ Expression *e2;
+ Token *t;
+ Loc loc = token.loc;
+
+ e = parseShiftExp();
+ TOK op = token.value;
+
+ switch (op)
+ {
+ case TOKequal:
+ case TOKnotequal:
+ nextToken();
+ e2 = parseShiftExp();
+ e = new EqualExp(op, loc, e, e2);
+ break;
+
+ case TOKis:
+ op = TOKidentity;
+ goto L1;
+
+ case TOKnot:
+ // Attempt to identify '!is'
+ t = peek(&token);
+ if (t->value == TOKin)
+ {
+ nextToken();
+ nextToken();
+ e2 = parseShiftExp();
+ e = new InExp(loc, e, e2);
+ e = new NotExp(loc, e);
+ break;
+ }
+ if (t->value != TOKis)
+ break;
+ nextToken();
+ op = TOKnotidentity;
+ goto L1;
+
+ L1:
+ nextToken();
+ e2 = parseShiftExp();
+ e = new IdentityExp(op, loc, e, e2);
+ break;
+
+ case TOKlt:
+ case TOKle:
+ case TOKgt:
+ case TOKge:
+ case TOKunord:
+ case TOKlg:
+ case TOKleg:
+ case TOKule:
+ case TOKul:
+ case TOKuge:
+ case TOKug:
+ case TOKue:
+ nextToken();
+ e2 = parseShiftExp();
+ e = new CmpExp(op, loc, e, e2);
+ break;
+
+ case TOKin:
+ nextToken();
+ e2 = parseShiftExp();
+ e = new InExp(loc, e, e2);
+ break;
+
+ default:
+ break;
+ }
+ return e;
+}
+
+Expression *Parser::parseAndExp()
+{
+ Loc loc = token.loc;
+
+ Expression *e = parseCmpExp();
+ while (token.value == TOKand)
+ {
+ checkParens(TOKand, e);
+ nextToken();
+ Expression *e2 = parseCmpExp();
+ checkParens(TOKand, e2);
+ e = new AndExp(loc,e,e2);
+ loc = token.loc;
+ }
+ return e;
+}
+
+Expression *Parser::parseXorExp()
+{
+ Loc loc = token.loc;
+
+ Expression *e = parseAndExp();
+ while (token.value == TOKxor)
+ {
+ checkParens(TOKxor, e);
+ nextToken();
+ Expression *e2 = parseAndExp();
+ checkParens(TOKxor, e2);
+ e = new XorExp(loc, e, e2);
+ }
+ return e;
+}
+
+Expression *Parser::parseOrExp()
+{
+ Loc loc = token.loc;
+
+ Expression *e = parseXorExp();
+ while (token.value == TOKor)
+ {
+ checkParens(TOKor, e);
+ nextToken();
+ Expression *e2 = parseXorExp();
+ checkParens(TOKor, e2);
+ e = new OrExp(loc, e, e2);
+ }
+ return e;
+}
+
+Expression *Parser::parseAndAndExp()
+{
+ Expression *e;
+ Expression *e2;
+ Loc loc = token.loc;
+
+ e = parseOrExp();
+ while (token.value == TOKandand)
+ {
+ nextToken();
+ e2 = parseOrExp();
+ e = new AndAndExp(loc, e, e2);
+ }
+ return e;
+}
+
+Expression *Parser::parseOrOrExp()
+{
+ Expression *e;
+ Expression *e2;
+ Loc loc = token.loc;
+
+ e = parseAndAndExp();
+ while (token.value == TOKoror)
+ {
+ nextToken();
+ e2 = parseAndAndExp();
+ e = new OrOrExp(loc, e, e2);
+ }
+ return e;
+}
+
+Expression *Parser::parseCondExp()
+{
+ Expression *e;
+ Expression *e1;
+ Expression *e2;
+ Loc loc = token.loc;
+
+ e = parseOrOrExp();
+ if (token.value == TOKquestion)
+ {
+ nextToken();
+ e1 = parseExpression();
+ check(TOKcolon);
+ e2 = parseCondExp();
+ e = new CondExp(loc, e, e1, e2);
+ }
+ return e;
+}
+
+Expression *Parser::parseAssignExp()
+{
+ Expression *e;
+ Expression *e2;
+ Loc loc;
+
+ e = parseCondExp();
+ while (1)
+ {
+ loc = token.loc;
+ switch (token.value)
+ {
+ case TOKassign: nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue;
+ case TOKaddass: nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue;
+ case TOKminass: nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue;
+ case TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue;
+ case TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue;
+ case TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue;
+ case TOKpowass: nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue;
+ case TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue;
+ case TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue;
+ case TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue;
+ case TOKshlass: nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue;
+ case TOKshrass: nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue;
+ case TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue;
+ case TOKcatass: nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue;
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+}
+
+Expression *Parser::parseExpression()
+{
+ Expression *e;
+ Expression *e2;
+ Loc loc = token.loc;
+
+ //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
+ e = parseAssignExp();
+ while (token.value == TOKcomma)
+ {
+ nextToken();
+ e2 = parseAssignExp();
+ e = new CommaExp(loc, e, e2, false);
+ loc = token.loc;
+ }
+ return e;
+}
+
+
+/*************************
+ * Collect argument list.
+ * Assume current token is ',', '(' or '['.
+ */
+
+Expressions *Parser::parseArguments()
+{ // function call
+ Expressions *arguments;
+ Expression *arg;
+ TOK endtok;
+
+ arguments = new Expressions();
+ if (token.value == TOKlbracket)
+ endtok = TOKrbracket;
+ else
+ endtok = TOKrparen;
+
+ {
+ nextToken();
+ while (token.value != endtok && token.value != TOKeof)
+ {
+ arg = parseAssignExp();
+ arguments->push(arg);
+ if (token.value == endtok)
+ break;
+ check(TOKcomma);
+ }
+ check(endtok);
+ }
+ return arguments;
+}
+
+/*******************************************
+ */
+
+Expression *Parser::parseNewExp(Expression *thisexp)
+{
+ Type *t;
+ Expressions *newargs;
+ Expressions *arguments = NULL;
+ Loc loc = token.loc;
+
+ nextToken();
+ newargs = NULL;
+ if (token.value == TOKlparen)
+ {
+ newargs = parseArguments();
+ }
+
+ // An anonymous nested class starts with "class"
+ if (token.value == TOKclass)
+ {
+ nextToken();
+ if (token.value == TOKlparen)
+ arguments = parseArguments();
+
+ BaseClasses *baseclasses = NULL;
+ if (token.value != TOKlcurly)
+ baseclasses = parseBaseClasses();
+
+ Identifier *id = NULL;
+ Dsymbols *members = NULL;
+
+ if (token.value != TOKlcurly)
+ {
+ error("{ members } expected for anonymous class");
+ }
+ else
+ {
+ nextToken();
+ members = parseDeclDefs(0);
+ if (token.value != TOKrcurly)
+ error("class member expected");
+ nextToken();
+ }
+
+ ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses, members, false);
+ Expression *e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
+
+ return e;
+ }
+
+ StorageClass stc = parseTypeCtor();
+ t = parseBasicType(true);
+ t = parseBasicType2(t);
+ t = t->addSTC(stc);
+ if (t->ty == Taarray)
+ {
+ TypeAArray *taa = (TypeAArray *)t;
+ Type *index = taa->index;
+
+ Expression *edim = typeToExpression(index);
+ if (!edim)
+ {
+ error("need size of rightmost array, not type %s", index->toChars());
+ return new NullExp(loc);
+ }
+ t = new TypeSArray(taa->next, edim);
+ }
+ else if (t->ty == Tsarray)
+ {
+ }
+ else if (token.value == TOKlparen)
+ {
+ arguments = parseArguments();
+ }
+ Expression *e = new NewExp(loc, thisexp, newargs, t, arguments);
+ return e;
+}
+
+/**********************************************
+ */
+
+void Parser::addComment(Dsymbol *s, const utf8_t *blockComment)
+{
+ s->addComment(combineComments(blockComment, token.lineComment));
+ token.lineComment = NULL;
+}
+
+
+/**********************************
+ * Set operator precedence for each operator.
+ */
+
+PREC precedence[TOKMAX];
+
+struct PrecedenceInitializer
+{
+ PrecedenceInitializer();
+};
+
+static PrecedenceInitializer precedenceinitializer;
+
+PrecedenceInitializer::PrecedenceInitializer()
+{
+ for (size_t i = 0; i < TOKMAX; i++)
+ precedence[i] = PREC_zero;
+
+ precedence[TOKtype] = PREC_expr;
+ precedence[TOKerror] = PREC_expr;
+
+ precedence[TOKtypeof] = PREC_primary;
+ precedence[TOKmixin] = PREC_primary;
+ precedence[TOKimport] = PREC_primary;
+
+ precedence[TOKdotvar] = PREC_primary;
+ precedence[TOKscope] = PREC_primary;
+ precedence[TOKidentifier] = PREC_primary;
+ precedence[TOKthis] = PREC_primary;
+ precedence[TOKsuper] = PREC_primary;
+ precedence[TOKint64] = PREC_primary;
+ precedence[TOKfloat64] = PREC_primary;
+ precedence[TOKcomplex80] = PREC_primary;
+ precedence[TOKnull] = PREC_primary;
+ precedence[TOKstring] = PREC_primary;
+ precedence[TOKarrayliteral] = PREC_primary;
+ precedence[TOKassocarrayliteral] = PREC_primary;
+ precedence[TOKclassreference] = PREC_primary;
+ precedence[TOKfile] = PREC_primary;
+ precedence[TOKfilefullpath] = PREC_primary;
+ precedence[TOKline] = PREC_primary;
+ precedence[TOKmodulestring] = PREC_primary;
+ precedence[TOKfuncstring] = PREC_primary;
+ precedence[TOKprettyfunc] = PREC_primary;
+ precedence[TOKtypeid] = PREC_primary;
+ precedence[TOKis] = PREC_primary;
+ precedence[TOKassert] = PREC_primary;
+ precedence[TOKhalt] = PREC_primary;
+ precedence[TOKtemplate] = PREC_primary;
+ precedence[TOKdsymbol] = PREC_primary;
+ precedence[TOKfunction] = PREC_primary;
+ precedence[TOKvar] = PREC_primary;
+ precedence[TOKsymoff] = PREC_primary;
+ precedence[TOKstructliteral] = PREC_primary;
+ precedence[TOKarraylength] = PREC_primary;
+ precedence[TOKdelegateptr] = PREC_primary;
+ precedence[TOKdelegatefuncptr] = PREC_primary;
+ precedence[TOKremove] = PREC_primary;
+ precedence[TOKtuple] = PREC_primary;
+ precedence[TOKtraits] = PREC_primary;
+ precedence[TOKdefault] = PREC_primary;
+ precedence[TOKoverloadset] = PREC_primary;
+ precedence[TOKvoid] = PREC_primary;
+
+ // post
+ precedence[TOKdotti] = PREC_primary;
+ precedence[TOKdotid] = PREC_primary;
+ precedence[TOKdottd] = PREC_primary;
+ precedence[TOKdot] = PREC_primary;
+ precedence[TOKdottype] = PREC_primary;
+// precedence[TOKarrow] = PREC_primary;
+ precedence[TOKplusplus] = PREC_primary;
+ precedence[TOKminusminus] = PREC_primary;
+ precedence[TOKpreplusplus] = PREC_primary;
+ precedence[TOKpreminusminus] = PREC_primary;
+ precedence[TOKcall] = PREC_primary;
+ precedence[TOKslice] = PREC_primary;
+ precedence[TOKarray] = PREC_primary;
+ precedence[TOKindex] = PREC_primary;
+
+ precedence[TOKdelegate] = PREC_unary;
+ precedence[TOKaddress] = PREC_unary;
+ precedence[TOKstar] = PREC_unary;
+ precedence[TOKneg] = PREC_unary;
+ precedence[TOKuadd] = PREC_unary;
+ precedence[TOKnot] = PREC_unary;
+ precedence[TOKtilde] = PREC_unary;
+ precedence[TOKdelete] = PREC_unary;
+ precedence[TOKnew] = PREC_unary;
+ precedence[TOKnewanonclass] = PREC_unary;
+ precedence[TOKcast] = PREC_unary;
+
+ precedence[TOKvector] = PREC_unary;
+ precedence[TOKpow] = PREC_pow;
+
+ precedence[TOKmul] = PREC_mul;
+ precedence[TOKdiv] = PREC_mul;
+ precedence[TOKmod] = PREC_mul;
+
+ precedence[TOKadd] = PREC_add;
+ precedence[TOKmin] = PREC_add;
+ precedence[TOKcat] = PREC_add;
+
+ precedence[TOKshl] = PREC_shift;
+ precedence[TOKshr] = PREC_shift;
+ precedence[TOKushr] = PREC_shift;
+
+ precedence[TOKlt] = PREC_rel;
+ precedence[TOKle] = PREC_rel;
+ precedence[TOKgt] = PREC_rel;
+ precedence[TOKge] = PREC_rel;
+ precedence[TOKunord] = PREC_rel;
+ precedence[TOKlg] = PREC_rel;
+ precedence[TOKleg] = PREC_rel;
+ precedence[TOKule] = PREC_rel;
+ precedence[TOKul] = PREC_rel;
+ precedence[TOKuge] = PREC_rel;
+ precedence[TOKug] = PREC_rel;
+ precedence[TOKue] = PREC_rel;
+ precedence[TOKin] = PREC_rel;
+
+ /* Note that we changed precedence, so that < and != have the same
+ * precedence. This change is in the parser, too.
+ */
+ precedence[TOKequal] = PREC_rel;
+ precedence[TOKnotequal] = PREC_rel;
+ precedence[TOKidentity] = PREC_rel;
+ precedence[TOKnotidentity] = PREC_rel;
+
+ precedence[TOKand] = PREC_and;
+
+ precedence[TOKxor] = PREC_xor;
+
+ precedence[TOKor] = PREC_or;
+
+ precedence[TOKandand] = PREC_andand;
+
+ precedence[TOKoror] = PREC_oror;
+
+ precedence[TOKquestion] = PREC_cond;
+
+ precedence[TOKassign] = PREC_assign;
+ precedence[TOKconstruct] = PREC_assign;
+ precedence[TOKblit] = PREC_assign;
+ precedence[TOKaddass] = PREC_assign;
+ precedence[TOKminass] = PREC_assign;
+ precedence[TOKcatass] = PREC_assign;
+ precedence[TOKmulass] = PREC_assign;
+ precedence[TOKdivass] = PREC_assign;
+ precedence[TOKmodass] = PREC_assign;
+ precedence[TOKpowass] = PREC_assign;
+ precedence[TOKshlass] = PREC_assign;
+ precedence[TOKshrass] = PREC_assign;
+ precedence[TOKushrass] = PREC_assign;
+ precedence[TOKandass] = PREC_assign;
+ precedence[TOKorass] = PREC_assign;
+ precedence[TOKxorass] = PREC_assign;
+
+ precedence[TOKcomma] = PREC_expr;
+ precedence[TOKdeclaration] = PREC_expr;
+
+ precedence[TOKinterval] = PREC_assign;
+}
diff --git a/gcc/d/dmd/parse.h b/gcc/d/dmd/parse.h
new file mode 100644
index 0000000..5038106
--- /dev/null
+++ b/gcc/d/dmd/parse.h
@@ -0,0 +1,188 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.h
+ */
+
+#pragma once
+
+#include "arraytypes.h"
+#include "lexer.h"
+#include "enum.h"
+
+class Type;
+class TypeQualified;
+class Expression;
+class Declaration;
+class Statement;
+class Import;
+class Initializer;
+class FuncDeclaration;
+class CtorDeclaration;
+class PostBlitDeclaration;
+class DtorDeclaration;
+class StaticCtorDeclaration;
+class StaticDtorDeclaration;
+class SharedStaticCtorDeclaration;
+class SharedStaticDtorDeclaration;
+class ConditionalDeclaration;
+class InvariantDeclaration;
+class UnitTestDeclaration;
+class NewDeclaration;
+class DeleteDeclaration;
+class Condition;
+class Module;
+struct ModuleDeclaration;
+class TemplateDeclaration;
+class TemplateInstance;
+class StaticAssert;
+struct PrefixAttributes;
+
+/************************************
+ * These control how parseStatement() works.
+ */
+
+enum ParseStatementFlags
+{
+ PSsemi = 1, // empty ';' statements are allowed, but deprecated
+ PSscope = 2, // start a new scope
+ PScurly = 4, // { } statement is required
+ PScurlyscope = 8, // { } starts a new scope
+ PSsemi_ok = 0x10, // empty ';' are really ok
+};
+
+
+class Parser : public Lexer
+{
+public:
+ Module *mod;
+ ModuleDeclaration *md;
+ LINK linkage;
+ CPPMANGLE cppmangle;
+ Loc endloc; // set to location of last right curly
+ int inBrackets; // inside [] of array index or slice
+ Loc lookingForElse; // location of lonely if looking for an else
+
+ Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment);
+ Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment);
+
+ Dsymbols *parseModule();
+ Dsymbols *parseDeclDefs(int once, Dsymbol **pLastDecl = NULL, PrefixAttributes *pAttrs = NULL);
+ Dsymbols *parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment);
+ Dsymbols *parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs = NULL);
+ StorageClass appendStorageClass(StorageClass storageClass, StorageClass stc, bool deprec = false);
+ StorageClass parseAttribute(Expressions **pexps);
+ StorageClass parsePostfix(StorageClass storageClass, Expressions **pudas);
+ StorageClass parseTypeCtor();
+ Expression *parseConstraint();
+ TemplateDeclaration *parseTemplateDeclaration(bool ismixin = false);
+ TemplateParameters *parseTemplateParameterList(int flag = 0);
+ Dsymbol *parseMixin();
+ Objects *parseTemplateArguments();
+ Objects *parseTemplateArgumentList();
+ Objects *parseTemplateSingleArgument();
+ StaticAssert *parseStaticAssert();
+ TypeQualified *parseTypeof();
+ Type *parseVector();
+ LINK parseLinkage(Identifiers **, CPPMANGLE *);
+ Identifiers *parseQualifiedIdentifier(const char *entity);
+ Condition *parseDebugCondition();
+ Condition *parseVersionCondition();
+ Condition *parseStaticIfCondition();
+ Dsymbol *parseCtor(PrefixAttributes *pAttrs);
+ Dsymbol *parseDtor(PrefixAttributes *pAttrs);
+ Dsymbol *parseStaticCtor(PrefixAttributes *pAttrs);
+ Dsymbol *parseStaticDtor(PrefixAttributes *pAttrs);
+ Dsymbol *parseSharedStaticCtor(PrefixAttributes *pAttrs);
+ Dsymbol *parseSharedStaticDtor(PrefixAttributes *pAttrs);
+ Dsymbol *parseInvariant(PrefixAttributes *pAttrs);
+ Dsymbol *parseUnitTest(PrefixAttributes *pAttrs);
+ Dsymbol *parseNew(PrefixAttributes *pAttrs);
+ Dsymbol *parseDelete(PrefixAttributes *pAttrs);
+ Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL);
+ EnumDeclaration *parseEnum();
+ Dsymbol *parseAggregate();
+ BaseClasses *parseBaseClasses();
+ Dsymbols *parseImport();
+ Type *parseType(Identifier **pident = NULL, TemplateParameters **ptpl = NULL);
+ Type *parseBasicType(bool dontLookDotIdents = false);
+ Type *parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents);
+ Type *parseBasicType2(Type *t);
+ Type *parseDeclarator(Type *t, int *alt, Identifier **pident,
+ TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int *pdisable = NULL, Expressions **pudas = NULL);
+ void parseStorageClasses(StorageClass &storage_class, LINK &link, bool &setAlignment, Expression *&ealign, Expressions *&udas);
+ Dsymbols *parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment);
+ Dsymbol *parseFunctionLiteral();
+ FuncDeclaration *parseContracts(FuncDeclaration *f);
+ void checkDanglingElse(Loc elseloc);
+ void checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident);
+ /** endPtr used for documented unittests */
+ Statement *parseStatement(int flags, const utf8_t** endPtr = NULL, Loc *pEndloc = NULL);
+ Initializer *parseInitializer();
+ Expression *parseDefaultInitExp();
+ void check(Loc loc, TOK value);
+ void check(TOK value);
+ void check(TOK value, const char *string);
+ void checkParens(TOK value, Expression *e);
+ bool isDeclaration(Token *t, int needId, TOK endtok, Token **pt);
+ bool isBasicType(Token **pt);
+ bool isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax = true);
+ bool isParameters(Token **pt);
+ bool isExpression(Token **pt);
+ bool skipParens(Token *t, Token **pt);
+ bool skipParensIf(Token *t, Token **pt);
+ bool skipAttributes(Token *t, Token **pt);
+
+ Expression *parseExpression();
+ Expression *parsePrimaryExp();
+ Expression *parseUnaryExp();
+ Expression *parsePostExp(Expression *e);
+ Expression *parseMulExp();
+ Expression *parseAddExp();
+ Expression *parseShiftExp();
+ Expression *parseCmpExp();
+ Expression *parseAndExp();
+ Expression *parseXorExp();
+ Expression *parseOrExp();
+ Expression *parseAndAndExp();
+ Expression *parseOrOrExp();
+ Expression *parseCondExp();
+ Expression *parseAssignExp();
+
+ Expressions *parseArguments();
+
+ Expression *parseNewExp(Expression *thisexp);
+
+ void addComment(Dsymbol *s, const utf8_t *blockComment);
+};
+
+// Operator precedence - greater values are higher precedence
+
+enum PREC
+{
+ PREC_zero,
+ PREC_expr,
+ PREC_assign,
+ PREC_cond,
+ PREC_oror,
+ PREC_andand,
+ PREC_or,
+ PREC_xor,
+ PREC_and,
+ PREC_equal,
+ PREC_rel,
+ PREC_shift,
+ PREC_add,
+ PREC_mul,
+ PREC_pow,
+ PREC_unary,
+ PREC_primary,
+};
+
+extern PREC precedence[TOKMAX];
+
+void initPrecedence();
diff --git a/gcc/d/dmd/readme.txt b/gcc/d/dmd/readme.txt
new file mode 100644
index 0000000..a9a31af
--- /dev/null
+++ b/gcc/d/dmd/readme.txt
@@ -0,0 +1,13 @@
+This is the source code to the DMD compiler
+for the D Programming Language defined in the documents at
+http://dlang.org/
+
+These sources are free, they are redistributable and modifiable
+under the terms of the Boost Software License, Version 1.0.
+The terms of this license are in the file boostlicense.txt,
+or see http://www.boost.org/LICENSE_1_0.txt.
+
+If a particular file has a different license in it, that overrides
+this license for that file.
+
+-Walter Bright
diff --git a/gcc/d/dmd/root/aav.c b/gcc/d/dmd/root/aav.c
new file mode 100644
index 0000000..4c015bf
--- /dev/null
+++ b/gcc/d/dmd/root/aav.c
@@ -0,0 +1,175 @@
+
+/* Copyright (C) 2010-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/aav.c
+ */
+
+/**
+ * Implementation of associative arrays.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "aav.h"
+#include "rmem.h"
+
+
+inline size_t hash(size_t a)
+{
+ a ^= (a >> 20) ^ (a >> 12);
+ return a ^ (a >> 7) ^ (a >> 4);
+}
+
+struct aaA
+{
+ aaA *next;
+ Key key;
+ Value value;
+};
+
+struct AA
+{
+ aaA* *b;
+ size_t b_length;
+ size_t nodes; // total number of aaA nodes
+ aaA* binit[4]; // initial value of b[]
+
+ aaA aafirst; // a lot of these AA's have only one entry
+};
+
+/****************************************************
+ * Determine number of entries in associative array.
+ */
+
+size_t dmd_aaLen(AA* aa)
+{
+ return aa ? aa->nodes : 0;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Add entry for key if it is not already there, returning a pointer to a null Value.
+ * Create the associative array if it does not already exist.
+ */
+
+Value* dmd_aaGet(AA** paa, Key key)
+{
+ //printf("paa = %p\n", paa);
+
+ if (!*paa)
+ { AA *a = (AA *)mem.xmalloc(sizeof(AA));
+ a->b = (aaA**)a->binit;
+ a->b_length = 4;
+ a->nodes = 0;
+ a->binit[0] = NULL;
+ a->binit[1] = NULL;
+ a->binit[2] = NULL;
+ a->binit[3] = NULL;
+ *paa = a;
+ assert((*paa)->b_length == 4);
+ }
+ //printf("paa = %p, *paa = %p\n", paa, *paa);
+
+ assert((*paa)->b_length);
+ size_t i = hash((size_t)key) & ((*paa)->b_length - 1);
+ aaA** pe = &(*paa)->b[i];
+ aaA *e;
+ while ((e = *pe) != NULL)
+ {
+ if (key == e->key)
+ return &e->value;
+ pe = &e->next;
+ }
+
+ // Not found, create new elem
+ //printf("create new one\n");
+
+ size_t nodes = ++(*paa)->nodes;
+ e = (nodes != 1) ? (aaA *)mem.xmalloc(sizeof(aaA)) : &(*paa)->aafirst;
+ //e = new aaA();
+ e->next = NULL;
+ e->key = key;
+ e->value = NULL;
+ *pe = e;
+
+ //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes);
+ if (nodes > (*paa)->b_length * 2)
+ {
+ //printf("rehash\n");
+ dmd_aaRehash(paa);
+ }
+
+ return &e->value;
+}
+
+
+/*************************************************
+ * Get value in associative array indexed by key.
+ * Returns NULL if it is not already there.
+ */
+
+Value dmd_aaGetRvalue(AA* aa, Key key)
+{
+ //printf("_aaGetRvalue(key = %p)\n", key);
+ if (aa)
+ {
+ size_t i;
+ size_t len = aa->b_length;
+ i = hash((size_t)key) & (len-1);
+ aaA* e = aa->b[i];
+ while (e)
+ {
+ if (key == e->key)
+ return e->value;
+ e = e->next;
+ }
+ }
+ return NULL; // not found
+}
+
+
+/********************************************
+ * Rehash an array.
+ */
+
+void dmd_aaRehash(AA** paa)
+{
+ //printf("Rehash\n");
+ if (*paa)
+ {
+ AA *aa = *paa;
+ if (aa)
+ {
+ size_t len = aa->b_length;
+ if (len == 4)
+ len = 32;
+ else
+ len *= 4;
+ aaA** newb = (aaA**)mem.xmalloc(sizeof(aaA)*len);
+ memset(newb, 0, len * sizeof(aaA*));
+
+ for (size_t k = 0; k < aa->b_length; k++)
+ { aaA *e = aa->b[k];
+ while (e)
+ { aaA* enext = e->next;
+ size_t j = hash((size_t)e->key) & (len-1);
+ e->next = newb[j];
+ newb[j] = e;
+ e = enext;
+ }
+ }
+ if (aa->b != (aaA**)aa->binit)
+ mem.xfree(aa->b);
+
+ aa->b = newb;
+ aa->b_length = len;
+ }
+ }
+}
diff --git a/gcc/d/dmd/root/aav.h b/gcc/d/dmd/root/aav.h
new file mode 100644
index 0000000..24c281a
--- /dev/null
+++ b/gcc/d/dmd/root/aav.h
@@ -0,0 +1,20 @@
+
+/* Copyright (C) 2010-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/aav.h
+ */
+
+#pragma once
+
+typedef void* Value;
+typedef void* Key;
+
+struct AA;
+
+size_t dmd_aaLen(AA* aa);
+Value* dmd_aaGet(AA** aa, Key key);
+Value dmd_aaGetRvalue(AA* aa, Key key);
+void dmd_aaRehash(AA** paa);
+
diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h
new file mode 100644
index 0000000..ed128b9
--- /dev/null
+++ b/gcc/d/dmd/root/array.h
@@ -0,0 +1,232 @@
+/* Copyright (C) 2011-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/array.h
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "object.h"
+#include "rmem.h"
+
+template <typename TYPE>
+struct Array
+{
+ d_size_t dim;
+ TYPE *data;
+
+ private:
+ Array(const Array&);
+
+ d_size_t allocdim;
+ #define SMALLARRAYCAP 1
+ TYPE smallarray[SMALLARRAYCAP]; // inline storage for small arrays
+
+ public:
+ Array()
+ {
+ data = SMALLARRAYCAP ? &smallarray[0] : NULL;
+ dim = 0;
+ allocdim = SMALLARRAYCAP;
+ }
+
+ ~Array()
+ {
+ if (data != &smallarray[0])
+ mem.xfree(data);
+ }
+
+ char *toChars()
+ {
+ const char **buf = (const char **)mem.xmalloc(dim * sizeof(const char *));
+ d_size_t len = 2;
+ for (d_size_t u = 0; u < dim; u++)
+ {
+ buf[u] = ((RootObject *)data[u])->toChars();
+ len += strlen(buf[u]) + 1;
+ }
+ char *str = (char *)mem.xmalloc(len);
+
+ str[0] = '[';
+ char *p = str + 1;
+ for (d_size_t u = 0; u < dim; u++)
+ {
+ if (u)
+ *p++ = ',';
+ len = strlen(buf[u]);
+ memcpy(p,buf[u],len);
+ p += len;
+ }
+ *p++ = ']';
+ *p = 0;
+ mem.xfree(buf);
+ return str;
+ }
+
+ void reserve(d_size_t nentries)
+ {
+ //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", (int)dim, (int)allocdim, (int)nentries);
+ if (allocdim - dim < nentries)
+ {
+ if (allocdim == 0)
+ { // Not properly initialized, someone memset it to zero
+ if (nentries <= SMALLARRAYCAP)
+ { allocdim = SMALLARRAYCAP;
+ data = SMALLARRAYCAP ? &smallarray[0] : NULL;
+ }
+ else
+ { allocdim = nentries;
+ data = (TYPE *)mem.xmalloc(allocdim * sizeof(*data));
+ }
+ }
+ else if (allocdim == SMALLARRAYCAP)
+ {
+ allocdim = dim + nentries;
+ data = (TYPE *)mem.xmalloc(allocdim * sizeof(*data));
+ memcpy(data, &smallarray[0], dim * sizeof(*data));
+ }
+ else
+ {
+ /* Increase size by 1.5x to avoid excessive memory fragmentation
+ */
+ d_size_t increment = dim / 2;
+ if (nentries > increment) // if 1.5 is not enough
+ increment = nentries;
+ allocdim = dim + increment;
+ data = (TYPE *)mem.xrealloc(data, allocdim * sizeof(*data));
+ }
+ }
+ }
+
+ void setDim(d_size_t newdim)
+ {
+ if (dim < newdim)
+ {
+ reserve(newdim - dim);
+ }
+ dim = newdim;
+ }
+
+ TYPE pop()
+ {
+ return data[--dim];
+ }
+
+ void shift(TYPE ptr)
+ {
+ reserve(1);
+ memmove(data + 1, data, dim * sizeof(*data));
+ data[0] = ptr;
+ dim++;
+ }
+
+ void remove(d_size_t i)
+ {
+ if (dim - i - 1)
+ memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0]));
+ dim--;
+ }
+
+ void zero()
+ {
+ memset(data,0,dim * sizeof(data[0]));
+ }
+
+ void sort()
+ {
+ struct ArraySort
+ {
+ static int
+ #if _WIN32
+ __cdecl
+ #endif
+ Array_sort_compare(const void *x, const void *y)
+ {
+ RootObject *ox = *(RootObject **)const_cast<void *>(x);
+ RootObject *oy = *(RootObject **)const_cast<void *>(y);
+
+ return ox->compare(oy);
+ }
+ };
+
+ if (dim)
+ {
+ qsort(data, dim, sizeof(RootObject *), &ArraySort::Array_sort_compare);
+ }
+ }
+
+ TYPE *tdata()
+ {
+ return data;
+ }
+
+ TYPE& operator[] (d_size_t index)
+ {
+ return data[index];
+ }
+
+ void insert(d_size_t index, TYPE v)
+ {
+ reserve(1);
+ memmove(data + index + 1, data + index, (dim - index) * sizeof(*data));
+ data[index] = v;
+ dim++;
+ }
+
+ void insert(d_size_t index, Array *a)
+ {
+ if (a)
+ {
+ d_size_t 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;
+ }
+ }
+
+ void append(Array *a)
+ {
+ insert(dim, a);
+ }
+
+ void push(TYPE a)
+ {
+ reserve(1);
+ data[dim++] = a;
+ }
+
+ Array *copy()
+ {
+ Array *a = new Array();
+ a->setDim(dim);
+ memcpy(a->data, data, dim * sizeof(*data));
+ return a;
+ }
+};
+
+struct BitArray
+{
+ BitArray()
+ : len(0)
+ , ptr(NULL)
+ {}
+
+ ~BitArray()
+ {
+ mem.xfree(ptr);
+ }
+
+ d_size_t len;
+ d_size_t *ptr;
+
+private:
+ BitArray(const BitArray&);
+};
diff --git a/gcc/d/dmd/root/ctfloat.h b/gcc/d/dmd/root/ctfloat.h
new file mode 100644
index 0000000..888ae53
--- /dev/null
+++ b/gcc/d/dmd/root/ctfloat.h
@@ -0,0 +1,47 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.h
+ */
+
+#pragma once
+
+#include "longdouble.h"
+
+// Type used by the front-end for compile-time reals
+typedef longdouble real_t;
+
+// Compile-time floating-point helper
+struct CTFloat
+{
+ static bool yl2x_supported;
+ static bool yl2xp1_supported;
+
+ static void yl2x(const real_t *x, const real_t *y, real_t *res);
+ static void yl2xp1(const real_t *x, const real_t *y, real_t *res);
+
+ static real_t sin(real_t x);
+ static real_t cos(real_t x);
+ static real_t tan(real_t x);
+ static real_t sqrt(real_t x);
+ static real_t fabs(real_t x);
+ static real_t ldexp(real_t n, int exp);
+
+ static bool isIdentical(real_t a, real_t b);
+ static bool isNaN(real_t r);
+ static bool isSNaN(real_t r);
+ static bool isInfinity(real_t r);
+
+ static real_t parse(const char *literal, bool *isOutOfRange = NULL);
+ static int sprint(char *str, char fmt, real_t x);
+
+ static size_t hash(real_t a);
+
+ // Constant real values 0, 1, -1 and 0.5.
+ static real_t zero;
+ static real_t one;
+ static real_t minusone;
+ static real_t half;
+};
diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h
new file mode 100644
index 0000000..3fc169c
--- /dev/null
+++ b/gcc/d/dmd/root/dcompat.h
@@ -0,0 +1,18 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/dcompat.h
+ */
+
+#pragma once
+
+/// Represents a D [ ] array
+template<typename T>
+struct DArray
+{
+ size_t length;
+ T *ptr;
+};
diff --git a/gcc/d/dmd/root/file.c b/gcc/d/dmd/root/file.c
new file mode 100644
index 0000000..f4fd51a
--- /dev/null
+++ b/gcc/d/dmd/root/file.c
@@ -0,0 +1,265 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/file.c
+ */
+
+#include "file.h"
+
+#if defined (__sun)
+#include <alloca.h>
+#endif
+
+#if _MSC_VER ||__MINGW32__
+#include <malloc.h>
+#include <string>
+#endif
+
+#if _WIN32
+#include <windows.h>
+#include <direct.h>
+#include <errno.h>
+#endif
+
+#if POSIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+#include "filename.h"
+#include "array.h"
+#include "rmem.h"
+
+/****************************** File ********************************/
+
+File::File(const FileName *n)
+{
+ ref = 0;
+ buffer = NULL;
+ len = 0;
+ name = const_cast<FileName *>(n);
+}
+
+File *File::create(const char *n)
+{
+ return new File(n);
+}
+
+File::File(const char *n)
+{
+ ref = 0;
+ buffer = NULL;
+ len = 0;
+ name = new FileName(n);
+}
+
+File::~File()
+{
+ if (buffer)
+ {
+ if (ref == 0)
+ mem.xfree(buffer);
+#if _WIN32
+ if (ref == 2)
+ UnmapViewOfFile(buffer);
+#endif
+ }
+}
+
+/*************************************
+ */
+
+bool File::read()
+{
+ if (len)
+ return false; // already read the file
+#if POSIX
+ size_t size;
+ struct stat buf;
+ ssize_t numread;
+
+ const char *name = this->name->toChars();
+ //printf("File::read('%s')\n",name);
+ int fd = open(name, O_RDONLY);
+ if (fd == -1)
+ {
+ //printf("\topen error, errno = %d\n",errno);
+ goto err1;
+ }
+
+ if (!ref)
+ ::free(buffer);
+ ref = 0; // we own the buffer now
+
+ //printf("\tfile opened\n");
+ if (fstat(fd, &buf))
+ {
+ printf("\tfstat error, errno = %d\n",errno);
+ goto err2;
+ }
+ size = (size_t)buf.st_size;
+ buffer = (unsigned char *) ::malloc(size + 2);
+ if (!buffer)
+ {
+ printf("\tmalloc error, errno = %d\n",errno);
+ goto err2;
+ }
+
+ numread = ::read(fd, buffer, size);
+ if (numread != (ssize_t)size)
+ {
+ printf("\tread error, errno = %d\n",errno);
+ goto err2;
+ }
+
+ if (close(fd) == -1)
+ {
+ printf("\tclose error, errno = %d\n",errno);
+ goto err;
+ }
+
+ len = size;
+
+ // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+ buffer[size] = 0; // ^Z is obsolete, use 0
+ buffer[size + 1] = 0;
+ return false;
+
+err2:
+ close(fd);
+err:
+ ::free(buffer);
+ buffer = NULL;
+ len = 0;
+
+err1:
+ return true;
+#elif _WIN32
+ DWORD size;
+ DWORD numread;
+
+ const char *name = this->name->toChars();
+ HANDLE h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ goto err1;
+
+ if (!ref)
+ ::free(buffer);
+ ref = 0;
+
+ size = GetFileSize(h,NULL);
+ buffer = (unsigned char *) ::malloc(size + 2);
+ if (!buffer)
+ goto err2;
+
+ if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
+ goto err2;
+
+ if (numread != size)
+ goto err2;
+
+ if (!CloseHandle(h))
+ goto err;
+
+ len = size;
+
+ // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+ buffer[size] = 0; // ^Z is obsolete, use 0
+ buffer[size + 1] = 0;
+ return 0;
+
+err2:
+ CloseHandle(h);
+err:
+ ::free(buffer);
+ buffer = NULL;
+ len = 0;
+
+err1:
+ return true;
+#else
+ assert(0);
+#endif
+}
+
+/*********************************************
+ * Write a file.
+ * Returns:
+ * false success
+ */
+
+bool File::write()
+{
+#if POSIX
+ ssize_t numwritten;
+
+ const char *name = this->name->toChars();
+ int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
+ if (fd == -1)
+ goto err;
+
+ numwritten = ::write(fd, buffer, len);
+ if ((ssize_t)len != numwritten)
+ goto err2;
+
+ if (close(fd) == -1)
+ goto err;
+
+ return false;
+
+err2:
+ close(fd);
+ ::remove(name);
+err:
+ return true;
+#elif _WIN32
+ DWORD numwritten;
+
+ const char *name = this->name->toChars();
+ HANDLE h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ goto err;
+
+ if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
+ goto err2;
+
+ if (len != numwritten)
+ goto err2;
+
+ if (!CloseHandle(h))
+ goto err;
+ return false;
+
+err2:
+ CloseHandle(h);
+ DeleteFileA(name);
+err:
+ return true;
+#else
+ assert(0);
+#endif
+}
+
+void File::remove()
+{
+#if POSIX
+ ::remove(this->name->toChars());
+#elif _WIN32
+ DeleteFileA(this->name->toChars());
+#else
+ assert(0);
+#endif
+}
+
+const char *File::toChars()
+{
+ return name->toChars();
+}
diff --git a/gcc/d/dmd/root/file.h b/gcc/d/dmd/root/file.h
new file mode 100644
index 0000000..f6953ab
--- /dev/null
+++ b/gcc/d/dmd/root/file.h
@@ -0,0 +1,54 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/file.h
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+#include "array.h"
+
+typedef Array<struct File *> Files;
+
+struct FileName;
+
+struct File
+{
+ int ref; // != 0 if this is a reference to someone else's buffer
+ unsigned char *buffer; // data for our file
+ size_t len; // amount of data in buffer[]
+
+ FileName *name; // name of our file
+
+ File(const char *);
+ static File *create(const char *);
+ File(const FileName *);
+ ~File();
+
+ const char *toChars();
+
+ /* Read file, return true if error
+ */
+
+ bool read();
+
+ /* Write file, return true if error
+ */
+
+ bool write();
+
+ /* Set buffer
+ */
+
+ void setbuffer(void *buffer, size_t len)
+ {
+ this->buffer = (unsigned char *)buffer;
+ this->len = len;
+ }
+
+ void remove(); // delete file
+};
diff --git a/gcc/d/dmd/root/filename.c b/gcc/d/dmd/root/filename.c
new file mode 100644
index 0000000..307e94f
--- /dev/null
+++ b/gcc/d/dmd/root/filename.c
@@ -0,0 +1,673 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/filename.c
+ */
+
+#include "filename.h"
+
+#include <stdint.h>
+#include <ctype.h>
+
+#include "outbuffer.h"
+#include "array.h"
+#include "file.h"
+#include "rmem.h"
+
+#if defined (__sun)
+#include <alloca.h>
+#endif
+
+#if _MSC_VER ||__MINGW32__
+#include <malloc.h>
+#include <string>
+#endif
+
+#if _WIN32
+#include <windows.h>
+#include <direct.h>
+#include <errno.h>
+#endif
+
+#if POSIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <utime.h>
+#endif
+
+/****************************** FileName ********************************/
+
+FileName::FileName(const char *str)
+ : str(mem.xstrdup(str))
+{
+}
+
+const char *FileName::combine(const char *path, const char *name)
+{ char *f;
+ size_t pathlen;
+ size_t namelen;
+
+ if (!path || !*path)
+ return name;
+ pathlen = strlen(path);
+ namelen = strlen(name);
+ f = (char *)mem.xmalloc(pathlen + 1 + namelen + 1);
+ memcpy(f, path, pathlen);
+#if POSIX
+ if (path[pathlen - 1] != '/')
+ { f[pathlen] = '/';
+ pathlen++;
+ }
+#elif _WIN32
+ if (path[pathlen - 1] != '\\' &&
+ path[pathlen - 1] != '/' &&
+ path[pathlen - 1] != ':')
+ { f[pathlen] = '\\';
+ pathlen++;
+ }
+#else
+ assert(0);
+#endif
+ memcpy(f + pathlen, name, namelen + 1);
+ return f;
+}
+
+// Split a path into an Array of paths
+Strings *FileName::splitPath(const char *path)
+{
+ char c = 0; // unnecessary initializer is for VC /W4
+ const char *p;
+ OutBuffer buf;
+ Strings *array;
+
+ array = new Strings();
+ if (path)
+ {
+ p = path;
+ do
+ { char instring = 0;
+
+ while (isspace((utf8_t)*p)) // skip leading whitespace
+ p++;
+ buf.reserve(strlen(p) + 1); // guess size of path
+ for (; ; p++)
+ {
+ c = *p;
+ switch (c)
+ {
+ case '"':
+ instring ^= 1; // toggle inside/outside of string
+ continue;
+
+#if MACINTOSH
+ case ',':
+#endif
+#if _WIN32
+ case ';':
+#endif
+#if POSIX
+ case ':':
+#endif
+ p++;
+ break; // note that ; cannot appear as part
+ // of a path, quotes won't protect it
+
+ case 0x1A: // ^Z means end of file
+ case 0:
+ break;
+
+ case '\r':
+ continue; // ignore carriage returns
+
+#if POSIX
+ case '~':
+ {
+ char *home = getenv("HOME");
+ if (home)
+ buf.writestring(home);
+ else
+ buf.writestring("~");
+ continue;
+ }
+#endif
+
+ default:
+ buf.writeByte(c);
+ continue;
+ }
+ break;
+ }
+ if (buf.offset) // if path is not empty
+ {
+ array->push(buf.extractString());
+ }
+ } while (c);
+ }
+ return array;
+}
+
+int FileName::compare(RootObject *obj)
+{
+ return compare(str, ((FileName *)obj)->str);
+}
+
+int FileName::compare(const char *name1, const char *name2)
+{
+#if _WIN32
+ return stricmp(name1, name2);
+#else
+ return strcmp(name1, name2);
+#endif
+}
+
+bool FileName::equals(RootObject *obj)
+{
+ return compare(obj) == 0;
+}
+
+bool FileName::equals(const char *name1, const char *name2)
+{
+ return compare(name1, name2) == 0;
+}
+
+/************************************
+ * Return !=0 if absolute path name.
+ */
+
+bool FileName::absolute(const char *name)
+{
+#if _WIN32
+ return (*name == '\\') ||
+ (*name == '/') ||
+ (*name && name[1] == ':');
+#elif POSIX
+ return (*name == '/');
+#else
+ assert(0);
+#endif
+}
+
+/********************************
+ * Return filename extension (read-only).
+ * Points past '.' of extension.
+ * If there isn't one, return NULL.
+ */
+
+const char *FileName::ext(const char *str)
+{
+ size_t len = strlen(str);
+
+ const char *e = str + len;
+ for (;;)
+ {
+ switch (*e)
+ { case '.':
+ return e + 1;
+#if POSIX
+ case '/':
+ break;
+#endif
+#if _WIN32
+ case '\\':
+ case ':':
+ case '/':
+ break;
+#endif
+ default:
+ if (e == str)
+ break;
+ e--;
+ continue;
+ }
+ return NULL;
+ }
+}
+
+const char *FileName::ext()
+{
+ return ext(str);
+}
+
+/********************************
+ * Return mem.xmalloc'd filename with extension removed.
+ */
+
+const char *FileName::removeExt(const char *str)
+{
+ const char *e = ext(str);
+ if (e)
+ { size_t len = (e - str) - 1;
+ char *n = (char *)mem.xmalloc(len + 1);
+ memcpy(n, str, len);
+ n[len] = 0;
+ return n;
+ }
+ return mem.xstrdup(str);
+}
+
+/********************************
+ * Return filename name excluding path (read-only).
+ */
+
+const char *FileName::name(const char *str)
+{
+ size_t len = strlen(str);
+
+ const char *e = str + len;
+ for (;;)
+ {
+ switch (*e)
+ {
+#if POSIX
+ case '/':
+ return e + 1;
+#endif
+#if _WIN32
+ case '/':
+ case '\\':
+ return e + 1;
+ case ':':
+ /* The ':' is a drive letter only if it is the second
+ * character or the last character,
+ * otherwise it is an ADS (Alternate Data Stream) separator.
+ * Consider ADS separators as part of the file name.
+ */
+ if (e == str + 1 || e == str + len - 1)
+ return e + 1;
+#endif
+ default:
+ if (e == str)
+ break;
+ e--;
+ continue;
+ }
+ return e;
+ }
+}
+
+const char *FileName::name()
+{
+ return name(str);
+}
+
+/**************************************
+ * Return path portion of str.
+ * Path will does not include trailing path separator.
+ */
+
+const char *FileName::path(const char *str)
+{
+ const char *n = name(str);
+ size_t pathlen;
+
+ if (n > str)
+ {
+#if POSIX
+ if (n[-1] == '/')
+ n--;
+#elif _WIN32
+ if (n[-1] == '\\' || n[-1] == '/')
+ n--;
+#else
+ assert(0);
+#endif
+ }
+ pathlen = n - str;
+ char *path = (char *)mem.xmalloc(pathlen + 1);
+ memcpy(path, str, pathlen);
+ path[pathlen] = 0;
+ return path;
+}
+
+/**************************************
+ * Replace filename portion of path.
+ */
+
+const char *FileName::replaceName(const char *path, const char *name)
+{
+ size_t pathlen;
+ size_t namelen;
+
+ if (absolute(name))
+ return name;
+
+ const char *n = FileName::name(path);
+ if (n == path)
+ return name;
+ pathlen = n - path;
+ namelen = strlen(name);
+ char *f = (char *)mem.xmalloc(pathlen + 1 + namelen + 1);
+ memcpy(f, path, pathlen);
+#if POSIX
+ if (path[pathlen - 1] != '/')
+ { f[pathlen] = '/';
+ pathlen++;
+ }
+#elif _WIN32
+ if (path[pathlen - 1] != '\\' &&
+ path[pathlen - 1] != '/' &&
+ path[pathlen - 1] != ':')
+ { f[pathlen] = '\\';
+ pathlen++;
+ }
+#else
+ assert(0);
+#endif
+ memcpy(f + pathlen, name, namelen + 1);
+ return f;
+}
+
+/***************************
+ * Free returned value with FileName::free()
+ */
+
+const char *FileName::defaultExt(const char *name, const char *ext)
+{
+ const char *e = FileName::ext(name);
+ if (e) // if already has an extension
+ return mem.xstrdup(name);
+
+ size_t len = strlen(name);
+ size_t extlen = strlen(ext);
+ char *s = (char *)mem.xmalloc(len + 1 + extlen + 1);
+ memcpy(s,name,len);
+ s[len] = '.';
+ memcpy(s + len + 1, ext, extlen + 1);
+ return s;
+}
+
+/***************************
+ * Free returned value with FileName::free()
+ */
+
+const char *FileName::forceExt(const char *name, const char *ext)
+{
+ const char *e = FileName::ext(name);
+ if (e) // if already has an extension
+ {
+ size_t len = e - name;
+ size_t extlen = strlen(ext);
+
+ char *s = (char *)mem.xmalloc(len + extlen + 1);
+ memcpy(s,name,len);
+ memcpy(s + len, ext, extlen + 1);
+ return s;
+ }
+ else
+ return defaultExt(name, ext); // doesn't have one
+}
+
+/******************************
+ * Return !=0 if extensions match.
+ */
+
+bool FileName::equalsExt(const char *ext)
+{
+ return equalsExt(str, ext);
+}
+
+bool FileName::equalsExt(const char *name, const char *ext)
+{
+ const char *e = FileName::ext(name);
+ if (!e && !ext)
+ return true;
+ if (!e || !ext)
+ return false;
+ return FileName::compare(e, ext) == 0;
+}
+
+/*************************************
+ * Search Path for file.
+ * Input:
+ * cwd if true, search current directory before searching path
+ */
+
+const char *FileName::searchPath(Strings *path, const char *name, bool cwd)
+{
+ if (absolute(name))
+ {
+ return exists(name) ? name : NULL;
+ }
+ if (cwd)
+ {
+ if (exists(name))
+ return name;
+ }
+ if (path)
+ {
+
+ for (size_t i = 0; i < path->dim; i++)
+ {
+ const char *p = (*path)[i];
+ const char *n = combine(p, name);
+
+ if (exists(n))
+ return n;
+ }
+ }
+ return NULL;
+}
+
+
+/*************************************
+ * Search Path for file in a safe manner.
+ *
+ * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
+ * ('Path Traversal') attacks.
+ * http://cwe.mitre.org/data/definitions/22.html
+ * More info:
+ * https://www.securecoding.cert.org/confluence/display/c/FIO02-C.+Canonicalize+path+names+originating+from+tainted+sources
+ * Returns:
+ * NULL file not found
+ * !=NULL mem.xmalloc'd file name
+ */
+
+const char *FileName::safeSearchPath(Strings *path, const char *name)
+{
+#if _WIN32
+ // don't allow leading / because it might be an absolute
+ // path or UNC path or something we'd prefer to just not deal with
+ if (*name == '/')
+ {
+ return NULL;
+ }
+ /* Disallow % \ : and .. in name characters
+ * We allow / for compatibility with subdirectories which is allowed
+ * on dmd/posix. With the leading / blocked above and the rest of these
+ * conservative restrictions, we should be OK.
+ */
+ for (const char *p = name; *p; p++)
+ {
+ char c = *p;
+ if (c == '\\' || c == ':' || c == '%' || (c == '.' && p[1] == '.'))
+ {
+ return NULL;
+ }
+ }
+
+ return FileName::searchPath(path, name, false);
+#elif POSIX
+ /* Even with realpath(), we must check for // and disallow it
+ */
+ for (const char *p = name; *p; p++)
+ {
+ char c = *p;
+ if (c == '/' && p[1] == '/')
+ {
+ return NULL;
+ }
+ }
+
+ if (path)
+ {
+ /* Each path is converted to a cannonical name and then a check is done to see
+ * that the searched name is really a child one of the the paths searched.
+ */
+ for (size_t i = 0; i < path->dim; i++)
+ {
+ const char *cname = NULL;
+ const char *cpath = canonicalName((*path)[i]);
+ //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n",
+ // name, (char *)path->data[i], cpath);
+ if (cpath == NULL)
+ goto cont;
+ cname = canonicalName(combine(cpath, name));
+ //printf("FileName::safeSearchPath(): cname=%s\n", cname);
+ if (cname == NULL)
+ goto cont;
+ //printf("FileName::safeSearchPath(): exists=%i "
+ // "strncmp(cpath, cname, %i)=%i\n", exists(cname),
+ // strlen(cpath), strncmp(cpath, cname, strlen(cpath)));
+ // exists and name is *really* a "child" of path
+ if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0)
+ {
+ ::free(const_cast<char *>(cpath));
+ const char *p = mem.xstrdup(cname);
+ ::free(const_cast<char *>(cname));
+ return p;
+ }
+cont:
+ if (cpath)
+ ::free(const_cast<char *>(cpath));
+ if (cname)
+ ::free(const_cast<char *>(cname));
+ }
+ }
+ return NULL;
+#else
+ assert(0);
+#endif
+}
+
+
+int FileName::exists(const char *name)
+{
+#if POSIX
+ struct stat st;
+
+ if (stat(name, &st) < 0)
+ return 0;
+ if (S_ISDIR(st.st_mode))
+ return 2;
+ return 1;
+#elif _WIN32
+ DWORD dw;
+ int result;
+
+ dw = GetFileAttributesA(name);
+ if (dw == -1L)
+ result = 0;
+ else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+ result = 2;
+ else
+ result = 1;
+ return result;
+#else
+ assert(0);
+#endif
+}
+
+bool FileName::ensurePathExists(const char *path)
+{
+ //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
+ if (path && *path)
+ {
+ if (!exists(path))
+ {
+ const char *p = FileName::path(path);
+ if (*p)
+ {
+#if _WIN32
+ size_t len = strlen(path);
+ if ((len > 2 && p[-1] == ':' && strcmp(path + 2, p) == 0) ||
+ len == strlen(p))
+ { mem.xfree(const_cast<void *>(p));
+ return 0;
+ }
+#endif
+ bool r = ensurePathExists(p);
+ mem.xfree(const_cast<char *>(p));
+ if (r)
+ return r;
+ }
+#if _WIN32
+ char sep = '\\';
+#elif POSIX
+ char sep = '/';
+#endif
+ if (path[strlen(path) - 1] != sep)
+ {
+ //printf("mkdir(%s)\n", path);
+#if _WIN32
+ int r = _mkdir(path);
+#endif
+#if POSIX
+ int r = mkdir(path, (7 << 6) | (7 << 3) | 7);
+#endif
+ if (r)
+ {
+ /* Don't error out if another instance of dmd just created
+ * this directory
+ */
+ if (errno != EEXIST)
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/******************************************
+ * Return canonical version of name in a malloc'd buffer.
+ * This code is high risk.
+ */
+const char *FileName::canonicalName(const char *name)
+{
+#if POSIX
+ // NULL destination buffer is allowed and preferred
+ return realpath(name, NULL);
+#elif _WIN32
+ /* Apparently, there is no good way to do this on Windows.
+ * GetFullPathName isn't it, but use it anyway.
+ */
+ DWORD result = GetFullPathNameA(name, 0, NULL, NULL);
+ if (result)
+ {
+ char *buf = (char *)malloc(result);
+ result = GetFullPathNameA(name, result, buf, NULL);
+ if (result == 0)
+ {
+ ::free(buf);
+ return NULL;
+ }
+ return buf;
+ }
+ return NULL;
+#else
+ assert(0);
+ return NULL;
+#endif
+}
+
+/********************************
+ * Free memory allocated by FileName routines
+ */
+void FileName::free(const char *str)
+{
+ if (str)
+ { assert(str[0] != (char)0xAB);
+ memset(const_cast<char *>(str), 0xAB, strlen(str) + 1); // stomp
+ }
+ mem.xfree(const_cast<char *>(str));
+}
+
+const char *FileName::toChars() const
+{
+ return str;
+}
diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h
new file mode 100644
index 0000000..0ef8c21
--- /dev/null
+++ b/gcc/d/dmd/root/filename.h
@@ -0,0 +1,51 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.h
+ */
+
+#pragma once
+
+#include "array.h"
+
+class RootObject;
+
+template <typename TYPE> struct Array;
+typedef Array<const char *> Strings;
+
+struct FileName
+{
+ const char *str;
+ FileName(const char *str);
+ bool equals(RootObject *obj);
+ static bool equals(const char *name1, const char *name2);
+ int compare(RootObject *obj);
+ static int compare(const char *name1, const char *name2);
+ static bool absolute(const char *name);
+ static const char *ext(const char *);
+ const char *ext();
+ static const char *removeExt(const char *str);
+ static const char *name(const char *);
+ const char *name();
+ static const char *path(const char *);
+ static const char *replaceName(const char *path, const char *name);
+
+ static const char *combine(const char *path, const char *name);
+ static Strings *splitPath(const char *path);
+ static const char *defaultExt(const char *name, const char *ext);
+ static const char *forceExt(const char *name, const char *ext);
+ static bool equalsExt(const char *name, const char *ext);
+
+ bool equalsExt(const char *ext);
+
+ static const char *searchPath(Strings *path, const char *name, bool cwd);
+ static const char *safeSearchPath(Strings *path, const char *name);
+ static int exists(const char *name);
+ static bool ensurePathExists(const char *path);
+ static const char *canonicalName(const char *name);
+
+ static void free(const char *str);
+ const char *toChars() const;
+};
diff --git a/gcc/d/dmd/root/hash.h b/gcc/d/dmd/root/hash.h
new file mode 100644
index 0000000..1b05672
--- /dev/null
+++ b/gcc/d/dmd/root/hash.h
@@ -0,0 +1,77 @@
+/**
+ * Compiler implementation of the D programming language
+ * http://dlang.org
+ *
+ * Copyright: Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * Authors: Martin Nowak, Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(DMDSRC root/_hash.h)
+ */
+
+#pragma once
+
+#include <stdint.h> // uint{8|16|32}_t
+#include <stdlib.h>
+
+// MurmurHash2 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+// https://sites.google.com/site/murmurhash/
+static inline uint32_t calcHash(const uint8_t *data, size_t len)
+{
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+
+ uint32_t h = (uint32_t)len;
+
+ // Mix 4 bytes at a time into the hash
+
+ while(len >= 4)
+ {
+ uint32_t k = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+
+ switch(len & 3)
+ {
+ case 3: h ^= data[2] << 16; /* fall through */
+ case 2: h ^= data[1] << 8; /* fall through */
+ case 1: h ^= data[0];
+ h *= m;
+ }
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+static inline uint32_t calcHash(const char *data, size_t len)
+{
+ return calcHash((const uint8_t *)data, len);
+}
+
+// combine and mix two words (boost::hash_combine)
+static inline size_t mixHash(size_t h, size_t k)
+{
+ return h ^ (k + 0x9e3779b9 + (h << 6) + (h >> 2));
+}
diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/root/object.h
new file mode 100644
index 0000000..e9d770d
--- /dev/null
+++ b/gcc/d/dmd/root/object.h
@@ -0,0 +1,60 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/dlang/dmd/blob/master/src/root/object.h
+ */
+
+#define POSIX (__linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun)
+
+#pragma once
+
+#include <stddef.h>
+
+typedef size_t hash_t;
+
+struct OutBuffer;
+
+enum DYNCAST
+{
+ DYNCAST_OBJECT,
+ DYNCAST_EXPRESSION,
+ DYNCAST_DSYMBOL,
+ DYNCAST_TYPE,
+ DYNCAST_IDENTIFIER,
+ DYNCAST_TUPLE,
+ DYNCAST_PARAMETER,
+ DYNCAST_STATEMENT,
+};
+
+/*
+ * Root of our class library.
+ */
+class RootObject
+{
+public:
+ RootObject() { }
+
+ virtual bool equals(RootObject *o);
+
+ /**
+ * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj.
+ * Useful for sorting Objects.
+ */
+ virtual int compare(RootObject *obj);
+
+ /**
+ * Pretty-print an Object. Useful for debugging the old-fashioned way.
+ */
+ virtual void print();
+
+ virtual const char *toChars();
+ virtual void toBuffer(OutBuffer *buf);
+
+ /**
+ * Used as a replacement for dynamic_cast. Returns a unique number
+ * defined by the library user. For Object, the return value is 0.
+ */
+ virtual int dyncast() const;
+};
diff --git a/gcc/d/dmd/root/outbuffer.c b/gcc/d/dmd/root/outbuffer.c
new file mode 100644
index 0000000..7b6782d
--- /dev/null
+++ b/gcc/d/dmd/root/outbuffer.c
@@ -0,0 +1,401 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/outbuffer.c
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if __sun
+#include <alloca.h>
+#endif
+
+#include "outbuffer.h"
+#include "object.h"
+
+char *OutBuffer::extractData()
+{
+ char *p;
+
+ p = (char *)data;
+ data = NULL;
+ offset = 0;
+ size = 0;
+ return p;
+}
+
+void OutBuffer::reserve(size_t nbytes)
+{
+ //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes);
+ if (size - offset < nbytes)
+ {
+ size = (offset + nbytes) * 2;
+ size = (size + 15) & ~15;
+ data = (unsigned char *)mem.xrealloc(data, size);
+ }
+}
+
+void OutBuffer::reset()
+{
+ offset = 0;
+}
+
+void OutBuffer::setsize(size_t size)
+{
+ offset = size;
+}
+
+void OutBuffer::write(const void *data, size_t nbytes)
+{
+ if (doindent && !notlinehead)
+ {
+ if (level)
+ {
+ reserve(level);
+ for (int i = 0; i < level; i++)
+ {
+ this->data[offset] = '\t';
+ offset++;
+ }
+ }
+ notlinehead = 1;
+ }
+ reserve(nbytes);
+ memcpy(this->data + offset, data, nbytes);
+ offset += nbytes;
+}
+
+void OutBuffer::writebstring(utf8_t *string)
+{
+ write(string,*string + 1);
+}
+
+void OutBuffer::writestring(const char *string)
+{
+ write(string,strlen(string));
+}
+
+void OutBuffer::prependstring(const char *string)
+{
+ size_t len = strlen(string);
+ reserve(len);
+ memmove(data + len, data, offset);
+ memcpy(data, string, len);
+ offset += len;
+}
+
+void OutBuffer::writenl()
+{
+#if _WIN32
+ writeword(0x0A0D); // newline is CR,LF on Microsoft OS's
+#else
+ writeByte('\n');
+#endif
+ if (doindent)
+ notlinehead = 0;
+}
+
+void OutBuffer::writeByte(unsigned b)
+{
+ if (doindent && !notlinehead
+ && b != '\n')
+ {
+ if (level)
+ {
+ reserve(level);
+ for (int i = 0; i < level; i++)
+ {
+ this->data[offset] = '\t';
+ offset++;
+ }
+ }
+ notlinehead = 1;
+ }
+ reserve(1);
+ this->data[offset] = (unsigned char)b;
+ offset++;
+}
+
+void OutBuffer::writeUTF8(unsigned b)
+{
+ reserve(6);
+ if (b <= 0x7F)
+ {
+ this->data[offset] = (unsigned char)b;
+ offset++;
+ }
+ else if (b <= 0x7FF)
+ {
+ this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
+ this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
+ offset += 2;
+ }
+ else if (b <= 0xFFFF)
+ {
+ this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
+ this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+ this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
+ offset += 3;
+ }
+ else if (b <= 0x1FFFFF)
+ {
+ this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
+ this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+ this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+ this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
+ offset += 4;
+ }
+ else if (b <= 0x3FFFFFF)
+ {
+ this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
+ this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+ this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+ this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+ this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
+ offset += 5;
+ }
+ else if (b <= 0x7FFFFFFF)
+ {
+ this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
+ this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
+ this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
+ this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
+ this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
+ this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
+ offset += 6;
+ }
+ else
+ assert(0);
+}
+
+void OutBuffer::prependbyte(unsigned b)
+{
+ reserve(1);
+ memmove(data + 1, data, offset);
+ data[0] = (unsigned char)b;
+ offset++;
+}
+
+void OutBuffer::writewchar(unsigned w)
+{
+#if _WIN32
+ writeword(w);
+#else
+ write4(w);
+#endif
+}
+
+void OutBuffer::writeword(unsigned w)
+{
+#if _WIN32
+ unsigned newline = 0x0A0D;
+#else
+ unsigned newline = '\n';
+#endif
+ if (doindent && !notlinehead
+ && w != newline)
+ {
+ if (level)
+ {
+ reserve(level);
+ for (int i = 0; i < level; i++)
+ {
+ this->data[offset] = '\t';
+ offset++;
+ }
+ }
+ notlinehead = 1;
+ }
+ reserve(2);
+ *(unsigned short *)(this->data + offset) = (unsigned short)w;
+ offset += 2;
+}
+
+void OutBuffer::writeUTF16(unsigned w)
+{
+ reserve(4);
+ if (w <= 0xFFFF)
+ {
+ *(unsigned short *)(this->data + offset) = (unsigned short)w;
+ offset += 2;
+ }
+ else if (w <= 0x10FFFF)
+ {
+ *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0);
+ *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
+ offset += 4;
+ }
+ else
+ assert(0);
+}
+
+void OutBuffer::write4(unsigned w)
+{
+#if _WIN32
+ bool notnewline = w != 0x000A000D;
+#else
+ bool notnewline = true;
+#endif
+ if (doindent && !notlinehead && notnewline)
+ {
+ if (level)
+ {
+ reserve(level);
+ for (int i = 0; i < level; i++)
+ {
+ this->data[offset] = '\t';
+ offset++;
+ }
+ }
+ notlinehead = 1;
+ }
+ reserve(4);
+ *(unsigned *)(this->data + offset) = w;
+ offset += 4;
+}
+
+void OutBuffer::write(OutBuffer *buf)
+{
+ if (buf)
+ { reserve(buf->offset);
+ memcpy(data + offset, buf->data, buf->offset);
+ offset += buf->offset;
+ }
+}
+
+void OutBuffer::write(RootObject *obj)
+{
+ if (obj)
+ {
+ writestring(obj->toChars());
+ }
+}
+
+void OutBuffer::fill0(size_t nbytes)
+{
+ reserve(nbytes);
+ memset(data + offset,0,nbytes);
+ offset += nbytes;
+}
+
+void OutBuffer::vprintf(const char *format, va_list args)
+{
+ int count;
+
+ if (doindent)
+ write(NULL, 0); // perform indent
+ int psize = 128;
+ for (;;)
+ {
+ reserve(psize);
+#if _WIN32
+ count = _vsnprintf((char *)data + offset,psize,format,args);
+ if (count != -1)
+ break;
+ psize *= 2;
+#elif POSIX
+ va_list va;
+ va_copy(va, args);
+/*
+ The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
+ are equivalent to the functions printf(), fprintf(), sprintf(),
+ snprintf(), respectively, except that they are called with a
+ va_list instead of a variable number of arguments. These
+ functions do not call the va_end macro. Consequently, the value
+ of ap is undefined after the call. The application should call
+ va_end(ap) itself afterwards.
+ */
+ count = vsnprintf((char *)data + offset,psize,format,va);
+ va_end(va);
+ if (count == -1)
+ psize *= 2;
+ else if (count >= psize)
+ psize = count + 1;
+ else
+ break;
+#else
+ assert(0);
+#endif
+ }
+ offset += count;
+}
+
+void OutBuffer::printf(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vprintf(format,ap);
+ va_end(ap);
+}
+
+void OutBuffer::bracket(char left, char right)
+{
+ reserve(2);
+ memmove(data + 1, data, offset);
+ data[0] = left;
+ data[offset + 1] = right;
+ offset += 2;
+}
+
+/******************
+ * Insert left at i, and right at j.
+ * Return index just past right.
+ */
+
+size_t OutBuffer::bracket(size_t i, const char *left, size_t j, const char *right)
+{
+ size_t leftlen = strlen(left);
+ size_t rightlen = strlen(right);
+ reserve(leftlen + rightlen);
+ insert(i, left, leftlen);
+ insert(j + leftlen, right, rightlen);
+ return j + leftlen + rightlen;
+}
+
+void OutBuffer::spread(size_t offset, size_t nbytes)
+{
+ reserve(nbytes);
+ memmove(data + offset + nbytes, data + offset,
+ this->offset - offset);
+ this->offset += nbytes;
+}
+
+/****************************************
+ * Returns: offset + nbytes
+ */
+
+size_t OutBuffer::insert(size_t offset, const void *p, size_t nbytes)
+{
+ spread(offset, nbytes);
+ memmove(data + offset, p, nbytes);
+ return offset + nbytes;
+}
+
+void OutBuffer::remove(size_t offset, size_t nbytes)
+{
+ memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes));
+ this->offset -= nbytes;
+}
+
+char *OutBuffer::peekString()
+{
+ if (!offset || data[offset-1] != '\0')
+ {
+ writeByte(0);
+ offset--; // allow appending more
+ }
+ return (char *)data;
+}
+
+char *OutBuffer::extractString()
+{
+ if (!offset || data[offset-1] != '\0')
+ writeByte(0);
+ return extractData();
+}
diff --git a/gcc/d/dmd/root/outbuffer.h b/gcc/d/dmd/root/outbuffer.h
new file mode 100644
index 0000000..6d3be10
--- /dev/null
+++ b/gcc/d/dmd/root/outbuffer.h
@@ -0,0 +1,77 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.h
+ */
+
+#pragma once
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include "port.h"
+#include "rmem.h"
+
+class RootObject;
+
+struct OutBuffer
+{
+ unsigned char *data;
+ size_t offset;
+ size_t size;
+
+ int level;
+ bool doindent;
+private:
+ bool notlinehead;
+public:
+
+ OutBuffer()
+ {
+ data = NULL;
+ offset = 0;
+ size = 0;
+
+ doindent = 0;
+ level = 0;
+ notlinehead = 0;
+ }
+ ~OutBuffer()
+ {
+ mem.xfree(data);
+ }
+ char *extractData();
+
+ void reserve(size_t nbytes);
+ void setsize(size_t size);
+ void reset();
+ void write(const void *data, d_size_t nbytes);
+ void writebstring(utf8_t *string);
+ void writestring(const char *string);
+ void prependstring(const char *string);
+ void writenl(); // write newline
+ void writeByte(unsigned b);
+ void writeUTF8(unsigned b);
+ void prependbyte(unsigned b);
+ void writewchar(unsigned w);
+ void writeword(unsigned w);
+ void writeUTF16(unsigned w);
+ void write4(unsigned w);
+ void write(OutBuffer *buf);
+ void write(RootObject *obj);
+ void fill0(size_t nbytes);
+ void vprintf(const char *format, va_list args);
+ void printf(const char *format, ...);
+ void bracket(char left, char right);
+ size_t bracket(size_t i, const char *left, size_t j, const char *right);
+ void spread(size_t offset, size_t nbytes);
+ size_t insert(size_t offset, const void *data, size_t nbytes);
+ void remove(size_t offset, size_t nbytes);
+ // Append terminating null if necessary and get view of internal buffer
+ char *peekString();
+ // Append terminating null if necessary and take ownership of data
+ char *extractString();
+};
diff --git a/gcc/d/dmd/root/port.h b/gcc/d/dmd/root/port.h
new file mode 100644
index 0000000..3f3c46d
--- /dev/null
+++ b/gcc/d/dmd/root/port.h
@@ -0,0 +1,43 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/port.h
+ */
+
+#pragma once
+
+// Portable wrapper around compiler/system specific things.
+// The idea is to minimize #ifdef's in the app code.
+
+#include <stdlib.h> // for alloca
+#include <stdint.h>
+
+#if _MSC_VER
+#include <alloca.h>
+typedef __int64 longlong;
+typedef unsigned __int64 ulonglong;
+#else
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+#endif
+
+typedef unsigned char utf8_t;
+
+struct Port
+{
+ static int memicmp(const char *s1, const char *s2, size_t n);
+ static char *strupr(char *s);
+
+ static bool isFloat32LiteralOutOfRange(const char *s);
+ static bool isFloat64LiteralOutOfRange(const char *s);
+
+ static void writelongLE(unsigned value, void *buffer);
+ static unsigned readlongLE(void *buffer);
+ static void writelongBE(unsigned value, void *buffer);
+ static unsigned readlongBE(void *buffer);
+ static unsigned readwordLE(void *buffer);
+ static unsigned readwordBE(void *buffer);
+ static void valcpy(void *dst, uint64_t val, size_t size);
+};
diff --git a/gcc/d/dmd/root/rmem.c b/gcc/d/dmd/root/rmem.c
new file mode 100644
index 0000000..92e79ca
--- /dev/null
+++ b/gcc/d/dmd/root/rmem.c
@@ -0,0 +1,162 @@
+
+/* Copyright (C) 2000-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/rmem.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rmem.h"
+
+/* This implementation of the storage allocator uses the standard C allocation package.
+ */
+
+Mem mem;
+
+char *Mem::xstrdup(const char *s)
+{
+ char *p;
+
+ if (s)
+ {
+ p = strdup(s);
+ if (p)
+ return p;
+ error();
+ }
+ return NULL;
+}
+
+void *Mem::xmalloc(size_t size)
+{ void *p;
+
+ if (!size)
+ p = NULL;
+ else
+ {
+ p = malloc(size);
+ if (!p)
+ error();
+ }
+ return p;
+}
+
+void *Mem::xcalloc(size_t size, size_t n)
+{ void *p;
+
+ if (!size || !n)
+ p = NULL;
+ else
+ {
+ p = calloc(size, n);
+ if (!p)
+ error();
+ }
+ return p;
+}
+
+void *Mem::xrealloc(void *p, size_t size)
+{
+ if (!size)
+ { if (p)
+ {
+ free(p);
+ p = NULL;
+ }
+ }
+ else if (!p)
+ {
+ p = malloc(size);
+ if (!p)
+ error();
+ }
+ else
+ {
+ void *psave = p;
+ p = realloc(psave, size);
+ if (!p)
+ { xfree(psave);
+ error();
+ }
+ }
+ return p;
+}
+
+void Mem::xfree(void *p)
+{
+ if (p)
+ free(p);
+}
+
+void *Mem::xmallocdup(void *o, size_t size)
+{ void *p;
+
+ if (!size)
+ p = NULL;
+ else
+ {
+ p = malloc(size);
+ if (!p)
+ error();
+ else
+ memcpy(p,o,size);
+ }
+ return p;
+}
+
+void Mem::error()
+{
+ printf("Error: out of memory\n");
+ exit(EXIT_FAILURE);
+}
+
+/* =================================================== */
+
+/* Allocate, but never release
+ */
+
+// Allocate a little less than 1Mb because the C runtime adds some overhead that
+// causes the actual memory block to be larger than 1Mb otherwise.
+#define CHUNK_SIZE (256 * 4096 - 64)
+
+static size_t heapleft = 0;
+static void *heapp;
+
+extern "C" void *allocmemory(size_t m_size)
+{
+ // 16 byte alignment is better (and sometimes needed) for doubles
+ m_size = (m_size + 15) & ~15;
+
+ // The layout of the code is selected so the most common case is straight through
+ if (m_size <= heapleft)
+ {
+ L1:
+ heapleft -= m_size;
+ void *p = heapp;
+ heapp = (void *)((char *)heapp + m_size);
+ return p;
+ }
+
+ if (m_size > CHUNK_SIZE)
+ {
+ void *p = malloc(m_size);
+ if (p)
+ return p;
+ printf("Error: out of memory\n");
+ exit(EXIT_FAILURE);
+ return p;
+ }
+
+ heapleft = CHUNK_SIZE;
+ heapp = malloc(CHUNK_SIZE);
+ if (!heapp)
+ {
+ printf("Error: out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+ goto L1;
+}
diff --git a/gcc/d/dmd/root/rmem.h b/gcc/d/dmd/root/rmem.h
new file mode 100644
index 0000000..87d465f
--- /dev/null
+++ b/gcc/d/dmd/root/rmem.h
@@ -0,0 +1,35 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.h
+ */
+
+#pragma once
+
+#include <stddef.h> // for size_t
+
+#if __APPLE__ && __i386__
+ /* size_t is 'unsigned long', which makes it mangle differently
+ * than D's 'uint'
+ */
+ typedef unsigned d_size_t;
+#else
+ typedef size_t d_size_t;
+#endif
+
+struct Mem
+{
+ Mem() { }
+
+ static char *xstrdup(const char *s);
+ static void *xmalloc(d_size_t size);
+ static void *xcalloc(d_size_t size, d_size_t n);
+ static void *xrealloc(void *p, d_size_t size);
+ static void xfree(void *p);
+ static void *xmallocdup(void *o, d_size_t size);
+ static void error();
+};
+
+extern Mem mem;
diff --git a/gcc/d/dmd/root/root.h b/gcc/d/dmd/root/root.h
new file mode 100644
index 0000000..6c3df31
--- /dev/null
+++ b/gcc/d/dmd/root/root.h
@@ -0,0 +1,19 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/root.h
+ */
+
+#pragma once
+
+#include "object.h"
+
+#include "filename.h"
+
+#include "file.h"
+
+#include "outbuffer.h"
+
+#include "array.h"
diff --git a/gcc/d/dmd/root/rootobject.c b/gcc/d/dmd/root/rootobject.c
new file mode 100644
index 0000000..cd239d6
--- /dev/null
+++ b/gcc/d/dmd/root/rootobject.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/object.c
+ */
+
+#include <stdio.h>
+
+#include "object.h"
+#include "outbuffer.h"
+
+/****************************** Object ********************************/
+
+bool RootObject::equals(RootObject *o)
+{
+ return o == this;
+}
+
+int RootObject::compare(RootObject *obj)
+{
+ size_t lhs = (size_t)this;
+ size_t rhs = (size_t)obj;
+ if (lhs < rhs)
+ return -1;
+ else if (lhs > rhs)
+ return 1;
+ return 0;
+}
+
+void RootObject::print()
+{
+ printf("%s %p\n", toChars(), this);
+}
+
+const char *RootObject::toChars()
+{
+ return "Object";
+}
+
+int RootObject::dyncast() const
+{
+ return DYNCAST_OBJECT;
+}
+
+void RootObject::toBuffer(OutBuffer *b)
+{
+ b->writestring("Object");
+}
diff --git a/gcc/d/dmd/root/speller.c b/gcc/d/dmd/root/speller.c
new file mode 100644
index 0000000..52b4e47
--- /dev/null
+++ b/gcc/d/dmd/root/speller.c
@@ -0,0 +1,240 @@
+
+/* Copyright (C) 2010-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/speller.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+
+#if __sun || _MSC_VER
+#include <alloca.h>
+#endif
+
+#include "speller.h"
+
+const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+
+/**************************************************
+ * combine a new result from the spell checker to
+ * find the one with the closest symbol with
+ * respect to the cost defined by the search function
+ * Input/Output:
+ * p best found spelling (NULL if none found yet)
+ * cost cost of p (INT_MAX if none found yet)
+ * Input:
+ * np new found spelling (NULL if none found)
+ * ncost cost of np if non-NULL
+ * Returns:
+ * true if the cost is less or equal 0
+ * false otherwise
+ */
+bool combineSpellerResult(void*& p, int& cost, void* np, int ncost)
+{
+ if (np && ncost < cost)
+ {
+ p = np;
+ cost = ncost;
+ if (cost <= 0)
+ return true;
+ }
+ return false;
+}
+
+void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
+ const char *charset, size_t index, int* cost)
+{
+ if (!seedlen)
+ return NULL;
+ assert(seed[seedlen] == 0);
+
+ char tmp[30];
+ char *buf;
+ if (seedlen <= sizeof(tmp) - 2)
+ buf = tmp;
+ else
+ {
+ buf = (char *)alloca(seedlen + 2); // leave space for extra char
+ if (!buf)
+ return NULL; // no matches
+ }
+
+ memcpy(buf, seed, index);
+ *cost = INT_MAX;
+ void* p = NULL;
+ int ncost;
+
+ /* Delete at seed[index] */
+ if (index < seedlen)
+ {
+ memcpy(buf + index, seed + index + 1, seedlen - index);
+ assert(buf[seedlen - 1] == 0);
+ void* np = (*fp)(fparg, buf, &ncost);
+ if (combineSpellerResult(p, *cost, np, ncost))
+ return p;
+ }
+
+ if (charset && *charset)
+ {
+ /* Substitutions */
+ if (index < seedlen)
+ {
+ memcpy(buf, seed, seedlen + 1);
+ for (const char *s = charset; *s; s++)
+ {
+ buf[index] = *s;
+
+ //printf("sub buf = '%s'\n", buf);
+ void* np = (*fp)(fparg, buf, &ncost);
+ if (combineSpellerResult(p, *cost, np, ncost))
+ return p;
+ }
+ assert(buf[seedlen] == 0);
+ }
+
+ /* Insertions */
+ memcpy (buf + index + 1, seed + index, seedlen + 1 - index);
+
+ for (const char *s = charset; *s; s++)
+ {
+ buf[index] = *s;
+
+ //printf("ins buf = '%s'\n", buf);
+ void* np = (*fp)(fparg, buf, &ncost);
+ if (combineSpellerResult(p, *cost, np, ncost))
+ return p;
+ }
+ assert(buf[seedlen + 1] == 0);
+ }
+
+ return p; // return "best" result
+}
+
+void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
+ const char *charset, int flag)
+{
+ if (!seedlen)
+ return NULL;
+
+ char tmp[30];
+ char *buf;
+ if (seedlen <= sizeof(tmp) - 2)
+ buf = tmp;
+ else
+ {
+ buf = (char *)alloca(seedlen + 2); // leave space for extra char
+ if (!buf)
+ return NULL; // no matches
+ }
+ int cost = INT_MAX, ncost;
+ void *p = NULL, *np;
+
+ /* Deletions */
+ memcpy(buf, seed + 1, seedlen);
+ for (size_t i = 0; i < seedlen; i++)
+ {
+ //printf("del buf = '%s'\n", buf);
+ if (flag)
+ np = spellerY(buf, seedlen - 1, fp, fparg, charset, i, &ncost);
+ else
+ np = (*fp)(fparg, buf, &ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+
+ buf[i] = seed[i];
+ }
+
+ /* Transpositions */
+ if (!flag)
+ {
+ memcpy(buf, seed, seedlen + 1);
+ for (size_t i = 0; i + 1 < seedlen; i++)
+ {
+ // swap [i] and [i + 1]
+ buf[i] = seed[i + 1];
+ buf[i + 1] = seed[i];
+
+ //printf("tra buf = '%s'\n", buf);
+ if (combineSpellerResult(p, cost, (*fp)(fparg, buf, &ncost), ncost))
+ return p;
+
+ buf[i] = seed[i];
+ }
+ }
+
+ if (charset && *charset)
+ {
+ /* Substitutions */
+ memcpy(buf, seed, seedlen + 1);
+ for (size_t i = 0; i < seedlen; i++)
+ {
+ for (const char *s = charset; *s; s++)
+ {
+ buf[i] = *s;
+
+ //printf("sub buf = '%s'\n", buf);
+ if (flag)
+ np = spellerY(buf, seedlen, fp, fparg, charset, i + 1, &ncost);
+ else
+ np = (*fp)(fparg, buf, &ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ }
+ buf[i] = seed[i];
+ }
+
+ /* Insertions */
+ memcpy(buf + 1, seed, seedlen + 1);
+ for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations
+ {
+ for (const char *s = charset; *s; s++)
+ {
+ buf[i] = *s;
+
+ //printf("ins buf = '%s'\n", buf);
+ if (flag)
+ np = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1, &ncost);
+ else
+ np = (*fp)(fparg, buf, &ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ }
+ buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0
+ }
+ }
+
+ return p; // return "best" result
+}
+
+/**************************************************
+ * Looks for correct spelling.
+ * Currently only looks a 'distance' of one from the seed[].
+ * This does an exhaustive search, so can potentially be very slow.
+ * Input:
+ * seed wrongly spelled word
+ * fp search function
+ * fparg argument to search function
+ * charset character set
+ * Returns:
+ * NULL no correct spellings found
+ * void* value returned by fp() for first possible correct spelling
+ */
+
+void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset)
+{
+ size_t seedlen = strlen(seed);
+ size_t maxdist = seedlen < 4 ? seedlen / 2 : 2;
+ for (size_t distance = 0; distance < maxdist; distance++)
+ { void *p = spellerX(seed, seedlen, fp, fparg, charset, distance);
+ if (p)
+ return p;
+// if (seedlen > 10)
+// break;
+ }
+ return NULL; // didn't find it
+}
diff --git a/gcc/d/dmd/root/speller.h b/gcc/d/dmd/root/speller.h
new file mode 100644
index 0000000..eaf3b28
--- /dev/null
+++ b/gcc/d/dmd/root/speller.h
@@ -0,0 +1,16 @@
+
+/* Copyright (C) 2010-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/speller.h
+ */
+
+#pragma once
+
+typedef void *(fp_speller_t)(void *, const char *, int*);
+
+extern const char idchars[];
+
+void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset);
+
diff --git a/gcc/d/dmd/root/stringtable.c b/gcc/d/dmd/root/stringtable.c
new file mode 100644
index 0000000..158e2af
--- /dev/null
+++ b/gcc/d/dmd/root/stringtable.c
@@ -0,0 +1,200 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/stringtable.c
+ */
+
+#include <stdio.h>
+#include <stdint.h> // uint{8|16|32}_t
+#include <string.h> // memcpy()
+#include <stdlib.h>
+
+#include "root.h"
+#include "rmem.h" // mem
+#include "stringtable.h"
+#include "hash.h"
+
+#define POOL_BITS 12
+#define POOL_SIZE (1U << POOL_BITS)
+
+struct StringEntry
+{
+ uint32_t hash;
+ uint32_t vptr;
+};
+
+uint32_t StringTable::allocValue(const char *s, size_t length, void *ptrvalue)
+{
+ const size_t nbytes = sizeof(StringValue) + length + 1;
+
+ if (!npools || nfill + nbytes > POOL_SIZE)
+ {
+ pools = (uint8_t **)mem.xrealloc(pools, ++npools * sizeof(pools[0]));
+ pools[npools - 1] = (uint8_t *)mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE);
+ nfill = 0;
+ }
+
+ StringValue *sv = (StringValue *)&pools[npools - 1][nfill];
+ sv->ptrvalue = ptrvalue;
+ sv->length = length;
+ ::memcpy(sv->lstring(), s, length);
+ sv->lstring()[length] = 0;
+
+ const uint32_t vptr = (uint32_t)(npools << POOL_BITS | nfill);
+ nfill += nbytes + (-nbytes & 7); // align to 8 bytes
+ return vptr;
+}
+
+StringValue *StringTable::getValue(uint32_t vptr)
+{
+ if (!vptr) return NULL;
+
+ const size_t idx = (vptr >> POOL_BITS) - 1;
+ const size_t off = vptr & (POOL_SIZE - 1);
+ return (StringValue *)&pools[idx][off];
+}
+
+static size_t nextpow2(size_t val)
+{
+ size_t res = 1;
+ while (res < val)
+ res <<= 1;
+ return res;
+}
+
+static const double loadFactor = 0.8;
+
+void StringTable::_init(size_t size)
+{
+ size = nextpow2((size_t)(size / loadFactor));
+ if (size < 32) size = 32;
+ table = (StringEntry *)mem.xcalloc(size, sizeof(table[0]));
+ tabledim = size;
+ pools = NULL;
+ npools = nfill = 0;
+ count = 0;
+}
+
+void StringTable::reset(size_t size)
+{
+ for (size_t i = 0; i < npools; ++i)
+ mem.xfree(pools[i]);
+
+ mem.xfree(table);
+ mem.xfree(pools);
+ table = NULL;
+ pools = NULL;
+ _init(size);
+}
+
+StringTable::~StringTable()
+{
+ for (size_t i = 0; i < npools; ++i)
+ mem.xfree(pools[i]);
+
+ mem.xfree(table);
+ mem.xfree(pools);
+ table = NULL;
+ pools = NULL;
+}
+
+size_t StringTable::findSlot(hash_t hash, const char *s, size_t length)
+{
+ // quadratic probing using triangular numbers
+ // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774
+ for (size_t i = hash & (tabledim - 1), j = 1; ;++j)
+ {
+ StringValue *sv;
+ if (!table[i].vptr ||
+ (table[i].hash == hash &&
+ (sv = getValue(table[i].vptr))->length == length &&
+ ::memcmp(s, sv->lstring(), length) == 0))
+ return i;
+ i = (i + j) & (tabledim - 1);
+ }
+}
+
+StringValue *StringTable::lookup(const char *s, size_t length)
+{
+ const hash_t hash = calcHash(s, length);
+ const size_t i = findSlot(hash, s, length);
+ // printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL);
+ return getValue(table[i].vptr);
+}
+
+StringValue *StringTable::update(const char *s, size_t length)
+{
+ const hash_t hash = calcHash(s, length);
+ size_t i = findSlot(hash, s, length);
+ if (!table[i].vptr)
+ {
+ if (++count > tabledim * loadFactor)
+ {
+ grow();
+ i = findSlot(hash, s, length);
+ }
+ table[i].hash = hash;
+ table[i].vptr = allocValue(s, length, NULL);
+ }
+ // printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL);
+ return getValue(table[i].vptr);
+}
+
+StringValue *StringTable::insert(const char *s, size_t length, void *ptrvalue)
+{
+ const hash_t hash = calcHash(s, length);
+ size_t i = findSlot(hash, s, length);
+ if (table[i].vptr)
+ return NULL; // already in table
+ if (++count > tabledim * loadFactor)
+ {
+ grow();
+ i = findSlot(hash, s, length);
+ }
+ table[i].hash = hash;
+ table[i].vptr = allocValue(s, length, ptrvalue);
+ // printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL);
+ return getValue(table[i].vptr);
+}
+
+void StringTable::grow()
+{
+ const size_t odim = tabledim;
+ StringEntry *otab = table;
+ tabledim *= 2;
+ table = (StringEntry *)mem.xcalloc(tabledim, sizeof(table[0]));
+
+ for (size_t i = 0; i < odim; ++i)
+ {
+ StringEntry *se = &otab[i];
+ if (!se->vptr) continue;
+ StringValue *sv = getValue(se->vptr);
+ table[findSlot(se->hash, sv->lstring(), sv->length)] = *se;
+ }
+ mem.xfree(otab);
+}
+
+/********************************
+ * Walk the contents of the string table,
+ * calling fp for each entry.
+ * Params:
+ * fp = function to call. Returns !=0 to stop
+ * Returns:
+ * last return value of fp call
+ */
+int StringTable::apply(int (*fp)(StringValue *))
+{
+ for (size_t i = 0; i < tabledim; ++i)
+ {
+ StringEntry *se = &table[i];
+ if (!se->vptr) continue;
+ StringValue *sv = getValue(se->vptr);
+ int result = (*fp)(sv);
+ if (result)
+ return result;
+ }
+ return 0;
+}
+
diff --git a/gcc/d/dmd/root/stringtable.h b/gcc/d/dmd/root/stringtable.h
new file mode 100644
index 0000000..2b4524b
--- /dev/null
+++ b/gcc/d/dmd/root/stringtable.h
@@ -0,0 +1,57 @@
+
+/* Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.h
+ */
+
+#pragma once
+
+#include "root.h"
+#include "rmem.h" // for d_size_t
+
+struct StringEntry;
+
+// StringValue is a variable-length structure. It has neither proper c'tors nor a
+// factory method because the only thing which should be creating these is StringTable.
+struct StringValue
+{
+ void *ptrvalue;
+ size_t length;
+ char *lstring() { return (char *)(this + 1); }
+
+ size_t len() const { return length; }
+ const char *toDchars() const { return (const char *)(this + 1); }
+
+ StringValue(); // not constructible
+};
+
+struct StringTable
+{
+private:
+ StringEntry *table;
+ size_t tabledim;
+
+ uint8_t **pools;
+ size_t npools;
+ size_t nfill;
+
+ size_t count;
+
+public:
+ void _init(d_size_t size = 0);
+ void reset(d_size_t size = 0);
+ ~StringTable();
+
+ StringValue *lookup(const char *s, d_size_t len);
+ StringValue *insert(const char *s, size_t len, void *ptrvalue);
+ StringValue *update(const char *s, d_size_t len);
+ int apply(int (*fp)(StringValue *));
+
+private:
+ uint32_t allocValue(const char *p, size_t length, void *ptrvalue);
+ StringValue *getValue(uint32_t validx);
+ size_t findSlot(hash_t hash, const char *s, size_t len);
+ void grow();
+};
diff --git a/gcc/d/dmd/safe.c b/gcc/d/dmd/safe.c
new file mode 100644
index 0000000..138beb4
--- /dev/null
+++ b/gcc/d/dmd/safe.c
@@ -0,0 +1,168 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/safe.c
+ */
+
+#include "mars.h"
+#include "expression.h"
+#include "scope.h"
+#include "aggregate.h"
+#include "target.h"
+
+bool MODimplicitConv(MOD modfrom, MOD modto);
+
+/*************************************************************
+ * Check for unsafe access in @safe code:
+ * 1. read overlapped pointers
+ * 2. write misaligned pointers
+ * 3. write overlapped storage classes
+ * Print error if unsafe.
+ * Params:
+ * sc = scope
+ * e = expression to check
+ * readonly = if access is read-only
+ * printmsg = print error message if true
+ * Returns:
+ * true if error
+ */
+
+bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg)
+{
+ if (e->op != TOKdotvar)
+ return false;
+ DotVarExp *dve = (DotVarExp *)e;
+ if (VarDeclaration *v = dve->var->isVarDeclaration())
+ {
+ if (sc->intypeof || !sc->func || !sc->func->isSafeBypassingInference())
+ return false;
+
+ AggregateDeclaration *ad = v->toParent2()->isAggregateDeclaration();
+ if (!ad)
+ return false;
+
+ if (v->overlapped && v->type->hasPointers() && sc->func->setUnsafe())
+ {
+ if (printmsg)
+ e->error("field %s.%s cannot access pointers in @safe code that overlap other fields",
+ ad->toChars(), v->toChars());
+ return true;
+ }
+
+ if (readonly || !e->type->isMutable())
+ return false;
+
+ if (v->type->hasPointers() && v->type->toBasetype()->ty != Tstruct)
+ {
+ if ((ad->type->alignment() < (unsigned)Target::ptrsize ||
+ (v->offset & (Target::ptrsize - 1))) &&
+ sc->func->setUnsafe())
+ {
+ if (printmsg)
+ e->error("field %s.%s cannot modify misaligned pointers in @safe code",
+ ad->toChars(), v->toChars());
+ return true;
+ }
+ }
+
+ if (v->overlapUnsafe && sc->func->setUnsafe())
+ {
+ if (printmsg)
+ e->error("field %s.%s cannot modify fields in @safe code that overlap fields with other storage classes",
+ ad->toChars(), v->toChars());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**********************************************
+ * Determine if it is @safe to cast e from tfrom to tto.
+ * Params:
+ * e = expression to be cast
+ * tfrom = type of e
+ * tto = type to cast e to
+ * Returns:
+ * true if @safe
+ */
+bool isSafeCast(Expression *e, Type *tfrom, Type *tto)
+{
+ // Implicit conversions are always safe
+ if (tfrom->implicitConvTo(tto))
+ return true;
+
+ if (!tto->hasPointers())
+ return true;
+
+ Type *ttob = tto->toBasetype();
+
+ if (ttob->ty == Tclass && tfrom->ty == Tclass)
+ {
+ ClassDeclaration *cdfrom = tfrom->isClassHandle();
+ ClassDeclaration *cdto = ttob->isClassHandle();
+
+ int offset;
+ if (!cdfrom->isBaseOf(cdto, &offset))
+ return false;
+
+ if (cdfrom->isCPPinterface() || cdto->isCPPinterface())
+ return false;
+
+ if (!MODimplicitConv(tfrom->mod, ttob->mod))
+ return false;
+ return true;
+ }
+
+ if (ttob->ty == Tarray && tfrom->ty == Tsarray) // Bugzilla 12502
+ tfrom = tfrom->nextOf()->arrayOf();
+
+ if ((ttob->ty == Tarray && tfrom->ty == Tarray) ||
+ (ttob->ty == Tpointer && tfrom->ty == Tpointer))
+ {
+ Type *ttobn = ttob->nextOf()->toBasetype();
+ Type *tfromn = tfrom->nextOf()->toBasetype();
+
+ /* From void[] to anything mutable is unsafe because:
+ * int*[] api;
+ * void[] av = api;
+ * int[] ai = cast(int[]) av;
+ * ai[0] = 7;
+ * *api[0] crash!
+ */
+ if (tfromn->ty == Tvoid && ttobn->isMutable())
+ {
+ if (ttob->ty == Tarray && e->op == TOKarrayliteral)
+ return true;
+ return false;
+ }
+
+ // If the struct is opaque we don't know about the struct members then the cast becomes unsafe
+ if ((ttobn->ty == Tstruct && !((TypeStruct *)ttobn)->sym->members) ||
+ (tfromn->ty == Tstruct && !((TypeStruct *)tfromn)->sym->members))
+ return false;
+
+ const bool frompointers = tfromn->hasPointers();
+ const bool topointers = ttobn->hasPointers();
+
+ if (frompointers && !topointers && ttobn->isMutable())
+ return false;
+
+ if (!frompointers && topointers)
+ return false;
+
+ if (!topointers &&
+ ttobn->ty != Tfunction && tfromn->ty != Tfunction &&
+ (ttob->ty == Tarray || ttobn->size() <= tfromn->size()) &&
+ MODimplicitConv(tfromn->mod, ttobn->mod))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/gcc/d/dmd/sapply.c b/gcc/d/dmd/sapply.c
new file mode 100644
index 0000000..8920977
--- /dev/null
+++ b/gcc/d/dmd/sapply.c
@@ -0,0 +1,156 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/sapply.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "statement.h"
+#include "visitor.h"
+
+
+/**************************************
+ * A Statement tree walker that will visit each Statement s in the tree,
+ * in depth-first evaluation order, and call fp(s,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ * 0 continue
+ * 1 done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+
+class PostorderStatementVisitor : public StoppableVisitor
+{
+public:
+ StoppableVisitor *v;
+ PostorderStatementVisitor(StoppableVisitor *v) : v(v) {}
+
+ bool doCond(Statement *s)
+ {
+ if (!stop && s)
+ s->accept(this);
+ return stop;
+ }
+ bool applyTo(Statement *s)
+ {
+ s->accept(v);
+ stop = v->stop;
+ return true;
+ }
+
+ void visit(Statement *s)
+ {
+ applyTo(s);
+ }
+ void visit(PeelStatement *s)
+ {
+ doCond(s->s) || applyTo(s);
+ }
+ void visit(CompoundStatement *s)
+ {
+ for (size_t i = 0; i < s->statements->dim; i++)
+ if (doCond((*s->statements)[i]))
+ return;
+ applyTo(s);
+ }
+ void visit(UnrolledLoopStatement *s)
+ {
+ for (size_t i = 0; i < s->statements->dim; i++)
+ if (doCond((*s->statements)[i]))
+ return;
+ applyTo(s);
+ }
+ void visit(ScopeStatement *s)
+ {
+ doCond(s->statement) || applyTo(s);
+ }
+ void visit(WhileStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(DoStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(ForStatement *s)
+ {
+ doCond(s->_init) || doCond(s->_body) || applyTo(s);
+ }
+ void visit(ForeachStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(ForeachRangeStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(IfStatement *s)
+ {
+ doCond(s->ifbody) || doCond(s->elsebody) || applyTo(s);
+ }
+ void visit(PragmaStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(SwitchStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(CaseStatement *s)
+ {
+ doCond(s->statement) || applyTo(s);
+ }
+ void visit(DefaultStatement *s)
+ {
+ doCond(s->statement) || applyTo(s);
+ }
+ void visit(SynchronizedStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(WithStatement *s)
+ {
+ doCond(s->_body) || applyTo(s);
+ }
+ void visit(TryCatchStatement *s)
+ {
+ if (doCond(s->_body))
+ return;
+
+ for (size_t i = 0; i < s->catches->dim; i++)
+ if (doCond((*s->catches)[i]->handler))
+ return;
+ applyTo(s);
+ }
+ void visit(TryFinallyStatement *s)
+ {
+ doCond(s->_body) || doCond(s->finalbody) || applyTo(s);
+ }
+ void visit(OnScopeStatement *s)
+ {
+ doCond(s->statement) || applyTo(s);
+ }
+ void visit(DebugStatement *s)
+ {
+ doCond(s->statement) || applyTo(s);
+ }
+ void visit(LabelStatement *s)
+ {
+ doCond(s->statement) || applyTo(s);
+ }
+};
+
+bool walkPostorder(Statement *s, StoppableVisitor *v)
+{
+ PostorderStatementVisitor pv(v);
+ s->accept(&pv);
+ return v->stop;
+}
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
new file mode 100644
index 0000000..f42a317
--- /dev/null
+++ b/gcc/d/dmd/scope.h
@@ -0,0 +1,158 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/scope.h
+ */
+
+#pragma once
+
+class Dsymbol;
+class ScopeDsymbol;
+class Identifier;
+class Module;
+class Statement;
+class SwitchStatement;
+class TryFinallyStatement;
+class LabelStatement;
+class ForeachStatement;
+class ClassDeclaration;
+class AggregateDeclaration;
+class FuncDeclaration;
+class UserAttributeDeclaration;
+struct DocComment;
+struct AA;
+class TemplateInstance;
+
+#include "dsymbol.h"
+
+#if __GNUC__
+// Requires a full definition for LINK
+#include "globals.h"
+#else
+enum LINK;
+enum PINLINE;
+#endif
+
+#define CSXthis_ctor 1 // called this()
+#define CSXsuper_ctor 2 // called super()
+#define CSXthis 4 // referenced this
+#define CSXsuper 8 // referenced super
+#define CSXlabel 0x10 // seen a label
+#define CSXreturn 0x20 // seen a return statement
+#define CSXany_ctor 0x40 // either this() or super() was called
+#define CSXhalt 0x80 // assert(0)
+
+// Flags that would not be inherited beyond scope nesting
+#define SCOPEctor 0x0001 // constructor type
+#define SCOPEcondition 0x0004 // inside static if/assert condition
+#define SCOPEdebug 0x0008 // inside debug conditional
+
+// Flags that would be inherited beyond scope nesting
+#define SCOPEnoaccesscheck 0x0002 // don't do access checks
+#define SCOPEconstraint 0x0010 // inside template constraint
+#define SCOPEinvariant 0x0020 // inside invariant code
+#define SCOPErequire 0x0040 // inside in contract code
+#define SCOPEensure 0x0060 // inside out contract code
+#define SCOPEcontract 0x0060 // [mask] we're inside contract code
+#define SCOPEctfe 0x0080 // inside a ctfe-only expression
+#define SCOPEcompile 0x0100 // inside __traits(compile)
+#define SCOPEignoresymbolvisibility 0x0200 // ignore symbol visibility (Bugzilla 15907)
+#define SCOPEfullinst 0x1000 // fully instantiate templates
+
+#define SCOPEfree 0x8000 // is on free list
+
+struct Scope
+{
+ Scope *enclosing; // enclosing Scope
+
+ Module *_module; // Root module
+ ScopeDsymbol *scopesym; // current symbol
+ ScopeDsymbol *sds; // if in static if, and declaring new symbols,
+ // sds gets the addMember()
+ FuncDeclaration *func; // function we are in
+ Dsymbol *parent; // parent to use
+ LabelStatement *slabel; // enclosing labelled statement
+ SwitchStatement *sw; // enclosing switch statement
+ TryFinallyStatement *tf; // enclosing try finally statement
+ OnScopeStatement *os; // enclosing scope(xxx) statement
+ Statement *sbreak; // enclosing statement that supports "break"
+ Statement *scontinue; // enclosing statement that supports "continue"
+ ForeachStatement *fes; // if nested function for ForeachStatement, this is it
+ Scope *callsc; // used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__
+ int inunion; // we're processing members of a union
+ int nofree; // set if shouldn't free it
+ int noctor; // set if constructor calls aren't allowed
+ int intypeof; // in typeof(exp)
+ VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init
+
+ /* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope).
+ * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint).
+ * If minst && tinst, it's in instantiated code scope without speculation.
+ * If !minst && tinst, it's in instantiated code scope with speculation.
+ */
+ Module *minst; // root module where the instantiated templates should belong to
+ TemplateInstance *tinst; // enclosing template instance
+
+ unsigned callSuper; // primitive flow analysis for constructors
+ unsigned *fieldinit;
+ size_t fieldinit_dim;
+
+ AlignDeclaration *aligndecl; // alignment for struct members
+
+ LINK linkage; // linkage for external functions
+ CPPMANGLE cppmangle; // C++ mangle type
+ PINLINE inlining; // inlining strategy for functions
+
+ Prot protection; // protection for class members
+ int explicitProtection; // set if in an explicit protection attribute
+
+ StorageClass stc; // storage class
+
+ DeprecatedDeclaration *depdecl; // customized deprecation message
+
+ unsigned flags;
+
+ UserAttributeDeclaration *userAttribDecl; // user defined attributes
+
+ DocComment *lastdc; // documentation comment for last symbol at this scope
+ AA *anchorCounts; // lookup duplicate anchor name count
+ Identifier *prevAnchor; // qualified symbol name of last doc anchor
+
+ static Scope *freelist;
+ static Scope *alloc();
+ static Scope *createGlobal(Module *module);
+
+ Scope();
+
+ Scope *copy();
+
+ Scope *push();
+ Scope *push(ScopeDsymbol *ss);
+ Scope *pop();
+
+ Scope *startCTFE();
+ Scope *endCTFE();
+
+ void mergeCallSuper(Loc loc, unsigned cs);
+
+ unsigned *saveFieldInit();
+ void mergeFieldInit(Loc loc, unsigned *cses);
+
+ Module *instantiatingModule();
+
+ Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone);
+ static void deprecation10378(Loc loc, Dsymbol *sold, Dsymbol *snew);
+ Dsymbol *search_correct(Identifier *ident);
+ static const char *search_correct_C(Identifier *ident);
+ Dsymbol *insert(Dsymbol *s);
+
+ ClassDeclaration *getClassScope();
+ AggregateDeclaration *getStructClassScope();
+ void setNoFree();
+
+ structalign_t alignment();
+};
diff --git a/gcc/d/dmd/sideeffect.c b/gcc/d/dmd/sideeffect.c
new file mode 100644
index 0000000..83e7973
--- /dev/null
+++ b/gcc/d/dmd/sideeffect.c
@@ -0,0 +1,439 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/sideeffect.c
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "statement.h"
+#include "mtype.h"
+#include "utf.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "scope.h"
+#include "attrib.h"
+#include "tokens.h"
+
+bool walkPostorder(Expression *e, StoppableVisitor *v);
+bool lambdaHasSideEffect(Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+
+/**************************************************
+ * Front-end expression rewriting should create temporary variables for
+ * non trivial sub-expressions in order to:
+ * 1. save evaluation order
+ * 2. prevent sharing of sub-expression in AST
+ */
+bool isTrivialExp(Expression *e)
+{
+ class IsTrivialExp : public StoppableVisitor
+ {
+ public:
+ IsTrivialExp() {}
+
+ void visit(Expression *e)
+ {
+ /* Bugzilla 11201: CallExp is always non trivial expression,
+ * especially for inlining.
+ */
+ if (e->op == TOKcall)
+ {
+ stop = true;
+ return;
+ }
+
+ // stop walking if we determine this expression has side effects
+ stop = lambdaHasSideEffect(e);
+ }
+ };
+
+ IsTrivialExp v;
+ return walkPostorder(e, &v) == false;
+}
+
+/********************************************
+ * Determine if Expression has any side effects.
+ */
+
+bool hasSideEffect(Expression *e)
+{
+ class LambdaHasSideEffect : public StoppableVisitor
+ {
+ public:
+ LambdaHasSideEffect() {}
+
+ void visit(Expression *e)
+ {
+ // stop walking if we determine this expression has side effects
+ stop = lambdaHasSideEffect(e);
+ }
+ };
+
+ LambdaHasSideEffect v;
+ return walkPostorder(e, &v);
+}
+
+/********************************************
+ * Determine if the call of f, or function type or delegate type t1, has any side effects.
+ * Returns:
+ * 0 has any side effects
+ * 1 nothrow + constant purity
+ * 2 nothrow + strong purity
+ */
+
+int callSideEffectLevel(FuncDeclaration *f)
+{
+ /* Bugzilla 12760: ctor call always has side effects.
+ */
+ if (f->isCtorDeclaration())
+ return 0;
+
+ assert(f->type->ty == Tfunction);
+ TypeFunction *tf = (TypeFunction *)f->type;
+ if (tf->isnothrow)
+ {
+ PURE purity = f->isPure();
+ if (purity == PUREstrong)
+ return 2;
+ if (purity == PUREconst)
+ return 1;
+ }
+ return 0;
+}
+
+int callSideEffectLevel(Type *t)
+{
+ t = t->toBasetype();
+
+ TypeFunction *tf;
+ if (t->ty == Tdelegate)
+ tf = (TypeFunction *)((TypeDelegate *)t)->next;
+ else
+ {
+ assert(t->ty == Tfunction);
+ tf = (TypeFunction *)t;
+ }
+
+ tf->purityLevel();
+ PURE purity = tf->purity;
+ if (t->ty == Tdelegate && purity > PUREweak)
+ {
+ if (tf->isMutable())
+ purity = PUREweak;
+ else if (!tf->isImmutable())
+ purity = PUREconst;
+ }
+
+ if (tf->isnothrow)
+ {
+ if (purity == PUREstrong)
+ return 2;
+ if (purity == PUREconst)
+ return 1;
+ }
+ return 0;
+}
+
+bool lambdaHasSideEffect(Expression *e)
+{
+ switch (e->op)
+ {
+ // Sort the cases by most frequently used first
+ case TOKassign:
+ case TOKplusplus:
+ case TOKminusminus:
+ case TOKdeclaration:
+ case TOKconstruct:
+ case TOKblit:
+ case TOKaddass:
+ case TOKminass:
+ case TOKcatass:
+ case TOKmulass:
+ case TOKdivass:
+ case TOKmodass:
+ case TOKshlass:
+ case TOKshrass:
+ case TOKushrass:
+ case TOKandass:
+ case TOKorass:
+ case TOKxorass:
+ case TOKpowass:
+ case TOKin:
+ case TOKremove:
+ case TOKassert:
+ case TOKhalt:
+ case TOKdelete:
+ case TOKnew:
+ case TOKnewanonclass:
+ return true;
+
+ case TOKcall:
+ {
+ CallExp *ce = (CallExp *)e;
+ /* Calling a function or delegate that is pure nothrow
+ * has no side effects.
+ */
+ if (ce->e1->type)
+ {
+ Type *t = ce->e1->type->toBasetype();
+ if (t->ty == Tdelegate)
+ t = ((TypeDelegate *)t)->next;
+ if (t->ty == Tfunction &&
+ (ce->f ? callSideEffectLevel(ce->f)
+ : callSideEffectLevel(ce->e1->type)) > 0)
+ {
+ }
+ else
+ return true;
+ }
+ break;
+ }
+
+ case TOKcast:
+ {
+ CastExp *ce = (CastExp *)e;
+ /* if:
+ * cast(classtype)func() // because it may throw
+ */
+ if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass)
+ return true;
+ break;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+/***********************************
+ * The result of this expression will be discarded.
+ * Print error messages if the operation has no side effects (and hence is meaningless).
+ * Returns:
+ * true if expression has no side effects
+ */
+bool discardValue(Expression *e)
+{
+ if (lambdaHasSideEffect(e)) // check side-effect shallowly
+ return false;
+ switch (e->op)
+ {
+ case TOKcast:
+ {
+ CastExp *ce = (CastExp *)e;
+ if (ce->to->equals(Type::tvoid))
+ {
+ /*
+ * Don't complain about an expression with no effect if it was cast to void
+ */
+ return false;
+ }
+ break; // complain
+ }
+
+ case TOKerror:
+ return false;
+
+ case TOKvar:
+ {
+ VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
+ if (v && (v->storage_class & STCtemp))
+ {
+ // Bugzilla 5810: Don't complain about an internal generated variable.
+ return false;
+ }
+ break;
+ }
+ case TOKcall:
+ /* Issue 3882: */
+ if (global.params.warnings != DIAGNOSTICoff && !global.gag)
+ {
+ CallExp *ce = (CallExp *)e;
+ if (e->type->ty == Tvoid)
+ {
+ /* Don't complain about calling void-returning functions with no side-effect,
+ * because purity and nothrow are inferred, and because some of the
+ * runtime library depends on it. Needs more investigation.
+ *
+ * One possible solution is to restrict this message to only be called in hierarchies that
+ * never call assert (and or not called from inside unittest blocks)
+ */
+ }
+ else if (ce->e1->type)
+ {
+ Type *t = ce->e1->type->toBasetype();
+ if (t->ty == Tdelegate)
+ t = ((TypeDelegate *)t)->next;
+ if (t->ty == Tfunction &&
+ (ce->f ? callSideEffectLevel(ce->f)
+ : callSideEffectLevel(ce->e1->type)) > 0)
+ {
+ const char *s;
+ if (ce->f)
+ s = ce->f->toPrettyChars();
+ else if (ce->e1->op == TOKstar)
+ {
+ // print 'fp' if ce->e1 is (*fp)
+ s = ((PtrExp *)ce->e1)->e1->toChars();
+ }
+ else
+ s = ce->e1->toChars();
+
+ e->warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional",
+ s, e->type->toChars());
+ }
+ }
+ }
+ return false;
+
+ case TOKscope:
+ e->error("%s has no effect", e->toChars());
+ return true;
+
+ case TOKandand:
+ {
+ AndAndExp *aae = (AndAndExp *)e;
+ return discardValue(aae->e2);
+ }
+
+ case TOKoror:
+ {
+ OrOrExp *ooe = (OrOrExp *)e;
+ return discardValue(ooe->e2);
+ }
+
+ case TOKquestion:
+ {
+ CondExp *ce = (CondExp *)e;
+
+ /* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have
+ * redundant expression to make those types common. For example:
+ *
+ * struct S { this(int n); int v; alias v this; }
+ * S[int] aa;
+ * aa[1] = 0;
+ *
+ * The last assignment statement will be rewitten to:
+ *
+ * 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
+ *
+ * The last DotVarExp is necessary to take assigned value.
+ *
+ * int value = (aa[1] = 0); // value = aa[1].value
+ *
+ * To avoid false error, discardValue() should be called only when
+ * the both tops of e1 and e2 have actually no side effects.
+ */
+ if (!lambdaHasSideEffect(ce->e1) &&
+ !lambdaHasSideEffect(ce->e2))
+ {
+ return discardValue(ce->e1) |
+ discardValue(ce->e2);
+ }
+ return false;
+ }
+
+ case TOKcomma:
+ {
+ CommaExp *ce = (CommaExp *)e;
+ /* Check for compiler-generated code of the form auto __tmp, e, __tmp;
+ * In such cases, only check e for side effect (it's OK for __tmp to have
+ * no side effect).
+ * See Bugzilla 4231 for discussion
+ */
+ CommaExp *firstComma = ce;
+ while (firstComma->e1->op == TOKcomma)
+ firstComma = (CommaExp *)firstComma->e1;
+ if (firstComma->e1->op == TOKdeclaration &&
+ ce->e2->op == TOKvar &&
+ ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var)
+ {
+ return false;
+ }
+ // Don't check e1 until we cast(void) the a,b code generation
+ //discardValue(ce->e1);
+ return discardValue(ce->e2);
+ }
+
+ case TOKtuple:
+ /* Pass without complaint if any of the tuple elements have side effects.
+ * Ideally any tuple elements with no side effects should raise an error,
+ * this needs more investigation as to what is the right thing to do.
+ */
+ if (!hasSideEffect(e))
+ break;
+ return false;
+
+ default:
+ break;
+ }
+ e->error("%s has no effect in expression (%s)", Token::toChars(e->op), e->toChars());
+ return true;
+}
+
+/**************************************************
+ * Build a temporary variable to copy the value of e into.
+ * Params:
+ * stc = storage classes will be added to the made temporary variable
+ * name = name for temporary variable
+ * e = original expression
+ * Returns:
+ * Newly created temporary variable.
+ */
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e)
+{
+ assert(name && name[0] == '_' && name[1] == '_');
+ Identifier *id = Identifier::generateId(name);
+ ExpInitializer *ez = new ExpInitializer(e->loc, e);
+ VarDeclaration *vd = new VarDeclaration(e->loc, e->type, id, ez);
+ vd->storage_class = stc;
+ vd->storage_class |= STCtemp;
+ vd->storage_class |= STCctfe; // temporary is always CTFEable
+ return vd;
+}
+
+/**************************************************
+ * Build a temporary variable to extract e's evaluation, if e is not trivial.
+ * Params:
+ * sc = scope
+ * name = name for temporary variable
+ * e0 = a new side effect part will be appended to it.
+ * e = original expression
+ * alwaysCopy = if true, build new temporary variable even if e is trivial.
+ * Returns:
+ * When e is trivial and alwaysCopy == false, e itself is returned.
+ * Otherwise, a new VarExp is returned.
+ * Note:
+ * e's lvalue-ness will be handled well by STCref or STCrvalue.
+ */
+Expression *extractSideEffect(Scope *sc, const char *name,
+ Expression **e0, Expression *e, bool alwaysCopy = false)
+{
+ if (!alwaysCopy && isTrivialExp(e))
+ return e;
+
+ VarDeclaration *vd = copyToTemp(0, name, e);
+ if (e->isLvalue())
+ vd->storage_class |= STCref;
+ else
+ vd->storage_class |= STCrvalue;
+
+ Expression *de = new DeclarationExp(vd->loc, vd);
+ Expression *ve = new VarExp(vd->loc, vd);
+ de = semantic(de, sc);
+ ve = semantic(ve, sc);
+
+ *e0 = Expression::combine(*e0, de);
+ return ve;
+}
diff --git a/gcc/d/dmd/statement.c b/gcc/d/dmd/statement.c
new file mode 100644
index 0000000..6e67907
--- /dev/null
+++ b/gcc/d/dmd/statement.c
@@ -0,0 +1,1661 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/statement.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "statement.h"
+#include "errors.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "hdrgen.h"
+#include "parse.h"
+#include "template.h"
+#include "attrib.h"
+#include "import.h"
+
+bool walkPostorder(Statement *s, StoppableVisitor *v);
+StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
+bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *semantic(Expression *e, Scope *sc);
+
+Identifier *fixupLabelName(Scope *sc, Identifier *ident)
+{
+ unsigned flags = (sc->flags & SCOPEcontract);
+ const char *id = ident->toChars();
+ if (flags && flags != SCOPEinvariant &&
+ !(id[0] == '_' && id[1] == '_'))
+ {
+ /* CTFE requires FuncDeclaration::labtab for the interpretation.
+ * So fixing the label name inside in/out contracts is necessary
+ * for the uniqueness in labtab.
+ */
+ const char *prefix = flags == SCOPErequire ? "__in_" : "__out_";
+ OutBuffer buf;
+ buf.printf("%s%s", prefix, ident->toChars());
+
+ const char *name = buf.extractString();
+ ident = Identifier::idPool(name);
+ }
+ return ident;
+}
+
+LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement)
+{
+ if (sc->slabel && sc->slabel->statement == statement)
+ {
+ return sc->slabel;
+ }
+ return NULL;
+}
+
+/***********************************************************
+ * Check an assignment is used as a condition.
+ * Intended to be use before the `semantic` call on `e`.
+ * Params:
+ * e = condition expression which is not yet run semantic analysis.
+ * Returns:
+ * `e` or ErrorExp.
+ */
+Expression *checkAssignmentAsCondition(Expression *e)
+{
+ Expression *ec = e;
+ while (ec->op == TOKcomma)
+ ec = ((CommaExp *)ec)->e2;
+ if (ec->op == TOKassign)
+ {
+ ec->error("assignment cannot be used as a condition, perhaps == was meant?");
+ return new ErrorExp();
+ }
+ return e;
+}
+
+/// Return a type identifier reference to 'object.Throwable'
+TypeIdentifier *getThrowable()
+{
+ TypeIdentifier *tid = new TypeIdentifier(Loc(), Id::empty);
+ tid->addIdent(Id::object);
+ tid->addIdent(Id::Throwable);
+ return tid;
+}
+
+/******************************** Statement ***************************/
+
+Statement::Statement(Loc loc)
+ : loc(loc)
+{
+ // If this is an in{} contract scope statement (skip for determining
+ // inlineStatus of a function body for header content)
+}
+
+Statement *Statement::syntaxCopy()
+{
+ assert(0);
+ return NULL;
+}
+
+void Statement::print()
+{
+ fprintf(stderr, "%s\n", toChars());
+ fflush(stderr);
+}
+
+const char *Statement::toChars()
+{
+ HdrGenState hgs;
+
+ OutBuffer buf;
+ ::toCBuffer(this, &buf, &hgs);
+ return buf.extractString();
+}
+
+
+void Statement::error(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::verror(loc, format, ap);
+ va_end( ap );
+}
+
+void Statement::warning(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::vwarning(loc, format, ap);
+ va_end( ap );
+}
+
+void Statement::deprecation(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ ::vdeprecation(loc, format, ap);
+ va_end( ap );
+}
+
+bool Statement::hasBreak()
+{
+ //printf("Statement::hasBreak()\n");
+ return false;
+}
+
+bool Statement::hasContinue()
+{
+ return false;
+}
+
+/* ============================================== */
+// true if statement uses exception handling
+
+bool Statement::usesEH()
+{
+ class UsesEH : public StoppableVisitor
+ {
+ public:
+ void visit(Statement *) {}
+ void visit(TryCatchStatement *) { stop = true; }
+ void visit(TryFinallyStatement *) { stop = true; }
+ void visit(OnScopeStatement *) { stop = true; }
+ void visit(SynchronizedStatement *) { stop = true; }
+ };
+
+ UsesEH ueh;
+ return walkPostorder(this, &ueh);
+}
+
+/* ============================================== */
+// true if statement 'comes from' somewhere else, like a goto
+
+bool Statement::comeFrom()
+{
+ class ComeFrom : public StoppableVisitor
+ {
+ public:
+ void visit(Statement *) {}
+ void visit(CaseStatement *) { stop = true; }
+ void visit(DefaultStatement *) { stop = true; }
+ void visit(LabelStatement *) { stop = true; }
+ void visit(AsmStatement *) { stop = true; }
+ };
+
+ ComeFrom cf;
+ return walkPostorder(this, &cf);
+}
+
+/* ============================================== */
+// Return true if statement has executable code.
+
+bool Statement::hasCode()
+{
+ class HasCode : public StoppableVisitor
+ {
+ public:
+ void visit(Statement *)
+ {
+ stop = true;
+ }
+
+ void visit(ExpStatement *s)
+ {
+ if (s->exp != NULL)
+ {
+ stop = s->exp->hasCode();
+ }
+ }
+
+ void visit(CompoundStatement *) {}
+ void visit(ScopeStatement *) {}
+ void visit(ImportStatement *) {}
+ };
+
+ HasCode hc;
+ return walkPostorder(this, &hc);
+}
+
+Statement *Statement::last()
+{
+ return this;
+}
+
+/****************************************
+ * If this statement has code that needs to run in a finally clause
+ * at the end of the current scope, return that code in the form of
+ * a Statement.
+ * Output:
+ * *sentry code executed upon entry to the scope
+ * *sexception code executed upon exit from the scope via exception
+ * *sfinally code executed in finally block
+ */
+
+Statement *Statement::scopeCode(Scope *, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+ //printf("Statement::scopeCode()\n");
+ //print();
+ *sentry = NULL;
+ *sexception = NULL;
+ *sfinally = NULL;
+ return this;
+}
+
+/*********************************
+ * Flatten out the scope by presenting the statement
+ * as an array of statements.
+ * Returns NULL if no flattening necessary.
+ */
+
+Statements *Statement::flatten(Scope *)
+{
+ return NULL;
+}
+
+
+/******************************** ErrorStatement ***************************/
+
+ErrorStatement::ErrorStatement()
+ : Statement(Loc())
+{
+ assert(global.gaggedErrors || global.errors);
+}
+
+Statement *ErrorStatement::syntaxCopy()
+{
+ return this;
+}
+
+/******************************** PeelStatement ***************************/
+
+PeelStatement::PeelStatement(Statement *s)
+ : Statement(s->loc)
+{
+ this->s = s;
+}
+
+/******************************** ExpStatement ***************************/
+
+ExpStatement::ExpStatement(Loc loc, Expression *exp)
+ : Statement(loc)
+{
+ this->exp = exp;
+}
+
+ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration)
+ : Statement(loc)
+{
+ this->exp = new DeclarationExp(loc, declaration);
+}
+
+ExpStatement *ExpStatement::create(Loc loc, Expression *exp)
+{
+ return new ExpStatement(loc, exp);
+}
+
+Statement *ExpStatement::syntaxCopy()
+{
+ return new ExpStatement(loc, exp ? exp->syntaxCopy() : NULL);
+}
+
+Statement *ExpStatement::scopeCode(Scope *, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+ //printf("ExpStatement::scopeCode()\n");
+ //print();
+
+ *sentry = NULL;
+ *sexception = NULL;
+ *sfinally = NULL;
+
+ if (exp)
+ {
+ if (exp->op == TOKdeclaration)
+ {
+ DeclarationExp *de = (DeclarationExp *)(exp);
+ VarDeclaration *v = de->declaration->isVarDeclaration();
+ if (v && !v->isDataseg())
+ {
+ if (v->needsScopeDtor())
+ {
+ //printf("dtor is: "); v->edtor->print();
+ *sfinally = new DtorExpStatement(loc, v->edtor, v);
+ v->storage_class |= STCnodtor; // don't add in dtor again
+ }
+ }
+ }
+ }
+ return this;
+}
+
+/****************************************
+ * Convert TemplateMixin members (== Dsymbols) to Statements.
+ */
+Statement *toStatement(Dsymbol *s)
+{
+ class ToStmt : public Visitor
+ {
+ public:
+ Statement *result;
+
+ ToStmt()
+ {
+ this->result = NULL;
+ }
+
+ Statement *visitMembers(Loc loc, Dsymbols *a)
+ {
+ if (!a)
+ return NULL;
+
+ Statements *statements = new Statements();
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ statements->push(toStatement((*a)[i]));
+ }
+ return new CompoundStatement(loc, statements);
+ }
+
+ void visit(Dsymbol *s)
+ {
+ ::error(Loc(), "Internal Compiler Error: cannot mixin %s %s\n", s->kind(), s->toChars());
+ result = new ErrorStatement();
+ }
+
+ void visit(TemplateMixin *tm)
+ {
+ Statements *a = new Statements();
+ for (size_t i = 0; i < tm->members->dim; i++)
+ {
+ Statement *s = toStatement((*tm->members)[i]);
+ if (s)
+ a->push(s);
+ }
+ result = new CompoundStatement(tm->loc, a);
+ }
+
+ /* An actual declaration symbol will be converted to DeclarationExp
+ * with ExpStatement.
+ */
+ Statement *declStmt(Dsymbol *s)
+ {
+ DeclarationExp *de = new DeclarationExp(s->loc, s);
+ de->type = Type::tvoid; // avoid repeated semantic
+ return new ExpStatement(s->loc, de);
+ }
+ void visit(VarDeclaration *d) { result = declStmt(d); }
+ void visit(AggregateDeclaration *d) { result = declStmt(d); }
+ void visit(FuncDeclaration *d) { result = declStmt(d); }
+ void visit(EnumDeclaration *d) { result = declStmt(d); }
+ void visit(AliasDeclaration *d) { result = declStmt(d); }
+ void visit(TemplateDeclaration *d) { result = declStmt(d); }
+
+ /* All attributes have been already picked by the semantic analysis of
+ * 'bottom' declarations (function, struct, class, etc).
+ * So we don't have to copy them.
+ */
+ void visit(StorageClassDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+ void visit(DeprecatedDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+ void visit(LinkDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+ void visit(ProtDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+ void visit(AlignDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+ void visit(UserAttributeDeclaration *d) { result = visitMembers(d->loc, d->decl); }
+
+ void visit(StaticAssert *) {}
+ void visit(Import *) {}
+ void visit(PragmaDeclaration *) {}
+
+ void visit(ConditionalDeclaration *d)
+ {
+ result = visitMembers(d->loc, d->include(NULL, NULL));
+ }
+
+ void visit(CompileDeclaration *d)
+ {
+ result = visitMembers(d->loc, d->include(NULL, NULL));
+ }
+ };
+
+ if (!s)
+ return NULL;
+
+ ToStmt v;
+ s->accept(&v);
+ return v.result;
+}
+
+Statements *ExpStatement::flatten(Scope *sc)
+{
+ /* Bugzilla 14243: expand template mixin in statement scope
+ * to handle variable destructors.
+ */
+ if (exp && exp->op == TOKdeclaration)
+ {
+ Dsymbol *d = ((DeclarationExp *)exp)->declaration;
+ if (TemplateMixin *tm = d->isTemplateMixin())
+ {
+ Expression *e = semantic(exp, sc);
+ if (e->op == TOKerror || tm->errors)
+ {
+ Statements *a = new Statements();
+ a->push(new ErrorStatement());
+ return a;
+ }
+ assert(tm->members);
+
+ Statement *s = toStatement(tm);
+ Statements *a = new Statements();
+ a->push(s);
+ return a;
+ }
+ }
+ return NULL;
+}
+
+/******************************** DtorExpStatement ***************************/
+
+DtorExpStatement::DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v)
+ : ExpStatement(loc, exp)
+{
+ this->var = v;
+}
+
+Statement *DtorExpStatement::syntaxCopy()
+{
+ return new DtorExpStatement(loc, exp ? exp->syntaxCopy() : NULL, var);
+}
+
+/******************************** CompileStatement ***************************/
+
+CompileStatement::CompileStatement(Loc loc, Expression *exp)
+ : Statement(loc)
+{
+ this->exp = exp;
+}
+
+Statement *CompileStatement::syntaxCopy()
+{
+ return new CompileStatement(loc, exp->syntaxCopy());
+}
+
+Statements *CompileStatement::flatten(Scope *sc)
+{
+ //printf("CompileStatement::flatten() %s\n", exp->toChars());
+ sc = sc->startCTFE();
+ exp = semantic(exp, sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc->endCTFE();
+
+ Statements *a = new Statements();
+ if (exp->op != TOKerror)
+ {
+ Expression *e = exp->ctfeInterpret();
+ if (e->op == TOKerror) // Bugzilla 15974
+ goto Lerror;
+ StringExp *se = e->toStringExp();
+ if (!se)
+ error("argument to mixin must be a string, not (%s) of type %s", exp->toChars(), exp->type->toChars());
+ else
+ {
+ se = se->toUTF8(sc);
+ unsigned errors = global.errors;
+ Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+ p.nextToken();
+
+ while (p.token.value != TOKeof)
+ {
+ Statement *s = p.parseStatement(PSsemi | PScurlyscope);
+ if (!s || p.errors)
+ {
+ assert(!p.errors || global.errors != errors); // make sure we caught all the cases
+ goto Lerror;
+ }
+ a->push(s);
+ }
+ return a;
+ }
+ }
+Lerror:
+ a->push(new ErrorStatement());
+ return a;
+}
+
+/******************************** CompoundStatement ***************************/
+
+CompoundStatement::CompoundStatement(Loc loc, Statements *s)
+ : Statement(loc)
+{
+ statements = s;
+}
+
+CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
+ : Statement(loc)
+{
+ statements = new Statements();
+ statements->reserve(2);
+ statements->push(s1);
+ statements->push(s2);
+}
+
+CompoundStatement::CompoundStatement(Loc loc, Statement *s1)
+ : Statement(loc)
+{
+ statements = new Statements();
+ statements->push(s1);
+}
+
+CompoundStatement *CompoundStatement::create(Loc loc, Statement *s1, Statement *s2)
+{
+ return new CompoundStatement(loc, s1, s2);
+}
+
+Statement *CompoundStatement::syntaxCopy()
+{
+ Statements *a = new Statements();
+ a->setDim(statements->dim);
+ for (size_t i = 0; i < statements->dim; i++)
+ {
+ Statement *s = (*statements)[i];
+ (*a)[i] = s ? s->syntaxCopy() : NULL;
+ }
+ return new CompoundStatement(loc, a);
+}
+
+Statements *CompoundStatement::flatten(Scope *)
+{
+ return statements;
+}
+
+ReturnStatement *CompoundStatement::isReturnStatement()
+{
+ ReturnStatement *rs = NULL;
+
+ for (size_t i = 0; i < statements->dim; i++)
+ {
+ Statement *s = (*statements)[i];
+ if (s)
+ {
+ rs = s->isReturnStatement();
+ if (rs)
+ break;
+ }
+ }
+ return rs;
+}
+
+Statement *CompoundStatement::last()
+{
+ Statement *s = NULL;
+
+ for (size_t i = statements->dim; i; --i)
+ { s = (*statements)[i - 1];
+ if (s)
+ {
+ s = s->last();
+ if (s)
+ break;
+ }
+ }
+ return s;
+}
+
+/******************************** CompoundDeclarationStatement ***************************/
+
+CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s)
+ : CompoundStatement(loc, s)
+{
+ statements = s;
+}
+
+Statement *CompoundDeclarationStatement::syntaxCopy()
+{
+ Statements *a = new Statements();
+ a->setDim(statements->dim);
+ for (size_t i = 0; i < statements->dim; i++)
+ {
+ Statement *s = (*statements)[i];
+ (*a)[i] = s ? s->syntaxCopy() : NULL;
+ }
+ return new CompoundDeclarationStatement(loc, a);
+}
+
+/**************************** UnrolledLoopStatement ***************************/
+
+UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
+ : Statement(loc)
+{
+ statements = s;
+}
+
+Statement *UnrolledLoopStatement::syntaxCopy()
+{
+ Statements *a = new Statements();
+ a->setDim(statements->dim);
+ for (size_t i = 0; i < statements->dim; i++)
+ {
+ Statement *s = (*statements)[i];
+ (*a)[i] = s ? s->syntaxCopy() : NULL;
+ }
+ return new UnrolledLoopStatement(loc, a);
+}
+
+bool UnrolledLoopStatement::hasBreak()
+{
+ return true;
+}
+
+bool UnrolledLoopStatement::hasContinue()
+{
+ return true;
+}
+
+/******************************** ScopeStatement ***************************/
+
+ScopeStatement::ScopeStatement(Loc loc, Statement *s, Loc endloc)
+ : Statement(loc)
+{
+ this->statement = s;
+ this->endloc = endloc;
+}
+
+Statement *ScopeStatement::syntaxCopy()
+{
+ return new ScopeStatement(loc, statement ? statement->syntaxCopy() : NULL, endloc);
+}
+
+ReturnStatement *ScopeStatement::isReturnStatement()
+{
+ if (statement)
+ return statement->isReturnStatement();
+ return NULL;
+}
+
+bool ScopeStatement::hasBreak()
+{
+ //printf("ScopeStatement::hasBreak() %s\n", toChars());
+ return statement ? statement->hasBreak() : false;
+}
+
+bool ScopeStatement::hasContinue()
+{
+ return statement ? statement->hasContinue() : false;
+}
+
+/******************************** WhileStatement ***************************/
+
+WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc)
+ : Statement(loc)
+{
+ condition = c;
+ _body = b;
+ this->endloc = endloc;
+}
+
+Statement *WhileStatement::syntaxCopy()
+{
+ return new WhileStatement(loc,
+ condition->syntaxCopy(),
+ _body ? _body->syntaxCopy() : NULL,
+ endloc);
+}
+
+bool WhileStatement::hasBreak()
+{
+ return true;
+}
+
+bool WhileStatement::hasContinue()
+{
+ return true;
+}
+
+/******************************** DoStatement ***************************/
+
+DoStatement::DoStatement(Loc loc, Statement *b, Expression *c, Loc endloc)
+ : Statement(loc)
+{
+ _body = b;
+ condition = c;
+ this->endloc = endloc;
+}
+
+Statement *DoStatement::syntaxCopy()
+{
+ return new DoStatement(loc,
+ _body ? _body->syntaxCopy() : NULL,
+ condition->syntaxCopy(),
+ endloc);
+}
+
+bool DoStatement::hasBreak()
+{
+ return true;
+}
+
+bool DoStatement::hasContinue()
+{
+ return true;
+}
+
+/******************************** ForStatement ***************************/
+
+ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body, Loc endloc)
+ : Statement(loc)
+{
+ this->_init = init;
+ this->condition = condition;
+ this->increment = increment;
+ this->_body = body;
+ this->endloc = endloc;
+ this->relatedLabeled = NULL;
+}
+
+Statement *ForStatement::syntaxCopy()
+{
+ return new ForStatement(loc,
+ _init ? _init->syntaxCopy() : NULL,
+ condition ? condition->syntaxCopy() : NULL,
+ increment ? increment->syntaxCopy() : NULL,
+ _body->syntaxCopy(),
+ endloc);
+}
+
+Statement *ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+ //printf("ForStatement::scopeCode()\n");
+ Statement::scopeCode(sc, sentry, sexception, sfinally);
+ return this;
+}
+
+bool ForStatement::hasBreak()
+{
+ //printf("ForStatement::hasBreak()\n");
+ return true;
+}
+
+bool ForStatement::hasContinue()
+{
+ return true;
+}
+
+/******************************** ForeachStatement ***************************/
+
+ForeachStatement::ForeachStatement(Loc loc, TOK op, Parameters *parameters,
+ Expression *aggr, Statement *body, Loc endloc)
+ : Statement(loc)
+{
+ this->op = op;
+ this->parameters = parameters;
+ this->aggr = aggr;
+ this->_body = body;
+ this->endloc = endloc;
+
+ this->key = NULL;
+ this->value = NULL;
+
+ this->func = NULL;
+
+ this->cases = NULL;
+ this->gotos = NULL;
+}
+
+Statement *ForeachStatement::syntaxCopy()
+{
+ return new ForeachStatement(loc, op,
+ Parameter::arraySyntaxCopy(parameters),
+ aggr->syntaxCopy(),
+ _body ? _body->syntaxCopy() : NULL,
+ endloc);
+}
+
+bool ForeachStatement::checkForArgTypes()
+{
+ bool result = false;
+
+ for (size_t i = 0; i < parameters->dim; i++)
+ {
+ Parameter *p = (*parameters)[i];
+ if (!p->type)
+ {
+ error("cannot infer type for %s", p->ident->toChars());
+ p->type = Type::terror;
+ result = true;
+ }
+ }
+ return result;
+}
+
+bool ForeachStatement::hasBreak()
+{
+ return true;
+}
+
+bool ForeachStatement::hasContinue()
+{
+ return true;
+}
+
+/**************************** ForeachRangeStatement ***************************/
+
+
+ForeachRangeStatement::ForeachRangeStatement(Loc loc, TOK op, Parameter *prm,
+ Expression *lwr, Expression *upr, Statement *body, Loc endloc)
+ : Statement(loc)
+{
+ this->op = op;
+ this->prm = prm;
+ this->lwr = lwr;
+ this->upr = upr;
+ this->_body = body;
+ this->endloc = endloc;
+
+ this->key = NULL;
+}
+
+Statement *ForeachRangeStatement::syntaxCopy()
+{
+ return new ForeachRangeStatement(loc, op,
+ prm->syntaxCopy(),
+ lwr->syntaxCopy(),
+ upr->syntaxCopy(),
+ _body ? _body->syntaxCopy() : NULL,
+ endloc);
+}
+
+bool ForeachRangeStatement::hasBreak()
+{
+ return true;
+}
+
+bool ForeachRangeStatement::hasContinue()
+{
+ return true;
+}
+
+/******************************** IfStatement ***************************/
+
+IfStatement::IfStatement(Loc loc, Parameter *prm, Expression *condition, Statement *ifbody, Statement *elsebody, Loc endloc)
+ : Statement(loc)
+{
+ this->prm = prm;
+ this->condition = condition;
+ this->ifbody = ifbody;
+ this->elsebody = elsebody;
+ this->endloc = endloc;
+ this->match = NULL;
+}
+
+Statement *IfStatement::syntaxCopy()
+{
+ return new IfStatement(loc,
+ prm ? prm->syntaxCopy() : NULL,
+ condition->syntaxCopy(),
+ ifbody ? ifbody->syntaxCopy() : NULL,
+ elsebody ? elsebody->syntaxCopy() : NULL,
+ endloc);
+}
+
+/******************************** ConditionalStatement ***************************/
+
+ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
+ : Statement(loc)
+{
+ this->condition = condition;
+ this->ifbody = ifbody;
+ this->elsebody = elsebody;
+}
+
+Statement *ConditionalStatement::syntaxCopy()
+{
+ return new ConditionalStatement(loc,
+ condition->syntaxCopy(),
+ ifbody->syntaxCopy(),
+ elsebody ? elsebody->syntaxCopy() : NULL);
+}
+
+Statements *ConditionalStatement::flatten(Scope *sc)
+{
+ Statement *s;
+
+ //printf("ConditionalStatement::flatten()\n");
+ if (condition->include(sc, NULL))
+ {
+ DebugCondition *dc = condition->isDebugCondition();
+ if (dc)
+ s = new DebugStatement(loc, ifbody);
+ else
+ s = ifbody;
+ }
+ else
+ s = elsebody;
+
+ Statements *a = new Statements();
+ a->push(s);
+ return a;
+}
+
+/******************************** PragmaStatement ***************************/
+
+PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
+ : Statement(loc)
+{
+ this->ident = ident;
+ this->args = args;
+ this->_body = body;
+}
+
+Statement *PragmaStatement::syntaxCopy()
+{
+ return new PragmaStatement(loc, ident,
+ Expression::arraySyntaxCopy(args),
+ _body ? _body->syntaxCopy() : NULL);
+}
+
+/******************************** StaticAssertStatement ***************************/
+
+StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
+ : Statement(sa->loc)
+{
+ this->sa = sa;
+}
+
+Statement *StaticAssertStatement::syntaxCopy()
+{
+ return new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
+}
+
+/******************************** SwitchStatement ***************************/
+
+SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal)
+ : Statement(loc)
+{
+ this->condition = c;
+ this->_body = b;
+ this->isFinal = isFinal;
+ sdefault = NULL;
+ tf = NULL;
+ cases = NULL;
+ hasNoDefault = 0;
+ hasVars = 0;
+ lastVar = NULL;
+}
+
+Statement *SwitchStatement::syntaxCopy()
+{
+ return new SwitchStatement(loc,
+ condition->syntaxCopy(),
+ _body->syntaxCopy(),
+ isFinal);
+}
+
+bool SwitchStatement::hasBreak()
+{
+ return true;
+}
+
+static bool checkVar(SwitchStatement *s, VarDeclaration *vd)
+{
+ if (!vd || vd->isDataseg() || (vd->storage_class & STCmanifest))
+ return false;
+
+ VarDeclaration *last = s->lastVar;
+ while (last && last != vd)
+ last = last->lastVar;
+ if (last == vd)
+ {
+ // All good, the label's scope has no variables
+ }
+ else if (vd->storage_class & STCexptemp)
+ {
+ // Lifetime ends at end of expression, so no issue with skipping the statement
+ }
+ else if (vd->ident == Id::withSym)
+ {
+ s->deprecation("'switch' skips declaration of 'with' temporary at %s", vd->loc.toChars());
+ return true;
+ }
+ else
+ {
+ s->deprecation("'switch' skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
+ return true;
+ }
+
+ return false;
+}
+
+bool SwitchStatement::checkLabel()
+{
+ const bool error = true;
+
+ if (sdefault && checkVar(this, sdefault->lastVar))
+ return !error; // return error once fully deprecated
+
+ for (size_t i = 0; i < cases->dim; i++)
+ {
+ CaseStatement *scase = (*cases)[i];
+ if (scase && checkVar(this, scase->lastVar))
+ return !error; // return error once fully deprecated
+ }
+ return !error;
+}
+
+/******************************** CaseStatement ***************************/
+
+CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
+ : Statement(loc)
+{
+ this->exp = exp;
+ this->statement = s;
+ index = 0;
+ lastVar = NULL;
+}
+
+Statement *CaseStatement::syntaxCopy()
+{
+ return new CaseStatement(loc,
+ exp->syntaxCopy(),
+ statement->syntaxCopy());
+}
+
+int CaseStatement::compare(RootObject *obj)
+{
+ // Sort cases so we can do an efficient lookup
+ CaseStatement *cs2 = (CaseStatement *)(obj);
+
+ return exp->compare(cs2->exp);
+}
+
+/******************************** CaseRangeStatement ***************************/
+
+
+CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first,
+ Expression *last, Statement *s)
+ : Statement(loc)
+{
+ this->first = first;
+ this->last = last;
+ this->statement = s;
+}
+
+Statement *CaseRangeStatement::syntaxCopy()
+{
+ return new CaseRangeStatement(loc,
+ first->syntaxCopy(),
+ last->syntaxCopy(),
+ statement->syntaxCopy());
+}
+
+/******************************** DefaultStatement ***************************/
+
+DefaultStatement::DefaultStatement(Loc loc, Statement *s)
+ : Statement(loc)
+{
+ this->statement = s;
+ this->lastVar = NULL;
+}
+
+Statement *DefaultStatement::syntaxCopy()
+{
+ return new DefaultStatement(loc, statement->syntaxCopy());
+}
+
+/******************************** GotoDefaultStatement ***************************/
+
+GotoDefaultStatement::GotoDefaultStatement(Loc loc)
+ : Statement(loc)
+{
+ sw = NULL;
+}
+
+Statement *GotoDefaultStatement::syntaxCopy()
+{
+ return new GotoDefaultStatement(loc);
+}
+
+/******************************** GotoCaseStatement ***************************/
+
+GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
+ : Statement(loc)
+{
+ cs = NULL;
+ this->exp = exp;
+}
+
+Statement *GotoCaseStatement::syntaxCopy()
+{
+ return new GotoCaseStatement(loc, exp ? exp->syntaxCopy() : NULL);
+}
+
+/******************************** SwitchErrorStatement ***************************/
+
+SwitchErrorStatement::SwitchErrorStatement(Loc loc)
+ : Statement(loc)
+{
+}
+
+/******************************** ReturnStatement ***************************/
+
+ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
+ : Statement(loc)
+{
+ this->exp = exp;
+ this->caseDim = 0;
+}
+
+Statement *ReturnStatement::syntaxCopy()
+{
+ return new ReturnStatement(loc, exp ? exp->syntaxCopy() : NULL);
+}
+
+/******************************** BreakStatement ***************************/
+
+BreakStatement::BreakStatement(Loc loc, Identifier *ident)
+ : Statement(loc)
+{
+ this->ident = ident;
+}
+
+Statement *BreakStatement::syntaxCopy()
+{
+ return new BreakStatement(loc, ident);
+}
+
+/******************************** ContinueStatement ***************************/
+
+ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
+ : Statement(loc)
+{
+ this->ident = ident;
+}
+
+Statement *ContinueStatement::syntaxCopy()
+{
+ return new ContinueStatement(loc, ident);
+}
+
+/******************************** SynchronizedStatement ***************************/
+
+SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
+ : Statement(loc)
+{
+ this->exp = exp;
+ this->_body = body;
+}
+
+Statement *SynchronizedStatement::syntaxCopy()
+{
+ return new SynchronizedStatement(loc,
+ exp ? exp->syntaxCopy() : NULL,
+ _body ? _body->syntaxCopy() : NULL);
+}
+
+bool SynchronizedStatement::hasBreak()
+{
+ return false; //true;
+}
+
+bool SynchronizedStatement::hasContinue()
+{
+ return false; //true;
+}
+
+/******************************** WithStatement ***************************/
+
+WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body, Loc endloc)
+ : Statement(loc)
+{
+ this->exp = exp;
+ this->_body = body;
+ this->endloc = endloc;
+ wthis = NULL;
+}
+
+Statement *WithStatement::syntaxCopy()
+{
+ return new WithStatement(loc,
+ exp->syntaxCopy(),
+ _body ? _body->syntaxCopy() : NULL, endloc);
+}
+
+/******************************** TryCatchStatement ***************************/
+
+TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Catches *catches)
+ : Statement(loc)
+{
+ this->_body = body;
+ this->catches = catches;
+}
+
+Statement *TryCatchStatement::syntaxCopy()
+{
+ Catches *a = new Catches();
+ a->setDim(catches->dim);
+ for (size_t i = 0; i < a->dim; i++)
+ {
+ Catch *c = (*catches)[i];
+ (*a)[i] = c->syntaxCopy();
+ }
+ return new TryCatchStatement(loc, _body->syntaxCopy(), a);
+}
+
+bool TryCatchStatement::hasBreak()
+{
+ return false;
+}
+
+/******************************** Catch ***************************/
+
+Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
+{
+ //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
+ this->loc = loc;
+ this->type = t;
+ this->ident = id;
+ this->handler = handler;
+ var = NULL;
+ errors = false;
+ internalCatch = false;
+}
+
+Catch *Catch::syntaxCopy()
+{
+ Catch *c = new Catch(loc,
+ type ? type->syntaxCopy() : getThrowable(),
+ ident,
+ (handler ? handler->syntaxCopy() : NULL));
+ c->internalCatch = internalCatch;
+ return c;
+}
+
+/****************************** TryFinallyStatement ***************************/
+
+TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
+ : Statement(loc)
+{
+ this->_body = body;
+ this->finalbody = finalbody;
+}
+
+TryFinallyStatement *TryFinallyStatement::create(Loc loc, Statement *body, Statement *finalbody)
+{
+ return new TryFinallyStatement(loc, body, finalbody);
+}
+
+Statement *TryFinallyStatement::syntaxCopy()
+{
+ return new TryFinallyStatement(loc,
+ _body->syntaxCopy(), finalbody->syntaxCopy());
+}
+
+bool TryFinallyStatement::hasBreak()
+{
+ return false; //true;
+}
+
+bool TryFinallyStatement::hasContinue()
+{
+ return false; //true;
+}
+
+/****************************** OnScopeStatement ***************************/
+
+OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement)
+ : Statement(loc)
+{
+ this->tok = tok;
+ this->statement = statement;
+}
+
+Statement *OnScopeStatement::syntaxCopy()
+{
+ return new OnScopeStatement(loc, tok, statement->syntaxCopy());
+}
+
+Statement *OnScopeStatement::scopeCode(Scope *, Statement **sentry, Statement **sexception, Statement **sfinally)
+{
+ //printf("OnScopeStatement::scopeCode()\n");
+ //print();
+ *sentry = NULL;
+ *sexception = NULL;
+ *sfinally = NULL;
+
+ Statement *s = new PeelStatement(statement);
+
+ switch (tok)
+ {
+ case TOKon_scope_exit:
+ *sfinally = s;
+ break;
+
+ case TOKon_scope_failure:
+ *sexception = s;
+ break;
+
+ case TOKon_scope_success:
+ {
+ /* Create:
+ * sentry: bool x = false;
+ * sexception: x = true;
+ * sfinally: if (!x) statement;
+ */
+ VarDeclaration *v = copyToTemp(0, "__os", new IntegerExp(Loc(), 0, Type::tbool));
+ *sentry = new ExpStatement(loc, v);
+
+ Expression *e = new IntegerExp(Loc(), 1, Type::tbool);
+ e = new AssignExp(Loc(), new VarExp(Loc(), v), e);
+ *sexception = new ExpStatement(Loc(), e);
+
+ e = new VarExp(Loc(), v);
+ e = new NotExp(Loc(), e);
+ *sfinally = new IfStatement(Loc(), NULL, e, s, NULL, Loc());
+
+ break;
+ }
+
+ default:
+ assert(0);
+ }
+ return NULL;
+}
+
+/******************************** ThrowStatement ***************************/
+
+ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
+ : Statement(loc)
+{
+ this->exp = exp;
+ this->internalThrow = false;
+}
+
+Statement *ThrowStatement::syntaxCopy()
+{
+ ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
+ s->internalThrow = internalThrow;
+ return s;
+}
+
+/******************************** DebugStatement **************************/
+
+DebugStatement::DebugStatement(Loc loc, Statement *statement)
+ : Statement(loc)
+{
+ this->statement = statement;
+}
+
+Statement *DebugStatement::syntaxCopy()
+{
+ return new DebugStatement(loc,
+ statement ? statement->syntaxCopy() : NULL);
+}
+
+Statements *DebugStatement::flatten(Scope *sc)
+{
+ Statements *a = statement ? statement->flatten(sc) : NULL;
+ if (a)
+ {
+ for (size_t i = 0; i < a->dim; i++)
+ { Statement *s = (*a)[i];
+
+ s = new DebugStatement(loc, s);
+ (*a)[i] = s;
+ }
+ }
+
+ return a;
+}
+
+/******************************** GotoStatement ***************************/
+
+GotoStatement::GotoStatement(Loc loc, Identifier *ident)
+ : Statement(loc)
+{
+ this->ident = ident;
+ this->label = NULL;
+ this->tf = NULL;
+ this->os = NULL;
+ this->lastVar = NULL;
+}
+
+Statement *GotoStatement::syntaxCopy()
+{
+ return new GotoStatement(loc, ident);
+}
+
+bool GotoStatement::checkLabel()
+{
+ if (!label->statement)
+ {
+ error("label '%s' is undefined", label->toChars());
+ return true;
+ }
+
+ if (label->statement->os != os)
+ {
+ if (os && os->tok == TOKon_scope_failure && !label->statement->os)
+ {
+ // Jump out from scope(failure) block is allowed.
+ }
+ else
+ {
+ if (label->statement->os)
+ error("cannot goto in to %s block", Token::toChars(label->statement->os->tok));
+ else
+ error("cannot goto out of %s block", Token::toChars(os->tok));
+ return true;
+ }
+ }
+
+ if (label->statement->tf != tf)
+ {
+ error("cannot goto in or out of finally block");
+ return true;
+ }
+
+ VarDeclaration *vd = label->statement->lastVar;
+ if (!vd || vd->isDataseg() || (vd->storage_class & STCmanifest))
+ return false;
+
+ VarDeclaration *last = lastVar;
+ while (last && last != vd)
+ last = last->lastVar;
+ if (last == vd)
+ {
+ // All good, the label's scope has no variables
+ }
+ else if (vd->ident == Id::withSym)
+ {
+ error("goto skips declaration of with temporary at %s", vd->loc.toChars());
+ return true;
+ }
+ else
+ {
+ error("goto skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
+ return true;
+ }
+
+ return false;
+}
+
+/******************************** LabelStatement ***************************/
+
+LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
+ : Statement(loc)
+{
+ this->ident = ident;
+ this->statement = statement;
+ this->tf = NULL;
+ this->os = NULL;
+ this->lastVar = NULL;
+ this->gotoTarget = NULL;
+ this->breaks = false;
+}
+
+Statement *LabelStatement::syntaxCopy()
+{
+ return new LabelStatement(loc, ident, statement ? statement->syntaxCopy() : NULL);
+}
+
+Statement *LabelStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally)
+{
+ //printf("LabelStatement::scopeCode()\n");
+ if (statement)
+ statement = statement->scopeCode(sc, sentry, sexit, sfinally);
+ else
+ {
+ *sentry = NULL;
+ *sexit = NULL;
+ *sfinally = NULL;
+ }
+ return this;
+}
+
+Statements *LabelStatement::flatten(Scope *sc)
+{
+ Statements *a = NULL;
+
+ if (statement)
+ {
+ a = statement->flatten(sc);
+ if (a)
+ {
+ if (!a->dim)
+ {
+ a->push(new ExpStatement(loc, (Expression *)NULL));
+ }
+
+ // reuse 'this' LabelStatement
+ this->statement = (*a)[0];
+ (*a)[0] = this;
+ }
+ }
+
+ return a;
+}
+
+/******************************** LabelDsymbol ***************************/
+
+LabelDsymbol::LabelDsymbol(Identifier *ident)
+ : Dsymbol(ident)
+{
+ statement = NULL;
+}
+
+LabelDsymbol *LabelDsymbol::create(Identifier *ident)
+{
+ return new LabelDsymbol(ident);
+}
+
+LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
+{
+ return this;
+}
+
+
+/************************ AsmStatement ***************************************/
+
+AsmStatement::AsmStatement(Loc loc, Token *tokens)
+ : Statement(loc)
+{
+ this->tokens = tokens;
+}
+
+Statement *AsmStatement::syntaxCopy()
+{
+ return new AsmStatement(loc, tokens);
+}
+
+
+/************************ InlineAsmStatement **********************************/
+
+InlineAsmStatement::InlineAsmStatement(Loc loc, Token *tokens)
+ : AsmStatement(loc, tokens)
+{
+ asmcode = NULL;
+ asmalign = 0;
+ refparam = false;
+ naked = false;
+ regs = 0;
+}
+
+Statement *InlineAsmStatement::syntaxCopy()
+{
+ return new InlineAsmStatement(loc, tokens);
+}
+
+
+/************************ GccAsmStatement ***************************************/
+
+GccAsmStatement::GccAsmStatement(Loc loc, Token *tokens)
+ : AsmStatement(loc, tokens)
+{
+ this->stc = STCundefined;
+ this->insn = NULL;
+ this->args = NULL;
+ this->outputargs = 0;
+ this->names = NULL;
+ this->constraints = NULL;
+ this->clobbers = NULL;
+ this->labels = NULL;
+ this->gotos = NULL;
+}
+
+Statement *GccAsmStatement::syntaxCopy()
+{
+ return new GccAsmStatement(loc, tokens);
+}
+
+/************************ CompoundAsmStatement ***************************************/
+
+CompoundAsmStatement::CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc)
+ : CompoundStatement(loc, s)
+{
+ this->stc = stc;
+}
+
+CompoundAsmStatement *CompoundAsmStatement::syntaxCopy()
+{
+ Statements *a = new Statements();
+ a->setDim(statements->dim);
+ for (size_t i = 0; i < statements->dim; i++)
+ {
+ Statement *s = (*statements)[i];
+ (*a)[i] = s ? s->syntaxCopy() : NULL;
+ }
+ return new CompoundAsmStatement(loc, a, stc);
+}
+
+Statements *CompoundAsmStatement::flatten(Scope *)
+{
+ return NULL;
+}
+
+/************************ ImportStatement ***************************************/
+
+ImportStatement::ImportStatement(Loc loc, Dsymbols *imports)
+ : Statement(loc)
+{
+ this->imports = imports;
+}
+
+Statement *ImportStatement::syntaxCopy()
+{
+ Dsymbols *m = new Dsymbols();
+ m->setDim(imports->dim);
+ for (size_t i = 0; i < imports->dim; i++)
+ {
+ Dsymbol *s = (*imports)[i];
+ (*m)[i] = s->syntaxCopy(NULL);
+ }
+ return new ImportStatement(loc, m);
+}
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
new file mode 100644
index 0000000..269d8ed
--- /dev/null
+++ b/gcc/d/dmd/statement.h
@@ -0,0 +1,783 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/statement.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+
+#include "arraytypes.h"
+#include "dsymbol.h"
+#include "visitor.h"
+#include "tokens.h"
+
+struct OutBuffer;
+struct Scope;
+class Expression;
+class LabelDsymbol;
+class Identifier;
+class IfStatement;
+class ExpStatement;
+class DefaultStatement;
+class VarDeclaration;
+class Condition;
+class Module;
+struct Token;
+class ErrorStatement;
+class ReturnStatement;
+class CompoundStatement;
+class Parameter;
+class StaticAssert;
+class AsmStatement;
+class GotoStatement;
+class ScopeStatement;
+class TryCatchStatement;
+class TryFinallyStatement;
+class CaseStatement;
+class DefaultStatement;
+class LabelStatement;
+class StaticForeach;
+
+// Back end
+struct code;
+
+bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
+bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
+
+/* How a statement exits; this is returned by blockExit()
+ */
+enum BE
+{
+ BEnone = 0,
+ BEfallthru = 1,
+ BEthrow = 2,
+ BEreturn = 4,
+ BEgoto = 8,
+ BEhalt = 0x10,
+ BEbreak = 0x20,
+ BEcontinue = 0x40,
+ BEerrthrow = 0x80,
+ BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt)
+};
+
+class Statement : public RootObject
+{
+public:
+ Loc loc;
+
+ Statement(Loc loc);
+ virtual Statement *syntaxCopy();
+
+ void print();
+ const char *toChars();
+
+ void error(const char *format, ...);
+ void warning(const char *format, ...);
+ void deprecation(const char *format, ...);
+ virtual Statement *getRelatedLabeled() { return this; }
+ virtual bool hasBreak();
+ virtual bool hasContinue();
+ bool usesEH();
+ bool comeFrom();
+ bool hasCode();
+ virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+ virtual Statements *flatten(Scope *sc);
+ virtual Statement *last();
+
+ // Avoid dynamic_cast
+ virtual ErrorStatement *isErrorStatement() { return NULL; }
+ virtual ScopeStatement *isScopeStatement() { return NULL; }
+ virtual ExpStatement *isExpStatement() { return NULL; }
+ virtual CompoundStatement *isCompoundStatement() { return NULL; }
+ virtual ReturnStatement *isReturnStatement() { return NULL; }
+ virtual IfStatement *isIfStatement() { return NULL; }
+ virtual CaseStatement *isCaseStatement() { return NULL; }
+ virtual DefaultStatement *isDefaultStatement() { return NULL; }
+ virtual LabelStatement *isLabelStatement() { return NULL; }
+ virtual GotoDefaultStatement *isGotoDefaultStatement() { return NULL; }
+ virtual GotoCaseStatement *isGotoCaseStatement() { return NULL; }
+ virtual BreakStatement *isBreakStatement() { return NULL; }
+ virtual DtorExpStatement *isDtorExpStatement() { return NULL; }
+ virtual ForwardingStatement *isForwardingStatement() { return NULL; }
+ virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+/** Any Statement that fails semantic() or has a component that is an ErrorExp or
+ * a TypeError should return an ErrorStatement from semantic().
+ */
+class ErrorStatement : public Statement
+{
+public:
+ ErrorStatement();
+ Statement *syntaxCopy();
+
+ ErrorStatement *isErrorStatement() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PeelStatement : public Statement
+{
+public:
+ Statement *s;
+
+ PeelStatement(Statement *s);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ExpStatement : public Statement
+{
+public:
+ Expression *exp;
+
+ ExpStatement(Loc loc, Expression *exp);
+ ExpStatement(Loc loc, Dsymbol *s);
+ static ExpStatement *create(Loc loc, Expression *exp);
+ Statement *syntaxCopy();
+ Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+ Statements *flatten(Scope *sc);
+
+ ExpStatement *isExpStatement() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DtorExpStatement : public ExpStatement
+{
+public:
+ /* Wraps an expression that is the destruction of 'var'
+ */
+
+ VarDeclaration *var;
+
+ DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v);
+ Statement *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+
+ DtorExpStatement *isDtorExpStatement() { return this; }
+};
+
+class CompileStatement : public Statement
+{
+public:
+ Expression *exp;
+
+ CompileStatement(Loc loc, Expression *exp);
+ Statement *syntaxCopy();
+ Statements *flatten(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CompoundStatement : public Statement
+{
+public:
+ Statements *statements;
+
+ CompoundStatement(Loc loc, Statements *s);
+ CompoundStatement(Loc loc, Statement *s1);
+ CompoundStatement(Loc loc, Statement *s1, Statement *s2);
+ static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
+ Statement *syntaxCopy();
+ Statements *flatten(Scope *sc);
+ ReturnStatement *isReturnStatement();
+ Statement *last();
+
+ CompoundStatement *isCompoundStatement() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CompoundDeclarationStatement : public CompoundStatement
+{
+public:
+ CompoundDeclarationStatement(Loc loc, Statements *s);
+ Statement *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* The purpose of this is so that continue will go to the next
+ * of the statements, and break will go to the end of the statements.
+ */
+class UnrolledLoopStatement : public Statement
+{
+public:
+ Statements *statements;
+
+ UnrolledLoopStatement(Loc loc, Statements *statements);
+ Statement *syntaxCopy();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ScopeStatement : public Statement
+{
+public:
+ Statement *statement;
+ Loc endloc; // location of closing curly bracket
+
+ ScopeStatement(Loc loc, Statement *s, Loc endloc);
+ Statement *syntaxCopy();
+ ScopeStatement *isScopeStatement() { return this; }
+ ReturnStatement *isReturnStatement();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForwardingStatement : public Statement
+{
+ ForwardingScopeDsymbol *sym;
+ Statement *statement;
+
+ Statement *syntaxCopy();
+ Statement *getRelatedLabeled();
+ bool hasBreak();
+ bool hasContinue();
+ Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally);
+ Statement *last();
+ Statements *flatten(Scope *sc);
+ ForwardingStatement *isForwardingStatement() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class WhileStatement : public Statement
+{
+public:
+ Expression *condition;
+ Statement *_body;
+ Loc endloc; // location of closing curly bracket
+
+ WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc);
+ Statement *syntaxCopy();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DoStatement : public Statement
+{
+public:
+ Statement *_body;
+ Expression *condition;
+ Loc endloc; // location of ';' after while
+
+ DoStatement(Loc loc, Statement *b, Expression *c, Loc endloc);
+ Statement *syntaxCopy();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForStatement : public Statement
+{
+public:
+ Statement *_init;
+ Expression *condition;
+ Expression *increment;
+ Statement *_body;
+ Loc endloc; // location of closing curly bracket
+
+ // When wrapped in try/finally clauses, this points to the outermost one,
+ // which may have an associated label. Internal break/continue statements
+ // treat that label as referring to this loop.
+ Statement *relatedLabeled;
+
+ ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body, Loc endloc);
+ Statement *syntaxCopy();
+ Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+ Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; }
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForeachStatement : public Statement
+{
+public:
+ TOK op; // TOKforeach or TOKforeach_reverse
+ Parameters *parameters; // array of Parameter*'s
+ Expression *aggr;
+ Statement *_body;
+ Loc endloc; // location of closing curly bracket
+
+ VarDeclaration *key;
+ VarDeclaration *value;
+
+ FuncDeclaration *func; // function we're lexically in
+
+ Statements *cases; // put breaks, continues, gotos and returns here
+ ScopeStatements *gotos; // forward referenced goto's go here
+
+ ForeachStatement(Loc loc, TOK op, Parameters *parameters, Expression *aggr, Statement *body, Loc endloc);
+ Statement *syntaxCopy();
+ bool checkForArgTypes();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ForeachRangeStatement : public Statement
+{
+public:
+ TOK op; // TOKforeach or TOKforeach_reverse
+ Parameter *prm; // loop index variable
+ Expression *lwr;
+ Expression *upr;
+ Statement *_body;
+ Loc endloc; // location of closing curly bracket
+
+ VarDeclaration *key;
+
+ ForeachRangeStatement(Loc loc, TOK op, Parameter *prm,
+ Expression *lwr, Expression *upr, Statement *body, Loc endloc);
+ Statement *syntaxCopy();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class IfStatement : public Statement
+{
+public:
+ Parameter *prm;
+ Expression *condition;
+ Statement *ifbody;
+ Statement *elsebody;
+ Loc endloc; // location of closing curly bracket
+
+ VarDeclaration *match; // for MatchExpression results
+
+ IfStatement(Loc loc, Parameter *prm, Expression *condition, Statement *ifbody, Statement *elsebody, Loc endloc);
+ Statement *syntaxCopy();
+ IfStatement *isIfStatement() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ConditionalStatement : public Statement
+{
+public:
+ Condition *condition;
+ Statement *ifbody;
+ Statement *elsebody;
+
+ ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody);
+ Statement *syntaxCopy();
+ Statements *flatten(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticForeachStatement : public Statement
+{
+public:
+ StaticForeach *sfe;
+
+ Statement *syntaxCopy();
+ Statements *flatten(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class PragmaStatement : public Statement
+{
+public:
+ Identifier *ident;
+ Expressions *args; // array of Expression's
+ Statement *_body;
+
+ PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body);
+ Statement *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class StaticAssertStatement : public Statement
+{
+public:
+ StaticAssert *sa;
+
+ StaticAssertStatement(StaticAssert *sa);
+ Statement *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SwitchStatement : public Statement
+{
+public:
+ Expression *condition;
+ Statement *_body;
+ bool isFinal;
+
+ DefaultStatement *sdefault;
+ TryFinallyStatement *tf;
+ GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's
+ CaseStatements *cases; // array of CaseStatement's
+ int hasNoDefault; // !=0 if no default statement
+ int hasVars; // !=0 if has variable case values
+ VarDeclaration *lastVar;
+
+ SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal);
+ Statement *syntaxCopy();
+ bool hasBreak();
+ bool checkLabel();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class CaseStatement : public Statement
+{
+public:
+ Expression *exp;
+ Statement *statement;
+
+ int index; // which case it is (since we sort this)
+ VarDeclaration *lastVar;
+
+ CaseStatement(Loc loc, Expression *exp, Statement *s);
+ Statement *syntaxCopy();
+ int compare(RootObject *obj);
+ CaseStatement *isCaseStatement() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class CaseRangeStatement : public Statement
+{
+public:
+ Expression *first;
+ Expression *last;
+ Statement *statement;
+
+ CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s);
+ Statement *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+
+class DefaultStatement : public Statement
+{
+public:
+ Statement *statement;
+ VarDeclaration *lastVar;
+
+ DefaultStatement(Loc loc, Statement *s);
+ Statement *syntaxCopy();
+ DefaultStatement *isDefaultStatement() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class GotoDefaultStatement : public Statement
+{
+public:
+ SwitchStatement *sw;
+
+ GotoDefaultStatement(Loc loc);
+ Statement *syntaxCopy();
+ GotoDefaultStatement *isGotoDefaultStatement() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class GotoCaseStatement : public Statement
+{
+public:
+ Expression *exp; // NULL, or which case to goto
+ CaseStatement *cs; // case statement it resolves to
+
+ GotoCaseStatement(Loc loc, Expression *exp);
+ Statement *syntaxCopy();
+ GotoCaseStatement *isGotoCaseStatement() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SwitchErrorStatement : public Statement
+{
+public:
+ SwitchErrorStatement(Loc loc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ReturnStatement : public Statement
+{
+public:
+ Expression *exp;
+ size_t caseDim;
+
+ ReturnStatement(Loc loc, Expression *exp);
+ Statement *syntaxCopy();
+
+ ReturnStatement *isReturnStatement() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class BreakStatement : public Statement
+{
+public:
+ Identifier *ident;
+
+ BreakStatement(Loc loc, Identifier *ident);
+ Statement *syntaxCopy();
+
+ BreakStatement *isBreakStatement() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ContinueStatement : public Statement
+{
+public:
+ Identifier *ident;
+
+ ContinueStatement(Loc loc, Identifier *ident);
+ Statement *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class SynchronizedStatement : public Statement
+{
+public:
+ Expression *exp;
+ Statement *_body;
+
+ SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
+ Statement *syntaxCopy();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class WithStatement : public Statement
+{
+public:
+ Expression *exp;
+ Statement *_body;
+ VarDeclaration *wthis;
+ Loc endloc;
+
+ WithStatement(Loc loc, Expression *exp, Statement *body, Loc endloc);
+ Statement *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TryCatchStatement : public Statement
+{
+public:
+ Statement *_body;
+ Catches *catches;
+
+ TryCatchStatement(Loc loc, Statement *body, Catches *catches);
+ Statement *syntaxCopy();
+ bool hasBreak();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class Catch : public RootObject
+{
+public:
+ Loc loc;
+ Type *type;
+ Identifier *ident;
+ VarDeclaration *var;
+ Statement *handler;
+
+ // set if semantic processing errors
+ bool errors;
+
+ // was generated by the compiler,
+ // wasn't present in source code
+ bool internalCatch;
+
+ Catch(Loc loc, Type *t, Identifier *id, Statement *handler);
+ Catch *syntaxCopy();
+};
+
+class TryFinallyStatement : public Statement
+{
+public:
+ Statement *_body;
+ Statement *finalbody;
+
+ TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
+ static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody);
+ Statement *syntaxCopy();
+ bool hasBreak();
+ bool hasContinue();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class OnScopeStatement : public Statement
+{
+public:
+ TOK tok;
+ Statement *statement;
+
+ OnScopeStatement(Loc loc, TOK tok, Statement *statement);
+ Statement *syntaxCopy();
+ Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ThrowStatement : public Statement
+{
+public:
+ Expression *exp;
+ // was generated by the compiler,
+ // wasn't present in source code
+ bool internalThrow;
+
+ ThrowStatement(Loc loc, Expression *exp);
+ Statement *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class DebugStatement : public Statement
+{
+public:
+ Statement *statement;
+
+ DebugStatement(Loc loc, Statement *statement);
+ Statement *syntaxCopy();
+ Statements *flatten(Scope *sc);
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class GotoStatement : public Statement
+{
+public:
+ Identifier *ident;
+ LabelDsymbol *label;
+ TryFinallyStatement *tf;
+ OnScopeStatement *os;
+ VarDeclaration *lastVar;
+
+ GotoStatement(Loc loc, Identifier *ident);
+ Statement *syntaxCopy();
+ bool checkLabel();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class LabelStatement : public Statement
+{
+public:
+ Identifier *ident;
+ Statement *statement;
+ TryFinallyStatement *tf;
+ OnScopeStatement *os;
+ VarDeclaration *lastVar;
+ Statement *gotoTarget; // interpret
+
+ bool breaks; // someone did a 'break ident'
+
+ LabelStatement(Loc loc, Identifier *ident, Statement *statement);
+ Statement *syntaxCopy();
+ Statements *flatten(Scope *sc);
+ Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+
+ LabelStatement *isLabelStatement() { return this; }
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class LabelDsymbol : public Dsymbol
+{
+public:
+ LabelStatement *statement;
+
+ LabelDsymbol(Identifier *ident);
+ static LabelDsymbol *create(Identifier *ident);
+ LabelDsymbol *isLabel();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+Statement* asmSemantic(AsmStatement *s, Scope *sc);
+
+class AsmStatement : public Statement
+{
+public:
+ Token *tokens;
+
+ AsmStatement(Loc loc, Token *tokens);
+ Statement *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class InlineAsmStatement : public AsmStatement
+{
+public:
+ code *asmcode;
+ unsigned asmalign; // alignment of this statement
+ unsigned regs; // mask of registers modified (must match regm_t in back end)
+ bool refparam; // true if function parameter is referenced
+ bool naked; // true if function is to be naked
+
+ InlineAsmStatement(Loc loc, Token *tokens);
+ Statement *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// A GCC asm statement - assembler instructions with D expression operands
+class GccAsmStatement : public AsmStatement
+{
+public:
+ StorageClass stc; // attributes of the asm {} block
+ Expression *insn; // string expression that is the template for assembler code
+ Expressions *args; // input and output operands of the statement
+ unsigned outputargs; // of the operands in 'args', the number of output operands
+ Identifiers *names; // list of symbolic names for the operands
+ Expressions *constraints; // list of string constants specifying constraints on operands
+ Expressions *clobbers; // list of string constants specifying clobbers and scratch registers
+ Identifiers *labels; // list of goto labels
+ GotoStatements *gotos; // of the goto labels, the equivalent statements they represent
+
+ GccAsmStatement(Loc loc, Token *tokens);
+ Statement *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+// a complete asm {} block
+class CompoundAsmStatement : public CompoundStatement
+{
+public:
+ StorageClass stc; // postfix attributes like nothrow/pure/@trusted
+
+ CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc);
+ CompoundAsmStatement *syntaxCopy();
+ Statements *flatten(Scope *sc);
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class ImportStatement : public Statement
+{
+public:
+ Dsymbols *imports; // Array of Import's
+
+ ImportStatement(Loc loc, Dsymbols *imports);
+ Statement *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
new file mode 100644
index 0000000..7ee541c
--- /dev/null
+++ b/gcc/d/dmd/statementsem.c
@@ -0,0 +1,3574 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "root/rmem.h"
+#include "checkedint.h"
+
+#include "errors.h"
+#include "statement.h"
+#include "expression.h"
+#include "cond.h"
+#include "init.h"
+#include "staticassert.h"
+#include "module.h"
+#include "scope.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "id.h"
+#include "enum.h"
+#include "template.h"
+#include "import.h"
+#include "target.h"
+#include "visitor.h"
+
+StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
+bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag);
+bool checkThrowEscape(Scope *sc, Expression *e, bool gag);
+LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement);
+Identifier *fixupLabelName(Scope *sc, Identifier *ident);
+FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
+VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
+Expression *checkAssignmentAsCondition(Expression *e);
+TypeIdentifier *getThrowable();
+
+Expression *semantic(Expression *e, Scope *sc);
+Statement *semantic(Statement *s, Scope *sc);
+void semantic(Catch *c, Scope *sc);
+Statement *semanticNoScope(Statement *s, Scope *sc);
+Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue);
+int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
+
+class StatementSemanticVisitor : public Visitor
+{
+public:
+ Statement *result;
+ Scope *sc;
+
+ StatementSemanticVisitor(Scope *sc)
+ {
+ this->result = NULL;
+ this->sc = sc;
+ }
+
+private:
+ void setError()
+ {
+ result = new ErrorStatement();
+ }
+
+public:
+ void visit(Statement *s)
+ {
+ result = s;
+ }
+
+ void visit(ErrorStatement *s)
+ {
+ result = s;
+ }
+
+ void visit(PeelStatement *s)
+ {
+ /* "peel" off this wrapper, and don't run semantic()
+ * on the result.
+ */
+ result = s->s;
+ }
+
+ void visit(ExpStatement *s)
+ {
+ if (s->exp)
+ {
+ //printf("ExpStatement::semantic() %s\n", s->exp->toChars());
+
+ // Allow CommaExp in ExpStatement because return isn't used
+ if (s->exp->op == TOKcomma)
+ ((CommaExp *)s->exp)->allowCommaExp = true;
+
+ s->exp = semantic(s->exp, sc);
+ s->exp = resolveProperties(sc, s->exp);
+ s->exp = s->exp->addDtorHook(sc);
+ if (FuncDeclaration *f = isFuncAddress(s->exp))
+ {
+ if (f->checkForwardRef(s->exp->loc))
+ s->exp = new ErrorExp();
+ }
+ if (discardValue(s->exp))
+ s->exp = new ErrorExp();
+
+ s->exp = s->exp->optimize(WANTvalue);
+ s->exp = checkGC(sc, s->exp);
+ if (s->exp->op == TOKerror)
+ return setError();
+ }
+ result = s;
+ }
+
+ void visit(CompileStatement *cs)
+ {
+ //printf("CompileStatement::semantic() %s\n", cs->exp->toChars());
+ Statements *a = cs->flatten(sc);
+ if (!a)
+ return;
+ Statement *s = new CompoundStatement(cs->loc, a);
+ result = semantic(s, sc);
+ }
+
+ void visit(CompoundStatement *cs)
+ {
+ //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc);
+ for (size_t i = 0; i < cs->statements->dim; )
+ {
+ Statement *s = (*cs->statements)[i];
+ if (s)
+ {
+ Statements *flt = s->flatten(sc);
+ if (flt)
+ {
+ cs->statements->remove(i);
+ cs->statements->insert(i, flt);
+ continue;
+ }
+ s = semantic(s, sc);
+ (*cs->statements)[i] = s;
+ if (s)
+ {
+ Statement *sentry;
+ Statement *sexception;
+ Statement *sfinally;
+
+ (*cs->statements)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally);
+ if (sentry)
+ {
+ sentry = semantic(sentry, sc);
+ cs->statements->insert(i, sentry);
+ i++;
+ }
+ if (sexception)
+ sexception = semantic(sexception, sc);
+ if (sexception)
+ {
+ if (i + 1 == cs->statements->dim && !sfinally)
+ {
+ }
+ else
+ {
+ /* Rewrite:
+ * s; s1; s2;
+ * As:
+ * s;
+ * try { s1; s2; }
+ * catch (Throwable __o)
+ * { sexception; throw __o; }
+ */
+ Statements *a = new Statements();
+ for (size_t j = i + 1; j < cs->statements->dim; j++)
+ {
+ a->push((*cs->statements)[j]);
+ }
+ Statement *body = new CompoundStatement(Loc(), a);
+ body = new ScopeStatement(Loc(), body, Loc());
+
+ Identifier *id = Identifier::generateId("__o");
+
+ Statement *handler = new PeelStatement(sexception);
+ if (blockExit(sexception, sc->func, false) & BEfallthru)
+ {
+ ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
+ ts->internalThrow = true;
+ handler = new CompoundStatement(Loc(), handler, ts);
+ }
+
+ Catches *catches = new Catches();
+ Catch *ctch = new Catch(Loc(), getThrowable(), id, handler);
+ ctch->internalCatch = true;
+ catches->push(ctch);
+
+ s = new TryCatchStatement(Loc(), body, catches);
+ if (sfinally)
+ s = new TryFinallyStatement(Loc(), s, sfinally);
+ s = semantic(s, sc);
+
+ cs->statements->setDim(i + 1);
+ cs->statements->push(s);
+ break;
+ }
+ }
+ else if (sfinally)
+ {
+ if (0 && i + 1 == cs->statements->dim)
+ {
+ cs->statements->push(sfinally);
+ }
+ else
+ {
+ /* Rewrite:
+ * s; s1; s2;
+ * As:
+ * s; try { s1; s2; } finally { sfinally; }
+ */
+ Statements *a = new Statements();
+ for (size_t j = i + 1; j < cs->statements->dim; j++)
+ {
+ a->push((*cs->statements)[j]);
+ }
+ Statement *body = new CompoundStatement(Loc(), a);
+ s = new TryFinallyStatement(Loc(), body, sfinally);
+ s = semantic(s, sc);
+ cs->statements->setDim(i + 1);
+ cs->statements->push(s);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Remove NULL statements from the list.
+ */
+ cs->statements->remove(i);
+ continue;
+ }
+ }
+ i++;
+ }
+ for (size_t i = 0; i < cs->statements->dim; ++i)
+ {
+ Lagain:
+ Statement *s = (*cs->statements)[i];
+ if (!s)
+ continue;
+
+ Statement *se = s->isErrorStatement();
+ if (se)
+ {
+ result = se;
+ return;
+ }
+
+ /* Bugzilla 11653: 'semantic' may return another CompoundStatement
+ * (eg. CaseRangeStatement), so flatten it here.
+ */
+ Statements *flt = s->flatten(sc);
+ if (flt)
+ {
+ cs->statements->remove(i);
+ cs->statements->insert(i, flt);
+ if (cs->statements->dim <= i)
+ break;
+ goto Lagain;
+ }
+ }
+ if (cs->statements->dim == 1)
+ {
+ result = (*cs->statements)[0];
+ return;
+ }
+ result = cs;
+ }
+
+ void visit(UnrolledLoopStatement *uls)
+ {
+ //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc);
+ Scope *scd = sc->push();
+ scd->sbreak = uls;
+ scd->scontinue = uls;
+
+ Statement *serror = NULL;
+ for (size_t i = 0; i < uls->statements->dim; i++)
+ {
+ Statement *s = (*uls->statements)[i];
+ if (s)
+ {
+ //printf("[%d]: %s\n", i, s->toChars());
+ s = semantic(s, scd);
+ (*uls->statements)[i] = s;
+
+ if (s && !serror)
+ serror = s->isErrorStatement();
+ }
+ }
+
+ scd->pop();
+ result = serror ? serror : uls;
+ }
+
+ void visit(ScopeStatement *ss)
+ {
+ ScopeDsymbol *sym;
+ //printf("ScopeStatement::semantic(sc = %p)\n", sc);
+ if (ss->statement)
+ {
+ sym = new ScopeDsymbol();
+ sym->parent = sc->scopesym;
+ sym->endlinnum = ss->endloc.linnum;
+ sc = sc->push(sym);
+
+ Statements *a = ss->statement->flatten(sc);
+ if (a)
+ {
+ ss->statement = new CompoundStatement(ss->loc, a);
+ }
+
+ ss->statement = semantic(ss->statement, sc);
+ if (ss->statement)
+ {
+ if (ss->statement->isErrorStatement())
+ {
+ sc->pop();
+ result = ss->statement;
+ return;
+ }
+
+ Statement *sentry;
+ Statement *sexception;
+ Statement *sfinally;
+
+ ss->statement = ss->statement->scopeCode(sc, &sentry, &sexception, &sfinally);
+ assert(!sentry);
+ assert(!sexception);
+ if (sfinally)
+ {
+ //printf("adding sfinally\n");
+ sfinally = semantic(sfinally, sc);
+ ss->statement = new CompoundStatement(ss->loc, ss->statement, sfinally);
+ }
+ }
+
+ sc->pop();
+ }
+ result = ss;
+ }
+
+ void visit(WhileStatement *ws)
+ {
+ /* Rewrite as a for(;condition;) loop
+ */
+ Statement *s = new ForStatement(ws->loc, NULL, ws->condition, NULL, ws->_body, ws->endloc);
+ s = semantic(s, sc);
+ result = s;
+ }
+
+ void visit(DoStatement *ds)
+ {
+ sc->noctor++;
+ if (ds->_body)
+ ds->_body = semanticScope(ds->_body, sc, ds, ds);
+ sc->noctor--;
+
+ if (ds->condition->op == TOKdotid)
+ ((DotIdExp *)ds->condition)->noderef = true;
+
+ // check in syntax level
+ ds->condition = checkAssignmentAsCondition(ds->condition);
+
+ ds->condition = semantic(ds->condition, sc);
+ ds->condition = resolveProperties(sc, ds->condition);
+ ds->condition = ds->condition->optimize(WANTvalue);
+ ds->condition = checkGC(sc, ds->condition);
+
+ ds->condition = ds->condition->toBoolean(sc);
+
+ if (ds->condition->op == TOKerror)
+ return setError();
+
+ if (ds->_body && ds->_body->isErrorStatement())
+ {
+ result = ds->_body;
+ return;
+ }
+
+ result = ds;
+ }
+
+ void visit(ForStatement *fs)
+ {
+ //printf("ForStatement::semantic %s\n", toChars());
+
+ if (fs->_init)
+ {
+ /* Rewrite:
+ * for (auto v1 = i1, v2 = i2; condition; increment) { ... }
+ * to:
+ * { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } }
+ * then lowered to:
+ * auto v1 = i1;
+ * try {
+ * auto v2 = i2;
+ * try {
+ * for (; condition; increment) { ... }
+ * } finally { v2.~this(); }
+ * } finally { v1.~this(); }
+ */
+ Statements *ainit = new Statements();
+ ainit->push(fs->_init);
+ fs->_init = NULL;
+ ainit->push(fs);
+ Statement *s = new CompoundStatement(fs->loc, ainit);
+ s = new ScopeStatement(fs->loc, s, fs->endloc);
+ s = semantic(s, sc);
+ if (!s->isErrorStatement())
+ {
+ if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+ ls->gotoTarget = fs;
+ fs->relatedLabeled = s;
+ }
+ result = s;
+ return;
+ }
+ assert(fs->_init == NULL);
+
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc->scopesym;
+ sym->endlinnum = fs->endloc.linnum;
+ sc = sc->push(sym);
+
+ sc->noctor++;
+ if (fs->condition)
+ {
+ if (fs->condition->op == TOKdotid)
+ ((DotIdExp *)fs->condition)->noderef = true;
+
+ // check in syntax level
+ fs->condition = checkAssignmentAsCondition(fs->condition);
+
+ fs->condition = semantic(fs->condition, sc);
+ fs->condition = resolveProperties(sc, fs->condition);
+ fs->condition = fs->condition->optimize(WANTvalue);
+ fs->condition = checkGC(sc, fs->condition);
+ fs->condition = fs->condition->toBoolean(sc);
+ }
+ if (fs->increment)
+ {
+ if (fs->increment->op == TOKcomma)
+ ((CommaExp *)fs->increment)->allowCommaExp = true;
+ fs->increment = semantic(fs->increment, sc);
+ fs->increment = resolveProperties(sc, fs->increment);
+ fs->increment = fs->increment->optimize(WANTvalue);
+ fs->increment = checkGC(sc, fs->increment);
+ }
+
+ sc->sbreak = fs;
+ sc->scontinue = fs;
+ if (fs->_body)
+ fs->_body = semanticNoScope(fs->_body, sc);
+ sc->noctor--;
+
+ sc->pop();
+
+ if ((fs->condition && fs->condition->op == TOKerror) ||
+ (fs->increment && fs->increment->op == TOKerror) ||
+ (fs->_body && fs->_body->isErrorStatement()))
+ return setError();
+
+ result = fs;
+ }
+
+ void visit(ForeachStatement *fs)
+ {
+ //printf("ForeachStatement::semantic() %p\n", fs);
+ ScopeDsymbol *sym;
+ Statement *s = fs;
+ Loc loc = fs->loc;
+ size_t dim = fs->parameters->dim;
+ TypeAArray *taa = NULL;
+ Dsymbol *sapply = NULL;
+
+ Type *tn = NULL;
+ Type *tnv = NULL;
+
+ fs->func = sc->func;
+ if (fs->func->fes)
+ fs->func = fs->func->fes->func;
+
+ VarDeclaration *vinit = NULL;
+ fs->aggr = semantic(fs->aggr, sc);
+ fs->aggr = resolveProperties(sc, fs->aggr);
+ fs->aggr = fs->aggr->optimize(WANTvalue);
+ if (fs->aggr->op == TOKerror)
+ return setError();
+
+ Expression *oaggr = fs->aggr;
+ if (fs->aggr->type && fs->aggr->type->toBasetype()->ty == Tstruct &&
+ ((TypeStruct *)(fs->aggr->type->toBasetype()))->sym->dtor &&
+ fs->aggr->op != TOKtype && !fs->aggr->isLvalue())
+ {
+ // Bugzilla 14653: Extend the life of rvalue aggregate till the end of foreach.
+ vinit = copyToTemp(STCrvalue, "__aggr", fs->aggr);
+ vinit->semantic(sc);
+ fs->aggr = new VarExp(fs->aggr->loc, vinit);
+ }
+
+ if (!inferAggregate(fs, sc, sapply))
+ {
+ const char *msg = "";
+ if (fs->aggr->type && isAggregate(fs->aggr->type))
+ {
+ msg = ", define opApply(), range primitives, or use .tupleof";
+ }
+ fs->error("invalid foreach aggregate %s%s", oaggr->toChars(), msg);
+ return setError();
+ }
+
+ Dsymbol* sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
+
+ /* Check for inference errors
+ */
+ if (!inferApplyArgTypes(fs, sc, sapply))
+ {
+ /**
+ Try and extract the parameter count of the opApply callback function, e.g.:
+ int opApply(int delegate(int, float)) => 2 args
+ */
+ bool foundMismatch = false;
+ size_t foreachParamCount = 0;
+ if (sapplyOld)
+ {
+ if (FuncDeclaration *fd = sapplyOld->isFuncDeclaration())
+ {
+ int fvarargs; // ignored (opApply shouldn't take variadics)
+ Parameters *fparameters = fd->getParameters(&fvarargs);
+
+ if (Parameter::dim(fparameters) == 1)
+ {
+ // first param should be the callback function
+ Parameter *fparam = Parameter::getNth(fparameters, 0);
+ if ((fparam->type->ty == Tpointer || fparam->type->ty == Tdelegate) &&
+ fparam->type->nextOf()->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)fparam->type->nextOf();
+ foreachParamCount = Parameter::dim(tf->parameters);
+ foundMismatch = true;
+ }
+ }
+ }
+ }
+
+ //printf("dim = %d, parameters->dim = %d\n", dim, fs->parameters->dim);
+ if (foundMismatch && dim != foreachParamCount)
+ {
+ const char *plural = foreachParamCount > 1 ? "s" : "";
+ fs->error("cannot infer argument types, expected %d argument%s, not %d",
+ foreachParamCount, plural, dim);
+ }
+ else
+ fs->error("cannot uniquely infer foreach argument types");
+
+ return setError();
+ }
+
+ Type *tab = fs->aggr->type->toBasetype();
+
+ if (tab->ty == Ttuple) // don't generate new scope for tuple loops
+ {
+ if (dim < 1 || dim > 2)
+ {
+ fs->error("only one (value) or two (key,value) arguments for tuple foreach");
+ return setError();
+ }
+
+ Type *paramtype = (*fs->parameters)[dim-1]->type;
+ if (paramtype)
+ {
+ paramtype = paramtype->semantic(loc, sc);
+ if (paramtype->ty == Terror)
+ return setError();
+ }
+
+ TypeTuple *tuple = (TypeTuple *)tab;
+ Statements *statements = new Statements();
+ //printf("aggr: op = %d, %s\n", fs->aggr->op, fs->aggr->toChars());
+ size_t n;
+ TupleExp *te = NULL;
+ if (fs->aggr->op == TOKtuple) // expression tuple
+ {
+ te = (TupleExp *)fs->aggr;
+ n = te->exps->dim;
+ }
+ else if (fs->aggr->op == TOKtype) // type tuple
+ {
+ n = Parameter::dim(tuple->arguments);
+ }
+ else
+ assert(0);
+ for (size_t j = 0; j < n; j++)
+ {
+ size_t k = (fs->op == TOKforeach) ? j : n - 1 - j;
+ Expression *e = NULL;
+ Type *t = NULL;
+ if (te)
+ e = (*te->exps)[k];
+ else
+ t = Parameter::getNth(tuple->arguments, k)->type;
+ Parameter *p = (*fs->parameters)[0];
+ Statements *st = new Statements();
+
+ if (dim == 2)
+ {
+ // Declare key
+ if (p->storageClass & (STCout | STCref | STClazy))
+ {
+ fs->error("no storage class for key %s", p->ident->toChars());
+ return setError();
+ }
+ p->type = p->type->semantic(loc, sc);
+ TY keyty = p->type->ty;
+ if (keyty != Tint32 && keyty != Tuns32)
+ {
+ if (global.params.isLP64)
+ {
+ if (keyty != Tint64 && keyty != Tuns64)
+ {
+ fs->error("foreach: key type must be int or uint, long or ulong, not %s", p->type->toChars());
+ return setError();
+ }
+ }
+ else
+ {
+ fs->error("foreach: key type must be int or uint, not %s", p->type->toChars());
+ return setError();
+ }
+ }
+ Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k));
+ VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, ie);
+ var->storage_class |= STCmanifest;
+ st->push(new ExpStatement(loc, var));
+ p = (*fs->parameters)[1]; // value
+ }
+ // Declare value
+ if (p->storageClass & (STCout | STClazy) ||
+ (p->storageClass & STCref && !te))
+ {
+ fs->error("no storage class for value %s", p->ident->toChars());
+ return setError();
+ }
+ Dsymbol *var;
+ if (te)
+ {
+ Type *tb = e->type->toBasetype();
+ Dsymbol *ds = NULL;
+ if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar)
+ ds = ((VarExp *)e)->var;
+ else if (e->op == TOKtemplate)
+ ds = ((TemplateExp *)e)->td;
+ else if (e->op == TOKscope)
+ ds = ((ScopeExp *)e)->sds;
+ else if (e->op == TOKfunction)
+ {
+ FuncExp *fe = (FuncExp *)e;
+ ds = fe->td ? (Dsymbol *)fe->td : fe->fd;
+ }
+
+ if (ds)
+ {
+ var = new AliasDeclaration(loc, p->ident, ds);
+ if (p->storageClass & STCref)
+ {
+ fs->error("symbol %s cannot be ref", s->toChars());
+ return setError();
+ }
+ if (paramtype)
+ {
+ fs->error("cannot specify element type for symbol %s", ds->toChars());
+ return setError();
+ }
+ }
+ else if (e->op == TOKtype)
+ {
+ var = new AliasDeclaration(loc, p->ident, e->type);
+ if (paramtype)
+ {
+ fs->error("cannot specify element type for type %s", e->type->toChars());
+ return setError();
+ }
+ }
+ else
+ {
+ p->type = e->type;
+ if (paramtype)
+ p->type = paramtype;
+ Initializer *ie = new ExpInitializer(Loc(), e);
+ VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ie);
+ if (p->storageClass & STCref)
+ v->storage_class |= STCref | STCforeach;
+ if (e->isConst() || e->op == TOKstring ||
+ e->op == TOKstructliteral || e->op == TOKarrayliteral)
+ {
+ if (v->storage_class & STCref)
+ {
+ fs->error("constant value %s cannot be ref", ie->toChars());
+ return setError();
+ }
+ else
+ v->storage_class |= STCmanifest;
+ }
+ var = v;
+ }
+ }
+ else
+ {
+ var = new AliasDeclaration(loc, p->ident, t);
+ if (paramtype)
+ {
+ fs->error("cannot specify element type for symbol %s", s->toChars());
+ return setError();
+ }
+ }
+ st->push(new ExpStatement(loc, var));
+
+ if (fs->_body)
+ st->push(fs->_body->syntaxCopy());
+ s = new CompoundStatement(loc, st);
+ s = new ScopeStatement(loc, s, fs->endloc);
+ statements->push(s);
+ }
+
+ s = new UnrolledLoopStatement(loc, statements);
+ if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+ ls->gotoTarget = s;
+ if (te && te->e0)
+ s = new CompoundStatement(loc, new ExpStatement(te->e0->loc, te->e0), s);
+ if (vinit)
+ s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
+ s = semantic(s, sc);
+ result = s;
+ return;
+ }
+
+ sym = new ScopeDsymbol();
+ sym->parent = sc->scopesym;
+ sym->endlinnum = fs->endloc.linnum;
+ Scope *sc2 = sc->push(sym);
+
+ sc2->noctor++;
+
+ switch (tab->ty)
+ {
+ case Tarray:
+ case Tsarray:
+ {
+ if (fs->checkForArgTypes())
+ {
+ result = fs;
+ return;
+ }
+
+ if (dim < 1 || dim > 2)
+ {
+ fs->error("only one or two arguments for array foreach");
+ goto Lerror2;
+ }
+
+ /* Look for special case of parsing char types out of char type
+ * array.
+ */
+ tn = tab->nextOf()->toBasetype();
+ if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
+ {
+ int i = (dim == 1) ? 0 : 1; // index of value
+ Parameter *p = (*fs->parameters)[i];
+ p->type = p->type->semantic(loc, sc2);
+ p->type = p->type->addStorageClass(p->storageClass);
+ tnv = p->type->toBasetype();
+ if (tnv->ty != tn->ty &&
+ (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
+ {
+ if (p->storageClass & STCref)
+ {
+ fs->error("foreach: value of UTF conversion cannot be ref");
+ goto Lerror2;
+ }
+ if (dim == 2)
+ {
+ p = (*fs->parameters)[0];
+ if (p->storageClass & STCref)
+ {
+ fs->error("foreach: key cannot be ref");
+ goto Lerror2;
+ }
+ }
+ goto Lapply;
+ }
+ }
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ // Declare parameterss
+ Parameter *p = (*fs->parameters)[i];
+ p->type = p->type->semantic(loc, sc2);
+ p->type = p->type->addStorageClass(p->storageClass);
+ VarDeclaration *var;
+
+ if (dim == 2 && i == 0)
+ {
+ var = new VarDeclaration(loc, p->type->mutableOf(), Identifier::generateId("__key"), NULL);
+ var->storage_class |= STCtemp | STCforeach;
+ if (var->storage_class & (STCref | STCout))
+ var->storage_class |= STCnodtor;
+
+ fs->key = var;
+ if (p->storageClass & STCref)
+ {
+ if (var->type->constConv(p->type) <= MATCHnomatch)
+ {
+ fs->error("key type mismatch, %s to ref %s",
+ var->type->toChars(), p->type->toChars());
+ goto Lerror2;
+ }
+ }
+ if (tab->ty == Tsarray)
+ {
+ TypeSArray *ta = (TypeSArray *)tab;
+ IntRange dimrange = getIntRange(ta->dim);
+ if (!IntRange::fromType(var->type).contains(dimrange))
+ {
+ fs->error("index type '%s' cannot cover index range 0..%llu", p->type->toChars(), ta->dim->toInteger());
+ goto Lerror2;
+ }
+ fs->key->range = new IntRange(SignExtendedNumber(0), dimrange.imax);
+ }
+ }
+ else
+ {
+ var = new VarDeclaration(loc, p->type, p->ident, NULL);
+ var->storage_class |= STCforeach;
+ var->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
+ if (var->storage_class & (STCref | STCout))
+ var->storage_class |= STCnodtor;
+
+ fs->value = var;
+ if (var->storage_class & STCref)
+ {
+ if (fs->aggr->checkModifiable(sc2, 1) == 2)
+ var->storage_class |= STCctorinit;
+
+ Type *t = tab->nextOf();
+ if (t->constConv(p->type) <= MATCHnomatch)
+ {
+ fs->error("argument type mismatch, %s to ref %s",
+ t->toChars(), p->type->toChars());
+ goto Lerror2;
+ }
+ }
+ }
+ }
+
+ /* Convert to a ForStatement
+ * foreach (key, value; a) body =>
+ * for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
+ * { T value = tmp[k]; body }
+ *
+ * foreach_reverse (key, value; a) body =>
+ * for (T[] tmp = a[], size_t key = tmp.length; key--; )
+ * { T value = tmp[k]; body }
+ */
+ Identifier *id = Identifier::generateId("__r");
+ ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, fs->aggr, NULL, NULL));
+ VarDeclaration *tmp;
+ if (fs->aggr->op == TOKarrayliteral &&
+ !((*fs->parameters)[dim - 1]->storageClass & STCref))
+ {
+ ArrayLiteralExp *ale = (ArrayLiteralExp *)fs->aggr;
+ size_t edim = ale->elements ? ale->elements->dim : 0;
+ Type *telem = (*fs->parameters)[dim - 1]->type;
+
+ // Bugzilla 12936: if telem has been specified explicitly,
+ // converting array literal elements to telem might make it @nogc.
+ fs->aggr = fs->aggr->implicitCastTo(sc, telem->sarrayOf(edim));
+ if (fs->aggr->op == TOKerror)
+ goto Lerror2;
+
+ // for (T[edim] tmp = a, ...)
+ tmp = new VarDeclaration(loc, fs->aggr->type, id, ie);
+ }
+ else
+ tmp = new VarDeclaration(loc, tab->nextOf()->arrayOf(), id, ie);
+ tmp->storage_class |= STCtemp;
+ tmp->endlinnum = fs->endloc.linnum;
+
+ Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length);
+
+ if (!fs->key)
+ {
+ Identifier *idkey = Identifier::generateId("__key");
+ fs->key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL);
+ fs->key->storage_class |= STCtemp;
+ }
+ if (fs->op == TOKforeach_reverse)
+ fs->key->_init = new ExpInitializer(loc, tmp_length);
+ else
+ fs->key->_init = new ExpInitializer(loc, new IntegerExp(loc, 0, fs->key->type));
+
+ Statements *cs = new Statements();
+ if (vinit)
+ cs->push(new ExpStatement(loc, vinit));
+ cs->push(new ExpStatement(loc, tmp));
+ cs->push(new ExpStatement(loc, fs->key));
+ Statement *forinit = new CompoundDeclarationStatement(loc, cs);
+
+ Expression *cond;
+ if (fs->op == TOKforeach_reverse)
+ {
+ // key--
+ cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
+ }
+ else
+ {
+ // key < tmp.length
+ cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), tmp_length);
+ }
+
+ Expression *increment = NULL;
+ if (fs->op == TOKforeach)
+ {
+ // key += 1
+ increment = new AddAssignExp(loc, new VarExp(loc, fs->key), new IntegerExp(loc, 1, fs->key->type));
+ }
+
+ // T value = tmp[key];
+ fs->value->_init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, fs->key)));
+ Statement *ds = new ExpStatement(loc, fs->value);
+
+ if (dim == 2)
+ {
+ Parameter *p = (*fs->parameters)[0];
+ if ((p->storageClass & STCref) && p->type->equals(fs->key->type))
+ {
+ fs->key->range = NULL;
+ AliasDeclaration *v = new AliasDeclaration(loc, p->ident, fs->key);
+ fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+ }
+ else
+ {
+ ExpInitializer *ei = new ExpInitializer(loc, new IdentifierExp(loc, fs->key->ident));
+ VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ei);
+ v->storage_class |= STCforeach | (p->storageClass & STCref);
+ fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+ if (fs->key->range && !p->type->isMutable())
+ {
+ /* Limit the range of the key to the specified range
+ */
+ v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
+ }
+ }
+ }
+ fs->_body = new CompoundStatement(loc, ds, fs->_body);
+
+ s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
+ if (LabelStatement *ls = checkLabeledLoop(sc, fs)) // Bugzilla 15450: don't use sc2
+ ls->gotoTarget = s;
+ s = semantic(s, sc2);
+ break;
+ }
+
+ case Taarray:
+ if (fs->op == TOKforeach_reverse)
+ fs->warning("cannot use foreach_reverse with an associative array");
+ if (fs->checkForArgTypes())
+ {
+ result = fs;
+ return;
+ }
+
+ taa = (TypeAArray *)tab;
+ if (dim < 1 || dim > 2)
+ {
+ fs->error("only one or two arguments for associative array foreach");
+ goto Lerror2;
+ }
+ goto Lapply;
+
+ case Tclass:
+ case Tstruct:
+ /* Prefer using opApply, if it exists
+ */
+ if (sapply)
+ goto Lapply;
+
+ {
+ /* Look for range iteration, i.e. the properties
+ * .empty, .popFront, .popBack, .front and .back
+ * foreach (e; aggr) { ... }
+ * translates to:
+ * for (auto __r = aggr[]; !__r.empty; __r.popFront()) {
+ * auto e = __r.front;
+ * ...
+ * }
+ */
+ AggregateDeclaration *ad = (tab->ty == Tclass)
+ ? (AggregateDeclaration *)((TypeClass *)tab)->sym
+ : (AggregateDeclaration *)((TypeStruct *)tab)->sym;
+ Identifier *idfront;
+ Identifier *idpopFront;
+ if (fs->op == TOKforeach)
+ {
+ idfront = Id::Ffront;
+ idpopFront = Id::FpopFront;
+ }
+ else
+ {
+ idfront = Id::Fback;
+ idpopFront = Id::FpopBack;
+ }
+ Dsymbol *sfront = ad->search(Loc(), idfront);
+ if (!sfront)
+ goto Lapply;
+
+ /* Generate a temporary __r and initialize it with the aggregate.
+ */
+ VarDeclaration *r;
+ Statement *init;
+ if (vinit && fs->aggr->op == TOKvar && ((VarExp *)fs->aggr)->var == vinit)
+ {
+ r = vinit;
+ init = new ExpStatement(loc, vinit);
+ }
+ else
+ {
+ r = copyToTemp(0, "__r", fs->aggr);
+ init = new ExpStatement(loc, r);
+ if (vinit)
+ init = new CompoundStatement(loc, new ExpStatement(loc, vinit), init);
+ }
+
+ // !__r.empty
+ Expression *e = new VarExp(loc, r);
+ e = new DotIdExp(loc, e, Id::Fempty);
+ Expression *condition = new NotExp(loc, e);
+
+ // __r.idpopFront()
+ e = new VarExp(loc, r);
+ Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront));
+
+ /* Declaration statement for e:
+ * auto e = __r.idfront;
+ */
+ e = new VarExp(loc, r);
+ Expression *einit = new DotIdExp(loc, e, idfront);
+ Statement *makeargs, *forbody;
+ if (dim == 1)
+ {
+ Parameter *p = (*fs->parameters)[0];
+ VarDeclaration *ve = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, einit));
+ ve->storage_class |= STCforeach;
+ ve->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
+
+ makeargs = new ExpStatement(loc, ve);
+ }
+ else
+ {
+ VarDeclaration *vd = copyToTemp(STCref, "__front", einit);
+ makeargs = new ExpStatement(loc, vd);
+
+ Type *tfront = NULL;
+ if (FuncDeclaration *fd = sfront->isFuncDeclaration())
+ {
+ if (!fd->functionSemantic())
+ goto Lrangeerr;
+ tfront = fd->type;
+ }
+ else if (TemplateDeclaration *td = sfront->isTemplateDeclaration())
+ {
+ Expressions a;
+ if (FuncDeclaration *f = resolveFuncCall(loc, sc, td, NULL, tab, &a, 1))
+ tfront = f->type;
+ }
+ else if (Declaration *d = sfront->isDeclaration())
+ {
+ tfront = d->type;
+ }
+ if (!tfront || tfront->ty == Terror)
+ goto Lrangeerr;
+
+ if (tfront->toBasetype()->ty == Tfunction)
+ tfront = tfront->toBasetype()->nextOf();
+ if (tfront->ty == Tvoid)
+ {
+ fs->error("%s.front is void and has no value", oaggr->toChars());
+ goto Lerror2;
+ }
+
+ // Resolve inout qualifier of front type
+ tfront = tfront->substWildTo(tab->mod);
+
+ Expression *ve = new VarExp(loc, vd);
+ ve->type = tfront;
+
+ Expressions *exps = new Expressions();
+ exps->push(ve);
+ int pos = 0;
+ while (exps->dim < dim)
+ {
+ pos = expandAliasThisTuples(exps, pos);
+ if (pos == -1)
+ break;
+ }
+ if (exps->dim != dim)
+ {
+ const char *plural = exps->dim > 1 ? "s" : "";
+ fs->error("cannot infer argument types, expected %d argument%s, not %d",
+ exps->dim, plural, dim);
+ goto Lerror2;
+ }
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *p = (*fs->parameters)[i];
+ Expression *exp = (*exps)[i];
+ if (!p->type)
+ p->type = exp->type;
+ p->type = p->type->addStorageClass(p->storageClass)->semantic(loc, sc2);
+ if (!exp->implicitConvTo(p->type))
+ goto Lrangeerr;
+
+ VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, exp));
+ var->storage_class |= STCctfe | STCref | STCforeach;
+ makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, var));
+ }
+
+ }
+
+ forbody = new CompoundStatement(loc,
+ makeargs, fs->_body);
+
+ s = new ForStatement(loc, init, condition, increment, forbody, fs->endloc);
+ if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+ ls->gotoTarget = s;
+ s = semantic(s, sc2);
+ break;
+
+ Lrangeerr:
+ fs->error("cannot infer argument types");
+ goto Lerror2;
+ }
+ case Tdelegate:
+ if (fs->op == TOKforeach_reverse)
+ fs->deprecation("cannot use foreach_reverse with a delegate");
+ Lapply:
+ {
+ if (fs->checkForArgTypes())
+ {
+ fs->_body = semanticNoScope(fs->_body, sc2);
+ result = fs;
+ return;
+ }
+
+ TypeFunction *tfld = NULL;
+ if (sapply)
+ {
+ FuncDeclaration *fdapply = sapply->isFuncDeclaration();
+ if (fdapply)
+ {
+ assert(fdapply->type && fdapply->type->ty == Tfunction);
+ tfld = (TypeFunction *)fdapply->type->semantic(loc, sc2);
+ goto Lget;
+ }
+ else if (tab->ty == Tdelegate)
+ {
+ tfld = (TypeFunction *)tab->nextOf();
+ Lget:
+ //printf("tfld = %s\n", tfld->toChars());
+ if (tfld->parameters->dim == 1)
+ {
+ Parameter *p = Parameter::getNth(tfld->parameters, 0);
+ if (p->type && p->type->ty == Tdelegate)
+ {
+ Type *t = p->type->semantic(loc, sc2);
+ assert(t->ty == Tdelegate);
+ tfld = (TypeFunction *)t->nextOf();
+ }
+ }
+ }
+ }
+
+ /* Turn body into the function literal:
+ * int delegate(ref T param) { body }
+ */
+ Parameters *params = new Parameters();
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter *p = (*fs->parameters)[i];
+ StorageClass stc = STCref;
+ Identifier *id;
+
+ p->type = p->type->semantic(loc, sc2);
+ p->type = p->type->addStorageClass(p->storageClass);
+ if (tfld)
+ {
+ Parameter *prm = Parameter::getNth(tfld->parameters, i);
+ //printf("\tprm = %s%s\n", (prm->storageClass&STCref?"ref ":""), prm->ident->toChars());
+ stc = prm->storageClass & STCref;
+ id = p->ident; // argument copy is not need.
+ if ((p->storageClass & STCref) != stc)
+ {
+ if (!stc)
+ {
+ fs->error("foreach: cannot make %s ref", p->ident->toChars());
+ goto Lerror2;
+ }
+ goto LcopyArg;
+ }
+ }
+ else if (p->storageClass & STCref)
+ {
+ // default delegate parameters are marked as ref, then
+ // argument copy is not need.
+ id = p->ident;
+ }
+ else
+ {
+ // Make a copy of the ref argument so it isn't
+ // a reference.
+ LcopyArg:
+ id = Identifier::generateId("__applyArg", (int)i);
+
+ Initializer *ie = new ExpInitializer(Loc(), new IdentifierExp(Loc(), id));
+ VarDeclaration *v = new VarDeclaration(Loc(), p->type, p->ident, ie);
+ v->storage_class |= STCtemp;
+ s = new ExpStatement(Loc(), v);
+ fs->_body = new CompoundStatement(loc, s, fs->_body);
+ }
+ params->push(new Parameter(stc, p->type, id, NULL));
+ }
+ // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable.
+ StorageClass stc = mergeFuncAttrs(STCsafe | STCpure | STCnogc, fs->func);
+ tfld = new TypeFunction(params, Type::tint32, 0, LINKd, stc);
+ fs->cases = new Statements();
+ fs->gotos = new ScopeStatements();
+ FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, Loc(), tfld, TOKdelegate, fs);
+ fld->fbody = fs->_body;
+ Expression *flde = new FuncExp(loc, fld);
+ flde = semantic(flde, sc2);
+ fld->tookAddressOf = 0;
+
+ // Resolve any forward referenced goto's
+ for (size_t i = 0; i < fs->gotos->dim; i++)
+ {
+ GotoStatement *gs = (GotoStatement *)(*fs->gotos)[i]->statement;
+ if (!gs->label->statement)
+ {
+ // 'Promote' it to this scope, and replace with a return
+ fs->cases->push(gs);
+ s = new ReturnStatement(Loc(), new IntegerExp(fs->cases->dim + 1));
+ (*fs->gotos)[i]->statement = s;
+ }
+ }
+
+ Expression *e = NULL;
+ Expression *ec;
+ if (vinit)
+ {
+ e = new DeclarationExp(loc, vinit);
+ e = semantic(e, sc2);
+ if (e->op == TOKerror)
+ goto Lerror2;
+ }
+
+ if (taa)
+ {
+ // Check types
+ Parameter *p = (*fs->parameters)[0];
+ bool isRef = (p->storageClass & STCref) != 0;
+ Type *ta = p->type;
+ if (dim == 2)
+ {
+ Type *ti = (isRef ? taa->index->addMod(MODconst) : taa->index);
+ if (isRef ? !ti->constConv(ta) : !ti->implicitConvTo(ta))
+ {
+ fs->error("foreach: index must be type %s, not %s", ti->toChars(), ta->toChars());
+ goto Lerror2;
+ }
+ p = (*fs->parameters)[1];
+ isRef = (p->storageClass & STCref) != 0;
+ ta = p->type;
+ }
+ Type *taav = taa->nextOf();
+ if (isRef ? !taav->constConv(ta) : !taav->implicitConvTo(ta))
+ {
+ fs->error("foreach: value must be type %s, not %s", taav->toChars(), ta->toChars());
+ goto Lerror2;
+ }
+
+ /* Call:
+ * extern(C) int _aaApply(void*, in size_t, int delegate(void*))
+ * _aaApply(aggr, keysize, flde)
+ *
+ * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
+ * _aaApply2(aggr, keysize, flde)
+ */
+ static const char *name[2] = { "_aaApply", "_aaApply2" };
+ static FuncDeclaration *fdapply[2] = { NULL, NULL };
+ static TypeDelegate *fldeTy[2] = { NULL, NULL };
+
+ unsigned char i = (dim == 2 ? 1 : 0);
+ if (!fdapply[i])
+ {
+ params = new Parameters();
+ params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL));
+ params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL));
+ Parameters* dgparams = new Parameters;
+ dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+ if (dim == 2)
+ dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+ fldeTy[i] = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd));
+ params->push(new Parameter(0, fldeTy[i], NULL, NULL));
+ fdapply[i] = FuncDeclaration::genCfunc(params, Type::tint32, name[i]);
+ }
+
+ Expressions *exps = new Expressions();
+ exps->push(fs->aggr);
+ d_uns64 keysize = taa->index->size();
+ if (keysize == SIZE_INVALID)
+ goto Lerror2;
+ assert(keysize < UINT64_MAX - Target::ptrsize);
+ keysize = (keysize + (Target::ptrsize- 1)) & ~(Target::ptrsize - 1);
+ // paint delegate argument to the type runtime expects
+ if (!fldeTy[i]->equals(flde->type))
+ {
+ flde = new CastExp(loc, flde, flde->type);
+ flde->type = fldeTy[i];
+ }
+ exps->push(new IntegerExp(Loc(), keysize, Type::tsize_t));
+ exps->push(flde);
+
+ ec = new VarExp(Loc(), fdapply[i], false);
+ ec = new CallExp(loc, ec, exps);
+ ec->type = Type::tint32; // don't run semantic() on ec
+ }
+ else if (tab->ty == Tarray || tab->ty == Tsarray)
+ {
+ /* Call:
+ * _aApply(aggr, flde)
+ */
+ static const char fntab[9][3] =
+ { "cc","cw","cd",
+ "wc","cc","wd",
+ "dc","dw","dd"
+ };
+ const int BUFFER_LEN = 7+1+2+ sizeof(dim)*3 + 1;
+ char fdname[BUFFER_LEN];
+ int flag;
+
+ switch (tn->ty)
+ {
+ case Tchar: flag = 0; break;
+ case Twchar: flag = 3; break;
+ case Tdchar: flag = 6; break;
+ default: assert(0);
+ }
+ switch (tnv->ty)
+ {
+ case Tchar: flag += 0; break;
+ case Twchar: flag += 1; break;
+ case Tdchar: flag += 2; break;
+ default: assert(0);
+ }
+ const char *r = (fs->op == TOKforeach_reverse) ? "R" : "";
+ int j = sprintf(fdname, "_aApply%s%.*s%llu", r, 2, fntab[flag], (ulonglong)dim);
+ assert(j < BUFFER_LEN);
+
+ FuncDeclaration *fdapply;
+ TypeDelegate *dgty;
+ params = new Parameters();
+ params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL));
+ Parameters* dgparams = new Parameters;
+ dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+ if (dim == 2)
+ dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL));
+ dgty = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd));
+ params->push(new Parameter(0, dgty, NULL, NULL));
+ fdapply = FuncDeclaration::genCfunc(params, Type::tint32, fdname);
+
+ if (tab->ty == Tsarray)
+ fs->aggr = fs->aggr->castTo(sc2, tn->arrayOf());
+
+ // paint delegate argument to the type runtime expects
+ if (!dgty->equals(flde->type)) {
+ flde = new CastExp(loc, flde, flde->type);
+ flde->type = dgty;
+ }
+
+ ec = new VarExp(Loc(), fdapply, false);
+ ec = new CallExp(loc, ec, fs->aggr, flde);
+ ec->type = Type::tint32; // don't run semantic() on ec
+ }
+ else if (tab->ty == Tdelegate)
+ {
+ /* Call:
+ * aggr(flde)
+ */
+ if (fs->aggr->op == TOKdelegate &&
+ ((DelegateExp *)fs->aggr)->func->isNested())
+ {
+ // See Bugzilla 3560
+ fs->aggr = ((DelegateExp *)fs->aggr)->e1;
+ }
+ ec = new CallExp(loc, fs->aggr, flde);
+ ec = semantic(ec, sc2);
+ if (ec->op == TOKerror)
+ goto Lerror2;
+ if (ec->type != Type::tint32)
+ {
+ fs->error("opApply() function for %s must return an int", tab->toChars());
+ goto Lerror2;
+ }
+ }
+ else
+ {
+ if (global.params.vsafe)
+ fld->tookAddressOf = 1; // allocate a closure unless the opApply() uses 'scope'
+
+ assert(tab->ty == Tstruct || tab->ty == Tclass);
+ assert(sapply);
+ /* Call:
+ * aggr.apply(flde)
+ */
+ ec = new DotIdExp(loc, fs->aggr, sapply->ident);
+ ec = new CallExp(loc, ec, flde);
+ ec = semantic(ec, sc2);
+ if (ec->op == TOKerror)
+ goto Lerror2;
+ if (ec->type != Type::tint32)
+ {
+ fs->error("opApply() function for %s must return an int", tab->toChars());
+ goto Lerror2;
+ }
+ }
+ e = Expression::combine(e, ec);
+
+ if (!fs->cases->dim)
+ {
+ // Easy case, a clean exit from the loop
+ e = new CastExp(loc, e, Type::tvoid); // Bugzilla 13899
+ s = new ExpStatement(loc, e);
+ }
+ else
+ {
+ // Construct a switch statement around the return value
+ // of the apply function.
+ Statements *a = new Statements();
+
+ // default: break; takes care of cases 0 and 1
+ s = new BreakStatement(Loc(), NULL);
+ s = new DefaultStatement(Loc(), s);
+ a->push(s);
+
+ // cases 2...
+ for (size_t i = 0; i < fs->cases->dim; i++)
+ {
+ s = (*fs->cases)[i];
+ s = new CaseStatement(Loc(), new IntegerExp(i + 2), s);
+ a->push(s);
+ }
+
+ s = new CompoundStatement(loc, a);
+ s = new SwitchStatement(loc, e, s, false);
+ }
+ s = semantic(s, sc2);
+ break;
+ }
+ case Terror:
+ Lerror2:
+ s = new ErrorStatement();
+ break;
+
+ default:
+ fs->error("foreach: %s is not an aggregate type", fs->aggr->type->toChars());
+ goto Lerror2;
+ }
+ sc2->noctor--;
+ sc2->pop();
+ result = s;
+ }
+
+ void visit(ForeachRangeStatement *fs)
+ {
+ //printf("ForeachRangeStatement::semantic() %p\n", fs);
+ Loc loc = fs->loc;
+ fs->lwr = semantic(fs->lwr, sc);
+ fs->lwr = resolveProperties(sc, fs->lwr);
+ fs->lwr = fs->lwr->optimize(WANTvalue);
+ if (!fs->lwr->type)
+ {
+ fs->error("invalid range lower bound %s", fs->lwr->toChars());
+ Lerror:
+ return setError();
+ }
+
+ fs->upr = semantic(fs->upr, sc);
+ fs->upr = resolveProperties(sc, fs->upr);
+ fs->upr = fs->upr->optimize(WANTvalue);
+ if (!fs->upr->type)
+ {
+ fs->error("invalid range upper bound %s", fs->upr->toChars());
+ goto Lerror;
+ }
+
+ if (fs->prm->type)
+ {
+ fs->prm->type = fs->prm->type->semantic(loc, sc);
+ fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
+ fs->lwr = fs->lwr->implicitCastTo(sc, fs->prm->type);
+
+ if (fs->upr->implicitConvTo(fs->prm->type) || (fs->prm->storageClass & STCref))
+ {
+ fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
+ }
+ else
+ {
+ // See if upr-1 fits in prm->type
+ Expression *limit = new MinExp(loc, fs->upr, new IntegerExp(1));
+ limit = semantic(limit, sc);
+ limit = limit->optimize(WANTvalue);
+ if (!limit->implicitConvTo(fs->prm->type))
+ {
+ fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
+ }
+ }
+ }
+ else
+ {
+ /* Must infer types from lwr and upr
+ */
+ Type *tlwr = fs->lwr->type->toBasetype();
+ if (tlwr->ty == Tstruct || tlwr->ty == Tclass)
+ {
+ /* Just picking the first really isn't good enough.
+ */
+ fs->prm->type = fs->lwr->type;
+ }
+ else if (fs->lwr->type == fs->upr->type)
+ {
+ /* Same logic as CondExp ?lwr:upr
+ */
+ fs->prm->type = fs->lwr->type;
+ }
+ else
+ {
+ AddExp ea(loc, fs->lwr, fs->upr);
+ if (typeCombine(&ea, sc))
+ return setError();
+ fs->prm->type = ea.type;
+ fs->lwr = ea.e1;
+ fs->upr = ea.e2;
+ }
+ fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
+ }
+ if (fs->prm->type->ty == Terror ||
+ fs->lwr->op == TOKerror ||
+ fs->upr->op == TOKerror)
+ {
+ return setError();
+ }
+
+ /* Convert to a for loop:
+ * foreach (key; lwr .. upr) =>
+ * for (auto key = lwr, auto tmp = upr; key < tmp; ++key)
+ *
+ * foreach_reverse (key; lwr .. upr) =>
+ * for (auto tmp = lwr, auto key = upr; key-- > tmp;)
+ */
+ ExpInitializer *ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->lwr : fs->upr);
+ fs->key = new VarDeclaration(loc, fs->upr->type->mutableOf(), Identifier::generateId("__key"), ie);
+ fs->key->storage_class |= STCtemp;
+ SignExtendedNumber lower = getIntRange(fs->lwr).imin;
+ SignExtendedNumber upper = getIntRange(fs->upr).imax;
+ if (lower <= upper)
+ {
+ fs->key->range = new IntRange(lower, upper);
+ }
+
+ Identifier *id = Identifier::generateId("__limit");
+ ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->upr : fs->lwr);
+ VarDeclaration *tmp = new VarDeclaration(loc, fs->upr->type, id, ie);
+ tmp->storage_class |= STCtemp;
+
+ Statements *cs = new Statements();
+ // Keep order of evaluation as lwr, then upr
+ if (fs->op == TOKforeach)
+ {
+ cs->push(new ExpStatement(loc, fs->key));
+ cs->push(new ExpStatement(loc, tmp));
+ }
+ else
+ {
+ cs->push(new ExpStatement(loc, tmp));
+ cs->push(new ExpStatement(loc, fs->key));
+ }
+ Statement *forinit = new CompoundDeclarationStatement(loc, cs);
+
+ Expression *cond;
+ if (fs->op == TOKforeach_reverse)
+ {
+ cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
+ if (fs->prm->type->isscalar())
+ {
+ // key-- > tmp
+ cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp));
+ }
+ else
+ {
+ // key-- != tmp
+ cond = new EqualExp(TOKnotequal, loc, cond, new VarExp(loc, tmp));
+ }
+ }
+ else
+ {
+ if (fs->prm->type->isscalar())
+ {
+ // key < tmp
+ cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
+ }
+ else
+ {
+ // key != tmp
+ cond = new EqualExp(TOKnotequal, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
+ }
+ }
+
+ Expression *increment = NULL;
+ if (fs->op == TOKforeach)
+ {
+ // key += 1
+ //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
+ increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, fs->key));
+ }
+
+ if ((fs->prm->storageClass & STCref) && fs->prm->type->equals(fs->key->type))
+ {
+ fs->key->range = NULL;
+ AliasDeclaration *v = new AliasDeclaration(loc, fs->prm->ident, fs->key);
+ fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+ }
+ else
+ {
+ ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs->key), fs->prm->type));
+ VarDeclaration *v = new VarDeclaration(loc, fs->prm->type, fs->prm->ident, ie);
+ v->storage_class |= STCtemp | STCforeach | (fs->prm->storageClass & STCref);
+ fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
+ if (fs->key->range && !fs->prm->type->isMutable())
+ {
+ /* Limit the range of the key to the specified range
+ */
+ v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
+ }
+ }
+ if (fs->prm->storageClass & STCref)
+ {
+ if (fs->key->type->constConv(fs->prm->type) <= MATCHnomatch)
+ {
+ fs->error("prmument type mismatch, %s to ref %s",
+ fs->key->type->toChars(), fs->prm->type->toChars());
+ goto Lerror;
+ }
+ }
+
+ ForStatement *s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
+ if (LabelStatement *ls = checkLabeledLoop(sc, fs))
+ ls->gotoTarget = s;
+ result = semantic(s, sc);
+ }
+
+ void visit(IfStatement *ifs)
+ {
+ // Evaluate at runtime
+ unsigned cs0 = sc->callSuper;
+ unsigned cs1;
+ unsigned *fi0 = sc->saveFieldInit();
+ unsigned *fi1 = NULL;
+
+ // check in syntax level
+ ifs->condition = checkAssignmentAsCondition(ifs->condition);
+
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc->scopesym;
+ sym->endlinnum = ifs->endloc.linnum;
+ Scope *scd = sc->push(sym);
+ if (ifs->prm)
+ {
+ /* Declare prm, which we will set to be the
+ * result of condition.
+ */
+ ExpInitializer *ei = new ExpInitializer(ifs->loc, ifs->condition);
+ ifs->match = new VarDeclaration(ifs->loc, ifs->prm->type, ifs->prm->ident, ei);
+ ifs->match->parent = sc->func;
+ ifs->match->storage_class |= ifs->prm->storageClass;
+ ifs->match->semantic(scd);
+
+ DeclarationExp *de = new DeclarationExp(ifs->loc, ifs->match);
+ VarExp *ve = new VarExp(ifs->loc, ifs->match);
+ ifs->condition = new CommaExp(ifs->loc, de, ve);
+ ifs->condition = semantic(ifs->condition, scd);
+
+ if (ifs->match->edtor)
+ {
+ Statement *sdtor = new DtorExpStatement(ifs->loc, ifs->match->edtor, ifs->match);
+ sdtor = new OnScopeStatement(ifs->loc, TOKon_scope_exit, sdtor);
+ ifs->ifbody = new CompoundStatement(ifs->loc, sdtor, ifs->ifbody);
+ ifs->match->storage_class |= STCnodtor;
+ }
+ }
+ else
+ {
+ if (ifs->condition->op == TOKdotid)
+ ((DotIdExp *)ifs->condition)->noderef = true;
+
+ ifs->condition = semantic(ifs->condition, sc);
+ ifs->condition = resolveProperties(sc, ifs->condition);
+ ifs->condition = ifs->condition->addDtorHook(sc);
+ }
+ ifs->condition = checkGC(sc, ifs->condition);
+
+ // Convert to boolean after declaring prm so this works:
+ // if (S prm = S()) {}
+ // where S is a struct that defines opCast!bool.
+ ifs->condition = ifs->condition->toBoolean(sc);
+
+ // If we can short-circuit evaluate the if statement, don't do the
+ // semantic analysis of the skipped code.
+ // This feature allows a limited form of conditional compilation.
+ ifs->condition = ifs->condition->optimize(WANTvalue);
+ ifs->ifbody = semanticNoScope(ifs->ifbody, scd);
+ scd->pop();
+
+ cs1 = sc->callSuper;
+ fi1 = sc->fieldinit;
+ sc->callSuper = cs0;
+ sc->fieldinit = fi0;
+ if (ifs->elsebody)
+ ifs->elsebody = semanticScope(ifs->elsebody, sc, NULL, NULL);
+ sc->mergeCallSuper(ifs->loc, cs1);
+ sc->mergeFieldInit(ifs->loc, fi1);
+
+ if (ifs->condition->op == TOKerror ||
+ (ifs->ifbody && ifs->ifbody->isErrorStatement()) ||
+ (ifs->elsebody && ifs->elsebody->isErrorStatement()))
+ {
+ return setError();
+ }
+ result = ifs;
+ }
+
+ void visit(ConditionalStatement *cs)
+ {
+ //printf("ConditionalStatement::semantic()\n");
+
+ // If we can short-circuit evaluate the if statement, don't do the
+ // semantic analysis of the skipped code.
+ // This feature allows a limited form of conditional compilation.
+ if (cs->condition->include(sc, NULL))
+ {
+ DebugCondition *dc = cs->condition->isDebugCondition();
+ if (dc)
+ {
+ sc = sc->push();
+ sc->flags |= SCOPEdebug;
+ cs->ifbody = semantic(cs->ifbody, sc);
+ sc->pop();
+ }
+ else
+ cs->ifbody = semantic(cs->ifbody, sc);
+ result = cs->ifbody;
+ }
+ else
+ {
+ if (cs->elsebody)
+ cs->elsebody = semantic(cs->elsebody, sc);
+ result = cs->elsebody;
+ }
+ }
+
+ void visit(PragmaStatement *ps)
+ {
+ // Should be merged with PragmaDeclaration
+ //printf("PragmaStatement::semantic() %s\n", ps->toChars());
+ //printf("body = %p\n", ps->_body);
+ if (ps->ident == Id::msg)
+ {
+ if (ps->args)
+ {
+ for (size_t i = 0; i < ps->args->dim; i++)
+ {
+ Expression *e = (*ps->args)[i];
+
+ sc = sc->startCTFE();
+ e = semantic(e, sc);
+ e = resolveProperties(sc, e);
+ sc = sc->endCTFE();
+ // pragma(msg) is allowed to contain types as well as expressions
+ e = ctfeInterpretForPragmaMsg(e);
+ if (e->op == TOKerror)
+ {
+ errorSupplemental(ps->loc, "while evaluating pragma(msg, %s)", (*ps->args)[i]->toChars());
+ goto Lerror;
+ }
+ StringExp *se = e->toStringExp();
+ if (se)
+ {
+ se = se->toUTF8(sc);
+ fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
+ }
+ else
+ fprintf(stderr, "%s", e->toChars());
+ }
+ fprintf(stderr, "\n");
+ }
+ }
+ else if (ps->ident == Id::lib)
+ {
+ /* Should this be allowed?
+ */
+ ps->error("pragma(lib) not allowed as statement");
+ goto Lerror;
+ }
+ else if (ps->ident == Id::startaddress)
+ {
+ if (!ps->args || ps->args->dim != 1)
+ ps->error("function name expected for start address");
+ else
+ {
+ Expression *e = (*ps->args)[0];
+
+ sc = sc->startCTFE();
+ e = semantic(e, sc);
+ e = resolveProperties(sc, e);
+ sc = sc->endCTFE();
+
+ e = e->ctfeInterpret();
+ (*ps->args)[0] = e;
+ Dsymbol *sa = getDsymbol(e);
+ if (!sa || !sa->isFuncDeclaration())
+ {
+ ps->error("function name expected for start address, not '%s'", e->toChars());
+ goto Lerror;
+ }
+ if (ps->_body)
+ {
+ ps->_body = semantic(ps->_body, sc);
+ if (ps->_body->isErrorStatement())
+ {
+ result = ps->_body;
+ return;
+ }
+ }
+ result = ps;
+ return;
+ }
+ }
+ else if (ps->ident == Id::Pinline)
+ {
+ PINLINE inlining = PINLINEdefault;
+ if (!ps->args || ps->args->dim == 0)
+ inlining = PINLINEdefault;
+ else if (!ps->args || ps->args->dim != 1)
+ {
+ ps->error("boolean expression expected for pragma(inline)");
+ goto Lerror;
+ }
+ else
+ {
+ Expression *e = (*ps->args)[0];
+
+ if (e->op != TOKint64 || !e->type->equals(Type::tbool))
+ {
+ ps->error("pragma(inline, true or false) expected, not %s", e->toChars());
+ goto Lerror;
+ }
+
+ if (e->isBool(true))
+ inlining = PINLINEalways;
+ else if (e->isBool(false))
+ inlining = PINLINEnever;
+
+ FuncDeclaration *fd = sc->func;
+ if (!fd)
+ {
+ ps->error("pragma(inline) is not inside a function");
+ goto Lerror;
+ }
+ fd->inlining = inlining;
+ }
+ }
+ else
+ {
+ ps->error("unrecognized pragma(%s)", ps->ident->toChars());
+ goto Lerror;
+ }
+
+ if (ps->_body)
+ {
+ ps->_body = semantic(ps->_body, sc);
+ }
+ result = ps->_body;
+ return;
+
+ Lerror:
+ return setError();
+ }
+
+ void visit(StaticAssertStatement *s)
+ {
+ s->sa->semantic2(sc);
+ }
+
+ void visit(SwitchStatement *ss)
+ {
+ //printf("SwitchStatement::semantic(%p)\n", ss);
+ ss->tf = sc->tf;
+ if (ss->cases)
+ {
+ result = ss; // already run
+ return;
+ }
+ bool conditionError = false;
+ ss->condition = semantic(ss->condition, sc);
+ ss->condition = resolveProperties(sc, ss->condition);
+
+ Type *att = NULL;
+ TypeEnum *te = NULL;
+ while (ss->condition->op != TOKerror)
+ {
+ // preserve enum type for final switches
+ if (ss->condition->type->ty == Tenum)
+ te = (TypeEnum *)ss->condition->type;
+ if (ss->condition->type->isString())
+ {
+ // If it's not an array, cast it to one
+ if (ss->condition->type->ty != Tarray)
+ {
+ ss->condition = ss->condition->implicitCastTo(sc, ss->condition->type->nextOf()->arrayOf());
+ }
+ ss->condition->type = ss->condition->type->constOf();
+ break;
+ }
+ ss->condition = integralPromotions(ss->condition, sc);
+ if (ss->condition->op != TOKerror && ss->condition->type->isintegral())
+ break;
+
+ AggregateDeclaration *ad = isAggregate(ss->condition->type);
+ if (ad && ad->aliasthis && ss->condition->type != att)
+ {
+ if (!att && ss->condition->type->checkAliasThisRec())
+ att = ss->condition->type;
+ if (Expression *e = resolveAliasThis(sc, ss->condition, true))
+ {
+ ss->condition = e;
+ continue;
+ }
+ }
+
+ if (ss->condition->op != TOKerror)
+ {
+ ss->error("'%s' must be of integral or string type, it is a %s",
+ ss->condition->toChars(), ss->condition->type->toChars());
+ conditionError = true;
+ break;
+ }
+ }
+ ss->condition = ss->condition->optimize(WANTvalue);
+ ss->condition = checkGC(sc, ss->condition);
+ if (ss->condition->op == TOKerror)
+ conditionError = true;
+
+ bool needswitcherror = false;
+
+ ss->lastVar = sc->lastVar;
+
+ sc = sc->push();
+ sc->sbreak = ss;
+ sc->sw = ss;
+
+ ss->cases = new CaseStatements();
+ sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
+ ss->_body = semantic(ss->_body, sc);
+ sc->noctor--;
+
+ if (conditionError || ss->_body->isErrorStatement())
+ goto Lerror;
+
+ // Resolve any goto case's with exp
+ for (size_t i = 0; i < ss->gotoCases.dim; i++)
+ {
+ GotoCaseStatement *gcs = ss->gotoCases[i];
+
+ if (!gcs->exp)
+ {
+ gcs->error("no case statement following goto case;");
+ goto Lerror;
+ }
+
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (!scx->sw)
+ continue;
+ for (size_t j = 0; j < scx->sw->cases->dim; j++)
+ {
+ CaseStatement *cs = (*scx->sw->cases)[j];
+
+ if (cs->exp->equals(gcs->exp))
+ {
+ gcs->cs = cs;
+ goto Lfoundcase;
+ }
+ }
+ }
+ gcs->error("case %s not found", gcs->exp->toChars());
+ goto Lerror;
+
+ Lfoundcase:
+ ;
+ }
+
+ if (ss->isFinal)
+ {
+ Type *t = ss->condition->type;
+ Dsymbol *ds;
+ EnumDeclaration *ed = NULL;
+ if (t && ((ds = t->toDsymbol(sc)) != NULL))
+ ed = ds->isEnumDeclaration(); // typedef'ed enum
+ if (!ed && te && ((ds = te->toDsymbol(sc)) != NULL))
+ ed = ds->isEnumDeclaration();
+ if (ed)
+ {
+ size_t dim = ed->members->dim;
+ for (size_t i = 0; i < dim; i++)
+ {
+ EnumMember *em = (*ed->members)[i]->isEnumMember();
+ if (em)
+ {
+ for (size_t j = 0; j < ss->cases->dim; j++)
+ {
+ CaseStatement *cs = (*ss->cases)[j];
+ if (cs->exp->equals(em->value()) ||
+ (!cs->exp->type->isString() && !em->value()->type->isString() &&
+ cs->exp->toInteger() == em->value()->toInteger()))
+ goto L1;
+ }
+ ss->error("enum member %s not represented in final switch", em->toChars());
+ goto Lerror;
+ }
+ L1:
+ ;
+ }
+ }
+ else
+ needswitcherror = true;
+ }
+
+ if (!sc->sw->sdefault && (!ss->isFinal || needswitcherror || global.params.useAssert))
+ {
+ ss->hasNoDefault = 1;
+
+ if (!ss->isFinal && !ss->_body->isErrorStatement())
+ ss->error("switch statement without a default; use 'final switch' or add 'default: assert(0);' or add 'default: break;'");
+
+ // Generate runtime error if the default is hit
+ Statements *a = new Statements();
+ CompoundStatement *cs;
+ Statement *s;
+
+ if (global.params.useSwitchError)
+ s = new SwitchErrorStatement(ss->loc);
+ else
+ s = new ExpStatement(ss->loc, new HaltExp(ss->loc));
+
+ a->reserve(2);
+ sc->sw->sdefault = new DefaultStatement(ss->loc, s);
+ a->push(ss->_body);
+ if (blockExit(ss->_body, sc->func, false) & BEfallthru)
+ a->push(new BreakStatement(Loc(), NULL));
+ a->push(sc->sw->sdefault);
+ cs = new CompoundStatement(ss->loc, a);
+ ss->_body = cs;
+ }
+
+ if (ss->checkLabel())
+ goto Lerror;
+
+ sc->pop();
+ result = ss;
+ return;
+
+ Lerror:
+ sc->pop();
+ result = new ErrorStatement();
+ }
+
+ void visit(CaseStatement *cs)
+ {
+ SwitchStatement *sw = sc->sw;
+ bool errors = false;
+
+ //printf("CaseStatement::semantic() %s\n", cs->toChars());
+ sc = sc->startCTFE();
+ cs->exp = semantic(cs->exp, sc);
+ cs->exp = resolveProperties(sc, cs->exp);
+ sc = sc->endCTFE();
+ if (sw)
+ {
+ cs->exp = cs->exp->implicitCastTo(sc, sw->condition->type);
+ cs->exp = cs->exp->optimize(WANTvalue | WANTexpand);
+
+ Expression *e = cs->exp;
+ // Remove all the casts the user and/or implicitCastTo may introduce
+ // otherwise we'd sometimes fail the check below.
+ while (e->op == TOKcast)
+ e = ((CastExp *)e)->e1;
+
+ /* This is where variables are allowed as case expressions.
+ */
+ if (e->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)e;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+ Type *t = cs->exp->type->toBasetype();
+ if (v && (t->isintegral() || t->ty == Tclass))
+ {
+ /* Flag that we need to do special code generation
+ * for this, i.e. generate a sequence of if-then-else
+ */
+ sw->hasVars = 1;
+
+ /* TODO check if v can be uninitialized at that point.
+ */
+ if (!v->isConst() && !v->isImmutable())
+ {
+ cs->deprecation("case variables have to be const or immutable");
+ }
+
+ if (sw->isFinal)
+ {
+ cs->error("case variables not allowed in final switch statements");
+ errors = true;
+ }
+
+ /* Also check if the VarExp is declared in a scope outside of this one.
+ * 'scx' is set to the scope of the switch statement.
+ */
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (scx->enclosing && scx->enclosing->sw == sw)
+ continue;
+ assert(scx->sw == sw);
+
+ if (!scx->search(cs->exp->loc, v->ident, NULL))
+ {
+ cs->error("case variable `%s` declared at %s cannot be declared in switch body",
+ v->toChars(), v->loc.toChars());
+ errors = true;
+ }
+ break;
+ }
+ goto L1;
+ }
+ }
+ else
+ cs->exp = cs->exp->ctfeInterpret();
+
+ if (StringExp *se = cs->exp->toStringExp())
+ cs->exp = se;
+ else if (cs->exp->op != TOKint64 && cs->exp->op != TOKerror)
+ {
+ cs->error("case must be a string or an integral constant, not %s", cs->exp->toChars());
+ errors = true;
+ }
+
+ L1:
+ for (size_t i = 0; i < sw->cases->dim; i++)
+ {
+ CaseStatement *cs2 = (*sw->cases)[i];
+
+ //printf("comparing '%s' with '%s'\n", cs->exp->toChars(), cs2->exp->toChars());
+ if (cs2->exp->equals(cs->exp))
+ {
+ cs->error("duplicate case %s in switch statement", cs->exp->toChars());
+ errors = true;
+ break;
+ }
+ }
+
+ sw->cases->push(cs);
+
+ // Resolve any goto case's with no exp to this case statement
+ for (size_t i = 0; i < sw->gotoCases.dim; )
+ {
+ GotoCaseStatement *gcs = sw->gotoCases[i];
+
+ if (!gcs->exp)
+ {
+ gcs->cs = cs;
+ sw->gotoCases.remove(i); // remove from array
+ continue;
+ }
+ i++;
+ }
+
+ if (sc->sw->tf != sc->tf)
+ {
+ cs->error("switch and case are in different finally blocks");
+ errors = true;
+ }
+ }
+ else
+ {
+ cs->error("case not in switch statement");
+ errors = true;
+ }
+ cs->statement = semantic(cs->statement, sc);
+ if (cs->statement->isErrorStatement())
+ {
+ result = cs->statement;
+ return;
+ }
+ if (errors || cs->exp->op == TOKerror)
+ return setError();
+
+ cs->lastVar = sc->lastVar;
+ result = cs;
+ }
+
+ void visit(CaseRangeStatement *crs)
+ {
+ SwitchStatement *sw = sc->sw;
+ if (sw == NULL)
+ {
+ crs->error("case range not in switch statement");
+ return setError();
+ }
+
+ //printf("CaseRangeStatement::semantic() %s\n", toChars());
+ bool errors = false;
+ if (sw->isFinal)
+ {
+ crs->error("case ranges not allowed in final switch");
+ errors = true;
+ }
+
+ sc = sc->startCTFE();
+ crs->first = semantic(crs->first, sc);
+ crs->first = resolveProperties(sc, crs->first);
+ sc = sc->endCTFE();
+ crs->first = crs->first->implicitCastTo(sc, sw->condition->type);
+ crs->first = crs->first->ctfeInterpret();
+
+ sc = sc->startCTFE();
+ crs->last = semantic(crs->last, sc);
+ crs->last = resolveProperties(sc, crs->last);
+ sc = sc->endCTFE();
+ crs->last = crs->last->implicitCastTo(sc, sw->condition->type);
+ crs->last = crs->last->ctfeInterpret();
+
+ if (crs->first->op == TOKerror || crs->last->op == TOKerror || errors)
+ {
+ if (crs->statement)
+ semantic(crs->statement, sc);
+ return setError();
+ }
+
+ uinteger_t fval = crs->first->toInteger();
+ uinteger_t lval = crs->last->toInteger();
+
+
+ if ( (crs->first->type->isunsigned() && fval > lval) ||
+ (!crs->first->type->isunsigned() && (sinteger_t)fval > (sinteger_t)lval))
+ {
+ crs->error("first case %s is greater than last case %s",
+ crs->first->toChars(), crs->last->toChars());
+ errors = true;
+ lval = fval;
+ }
+
+ if (lval - fval > 256)
+ {
+ crs->error("had %llu cases which is more than 256 cases in case range", lval - fval);
+ errors = true;
+ lval = fval + 256;
+ }
+
+ if (errors)
+ return setError();
+
+ /* This works by replacing the CaseRange with an array of Case's.
+ *
+ * case a: .. case b: s;
+ * =>
+ * case a:
+ * [...]
+ * case b:
+ * s;
+ */
+
+ Statements *statements = new Statements();
+ for (uinteger_t i = fval; i != lval + 1; i++)
+ {
+ Statement *s = crs->statement;
+ if (i != lval) // if not last case
+ s = new ExpStatement(crs->loc, (Expression *)NULL);
+ Expression *e = new IntegerExp(crs->loc, i, crs->first->type);
+ Statement *cs = new CaseStatement(crs->loc, e, s);
+ statements->push(cs);
+ }
+ Statement *s = new CompoundStatement(crs->loc, statements);
+ s = semantic(s, sc);
+ result = s;
+ }
+
+ void visit(DefaultStatement *ds)
+ {
+ //printf("DefaultStatement::semantic()\n");
+ bool errors = false;
+ if (sc->sw)
+ {
+ if (sc->sw->sdefault)
+ {
+ ds->error("switch statement already has a default");
+ errors = true;
+ }
+ sc->sw->sdefault = ds;
+
+ if (sc->sw->tf != sc->tf)
+ {
+ ds->error("switch and default are in different finally blocks");
+ errors = true;
+ }
+ if (sc->sw->isFinal)
+ {
+ ds->error("default statement not allowed in final switch statement");
+ errors = true;
+ }
+ }
+ else
+ {
+ ds->error("default not in switch statement");
+ errors = true;
+ }
+ ds->statement = semantic(ds->statement, sc);
+ if (errors || ds->statement->isErrorStatement())
+ return setError();
+
+ ds->lastVar = sc->lastVar;
+ result = ds;
+ }
+
+ void visit(GotoDefaultStatement *gds)
+ {
+ gds->sw = sc->sw;
+ if (!gds->sw)
+ {
+ gds->error("goto default not in switch statement");
+ return setError();
+ }
+ if (gds->sw->isFinal)
+ {
+ gds->error("goto default not allowed in final switch statement");
+ return setError();
+ }
+ result = gds;
+ }
+
+ void visit(GotoCaseStatement *gcs)
+ {
+ if (!sc->sw)
+ {
+ gcs->error("goto case not in switch statement");
+ return setError();
+ }
+
+ if (gcs->exp)
+ {
+ gcs->exp = semantic(gcs->exp, sc);
+ gcs->exp = gcs->exp->implicitCastTo(sc, sc->sw->condition->type);
+ gcs->exp = gcs->exp->optimize(WANTvalue);
+ if (gcs->exp->op == TOKerror)
+ return setError();
+ }
+
+ sc->sw->gotoCases.push(gcs);
+ result = gcs;
+ }
+
+ void visit(ReturnStatement *rs)
+ {
+ //printf("ReturnStatement::semantic() %s\n", toChars());
+
+ FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+
+ if (fd->fes)
+ fd = fd->fes->func; // fd is now function enclosing foreach
+
+ TypeFunction *tf = (TypeFunction *)fd->type;
+ assert(tf->ty == Tfunction);
+
+ if (rs->exp && rs->exp->op == TOKvar && ((VarExp *)rs->exp)->var == fd->vresult)
+ {
+ // return vresult;
+ if (sc->fes)
+ {
+ assert(rs->caseDim == 0);
+ sc->fes->cases->push(rs);
+ result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
+ return;
+ }
+ if (fd->returnLabel)
+ {
+ GotoStatement *gs = new GotoStatement(rs->loc, Id::returnLabel);
+ gs->label = fd->returnLabel;
+ result = gs;
+ return;
+ }
+
+ if (!fd->returns)
+ fd->returns = new ReturnStatements();
+ fd->returns->push(rs);
+ result = rs;
+ return;
+ }
+
+ Type *tret = tf->next;
+ Type *tbret = tret ? tret->toBasetype() : NULL;
+
+ bool inferRef = (tf->isref && (fd->storage_class & STCauto));
+ Expression *e0 = NULL;
+
+ bool errors = false;
+ if (sc->flags & SCOPEcontract)
+ {
+ rs->error("return statements cannot be in contracts");
+ errors = true;
+ }
+ if (sc->os && sc->os->tok != TOKon_scope_failure)
+ {
+ rs->error("return statements cannot be in %s bodies", Token::toChars(sc->os->tok));
+ errors = true;
+ }
+ if (sc->tf)
+ {
+ rs->error("return statements cannot be in finally bodies");
+ errors = true;
+ }
+
+ if (fd->isCtorDeclaration())
+ {
+ if (rs->exp)
+ {
+ rs->error("cannot return expression from constructor");
+ errors = true;
+ }
+
+ // Constructors implicitly do:
+ // return this;
+ rs->exp = new ThisExp(Loc());
+ rs->exp->type = tret;
+ }
+ else if (rs->exp)
+ {
+ fd->hasReturnExp |= (fd->hasReturnExp & 1 ? 16 : 1);
+
+ FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration();
+ if (tret)
+ rs->exp = inferType(rs->exp, tret);
+ else if (fld && fld->treq)
+ rs->exp = inferType(rs->exp, fld->treq->nextOf()->nextOf());
+ rs->exp = semantic(rs->exp, sc);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (rs->exp->op == TOKtype)
+ rs->exp = resolveAliasThis(sc, rs->exp);
+
+ rs->exp = resolveProperties(sc, rs->exp);
+ if (rs->exp->checkType())
+ rs->exp = new ErrorExp();
+ if (FuncDeclaration *f = isFuncAddress(rs->exp))
+ {
+ if (fd->inferRetType && f->checkForwardRef(rs->exp->loc))
+ rs->exp = new ErrorExp();
+ }
+ if (checkNonAssignmentArrayOp(rs->exp))
+ rs->exp = new ErrorExp();
+
+ // Extract side-effect part
+ rs->exp = Expression::extractLast(rs->exp, &e0);
+ if (rs->exp->op == TOKcall)
+ rs->exp = valueNoDtor(rs->exp);
+
+ if (e0)
+ e0 = e0->optimize(WANTvalue);
+
+ /* Void-return function can have void typed expression
+ * on return statement.
+ */
+ if ((tbret && tbret->ty == Tvoid) || rs->exp->type->ty == Tvoid)
+ {
+ if (rs->exp->type->ty != Tvoid)
+ {
+ rs->error("cannot return non-void from void function");
+ errors = true;
+
+ rs->exp = new CastExp(rs->loc, rs->exp, Type::tvoid);
+ rs->exp = semantic(rs->exp, sc);
+ }
+
+ /* Replace:
+ * return exp;
+ * with:
+ * exp; return;
+ */
+ e0 = Expression::combine(e0, rs->exp);
+ rs->exp = NULL;
+ }
+ if (e0)
+ e0 = checkGC(sc, e0);
+ }
+
+ if (rs->exp)
+ {
+ if (fd->inferRetType) // infer return type
+ {
+ if (!tret)
+ {
+ tf->next = rs->exp->type;
+ }
+ else if (tret->ty != Terror && !rs->exp->type->equals(tret))
+ {
+ int m1 = rs->exp->type->implicitConvTo(tret);
+ int m2 = tret->implicitConvTo(rs->exp->type);
+ //printf("exp->type = %s m2<-->m1 tret %s\n", rs->exp->type->toChars(), tret->toChars());
+ //printf("m1 = %d, m2 = %d\n", m1, m2);
+
+ if (m1 && m2)
+ ;
+ else if (!m1 && m2)
+ tf->next = rs->exp->type;
+ else if (m1 && !m2)
+ ;
+ else if (rs->exp->op != TOKerror)
+ {
+ rs->error("mismatched function return type inference of %s and %s",
+ rs->exp->type->toChars(), tret->toChars());
+ errors = true;
+ tf->next = Type::terror;
+ }
+ }
+
+ tret = tf->next;
+ tbret = tret->toBasetype();
+ }
+
+ if (inferRef) // deduce 'auto ref'
+ {
+ /* Determine "refness" of function return:
+ * if it's an lvalue, return by ref, else return by value
+ */
+ if (rs->exp->isLvalue())
+ {
+ /* May return by ref
+ */
+ if (checkReturnEscapeRef(sc, rs->exp, true))
+ tf->isref = false; // return by value
+ }
+ else
+ tf->isref = false; // return by value
+
+ /* The "refness" is determined by all of return statements.
+ * This means:
+ * return 3; return x; // ok, x can be a value
+ * return x; return 3; // ok, x can be a value
+ */
+ }
+
+ // handle NRVO
+ if (fd->nrvo_can && rs->exp->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)rs->exp;
+ VarDeclaration *v = ve->var->isVarDeclaration();
+
+ if (tf->isref)
+ {
+ // Function returns a reference
+ if (!inferRef)
+ fd->nrvo_can = 0;
+ }
+ else if (!v || v->isOut() || v->isRef())
+ fd->nrvo_can = 0;
+ else if (fd->nrvo_var == NULL)
+ {
+ if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd)
+ {
+ //printf("Setting nrvo to %s\n", v->toChars());
+ fd->nrvo_var = v;
+ }
+ else
+ fd->nrvo_can = 0;
+ }
+ else if (fd->nrvo_var != v)
+ fd->nrvo_can = 0;
+ }
+ else //if (!exp->isLvalue()) // keep NRVO-ability
+ fd->nrvo_can = 0;
+ }
+ else
+ {
+ // handle NRVO
+ fd->nrvo_can = 0;
+
+ // infer return type
+ if (fd->inferRetType)
+ {
+ if (tf->next && tf->next->ty != Tvoid)
+ {
+ if (tf->next->ty != Terror)
+ {
+ rs->error("mismatched function return type inference of void and %s",
+ tf->next->toChars());
+ }
+ errors = true;
+ tf->next = Type::terror;
+ }
+ else
+ tf->next = Type::tvoid;
+
+ tret = tf->next;
+ tbret = tret->toBasetype();
+ }
+
+ if (inferRef) // deduce 'auto ref'
+ tf->isref = false;
+
+ if (tbret->ty != Tvoid) // if non-void return
+ {
+ if (tbret->ty != Terror)
+ rs->error("return expression expected");
+ errors = true;
+ }
+ else if (fd->isMain())
+ {
+ // main() returns 0, even if it returns void
+ rs->exp = new IntegerExp(0);
+ }
+ }
+
+ // If any branches have called a ctor, but this branch hasn't, it's an error
+ if (sc->callSuper & CSXany_ctor &&
+ !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
+ {
+ rs->error("return without calling constructor");
+ errors = true;
+ }
+ sc->callSuper |= CSXreturn;
+ if (sc->fieldinit)
+ {
+ AggregateDeclaration *ad = fd->isMember2();
+ assert(ad);
+ size_t dim = sc->fieldinit_dim;
+ for (size_t i = 0; i < dim; i++)
+ {
+ VarDeclaration *v = ad->fields[i];
+ bool mustInit = (v->storage_class & STCnodefaultctor ||
+ v->type->needsNested());
+ if (mustInit && !(sc->fieldinit[i] & CSXthis_ctor))
+ {
+ rs->error("an earlier return statement skips field %s initialization", v->toChars());
+ errors = true;
+ }
+ sc->fieldinit[i] |= CSXreturn;
+ }
+ }
+
+ if (errors)
+ return setError();
+
+ if (sc->fes)
+ {
+ if (!rs->exp)
+ {
+ // Send out "case receiver" statement to the foreach.
+ // return exp;
+ Statement *s = new ReturnStatement(Loc(), rs->exp);
+ sc->fes->cases->push(s);
+
+ // Immediately rewrite "this" return statement as:
+ // return cases->dim+1;
+ rs->exp = new IntegerExp(sc->fes->cases->dim + 1);
+ if (e0)
+ {
+ result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
+ return;
+ }
+ result = rs;
+ return;
+ }
+ else
+ {
+ fd->buildResultVar(NULL, rs->exp->type);
+ bool r = fd->vresult->checkNestedReference(sc, Loc());
+ assert(!r); // vresult should be always accessible
+
+ // Send out "case receiver" statement to the foreach.
+ // return vresult;
+ Statement *s = new ReturnStatement(Loc(), new VarExp(Loc(), fd->vresult));
+ sc->fes->cases->push(s);
+
+ // Save receiver index for the later rewriting from:
+ // return exp;
+ // to:
+ // vresult = exp; retrun caseDim;
+ rs->caseDim = sc->fes->cases->dim + 1;
+ }
+ }
+ if (rs->exp)
+ {
+ if (!fd->returns)
+ fd->returns = new ReturnStatements();
+ fd->returns->push(rs);
+ }
+ if (e0)
+ {
+ result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
+ return;
+ }
+ result = rs;
+ }
+
+ void visit(BreakStatement *bs)
+ {
+ //printf("BreakStatement::semantic()\n");
+ // If:
+ // break Identifier;
+ if (bs->ident)
+ {
+ bs->ident = fixupLabelName(sc, bs->ident);
+
+ FuncDeclaration *thisfunc = sc->func;
+
+ for (Scope *scx = sc; scx; scx = scx->enclosing)
+ {
+ if (scx->func != thisfunc) // if in enclosing function
+ {
+ if (sc->fes) // if this is the body of a foreach
+ {
+ /* Post this statement to the fes, and replace
+ * it with a return value that caller will put into
+ * a switch. Caller will figure out where the break
+ * label actually is.
+ * Case numbers start with 2, not 0, as 0 is continue
+ * and 1 is break.
+ */
+ sc->fes->cases->push(bs);
+ result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
+ return;
+ }
+ break; // can't break to it
+ }
+
+ LabelStatement *ls = scx->slabel;
+ if (ls && ls->ident == bs->ident)
+ {
+ Statement *s = ls->statement;
+
+ if (!s || !s->hasBreak())
+ bs->error("label '%s' has no break", bs->ident->toChars());
+ else if (ls->tf != sc->tf)
+ bs->error("cannot break out of finally block");
+ else
+ {
+ ls->breaks = true;
+ result = bs;
+ return;
+ }
+ return setError();
+ }
+ }
+ bs->error("enclosing label '%s' for break not found", bs->ident->toChars());
+ return setError();
+ }
+ else if (!sc->sbreak)
+ {
+ if (sc->os && sc->os->tok != TOKon_scope_failure)
+ {
+ bs->error("break is not inside %s bodies", Token::toChars(sc->os->tok));
+ }
+ else if (sc->fes)
+ {
+ // Replace break; with return 1;
+ result = new ReturnStatement(Loc(), new IntegerExp(1));
+ return;
+ }
+ else
+ bs->error("break is not inside a loop or switch");
+ return setError();
+ }
+ result = bs;
+ }
+
+ void visit(ContinueStatement *cs)
+ {
+ //printf("ContinueStatement::semantic() %p\n", cs);
+ if (cs->ident)
+ {
+ cs->ident = fixupLabelName(sc, cs->ident);
+
+ Scope *scx;
+ FuncDeclaration *thisfunc = sc->func;
+
+ for (scx = sc; scx; scx = scx->enclosing)
+ {
+ LabelStatement *ls;
+
+ if (scx->func != thisfunc) // if in enclosing function
+ {
+ if (sc->fes) // if this is the body of a foreach
+ {
+ for (; scx; scx = scx->enclosing)
+ {
+ ls = scx->slabel;
+ if (ls && ls->ident == cs->ident && ls->statement == sc->fes)
+ {
+ // Replace continue ident; with return 0;
+ result = new ReturnStatement(Loc(), new IntegerExp(0));
+ return;
+ }
+ }
+
+ /* Post this statement to the fes, and replace
+ * it with a return value that caller will put into
+ * a switch. Caller will figure out where the break
+ * label actually is.
+ * Case numbers start with 2, not 0, as 0 is continue
+ * and 1 is break.
+ */
+ sc->fes->cases->push(cs);
+ result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->dim + 1));
+ return;
+ }
+ break; // can't continue to it
+ }
+
+ ls = scx->slabel;
+ if (ls && ls->ident == cs->ident)
+ {
+ Statement *s = ls->statement;
+
+ if (!s || !s->hasContinue())
+ cs->error("label '%s' has no continue", cs->ident->toChars());
+ else if (ls->tf != sc->tf)
+ cs->error("cannot continue out of finally block");
+ else
+ {
+ result = cs;
+ return;
+ }
+ return setError();
+ }
+ }
+ cs->error("enclosing label '%s' for continue not found", cs->ident->toChars());
+ return setError();
+ }
+ else if (!sc->scontinue)
+ {
+ if (sc->os && sc->os->tok != TOKon_scope_failure)
+ {
+ cs->error("continue is not inside %s bodies", Token::toChars(sc->os->tok));
+ }
+ else if (sc->fes)
+ {
+ // Replace continue; with return 0;
+ result = new ReturnStatement(Loc(), new IntegerExp(0));
+ return;
+ }
+ else
+ cs->error("continue is not inside a loop");
+ return setError();
+ }
+ result = cs;
+ }
+
+ void visit(SynchronizedStatement *ss)
+ {
+ if (ss->exp)
+ {
+ ss->exp = semantic(ss->exp, sc);
+ ss->exp = resolveProperties(sc, ss->exp);
+ ss->exp = ss->exp->optimize(WANTvalue);
+ ss->exp = checkGC(sc, ss->exp);
+ if (ss->exp->op == TOKerror)
+ goto Lbody;
+ ClassDeclaration *cd = ss->exp->type->isClassHandle();
+ if (!cd)
+ {
+ ss->error("can only synchronize on class objects, not '%s'", ss->exp->type->toChars());
+ return setError();
+ }
+ else if (cd->isInterfaceDeclaration())
+ {
+ /* Cast the interface to an object, as the object has the monitor,
+ * not the interface.
+ */
+ if (!ClassDeclaration::object)
+ {
+ ss->error("missing or corrupt object.d");
+ fatal();
+ }
+
+ Type *t = ClassDeclaration::object->type;
+ t = t->semantic(Loc(), sc)->toBasetype();
+ assert(t->ty == Tclass);
+
+ ss->exp = new CastExp(ss->loc, ss->exp, t);
+ ss->exp = semantic(ss->exp, sc);
+ }
+
+ /* Rewrite as:
+ * auto tmp = exp;
+ * _d_monitorenter(tmp);
+ * try { body } finally { _d_monitorexit(tmp); }
+ */
+ VarDeclaration *tmp = copyToTemp(0, "__sync", ss->exp);
+
+ Statements *cs = new Statements();
+ cs->push(new ExpStatement(ss->loc, tmp));
+
+ Parameters* args = new Parameters;
+ args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL));
+
+ FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter);
+ Expression *e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), new VarExp(ss->loc, tmp));
+ e->type = Type::tvoid; // do not run semantic on e
+ cs->push(new ExpStatement(ss->loc, e));
+
+ FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit);
+ e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), new VarExp(ss->loc, tmp));
+ e->type = Type::tvoid; // do not run semantic on e
+ Statement *s = new ExpStatement(ss->loc, e);
+ s = new TryFinallyStatement(ss->loc, ss->_body, s);
+ cs->push(s);
+
+ s = new CompoundStatement(ss->loc, cs);
+ result = semantic(s, sc);
+ return;
+ }
+ else
+ {
+ /* Generate our own critical section, then rewrite as:
+ * __gshared byte[CriticalSection.sizeof] critsec;
+ * _d_criticalenter(critsec.ptr);
+ * try { body } finally { _d_criticalexit(critsec.ptr); }
+ */
+ Identifier *id = Identifier::generateId("__critsec");
+ Type *t = Type::tint8->sarrayOf(Target::ptrsize + Target::critsecsize());
+ VarDeclaration *tmp = new VarDeclaration(ss->loc, t, id, NULL);
+ tmp->storage_class |= STCtemp | STCgshared | STCstatic;
+
+ Statements *cs = new Statements();
+ cs->push(new ExpStatement(ss->loc, tmp));
+
+ /* This is just a dummy variable for "goto skips declaration" error.
+ * Backend optimizer could remove this unused variable.
+ */
+ VarDeclaration *v = new VarDeclaration(ss->loc, Type::tvoidptr, Identifier::generateId("__sync"), NULL);
+ v->semantic(sc);
+ cs->push(new ExpStatement(ss->loc, v));
+
+ Parameters* args = new Parameters;
+ args->push(new Parameter(0, t->pointerTo(), NULL, NULL));
+
+ FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow);
+ Expression *e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
+ e = semantic(e, sc);
+ e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), e);
+ e->type = Type::tvoid; // do not run semantic on e
+ cs->push(new ExpStatement(ss->loc, e));
+
+ FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit, STCnothrow);
+ e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
+ e = semantic(e, sc);
+ e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), e);
+ e->type = Type::tvoid; // do not run semantic on e
+ Statement *s = new ExpStatement(ss->loc, e);
+ s = new TryFinallyStatement(ss->loc, ss->_body, s);
+ cs->push(s);
+
+ s = new CompoundStatement(ss->loc, cs);
+ result = semantic(s, sc);
+ return;
+ }
+ Lbody:
+ if (ss->_body)
+ ss->_body = semantic(ss->_body, sc);
+ if (ss->_body && ss->_body->isErrorStatement())
+ {
+ result = ss->_body;
+ return;
+ }
+ result = ss;
+ }
+
+ void visit(WithStatement *ws)
+ {
+ ScopeDsymbol *sym;
+ Initializer *init;
+
+ //printf("WithStatement::semantic()\n");
+ ws->exp = semantic(ws->exp, sc);
+ ws->exp = resolveProperties(sc, ws->exp);
+ ws->exp = ws->exp->optimize(WANTvalue);
+ ws->exp = checkGC(sc, ws->exp);
+ if (ws->exp->op == TOKerror)
+ return setError();
+ if (ws->exp->op == TOKscope)
+ {
+ sym = new WithScopeSymbol(ws);
+ sym->parent = sc->scopesym;
+ sym->endlinnum = ws->endloc.linnum;
+ }
+ else if (ws->exp->op == TOKtype)
+ {
+ Dsymbol *s = ((TypeExp *)ws->exp)->type->toDsymbol(sc);
+ if (!s || !s->isScopeDsymbol())
+ {
+ ws->error("with type %s has no members", ws->exp->toChars());
+ return setError();
+ }
+ sym = new WithScopeSymbol(ws);
+ sym->parent = sc->scopesym;
+ sym->endlinnum = ws->endloc.linnum;
+ }
+ else
+ {
+ Type *t = ws->exp->type->toBasetype();
+
+ Expression *olde = ws->exp;
+ if (t->ty == Tpointer)
+ {
+ ws->exp = new PtrExp(ws->loc, ws->exp);
+ ws->exp = semantic(ws->exp, sc);
+ t = ws->exp->type->toBasetype();
+ }
+
+ assert(t);
+ t = t->toBasetype();
+ if (t->isClassHandle())
+ {
+ init = new ExpInitializer(ws->loc, ws->exp);
+ ws->wthis = new VarDeclaration(ws->loc, ws->exp->type, Id::withSym, init);
+ ws->wthis->semantic(sc);
+
+ sym = new WithScopeSymbol(ws);
+ sym->parent = sc->scopesym;
+ sym->endlinnum = ws->endloc.linnum;
+ }
+ else if (t->ty == Tstruct)
+ {
+ if (!ws->exp->isLvalue())
+ {
+ /* Re-write to
+ * {
+ * auto __withtmp = exp
+ * with(__withtmp)
+ * {
+ * ...
+ * }
+ * }
+ */
+ VarDeclaration *tmp = copyToTemp(0, "__withtmp", ws->exp);
+ ExpStatement *es = new ExpStatement(ws->loc, tmp);
+ ws->exp = new VarExp(ws->loc, tmp);
+ Statement *ss = new ScopeStatement(ws->loc, new CompoundStatement(ws->loc, es, ws), ws->endloc);
+ result = semantic(ss, sc);
+ return;
+ }
+ Expression *e = ws->exp->addressOf();
+ init = new ExpInitializer(ws->loc, e);
+ ws->wthis = new VarDeclaration(ws->loc, e->type, Id::withSym, init);
+ ws->wthis->semantic(sc);
+ sym = new WithScopeSymbol(ws);
+ // Need to set the scope to make use of resolveAliasThis
+ sym->setScope(sc);
+ sym->parent = sc->scopesym;
+ sym->endlinnum = ws->endloc.linnum;
+ }
+ else
+ {
+ ws->error("with expressions must be aggregate types or pointers to them, not '%s'", olde->type->toChars());
+ return setError();
+ }
+ }
+
+ if (ws->_body)
+ {
+ sym->_scope = sc;
+ sc = sc->push(sym);
+ sc->insert(sym);
+ ws->_body = semantic(ws->_body, sc);
+ sc->pop();
+ if (ws->_body && ws->_body->isErrorStatement())
+ {
+ result = ws->_body;
+ return;
+ }
+ }
+
+ result = ws;
+ }
+
+ void visit(TryCatchStatement *tcs)
+ {
+ unsigned flags = 0;
+ const unsigned FLAGcpp = 1;
+ const unsigned FLAGd = 2;
+
+ tcs->_body = semanticScope(tcs->_body, sc, NULL, NULL);
+ assert(tcs->_body);
+
+ /* Even if body is empty, still do semantic analysis on catches
+ */
+ bool catchErrors = false;
+ for (size_t i = 0; i < tcs->catches->dim; i++)
+ {
+ Catch *c = (*tcs->catches)[i];
+ semantic(c, sc);
+ if (c->errors)
+ {
+ catchErrors = true;
+ continue;
+ }
+ ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
+ flags |= cd->isCPPclass() ? FLAGcpp : FLAGd;
+
+ // Determine if current catch 'hides' any previous catches
+ for (size_t j = 0; j < i; j++)
+ {
+ Catch *cj = (*tcs->catches)[j];
+ const char *si = c->loc.toChars();
+ const char *sj = cj->loc.toChars();
+
+ if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
+ {
+ tcs->error("catch at %s hides catch at %s", sj, si);
+ catchErrors = true;
+ }
+ }
+ }
+
+ if (sc->func)
+ {
+ if (flags == (FLAGcpp | FLAGd))
+ {
+ tcs->error("cannot mix catching D and C++ exceptions in the same try-catch");
+ catchErrors = true;
+ }
+ }
+
+ if (catchErrors)
+ return setError();
+
+ if (tcs->_body->isErrorStatement())
+ {
+ result = tcs->_body;
+ return;
+ }
+
+ /* If the try body never throws, we can eliminate any catches
+ * of recoverable exceptions.
+ */
+
+ if (!(blockExit(tcs->_body, sc->func, false) & BEthrow) && ClassDeclaration::exception)
+ {
+ for (size_t i = 0; i < tcs->catches->dim; i++)
+ {
+ Catch *c = (*tcs->catches)[i];
+
+ /* If catch exception type is derived from Exception
+ */
+ if (c->type->toBasetype()->implicitConvTo(ClassDeclaration::exception->type) &&
+ (!c->handler || !c->handler->comeFrom()))
+ {
+ // Remove c from the array of catches
+ tcs->catches->remove(i);
+ --i;
+ }
+ }
+ }
+
+ if (tcs->catches->dim == 0)
+ {
+ result = tcs->_body->hasCode() ? tcs->_body : NULL;
+ return;
+ }
+
+ result = tcs;
+ }
+
+ void visit(TryFinallyStatement *tfs)
+ {
+ //printf("TryFinallyStatement::semantic()\n");
+ tfs->_body = semantic(tfs->_body, sc);
+ sc = sc->push();
+ sc->tf = tfs;
+ sc->sbreak = NULL;
+ sc->scontinue = NULL; // no break or continue out of finally block
+ tfs->finalbody = semanticNoScope(tfs->finalbody, sc);
+ sc->pop();
+
+ if (!tfs->_body)
+ {
+ result = tfs->finalbody;
+ return;
+ }
+
+ if (!tfs->finalbody)
+ {
+ result = tfs->_body;
+ return;
+ }
+
+ if (blockExit(tfs->_body, sc->func, false) == BEfallthru)
+ {
+ result = new CompoundStatement(tfs->loc, tfs->_body, tfs->finalbody);
+ return;
+ }
+ result = tfs;
+ }
+
+ void visit(OnScopeStatement *oss)
+ {
+#ifndef IN_GCC
+ if (oss->tok != TOKon_scope_exit)
+ {
+ // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
+ // so the generated catch block cannot be placed in finally block.
+ // See also Catch::semantic.
+ if (sc->os && sc->os->tok != TOKon_scope_failure)
+ {
+ // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
+ oss->error("cannot put %s statement inside %s", Token::toChars(oss->tok), Token::toChars(sc->os->tok));
+ return setError();
+ }
+ if (sc->tf)
+ {
+ oss->error("cannot put %s statement inside finally block", Token::toChars(oss->tok));
+ return setError();
+ }
+ }
+#endif
+
+ sc = sc->push();
+ sc->tf = NULL;
+ sc->os = oss;
+ if (oss->tok != TOKon_scope_failure)
+ {
+ // Jump out from scope(failure) block is allowed.
+ sc->sbreak = NULL;
+ sc->scontinue = NULL;
+ }
+ oss->statement = semanticNoScope(oss->statement, sc);
+ sc->pop();
+
+ if (!oss->statement || oss->statement->isErrorStatement())
+ {
+ result = oss->statement;
+ return;
+ }
+ result = oss;
+ }
+
+ void visit(ThrowStatement *ts)
+ {
+ //printf("ThrowStatement::semantic()\n");
+
+ FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+ fd->hasReturnExp |= 2;
+
+ ts->exp = semantic(ts->exp, sc);
+ ts->exp = resolveProperties(sc, ts->exp);
+ ts->exp = checkGC(sc, ts->exp);
+ if (ts->exp->op == TOKerror)
+ return setError();
+
+ checkThrowEscape(sc, ts->exp, false);
+
+ ClassDeclaration *cd = ts->exp->type->toBasetype()->isClassHandle();
+ if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL)))
+ {
+ ts->error("can only throw class objects derived from Throwable, not type %s", ts->exp->type->toChars());
+ return setError();
+ }
+
+ result = ts;
+ }
+
+ void visit(DebugStatement *ds)
+ {
+ if (ds->statement)
+ {
+ sc = sc->push();
+ sc->flags |= SCOPEdebug;
+ ds->statement = semantic(ds->statement, sc);
+ sc->pop();
+ }
+ result = ds->statement;
+ }
+
+ void visit(GotoStatement *gs)
+ {
+ //printf("GotoStatement::semantic()\n");
+ FuncDeclaration *fd = sc->func;
+
+ gs->ident = fixupLabelName(sc, gs->ident);
+ gs->label = fd->searchLabel(gs->ident);
+ gs->tf = sc->tf;
+ gs->os = sc->os;
+ gs->lastVar = sc->lastVar;
+
+ if (!gs->label->statement && sc->fes)
+ {
+ /* Either the goto label is forward referenced or it
+ * is in the function that the enclosing foreach is in.
+ * Can't know yet, so wrap the goto in a scope statement
+ * so we can patch it later, and add it to a 'look at this later'
+ * list.
+ */
+ ScopeStatement *ss = new ScopeStatement(gs->loc, gs, gs->loc);
+ sc->fes->gotos->push(ss); // 'look at this later' list
+ result = ss;
+ return;
+ }
+
+ // Add to fwdref list to check later
+ if (!gs->label->statement)
+ {
+ if (!fd->gotos)
+ fd->gotos = new GotoStatements();
+ fd->gotos->push(gs);
+ }
+ else if (gs->checkLabel())
+ return setError();
+
+ result = gs;
+ }
+
+ void visit(LabelStatement *ls)
+ {
+ //printf("LabelStatement::semantic()\n");
+ FuncDeclaration *fd = sc->parent->isFuncDeclaration();
+
+ ls->ident = fixupLabelName(sc, ls->ident);
+ ls->tf = sc->tf;
+ ls->os = sc->os;
+ ls->lastVar = sc->lastVar;
+
+ LabelDsymbol *ls2 = fd->searchLabel(ls->ident);
+ if (ls2->statement)
+ {
+ ls->error("label '%s' already defined", ls2->toChars());
+ return setError();
+ }
+ else
+ ls2->statement = ls;
+
+ sc = sc->push();
+ sc->scopesym = sc->enclosing->scopesym;
+ sc->callSuper |= CSXlabel;
+ if (sc->fieldinit)
+ {
+ size_t dim = sc->fieldinit_dim;
+ for (size_t i = 0; i < dim; i++)
+ sc->fieldinit[i] |= CSXlabel;
+ }
+ sc->slabel = ls;
+ if (ls->statement)
+ ls->statement = semantic(ls->statement, sc);
+ sc->pop();
+
+ result = ls;
+ }
+
+ void visit(AsmStatement *s)
+ {
+ result = asmSemantic(s, sc);
+ }
+
+ void visit(CompoundAsmStatement *cas)
+ {
+ // Apply postfix attributes of the asm block to each statement.
+ sc = sc->push();
+ sc->stc |= cas->stc;
+
+ for (size_t i = 0; i < cas->statements->dim; i++)
+ {
+ Statement *s = (*cas->statements)[i];
+ (*cas->statements)[i] = s ? semantic(s, sc) : NULL;
+ }
+
+ assert(sc->func);
+ // use setImpure/setGC when the deprecation cycle is over
+ PURE purity;
+ if (!(cas->stc & STCpure) && (purity = sc->func->isPureBypassingInference()) != PUREimpure && purity != PUREfwdref)
+ cas->deprecation("asm statement is assumed to be impure - mark it with 'pure' if it is not");
+ if (!(cas->stc & STCnogc) && sc->func->isNogcBypassingInference())
+ cas->deprecation("asm statement is assumed to use the GC - mark it with '@nogc' if it does not");
+ if (!(cas->stc & (STCtrusted|STCsafe)) && sc->func->setUnsafe())
+ cas->error("asm statement is assumed to be @system - mark it with '@trusted' if it is not");
+
+ sc->pop();
+ result = cas;
+ }
+
+ void visit(ImportStatement *imps)
+ {
+ for (size_t i = 0; i < imps->imports->dim; i++)
+ {
+ Import *s = (*imps->imports)[i]->isImport();
+ assert(!s->aliasdecls.dim);
+ for (size_t j = 0; j < s->names.dim; j++)
+ {
+ Identifier *name = s->names[j];
+ Identifier *alias = s->aliases[j];
+
+ if (!alias)
+ alias = name;
+
+ TypeIdentifier *tname = new TypeIdentifier(s->loc, name);
+ AliasDeclaration *ad = new AliasDeclaration(s->loc, alias, tname);
+ ad->_import = s;
+ s->aliasdecls.push(ad);
+ }
+
+ s->semantic(sc);
+ Module::addDeferredSemantic2(s); // Bugzilla 14666
+ sc->insert(s);
+
+ for (size_t j = 0; j < s->aliasdecls.dim; j++)
+ {
+ sc->insert(s->aliasdecls[j]);
+ }
+ }
+ result = imps;
+ }
+};
+
+Statement *semantic(Statement *s, Scope *sc)
+{
+ StatementSemanticVisitor v = StatementSemanticVisitor(sc);
+ s->accept(&v);
+ return v.result;
+}
+
+void semantic(Catch *c, Scope *sc)
+{
+ //printf("Catch::semantic(%s)\n", ident->toChars());
+
+#ifndef IN_GCC
+ if (sc->os && sc->os->tok != TOKon_scope_failure)
+ {
+ // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
+ error(c->loc, "cannot put catch statement inside %s", Token::toChars(sc->os->tok));
+ c->errors = true;
+ }
+ if (sc->tf)
+ {
+ /* This is because the _d_local_unwind() gets the stack munged
+ * up on this. The workaround is to place any try-catches into
+ * a separate function, and call that.
+ * To fix, have the compiler automatically convert the finally
+ * body into a nested function.
+ */
+ error(c->loc, "cannot put catch statement inside finally block");
+ c->errors = true;
+ }
+#endif
+
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc->scopesym;
+ sc = sc->push(sym);
+
+ if (!c->type)
+ {
+ deprecation(c->loc, "catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior");
+
+ // reference .object.Throwable
+ c->type = getThrowable();
+ }
+ c->type = c->type->semantic(c->loc, sc);
+ if (c->type == Type::terror)
+ c->errors = true;
+ else
+ {
+ ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
+ if (!cd)
+ {
+ error(c->loc, "can only catch class objects, not '%s'", c->type->toChars());
+ c->errors = true;
+ }
+ else if (cd->isCPPclass())
+ {
+ if (!Target::cppExceptions)
+ {
+ error(c->loc, "catching C++ class objects not supported for this target");
+ c->errors = true;
+ }
+ if (sc->func && !sc->intypeof && !c->internalCatch && sc->func->setUnsafe())
+ {
+ error(c->loc, "cannot catch C++ class objects in @safe code");
+ c->errors = true;
+ }
+ }
+ else if (cd != ClassDeclaration::throwable && !ClassDeclaration::throwable->isBaseOf(cd, NULL))
+ {
+ error(c->loc, "can only catch class objects derived from Throwable, not '%s'", c->type->toChars());
+ c->errors = true;
+ }
+ else if (sc->func && !sc->intypeof && !c->internalCatch &&
+ cd != ClassDeclaration::exception && !ClassDeclaration::exception->isBaseOf(cd, NULL) &&
+ sc->func->setUnsafe())
+ {
+ error(c->loc, "can only catch class objects derived from Exception in @safe code, not '%s'", c->type->toChars());
+ c->errors = true;
+ }
+
+ if (c->ident)
+ {
+ c->var = new VarDeclaration(c->loc, c->type, c->ident, NULL);
+ c->var->semantic(sc);
+ sc->insert(c->var);
+ }
+ c->handler = semantic(c->handler, sc);
+ if (c->handler && c->handler->isErrorStatement())
+ c->errors = true;
+ }
+ sc->pop();
+}
+
+Statement *semanticNoScope(Statement *s, Scope *sc)
+{
+ //printf("Statement::semanticNoScope() %s\n", toChars());
+ if (!s->isCompoundStatement() && !s->isScopeStatement())
+ {
+ s = new CompoundStatement(s->loc, s); // so scopeCode() gets called
+ }
+ s = semantic(s, sc);
+ return s;
+}
+
+// Same as semanticNoScope(), but do create a new scope
+Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue)
+{
+ ScopeDsymbol *sym = new ScopeDsymbol();
+ sym->parent = sc->scopesym;
+ Scope *scd = sc->push(sym);
+ if (sbreak)
+ scd->sbreak = sbreak;
+ if (scontinue)
+ scd->scontinue = scontinue;
+ s = semanticNoScope(s, scd);
+ scd->pop();
+ return s;
+}
diff --git a/gcc/d/dmd/staticassert.c b/gcc/d/dmd/staticassert.c
new file mode 100644
index 0000000..476668f
--- /dev/null
+++ b/gcc/d/dmd/staticassert.c
@@ -0,0 +1,104 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/staticassert.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "staticassert.h"
+#include "expression.h"
+#include "id.h"
+#include "scope.h"
+#include "template.h"
+#include "declaration.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
+
+/********************************* AttribDeclaration ****************************/
+
+StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg)
+ : Dsymbol(Id::empty)
+{
+ this->loc = loc;
+ this->exp = exp;
+ this->msg = msg;
+}
+
+Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s)
+{
+ assert(!s);
+ return new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
+}
+
+void StaticAssert::addMember(Scope *, ScopeDsymbol *)
+{
+ // we didn't add anything
+}
+
+void StaticAssert::semantic(Scope *)
+{
+}
+
+void StaticAssert::semantic2(Scope *sc)
+{
+ //printf("StaticAssert::semantic2() %s\n", toChars());
+ ScopeDsymbol *sds = new ScopeDsymbol();
+ sc = sc->push(sds);
+ sc->tinst = NULL;
+ sc->minst = NULL;
+
+ bool errors = false;
+ bool result = evalStaticCondition(sc, exp, exp, errors);
+ sc = sc->pop();
+ if (errors)
+ {
+ errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars());
+ }
+ else if (!result)
+ {
+ if (msg)
+ {
+ sc = sc->startCTFE();
+ msg = ::semantic(msg, sc);
+ msg = resolveProperties(sc, msg);
+ sc = sc->endCTFE();
+ msg = msg->ctfeInterpret();
+ if (StringExp * se = msg->toStringExp())
+ {
+ // same with pragma(msg)
+ se = se->toUTF8(sc);
+ error("\"%.*s\"", (int)se->len, (char *)se->string);
+ }
+ else
+ error("%s", msg->toChars());
+ }
+ else
+ error("(%s) is false", exp->toChars());
+ if (sc->tinst)
+ sc->tinst->printInstantiationTrace();
+ if (!global.gag)
+ fatal();
+ }
+}
+
+bool StaticAssert::oneMember(Dsymbol **ps, Identifier *)
+{
+ //printf("StaticAssert::oneMember())\n");
+ *ps = NULL;
+ return true;
+}
+
+const char *StaticAssert::kind()
+{
+ return "static assert";
+}
diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h
new file mode 100644
index 0000000..0112f02
--- /dev/null
+++ b/gcc/d/dmd/staticassert.h
@@ -0,0 +1,32 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/staticassert.h
+ */
+
+#pragma once
+
+#include "dsymbol.h"
+
+class Expression;
+
+class StaticAssert : public Dsymbol
+{
+public:
+ Expression *exp;
+ Expression *msg;
+
+ StaticAssert(Loc loc, Expression *exp, Expression *msg);
+
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ const char *kind();
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/staticcond.c b/gcc/d/dmd/staticcond.c
new file mode 100644
index 0000000..7a0004f
--- /dev/null
+++ b/gcc/d/dmd/staticcond.c
@@ -0,0 +1,100 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/staticcond.c
+ */
+
+#include "mars.h"
+#include "expression.h"
+#include "mtype.h"
+#include "scope.h"
+
+Expression *semantic(Expression *e, Scope *sc);
+
+/********************************************
+ * Semantically analyze and then evaluate a static condition at compile time.
+ * This is special because short circuit operators &&, || and ?: at the top
+ * level are not semantically analyzed if the result of the expression is not
+ * necessary.
+ * Params:
+ * exp = original expression, for error messages
+ * Returns:
+ * true if evaluates to true
+ */
+
+bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors)
+{
+ if (e->op == TOKandand)
+ {
+ AndAndExp *aae = (AndAndExp *)e;
+ bool result = evalStaticCondition(sc, exp, aae->e1, errors);
+ if (errors || !result)
+ return false;
+ result = evalStaticCondition(sc, exp, aae->e2, errors);
+ return !errors && result;
+ }
+
+ if (e->op == TOKoror)
+ {
+ OrOrExp *ooe = (OrOrExp *)e;
+ bool result = evalStaticCondition(sc, exp, ooe->e1, errors);
+ if (errors)
+ return false;
+ if (result)
+ return true;
+ result = evalStaticCondition(sc, exp, ooe->e2, errors);
+ return !errors && result;
+ }
+
+ if (e->op == TOKquestion)
+ {
+ CondExp *ce = (CondExp *)e;
+ bool result = evalStaticCondition(sc, exp, ce->econd, errors);
+ if (errors)
+ return false;
+ Expression *leg = result ? ce->e1 : ce->e2;
+ result = evalStaticCondition(sc, exp, leg, errors);
+ return !errors && result;
+ }
+
+ unsigned nerrors = global.errors;
+
+ sc = sc->startCTFE();
+ sc->flags |= SCOPEcondition;
+
+ e = semantic(e, sc);
+ e = resolveProperties(sc, e);
+
+ sc = sc->endCTFE();
+ e = e->optimize(WANTvalue);
+
+ if (nerrors != global.errors ||
+ e->op == TOKerror ||
+ e->type->toBasetype() == Type::terror)
+ {
+ errors = true;
+ return false;
+ }
+
+ if (!e->type->isBoolean())
+ {
+ exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars());
+ errors = true;
+ return false;
+ }
+
+ e = e->ctfeInterpret();
+
+ if (e->isBool(true))
+ return true;
+ else if (e->isBool(false))
+ return false;
+
+ e->error("expression %s is not constant", e->toChars());
+ errors = true;
+ return false;
+}
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
new file mode 100644
index 0000000..9379008
--- /dev/null
+++ b/gcc/d/dmd/target.h
@@ -0,0 +1,74 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2013-2018 by The D Language Foundation, All Rights Reserved
+ * written by Iain Buclaw
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/target.h
+ */
+
+#pragma once
+
+// This file contains a data structure that describes a back-end target.
+// At present it is incomplete, but in future it should grow to contain
+// most or all target machine and target O/S specific information.
+#include "globals.h"
+#include "tokens.h"
+
+class ClassDeclaration;
+class Dsymbol;
+class Expression;
+class Type;
+struct OutBuffer;
+
+struct Target
+{
+ static int ptrsize;
+ static int realsize; // size a real consumes in memory
+ static int realpad; // 'padding' added to the CPU real size to bring it up to realsize
+ static int realalignsize; // alignment for reals
+ static bool reverseCppOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
+ static bool cppExceptions; // set if catching C++ exceptions is supported
+ static int c_longsize; // size of a C 'long' or 'unsigned long' type
+ static int c_long_doublesize; // size of a C 'long double'
+ static int classinfosize; // size of 'ClassInfo'
+ static unsigned long long maxStaticDataSize; // maximum size of static data
+
+ template <typename T>
+ struct FPTypeProperties
+ {
+ static real_t max;
+ static real_t min_normal;
+ static real_t nan;
+ static real_t snan;
+ static real_t infinity;
+ static real_t epsilon;
+
+ static d_int64 dig;
+ static d_int64 mant_dig;
+ static d_int64 max_exp;
+ static d_int64 min_exp;
+ static d_int64 max_10_exp;
+ static d_int64 min_10_exp;
+ };
+
+ typedef FPTypeProperties<float> FloatProperties;
+ typedef FPTypeProperties<double> DoubleProperties;
+ typedef FPTypeProperties<real_t> RealProperties;
+
+ static void _init();
+ // Type sizes and support.
+ static unsigned alignsize(Type* type);
+ static unsigned fieldalign(Type* type);
+ static unsigned critsecsize();
+ static Type *va_listType(); // get type of va_list
+ static int isVectorTypeSupported(int sz, Type *type);
+ static bool isVectorOpSupported(Type *type, TOK op, Type *t2 = NULL);
+ // ABI and backend.
+ static const char *toCppMangle(Dsymbol *s);
+ static const char *cppTypeInfoMangle(ClassDeclaration *cd);
+ static const char *cppTypeMangle(Type *t);
+ static Type *cppParameterType(Parameter *p);
+ static LINK systemLinkage();
+};
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
new file mode 100644
index 0000000..f599103
--- /dev/null
+++ b/gcc/d/dmd/template.h
@@ -0,0 +1,397 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/template.h
+ */
+
+#pragma once
+
+#include "root/root.h"
+#include "arraytypes.h"
+#include "dsymbol.h"
+
+
+struct OutBuffer;
+class Identifier;
+class TemplateInstance;
+class TemplateParameter;
+class TemplateTypeParameter;
+class TemplateThisParameter;
+class TemplateValueParameter;
+class TemplateAliasParameter;
+class TemplateTupleParameter;
+class Type;
+class TypeQualified;
+class TypeTypeof;
+struct Scope;
+class Expression;
+class AliasDeclaration;
+class FuncDeclaration;
+class Parameter;
+enum MATCH;
+enum PASS;
+
+class Tuple : public RootObject
+{
+public:
+ Objects objects;
+
+ // kludge for template.isType()
+ int dyncast() const { return DYNCAST_TUPLE; }
+
+ const char *toChars() { return objects.toChars(); }
+};
+
+struct TemplatePrevious
+{
+ TemplatePrevious *prev;
+ Scope *sc;
+ Objects *dedargs;
+};
+
+class TemplateDeclaration : public ScopeDsymbol
+{
+public:
+ TemplateParameters *parameters; // array of TemplateParameter's
+
+ TemplateParameters *origParameters; // originals for Ddoc
+ Expression *constraint;
+
+ // Hash table to look up TemplateInstance's of this TemplateDeclaration
+ void *instances;
+
+ TemplateDeclaration *overnext; // next overloaded TemplateDeclaration
+ TemplateDeclaration *overroot; // first in overnext list
+ FuncDeclaration *funcroot; // first function in unified overload list
+
+ Dsymbol *onemember; // if !=NULL then one member of this template
+
+ bool literal; // this template declaration is a literal
+ bool ismixin; // template declaration is only to be used as a mixin
+ bool isstatic; // this is static template declaration
+ Prot protection;
+
+ TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack
+
+ TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters,
+ Expression *constraint, Dsymbols *decldefs, bool ismixin = false, bool literal = false);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc);
+ bool overloadInsert(Dsymbol *s);
+ bool hasStaticCtorOrDtor();
+ const char *kind();
+ const char *toChars();
+
+ Prot prot();
+
+ bool evaluateConstraint(TemplateInstance *ti, Scope *sc, Scope *paramscope, Objects *dedtypes, FuncDeclaration *fd);
+
+ MATCH matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag);
+ MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs);
+
+ MATCH deduceFunctionTemplateMatch(TemplateInstance *ti, Scope *sc, FuncDeclaration *&fd, Type *tthis, Expressions *fargs);
+ RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o);
+ FuncDeclaration *doHeaderInstantiation(TemplateInstance *ti, Scope *sc, FuncDeclaration *fd, Type *tthis, Expressions *fargs);
+ TemplateInstance *findExistingInstance(TemplateInstance *tithis, Expressions *fargs);
+ TemplateInstance *addInstance(TemplateInstance *ti);
+ void removeInstance(TemplateInstance *handle);
+
+ TemplateDeclaration *isTemplateDeclaration() { return this; }
+
+ TemplateTupleParameter *isVariadic();
+ bool isOverloadable();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* For type-parameter:
+ * template Foo(ident) // specType is set to NULL
+ * template Foo(ident : specType)
+ * For value-parameter:
+ * template Foo(valType ident) // specValue is set to NULL
+ * template Foo(valType ident : specValue)
+ * For alias-parameter:
+ * template Foo(alias ident)
+ * For this-parameter:
+ * template Foo(this ident)
+ */
+class TemplateParameter
+{
+public:
+ Loc loc;
+ Identifier *ident;
+
+ /* True if this is a part of precedent parameter specialization pattern.
+ *
+ * template A(T : X!TL, alias X, TL...) {}
+ * // X and TL are dependent template parameter
+ *
+ * A dependent template parameter should return MATCHexact in matchArg()
+ * to respect the match level of the corresponding precedent parameter.
+ */
+ bool dependent;
+
+ TemplateParameter(Loc loc, Identifier *ident);
+
+ virtual TemplateTypeParameter *isTemplateTypeParameter();
+ virtual TemplateValueParameter *isTemplateValueParameter();
+ virtual TemplateAliasParameter *isTemplateAliasParameter();
+ virtual TemplateThisParameter *isTemplateThisParameter();
+ virtual TemplateTupleParameter *isTemplateTupleParameter();
+
+ virtual TemplateParameter *syntaxCopy() = 0;
+ virtual bool declareParameter(Scope *sc) = 0;
+ virtual bool semantic(Scope *sc, TemplateParameters *parameters) = 0;
+ virtual void print(RootObject *oarg, RootObject *oded) = 0;
+ virtual RootObject *specialization() = 0;
+ virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0;
+ virtual bool hasDefaultArg() = 0;
+
+ /* Match actual argument against parameter.
+ */
+ virtual MATCH matchArg(Loc instLoc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+ virtual MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0;
+
+ /* Create dummy argument based on parameter.
+ */
+ virtual void *dummyArg() = 0;
+ virtual void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ * ident : specType = defaultType
+ */
+class TemplateTypeParameter : public TemplateParameter
+{
+ using TemplateParameter::matchArg;
+public:
+ Type *specType; // type parameter: if !=NULL, this is the type specialization
+ Type *defaultType;
+
+ static Type *tdummy;
+
+ TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
+
+ TemplateTypeParameter *isTemplateTypeParameter();
+ TemplateParameter *syntaxCopy();
+ bool declareParameter(Scope *sc);
+ bool semantic(Scope *sc, TemplateParameters *parameters);
+ void print(RootObject *oarg, RootObject *oded);
+ RootObject *specialization();
+ RootObject *defaultArg(Loc instLoc, Scope *sc);
+ bool hasDefaultArg();
+ MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+ void *dummyArg();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ * this ident : specType = defaultType
+ */
+class TemplateThisParameter : public TemplateTypeParameter
+{
+public:
+ TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
+
+ TemplateThisParameter *isTemplateThisParameter();
+ TemplateParameter *syntaxCopy();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ * valType ident : specValue = defaultValue
+ */
+class TemplateValueParameter : public TemplateParameter
+{
+ using TemplateParameter::matchArg;
+public:
+ Type *valType;
+ Expression *specValue;
+ Expression *defaultValue;
+
+ static AA *edummies;
+
+ TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue);
+
+ TemplateValueParameter *isTemplateValueParameter();
+ TemplateParameter *syntaxCopy();
+ bool declareParameter(Scope *sc);
+ bool semantic(Scope *sc, TemplateParameters *parameters);
+ void print(RootObject *oarg, RootObject *oded);
+ RootObject *specialization();
+ RootObject *defaultArg(Loc instLoc, Scope *sc);
+ bool hasDefaultArg();
+ MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+ void *dummyArg();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ * specType ident : specAlias = defaultAlias
+ */
+class TemplateAliasParameter : public TemplateParameter
+{
+ using TemplateParameter::matchArg;
+public:
+ Type *specType;
+ RootObject *specAlias;
+ RootObject *defaultAlias;
+
+ static Dsymbol *sdummy;
+
+ TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, RootObject *specAlias, RootObject *defaultAlias);
+
+ TemplateAliasParameter *isTemplateAliasParameter();
+ TemplateParameter *syntaxCopy();
+ bool declareParameter(Scope *sc);
+ bool semantic(Scope *sc, TemplateParameters *parameters);
+ void print(RootObject *oarg, RootObject *oded);
+ RootObject *specialization();
+ RootObject *defaultArg(Loc instLoc, Scope *sc);
+ bool hasDefaultArg();
+ MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+ void *dummyArg();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Syntax:
+ * ident ...
+ */
+class TemplateTupleParameter : public TemplateParameter
+{
+public:
+ TemplateTupleParameter(Loc loc, Identifier *ident);
+
+ TemplateTupleParameter *isTemplateTupleParameter();
+ TemplateParameter *syntaxCopy();
+ bool declareParameter(Scope *sc);
+ bool semantic(Scope *sc, TemplateParameters *parameters);
+ void print(RootObject *oarg, RootObject *oded);
+ RootObject *specialization();
+ RootObject *defaultArg(Loc instLoc, Scope *sc);
+ bool hasDefaultArg();
+ MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+ MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
+ void *dummyArg();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/* Given:
+ * foo!(args) =>
+ * name = foo
+ * tiargs = args
+ */
+class TemplateInstance : public ScopeDsymbol
+{
+public:
+ Identifier *name;
+
+ // Array of Types/Expressions of template
+ // instance arguments [int*, char, 10*10]
+ Objects *tiargs;
+
+ // Array of Types/Expressions corresponding
+ // to TemplateDeclaration.parameters
+ // [int, char, 100]
+ Objects tdtypes;
+
+ Dsymbol *tempdecl; // referenced by foo.bar.abc
+ Dsymbol *enclosing; // if referencing local symbols, this is the context
+ Dsymbol *aliasdecl; // !=NULL if instance is an alias for its sole member
+ TemplateInstance *inst; // refer to existing instance
+ ScopeDsymbol *argsym; // argument symbol table
+ int inuse; // for recursive expansion detection
+ int nest; // for recursive pretty printing detection
+ bool semantictiargsdone; // has semanticTiargs() been done?
+ bool havetempdecl; // if used second constructor
+ bool gagged; // if the instantiation is done with error gagging
+ hash_t hash; // cached result of toHash()
+ Expressions *fargs; // for function template, these are the function arguments
+
+ TemplateInstances* deferred;
+
+ Module *memberOf; // if !null, then this TemplateInstance appears in memberOf.members[]
+
+ // Used to determine the instance needs code generation.
+ // Note that these are inaccurate until semantic analysis phase completed.
+ TemplateInstance *tinst; // enclosing template instance
+ TemplateInstance *tnext; // non-first instantiated instances
+ Module *minst; // the top module that instantiated this instance
+
+ TemplateInstance(Loc loc, Identifier *temp_id);
+ TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs);
+ static Objects *arraySyntaxCopy(Objects *objs);
+ Dsymbol *syntaxCopy(Dsymbol *);
+ void semantic(Scope *sc, Expressions *fargs);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ void semantic3(Scope *sc);
+ Dsymbol *toAlias(); // resolve real symbol
+ const char *kind();
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ const char *toChars();
+ const char* toPrettyCharsHelper();
+ void printInstantiationTrace();
+ Identifier *getIdent();
+ int compare(RootObject *o);
+ hash_t toHash();
+
+ bool needsCodegen();
+
+ // Internal
+ bool findTempDecl(Scope *sc, WithScopeSymbol **pwithsym);
+ bool updateTempDecl(Scope *sc, Dsymbol *s);
+ static bool semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags);
+ bool semanticTiargs(Scope *sc);
+ bool findBestMatch(Scope *sc, Expressions *fargs);
+ bool needsTypeInference(Scope *sc, int flag = 0);
+ bool hasNestedArgs(Objects *tiargs, bool isstatic);
+ Dsymbols *appendToModuleMember();
+ void declareParameters(Scope *sc);
+ Identifier *genIdent(Objects *args);
+ void expandMembers(Scope *sc);
+ void tryExpandMembers(Scope *sc);
+ void trySemantic3(Scope *sc2);
+
+ TemplateInstance *isTemplateInstance() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TemplateMixin : public TemplateInstance
+{
+public:
+ TypeQualified *tqual;
+
+ TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs);
+ Dsymbol *syntaxCopy(Dsymbol *s);
+ void semantic(Scope *sc);
+ void semantic2(Scope *sc);
+ void semantic3(Scope *sc);
+ const char *kind();
+ bool oneMember(Dsymbol **ps, Identifier *ident);
+ int apply(Dsymbol_apply_ft_t fp, void *param);
+ bool hasPointers();
+ void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ const char *toChars();
+
+ bool findTempDecl(Scope *sc);
+
+ TemplateMixin *isTemplateMixin() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+Expression *isExpression(RootObject *o);
+Dsymbol *isDsymbol(RootObject *o);
+Type *isType(RootObject *o);
+Tuple *isTuple(RootObject *o);
+Parameter *isParameter(RootObject *o);
+bool arrayObjectIsError(Objects *args);
+bool isError(RootObject *o);
+Type *getType(RootObject *o);
+Dsymbol *getDsymbol(RootObject *o);
+
+RootObject *objectSyntaxCopy(RootObject *o);
diff --git a/gcc/d/dmd/tokens.c b/gcc/d/dmd/tokens.c
new file mode 100644
index 0000000..6f68e47
--- /dev/null
+++ b/gcc/d/dmd/tokens.c
@@ -0,0 +1,476 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.c
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "tokens.h"
+#include "root/rmem.h"
+#include "root/outbuffer.h"
+#include "id.h"
+#include "identifier.h"
+#include "utf.h"
+
+/************************* Token **********************************************/
+
+Token *Token::freelist = NULL;
+
+const char *Token::tochars[TOKMAX];
+
+Token *Token::alloc()
+{
+ if (Token::freelist)
+ {
+ Token *t = freelist;
+ freelist = t->next;
+ t->next = NULL;
+ return t;
+ }
+
+ return new Token();
+}
+
+void Token::free()
+{
+ next = freelist;
+ freelist = this;
+}
+
+const char *Token::toChars() const
+{
+ static char buffer[3 + 3 * sizeof(floatvalue) + 1];
+
+ const char *p = &buffer[0];
+ switch (value)
+ {
+ case TOKint32v:
+ sprintf(&buffer[0],"%d",(d_int32)int64value);
+ break;
+
+ case TOKuns32v:
+ case TOKcharv:
+ case TOKwcharv:
+ case TOKdcharv:
+ sprintf(&buffer[0],"%uU",(d_uns32)uns64value);
+ break;
+
+ case TOKint64v:
+ sprintf(&buffer[0],"%lldL",(longlong)int64value);
+ break;
+
+ case TOKuns64v:
+ sprintf(&buffer[0],"%lluUL",(ulonglong)uns64value);
+ break;
+
+ case TOKfloat32v:
+ CTFloat::sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "f");
+ break;
+
+ case TOKfloat64v:
+ CTFloat::sprint(&buffer[0], 'g', floatvalue);
+ break;
+
+ case TOKfloat80v:
+ CTFloat::sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "L");
+ break;
+
+ case TOKimaginary32v:
+ CTFloat::sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "fi");
+ break;
+
+ case TOKimaginary64v:
+ CTFloat::sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "i");
+ break;
+
+ case TOKimaginary80v:
+ CTFloat::sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "Li");
+ break;
+
+ case TOKstring:
+ {
+ OutBuffer buf;
+ buf.writeByte('"');
+ for (size_t i = 0; i < len; )
+ {
+ unsigned c;
+ utf_decodeChar((utf8_t *)ustring, len, &i, &c);
+ switch (c)
+ {
+ case 0:
+ break;
+
+ case '"':
+ case '\\':
+ buf.writeByte('\\');
+ /* fall through */
+ default:
+ if (c <= 0x7F)
+ {
+ if (isprint(c))
+ buf.writeByte(c);
+ else
+ buf.printf("\\x%02x", c);
+ }
+ else if (c <= 0xFFFF)
+ buf.printf("\\u%04x", c);
+ else
+ buf.printf("\\U%08x", c);
+ continue;
+ }
+ break;
+ }
+ buf.writeByte('"');
+ if (postfix)
+ buf.writeByte(postfix);
+ p = buf.extractString();
+ }
+ break;
+
+ case TOKxstring:
+ {
+ OutBuffer buf;
+ buf.writeByte('x');
+ buf.writeByte('"');
+ for (size_t i = 0; i < len; i++)
+ {
+ if (i)
+ buf.writeByte(' ');
+ buf.printf("%02x", ustring[i]);
+ }
+ buf.writeByte('"');
+ if (postfix)
+ buf.writeByte(postfix);
+ buf.writeByte(0);
+ p = (char *)buf.extractData();
+ break;
+ }
+
+ case TOKidentifier:
+ case TOKenum:
+ case TOKstruct:
+ case TOKimport:
+ case TOKwchar: case TOKdchar:
+ case TOKbool: case TOKchar:
+ case TOKint8: case TOKuns8:
+ case TOKint16: case TOKuns16:
+ case TOKint32: case TOKuns32:
+ case TOKint64: case TOKuns64:
+ case TOKint128: case TOKuns128:
+ case TOKfloat32: case TOKfloat64: case TOKfloat80:
+ case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
+ case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
+ case TOKvoid:
+ p = ident->toChars();
+ break;
+
+ default:
+ p = toChars(value);
+ break;
+ }
+ return p;
+}
+
+const char *Token::toChars(TOK value)
+{
+ static char buffer[3 + 3 * sizeof(value) + 1];
+
+ const char *p = tochars[value];
+ if (!p)
+ {
+ sprintf(&buffer[0],"TOK%d",value);
+ p = &buffer[0];
+ }
+ return p;
+}
+
+/****************************************
+ */
+
+struct Keyword
+{
+ const char *name;
+ TOK value;
+};
+
+static size_t nkeywords;
+static Keyword keywords[] =
+{
+ { "this", TOKthis },
+ { "super", TOKsuper },
+ { "assert", TOKassert },
+ { "null", TOKnull },
+ { "true", TOKtrue },
+ { "false", TOKfalse },
+ { "cast", TOKcast },
+ { "new", TOKnew },
+ { "delete", TOKdelete },
+ { "throw", TOKthrow },
+ { "module", TOKmodule },
+ { "pragma", TOKpragma },
+ { "typeof", TOKtypeof },
+ { "typeid", TOKtypeid },
+
+ { "template", TOKtemplate },
+
+ { "void", TOKvoid },
+ { "byte", TOKint8 },
+ { "ubyte", TOKuns8 },
+ { "short", TOKint16 },
+ { "ushort", TOKuns16 },
+ { "int", TOKint32 },
+ { "uint", TOKuns32 },
+ { "long", TOKint64 },
+ { "ulong", TOKuns64 },
+ { "cent", TOKint128, },
+ { "ucent", TOKuns128, },
+ { "float", TOKfloat32 },
+ { "double", TOKfloat64 },
+ { "real", TOKfloat80 },
+
+ { "bool", TOKbool },
+ { "char", TOKchar },
+ { "wchar", TOKwchar },
+ { "dchar", TOKdchar },
+
+ { "ifloat", TOKimaginary32 },
+ { "idouble", TOKimaginary64 },
+ { "ireal", TOKimaginary80 },
+
+ { "cfloat", TOKcomplex32 },
+ { "cdouble", TOKcomplex64 },
+ { "creal", TOKcomplex80 },
+
+ { "delegate", TOKdelegate },
+ { "function", TOKfunction },
+
+ { "is", TOKis },
+ { "if", TOKif },
+ { "else", TOKelse },
+ { "while", TOKwhile },
+ { "for", TOKfor },
+ { "do", TOKdo },
+ { "switch", TOKswitch },
+ { "case", TOKcase },
+ { "default", TOKdefault },
+ { "break", TOKbreak },
+ { "continue", TOKcontinue },
+ { "synchronized", TOKsynchronized },
+ { "return", TOKreturn },
+ { "goto", TOKgoto },
+ { "try", TOKtry },
+ { "catch", TOKcatch },
+ { "finally", TOKfinally },
+ { "with", TOKwith },
+ { "asm", TOKasm },
+ { "foreach", TOKforeach },
+ { "foreach_reverse", TOKforeach_reverse },
+ { "scope", TOKscope },
+
+ { "struct", TOKstruct },
+ { "class", TOKclass },
+ { "interface", TOKinterface },
+ { "union", TOKunion },
+ { "enum", TOKenum },
+ { "import", TOKimport },
+ { "mixin", TOKmixin },
+ { "static", TOKstatic },
+ { "final", TOKfinal },
+ { "const", TOKconst },
+ { "alias", TOKalias },
+ { "override", TOKoverride },
+ { "abstract", TOKabstract },
+ { "debug", TOKdebug },
+ { "deprecated", TOKdeprecated },
+ { "in", TOKin },
+ { "out", TOKout },
+ { "inout", TOKinout },
+ { "lazy", TOKlazy },
+ { "auto", TOKauto },
+
+ { "align", TOKalign },
+ { "extern", TOKextern },
+ { "private", TOKprivate },
+ { "package", TOKpackage },
+ { "protected", TOKprotected },
+ { "public", TOKpublic },
+ { "export", TOKexport },
+
+ { "invariant", TOKinvariant },
+ { "unittest", TOKunittest },
+ { "version", TOKversion },
+
+ { "__argTypes", TOKargTypes },
+ { "__parameters", TOKparameters },
+ { "ref", TOKref },
+ { "macro", TOKmacro },
+
+ { "pure", TOKpure },
+ { "nothrow", TOKnothrow },
+ { "__gshared", TOKgshared },
+ { "__traits", TOKtraits },
+ { "__vector", TOKvector },
+ { "__overloadset", TOKoverloadset },
+ { "__FILE__", TOKfile },
+ { "__FILE_FULL_PATH__", TOKfilefullpath },
+ { "__LINE__", TOKline },
+ { "__MODULE__", TOKmodulestring },
+ { "__FUNCTION__", TOKfuncstring },
+ { "__PRETTY_FUNCTION__", TOKprettyfunc },
+ { "shared", TOKshared },
+ { "immutable", TOKimmutable },
+ { NULL, TOKreserved }
+};
+
+int Token::isKeyword()
+{
+ for (size_t u = 0; u < nkeywords; u++)
+ {
+ if (keywords[u].value == value)
+ return 1;
+ }
+ return 0;
+}
+
+struct TokenInitializer
+{
+ TokenInitializer();
+};
+
+static TokenInitializer tokeninitializer;
+
+TokenInitializer::TokenInitializer()
+{
+ Identifier::initTable();
+ for (nkeywords = 0; keywords[nkeywords].name; nkeywords++)
+ {
+ //printf("keyword[%d] = '%s'\n",u, keywords[u].name);
+ const char *s = keywords[nkeywords].name;
+ size_t len = strlen(s);
+ TOK v = keywords[nkeywords].value;
+ Identifier::idPool(s, len, v);
+
+ //printf("tochars[%d] = '%s'\n",v, s);
+ Token::tochars[v] = s;
+ }
+
+ Token::tochars[TOKeof] = "EOF";
+ Token::tochars[TOKlcurly] = "{";
+ Token::tochars[TOKrcurly] = "}";
+ Token::tochars[TOKlparen] = "(";
+ Token::tochars[TOKrparen] = ")";
+ Token::tochars[TOKlbracket] = "[";
+ Token::tochars[TOKrbracket] = "]";
+ Token::tochars[TOKsemicolon] = ";";
+ Token::tochars[TOKcolon] = ":";
+ Token::tochars[TOKcomma] = ",";
+ Token::tochars[TOKdot] = ".";
+ Token::tochars[TOKxor] = "^";
+ Token::tochars[TOKxorass] = "^=";
+ Token::tochars[TOKassign] = "=";
+ Token::tochars[TOKconstruct] = "=";
+ Token::tochars[TOKblit] = "=";
+ Token::tochars[TOKlt] = "<";
+ Token::tochars[TOKgt] = ">";
+ Token::tochars[TOKle] = "<=";
+ Token::tochars[TOKge] = ">=";
+ Token::tochars[TOKequal] = "==";
+ Token::tochars[TOKnotequal] = "!=";
+ Token::tochars[TOKnotidentity] = "!is";
+
+ Token::tochars[TOKunord] = "!<>=";
+ Token::tochars[TOKue] = "!<>";
+ Token::tochars[TOKlg] = "<>";
+ Token::tochars[TOKleg] = "<>=";
+ Token::tochars[TOKule] = "!>";
+ Token::tochars[TOKul] = "!>=";
+ Token::tochars[TOKuge] = "!<";
+ Token::tochars[TOKug] = "!<=";
+
+ Token::tochars[TOKnot] = "!";
+ Token::tochars[TOKshl] = "<<";
+ Token::tochars[TOKshr] = ">>";
+ Token::tochars[TOKushr] = ">>>";
+ Token::tochars[TOKadd] = "+";
+ Token::tochars[TOKmin] = "-";
+ Token::tochars[TOKmul] = "*";
+ Token::tochars[TOKdiv] = "/";
+ Token::tochars[TOKmod] = "%";
+ Token::tochars[TOKslice] = "..";
+ Token::tochars[TOKdotdotdot] = "...";
+ Token::tochars[TOKand] = "&";
+ Token::tochars[TOKandand] = "&&";
+ Token::tochars[TOKor] = "|";
+ Token::tochars[TOKoror] = "||";
+ Token::tochars[TOKarray] = "[]";
+ Token::tochars[TOKindex] = "[i]";
+ Token::tochars[TOKaddress] = "&";
+ Token::tochars[TOKstar] = "*";
+ Token::tochars[TOKtilde] = "~";
+ Token::tochars[TOKdollar] = "$";
+ Token::tochars[TOKcast] = "cast";
+ Token::tochars[TOKplusplus] = "++";
+ Token::tochars[TOKminusminus] = "--";
+ Token::tochars[TOKpreplusplus] = "++";
+ Token::tochars[TOKpreminusminus] = "--";
+ Token::tochars[TOKtype] = "type";
+ Token::tochars[TOKquestion] = "?";
+ Token::tochars[TOKneg] = "-";
+ Token::tochars[TOKuadd] = "+";
+ Token::tochars[TOKvar] = "var";
+ Token::tochars[TOKaddass] = "+=";
+ Token::tochars[TOKminass] = "-=";
+ Token::tochars[TOKmulass] = "*=";
+ Token::tochars[TOKdivass] = "/=";
+ Token::tochars[TOKmodass] = "%=";
+ Token::tochars[TOKshlass] = "<<=";
+ Token::tochars[TOKshrass] = ">>=";
+ Token::tochars[TOKushrass] = ">>>=";
+ Token::tochars[TOKandass] = "&=";
+ Token::tochars[TOKorass] = "|=";
+ Token::tochars[TOKcatass] = "~=";
+ Token::tochars[TOKcat] = "~";
+ Token::tochars[TOKcall] = "call";
+ Token::tochars[TOKidentity] = "is";
+ Token::tochars[TOKnotidentity] = "!is";
+
+ Token::tochars[TOKorass] = "|=";
+ Token::tochars[TOKidentifier] = "identifier";
+ Token::tochars[TOKat] = "@";
+ Token::tochars[TOKpow] = "^^";
+ Token::tochars[TOKpowass] = "^^=";
+ Token::tochars[TOKgoesto] = "=>";
+ Token::tochars[TOKpound] = "#";
+
+ // For debugging
+ Token::tochars[TOKerror] = "error";
+ Token::tochars[TOKdotid] = "dotid";
+ Token::tochars[TOKdottd] = "dottd";
+ Token::tochars[TOKdotti] = "dotti";
+ Token::tochars[TOKdotvar] = "dotvar";
+ Token::tochars[TOKdottype] = "dottype";
+ Token::tochars[TOKsymoff] = "symoff";
+ Token::tochars[TOKarraylength] = "arraylength";
+ Token::tochars[TOKarrayliteral] = "arrayliteral";
+ Token::tochars[TOKassocarrayliteral] = "assocarrayliteral";
+ Token::tochars[TOKstructliteral] = "structliteral";
+ Token::tochars[TOKstring] = "string";
+ Token::tochars[TOKdsymbol] = "symbol";
+ Token::tochars[TOKtuple] = "tuple";
+ Token::tochars[TOKdeclaration] = "declaration";
+ Token::tochars[TOKon_scope_exit] = "scope(exit)";
+ Token::tochars[TOKon_scope_success] = "scope(success)";
+ Token::tochars[TOKon_scope_failure] = "scope(failure)";
+ Token::tochars[TOKdelegateptr] = "delegateptr";
+}
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
new file mode 100644
index 0000000..410af4e
--- /dev/null
+++ b/gcc/d/dmd/tokens.h
@@ -0,0 +1,233 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/tokens.h
+ */
+
+#pragma once
+
+#include "root/port.h"
+#include "globals.h"
+
+class Identifier;
+
+/* Tokens:
+ ( )
+ [ ]
+ { }
+ < > <= >= == != === !==
+ << >> <<= >>= >>> >>>=
+ + - += -=
+ * / % *= /= %=
+ & | ^ &= |= ^=
+ = ! ~ @
+ ^^ ^^=
+ ++ --
+ . -> : , =>
+ ? && ||
+ */
+
+enum TOK
+{
+ TOKreserved,
+
+ // Other
+ TOKlparen, TOKrparen,
+ TOKlbracket, TOKrbracket,
+ TOKlcurly, TOKrcurly,
+ TOKcolon, TOKneg,
+ TOKsemicolon, TOKdotdotdot,
+ TOKeof, TOKcast,
+ TOKnull, TOKassert,
+ TOKtrue, TOKfalse,
+ TOKarray, TOKcall,
+ TOKaddress,
+ TOKtype, TOKthrow,
+ TOKnew, TOKdelete,
+ TOKstar, TOKsymoff,
+ TOKvar, TOKdotvar,
+ TOKdotid, TOKdotti,
+ TOKdottype, TOKslice,
+ TOKarraylength, TOKversion,
+ TOKmodule, TOKdollar,
+ TOKtemplate, TOKdottd,
+ TOKdeclaration, TOKtypeof,
+ TOKpragma, TOKdsymbol,
+ TOKtypeid, TOKuadd,
+ TOKremove,
+ TOKnewanonclass, TOKcomment,
+ TOKarrayliteral, TOKassocarrayliteral,
+ TOKstructliteral,
+ TOKclassreference,
+ TOKthrownexception,
+ TOKdelegateptr,
+ TOKdelegatefuncptr,
+
+// 54
+ // Operators
+ TOKlt, TOKgt,
+ TOKle, TOKge,
+ TOKequal, TOKnotequal,
+ TOKidentity, TOKnotidentity,
+ TOKindex, TOKis,
+
+// 64
+ // NCEG floating point compares
+ // !<>= <> <>= !> !>= !< !<= !<>
+ TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue,
+
+// 72
+ TOKshl, TOKshr,
+ TOKshlass, TOKshrass,
+ TOKushr, TOKushrass,
+ TOKcat, TOKcatass, // ~ ~=
+ TOKadd, TOKmin, TOKaddass, TOKminass,
+ TOKmul, TOKdiv, TOKmod,
+ TOKmulass, TOKdivass, TOKmodass,
+ TOKand, TOKor, TOKxor,
+ TOKandass, TOKorass, TOKxorass,
+ TOKassign, TOKnot, TOKtilde,
+ TOKplusplus, TOKminusminus, TOKconstruct, TOKblit,
+ TOKdot, TOKarrow, TOKcomma,
+ TOKquestion, TOKandand, TOKoror,
+ TOKpreplusplus, TOKpreminusminus,
+
+// 111
+ // Numeric literals
+ TOKint32v, TOKuns32v,
+ TOKint64v, TOKuns64v,
+ TOKint128v, TOKuns128v,
+ TOKfloat32v, TOKfloat64v, TOKfloat80v,
+ TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
+
+ // Char constants
+ TOKcharv, TOKwcharv, TOKdcharv,
+
+ // Leaf operators
+ TOKidentifier, TOKstring, TOKxstring,
+ TOKthis, TOKsuper,
+ TOKhalt, TOKtuple,
+ TOKerror,
+
+ // Basic types
+ TOKvoid,
+ TOKint8, TOKuns8,
+ TOKint16, TOKuns16,
+ TOKint32, TOKuns32,
+ TOKint64, TOKuns64,
+ TOKint128, TOKuns128,
+ TOKfloat32, TOKfloat64, TOKfloat80,
+ TOKimaginary32, TOKimaginary64, TOKimaginary80,
+ TOKcomplex32, TOKcomplex64, TOKcomplex80,
+ TOKchar, TOKwchar, TOKdchar, TOKbool,
+
+// 158
+ // Aggregates
+ TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
+ TOKalias, TOKoverride, TOKdelegate, TOKfunction,
+ TOKmixin,
+
+ TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
+ TOKstatic, TOKfinal, TOKconst, TOKabstract,
+ TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
+ TOKauto, TOKpackage, TOKmanifest, TOKimmutable,
+
+ // Statements
+ TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
+ TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
+ TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
+ TOKasm, TOKforeach, TOKforeach_reverse,
+ TOKscope,
+ TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
+
+ // Contracts
+ TOKinvariant,
+
+ // Testing
+ TOKunittest,
+
+ // Added after 1.0
+ TOKargTypes,
+ TOKref,
+ TOKmacro,
+
+ TOKparameters,
+ TOKtraits,
+ TOKoverloadset,
+ TOKpure,
+ TOKnothrow,
+ TOKgshared,
+ TOKline,
+ TOKfile,
+ TOKfilefullpath,
+ TOKmodulestring,
+ TOKfuncstring,
+ TOKprettyfunc,
+ TOKshared,
+ TOKat,
+ TOKpow,
+ TOKpowass,
+ TOKgoesto,
+ TOKvector,
+ TOKpound,
+
+ TOKinterval,
+ TOKvoidexp,
+ TOKcantexp,
+
+ TOKMAX
+};
+
+#define TOKwild TOKinout
+
+// Token has an anonymous struct, which is not strict ISO C++.
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+
+struct Token
+{
+ Token *next;
+ Loc loc;
+ const utf8_t *ptr; // pointer to first character of this token within buffer
+ TOK value;
+ const utf8_t *blockComment; // doc comment string prior to this token
+ const utf8_t *lineComment; // doc comment for previous token
+ union
+ {
+ // Integers
+ d_int64 int64value;
+ d_uns64 uns64value;
+
+ // Floats
+ real_t floatvalue;
+
+ struct
+ { utf8_t *ustring; // UTF8 string
+ unsigned len;
+ unsigned char postfix; // 'c', 'w', 'd'
+ };
+
+ Identifier *ident;
+ };
+
+ static const char *tochars[TOKMAX];
+
+ static Token *freelist;
+ static Token *alloc();
+ void free();
+
+ Token() : next(NULL) {}
+ int isKeyword();
+ const char *toChars() const;
+ static const char *toChars(TOK);
+};
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c
new file mode 100644
index 0000000..b869893
--- /dev/null
+++ b/gcc/d/dmd/traits.c
@@ -0,0 +1,1451 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/traits.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+#include "root/rmem.h"
+#include "root/aav.h"
+
+#include "checkedint.h"
+#include "errors.h"
+#include "mtype.h"
+#include "init.h"
+#include "expression.h"
+#include "template.h"
+#include "utf.h"
+#include "enum.h"
+#include "scope.h"
+#include "hdrgen.h"
+#include "statement.h"
+#include "declaration.h"
+#include "aggregate.h"
+#include "import.h"
+#include "id.h"
+#include "dsymbol.h"
+#include "module.h"
+#include "attrib.h"
+#include "parse.h"
+#include "root/speller.h"
+
+typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
+int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
+void freeFieldinit(Scope *sc);
+Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
+Expression *trySemantic(Expression *e, Scope *sc);
+Expression *semantic(Expression *e, Scope *sc);
+Expression *typeToExpression(Type *t);
+
+
+/************************************************
+ * Delegate to be passed to overloadApply() that looks
+ * for functions matching a trait.
+ */
+
+struct Ptrait
+{
+ Expression *e1;
+ Expressions *exps; // collected results
+ Identifier *ident; // which trait we're looking for
+};
+
+static int fptraits(void *param, Dsymbol *s)
+{
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (!f)
+ return 0;
+
+ Ptrait *p = (Ptrait *)param;
+ if (p->ident == Id::getVirtualFunctions && !f->isVirtual())
+ return 0;
+
+ if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod())
+ return 0;
+
+ Expression *e;
+ FuncAliasDeclaration* ad = new FuncAliasDeclaration(f->ident, f, false);
+ ad->protection = f->protection;
+ if (p->e1)
+ e = new DotVarExp(Loc(), p->e1, ad, false);
+ else
+ e = new DsymbolExp(Loc(), ad, false);
+ p->exps->push(e);
+ return 0;
+}
+
+/**
+ * Collects all unit test functions from the given array of symbols.
+ *
+ * This is a helper function used by the implementation of __traits(getUnitTests).
+ *
+ * Input:
+ * symbols array of symbols to collect the functions from
+ * uniqueUnitTests an associative array (should actually be a set) to
+ * keep track of already collected functions. We're
+ * using an AA here to avoid doing a linear search of unitTests
+ *
+ * Output:
+ * unitTests array of DsymbolExp's of the collected unit test functions
+ * uniqueUnitTests updated with symbols from unitTests[ ]
+ */
+static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions *unitTests)
+{
+ if (!symbols)
+ return;
+ for (size_t i = 0; i < symbols->dim; i++)
+ {
+ Dsymbol *symbol = (*symbols)[i];
+ UnitTestDeclaration *unitTest = symbol->isUnitTestDeclaration();
+ if (unitTest)
+ {
+ if (!dmd_aaGetRvalue(uniqueUnitTests, (void *)unitTest))
+ {
+ FuncAliasDeclaration* ad = new FuncAliasDeclaration(unitTest->ident, unitTest, false);
+ ad->protection = unitTest->protection;
+ Expression* e = new DsymbolExp(Loc(), ad, false);
+ unitTests->push(e);
+ bool* value = (bool*) dmd_aaGet(&uniqueUnitTests, (void *)unitTest);
+ *value = true;
+ }
+ }
+ else
+ {
+ AttribDeclaration *attrDecl = symbol->isAttribDeclaration();
+
+ if (attrDecl)
+ {
+ Dsymbols *decl = attrDecl->include(NULL, NULL);
+ collectUnitTests(decl, uniqueUnitTests, unitTests);
+ }
+ }
+ }
+}
+
+/************************ TraitsExp ************************************/
+
+static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); }
+static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); }
+
+bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); }
+bool isTypeFloating(Type *t) { return t->isfloating(); }
+bool isTypeIntegral(Type *t) { return t->isintegral(); }
+bool isTypeScalar(Type *t) { return t->isscalar(); }
+bool isTypeUnsigned(Type *t) { return t->isunsigned(); }
+bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; }
+bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; }
+bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); }
+bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; }
+
+Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t))
+{
+ if (!e->args || !e->args->dim)
+ return False(e);
+ for (size_t i = 0; i < e->args->dim; i++)
+ {
+ Type *t = getType((*e->args)[i]);
+ if (!t || !fp(t))
+ return False(e);
+ }
+ return True(e);
+}
+
+bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); }
+bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); }
+bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); }
+bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); }
+bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); }
+bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); }
+
+Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f))
+{
+ if (!e->args || !e->args->dim)
+ return False(e);
+ for (size_t i = 0; i < e->args->dim; i++)
+ {
+ Dsymbol *s = getDsymbol((*e->args)[i]);
+ if (!s)
+ return False(e);
+ FuncDeclaration *f = s->isFuncDeclaration();
+ if (!f || !fp(f))
+ return False(e);
+ }
+ return True(e);
+}
+
+bool isDeclRef(Declaration *d) { return d->isRef(); }
+bool isDeclOut(Declaration *d) { return d->isOut(); }
+bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; }
+
+Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d))
+{
+ if (!e->args || !e->args->dim)
+ return False(e);
+ for (size_t i = 0; i < e->args->dim; i++)
+ {
+ Dsymbol *s = getDsymbol((*e->args)[i]);
+ if (!s)
+ return False(e);
+ Declaration *d = s->isDeclaration();
+ if (!d || !fp(d))
+ return False(e);
+ }
+ return True(e);
+}
+
+// callback for TypeFunction::attributesApply
+struct PushAttributes
+{
+ Expressions *mods;
+
+ static int fp(void *param, const char *str)
+ {
+ PushAttributes *p = (PushAttributes *)param;
+ p->mods->push(new StringExp(Loc(), const_cast<char *>(str)));
+ return 0;
+ }
+};
+
+StringTable traitsStringTable;
+
+struct TraitsInitializer
+{
+ TraitsInitializer();
+};
+
+static TraitsInitializer traitsinitializer;
+
+TraitsInitializer::TraitsInitializer()
+{
+ const char* traits[] = {
+ "isAbstractClass",
+ "isArithmetic",
+ "isAssociativeArray",
+ "isFinalClass",
+ "isPOD",
+ "isNested",
+ "isFloating",
+ "isIntegral",
+ "isScalar",
+ "isStaticArray",
+ "isUnsigned",
+ "isVirtualFunction",
+ "isVirtualMethod",
+ "isAbstractFunction",
+ "isFinalFunction",
+ "isOverrideFunction",
+ "isStaticFunction",
+ "isRef",
+ "isOut",
+ "isLazy",
+ "hasMember",
+ "identifier",
+ "getProtection",
+ "parent",
+ "getLinkage",
+ "getMember",
+ "getOverloads",
+ "getVirtualFunctions",
+ "getVirtualMethods",
+ "classInstanceSize",
+ "allMembers",
+ "derivedMembers",
+ "isSame",
+ "compiles",
+ "parameters",
+ "getAliasThis",
+ "getAttributes",
+ "getFunctionAttributes",
+ "getFunctionVariadicStyle",
+ "getParameterStorageClasses",
+ "getUnitTests",
+ "getVirtualIndex",
+ "getPointerBitmap",
+ NULL
+ };
+
+ traitsStringTable._init(40);
+
+ for (size_t idx = 0;; idx++)
+ {
+ const char *s = traits[idx];
+ if (!s) break;
+ StringValue *sv = traitsStringTable.insert(s, strlen(s), const_cast<char *>(s));
+ assert(sv);
+ }
+}
+
+void *trait_search_fp(void *, const char *seed, int* cost)
+{
+ //printf("trait_search_fp('%s')\n", seed);
+ size_t len = strlen(seed);
+ if (!len)
+ return NULL;
+
+ *cost = 0;
+ StringValue *sv = traitsStringTable.lookup(seed, len);
+ return sv ? (void*)sv->ptrvalue : NULL;
+}
+
+static int fpisTemplate(void *, Dsymbol *s)
+{
+ if (s->isTemplateDeclaration())
+ return 1;
+
+ return 0;
+}
+
+bool isTemplate(Dsymbol *s)
+{
+ if (!s->toAlias()->isOverloadable())
+ return false;
+
+ return overloadApply(s, NULL, &fpisTemplate) != 0;
+}
+
+Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s))
+{
+ if (!e->args || !e->args->dim)
+ return False(e);
+ for (size_t i = 0; i < e->args->dim; i++)
+ {
+ Dsymbol *s = getDsymbol((*e->args)[i]);
+ if (!s || !fp(s))
+ return False(e);
+ }
+ return True(e);
+}
+
+/**
+ * get an array of size_t values that indicate possible pointer words in memory
+ * if interpreted as the type given as argument
+ * the first array element is the size of the type for independent interpretation
+ * of the array
+ * following elements bits represent one word (4/8 bytes depending on the target
+ * architecture). If set the corresponding memory might contain a pointer/reference.
+ *
+ * [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
+ */
+Expression *pointerBitmap(TraitsExp *e)
+{
+ if (!e->args || e->args->dim != 1)
+ {
+ error(e->loc, "a single type expected for trait pointerBitmap");
+ return new ErrorExp();
+ }
+ Type *t = getType((*e->args)[0]);
+ if (!t)
+ {
+ error(e->loc, "%s is not a type", (*e->args)[0]->toChars());
+ return new ErrorExp();
+ }
+ d_uns64 sz;
+ if (t->ty == Tclass && !((TypeClass*)t)->sym->isInterfaceDeclaration())
+ sz = ((TypeClass*)t)->sym->AggregateDeclaration::size(e->loc);
+ else
+ sz = t->size(e->loc);
+ if (sz == SIZE_INVALID)
+ return new ErrorExp();
+
+ const d_uns64 sz_size_t = Type::tsize_t->size(e->loc);
+ if (sz > UINT64_MAX - sz_size_t)
+ {
+ error(e->loc, "size overflow for type %s", t->toChars());
+ return new ErrorExp();
+ }
+
+ d_uns64 bitsPerWord = sz_size_t * 8;
+ d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t;
+ d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
+ Array<d_uns64> data;
+ data.setDim((size_t)cntdata);
+ data.zero();
+
+ class PointerBitmapVisitor : public Visitor
+ {
+ public:
+ PointerBitmapVisitor(Array<d_uns64>* _data, d_uns64 _sz_size_t)
+ : data(_data), offset(0), sz_size_t(_sz_size_t), error(false)
+ {}
+
+ void setpointer(d_uns64 off)
+ {
+ d_uns64 ptroff = off / sz_size_t;
+ (*data)[(size_t)(ptroff / (8 * sz_size_t))] |= 1LL << (ptroff % (8 * sz_size_t));
+ }
+ virtual void visit(Type *t)
+ {
+ Type *tb = t->toBasetype();
+ if (tb != t)
+ tb->accept(this);
+ }
+ virtual void visit(TypeError *t) { visit((Type *)t); }
+ virtual void visit(TypeNext *) { assert(0); }
+ virtual void visit(TypeBasic *t)
+ {
+ if (t->ty == Tvoid)
+ setpointer(offset);
+ }
+ virtual void visit(TypeVector *) { }
+ virtual void visit(TypeArray *) { assert(0); }
+ virtual void visit(TypeSArray *t)
+ {
+ d_uns64 arrayoff = offset;
+ d_uns64 nextsize = t->next->size();
+ if (nextsize == SIZE_INVALID)
+ error = true;
+ d_uns64 dim = t->dim->toInteger();
+ for (d_uns64 i = 0; i < dim; i++)
+ {
+ offset = arrayoff + i * nextsize;
+ t->next->accept(this);
+ }
+ offset = arrayoff;
+ }
+ virtual void visit(TypeDArray *) { setpointer(offset + sz_size_t); } // dynamic array is {length,ptr}
+ virtual void visit(TypeAArray *) { setpointer(offset); }
+ virtual void visit(TypePointer *t)
+ {
+ if (t->nextOf()->ty != Tfunction) // don't mark function pointers
+ setpointer(offset);
+ }
+ virtual void visit(TypeReference *) { setpointer(offset); }
+ virtual void visit(TypeClass *) { setpointer(offset); }
+ virtual void visit(TypeFunction *) { }
+ virtual void visit(TypeDelegate *) { setpointer(offset); } // delegate is {context, function}
+ virtual void visit(TypeQualified *) { assert(0); } // assume resolved
+ virtual void visit(TypeIdentifier *) { assert(0); }
+ virtual void visit(TypeInstance *) { assert(0); }
+ virtual void visit(TypeTypeof *) { assert(0); }
+ virtual void visit(TypeReturn *) { assert(0); }
+ virtual void visit(TypeEnum *t) { visit((Type *)t); }
+ virtual void visit(TypeTuple *t) { visit((Type *)t); }
+ virtual void visit(TypeSlice *) { assert(0); }
+ virtual void visit(TypeNull *) { } // always a null pointer
+
+ virtual void visit(TypeStruct *t)
+ {
+ d_uns64 structoff = offset;
+ for (size_t i = 0; i < t->sym->fields.dim; i++)
+ {
+ VarDeclaration *v = t->sym->fields[i];
+ offset = structoff + v->offset;
+ if (v->type->ty == Tclass)
+ setpointer(offset);
+ else
+ v->type->accept(this);
+ }
+ offset = structoff;
+ }
+
+ // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
+ void visitClass(TypeClass* t)
+ {
+ d_uns64 classoff = offset;
+
+ // skip vtable-ptr and monitor
+ if (t->sym->baseClass)
+ visitClass((TypeClass*)t->sym->baseClass->type);
+
+ for (size_t i = 0; i < t->sym->fields.dim; i++)
+ {
+ VarDeclaration *v = t->sym->fields[i];
+ offset = classoff + v->offset;
+ v->type->accept(this);
+ }
+ offset = classoff;
+ }
+
+ Array<d_uns64>* data;
+ d_uns64 offset;
+ d_uns64 sz_size_t;
+ bool error;
+ };
+
+ PointerBitmapVisitor pbv(&data, sz_size_t);
+ if (t->ty == Tclass)
+ pbv.visitClass((TypeClass*)t);
+ else
+ t->accept(&pbv);
+ if (pbv.error)
+ return new ErrorExp();
+
+ Expressions* exps = new Expressions;
+ exps->push(new IntegerExp(e->loc, sz, Type::tsize_t));
+ for (d_uns64 i = 0; i < cntdata; i++)
+ exps->push(new IntegerExp(e->loc, data[(size_t)i], Type::tsize_t));
+
+ ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, exps);
+ ale->type = Type::tsize_t->sarrayOf(cntdata + 1);
+ return ale;
+}
+
+static Expression *dimError(TraitsExp *e, int expected, int dim)
+{
+ e->error("expected %d arguments for `%s` but had %d", expected, e->ident->toChars(), dim);
+ return new ErrorExp();
+}
+
+Expression *semanticTraits(TraitsExp *e, Scope *sc)
+{
+ if (e->ident != Id::compiles && e->ident != Id::isSame &&
+ e->ident != Id::identifier && e->ident != Id::getProtection)
+ {
+ if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1))
+ return new ErrorExp();
+ }
+ size_t dim = e->args ? e->args->dim : 0;
+
+ if (e->ident == Id::isArithmetic)
+ {
+ return isTypeX(e, &isTypeArithmetic);
+ }
+ else if (e->ident == Id::isFloating)
+ {
+ return isTypeX(e, &isTypeFloating);
+ }
+ else if (e->ident == Id::isIntegral)
+ {
+ return isTypeX(e, &isTypeIntegral);
+ }
+ else if (e->ident == Id::isScalar)
+ {
+ return isTypeX(e, &isTypeScalar);
+ }
+ else if (e->ident == Id::isUnsigned)
+ {
+ return isTypeX(e, &isTypeUnsigned);
+ }
+ else if (e->ident == Id::isAssociativeArray)
+ {
+ return isTypeX(e, &isTypeAssociativeArray);
+ }
+ else if (e->ident == Id::isStaticArray)
+ {
+ return isTypeX(e, &isTypeStaticArray);
+ }
+ else if (e->ident == Id::isAbstractClass)
+ {
+ return isTypeX(e, &isTypeAbstractClass);
+ }
+ else if (e->ident == Id::isFinalClass)
+ {
+ return isTypeX(e, &isTypeFinalClass);
+ }
+ else if (e->ident == Id::isTemplate)
+ {
+ return isSymbolX(e, &isTemplate);
+ }
+ else if (e->ident == Id::isPOD)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Type *t = isType(o);
+ if (!t)
+ {
+ e->error("type expected as second argument of __traits %s instead of %s",
+ e->ident->toChars(), o->toChars());
+ return new ErrorExp();
+ }
+
+ Type *tb = t->baseElemOf();
+ if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL)
+ {
+ return (sd->isPOD()) ? True(e) : False(e);
+ }
+ return True(e);
+ }
+ else if (e->ident == Id::isNested)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ if (!s)
+ {
+ }
+ else if (AggregateDeclaration *a = s->isAggregateDeclaration())
+ {
+ return a->isNested() ? True(e) : False(e);
+ }
+ else if (FuncDeclaration *f = s->isFuncDeclaration())
+ {
+ return f->isNested() ? True(e) : False(e);
+ }
+
+ e->error("aggregate or function expected instead of '%s'", o->toChars());
+ return new ErrorExp();
+ }
+ else if (e->ident == Id::isAbstractFunction)
+ {
+ return isFuncX(e, &isFuncAbstractFunction);
+ }
+ else if (e->ident == Id::isVirtualFunction)
+ {
+ return isFuncX(e, &isFuncVirtualFunction);
+ }
+ else if (e->ident == Id::isVirtualMethod)
+ {
+ return isFuncX(e, &isFuncVirtualMethod);
+ }
+ else if (e->ident == Id::isFinalFunction)
+ {
+ return isFuncX(e, &isFuncFinalFunction);
+ }
+ else if (e->ident == Id::isOverrideFunction)
+ {
+ return isFuncX(e, &isFuncOverrideFunction);
+ }
+ else if (e->ident == Id::isStaticFunction)
+ {
+ return isFuncX(e, &isFuncStaticFunction);
+ }
+ else if (e->ident == Id::isRef)
+ {
+ return isDeclX(e, &isDeclRef);
+ }
+ else if (e->ident == Id::isOut)
+ {
+ return isDeclX(e, &isDeclOut);
+ }
+ else if (e->ident == Id::isLazy)
+ {
+ return isDeclX(e, &isDeclLazy);
+ }
+ else if (e->ident == Id::identifier)
+ {
+ // Get identifier for symbol as a string literal
+ /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
+ * a symbol should not be folded to a constant.
+ * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
+ */
+ if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2))
+ return new ErrorExp();
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Identifier *id = NULL;
+ if (Parameter *po = isParameter(o))
+ {
+ id = po->ident;
+ assert(id);
+ }
+ else
+ {
+ Dsymbol *s = getDsymbol(o);
+ if (!s || !s->ident)
+ {
+ e->error("argument %s has no identifier", o->toChars());
+ return new ErrorExp();
+ }
+ id = s->ident;
+ }
+
+ StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
+ return semantic(se, sc);
+ }
+ else if (e->ident == Id::getProtection)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ Scope *sc2 = sc->push();
+ sc2->flags = sc->flags | SCOPEnoaccesscheck;
+ bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1);
+ sc2->pop();
+ if (!ok)
+ return new ErrorExp();
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ if (!s)
+ {
+ if (!isError(o))
+ e->error("argument %s has no protection", o->toChars());
+ return new ErrorExp();
+ }
+ if (s->_scope)
+ s->semantic(s->_scope);
+
+ const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names)
+ assert(protName);
+ StringExp *se = new StringExp(e->loc, const_cast<char *>(protName));
+ return semantic(se, sc);
+ }
+ else if (e->ident == Id::parent)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ if (s)
+ {
+ if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943
+ s = fd->toAliasFunc();
+ if (!s->isImport()) // Bugzilla 8922
+ s = s->toParent();
+ }
+ if (!s || s->isImport())
+ {
+ e->error("argument %s has no parent", o->toChars());
+ return new ErrorExp();
+ }
+
+ if (FuncDeclaration *f = s->isFuncDeclaration())
+ {
+ if (TemplateDeclaration *td = getFuncTemplateDecl(f))
+ {
+ if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td->overroot; // then get the start
+ Expression *ex = new TemplateExp(e->loc, td, f);
+ ex = semantic(ex, sc);
+ return ex;
+ }
+
+ if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration())
+ {
+ // Directly translate to VarExp instead of FuncExp
+ Expression *ex = new VarExp(e->loc, fld, true);
+ return semantic(ex, sc);
+ }
+ }
+
+ return resolve(e->loc, sc, s, false);
+ }
+ else if (e->ident == Id::hasMember ||
+ e->ident == Id::getMember ||
+ e->ident == Id::getOverloads ||
+ e->ident == Id::getVirtualMethods ||
+ e->ident == Id::getVirtualFunctions)
+ {
+ if (dim != 2)
+ return dimError(e, 2, dim);
+
+ RootObject *o = (*e->args)[0];
+ Expression *ex = isExpression((*e->args)[1]);
+ if (!ex)
+ {
+ e->error("expression expected as second argument of __traits %s", e->ident->toChars());
+ return new ErrorExp();
+ }
+ ex = ex->ctfeInterpret();
+
+ StringExp *se = ex->toStringExp();
+ if (!se || se->len == 0)
+ {
+ e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars());
+ return new ErrorExp();
+ }
+ se = se->toUTF8(sc);
+
+ if (se->sz != 1)
+ {
+ e->error("string must be chars");
+ return new ErrorExp();
+ }
+ Identifier *id = Identifier::idPool((char *)se->string, se->len);
+
+ /* Prefer dsymbol, because it might need some runtime contexts.
+ */
+ Dsymbol *sym = getDsymbol(o);
+ if (sym)
+ {
+ ex = new DsymbolExp(e->loc, sym);
+ ex = new DotIdExp(e->loc, ex, id);
+ }
+ else if (Type *t = isType(o))
+ ex = typeDotIdExp(e->loc, t, id);
+ else if (Expression *ex2 = isExpression(o))
+ ex = new DotIdExp(e->loc, ex2, id);
+ else
+ {
+ e->error("invalid first argument");
+ return new ErrorExp();
+ }
+
+ if (e->ident == Id::hasMember)
+ {
+ if (sym)
+ {
+ if (sym->search(e->loc, id))
+ return True(e);
+ }
+
+ /* Take any errors as meaning it wasn't found
+ */
+ Scope *scx = sc->push();
+ scx->flags |= SCOPEignoresymbolvisibility;
+ ex = trySemantic(ex, scx);
+ scx->pop();
+ return ex ? True(e) : False(e);
+ }
+ else if (e->ident == Id::getMember)
+ {
+ if (ex->op == TOKdotid)
+ // Prevent semantic() from replacing Symbol with its initializer
+ ((DotIdExp *)ex)->wantsym = true;
+ Scope *scx = sc->push();
+ scx->flags |= SCOPEignoresymbolvisibility;
+ ex = semantic(ex, scx);
+ scx->pop();
+ return ex;
+ }
+ else if (e->ident == Id::getVirtualFunctions ||
+ e->ident == Id::getVirtualMethods ||
+ e->ident == Id::getOverloads)
+ {
+ unsigned errors = global.errors;
+ Expression *eorig = ex;
+ Scope *scx = sc->push();
+ scx->flags |= SCOPEignoresymbolvisibility;
+ ex = semantic(ex, scx);
+ if (errors < global.errors)
+ e->error("%s cannot be resolved", eorig->toChars());
+ //ex->print();
+
+ /* Create tuple of functions of ex
+ */
+ Expressions *exps = new Expressions();
+ FuncDeclaration *f;
+ if (ex->op == TOKvar)
+ {
+ VarExp *ve = (VarExp *)ex;
+ f = ve->var->isFuncDeclaration();
+ ex = NULL;
+ }
+ else if (ex->op == TOKdotvar)
+ {
+ DotVarExp *dve = (DotVarExp *)ex;
+ f = dve->var->isFuncDeclaration();
+ if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis)
+ ex = NULL;
+ else
+ ex = dve->e1;
+ }
+ else
+ f = NULL;
+ Ptrait p;
+ p.exps = exps;
+ p.e1 = ex;
+ p.ident = e->ident;
+ overloadApply(f, &p, &fptraits);
+
+ ex = new TupleExp(e->loc, exps);
+ ex = semantic(ex, scx);
+ scx->pop();
+ return ex;
+ }
+ else
+ assert(0);
+ }
+ else if (e->ident == Id::classInstanceSize)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ ClassDeclaration *cd = s ? s->isClassDeclaration() : NULL;
+ if (!cd)
+ {
+ e->error("first argument is not a class");
+ return new ErrorExp();
+ }
+ if (cd->sizeok != SIZEOKdone)
+ {
+ cd->size(cd->loc);
+ }
+ if (cd->sizeok != SIZEOKdone)
+ {
+ e->error("%s %s is forward referenced", cd->kind(), cd->toChars());
+ return new ErrorExp();
+ }
+
+ return new IntegerExp(e->loc, cd->structsize, Type::tsize_t);
+ }
+ else if (e->ident == Id::getAliasThis)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
+ if (!ad)
+ {
+ e->error("argument is not an aggregate type");
+ return new ErrorExp();
+ }
+
+ Expressions *exps = new Expressions();
+ if (ad->aliasthis)
+ exps->push(new StringExp(e->loc, const_cast<char *>(ad->aliasthis->ident->toChars())));
+ Expression *ex = new TupleExp(e->loc, exps);
+ ex = semantic(ex, sc);
+ return ex;
+ }
+ else if (e->ident == Id::getAttributes)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ if (!s)
+ {
+ e->error("first argument is not a symbol");
+ return new ErrorExp();
+ }
+ if (Import *imp = s->isImport())
+ {
+ s = imp->mod;
+ }
+
+ //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
+ UserAttributeDeclaration *udad = s->userAttribDecl;
+ Expressions *exps = udad ? udad->getAttributes() : new Expressions();
+ TupleExp *tup = new TupleExp(e->loc, exps);
+ return semantic(tup, sc);
+ }
+ else if (e->ident == Id::getFunctionAttributes)
+ {
+ /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ Type *t = isType(o);
+ TypeFunction *tf = NULL;
+ if (s)
+ {
+ if (FuncDeclaration *f = s->isFuncDeclaration())
+ t = f->type;
+ else if (VarDeclaration *v = s->isVarDeclaration())
+ t = v->type;
+ }
+ if (t)
+ {
+ if (t->ty == Tfunction)
+ tf = (TypeFunction *)t;
+ else if (t->ty == Tdelegate)
+ tf = (TypeFunction *)t->nextOf();
+ else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+ tf = (TypeFunction *)t->nextOf();
+ }
+ if (!tf)
+ {
+ e->error("first argument is not a function");
+ return new ErrorExp();
+ }
+
+ Expressions *mods = new Expressions();
+ PushAttributes pa;
+ pa.mods = mods;
+ tf->modifiersApply(&pa, &PushAttributes::fp);
+ tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem);
+
+ TupleExp *tup = new TupleExp(e->loc, mods);
+ return semantic(tup, sc);
+ }
+ else if (e->ident == Id::getFunctionVariadicStyle)
+ {
+ /* Accept a symbol or a type. Returns one of the following:
+ * "none" not a variadic function
+ * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
+ * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
+ * "typesafe" void typesafe(T[] ...)
+ */
+ // get symbol linkage as a string
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ LINK link;
+ int varargs;
+ RootObject *o = (*e->args)[0];
+ Type *t = isType(o);
+ TypeFunction *tf = NULL;
+ if (t)
+ {
+ if (t->ty == Tfunction)
+ tf = (TypeFunction *)t;
+ else if (t->ty == Tdelegate)
+ tf = (TypeFunction *)t->nextOf();
+ else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+ tf = (TypeFunction *)t->nextOf();
+ }
+ if (tf)
+ {
+ link = tf->linkage;
+ varargs = tf->varargs;
+ }
+ else
+ {
+ Dsymbol *s = getDsymbol(o);
+ FuncDeclaration *fd = NULL;
+ if (!s || (fd = s->isFuncDeclaration()) == NULL)
+ {
+ e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars());
+ return new ErrorExp();
+ }
+ link = fd->linkage;
+ fd->getParameters(&varargs);
+ }
+ const char *style;
+ switch (varargs)
+ {
+ case 0: style = "none"; break;
+ case 1: style = (link == LINKd) ? "argptr"
+ : "stdarg"; break;
+ case 2: style = "typesafe"; break;
+ default:
+ assert(0);
+ }
+ StringExp *se = new StringExp(e->loc, const_cast<char*>(style));
+ return semantic(se, sc);
+ }
+ else if (e->ident == Id::getParameterStorageClasses)
+ {
+ /* Accept a function symbol or a type, followed by a parameter index.
+ * Returns a tuple of strings of the parameter's storage classes.
+ */
+ // get symbol linkage as a string
+ if (dim != 2)
+ return dimError(e, 2, dim);
+
+ RootObject *o1 = (*e->args)[1];
+ RootObject *o = (*e->args)[0];
+ Type *t = isType(o);
+ TypeFunction *tf = NULL;
+ if (t)
+ {
+ if (t->ty == Tfunction)
+ tf = (TypeFunction *)t;
+ else if (t->ty == Tdelegate)
+ tf = (TypeFunction *)t->nextOf();
+ else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+ tf = (TypeFunction *)t->nextOf();
+ }
+ Parameters* fparams;
+ if (tf)
+ {
+ fparams = tf->parameters;
+ }
+ else
+ {
+ Dsymbol *s = getDsymbol(o);
+ FuncDeclaration *fd = NULL;
+ if (!s || (fd = s->isFuncDeclaration()) == NULL)
+ {
+ e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
+ o->toChars(), o1->toChars());
+ return new ErrorExp();
+ }
+ fparams = fd->getParameters(NULL);
+ }
+
+ StorageClass stc;
+
+ // Set stc to storage class of the ith parameter
+ Expression *ex = isExpression((*e->args)[1]);
+ if (!ex)
+ {
+ e->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
+ o->toChars(), o1->toChars());
+ return new ErrorExp();
+ }
+ ex = ex->ctfeInterpret();
+ uinteger_t ii = ex->toUInteger();
+ if (ii >= Parameter::dim(fparams))
+ {
+ e->error("parameter index must be in range 0..%u not %s", (unsigned)Parameter::dim(fparams), ex->toChars());
+ return new ErrorExp();
+ }
+
+ unsigned n = (unsigned)ii;
+ Parameter *p = Parameter::getNth(fparams, n);
+ stc = p->storageClass;
+
+ // This mirrors hdrgen.visit(Parameter p)
+ if (p->type && p->type->mod & MODshared)
+ stc &= ~STCshared;
+
+ Expressions *exps = new Expressions;
+
+ if (stc & STCauto)
+ exps->push(new StringExp(e->loc, const_cast<char *>("auto")));
+ if (stc & STCreturn)
+ exps->push(new StringExp(e->loc, const_cast<char *>("return")));
+
+ if (stc & STCout)
+ exps->push(new StringExp(e->loc, const_cast<char *>("out")));
+ else if (stc & STCref)
+ exps->push(new StringExp(e->loc, const_cast<char *>("ref")));
+ else if (stc & STCin)
+ exps->push(new StringExp(e->loc, const_cast<char *>("in")));
+ else if (stc & STClazy)
+ exps->push(new StringExp(e->loc, const_cast<char *>("lazy")));
+ else if (stc & STCalias)
+ exps->push(new StringExp(e->loc, const_cast<char *>("alias")));
+
+ if (stc & STCconst)
+ exps->push(new StringExp(e->loc, const_cast<char *>("const")));
+ if (stc & STCimmutable)
+ exps->push(new StringExp(e->loc, const_cast<char *>("immutable")));
+ if (stc & STCwild)
+ exps->push(new StringExp(e->loc, const_cast<char *>("inout")));
+ if (stc & STCshared)
+ exps->push(new StringExp(e->loc, const_cast<char *>("shared")));
+ if (stc & STCscope && !(stc & STCscopeinferred))
+ exps->push(new StringExp(e->loc, const_cast<char *>("scope")));
+
+ TupleExp *tup = new TupleExp(e->loc, exps);
+ return semantic(tup, sc);
+ }
+ else if (e->ident == Id::getLinkage)
+ {
+ // get symbol linkage as a string
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ LINK link;
+ RootObject *o = (*e->args)[0];
+ Type *t = isType(o);
+ TypeFunction *tf = NULL;
+ if (t)
+ {
+ if (t->ty == Tfunction)
+ tf = (TypeFunction *)t;
+ else if (t->ty == Tdelegate)
+ tf = (TypeFunction *)t->nextOf();
+ else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
+ tf = (TypeFunction *)t->nextOf();
+ }
+ if (tf)
+ link = tf->linkage;
+ else
+ {
+ Dsymbol *s = getDsymbol(o);
+ Declaration *d = NULL;
+ if (!s || (d = s->isDeclaration()) == NULL)
+ {
+ e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars());
+ return new ErrorExp();
+ }
+ link = d->linkage;
+ }
+ const char *linkage = linkageToChars(link);
+ StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage));
+ return semantic(se, sc);
+ }
+ else if (e->ident == Id::allMembers ||
+ e->ident == Id::derivedMembers)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ if (!s)
+ {
+ e->error("argument has no members");
+ return new ErrorExp();
+ }
+ if (Import *imp = s->isImport())
+ {
+ // Bugzilla 9692
+ s = imp->mod;
+ }
+
+ ScopeDsymbol *sds = s->isScopeDsymbol();
+ if (!sds || sds->isTemplateDeclaration())
+ {
+ e->error("%s %s has no members", s->kind(), s->toChars());
+ return new ErrorExp();
+ }
+
+ // use a struct as local function
+ struct PushIdentsDg
+ {
+ ScopeDsymbol *sds;
+ Identifiers *idents;
+
+ static int dg(void *ctx, size_t, Dsymbol *sm)
+ {
+ if (!sm)
+ return 1;
+ //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
+ if (sm->ident)
+ {
+ const char *idx = sm->ident->toChars();
+ if (idx[0] == '_' && idx[1] == '_' &&
+ sm->ident != Id::ctor &&
+ sm->ident != Id::dtor &&
+ sm->ident != Id::__xdtor &&
+ sm->ident != Id::postblit &&
+ sm->ident != Id::__xpostblit)
+ {
+ return 0;
+ }
+
+ if (sm->ident == Id::empty)
+ {
+ return 0;
+ }
+ if (sm->isTypeInfoDeclaration()) // Bugzilla 15177
+ return 0;
+ PushIdentsDg *pid = (PushIdentsDg *)ctx;
+ if (!pid->sds->isModule() && sm->isImport()) // Bugzilla 17057
+ return 0;
+
+ //printf("\t%s\n", sm->ident->toChars());
+ Identifiers *idents = pid->idents;
+
+ /* Skip if already present in idents[]
+ */
+ for (size_t j = 0; j < idents->dim; j++)
+ {
+ Identifier *id = (*idents)[j];
+ if (id == sm->ident)
+ return 0;
+ }
+
+ idents->push(sm->ident);
+ }
+ else
+ {
+ EnumDeclaration *ed = sm->isEnumDeclaration();
+ if (ed)
+ {
+ ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, ctx);
+ }
+ }
+ return 0;
+ }
+ };
+
+ Identifiers *idents = new Identifiers;
+ PushIdentsDg ctx;
+ ctx.sds = sds;
+ ctx.idents = idents;
+ ScopeDsymbol_foreach(sc, sds->members, &PushIdentsDg::dg, &ctx);
+ ClassDeclaration *cd = sds->isClassDeclaration();
+ if (cd && e->ident == Id::allMembers)
+ {
+ if (cd->_scope)
+ cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference
+
+ struct PushBaseMembers
+ {
+ static void dg(ClassDeclaration *cd, PushIdentsDg *ctx)
+ {
+ for (size_t i = 0; i < cd->baseclasses->dim; i++)
+ {
+ ClassDeclaration *cb = (*cd->baseclasses)[i]->sym;
+ assert(cb);
+ ScopeDsymbol_foreach(NULL, cb->members, &PushIdentsDg::dg, ctx);
+ if (cb->baseclasses->dim)
+ dg(cb, ctx);
+ }
+ }
+ };
+ PushBaseMembers::dg(cd, &ctx);
+ }
+
+ // Turn Identifiers into StringExps reusing the allocated array
+ assert(sizeof(Expressions) == sizeof(Identifiers));
+ Expressions *exps = (Expressions *)idents;
+ for (size_t i = 0; i < idents->dim; i++)
+ {
+ Identifier *id = (*idents)[i];
+ StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
+ (*exps)[i] = se;
+ }
+
+ /* Making this a tuple is more flexible, as it can be statically unrolled.
+ * To make an array literal, enclose __traits in [ ]:
+ * [ __traits(allMembers, ...) ]
+ */
+ Expression *ex = new TupleExp(e->loc, exps);
+ ex = semantic(ex, sc);
+ return ex;
+ }
+ else if (e->ident == Id::compiles)
+ {
+ /* Determine if all the objects - types, expressions, or symbols -
+ * compile without error
+ */
+ if (!dim)
+ return False(e);
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ unsigned errors = global.startGagging();
+ Scope *sc2 = sc->push();
+ sc2->tinst = NULL;
+ sc2->minst = NULL;
+ sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile | SCOPEfullinst;
+ bool err = false;
+
+ RootObject *o = (*e->args)[i];
+ Type *t = isType(o);
+ Expression *ex = t ? typeToExpression(t) : isExpression(o);
+ if (!ex && t)
+ {
+ Dsymbol *s;
+ t->resolve(e->loc, sc2, &ex, &t, &s);
+ if (t)
+ {
+ t->semantic(e->loc, sc2);
+ if (t->ty == Terror)
+ err = true;
+ }
+ else if (s && s->errors)
+ err = true;
+ }
+ if (ex)
+ {
+ ex = semantic(ex, sc2);
+ ex = resolvePropertiesOnly(sc2, ex);
+ ex = ex->optimize(WANTvalue);
+ if (sc2->func && sc2->func->type->ty == Tfunction)
+ {
+ TypeFunction *tf = (TypeFunction *)sc2->func->type;
+ canThrow(ex, sc2->func, tf->isnothrow);
+ }
+ ex = checkGC(sc2, ex);
+ if (ex->op == TOKerror)
+ err = true;
+ }
+
+ // Carefully detach the scope from the parent and throw it away as
+ // we only need it to evaluate the expression
+ // https://issues.dlang.org/show_bug.cgi?id=15428
+ freeFieldinit(sc2);
+ sc2->enclosing = NULL;
+ sc2->pop();
+
+ if (global.endGagging(errors) || err)
+ {
+ return False(e);
+ }
+ }
+ return True(e);
+ }
+ else if (e->ident == Id::isSame)
+ {
+ /* Determine if two symbols are the same
+ */
+ if (dim != 2)
+ return dimError(e, 2, dim);
+
+ if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0))
+ return new ErrorExp();
+
+ RootObject *o1 = (*e->args)[0];
+ RootObject *o2 = (*e->args)[1];
+ Dsymbol *s1 = getDsymbol(o1);
+ Dsymbol *s2 = getDsymbol(o2);
+ //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
+ if (!s1 && !s2)
+ {
+ Expression *ea1 = isExpression(o1);
+ Expression *ea2 = isExpression(o2);
+ if (ea1 && ea2)
+ {
+ if (ea1->equals(ea2))
+ return True(e);
+ }
+ }
+ if (!s1 || !s2)
+ return False(e);
+ s1 = s1->toAlias();
+ s2 = s2->toAlias();
+
+ if (s1->isFuncAliasDeclaration())
+ s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
+ if (s2->isFuncAliasDeclaration())
+ s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();
+
+ return (s1 == s2) ? True(e) : False(e);
+ }
+ else if (e->ident == Id::getUnitTests)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+ if (!s)
+ {
+ e->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
+ o->toChars());
+ return new ErrorExp();
+ }
+ if (Import *imp = s->isImport()) // Bugzilla 10990
+ s = imp->mod;
+
+ ScopeDsymbol* sds = s->isScopeDsymbol();
+ if (!sds)
+ {
+ e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
+ s->toChars(), s->kind());
+ return new ErrorExp();
+ }
+
+ Expressions *exps = new Expressions();
+ if (global.params.useUnitTests)
+ {
+ // Should actually be a set
+ AA* uniqueUnitTests = NULL;
+ collectUnitTests(sds->members, uniqueUnitTests, exps);
+ }
+ TupleExp *te= new TupleExp(e->loc, exps);
+ return semantic(te, sc);
+ }
+ else if(e->ident == Id::getVirtualIndex)
+ {
+ if (dim != 1)
+ return dimError(e, 1, dim);
+
+ RootObject *o = (*e->args)[0];
+ Dsymbol *s = getDsymbol(o);
+
+ FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
+ if (!fd)
+ {
+ e->error("first argument to __traits(getVirtualIndex) must be a function");
+ return new ErrorExp();
+ }
+
+ fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
+ return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t);
+ }
+ else if (e->ident == Id::getPointerBitmap)
+ {
+ return pointerBitmap(e);
+ }
+
+ if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
+ e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub);
+ else
+ e->error("unrecognized trait '%s'", e->ident->toChars());
+ return new ErrorExp();
+
+ e->error("wrong number of arguments %d", (int)dim);
+ return new ErrorExp();
+}
diff --git a/gcc/d/dmd/typesem.c b/gcc/d/dmd/typesem.c
new file mode 100644
index 0000000..34e7da4
--- /dev/null
+++ b/gcc/d/dmd/typesem.c
@@ -0,0 +1,123 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include "mtype.h"
+#include "expression.h"
+#include "template.h"
+
+Expression *typeToExpression(Type *t);
+Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+
+class TypeToExpressionVisitor : public Visitor
+{
+public:
+ Expression *result;
+ Type *itype;
+
+ TypeToExpressionVisitor(Type *itype)
+ {
+ this->result = NULL;
+ this->itype = itype;
+ }
+
+ void visit(Type *)
+ {
+ result = NULL;
+ }
+
+ void visit(TypeSArray *t)
+ {
+ Expression *e = typeToExpression(t->next);
+ if (e)
+ e = new ArrayExp(t->dim->loc, e, t->dim);
+ result = e;
+ }
+
+ void visit(TypeAArray *t)
+ {
+ Expression *e = typeToExpression(t->next);
+ if (e)
+ {
+ Expression *ei = typeToExpression(t->index);
+ if (ei)
+ {
+ result = new ArrayExp(t->loc, e, ei);
+ return;
+ }
+ }
+ result = NULL;
+ }
+
+ void visit(TypeIdentifier *t)
+ {
+ result = typeToExpressionHelper(t, new IdentifierExp(t->loc, t->ident));
+ }
+
+ void visit(TypeInstance *t)
+ {
+ result = typeToExpressionHelper(t, new ScopeExp(t->loc, t->tempinst));
+ }
+};
+
+/* We've mistakenly parsed this as a type.
+ * Redo it as an Expression.
+ * NULL if cannot.
+ */
+Expression *typeToExpression(Type *t)
+{
+ TypeToExpressionVisitor v = TypeToExpressionVisitor(t);
+ t->accept(&v);
+ return v.result;
+}
+
+/* Helper function for `typeToExpression`. Contains common code
+ * for TypeQualified derived classes.
+ */
+Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i)
+{
+ //printf("toExpressionHelper(e = %s %s)\n", Token::toChars(e->op), e->toChars());
+ for (; i < t->idents.dim; i++)
+ {
+ RootObject *id = t->idents[i];
+ //printf("\t[%d] e: '%s', id: '%s'\n", i, e->toChars(), id->toChars());
+
+ switch (id->dyncast())
+ {
+ case DYNCAST_IDENTIFIER:
+ {
+ // ... '. ident'
+ e = new DotIdExp(e->loc, e, (Identifier *)id);
+ break;
+ }
+ case DYNCAST_DSYMBOL:
+ {
+ // ... '. name!(tiargs)'
+ TemplateInstance *ti = ((Dsymbol *)id)->isTemplateInstance();
+ assert(ti);
+ e = new DotTemplateInstanceExp(e->loc, e, ti->name, ti->tiargs);
+ break;
+ }
+ case DYNCAST_TYPE: // Bugzilla 1215
+ {
+ // ... '[type]'
+ e = new ArrayExp(t->loc, e, new TypeExp(t->loc, (Type *)id));
+ break;
+ }
+ case DYNCAST_EXPRESSION: // Bugzilla 1215
+ {
+ // ... '[expr]'
+ e = new ArrayExp(t->loc, e, (Expression *)id);
+ break;
+ }
+ default:
+ assert(0);
+ }
+ }
+ return e;
+}
diff --git a/gcc/d/dmd/unittests.c b/gcc/d/dmd/unittests.c
new file mode 100644
index 0000000..4827822
--- /dev/null
+++ b/gcc/d/dmd/unittests.c
@@ -0,0 +1,26 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/unittests.c
+ */
+
+#include <stdio.h>
+
+#include "mars.h"
+
+void unittest_speller();
+void unittest_importHint();
+void unittest_aa();
+
+void unittests()
+{
+#if UNITTEST
+ unittest_speller();
+ unittest_importHint();
+ unittest_aa();
+#endif
+}
diff --git a/gcc/d/dmd/utf.c b/gcc/d/dmd/utf.c
new file mode 100644
index 0000000..f07340e
--- /dev/null
+++ b/gcc/d/dmd/utf.c
@@ -0,0 +1,307 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2003-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/utf.c
+ */
+
+/// Description of UTF-8 in [1]. Unicode non-characters and private-use
+/// code points described in [2],[4].
+///
+/// References:
+/// [1] http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+/// [2] http://en.wikipedia.org/wiki/Unicode
+/// [3] http://unicode.org/faq/utf_bom.html
+/// [4] http://www.unicode.org/versions/Unicode6.1.0/ch03.pdf
+
+#include <assert.h>
+
+#include "utf.h"
+
+/* The following encodings are valid, except for the 5 and 6 byte
+ * combinations:
+ * 0xxxxxxx
+ * 110xxxxx 10xxxxxx
+ * 1110xxxx 10xxxxxx 10xxxxxx
+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ */
+const unsigned UTF8_STRIDE[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,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 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,0xFF,0xFF,
+};
+
+// UTF-8 decoding errors
+char const UTF8_DECODE_OUTSIDE_CODE_SPACE[] = "Outside Unicode code space";
+char const UTF8_DECODE_TRUNCATED_SEQUENCE[] = "Truncated UTF-8 sequence";
+char const UTF8_DECODE_OVERLONG[] = "Overlong UTF-8 sequence";
+char const UTF8_DECODE_INVALID_TRAILER[] = "Invalid trailing code unit";
+char const UTF8_DECODE_INVALID_CODE_POINT[] = "Invalid code point decoded";
+
+// UTF-16 decoding errors
+char const UTF16_DECODE_TRUNCATED_SEQUENCE[]= "Truncated UTF-16 sequence";
+char const UTF16_DECODE_INVALID_SURROGATE[] = "Invalid low surrogate";
+char const UTF16_DECODE_UNPAIRED_SURROGATE[]= "Unpaired surrogate";
+char const UTF16_DECODE_INVALID_CODE_POINT[]= "Invalid code point decoded";
+
+/// The Unicode code space is the range of code points [0x000000,0x10FFFF]
+/// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF]
+/// and non-characters (which end in 0xFFFE or 0xFFFF).
+bool utf_isValidDchar(dchar_t c)
+{
+ // TODO: Whether non-char code points should be rejected is pending review
+ // largest character code point
+ if (c > 0x10FFFF)
+ return false;
+ // surrogate pairs
+ if (0xD800 <= c && c <= 0xDFFF)
+ return false;
+ // non-characters
+ if ((c & 0xFFFFFE) == 0x00FFFE)
+ return false;
+ return true;
+}
+
+/*******************************
+ * Return !=0 if unicode alpha.
+ * Use table from C99 Appendix D.
+ */
+
+bool isUniAlpha(dchar_t c)
+{
+ size_t high = ALPHA_TABLE_LENGTH - 1;
+ // Shortcut search if c is out of range
+ size_t low
+ = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0;
+ // Binary search
+ while (low <= high)
+ {
+ size_t mid = (low + high) >> 1;
+ if (c < ALPHA_TABLE[mid][0])
+ high = mid - 1;
+ else if (ALPHA_TABLE[mid][1] < c)
+ low = mid + 1;
+ else
+ {
+ assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]);
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns the code length of c in code units.
+ */
+
+int utf_codeLengthChar(dchar_t c)
+{
+ if (c <= 0x7F)
+ return 1;
+ if (c <= 0x7FF)
+ return 2;
+ if (c <= 0xFFFF)
+ return 3;
+ if (c <= 0x10FFFF)
+ return 4;
+ assert(false);
+}
+
+int utf_codeLengthWchar(dchar_t c)
+{
+ return c <= 0xFFFF ? 1 : 2;
+}
+
+/**
+ * Returns the code length of c in code units for the encoding.
+ * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32.
+ */
+
+int utf_codeLength(int sz, dchar_t c)
+{
+ if (sz == 1)
+ return utf_codeLengthChar(c);
+ if (sz == 2)
+ return utf_codeLengthWchar(c);
+ assert(sz == 4);
+ return 1;
+}
+
+void utf_encodeChar(utf8_t *s, dchar_t c)
+{
+ assert(s != NULL);
+ assert(utf_isValidDchar(c));
+ if (c <= 0x7F)
+ {
+ s[0] = static_cast<utf8_t>(c);
+ }
+ else if (c <= 0x07FF)
+ {
+ s[0] = static_cast<utf8_t>(0xC0 | (c >> 6));
+ s[1] = static_cast<utf8_t>(0x80 | (c & 0x3F));
+ }
+ else if (c <= 0xFFFF)
+ {
+ s[0] = static_cast<utf8_t>(0xE0 | (c >> 12));
+ s[1] = static_cast<utf8_t>(0x80 | ((c >> 6) & 0x3F));
+ s[2] = static_cast<utf8_t>(0x80 | (c & 0x3F));
+ }
+ else if (c <= 0x10FFFF)
+ {
+ s[0] = static_cast<utf8_t>(0xF0 | (c >> 18));
+ s[1] = static_cast<utf8_t>(0x80 | ((c >> 12) & 0x3F));
+ s[2] = static_cast<utf8_t>(0x80 | ((c >> 6) & 0x3F));
+ s[3] = static_cast<utf8_t>(0x80 | (c & 0x3F));
+ }
+ else
+ assert(0);
+}
+
+void utf_encodeWchar(utf16_t *s, dchar_t c)
+{
+ assert(s != NULL);
+ assert(utf_isValidDchar(c));
+ if (c <= 0xFFFF)
+ {
+ s[0] = static_cast<utf16_t>(c);
+ }
+ else
+ {
+ s[0] = static_cast<utf16_t>((((c - 0x010000) >> 10) & 0x03FF) + 0xD800);
+ s[1] = static_cast<utf16_t>(((c - 0x010000) & 0x03FF) + 0xDC00);
+ }
+}
+
+void utf_encode(int sz, void *s, dchar_t c)
+{
+ if (sz == 1)
+ utf_encodeChar((utf8_t *)s, c);
+ else if (sz == 2)
+ utf_encodeWchar((utf16_t *)s, c);
+ else
+ {
+ assert(sz == 4);
+ *((utf32_t *)s) = c;
+ }
+}
+
+/********************************************
+ * Decode a UTF-8 sequence as a single UTF-32 code point.
+ * Returns:
+ * NULL success
+ * !=NULL error message string
+ */
+
+const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult)
+{
+ assert(s != NULL);
+ assert(pidx != NULL);
+ assert(presult != NULL);
+ size_t i = (*pidx)++;
+ assert(i < len);
+ utf8_t u = s[i];
+ // Pre-stage results for ASCII and error cases
+ *presult = u;
+
+ //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len);
+
+ // Get expected sequence length
+ size_t n = UTF8_STRIDE[u];
+ switch (n)
+ {
+ case 1: // ASCII
+ return UTF8_DECODE_OK;
+ case 2: case 3: case 4: // multi-byte UTF-8
+ break;
+ default: // 5- or 6-byte sequence
+ return UTF8_DECODE_OUTSIDE_CODE_SPACE;
+ }
+ if (len < i + n) // source too short
+ return UTF8_DECODE_TRUNCATED_SEQUENCE;
+
+ // Pick off 7 - n low bits from first code unit
+ utf32_t c = u & ((1 << (7 - n)) - 1);
+ /* The following combinations are overlong, and illegal:
+ * 1100000x (10xxxxxx)
+ * 11100000 100xxxxx (10xxxxxx)
+ * 11110000 1000xxxx (10xxxxxx 10xxxxxx)
+ * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
+ * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+ */
+ utf8_t u2 = s[++i];
+ // overlong combination
+ if ((u & 0xFE) == 0xC0 ||
+ (u == 0xE0 && (u2 & 0xE0) == 0x80) ||
+ (u == 0xF0 && (u2 & 0xF0) == 0x80) ||
+ (u == 0xF8 && (u2 & 0xF8) == 0x80) ||
+ (u == 0xFC && (u2 & 0xFC) == 0x80))
+ return UTF8_DECODE_OVERLONG;
+ // Decode remaining bits
+ for (n += i - 1; i != n; ++i)
+ {
+ u = s[i];
+ if ((u & 0xC0) != 0x80) // trailing bytes are 10xxxxxx
+ return UTF8_DECODE_INVALID_TRAILER;
+ c = (c << 6) | (u & 0x3F);
+ }
+ if (!utf_isValidDchar(c))
+ return UTF8_DECODE_INVALID_CODE_POINT;
+ *pidx = i;
+ *presult = c;
+ return UTF8_DECODE_OK;
+}
+
+/********************************************
+ * Decode a UTF-16 sequence as a single UTF-32 code point.
+ * Returns:
+ * NULL success
+ * !=NULL error message string
+ */
+
+const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult)
+{
+ assert(s != NULL);
+ assert(pidx != NULL);
+ assert(presult != NULL);
+ size_t i = (*pidx)++;
+ assert(i < len);
+ // Pre-stage results for ASCII and error cases
+ utf32_t u = *presult = s[i];
+
+ if (u < 0x80) // ASCII
+ return UTF16_DECODE_OK;
+ if (0xD800 <= u && u <= 0xDBFF) // Surrogate pair
+ { if (len <= i + 1)
+ return UTF16_DECODE_TRUNCATED_SEQUENCE;
+ utf16_t u2 = s[i + 1];
+ if (u2 < 0xDC00 || 0xDFFF < u)
+ return UTF16_DECODE_INVALID_SURROGATE;
+ u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
+ ++*pidx;
+ }
+ else if (0xDC00 <= u && u <= 0xDFFF)
+ return UTF16_DECODE_UNPAIRED_SURROGATE;
+ if (!utf_isValidDchar(u))
+ return UTF16_DECODE_INVALID_CODE_POINT;
+ *presult = u;
+ return UTF16_DECODE_OK;
+}
diff --git a/gcc/d/dmd/utf.h b/gcc/d/dmd/utf.h
new file mode 100644
index 0000000..154d39a
--- /dev/null
+++ b/gcc/d/dmd/utf.h
@@ -0,0 +1,117 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2003-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/D-Programming-Language/dmd/blob/master/src/utf.h
+ */
+
+#pragma once
+
+#include <stdlib.h>
+
+/// A UTF-8 code unit
+typedef unsigned char utf8_t;
+/// A UTF-16 code unit
+typedef unsigned short utf16_t;
+/// A UTF-32 code unit
+typedef unsigned int utf32_t;
+typedef utf32_t dchar_t;
+
+#define ALPHA_TABLE_LENGTH 245
+static utf16_t const ALPHA_TABLE[ALPHA_TABLE_LENGTH][2] =
+{
+ { 0x00AA, 0x00AA }, { 0x00B5, 0x00B5 }, { 0x00B7, 0x00B7 }, { 0x00BA, 0x00BA },
+ { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 }, { 0x01FA, 0x0217 },
+ { 0x0250, 0x02A8 }, { 0x02B0, 0x02B8 }, { 0x02BB, 0x02BB }, { 0x02BD, 0x02C1 },
+ { 0x02D0, 0x02D1 }, { 0x02E0, 0x02E4 }, { 0x037A, 0x037A }, { 0x0386, 0x0386 },
+ { 0x0388, 0x038A }, { 0x038C, 0x038C }, { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE },
+ { 0x03D0, 0x03D6 }, { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE },
+ { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 }, { 0x0401, 0x040C }, { 0x040E, 0x044F },
+ { 0x0451, 0x045C }, { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 },
+ { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 }, { 0x04F8, 0x04F9 },
+ { 0x0531, 0x0556 }, { 0x0559, 0x0559 }, { 0x0561, 0x0587 }, { 0x05B0, 0x05B9 },
+ { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05D0, 0x05EA },
+ { 0x05F0, 0x05F2 }, { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0660, 0x0669 },
+ { 0x0670, 0x06B7 }, { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06D0, 0x06DC },
+ { 0x06E5, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x06F0, 0x06F9 }, { 0x0901, 0x0903 },
+ { 0x0905, 0x0939 }, { 0x093D, 0x094D }, { 0x0950, 0x0952 }, { 0x0958, 0x0963 },
+ { 0x0966, 0x096F }, { 0x0981, 0x0983 }, { 0x0985, 0x098C }, { 0x098F, 0x0990 },
+ { 0x0993, 0x09A8 }, { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 },
+ { 0x09BE, 0x09C4 }, { 0x09C7, 0x09C8 }, { 0x09CB, 0x09CD }, { 0x09DC, 0x09DD },
+ { 0x09DF, 0x09E3 }, { 0x09E6, 0x09F1 }, { 0x0A02, 0x0A02 }, { 0x0A05, 0x0A0A },
+ { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 }, { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 },
+ { 0x0A35, 0x0A36 }, { 0x0A38, 0x0A39 }, { 0x0A3E, 0x0A42 }, { 0x0A47, 0x0A48 },
+ { 0x0A4B, 0x0A4D }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E }, { 0x0A66, 0x0A6F },
+ { 0x0A74, 0x0A74 }, { 0x0A81, 0x0A83 }, { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D },
+ { 0x0A8F, 0x0A91 }, { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 },
+ { 0x0AB5, 0x0AB9 }, { 0x0ABD, 0x0AC5 }, { 0x0AC7, 0x0AC9 }, { 0x0ACB, 0x0ACD },
+ { 0x0AD0, 0x0AD0 }, { 0x0AE0, 0x0AE0 }, { 0x0AE6, 0x0AEF }, { 0x0B01, 0x0B03 },
+ { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 }, { 0x0B2A, 0x0B30 },
+ { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 }, { 0x0B3D, 0x0B43 }, { 0x0B47, 0x0B48 },
+ { 0x0B4B, 0x0B4D }, { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 }, { 0x0B66, 0x0B6F },
+ { 0x0B82, 0x0B83 }, { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 },
+ { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F }, { 0x0BA3, 0x0BA4 },
+ { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 }, { 0x0BB7, 0x0BB9 }, { 0x0BBE, 0x0BC2 },
+ { 0x0BC6, 0x0BC8 }, { 0x0BCA, 0x0BCD }, { 0x0BE7, 0x0BEF }, { 0x0C01, 0x0C03 },
+ { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 }, { 0x0C2A, 0x0C33 },
+ { 0x0C35, 0x0C39 }, { 0x0C3E, 0x0C44 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D },
+ { 0x0C60, 0x0C61 }, { 0x0C66, 0x0C6F }, { 0x0C82, 0x0C83 }, { 0x0C85, 0x0C8C },
+ { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 }, { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 },
+ { 0x0CBE, 0x0CC4 }, { 0x0CC6, 0x0CC8 }, { 0x0CCA, 0x0CCD }, { 0x0CDE, 0x0CDE },
+ { 0x0CE0, 0x0CE1 }, { 0x0CE6, 0x0CEF }, { 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C },
+ { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 },
+ { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D61 }, { 0x0D66, 0x0D6F },
+ { 0x0E01, 0x0E3A }, { 0x0E40, 0x0E5B }, { 0x0E81, 0x0E82 },
+ { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D },
+ { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, { 0x0EA5, 0x0EA5 },
+ { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAB }, { 0x0EAD, 0x0EAE }, { 0x0EB0, 0x0EB9 },
+ { 0x0EBB, 0x0EBD }, { 0x0EC0, 0x0EC4 }, { 0x0EC6, 0x0EC6 }, { 0x0EC8, 0x0ECD },
+ { 0x0ED0, 0x0ED9 }, { 0x0EDC, 0x0EDD }, { 0x0F00, 0x0F00 }, { 0x0F18, 0x0F19 },
+ { 0x0F20, 0x0F33 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 },
+ { 0x0F3E, 0x0F47 }, { 0x0F49, 0x0F69 }, { 0x0F71, 0x0F84 }, { 0x0F86, 0x0F8B },
+ { 0x0F90, 0x0F95 }, { 0x0F97, 0x0F97 }, { 0x0F99, 0x0FAD }, { 0x0FB1, 0x0FB7 },
+ { 0x0FB9, 0x0FB9 }, { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 }, { 0x1E00, 0x1E9B },
+ { 0x1EA0, 0x1EF9 }, { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 },
+ { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 }, { 0x1F5B, 0x1F5B },
+ { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D }, { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC },
+ { 0x1FBE, 0x1FBE }, { 0x1FC2, 0x1FC4 }, { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 },
+ { 0x1FD6, 0x1FDB }, { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC },
+ { 0x203F, 0x2040 }, { 0x207F, 0x207F }, { 0x2102, 0x2102 }, { 0x2107, 0x2107 },
+ { 0x210A, 0x2113 }, { 0x2115, 0x2115 }, { 0x2118, 0x211D }, { 0x2124, 0x2124 },
+ { 0x2126, 0x2126 }, { 0x2128, 0x2128 }, { 0x212A, 0x2131 }, { 0x2133, 0x2138 },
+ { 0x2160, 0x2182 }, { 0x3005, 0x3007 }, { 0x3021, 0x3029 }, { 0x3041, 0x3093 },
+ { 0x309B, 0x309C }, { 0x30A1, 0x30F6 }, { 0x30FB, 0x30FC }, { 0x3105, 0x312C },
+ { 0x4E00, 0x9FA5 }, { 0xAC00, 0xD7A3 },
+};
+
+char const *const UTF8_DECODE_OK = NULL;
+extern char const UTF8_DECODE_OUTSIDE_CODE_SPACE[];
+extern char const UTF8_DECODE_TRUNCATED_SEQUENCE[];
+extern char const UTF8_DECODE_OVERLONG[];
+extern char const UTF8_DECODE_INVALID_TRAILER[];
+extern char const UTF8_DECODE_INVALID_CODE_POINT[];
+
+char const *const UTF16_DECODE_OK = NULL;
+extern char const UTF16_DECODE_TRUNCATED_SEQUENCE[];
+extern char const UTF16_DECODE_INVALID_SURROGATE[];
+extern char const UTF16_DECODE_UNPAIRED_SURROGATE[];
+extern char const UTF16_DECODE_INVALID_CODE_POINT[];
+
+/// \return true if \a c is a valid, non-private UTF-32 code point
+bool utf_isValidDchar(dchar_t c);
+
+bool isUniAlpha(dchar_t c);
+
+int utf_codeLengthChar(dchar_t c);
+int utf_codeLengthWchar(dchar_t c);
+int utf_codeLength(int sz, dchar_t c);
+
+void utf_encodeChar(utf8_t *s, dchar_t c);
+void utf_encodeWchar(utf16_t *s, dchar_t c);
+void utf_encode(int sz, void *s, dchar_t c);
+
+const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult);
+const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult);
diff --git a/gcc/d/dmd/utils.c b/gcc/d/dmd/utils.c
new file mode 100644
index 0000000..e3ea8c1
--- /dev/null
+++ b/gcc/d/dmd/utils.c
@@ -0,0 +1,122 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+#include <string.h>
+#include "mars.h"
+#include "globals.h"
+#include "root/file.h"
+#include "root/filename.h"
+#include "root/outbuffer.h"
+
+/**
+ * Normalize path by turning forward slashes into backslashes
+ *
+ * Params:
+ * src = Source path, using unix-style ('/') path separators
+ *
+ * Returns:
+ * A newly-allocated string with '/' turned into backslashes
+ */
+const char * toWinPath(const char *src)
+{
+ if (src == NULL)
+ return NULL;
+
+ char *result = strdup(src);
+ char *p = result;
+ while (*p != '\0')
+ {
+ if (*p == '/')
+ *p = '\\';
+ p++;
+ }
+ return result;
+}
+
+/**
+ * Reads a file, terminate the program on error
+ *
+ * Params:
+ * loc = The line number information from where the call originates
+ * f = a `ddmd.root.file.File` handle to read
+ */
+void readFile(Loc loc, File *f)
+{
+ if (f->read())
+ {
+ error(loc, "Error reading file '%s'", f->name->toChars());
+ fatal();
+ }
+}
+
+/**
+ * Writes a file, terminate the program on error
+ *
+ * Params:
+ * loc = The line number information from where the call originates
+ * f = a `ddmd.root.file.File` handle to write
+ */
+void writeFile(Loc loc, File *f)
+{
+ if (f->write())
+ {
+ error(loc, "Error writing file '%s'", f->name->toChars());
+ fatal();
+ }
+}
+
+/**
+ * Ensure the root path (the path minus the name) of the provided path
+ * exists, and terminate the process if it doesn't.
+ *
+ * Params:
+ * loc = The line number information from where the call originates
+ * name = a path to check (the name is stripped)
+ */
+void ensurePathToNameExists(Loc loc, const char *name)
+{
+ const char *pt = FileName::path(name);
+ if (*pt)
+ {
+ if (FileName::ensurePathExists(pt))
+ {
+ error(loc, "cannot create directory %s", pt);
+ fatal();
+ }
+ }
+ FileName::free(pt);
+}
+
+/**
+ * Takes a path, and escapes '(', ')' and backslashes
+ *
+ * Params:
+ * buf = Buffer to write the escaped path to
+ * fname = Path to escape
+ */
+void escapePath(OutBuffer *buf, const char *fname)
+{
+ while (1)
+ {
+ switch (*fname)
+ {
+ case 0:
+ return;
+ case '(':
+ case ')':
+ case '\\':
+ buf->writeByte('\\');
+ /* fall through */
+ default:
+ buf->writeByte(*fname);
+ break;
+ }
+ fname++;
+ }
+}
diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h
new file mode 100644
index 0000000..6268822
--- /dev/null
+++ b/gcc/d/dmd/version.h
@@ -0,0 +1,45 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/version.h
+ */
+
+#pragma once
+
+#include "dsymbol.h"
+
+class DebugSymbol : public Dsymbol
+{
+public:
+ unsigned level;
+
+ DebugSymbol(Loc loc, Identifier *ident);
+ DebugSymbol(Loc loc, unsigned level);
+ Dsymbol *syntaxCopy(Dsymbol *);
+
+ const char *toChars();
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void semantic(Scope *sc);
+ const char *kind();
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class VersionSymbol : public Dsymbol
+{
+public:
+ unsigned level;
+
+ VersionSymbol(Loc loc, Identifier *ident);
+ VersionSymbol(Loc loc, unsigned level);
+ Dsymbol *syntaxCopy(Dsymbol *);
+
+ const char *toChars();
+ void addMember(Scope *sc, ScopeDsymbol *sds);
+ void semantic(Scope *sc);
+ const char *kind();
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
new file mode 100644
index 0000000..ee0db98
--- /dev/null
+++ b/gcc/d/dmd/visitor.h
@@ -0,0 +1,599 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2013-2018 by The D Language Foundation, All Rights Reserved
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/visitor.h
+ */
+
+#pragma once
+
+#include <assert.h>
+
+class Statement;
+class ErrorStatement;
+class PeelStatement;
+class ExpStatement;
+class DtorExpStatement;
+class CompileStatement;
+class CompoundStatement;
+class CompoundDeclarationStatement;
+class UnrolledLoopStatement;
+class ScopeStatement;
+class ForwardingStatement;
+class WhileStatement;
+class DoStatement;
+class ForStatement;
+class ForeachStatement;
+class ForeachRangeStatement;
+class StaticForeachStatement;
+class IfStatement;
+class ConditionalStatement;
+class PragmaStatement;
+class StaticAssertStatement;
+class SwitchStatement;
+class CaseStatement;
+class CaseRangeStatement;
+class DefaultStatement;
+class GotoDefaultStatement;
+class GotoCaseStatement;
+class SwitchErrorStatement;
+class ReturnStatement;
+class BreakStatement;
+class ContinueStatement;
+class SynchronizedStatement;
+class WithStatement;
+class TryCatchStatement;
+class TryFinallyStatement;
+class OnScopeStatement;
+class ThrowStatement;
+class DebugStatement;
+class GotoStatement;
+class LabelStatement;
+class AsmStatement;
+class InlineAsmStatement;
+class GccAsmStatement;
+class CompoundAsmStatement;
+class ImportStatement;
+
+class Type;
+class TypeError;
+class TypeNext;
+class TypeBasic;
+class TypeVector;
+class TypeArray;
+class TypeSArray;
+class TypeDArray;
+class TypeAArray;
+class TypePointer;
+class TypeReference;
+class TypeFunction;
+class TypeDelegate;
+class TypeQualified;
+class TypeIdentifier;
+class TypeInstance;
+class TypeTypeof;
+class TypeReturn;
+class TypeStruct;
+class TypeEnum;
+class TypeClass;
+class TypeTuple;
+class TypeSlice;
+class TypeNull;
+
+class Dsymbol;
+
+class StaticAssert;
+class DebugSymbol;
+class VersionSymbol;
+class EnumMember;
+class Import;
+class OverloadSet;
+class LabelDsymbol;
+class AliasThis;
+
+class AttribDeclaration;
+class StorageClassDeclaration;
+class DeprecatedDeclaration;
+class LinkDeclaration;
+class CPPMangleDeclaration;
+class ProtDeclaration;
+class AlignDeclaration;
+class AnonDeclaration;
+class PragmaDeclaration;
+class ConditionalDeclaration;
+class StaticIfDeclaration;
+class CompileDeclaration;
+class StaticForeachDeclaration;
+class UserAttributeDeclaration;
+
+class ScopeDsymbol;
+class TemplateDeclaration;
+class TemplateInstance;
+class TemplateMixin;
+class EnumDeclaration;
+class Package;
+class Module;
+class WithScopeSymbol;
+class ArrayScopeSymbol;
+class Nspace;
+
+class AggregateDeclaration;
+class StructDeclaration;
+class UnionDeclaration;
+class ClassDeclaration;
+class InterfaceDeclaration;
+
+class Declaration;
+class TupleDeclaration;
+class AliasDeclaration;
+class OverDeclaration;
+class VarDeclaration;
+class SymbolDeclaration;
+class ThisDeclaration;
+
+class TypeInfoDeclaration;
+class TypeInfoStructDeclaration;
+class TypeInfoClassDeclaration;
+class TypeInfoInterfaceDeclaration;
+class TypeInfoPointerDeclaration;
+class TypeInfoArrayDeclaration;
+class TypeInfoStaticArrayDeclaration;
+class TypeInfoAssociativeArrayDeclaration;
+class TypeInfoEnumDeclaration;
+class TypeInfoFunctionDeclaration;
+class TypeInfoDelegateDeclaration;
+class TypeInfoTupleDeclaration;
+class TypeInfoConstDeclaration;
+class TypeInfoInvariantDeclaration;
+class TypeInfoSharedDeclaration;
+class TypeInfoWildDeclaration;
+class TypeInfoVectorDeclaration;
+
+class FuncDeclaration;
+class FuncAliasDeclaration;
+class FuncLiteralDeclaration;
+class CtorDeclaration;
+class PostBlitDeclaration;
+class DtorDeclaration;
+class StaticCtorDeclaration;
+class SharedStaticCtorDeclaration;
+class StaticDtorDeclaration;
+class SharedStaticDtorDeclaration;
+class InvariantDeclaration;
+class UnitTestDeclaration;
+class NewDeclaration;
+class DeleteDeclaration;
+
+class Initializer;
+class VoidInitializer;
+class ErrorInitializer;
+class StructInitializer;
+class ArrayInitializer;
+class ExpInitializer;
+
+class Expression;
+class IntegerExp;
+class ErrorExp;
+class RealExp;
+class ComplexExp;
+class IdentifierExp;
+class DollarExp;
+class DsymbolExp;
+class ThisExp;
+class SuperExp;
+class NullExp;
+class StringExp;
+class TupleExp;
+class ArrayLiteralExp;
+class AssocArrayLiteralExp;
+class StructLiteralExp;
+class TypeExp;
+class ScopeExp;
+class TemplateExp;
+class NewExp;
+class NewAnonClassExp;
+class SymbolExp;
+class SymOffExp;
+class VarExp;
+class OverExp;
+class FuncExp;
+class DeclarationExp;
+class TypeidExp;
+class TraitsExp;
+class HaltExp;
+class IsExp;
+class UnaExp;
+class BinExp;
+class BinAssignExp;
+class CompileExp;
+class ImportExp;
+class AssertExp;
+class DotIdExp;
+class DotTemplateExp;
+class DotVarExp;
+class DotTemplateInstanceExp;
+class DelegateExp;
+class DotTypeExp;
+class CallExp;
+class AddrExp;
+class PtrExp;
+class NegExp;
+class UAddExp;
+class ComExp;
+class NotExp;
+class DeleteExp;
+class CastExp;
+class VectorExp;
+class SliceExp;
+class ArrayLengthExp;
+class IntervalExp;
+class DelegatePtrExp;
+class DelegateFuncptrExp;
+class ArrayExp;
+class DotExp;
+class CommaExp;
+class IndexExp;
+class PostExp;
+class PreExp;
+class AssignExp;
+class ConstructExp;
+class BlitExp;
+class AddAssignExp;
+class MinAssignExp;
+class MulAssignExp;
+class DivAssignExp;
+class ModAssignExp;
+class AndAssignExp;
+class OrAssignExp;
+class XorAssignExp;
+class PowAssignExp;
+class ShlAssignExp;
+class ShrAssignExp;
+class UshrAssignExp;
+class CatAssignExp;
+class AddExp;
+class MinExp;
+class CatExp;
+class MulExp;
+class DivExp;
+class ModExp;
+class PowExp;
+class ShlExp;
+class ShrExp;
+class UshrExp;
+class AndExp;
+class OrExp;
+class XorExp;
+class OrOrExp;
+class AndAndExp;
+class CmpExp;
+class InExp;
+class RemoveExp;
+class EqualExp;
+class IdentityExp;
+class CondExp;
+class DefaultInitExp;
+class FileInitExp;
+class LineInitExp;
+class ModuleInitExp;
+class FuncInitExp;
+class PrettyFuncInitExp;
+class ClassReferenceExp;
+class VoidInitExp;
+class ThrownExceptionExp;
+
+class TemplateParameter;
+class TemplateTypeParameter;
+class TemplateThisParameter;
+class TemplateValueParameter;
+class TemplateAliasParameter;
+class TemplateTupleParameter;
+
+class Condition;
+class DVCondition;
+class DebugCondition;
+class VersionCondition;
+class StaticIfCondition;
+
+class Parameter;
+
+class Visitor
+{
+public:
+ virtual void visit(Statement *) { assert(0); }
+ virtual void visit(ErrorStatement *s) { visit((Statement *)s); }
+ virtual void visit(PeelStatement *s) { visit((Statement *)s); }
+ virtual void visit(ExpStatement *s) { visit((Statement *)s); }
+ virtual void visit(DtorExpStatement *s) { visit((ExpStatement *)s); }
+ virtual void visit(CompileStatement *s) { visit((Statement *)s); }
+ virtual void visit(CompoundStatement *s) { visit((Statement *)s); }
+ virtual void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
+ virtual void visit(UnrolledLoopStatement *s) { visit((Statement *)s); }
+ virtual void visit(ScopeStatement *s) { visit((Statement *)s); }
+ virtual void visit(ForwardingStatement *s) { visit((Statement *)s); }
+ virtual void visit(WhileStatement *s) { visit((Statement *)s); }
+ virtual void visit(DoStatement *s) { visit((Statement *)s); }
+ virtual void visit(ForStatement *s) { visit((Statement *)s); }
+ virtual void visit(ForeachStatement *s) { visit((Statement *)s); }
+ virtual void visit(ForeachRangeStatement *s) { visit((Statement *)s); }
+ virtual void visit(StaticForeachStatement *s) { visit((Statement *)s); }
+ virtual void visit(IfStatement *s) { visit((Statement *)s); }
+ virtual void visit(ConditionalStatement *s) { visit((Statement *)s); }
+ virtual void visit(PragmaStatement *s) { visit((Statement *)s); }
+ virtual void visit(StaticAssertStatement *s) { visit((Statement *)s); }
+ virtual void visit(SwitchStatement *s) { visit((Statement *)s); }
+ virtual void visit(CaseStatement *s) { visit((Statement *)s); }
+ virtual void visit(CaseRangeStatement *s) { visit((Statement *)s); }
+ virtual void visit(DefaultStatement *s) { visit((Statement *)s); }
+ virtual void visit(GotoDefaultStatement *s) { visit((Statement *)s); }
+ virtual void visit(GotoCaseStatement *s) { visit((Statement *)s); }
+ virtual void visit(SwitchErrorStatement *s) { visit((Statement *)s); }
+ virtual void visit(ReturnStatement *s) { visit((Statement *)s); }
+ virtual void visit(BreakStatement *s) { visit((Statement *)s); }
+ virtual void visit(ContinueStatement *s) { visit((Statement *)s); }
+ virtual void visit(SynchronizedStatement *s) { visit((Statement *)s); }
+ virtual void visit(WithStatement *s) { visit((Statement *)s); }
+ virtual void visit(TryCatchStatement *s) { visit((Statement *)s); }
+ virtual void visit(TryFinallyStatement *s) { visit((Statement *)s); }
+ virtual void visit(OnScopeStatement *s) { visit((Statement *)s); }
+ virtual void visit(ThrowStatement *s) { visit((Statement *)s); }
+ virtual void visit(DebugStatement *s) { visit((Statement *)s); }
+ virtual void visit(GotoStatement *s) { visit((Statement *)s); }
+ virtual void visit(LabelStatement *s) { visit((Statement *)s); }
+ virtual void visit(AsmStatement *s) { visit((Statement *)s); }
+ virtual void visit(InlineAsmStatement *s) { visit((AsmStatement *)s); }
+ virtual void visit(GccAsmStatement *s) { visit((AsmStatement *)s); }
+ virtual void visit(CompoundAsmStatement *s) { visit((CompoundStatement *)s); }
+ virtual void visit(ImportStatement *s) { visit((Statement *)s); }
+
+ virtual void visit(Type *) { assert(0); }
+ virtual void visit(TypeError *t) { visit((Type *)t); }
+ virtual void visit(TypeNext *t) { visit((Type *)t); }
+ virtual void visit(TypeBasic *t) { visit((Type *)t); }
+ virtual void visit(TypeVector *t) { visit((Type *)t); }
+ virtual void visit(TypeArray *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeSArray *t) { visit((TypeArray *)t); }
+ virtual void visit(TypeDArray *t) { visit((TypeArray *)t); }
+ virtual void visit(TypeAArray *t) { visit((TypeArray *)t); }
+ virtual void visit(TypePointer *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeReference *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeFunction *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeDelegate *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeQualified *t) { visit((Type *)t); }
+ virtual void visit(TypeIdentifier *t) { visit((TypeQualified *)t); }
+ virtual void visit(TypeInstance *t) { visit((TypeQualified *)t); }
+ virtual void visit(TypeTypeof *t) { visit((TypeQualified *)t); }
+ virtual void visit(TypeReturn *t) { visit((TypeQualified *)t); }
+ virtual void visit(TypeStruct *t) { visit((Type *)t); }
+ virtual void visit(TypeEnum *t) { visit((Type *)t); }
+ virtual void visit(TypeClass *t) { visit((Type *)t); }
+ virtual void visit(TypeTuple *t) { visit((Type *)t); }
+ virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeNull *t) { visit((Type *)t); }
+
+ virtual void visit(Dsymbol *) { assert(0); }
+
+ virtual void visit(StaticAssert *s) { visit((Dsymbol *)s); }
+ virtual void visit(DebugSymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(VersionSymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(EnumMember *s) { visit((VarDeclaration *)s); }
+ virtual void visit(Import *s) { visit((Dsymbol *)s); }
+ virtual void visit(OverloadSet *s) { visit((Dsymbol *)s); }
+ virtual void visit(LabelDsymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(AliasThis *s) { visit((Dsymbol *)s); }
+
+ virtual void visit(AttribDeclaration *s) { visit((Dsymbol *)s); }
+ virtual void visit(StorageClassDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(DeprecatedDeclaration *s) { visit((StorageClassDeclaration *)s); }
+ virtual void visit(LinkDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(CPPMangleDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(ProtDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(AlignDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(AnonDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(PragmaDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(ConditionalDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(StaticIfDeclaration *s) { visit((ConditionalDeclaration *)s); }
+ virtual void visit(StaticForeachDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); }
+
+ virtual void visit(ScopeDsymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(TemplateDeclaration *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(TemplateInstance *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(TemplateMixin *s) { visit((TemplateInstance *)s); }
+ virtual void visit(EnumDeclaration *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(Package *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(Module *s) { visit((Package *)s); }
+ virtual void visit(WithScopeSymbol *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(ArrayScopeSymbol *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(Nspace *s) { visit((ScopeDsymbol *)s); }
+
+ virtual void visit(AggregateDeclaration *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(StructDeclaration *s) { visit((AggregateDeclaration *)s); }
+ virtual void visit(UnionDeclaration *s) { visit((StructDeclaration *)s); }
+ virtual void visit(ClassDeclaration *s) { visit((AggregateDeclaration *)s); }
+ virtual void visit(InterfaceDeclaration *s) { visit((ClassDeclaration *)s); }
+
+ virtual void visit(Declaration *s) { visit((Dsymbol *)s); }
+ virtual void visit(TupleDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(AliasDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(OverDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(VarDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(SymbolDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(ThisDeclaration *s) { visit((VarDeclaration *)s); }
+
+ virtual void visit(TypeInfoDeclaration *s) { visit((VarDeclaration *)s); }
+ virtual void visit(TypeInfoStructDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoClassDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoInterfaceDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoPointerDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoStaticArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoAssociativeArrayDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoEnumDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoFunctionDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoDelegateDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoTupleDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoConstDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoInvariantDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoSharedDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoWildDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+ virtual void visit(TypeInfoVectorDeclaration *s) { visit((TypeInfoDeclaration *)s); }
+
+ virtual void visit(FuncDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(FuncAliasDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(FuncLiteralDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(CtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(PostBlitDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(DtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(StaticCtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(SharedStaticCtorDeclaration *s) { visit((StaticCtorDeclaration *)s); }
+ virtual void visit(StaticDtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(SharedStaticDtorDeclaration *s) { visit((StaticDtorDeclaration *)s); }
+ virtual void visit(InvariantDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(UnitTestDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(NewDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(DeleteDeclaration *s) { visit((FuncDeclaration *)s); }
+
+ virtual void visit(Initializer *) { assert(0); }
+ virtual void visit(VoidInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(ErrorInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(StructInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(ExpInitializer *i) { visit((Initializer *)i); }
+
+ virtual void visit(Expression *) { assert(0); }
+ virtual void visit(IntegerExp *e) { visit((Expression *)e); }
+ virtual void visit(ErrorExp *e) { visit((Expression *)e); }
+ virtual void visit(RealExp *e) { visit((Expression *)e); }
+ virtual void visit(ComplexExp *e) { visit((Expression *)e); }
+ virtual void visit(IdentifierExp *e) { visit((Expression *)e); }
+ virtual void visit(DollarExp *e) { visit((IdentifierExp *)e); }
+ virtual void visit(DsymbolExp *e) { visit((Expression *)e); }
+ virtual void visit(ThisExp *e) { visit((Expression *)e); }
+ virtual void visit(SuperExp *e) { visit((ThisExp *)e); }
+ virtual void visit(NullExp *e) { visit((Expression *)e); }
+ virtual void visit(StringExp *e) { visit((Expression *)e); }
+ virtual void visit(TupleExp *e) { visit((Expression *)e); }
+ virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); }
+ virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); }
+ virtual void visit(StructLiteralExp *e) { visit((Expression *)e); }
+ virtual void visit(TypeExp *e) { visit((Expression *)e); }
+ virtual void visit(ScopeExp *e) { visit((Expression *)e); }
+ virtual void visit(TemplateExp *e) { visit((Expression *)e); }
+ virtual void visit(NewExp *e) { visit((Expression *)e); }
+ virtual void visit(NewAnonClassExp *e) { visit((Expression *)e); }
+ virtual void visit(SymbolExp *e) { visit((Expression *)e); }
+ virtual void visit(SymOffExp *e) { visit((SymbolExp *)e); }
+ virtual void visit(VarExp *e) { visit((SymbolExp *)e); }
+ virtual void visit(OverExp *e) { visit((Expression *)e); }
+ virtual void visit(FuncExp *e) { visit((Expression *)e); }
+ virtual void visit(DeclarationExp *e) { visit((Expression *)e); }
+ virtual void visit(TypeidExp *e) { visit((Expression *)e); }
+ virtual void visit(TraitsExp *e) { visit((Expression *)e); }
+ virtual void visit(HaltExp *e) { visit((Expression *)e); }
+ virtual void visit(IsExp *e) { visit((Expression *)e); }
+ virtual void visit(UnaExp *e) { visit((Expression *)e); }
+ virtual void visit(BinExp *e) { visit((Expression *)e); }
+ virtual void visit(BinAssignExp *e) { visit((BinExp *)e); }
+ virtual void visit(CompileExp *e) { visit((UnaExp *)e); }
+ virtual void visit(ImportExp *e) { visit((UnaExp *)e); }
+ virtual void visit(AssertExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotIdExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotTemplateExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotVarExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotTemplateInstanceExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DelegateExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotTypeExp *e) { visit((UnaExp *)e); }
+ virtual void visit(CallExp *e) { visit((UnaExp *)e); }
+ virtual void visit(AddrExp *e) { visit((UnaExp *)e); }
+ virtual void visit(PtrExp *e) { visit((UnaExp *)e); }
+ virtual void visit(NegExp *e) { visit((UnaExp *)e); }
+ virtual void visit(UAddExp *e) { visit((UnaExp *)e); }
+ virtual void visit(ComExp *e) { visit((UnaExp *)e); }
+ virtual void visit(NotExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DeleteExp *e) { visit((UnaExp *)e); }
+ virtual void visit(CastExp *e) { visit((UnaExp *)e); }
+ virtual void visit(VectorExp *e) { visit((UnaExp *)e); }
+ virtual void visit(SliceExp *e) { visit((UnaExp *)e); }
+ virtual void visit(ArrayLengthExp *e) { visit((UnaExp *)e); }
+ virtual void visit(IntervalExp *e) { visit((Expression *)e); }
+ virtual void visit(DelegatePtrExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DelegateFuncptrExp *e) { visit((UnaExp *)e); }
+ virtual void visit(ArrayExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotExp *e) { visit((BinExp *)e); }
+ virtual void visit(CommaExp *e) { visit((BinExp *)e); }
+ virtual void visit(IndexExp *e) { visit((BinExp *)e); }
+ virtual void visit(PostExp *e) { visit((BinExp *)e); }
+ virtual void visit(PreExp *e) { visit((UnaExp *)e); }
+ virtual void visit(AssignExp *e) { visit((BinExp *)e); }
+ virtual void visit(ConstructExp *e) { visit((AssignExp *)e); }
+ virtual void visit(BlitExp *e) { visit((AssignExp *)e); }
+ virtual void visit(AddAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(MinAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(MulAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(DivAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(ModAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(AndAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(OrAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(XorAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(PowAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(ShlAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(ShrAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(UshrAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(CatAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(AddExp *e) { visit((BinExp *)e); }
+ virtual void visit(MinExp *e) { visit((BinExp *)e); }
+ virtual void visit(CatExp *e) { visit((BinExp *)e); }
+ virtual void visit(MulExp *e) { visit((BinExp *)e); }
+ virtual void visit(DivExp *e) { visit((BinExp *)e); }
+ virtual void visit(ModExp *e) { visit((BinExp *)e); }
+ virtual void visit(PowExp *e) { visit((BinExp *)e); }
+ virtual void visit(ShlExp *e) { visit((BinExp *)e); }
+ virtual void visit(ShrExp *e) { visit((BinExp *)e); }
+ virtual void visit(UshrExp *e) { visit((BinExp *)e); }
+ virtual void visit(AndExp *e) { visit((BinExp *)e); }
+ virtual void visit(OrExp *e) { visit((BinExp *)e); }
+ virtual void visit(XorExp *e) { visit((BinExp *)e); }
+ virtual void visit(OrOrExp *e) { visit((BinExp *)e); }
+ virtual void visit(AndAndExp *e) { visit((BinExp *)e); }
+ virtual void visit(CmpExp *e) { visit((BinExp *)e); }
+ virtual void visit(InExp *e) { visit((BinExp *)e); }
+ virtual void visit(RemoveExp *e) { visit((BinExp *)e); }
+ virtual void visit(EqualExp *e) { visit((BinExp *)e); }
+ virtual void visit(IdentityExp *e) { visit((BinExp *)e); }
+ virtual void visit(CondExp *e) { visit((BinExp *)e); }
+ virtual void visit(DefaultInitExp *e) { visit((Expression *)e); }
+ virtual void visit(FileInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(LineInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(ModuleInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(FuncInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(PrettyFuncInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(ClassReferenceExp *e) { visit((Expression *)e); }
+ virtual void visit(VoidInitExp *e) { visit((Expression *)e); }
+ virtual void visit(ThrownExceptionExp *e) { visit((Expression *)e); }
+
+ virtual void visit(TemplateParameter *) { assert(0); }
+ virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); }
+ virtual void visit(TemplateThisParameter *tp) { visit((TemplateTypeParameter *)tp); }
+ virtual void visit(TemplateValueParameter *tp) { visit((TemplateParameter *)tp); }
+ virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); }
+ virtual void visit(TemplateTupleParameter *tp) { visit((TemplateParameter *)tp); }
+
+ virtual void visit(Condition *) { assert(0); }
+ virtual void visit(DVCondition *c) { visit((Condition *)c); }
+ virtual void visit(DebugCondition *c) { visit((DVCondition *)c); }
+ virtual void visit(VersionCondition *c) { visit((DVCondition *)c); }
+ virtual void visit(StaticIfCondition *c) { visit((Condition *)c); }
+
+ virtual void visit(Parameter *) { assert(0); }
+};
+
+class StoppableVisitor : public Visitor
+{
+public:
+ bool stop;
+ StoppableVisitor() : stop(false) {}
+};
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
new file mode 100644
index 0000000..9a1aad4
--- /dev/null
+++ b/gcc/d/expr.cc
@@ -0,0 +1,3138 @@
+/* expr.cc -- Lower D frontend expressions to GCC trees.
+ Copyright (C) 2015-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/ctfe.h"
+#include "dmd/declaration.h"
+#include "dmd/expression.h"
+#include "dmd/identifier.h"
+#include "dmd/init.h"
+#include "dmd/module.h"
+#include "dmd/mtype.h"
+#include "dmd/template.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "tm.h"
+#include "function.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "predict.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+
+
+/* Implements the visitor interface to build the GCC trees of all Expression
+ AST classes emitted from the D Front-end.
+ All visit methods accept one parameter E, which holds the frontend AST
+ of the expression to compile. They also don't return any value, instead
+ generated code is cached in RESULT_ and returned from the caller. */
+
+class ExprVisitor : public Visitor
+{
+ using Visitor::visit;
+
+ tree result_;
+ bool constp_;
+
+ /* Determine if type is a struct that has a postblit. */
+
+ bool needs_postblit (Type *t)
+ {
+ t = t->baseElemOf ();
+
+ if (t->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *) t)->sym;
+ if (sd->postblit)
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Determine if type is a struct that has a destructor. */
+
+ bool needs_dtor (Type *t)
+ {
+ t = t->baseElemOf ();
+
+ if (t->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *) t)->sym;
+ if (sd->dtor)
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Determine if expression is suitable lvalue. */
+
+ bool lvalue_p (Expression *e)
+ {
+ return ((e->op != TOKslice && e->isLvalue ())
+ || (e->op == TOKslice && ((UnaExp *) e)->e1->isLvalue ())
+ || (e->op == TOKcast && ((UnaExp *) e)->e1->isLvalue ()));
+ }
+
+ /* Build an expression of code CODE, data type TYPE, and operands ARG0 and
+ ARG1. Perform relevant conversions needed for correct code operations. */
+
+ tree binary_op (tree_code code, tree type, tree arg0, tree arg1)
+ {
+ tree t0 = TREE_TYPE (arg0);
+ tree t1 = TREE_TYPE (arg1);
+ tree ret = NULL_TREE;
+
+ bool unsignedp = TYPE_UNSIGNED (t0) || TYPE_UNSIGNED (t1);
+
+ /* Deal with float mod expressions immediately. */
+ if (code == FLOAT_MOD_EXPR)
+ return build_float_modulus (type, arg0, arg1);
+
+ if (POINTER_TYPE_P (t0) && INTEGRAL_TYPE_P (t1))
+ return build_nop (type, build_offset_op (code, arg0, arg1));
+
+ if (INTEGRAL_TYPE_P (t0) && POINTER_TYPE_P (t1))
+ return build_nop (type, build_offset_op (code, arg1, arg0));
+
+ if (POINTER_TYPE_P (t0) && POINTER_TYPE_P (t1))
+ {
+ gcc_assert (code == MINUS_EXPR);
+ tree ptrtype = lang_hooks.types.type_for_mode (ptr_mode, 0);
+
+ /* POINTER_DIFF_EXPR requires a signed integer type of the same size as
+ pointers. If some platform cannot provide that, or has a larger
+ ptrdiff_type to support differences larger than half the address
+ space, cast the pointers to some larger integer type and do the
+ computations in that type. */
+ if (TYPE_PRECISION (ptrtype) > TYPE_PRECISION (t0))
+ ret = fold_build2 (MINUS_EXPR, ptrtype,
+ d_convert (ptrtype, arg0),
+ d_convert (ptrtype, arg1));
+ else
+ ret = fold_build2 (POINTER_DIFF_EXPR, ptrtype, arg0, arg1);
+ }
+ else if (INTEGRAL_TYPE_P (type) && (TYPE_UNSIGNED (type) != unsignedp))
+ {
+ tree inttype = (unsignedp)
+ ? d_unsigned_type (type) : d_signed_type (type);
+ ret = fold_build2 (code, inttype, arg0, arg1);
+ }
+ else
+ {
+ /* If the operation needs excess precision. */
+ tree eptype = excess_precision_type (type);
+ if (eptype != NULL_TREE)
+ {
+ arg0 = d_convert (eptype, arg0);
+ arg1 = d_convert (eptype, arg1);
+ }
+ else
+ {
+ /* Front-end does not do this conversion and GCC does not
+ always do it right. */
+ if (COMPLEX_FLOAT_TYPE_P (t0) && !COMPLEX_FLOAT_TYPE_P (t1))
+ arg1 = d_convert (t0, arg1);
+ else if (COMPLEX_FLOAT_TYPE_P (t1) && !COMPLEX_FLOAT_TYPE_P (t0))
+ arg0 = d_convert (t1, arg0);
+
+ eptype = type;
+ }
+
+ ret = fold_build2 (code, eptype, arg0, arg1);
+ }
+
+ return d_convert (type, ret);
+ }
+
+ /* Build a binary expression of code CODE, assigning the result into E1. */
+
+ tree binop_assignment (tree_code code, Expression *e1, Expression *e2)
+ {
+ /* Skip casts for lhs assignment. */
+ Expression *e1b = e1;
+ while (e1b->op == TOKcast)
+ {
+ CastExp *ce = (CastExp *) e1b;
+ gcc_assert (same_type_p (ce->type, ce->to));
+ e1b = ce->e1;
+ }
+
+ /* Stabilize LHS for assignment. */
+ tree lhs = build_expr (e1b);
+ tree lexpr = stabilize_expr (&lhs);
+
+ /* The LHS expression could be an assignment, to which its operation gets
+ lost during gimplification. */
+ if (TREE_CODE (lhs) == MODIFY_EXPR)
+ {
+ /* If LHS has side effects, call stabilize_reference on it, so it can
+ be evaluated multiple times. */
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
+ lhs = build_assign (MODIFY_EXPR,
+ stabilize_reference (TREE_OPERAND (lhs, 0)),
+ TREE_OPERAND (lhs, 1));
+
+ lexpr = compound_expr (lexpr, lhs);
+ lhs = TREE_OPERAND (lhs, 0);
+ }
+
+ lhs = stabilize_reference (lhs);
+
+ /* Save RHS, to ensure that the expression is evaluated before LHS. */
+ tree rhs = build_expr (e2);
+ tree rexpr = d_save_expr (rhs);
+
+ rhs = this->binary_op (code, build_ctype (e1->type),
+ convert_expr (lhs, e1b->type, e1->type), rexpr);
+ if (TREE_SIDE_EFFECTS (rhs))
+ rhs = compound_expr (rexpr, rhs);
+
+ tree expr = modify_expr (lhs, convert_expr (rhs, e1->type, e1b->type));
+ return compound_expr (lexpr, expr);
+ }
+
+public:
+ ExprVisitor (bool constp)
+ {
+ this->result_ = NULL_TREE;
+ this->constp_ = constp;
+ }
+
+ tree result (void)
+ {
+ return this->result_;
+ }
+
+ /* Visitor interfaces, each Expression class should have
+ overridden the default. */
+
+ void visit (Expression *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* Build a conditional expression. If either the second or third
+ expression is void, then the resulting type is void. Otherwise
+ they are implicitly converted to a common type. */
+
+ void visit (CondExp *e)
+ {
+ tree cond = convert_for_condition (build_expr (e->econd),
+ e->econd->type);
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+
+ if (e->type->ty != Tvoid)
+ {
+ t1 = convert_expr (t1, e->e1->type, e->type);
+ t2 = convert_expr (t2, e->e2->type, e->type);
+ }
+
+ this->result_ = build_condition (build_ctype (e->type), cond, t1, t2);
+ }
+
+ /* Build an identity comparison expression. Operands go through the
+ usual conversions to bring them to a common type before comparison.
+ The result type is bool. */
+
+ void visit (IdentityExp *e)
+ {
+ tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR;
+ Type *tb1 = e->e1->type->toBasetype ();
+ Type *tb2 = e->e2->type->toBasetype ();
+
+ if ((tb1->ty == Tsarray || tb1->ty == Tarray)
+ && (tb2->ty == Tsarray || tb2->ty == Tarray))
+ {
+ /* For static and dynamic arrays, identity is defined as referring to
+ the same array elements and the same number of elements. */
+ tree t1 = d_array_convert (e->e1);
+ tree t2 = d_array_convert (e->e2);
+ this->result_ = d_convert (build_ctype (e->type),
+ build_boolop (code, t1, t2));
+ }
+ else if (tb1->isfloating () && tb1->ty != Tvector)
+ {
+ /* For floating-point values, identity is defined as the bits in the
+ operands being identical. */
+ tree t1 = d_save_expr (build_expr (e->e1));
+ tree t2 = d_save_expr (build_expr (e->e2));
+
+ tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
+ tree size = size_int (TYPE_PRECISION (TREE_TYPE (t1)) / BITS_PER_UNIT);
+
+ tree result = build_call_expr (tmemcmp, 3, build_address (t1),
+ build_address (t2), size);
+ this->result_ = build_boolop (code, result, integer_zero_node);
+ }
+ else if (tb1->ty == Tstruct)
+ {
+ /* For struct objects, identity is defined as bits in operands being
+ identical also. Alignment holes in structs are ignored. */
+ StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+
+ gcc_assert (same_type_p (tb1, tb2));
+
+ this->result_ = build_struct_comparison (code, sd, t1, t2);
+ }
+ else
+ {
+ /* For operands of other types, identity is defined as being the
+ same as equality expressions. */
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+ this->result_ = d_convert (build_ctype (e->type),
+ build_boolop (code, t1, t2));
+ }
+ }
+
+ /* Build an equality expression, which compare the two operands for either
+ equality or inequality. Operands go through the usual conversions to bring
+ them to a common type before comparison. The result type is bool. */
+
+ void visit (EqualExp *e)
+ {
+ Type *tb1 = e->e1->type->toBasetype ();
+ Type *tb2 = e->e2->type->toBasetype ();
+ tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR;
+
+ if ((tb1->ty == Tsarray || tb1->ty == Tarray)
+ && (tb2->ty == Tsarray || tb2->ty == Tarray))
+ {
+ /* For static and dynamic arrays, equality is defined as the lengths of
+ the arrays matching, and all the elements are equal. */
+ Type *t1elem = tb1->nextOf ()->toBasetype ();
+ Type *t2elem = tb1->nextOf ()->toBasetype ();
+
+ /* Check if comparisons of arrays can be optimized using memcmp.
+ This will inline EQ expressions as:
+ e1.length == e2.length && memcmp(e1.ptr, e2.ptr, size) == 0;
+ Or when generating a NE expression:
+ e1.length != e2.length || memcmp(e1.ptr, e2.ptr, size) != 0; */
+ if ((t1elem->isintegral () || t1elem->ty == Tvoid
+ || (t1elem->ty == Tstruct && !((TypeStruct *)t1elem)->sym->xeq))
+ && t1elem->ty == t2elem->ty)
+ {
+ tree t1 = d_array_convert (e->e1);
+ tree t2 = d_array_convert (e->e2);
+ tree result;
+
+ /* Make temporaries to prevent multiple evaluations. */
+ tree t1saved = d_save_expr (t1);
+ tree t2saved = d_save_expr (t2);
+
+ /* Length of arrays, for comparisons done before calling memcmp. */
+ tree t1len = d_array_length (t1saved);
+ tree t2len = d_array_length (t2saved);
+
+ /* Reference to array data. */
+ tree t1ptr = d_array_ptr (t1saved);
+ tree t2ptr = d_array_ptr (t2saved);
+
+ /* Compare arrays using memcmp if possible, otherwise for structs,
+ each field is compared inline. */
+ if (t1elem->ty != Tstruct
+ || identity_compare_p (((TypeStruct *) t1elem)->sym))
+ {
+ tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
+ tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
+
+ result = build_call_expr (tmemcmp, 3, t1ptr, t2ptr, size);
+ result = build_boolop (code, result, integer_zero_node);
+ }
+ else
+ {
+ StructDeclaration *sd = ((TypeStruct *) t1elem)->sym;
+
+ result = build_array_struct_comparison (code, sd, t1len,
+ t1ptr, t2ptr);
+ }
+
+ /* Check array length first before passing to memcmp.
+ For equality expressions, this becomes:
+ (e1.length == 0 || memcmp);
+ Otherwise for inequality:
+ (e1.length != 0 && memcmp); */
+ tree tsizecmp = build_boolop (code, t1len, size_zero_node);
+ if (e->op == TOKequal)
+ result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result);
+ else
+ result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result);
+
+ /* Finally, check if lengths of both arrays match if dynamic.
+ The frontend should have already guaranteed that static arrays
+ have same size. */
+ if (tb1->ty == Tsarray && tb2->ty == Tsarray)
+ gcc_assert (tb1->size () == tb2->size ());
+ else
+ {
+ tree tlencmp = build_boolop (code, t1len, t2len);
+ if (e->op == TOKequal)
+ result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result);
+ else
+ result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result);
+ }
+
+ /* Ensure left-to-right order of evaluation. */
+ if (TREE_SIDE_EFFECTS (t2))
+ result = compound_expr (t2saved, result);
+
+ if (TREE_SIDE_EFFECTS (t1))
+ result = compound_expr (t1saved, result);
+
+ this->result_ = result;
+ }
+ else
+ {
+ /* Use _adEq2() to compare each element. */
+ Type *t1array = t1elem->arrayOf ();
+ tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3,
+ d_array_convert (e->e1),
+ d_array_convert (e->e2),
+ build_typeinfo (t1array));
+
+ if (e->op == TOKnotequal)
+ result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
+
+ this->result_ = result;
+ }
+ }
+ else if (tb1->ty == Tstruct)
+ {
+ /* Equality for struct objects means the logical product of all
+ equality results of the corresponding object fields. */
+ StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+
+ gcc_assert (same_type_p (tb1, tb2));
+
+ this->result_ = build_struct_comparison (code, sd, t1, t2);
+ }
+ else if (tb1->ty == Taarray && tb2->ty == Taarray)
+ {
+ /* Use _aaEqual() for associative arrays. */
+ TypeAArray *taa1 = (TypeAArray *) tb1;
+ tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3,
+ build_typeinfo (taa1),
+ build_expr (e->e1),
+ build_expr (e->e2));
+
+ if (e->op == TOKnotequal)
+ result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
+
+ this->result_ = result;
+ }
+ else
+ {
+ /* For operands of other types, equality is defined as the bit pattern
+ of the type matches exactly. */
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+
+ this->result_ = d_convert (build_ctype (e->type),
+ build_boolop (code, t1, t2));
+ }
+ }
+
+ /* Build an `in' expression. This is a condition to see if an element
+ exists in an associative array. The result is a pointer to the
+ element, or null if false. */
+
+ void visit (InExp *e)
+ {
+ Type *tb2 = e->e2->type->toBasetype ();
+ gcc_assert (tb2->ty == Taarray);
+
+ Type *tkey = ((TypeAArray *) tb2)->index->toBasetype ();
+ tree key = convert_expr (build_expr (e->e1), e->e1->type, tkey);
+
+ /* Build a call to _aaInX(). */
+ this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3,
+ build_expr (e->e2),
+ build_typeinfo (tkey),
+ build_address (key));
+ }
+
+ /* Build a relational expression. The result type is bool. */
+
+ void visit (CmpExp *e)
+ {
+ Type *tb1 = e->e1->type->toBasetype ();
+ Type *tb2 = e->e2->type->toBasetype ();
+
+ tree result;
+ tree_code code;
+
+ switch (e->op)
+ {
+ case TOKle:
+ code = LE_EXPR;
+ break;
+
+ case TOKlt:
+ code = LT_EXPR;
+ break;
+
+ case TOKge:
+ code = GE_EXPR;
+ break;
+
+ case TOKgt:
+ code = GT_EXPR;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if ((tb1->ty == Tsarray || tb1->ty == Tarray)
+ && (tb2->ty == Tsarray || tb2->ty == Tarray))
+ {
+ /* For static and dynamic arrays, the result of the relational op is
+ the result of the operator applied to the first non-equal element
+ of the array. If two arrays compare equal, but are of different
+ lengths, the shorter array compares as less than the longer. */
+ Type *telem = tb1->nextOf ()->toBasetype ();
+
+ tree call = build_libcall (LIBCALL_ADCMP2, Type::tint32, 3,
+ d_array_convert (e->e1),
+ d_array_convert (e->e2),
+ build_typeinfo (telem->arrayOf ()));
+ result = build_boolop (code, call, integer_zero_node);
+
+ this->result_ = d_convert (build_ctype (e->type), result);
+ return;
+ }
+
+ /* Simple comparison. */
+ result = build_boolop (code, build_expr (e->e1), build_expr (e->e2));
+ this->result_ = d_convert (build_ctype (e->type), result);
+ }
+
+ /* Build an `and if' expression. If the right operand expression is void,
+ then the resulting type is void. Otherwise the result is bool. */
+
+ void visit (AndAndExp *e)
+ {
+ if (e->e2->type->toBasetype ()->ty != Tvoid)
+ {
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+
+ t1 = convert_for_condition (t1, e->e1->type);
+ t2 = convert_for_condition (t2, e->e2->type);
+
+ this->result_ = d_convert (build_ctype (e->type),
+ build_boolop (TRUTH_ANDIF_EXPR, t1, t2));
+ }
+ else
+ {
+ tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
+ tree t2 = build_expr_dtor (e->e2);
+
+ this->result_ = build_condition (build_ctype (e->type),
+ t1, t2, void_node);
+ }
+ }
+
+ /* Build an `or if' expression. If the right operand expression is void,
+ then the resulting type is void. Otherwise the result is bool. */
+
+ void visit (OrOrExp *e)
+ {
+ if (e->e2->type->toBasetype ()->ty != Tvoid)
+ {
+ tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
+ tree t2 = convert_for_condition (build_expr (e->e2), e->e2->type);
+
+ this->result_ = d_convert (build_ctype (e->type),
+ build_boolop (TRUTH_ORIF_EXPR, t1, t2));
+ }
+ else
+ {
+ tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
+ tree t2 = build_expr_dtor (e->e2);
+ tree cond = build1 (TRUTH_NOT_EXPR, d_bool_type, t1);
+
+ this->result_ = build_condition (build_ctype (e->type),
+ cond, t2, void_node);
+ }
+ }
+
+ /* Build a binary operand expression. Operands go through usual arithmetic
+ conversions to bring them to a common type before evaluating. */
+
+ void visit (BinExp *e)
+ {
+ tree_code code;
+
+ switch (e->op)
+ {
+ case TOKadd:
+ case TOKmin:
+ if ((e->e1->type->isreal () && e->e2->type->isimaginary ())
+ || (e->e1->type->isimaginary () && e->e2->type->isreal ()))
+ {
+ /* If the result is complex, then we can shortcut binary_op.
+ Frontend should have already validated types and sizes. */
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+
+ if (e->op == TOKmin)
+ t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2);
+
+ if (e->e1->type->isreal ())
+ this->result_ = complex_expr (build_ctype (e->type), t1, t2);
+ else
+ this->result_ = complex_expr (build_ctype (e->type), t2, t1);
+
+ return;
+ }
+ else
+ code = (e->op == TOKadd)
+ ? PLUS_EXPR : MINUS_EXPR;
+ break;
+
+ case TOKmul:
+ code = MULT_EXPR;
+ break;
+
+ case TOKdiv:
+ code = e->e1->type->isintegral ()
+ ? TRUNC_DIV_EXPR : RDIV_EXPR;
+ break;
+
+ case TOKmod:
+ code = e->e1->type->isfloating ()
+ ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
+ break;
+
+ case TOKand:
+ code = BIT_AND_EXPR;
+ break;
+
+ case TOKor:
+ code = BIT_IOR_EXPR;
+ break;
+
+ case TOKxor:
+ code = BIT_XOR_EXPR;
+ break;
+
+ case TOKshl:
+ code = LSHIFT_EXPR;
+ break;
+
+ case TOKshr:
+ code = RSHIFT_EXPR;
+ break;
+
+ case TOKushr:
+ code = UNSIGNED_RSHIFT_EXPR;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ this->result_ = this->binary_op (code, build_ctype (e->type),
+ build_expr (e->e1), build_expr (e->e2));
+ }
+
+
+ /* Build a concat expression, which concatenates two or more arrays of the
+ same type, producing a dynamic array with the result. If one operand
+ is an element type, that element is converted to an array of length 1. */
+
+ void visit (CatExp *e)
+ {
+ Type *tb1 = e->e1->type->toBasetype ();
+ Type *tb2 = e->e2->type->toBasetype ();
+ Type *etype;
+
+ if (tb1->ty == Tarray || tb1->ty == Tsarray)
+ etype = tb1->nextOf ();
+ else
+ etype = tb2->nextOf ();
+
+ vec<tree, va_gc> *elemvars = NULL;
+ tree result;
+
+ if (e->e1->op == TOKcat)
+ {
+ /* Flatten multiple concatenations to an array.
+ So the expression ((a ~ b) ~ c) becomes [a, b, c] */
+ int ndims = 2;
+
+ for (Expression *ex = e->e1; ex->op == TOKcat;)
+ {
+ if (ex->op == TOKcat)
+ {
+ ex = ((CatExp *) ex)->e1;
+ ndims++;
+ }
+ }
+
+ /* Store all concatenation args to a temporary byte[][ndims] array. */
+ Type *targselem = Type::tint8->arrayOf ();
+ tree var = create_temporary_var (make_array_type (targselem, ndims));
+ tree init = build_constructor (TREE_TYPE (var), NULL);
+ vec_safe_push (elemvars, var);
+
+ /* Loop through each concatenation from right to left. */
+ vec<constructor_elt, va_gc> *elms = NULL;
+ CatExp *ce = e;
+ int dim = ndims - 1;
+
+ for (Expression *oe = ce->e2; oe != NULL;
+ (ce->e1->op != TOKcat
+ ? (oe = ce->e1)
+ : (ce = (CatExp *)ce->e1, oe = ce->e2)))
+ {
+ tree arg = d_array_convert (etype, oe, &elemvars);
+ tree index = size_int (dim);
+ CONSTRUCTOR_APPEND_ELT (elms, index, d_save_expr (arg));
+
+ /* Finished pushing all arrays. */
+ if (oe == ce->e1)
+ break;
+
+ dim -= 1;
+ }
+
+ /* Check there is no logic bug in constructing byte[][] of arrays. */
+ gcc_assert (dim == 0);
+ CONSTRUCTOR_ELTS (init) = elms;
+ DECL_INITIAL (var) = init;
+
+ tree arrs = d_array_value (build_ctype (targselem->arrayOf ()),
+ size_int (ndims), build_address (var));
+
+ result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2,
+ build_typeinfo (e->type), arrs);
+ }
+ else
+ {
+ /* Handle single concatenation (a ~ b). */
+ result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3,
+ build_typeinfo (e->type),
+ d_array_convert (etype, e->e1, &elemvars),
+ d_array_convert (etype, e->e2, &elemvars));
+ }
+
+ for (size_t i = 0; i < vec_safe_length (elemvars); ++i)
+ result = bind_expr ((*elemvars)[i], result);
+
+ this->result_ = result;
+ }
+
+ /* Build an assignment operator expression. The right operand is implicitly
+ converted to the type of the left operand, and assigned to it. */
+
+ void visit (BinAssignExp *e)
+ {
+ tree_code code;
+ Expression *e1b = e->e1;
+
+ switch (e->op)
+ {
+ case TOKaddass:
+ code = PLUS_EXPR;
+ break;
+
+ case TOKminass:
+ code = MINUS_EXPR;
+ break;
+
+ case TOKmulass:
+ code = MULT_EXPR;
+ break;
+
+ case TOKdivass:
+ code = e->e1->type->isintegral ()
+ ? TRUNC_DIV_EXPR : RDIV_EXPR;
+ break;
+
+ case TOKmodass:
+ code = e->e1->type->isfloating ()
+ ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
+ break;
+
+ case TOKandass:
+ code = BIT_AND_EXPR;
+ break;
+
+ case TOKorass:
+ code = BIT_IOR_EXPR;
+ break;
+
+ case TOKxorass:
+ code = BIT_XOR_EXPR;
+ break;
+
+ case TOKpowass:
+ gcc_unreachable ();
+
+ case TOKshlass:
+ code = LSHIFT_EXPR;
+ break;
+
+ case TOKshrass:
+ case TOKushrass:
+ /* Use the original lhs type before it was promoted. The left operand
+ of `>>>=' does not undergo integral promotions before shifting.
+ Strip off casts just incase anyway. */
+ while (e1b->op == TOKcast)
+ {
+ CastExp *ce = (CastExp *) e1b;
+ gcc_assert (same_type_p (ce->type, ce->to));
+ e1b = ce->e1;
+ }
+ code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ tree exp = this->binop_assignment (code, e1b, e->e2);
+ this->result_ = convert_expr (exp, e1b->type, e->type);
+ }
+
+ /* Build a concat assignment expression. The right operand is appended
+ to the the left operand. */
+
+ void visit (CatAssignExp *e)
+ {
+ Type *tb1 = e->e1->type->toBasetype ();
+ Type *tb2 = e->e2->type->toBasetype ();
+ Type *etype = tb1->nextOf ()->toBasetype ();
+
+ if (tb1->ty == Tarray && tb2->ty == Tdchar
+ && (etype->ty == Tchar || etype->ty == Twchar))
+ {
+ /* Append a dchar to a char[] or wchar[] */
+ libcall_fn libcall = (etype->ty == Tchar)
+ ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD;
+
+ this->result_ = build_libcall (libcall, e->type, 2,
+ build_address (build_expr (e->e1)),
+ build_expr (e->e2));
+ }
+ else
+ {
+ gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray);
+
+ tree tinfo = build_typeinfo (e->type);
+ tree ptr = build_address (build_expr (e->e1));
+
+ if ((tb2->ty == Tarray || tb2->ty == Tsarray)
+ && same_type_p (etype, tb2->nextOf ()->toBasetype ()))
+ {
+ /* Append an array. */
+ this->result_ = build_libcall (LIBCALL_ARRAYAPPENDT, e->type, 3,
+ tinfo, ptr, d_array_convert (e->e2));
+
+ }
+ else if (same_type_p (etype, tb2))
+ {
+ /* Append an element. */
+ tree result = build_libcall (LIBCALL_ARRAYAPPENDCTX, e->type, 3,
+ tinfo, ptr, size_one_node);
+ result = d_save_expr (result);
+
+ /* Assign e2 to last element. */
+ tree offexp = d_array_length (result);
+ offexp = build2 (MINUS_EXPR, TREE_TYPE (offexp),
+ offexp, size_one_node);
+ offexp = d_save_expr (offexp);
+
+ tree ptrexp = d_array_ptr (result);
+ ptrexp = void_okay_p (ptrexp);
+ ptrexp = build_array_index (ptrexp, offexp);
+
+ /* Evaluate expression before appending. */
+ tree t2 = build_expr (e->e2);
+ tree expr = stabilize_expr (&t2);
+
+ t2 = d_save_expr (t2);
+ result = modify_expr (build_deref (ptrexp), t2);
+ result = compound_expr (t2, result);
+
+ this->result_ = compound_expr (expr, result);
+ }
+ else
+ gcc_unreachable ();
+ }
+ }
+
+ /* Build an assignment expression. The right operand is implicitly
+ converted to the type of the left operand, and assigned to it. */
+
+ void visit (AssignExp *e)
+ {
+ /* First, handle special assignment semantics. */
+
+ /* Look for array.length = n; */
+ if (e->e1->op == TOKarraylength)
+ {
+ /* Assignment to an array's length property; resize the array. */
+ ArrayLengthExp *ale = (ArrayLengthExp *) e->e1;
+ tree newlength = convert_expr (build_expr (e->e2), e->e2->type,
+ Type::tsize_t);
+ tree ptr = build_address (build_expr (ale->e1));
+
+ /* Don't want the basetype for the element type. */
+ Type *etype = ale->e1->type->toBasetype ()->nextOf ();
+ libcall_fn libcall = etype->isZeroInit ()
+ ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT;
+
+ tree result = build_libcall (libcall, ale->e1->type, 3,
+ build_typeinfo (ale->e1->type),
+ newlength, ptr);
+
+ this->result_ = d_array_length (result);
+ return;
+ }
+
+ /* Look for array[] = n; */
+ if (e->e1->op == TOKslice)
+ {
+ SliceExp *se = (SliceExp *) e->e1;
+ Type *stype = se->e1->type->toBasetype ();
+ Type *etype = stype->nextOf ()->toBasetype ();
+
+ /* Determine if we need to run postblit or dtor. */
+ bool postblit = this->needs_postblit (etype) && this->lvalue_p (e->e2);
+ bool destructor = this->needs_dtor (etype);
+
+ if (e->memset & blockAssign)
+ {
+ /* Set a range of elements to one value. */
+ tree t1 = d_save_expr (build_expr (e->e1));
+ tree t2 = build_expr (e->e2);
+ tree result;
+
+ if ((postblit || destructor) && e->op != TOKblit)
+ {
+ libcall_fn libcall = (e->op == TOKconstruct)
+ ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN;
+ /* So we can call postblits on const/immutable objects. */
+ tree ti = build_typeinfo (etype->unSharedOf ()->mutableOf ());
+
+ tree result = build_libcall (libcall, Type::tvoid, 4,
+ d_array_ptr (t1),
+ build_address (t2),
+ d_array_length (t1), ti);
+ this->result_ = compound_expr (result, t1);
+ return;
+ }
+
+ if (integer_zerop (t2))
+ {
+ tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
+ tree size = size_mult_expr (d_array_length (t1),
+ size_int (etype->size ()));
+
+ result = build_call_expr (tmemset, 3, d_array_ptr (t1),
+ integer_zero_node, size);
+ }
+ else
+ result = build_array_set (d_array_ptr (t1),
+ d_array_length (t1), t2);
+
+ this->result_ = compound_expr (result, t1);
+ }
+ else
+ {
+ /* Perform a memcpy operation. */
+ gcc_assert (e->e2->type->ty != Tpointer);
+
+ if (!postblit && !destructor && !array_bounds_check ())
+ {
+ tree t1 = d_save_expr (d_array_convert (e->e1));
+ tree t2 = d_array_convert (e->e2);
+ tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY);
+ tree size = size_mult_expr (d_array_length (t1),
+ size_int (etype->size ()));
+
+ tree result = build_call_expr (tmemcpy, 3, d_array_ptr (t1),
+ d_array_ptr (t2), size);
+ this->result_ = compound_expr (result, t1);
+ }
+ else if ((postblit || destructor) && e->op != TOKblit)
+ {
+ /* Generate: _d_arrayassign(ti, from, to)
+ or: _d_arrayctor(ti, from, to) */
+ libcall_fn libcall = (e->op == TOKconstruct)
+ ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN;
+
+ this->result_ = build_libcall (libcall, e->type, 3,
+ build_typeinfo (etype),
+ d_array_convert (e->e2),
+ d_array_convert (e->e1));
+ }
+ else
+ {
+ /* Generate: _d_arraycopy() */
+ this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3,
+ size_int (etype->size ()),
+ d_array_convert (e->e2),
+ d_array_convert (e->e1));
+ }
+ }
+
+ return;
+ }
+
+ /* Look for reference initializations. */
+ if (e->memset & referenceInit)
+ {
+ gcc_assert (e->op == TOKconstruct || e->op == TOKblit);
+ gcc_assert (e->e1->op == TOKvar);
+
+ Declaration *decl = ((VarExp *) e->e1)->var;
+ if (decl->storage_class & (STCout | STCref))
+ {
+ tree t2 = convert_for_assignment (build_expr (e->e2),
+ e->e2->type, e->e1->type);
+ tree t1 = build_expr (e->e1);
+ /* Want reference to lhs, not indirect ref. */
+ t1 = TREE_OPERAND (t1, 0);
+ t2 = build_address (t2);
+
+ this->result_ = indirect_ref (build_ctype (e->type),
+ build_assign (INIT_EXPR, t1, t2));
+ return;
+ }
+ }
+
+ /* Other types of assignments that may require post construction. */
+ Type *tb1 = e->e1->type->toBasetype ();
+ tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR;
+
+ /* Look for struct assignment. */
+ if (tb1->ty == Tstruct)
+ {
+ tree t1 = build_expr (e->e1);
+ tree t2 = convert_for_assignment (build_expr (e->e2),
+ e->e2->type, e->e1->type);
+
+ /* Look for struct = 0. */
+ if (e->e2->op == TOKint64)
+ {
+ /* Use memset to fill struct. */
+ gcc_assert (e->op == TOKblit);
+ StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
+
+ tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
+ tree result = build_call_expr (tmemset, 3, build_address (t1),
+ t2, size_int (sd->structsize));
+
+ /* Maybe set-up hidden pointer to outer scope context. */
+ if (sd->isNested ())
+ {
+ tree field = get_symbol_decl (sd->vthis);
+ tree value = build_vthis (sd);
+
+ tree vthis_exp = modify_expr (component_ref (t1, field), value);
+ result = compound_expr (result, vthis_exp);
+ }
+
+ this->result_ = compound_expr (result, t1);
+ }
+ else
+ this->result_ = build_assign (modifycode, t1, t2);
+
+ return;
+ }
+
+ /* Look for static array assignment. */
+ if (tb1->ty == Tsarray)
+ {
+ /* Look for array = 0. */
+ if (e->e2->op == TOKint64)
+ {
+ /* Use memset to fill the array. */
+ gcc_assert (e->op == TOKblit);
+
+ tree t1 = build_expr (e->e1);
+ tree t2 = convert_for_assignment (build_expr (e->e2),
+ e->e2->type, e->e1->type);
+ tree size = size_int (e->e1->type->size ());
+
+ tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
+ this->result_ = build_call_expr (tmemset, 3, build_address (t1),
+ t2, size);
+ return;
+ }
+
+ Type *etype = tb1->nextOf ();
+ gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray);
+
+ /* Determine if we need to run postblit. */
+ bool postblit = this->needs_postblit (etype);
+ bool destructor = this->needs_dtor (etype);
+ bool lvalue_p = this->lvalue_p (e->e2);
+
+ /* Even if the elements in rhs are all rvalues and don't have
+ to call postblits, this assignment should call dtors on old
+ assigned elements. */
+ if ((!postblit && !destructor)
+ || (e->op == TOKconstruct && !lvalue_p && postblit)
+ || (e->op == TOKblit || e->e1->type->size () == 0))
+ {
+ tree t1 = build_expr (e->e1);
+ tree t2 = convert_for_assignment (build_expr (e->e2),
+ e->e2->type, e->e1->type);
+
+ this->result_ = build_assign (modifycode, t1, t2);
+ return;
+ }
+
+ Type *arrtype = (e->type->ty == Tsarray) ? etype->arrayOf () : e->type;
+ tree result;
+
+ if (e->op == TOKconstruct)
+ {
+ /* Generate: _d_arrayctor(ti, from, to) */
+ result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3,
+ build_typeinfo (etype),
+ d_array_convert (e->e2),
+ d_array_convert (e->e1));
+ }
+ else
+ {
+ /* Generate: _d_arrayassign_l()
+ or: _d_arrayassign_r() */
+ libcall_fn libcall = (lvalue_p)
+ ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
+ tree elembuf = build_local_temp (build_ctype (etype));
+
+ result = build_libcall (libcall, arrtype, 4,
+ build_typeinfo (etype),
+ d_array_convert (e->e2),
+ d_array_convert (e->e1),
+ build_address (elembuf));
+ }
+
+ /* Cast the libcall result back to a static array. */
+ if (e->type->ty == Tsarray)
+ result = indirect_ref (build_ctype (e->type),
+ d_array_ptr (result));
+
+ this->result_ = result;
+ return;
+ }
+
+ /* Simple assignment. */
+ tree t1 = build_expr (e->e1);
+ tree t2 = convert_for_assignment (build_expr (e->e2),
+ e->e2->type, e->e1->type);
+
+ this->result_ = build_assign (modifycode, t1, t2);
+ }
+
+ /* Build a postfix expression. */
+
+ void visit (PostExp *e)
+ {
+ tree result;
+
+ if (e->op == TOKplusplus)
+ {
+ result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type),
+ build_expr (e->e1), build_expr (e->e2));
+ }
+ else if (e->op == TOKminusminus)
+ {
+ result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type),
+ build_expr (e->e1), build_expr (e->e2));
+ }
+ else
+ gcc_unreachable ();
+
+ TREE_SIDE_EFFECTS (result) = 1;
+ this->result_ = result;
+ }
+
+ /* Build an index expression. */
+
+ void visit (IndexExp *e)
+ {
+ Type *tb1 = e->e1->type->toBasetype ();
+
+ if (tb1->ty == Taarray)
+ {
+ /* Get the key for the associative array. */
+ Type *tkey = ((TypeAArray *) tb1)->index->toBasetype ();
+ tree key = convert_expr (build_expr (e->e2), e->e2->type, tkey);
+ libcall_fn libcall;
+ tree tinfo, ptr;
+
+ if (e->modifiable)
+ {
+ libcall = LIBCALL_AAGETY;
+ ptr = build_address (build_expr (e->e1));
+ tinfo = build_typeinfo (tb1->unSharedOf ()->mutableOf ());
+ }
+ else
+ {
+ libcall = LIBCALL_AAGETRVALUEX;
+ ptr = build_expr (e->e1);
+ tinfo = build_typeinfo (tkey);
+ }
+
+ /* Index the associative array. */
+ tree result = build_libcall (libcall, e->type->pointerTo (), 4,
+ ptr, tinfo,
+ size_int (tb1->nextOf ()->size ()),
+ build_address (key));
+
+ if (!e->indexIsInBounds && array_bounds_check ())
+ {
+ tree tassert = d_assert_call (e->loc, LIBCALL_ARRAY_BOUNDS);
+ result = d_save_expr (result);
+ result = build_condition (TREE_TYPE (result),
+ d_truthvalue_conversion (result),
+ result, tassert);
+ }
+
+ this->result_ = indirect_ref (build_ctype (e->type), result);
+ }
+ else
+ {
+ /* Get the data pointer and length for static and dynamic arrays. */
+ tree array = d_save_expr (build_expr (e->e1));
+ tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
+
+ tree length = NULL_TREE;
+ if (tb1->ty != Tpointer)
+ length = get_array_length (array, tb1);
+ else
+ gcc_assert (e->lengthVar == NULL);
+
+ /* The __dollar variable just becomes a placeholder for the
+ actual length. */
+ if (e->lengthVar)
+ e->lengthVar->csym = length;
+
+ /* Generate the index. */
+ tree index = build_expr (e->e2);
+
+ /* If it's a static array and the index is constant, the front end has
+ already checked the bounds. */
+ if (tb1->ty != Tpointer && !e->indexIsInBounds)
+ index = build_bounds_condition (e->e2->loc, index, length, false);
+
+ /* Index the .ptr. */
+ ptr = void_okay_p (ptr);
+ this->result_ = indirect_ref (TREE_TYPE (TREE_TYPE (ptr)),
+ build_array_index (ptr, index));
+ }
+ }
+
+ /* Build a comma expression. The type is the type of the right operand. */
+
+ void visit (CommaExp *e)
+ {
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+ tree type = e->type ? build_ctype (e->type) : void_type_node;
+
+ this->result_ = build2 (COMPOUND_EXPR, type, t1, t2);
+ }
+
+ /* Build an array length expression. Returns the number of elements
+ in the array. The result is of type size_t. */
+
+ void visit (ArrayLengthExp *e)
+ {
+ if (e->e1->type->toBasetype ()->ty == Tarray)
+ this->result_ = d_array_length (build_expr (e->e1));
+ else
+ {
+ /* Static arrays have already been handled by the front-end. */
+ error ("unexpected type for array length: %qs", e->type->toChars ());
+ this->result_ = error_mark_node;
+ }
+ }
+
+ /* Build a delegate pointer expression. This will return the frame
+ pointer value as a type void*. */
+
+ void visit (DelegatePtrExp *e)
+ {
+ tree t1 = build_expr (e->e1);
+ this->result_ = delegate_object (t1);
+ }
+
+ /* Build a delegate function pointer expression. This will return the
+ function pointer value as a function type. */
+
+ void visit (DelegateFuncptrExp *e)
+ {
+ tree t1 = build_expr (e->e1);
+ this->result_ = delegate_method (t1);
+ }
+
+ /* Build a slice expression. */
+
+ void visit (SliceExp *e)
+ {
+ Type *tb = e->type->toBasetype ();
+ Type *tb1 = e->e1->type->toBasetype ();
+ gcc_assert (tb->ty == Tarray || tb->ty == Tsarray);
+
+ /* Use convert-to-dynamic-array code if possible. */
+ if (!e->lwr)
+ {
+ tree result = build_expr (e->e1);
+ if (e->e1->type->toBasetype ()->ty == Tsarray)
+ result = convert_expr (result, e->e1->type, e->type);
+
+ this->result_ = result;
+ return;
+ }
+ else
+ gcc_assert (e->upr != NULL);
+
+ /* Get the data pointer and length for static and dynamic arrays. */
+ tree array = d_save_expr (build_expr (e->e1));
+ tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
+ tree length = NULL_TREE;
+
+ /* Our array is already a SAVE_EXPR if necessary, so we don't make length
+ a SAVE_EXPR which is, at most, a COMPONENT_REF on top of array. */
+ if (tb1->ty != Tpointer)
+ length = get_array_length (array, tb1);
+ else
+ gcc_assert (e->lengthVar == NULL);
+
+ /* The __dollar variable just becomes a placeholder for the
+ actual length. */
+ if (e->lengthVar)
+ e->lengthVar->csym = length;
+
+ /* Generate upper and lower bounds. */
+ tree lwr_tree = d_save_expr (build_expr (e->lwr));
+ tree upr_tree = d_save_expr (build_expr (e->upr));
+
+ /* If the upper bound has any side effects, then the lower bound should be
+ copied to a temporary always. */
+ if (TREE_CODE (upr_tree) == SAVE_EXPR && TREE_CODE (lwr_tree) != SAVE_EXPR)
+ lwr_tree = save_expr (lwr_tree);
+
+ /* Adjust the .ptr offset. */
+ if (!integer_zerop (lwr_tree))
+ {
+ tree ptrtype = TREE_TYPE (ptr);
+ ptr = build_array_index (void_okay_p (ptr), lwr_tree);
+ ptr = build_nop (ptrtype, ptr);
+ }
+ else
+ lwr_tree = NULL_TREE;
+
+ /* Nothing more to do for static arrays, their bounds checking has been
+ done at compile-time. */
+ if (tb->ty == Tsarray)
+ {
+ this->result_ = indirect_ref (build_ctype (e->type), ptr);
+ return;
+ }
+ else
+ gcc_assert (tb->ty == Tarray);
+
+ /* Generate bounds checking code. */
+ tree newlength;
+
+ if (!e->upperIsInBounds)
+ {
+ if (length)
+ {
+ newlength = build_bounds_condition (e->upr->loc, upr_tree,
+ length, true);
+ }
+ else
+ {
+ /* Still need to check bounds lwr <= upr for pointers. */
+ gcc_assert (tb1->ty == Tpointer);
+ newlength = upr_tree;
+ }
+ }
+ else
+ newlength = upr_tree;
+
+ if (lwr_tree)
+ {
+ /* Enforces lwr <= upr. No need to check lwr <= length as
+ we've already ensured that upr <= length. */
+ if (!e->lowerIsLessThanUpper)
+ {
+ tree cond = build_bounds_condition (e->lwr->loc, lwr_tree,
+ upr_tree, true);
+
+ /* When bounds checking is off, the index value is
+ returned directly. */
+ if (cond != lwr_tree)
+ newlength = compound_expr (cond, newlength);
+ }
+
+ /* Need to ensure lwr always gets evaluated first, as it may be a
+ function call. Generates (lwr, upr) - lwr. */
+ newlength = fold_build2 (MINUS_EXPR, TREE_TYPE (newlength),
+ compound_expr (lwr_tree, newlength), lwr_tree);
+ }
+
+ tree result = d_array_value (build_ctype (e->type), newlength, ptr);
+ this->result_ = compound_expr (array, result);
+ }
+
+ /* Build a cast expression, which converts the given unary expression to the
+ type of result. */
+
+ void visit (CastExp *e)
+ {
+ Type *ebtype = e->e1->type->toBasetype ();
+ Type *tbtype = e->to->toBasetype ();
+ tree result = build_expr (e->e1, this->constp_);
+
+ /* Just evaluate e1 if it has any side effects. */
+ if (tbtype->ty == Tvoid)
+ this->result_ = build_nop (build_ctype (tbtype), result);
+ else
+ this->result_ = convert_expr (result, ebtype, tbtype);
+ }
+
+ /* Build a delete expression. */
+
+ void visit (DeleteExp *e)
+ {
+ tree t1 = build_expr (e->e1);
+ Type *tb1 = e->e1->type->toBasetype ();
+
+ if (tb1->ty == Tclass)
+ {
+ /* For class object references, if there is a destructor for that class,
+ the destructor is called for the object instance. */
+ libcall_fn libcall;
+
+ if (e->e1->op == TOKvar)
+ {
+ VarDeclaration *v = ((VarExp *) e->e1)->var->isVarDeclaration ();
+ if (v && v->onstack)
+ {
+ libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
+ ? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
+
+ this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
+ return;
+ }
+ }
+
+ /* Otherwise, the garbage collector is called to immediately free the
+ memory allocated for the class instance. */
+ libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
+ ? LIBCALL_DELINTERFACE : LIBCALL_DELCLASS;
+
+ t1 = build_address (t1);
+ this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
+ }
+ else if (tb1->ty == Tarray)
+ {
+ /* For dynamic arrays, the garbage collector is called to immediately
+ release the memory. */
+ Type *telem = tb1->nextOf ()->baseElemOf ();
+ tree ti = null_pointer_node;
+
+ if (telem->ty == Tstruct)
+ {
+ /* Might need to run destructor on array contents. */
+ TypeStruct *ts = (TypeStruct *) telem;
+ if (ts->sym->dtor)
+ ti = build_typeinfo (tb1->nextOf ());
+ }
+
+ /* Generate: _delarray_t (&t1, ti); */
+ this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2,
+ build_address (t1), ti);
+ }
+ else if (tb1->ty == Tpointer)
+ {
+ /* For pointers to a struct instance, if the struct has overloaded
+ operator delete, then that operator is called. */
+ t1 = build_address (t1);
+ Type *tnext = ((TypePointer *)tb1)->next->toBasetype ();
+
+ if (tnext->ty == Tstruct)
+ {
+ TypeStruct *ts = (TypeStruct *)tnext;
+ if (ts->sym->dtor)
+ {
+ this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid,
+ 2, t1, build_typeinfo (tnext));
+ return;
+ }
+ }
+
+ /* Otherwise, the garbage collector is called to immediately free the
+ memory allocated for the pointer. */
+ this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1);
+ }
+ else
+ {
+ error ("don't know how to delete %qs", e->e1->toChars ());
+ this->result_ = error_mark_node;
+ }
+ }
+
+ /* Build a remove expression, which removes a particular key from an
+ associative array. */
+
+ void visit (RemoveExp *e)
+ {
+ /* Check that the array is actually an associative array. */
+ if (e->e1->type->toBasetype ()->ty == Taarray)
+ {
+ Type *tb = e->e1->type->toBasetype ();
+ Type *tkey = ((TypeAArray *) tb)->index->toBasetype ();
+ tree index = convert_expr (build_expr (e->e2), e->e2->type, tkey);
+
+ this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3,
+ build_expr (e->e1),
+ build_typeinfo (tkey),
+ build_address (index));
+ }
+ else
+ {
+ error ("%qs is not an associative array", e->e1->toChars ());
+ this->result_ = error_mark_node;
+ }
+ }
+
+ /* Build an unary not expression. */
+
+ void visit (NotExp *e)
+ {
+ tree result = convert_for_condition (build_expr (e->e1), e->e1->type);
+ /* Need to convert to boolean type or this will fail. */
+ result = fold_build1 (TRUTH_NOT_EXPR, d_bool_type, result);
+
+ this->result_ = d_convert (build_ctype (e->type), result);
+ }
+
+ /* Build a compliment expression, where all the bits in the value are
+ complemented. Note: unlike in C, the usual integral promotions
+ are not performed prior to the complement operation. */
+
+ void visit (ComExp *e)
+ {
+ TY ty1 = e->e1->type->toBasetype ()->ty;
+ gcc_assert (ty1 != Tarray && ty1 != Tsarray);
+
+ this->result_ = fold_build1 (BIT_NOT_EXPR, build_ctype (e->type),
+ build_expr (e->e1));
+ }
+
+ /* Build an unary negation expression. */
+
+ void visit (NegExp *e)
+ {
+ TY ty1 = e->e1->type->toBasetype ()->ty;
+ gcc_assert (ty1 != Tarray && ty1 != Tsarray);
+
+ tree type = build_ctype (e->type);
+ tree expr = build_expr (e->e1);
+
+ /* If the operation needs excess precision. */
+ tree eptype = excess_precision_type (type);
+ if (eptype != NULL_TREE)
+ expr = d_convert (eptype, expr);
+ else
+ eptype = type;
+
+ tree ret = fold_build1 (NEGATE_EXPR, eptype, expr);
+ this->result_ = d_convert (type, ret);
+ }
+
+ /* Build a pointer index expression. */
+
+ void visit (PtrExp *e)
+ {
+ Type *tnext = NULL;
+ size_t offset;
+ tree result;
+
+ if (e->e1->op == TOKadd)
+ {
+ BinExp *be = (BinExp *) e->e1;
+ if (be->e1->op == TOKaddress
+ && be->e2->isConst () && be->e2->type->isintegral ())
+ {
+ Expression *ae = ((AddrExp *) be->e1)->e1;
+ tnext = ae->type->toBasetype ();
+ result = build_expr (ae);
+ offset = be->e2->toUInteger ();
+ }
+ }
+ else if (e->e1->op == TOKsymoff)
+ {
+ SymOffExp *se = (SymOffExp *) e->e1;
+ if (!declaration_reference_p (se->var))
+ {
+ tnext = se->var->type->toBasetype ();
+ result = get_decl_tree (se->var);
+ offset = se->offset;
+ }
+ }
+
+ /* Produce better code by converting *(#record + n) to
+ COMPONENT_REFERENCE. Otherwise, the variable will always be
+ allocated in memory because its address is taken. */
+ if (tnext && tnext->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *) tnext)->sym;
+
+ for (size_t i = 0; i < sd->fields.dim; i++)
+ {
+ VarDeclaration *field = sd->fields[i];
+
+ if (field->offset == offset
+ && same_type_p (field->type, e->type))
+ {
+ /* Catch errors, backend will ICE otherwise. */
+ if (error_operand_p (result))
+ this->result_ = result;
+ else
+ {
+ result = component_ref (result, get_symbol_decl (field));
+ this->result_ = result;
+ }
+ return;
+ }
+ else if (field->offset > offset)
+ break;
+ }
+ }
+
+ this->result_ = indirect_ref (build_ctype (e->type), build_expr (e->e1));
+ }
+
+ /* Build an unary address expression. */
+
+ void visit (AddrExp *e)
+ {
+ tree type = build_ctype (e->type);
+ tree exp;
+
+ /* The frontend optimizer can convert const symbol into a struct literal.
+ Taking the address of a struct literal is otherwise illegal. */
+ if (e->e1->op == TOKstructliteral)
+ {
+ StructLiteralExp *sle = ((StructLiteralExp *) e->e1)->origin;
+ gcc_assert (sle != NULL);
+
+ /* Build the reference symbol, the decl is built first as the
+ initializer may have recursive references. */
+ if (!sle->sym)
+ {
+ sle->sym = build_artificial_decl (build_ctype (sle->type),
+ NULL_TREE, "S");
+ DECL_INITIAL (sle->sym) = build_expr (sle, true);
+ d_pushdecl (sle->sym);
+ rest_of_decl_compilation (sle->sym, 1, 0);
+ }
+
+ exp = sle->sym;
+ }
+ else
+ exp = build_expr (e->e1, this->constp_);
+
+ TREE_CONSTANT (exp) = 0;
+ this->result_ = d_convert (type, build_address (exp));
+ }
+
+ /* Build a function call expression. */
+
+ void visit (CallExp *e)
+ {
+ Type *tb = e->e1->type->toBasetype ();
+ Expression *e1b = e->e1;
+
+ tree callee = NULL_TREE;
+ tree object = NULL_TREE;
+ tree cleanup = NULL_TREE;
+ TypeFunction *tf = NULL;
+
+ /* Calls to delegates can sometimes look like this. */
+ if (e1b->op == TOKcomma)
+ {
+ e1b = ((CommaExp *) e1b)->e2;
+ gcc_assert (e1b->op == TOKvar);
+
+ Declaration *var = ((VarExp *) e1b)->var;
+ gcc_assert (var->isFuncDeclaration () && !var->needThis ());
+ }
+
+ if (e1b->op == TOKdotvar && tb->ty != Tdelegate)
+ {
+ DotVarExp *dve = (DotVarExp *) e1b;
+
+ /* Don't modify the static initializer for struct literals. */
+ if (dve->e1->op == TOKstructliteral)
+ {
+ StructLiteralExp *sle = (StructLiteralExp *) dve->e1;
+ sle->useStaticInit = false;
+ }
+
+ FuncDeclaration *fd = dve->var->isFuncDeclaration ();
+ if (fd != NULL)
+ {
+ /* Get the correct callee from the DotVarExp object. */
+ tree fndecl = get_symbol_decl (fd);
+ AggregateDeclaration *ad = fd->isThis ();
+
+ /* Static method; ignore the object instance. */
+ if (!ad)
+ callee = build_address (fndecl);
+ else
+ {
+ tree thisexp = build_expr (dve->e1);
+
+ /* When constructing temporaries, if the constructor throws,
+ then the object is destructed even though it is not a fully
+ constructed object yet. And so this call will need to be
+ moved inside the TARGET_EXPR_INITIAL slot. */
+ if (fd->isCtorDeclaration ()
+ && TREE_CODE (thisexp) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (thisexp, 0)) == TARGET_EXPR
+ && TARGET_EXPR_CLEANUP (TREE_OPERAND (thisexp, 0)))
+ {
+ cleanup = TREE_OPERAND (thisexp, 0);
+ thisexp = TREE_OPERAND (thisexp, 1);
+ }
+
+ /* Want reference to 'this' object. */
+ if (!POINTER_TYPE_P (TREE_TYPE (thisexp)))
+ thisexp = build_address (thisexp);
+
+ /* Make the callee a virtual call. */
+ if (fd->isVirtual () && !fd->isFinalFunc () && !e->directcall)
+ {
+ tree fntype = build_pointer_type (TREE_TYPE (fndecl));
+ tree thistype = build_ctype (ad->handleType ());
+ thisexp = build_nop (thistype, d_save_expr (thisexp));
+ fndecl = build_vindex_ref (thisexp, fntype, fd->vtblIndex);
+ }
+ else
+ fndecl = build_address (fndecl);
+
+ callee = build_method_call (fndecl, thisexp, fd->type);
+ }
+ }
+ }
+
+ if (callee == NULL_TREE)
+ callee = build_expr (e1b);
+
+ if (METHOD_CALL_EXPR (callee))
+ {
+ /* This could be a delegate expression (TY == Tdelegate), but not
+ actually a delegate variable. */
+ if (e1b->op == TOKdotvar)
+ {
+ /* This gets the true function type, getting the function type
+ from e1->type can sometimes be incorrect, such as when calling
+ a 'ref' return function. */
+ tf = get_function_type (((DotVarExp *) e1b)->var->type);
+ }
+ else
+ tf = get_function_type (tb);
+
+ extract_from_method_call (callee, callee, object);
+ }
+ else if (tb->ty == Tdelegate)
+ {
+ /* Delegate call, extract .object and .funcptr from var. */
+ callee = d_save_expr (callee);
+ tf = get_function_type (tb);
+ object = delegate_object (callee);
+ callee = delegate_method (callee);
+ }
+ else if (e1b->op == TOKvar)
+ {
+ FuncDeclaration *fd = ((VarExp *) e1b)->var->isFuncDeclaration ();
+ gcc_assert (fd != NULL);
+ tf = get_function_type (fd->type);
+
+ if (fd->isNested ())
+ {
+ /* Maybe re-evaluate symbol storage treating 'fd' as public. */
+ if (call_by_alias_p (d_function_chain->function, fd))
+ TREE_PUBLIC (callee) = 1;
+
+ object = get_frame_for_symbol (fd);
+ }
+ else if (fd->needThis ())
+ {
+ error_at (make_location_t (e1b->loc),
+ "need %<this%> to access member %qs", fd->toChars ());
+ /* Continue compiling... */
+ object = null_pointer_node;
+ }
+ }
+ else
+ {
+ /* Normal direct function call. */
+ tf = get_function_type (tb);
+ }
+
+ gcc_assert (tf != NULL);
+
+ /* Now we have the type, callee and maybe object reference,
+ build the call expression. */
+ tree exp = d_build_call (tf, callee, object, e->arguments);
+
+ if (tf->isref)
+ exp = build_deref (exp);
+
+ /* Some library calls are defined to return a generic type.
+ this->type is the real type we want to return. */
+ if (e->type->isTypeBasic ())
+ exp = d_convert (build_ctype (e->type), exp);
+
+ /* If this call was found to be a constructor for a temporary with a
+ cleanup, then move the call inside the TARGET_EXPR. The original
+ initializer is turned into an assignment, to keep its side effect. */
+ if (cleanup != NULL_TREE)
+ {
+ tree init = TARGET_EXPR_INITIAL (cleanup);
+ tree slot = TARGET_EXPR_SLOT (cleanup);
+ d_mark_addressable (slot);
+ init = build_assign (INIT_EXPR, slot, init);
+
+ TARGET_EXPR_INITIAL (cleanup) = compound_expr (init, exp);
+ exp = cleanup;
+ }
+
+ this->result_ = exp;
+ }
+
+ /* Build a delegate expression. */
+
+ void visit (DelegateExp *e)
+ {
+ if (e->func->semanticRun == PASSsemantic3done)
+ {
+ /* Add the function as nested function if it belongs to this module.
+ ie: it is a member of this module, or it is a template instance. */
+ Dsymbol *owner = e->func->toParent ();
+ while (!owner->isTemplateInstance () && owner->toParent ())
+ owner = owner->toParent ();
+ if (owner->isTemplateInstance () || owner == d_function_chain->module)
+ build_decl_tree (e->func);
+ }
+
+ tree fndecl;
+ tree object;
+
+ if (e->func->isNested ())
+ {
+ if (e->e1->op == TOKnull)
+ object = build_expr (e->e1);
+ else
+ object = get_frame_for_symbol (e->func);
+
+ fndecl = build_address (get_symbol_decl (e->func));
+ }
+ else
+ {
+ if (!e->func->isThis ())
+ {
+ error ("delegates are only for non-static functions");
+ this->result_ = error_mark_node;
+ return;
+ }
+
+ object = build_expr (e->e1);
+
+ /* Want reference to `this' object. */
+ if (e->e1->type->ty != Tclass && e->e1->type->ty != Tpointer)
+ object = build_address (object);
+
+ /* Object reference could be the outer `this' field of a class or
+ closure of type `void*'. Cast it to the right type. */
+ if (e->e1->type->ty == Tclass)
+ object = d_convert (build_ctype (e->e1->type), object);
+
+ fndecl = get_symbol_decl (e->func);
+
+ /* Get pointer to function out of the virtual table. */
+ if (e->func->isVirtual () && !e->func->isFinalFunc ()
+ && e->e1->op != TOKsuper && e->e1->op != TOKdottype)
+ {
+ tree fntype = build_pointer_type (TREE_TYPE (fndecl));
+ object = d_save_expr (object);
+ fndecl = build_vindex_ref (object, fntype, e->func->vtblIndex);
+ }
+ else
+ fndecl = build_address (fndecl);
+ }
+
+ this->result_ = build_method_call (fndecl, object, e->type);
+ }
+
+ /* Build a type component expression. */
+
+ void visit (DotTypeExp *e)
+ {
+ /* Just a pass through to underlying expression. */
+ this->result_ = build_expr (e->e1);
+ }
+
+ /* Build a component reference expression. */
+
+ void visit (DotVarExp *e)
+ {
+ VarDeclaration *vd = e->var->isVarDeclaration ();
+
+ /* This could also be a function, but relying on that being taken
+ care of by the visitor interface for CallExp. */
+ if (vd != NULL)
+ {
+ if (!vd->isField ())
+ this->result_ = get_decl_tree (vd);
+ else
+ {
+ tree object = build_expr (e->e1);
+
+ if (e->e1->type->toBasetype ()->ty != Tstruct)
+ object = build_deref (object);
+
+ this->result_ = component_ref (object, get_symbol_decl (vd));
+ }
+ }
+ else
+ {
+ error ("%qs is not a field, but a %qs",
+ e->var->toChars (), e->var->kind ());
+ this->result_ = error_mark_node;
+ }
+ }
+
+ /* Build an assert expression, used to declare conditions that must hold at
+ that a given point in the program. */
+
+ void visit (AssertExp *e)
+ {
+ Type *tb1 = e->e1->type->toBasetype ();
+ tree arg = build_expr (e->e1);
+ tree tmsg = NULL_TREE;
+ tree assert_pass = void_node;
+ tree assert_fail;
+
+ if (global.params.useAssert)
+ {
+ /* Generate: ((bool) e1 ? (void)0 : _d_assert (...))
+ or: (e1 != null ? e1._invariant() : _d_assert (...)) */
+ bool unittest_p = d_function_chain->function->isUnitTestDeclaration ();
+ libcall_fn libcall;
+
+ if (e->msg)
+ {
+ tmsg = build_expr_dtor (e->msg);
+ libcall = unittest_p ? LIBCALL_UNITTEST_MSG : LIBCALL_ASSERT_MSG;
+ }
+ else
+ libcall = unittest_p ? LIBCALL_UNITTEST : LIBCALL_ASSERT;
+
+ /* Build a call to _d_assert(). */
+ assert_fail = d_assert_call (e->loc, libcall, tmsg);
+
+ if (global.params.useInvariants)
+ {
+ /* If the condition is a D class or struct object with an invariant,
+ call it if the condition result is true. */
+ if (tb1->ty == Tclass)
+ {
+ ClassDeclaration *cd = tb1->isClassHandle ();
+ if (!cd->isInterfaceDeclaration () && !cd->isCPPclass ())
+ {
+ arg = d_save_expr (arg);
+ assert_pass = build_libcall (LIBCALL_INVARIANT,
+ Type::tvoid, 1, arg);
+ }
+ }
+ else if (tb1->ty == Tpointer && tb1->nextOf ()->ty == Tstruct)
+ {
+ StructDeclaration *sd = ((TypeStruct *) tb1->nextOf ())->sym;
+ if (sd->inv != NULL)
+ {
+ Expressions args;
+ arg = d_save_expr (arg);
+ assert_pass = d_build_call_expr (sd->inv, arg, &args);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Assert contracts are turned off, if the contract condition has no
+ side effects can still use it as a predicate for the optimizer. */
+ if (TREE_SIDE_EFFECTS (arg))
+ {
+ this->result_ = void_node;
+ return;
+ }
+
+ assert_fail = build_predict_expr (PRED_NORETURN, NOT_TAKEN);
+ }
+
+ /* Build condition that we are asserting in this contract. */
+ tree condition = convert_for_condition (arg, e->e1->type);
+
+ /* We expect the condition to always be true, as what happens if an assert
+ contract is false is undefined behavior. */
+ tree fn = builtin_decl_explicit (BUILT_IN_EXPECT);
+ tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ tree pred_type = TREE_VALUE (arg_types);
+ tree expected_type = TREE_VALUE (TREE_CHAIN (arg_types));
+
+ condition = build_call_expr (fn, 2, d_convert (pred_type, condition),
+ build_int_cst (expected_type, 1));
+ condition = d_truthvalue_conversion (condition);
+
+ this->result_ = build_vcondition (condition, assert_pass, assert_fail);
+ }
+
+ /* Build a declaration expression. */
+
+ void visit (DeclarationExp *e)
+ {
+ /* Compile the declaration. */
+ push_stmt_list ();
+ build_decl_tree (e->declaration);
+ tree result = pop_stmt_list ();
+
+ /* Construction of an array for typesafe-variadic function arguments
+ can cause an empty STMT_LIST here. This can causes problems
+ during gimplification. */
+ if (TREE_CODE (result) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (result))
+ result = build_empty_stmt (input_location);
+
+ this->result_ = result;
+ }
+
+ /* Build a typeid expression. Returns an instance of class TypeInfo
+ corresponding to. */
+
+ void visit (TypeidExp *e)
+ {
+ if (Type *tid = isType (e->obj))
+ {
+ tree ti = build_typeinfo (tid);
+
+ /* If the typeinfo is at an offset. */
+ if (tid->vtinfo->offset)
+ ti = build_offset (ti, size_int (tid->vtinfo->offset));
+
+ this->result_ = build_nop (build_ctype (e->type), ti);
+ }
+ else if (Expression *tid = isExpression (e->obj))
+ {
+ Type *type = tid->type->toBasetype ();
+ assert (type->ty == Tclass);
+
+ /* Generate **classptr to get the classinfo. */
+ tree ci = build_expr (tid);
+ ci = indirect_ref (ptr_type_node, ci);
+ ci = indirect_ref (ptr_type_node, ci);
+
+ /* Add extra indirection for interfaces. */
+ if (((TypeClass *) type)->sym->isInterfaceDeclaration ())
+ ci = indirect_ref (ptr_type_node, ci);
+
+ this->result_ = build_nop (build_ctype (e->type), ci);
+ }
+ else
+ gcc_unreachable ();
+ }
+
+ /* Build a function/lambda expression. */
+
+ void visit (FuncExp *e)
+ {
+ Type *ftype = e->type->toBasetype ();
+
+ /* This check is for lambda's, remove 'vthis' as function isn't nested. */
+ if (e->fd->tok == TOKreserved && ftype->ty == Tpointer)
+ {
+ e->fd->tok = TOKfunction;
+ e->fd->vthis = NULL;
+ }
+
+ /* Compile the function literal body. */
+ build_decl_tree (e->fd);
+
+ /* If nested, this will be a trampoline. */
+ if (e->fd->isNested ())
+ {
+ tree func = build_address (get_symbol_decl (e->fd));
+ tree object;
+
+ if (this->constp_)
+ {
+ /* Static delegate variables have no context pointer. */
+ object = null_pointer_node;
+ this->result_ = build_method_call (func, object, e->fd->type);
+ TREE_CONSTANT (this->result_) = 1;
+ }
+ else
+ {
+ object = get_frame_for_symbol (e->fd);
+ this->result_ = build_method_call (func, object, e->fd->type);
+ }
+ }
+ else
+ {
+ this->result_ = build_nop (build_ctype (e->type),
+ build_address (get_symbol_decl (e->fd)));
+ }
+ }
+
+ /* Build a halt expression. */
+
+ void visit (HaltExp *)
+ {
+ /* Should we use trap() or abort()? */
+ tree ttrap = builtin_decl_explicit (BUILT_IN_TRAP);
+ this->result_ = build_call_expr (ttrap, 0);
+ }
+
+ /* Build a symbol pointer offset expression. */
+
+ void visit (SymOffExp *e)
+ {
+ /* Build the address and offset of the symbol. */
+ size_t soffset = ((SymOffExp *) e)->offset;
+ tree result = get_decl_tree (e->var);
+ TREE_USED (result) = 1;
+
+ if (declaration_reference_p (e->var))
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (result)));
+ else
+ result = build_address (result);
+
+ if (!soffset)
+ result = d_convert (build_ctype (e->type), result);
+ else
+ {
+ tree offset = size_int (soffset);
+ result = build_nop (build_ctype (e->type),
+ build_offset (result, offset));
+ }
+
+ this->result_ = result;
+ }
+
+ /* Build a variable expression. */
+
+ void visit (VarExp *e)
+ {
+ if (e->var->needThis ())
+ {
+ error ("need %<this%> to access member %qs", e->var->ident->toChars ());
+ this->result_ = error_mark_node;
+ return;
+ }
+ else if (e->var->ident == Identifier::idPool ("__ctfe"))
+ {
+ /* __ctfe is always false at run-time. */
+ this->result_ = integer_zero_node;
+ return;
+ }
+
+ /* This check is same as is done in FuncExp for lambdas. */
+ FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ();
+ if (fld != NULL)
+ {
+ if (fld->tok == TOKreserved)
+ {
+ fld->tok = TOKfunction;
+ fld->vthis = NULL;
+ }
+
+ /* Compiler the function literal body. */
+ build_decl_tree (fld);
+ }
+
+ if (this->constp_)
+ {
+ /* Want the initializer, not the expression. */
+ VarDeclaration *var = e->var->isVarDeclaration ();
+ SymbolDeclaration *sd = e->var->isSymbolDeclaration ();
+ tree init = NULL_TREE;
+
+ if (var && (var->isConst () || var->isImmutable ())
+ && e->type->toBasetype ()->ty != Tsarray && var->_init)
+ {
+ if (var->inuse)
+ error_at (make_location_t (e->loc), "recursive reference %qs",
+ e->toChars ());
+ else
+ {
+ var->inuse++;
+ init = build_expr (initializerToExpression (var->_init), true);
+ var->inuse--;
+ }
+ }
+ else if (sd && sd->dsym)
+ init = layout_struct_initializer (sd->dsym);
+ else
+ error_at (make_location_t (e->loc), "non-constant expression %qs",
+ e->toChars ());
+
+ if (init != NULL_TREE)
+ this->result_ = init;
+ else
+ this->result_ = error_mark_node;
+ }
+ else
+ {
+ tree result = get_decl_tree (e->var);
+ TREE_USED (result) = 1;
+
+ /* For variables that are references - currently only out/inout
+ arguments; objects don't count - evaluating the variable means
+ we want what it refers to. */
+ if (declaration_reference_p (e->var))
+ result = indirect_ref (build_ctype (e->var->type), result);
+
+ this->result_ = result;
+ }
+ }
+
+ /* Build a this variable expression. */
+
+ void visit (ThisExp *e)
+ {
+ FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL;
+ tree result = NULL_TREE;
+
+ if (e->var)
+ result = get_decl_tree (e->var);
+ else
+ {
+ gcc_assert (fd && fd->vthis);
+ result = get_decl_tree (fd->vthis);
+ }
+
+ if (e->type->ty == Tstruct)
+ result = build_deref (result);
+
+ this->result_ = result;
+ }
+
+ /* Build a new expression, which allocates memory either on the garbage
+ collected heap or by using a class or struct specific allocator. */
+
+ void visit (NewExp *e)
+ {
+ Type *tb = e->type->toBasetype ();
+ tree result;
+
+ if (e->allocator)
+ gcc_assert (e->newargs);
+
+ if (tb->ty == Tclass)
+ {
+ /* Allocating a new class. */
+ tb = e->newtype->toBasetype ();
+ gcc_assert (tb->ty == Tclass);
+
+ ClassDeclaration *cd = ((TypeClass *) tb)->sym;
+ tree type = build_ctype (tb);
+ tree setup_exp = NULL_TREE;
+ tree new_call;
+
+ if (e->onstack)
+ {
+ /* If being used as an initializer for a local variable with scope
+ storage class, then the instance is allocated on the stack
+ rather than the heap or using the class specific allocator. */
+ tree var = build_local_temp (TREE_TYPE (type));
+ new_call = build_nop (type, build_address (var));
+ setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
+ }
+ else if (e->allocator)
+ {
+ /* Call class allocator, and copy the initializer into memory. */
+ new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
+ new_call = d_save_expr (new_call);
+ new_call = build_nop (type, new_call);
+ setup_exp = modify_expr (build_deref (new_call),
+ aggregate_initializer_decl (cd));
+ }
+ else
+ {
+ /* Generate: _d_newclass() */
+ tree arg = build_address (get_classinfo_decl (cd));
+ new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg);
+ }
+
+ /* Set the context pointer for nested classes. */
+ if (cd->isNested ())
+ {
+ tree field = get_symbol_decl (cd->vthis);
+ tree value = NULL_TREE;
+
+ if (e->thisexp)
+ {
+ ClassDeclaration *tcd = e->thisexp->type->isClassHandle ();
+ Dsymbol *outer = cd->toParent2 ();
+ int offset = 0;
+
+ value = build_expr (e->thisexp);
+ if (outer != tcd)
+ {
+ ClassDeclaration *ocd = outer->isClassDeclaration ();
+ gcc_assert (ocd->isBaseOf (tcd, &offset));
+ /* Could just add offset... */
+ value = convert_expr (value, e->thisexp->type, ocd->type);
+ }
+ }
+ else
+ value = build_vthis (cd);
+
+ if (value != NULL_TREE)
+ {
+ /* Generate: (new())->vthis = this; */
+ new_call = d_save_expr (new_call);
+ field = component_ref (build_deref (new_call), field);
+ setup_exp = compound_expr (setup_exp,
+ modify_expr (field, value));
+ }
+ }
+ new_call = compound_expr (setup_exp, new_call);
+
+ /* Call the class constructor. */
+ if (e->member)
+ result = d_build_call_expr (e->member, new_call, e->arguments);
+ else
+ result = new_call;
+
+ if (e->argprefix)
+ result = compound_expr (build_expr (e->argprefix), result);
+ }
+ else if (tb->ty == Tpointer && tb->nextOf ()->toBasetype ()->ty == Tstruct)
+ {
+ /* Allocating memory for a new struct. */
+ Type *htype = e->newtype->toBasetype ();
+ gcc_assert (htype->ty == Tstruct);
+ gcc_assert (!e->onstack);
+
+ TypeStruct *stype = (TypeStruct *) htype;
+ StructDeclaration *sd = stype->sym;
+ tree new_call;
+
+ /* Cannot new an opaque struct. */
+ if (sd->size (e->loc) == 0)
+ {
+ this->result_ = d_convert (build_ctype (e->type),
+ integer_zero_node);
+ return;
+ }
+
+ if (e->allocator)
+ {
+ /* Call struct allocator. */
+ new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
+ new_call = build_nop (build_ctype (tb), new_call);
+ }
+ else
+ {
+ /* Generate: _d_newitemT() */
+ libcall_fn libcall = htype->isZeroInit ()
+ ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
+ tree arg = build_typeinfo (e->newtype);
+ new_call = build_libcall (libcall, tb, 1, arg);
+ }
+
+ if (e->member || !e->arguments)
+ {
+ /* Set the context pointer for nested structs. */
+ if (sd->isNested ())
+ {
+ tree value = build_vthis (sd);
+ tree field = get_symbol_decl (sd->vthis);
+ tree type = build_ctype (stype);
+
+ new_call = d_save_expr (new_call);
+ field = component_ref (indirect_ref (type, new_call), field);
+ new_call = compound_expr (modify_expr (field, value), new_call);
+ }
+
+ /* Call the struct constructor. */
+ if (e->member)
+ result = d_build_call_expr (e->member, new_call, e->arguments);
+ else
+ result = new_call;
+ }
+ else
+ {
+ /* If we have a user supplied initializer, then set-up with a
+ struct literal. */
+ if (e->arguments != NULL && sd->fields.dim != 0)
+ {
+ StructLiteralExp *se = StructLiteralExp::create (e->loc, sd,
+ e->arguments,
+ htype);
+ new_call = d_save_expr (new_call);
+ se->type = sd->type;
+ se->sym = new_call;
+ result = compound_expr (build_expr (se), new_call);
+ }
+ else
+ result = new_call;
+ }
+
+ if (e->argprefix)
+ result = compound_expr (build_expr (e->argprefix), result);
+ }
+ else if (tb->ty == Tarray)
+ {
+ /* Allocating memory for a new D array. */
+ tb = e->newtype->toBasetype ();
+ gcc_assert (tb->ty == Tarray);
+ TypeDArray *tarray = (TypeDArray *) tb;
+
+ gcc_assert (!e->allocator);
+ gcc_assert (e->arguments && e->arguments->dim >= 1);
+
+ if (e->arguments->dim == 1)
+ {
+ /* Single dimension array allocations. */
+ Expression *arg = (*e->arguments)[0];
+
+ if (tarray->next->size () == 0)
+ {
+ /* Array element size is unknown. */
+ this->result_ = d_array_value (build_ctype (e->type),
+ size_int (0), null_pointer_node);
+ return;
+ }
+
+ libcall_fn libcall = tarray->next->isZeroInit ()
+ ? LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT;
+ result = build_libcall (libcall, tb, 2,
+ build_typeinfo (e->type),
+ build_expr (arg));
+ }
+ else
+ {
+ /* Multidimensional array allocations. */
+ vec<constructor_elt, va_gc> *elms = NULL;
+ Type *telem = e->newtype->toBasetype ();
+ tree tarray = make_array_type (Type::tsize_t, e->arguments->dim);
+ tree var = create_temporary_var (tarray);
+ tree init = build_constructor (TREE_TYPE (var), NULL);
+
+ for (size_t i = 0; i < e->arguments->dim; i++)
+ {
+ Expression *arg = (*e->arguments)[i];
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg));
+
+ gcc_assert (telem->ty == Tarray);
+ telem = telem->toBasetype ()->nextOf ();
+ gcc_assert (telem);
+ }
+
+ CONSTRUCTOR_ELTS (init) = elms;
+ DECL_INITIAL (var) = init;
+
+ /* Generate: _d_newarraymTX(ti, dims)
+ or: _d_newarraymiTX(ti, dims) */
+ libcall_fn libcall = telem->isZeroInit ()
+ ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX;
+
+ tree tinfo = build_typeinfo (e->type);
+ tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()),
+ size_int (e->arguments->dim),
+ build_address (var));
+
+ result = build_libcall (libcall, tb, 2, tinfo, dims);
+ result = bind_expr (var, result);
+ }
+
+ if (e->argprefix)
+ result = compound_expr (build_expr (e->argprefix), result);
+ }
+ else if (tb->ty == Tpointer)
+ {
+ /* Allocating memory for a new pointer. */
+ TypePointer *tpointer = (TypePointer *) tb;
+
+ if (tpointer->next->size () == 0)
+ {
+ /* Pointer element size is unknown. */
+ this->result_ = d_convert (build_ctype (e->type),
+ integer_zero_node);
+ return;
+ }
+
+ libcall_fn libcall = tpointer->next->isZeroInit (e->loc)
+ ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
+
+ tree arg = build_typeinfo (e->newtype);
+ result = build_libcall (libcall, tb, 1, arg);
+
+ if (e->arguments && e->arguments->dim == 1)
+ {
+ result = d_save_expr (result);
+ tree init = modify_expr (build_deref (result),
+ build_expr ((*e->arguments)[0]));
+ result = compound_expr (init, result);
+ }
+
+ if (e->argprefix)
+ result = compound_expr (build_expr (e->argprefix), result);
+ }
+ else
+ gcc_unreachable ();
+
+ this->result_ = convert_expr (result, tb, e->type);
+ }
+
+ /* Build an integer literal. */
+
+ void visit (IntegerExp *e)
+ {
+ tree ctype = build_ctype (e->type->toBasetype ());
+ this->result_ = build_integer_cst (e->value, ctype);
+ }
+
+ /* Build a floating-point literal. */
+
+ void visit (RealExp *e)
+ {
+ this->result_ = build_float_cst (e->value, e->type->toBasetype ());
+ }
+
+ /* Build a complex literal. */
+
+ void visit (ComplexExp *e)
+ {
+ Type *tnext;
+
+ switch (e->type->toBasetype ()->ty)
+ {
+ case Tcomplex32:
+ tnext = (TypeBasic *) Type::tfloat32;
+ break;
+
+ case Tcomplex64:
+ tnext = (TypeBasic *) Type::tfloat64;
+ break;
+
+ case Tcomplex80:
+ tnext = (TypeBasic *) Type::tfloat80;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ this->result_ = build_complex (build_ctype (e->type),
+ build_float_cst (creall (e->value), tnext),
+ build_float_cst (cimagl (e->value), tnext));
+ }
+
+ /* Build a string literal, all strings are null terminated except for
+ static arrays. */
+
+ void visit (StringExp *e)
+ {
+ Type *tb = e->type->toBasetype ();
+ tree type = build_ctype (e->type);
+
+ if (tb->ty == Tsarray)
+ {
+ /* Turn the string into a constructor for the static array. */
+ vec<constructor_elt, va_gc> *elms = NULL;
+ vec_safe_reserve (elms, e->len);
+ tree etype = TREE_TYPE (type);
+
+ for (size_t i = 0; i < e->len; i++)
+ {
+ tree value = build_integer_cst (e->charAt (i), etype);
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+ }
+
+ tree ctor = build_constructor (type, elms);
+ TREE_CONSTANT (ctor) = 1;
+ this->result_ = ctor;
+ }
+ else
+ {
+ /* Copy the string contents to a null terminated string. */
+ dinteger_t length = (e->len * e->sz);
+ char *string = XALLOCAVEC (char, length + 1);
+ memcpy (string, e->string, length);
+ string[length] = '\0';
+
+ /* String value and type includes the null terminator. */
+ tree value = build_string (length, string);
+ TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1);
+ value = build_address (value);
+
+ if (tb->ty == Tarray)
+ value = d_array_value (type, size_int (e->len), value);
+
+ TREE_CONSTANT (value) = 1;
+ this->result_ = d_convert (type, value);
+ }
+ }
+
+ /* Build a tuple literal. Just an argument list that may have
+ side effects that need evaluation. */
+
+ void visit (TupleExp *e)
+ {
+ tree result = NULL_TREE;
+
+ if (e->e0)
+ result = build_expr (e->e0);
+
+ for (size_t i = 0; i < e->exps->dim; ++i)
+ {
+ Expression *exp = (*e->exps)[i];
+ result = compound_expr (result, build_expr (exp));
+ }
+
+ if (result == NULL_TREE)
+ result = void_node;
+
+ this->result_ = result;
+ }
+
+ /* Build an array literal. The common type of the all elements is taken to
+ be the type of the array element, and all elements are implicitly
+ converted to that type. */
+
+ void visit (ArrayLiteralExp *e)
+ {
+ Type *tb = e->type->toBasetype ();
+
+ /* Implicitly convert void[n] to ubyte[n]. */
+ if (tb->ty == Tsarray && tb->nextOf ()->toBasetype ()->ty == Tvoid)
+ tb = Type::tuns8->sarrayOf (((TypeSArray *) tb)->dim->toUInteger ());
+
+ gcc_assert (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tpointer);
+
+ /* Handle empty array literals. */
+ if (e->elements->dim == 0)
+ {
+ if (tb->ty == Tarray)
+ this->result_ = d_array_value (build_ctype (e->type),
+ size_int (0), null_pointer_node);
+ else
+ this->result_ = build_constructor (make_array_type (tb->nextOf (), 0),
+ NULL);
+
+ return;
+ }
+
+ /* Build an expression that assigns the expressions in ELEMENTS to
+ a constructor. */
+ vec<constructor_elt, va_gc> *elms = NULL;
+ vec_safe_reserve (elms, e->elements->dim);
+ bool constant_p = true;
+ tree saved_elems = NULL_TREE;
+
+ Type *etype = tb->nextOf ();
+ tree satype = make_array_type (etype, e->elements->dim);
+
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *expr = e->getElement (i);
+ tree value = build_expr (expr, this->constp_);
+
+ /* Only append nonzero values, the backend will zero out the rest
+ of the constructor as we don't set CONSTRUCTOR_NO_CLEARING. */
+ if (!initializer_zerop (value))
+ {
+ if (!TREE_CONSTANT (value))
+ constant_p = false;
+
+ /* Split construction of values out of the constructor if there
+ may be side effects. */
+ tree init = stabilize_expr (&value);
+ if (init != NULL_TREE)
+ saved_elems = compound_expr (saved_elems, init);
+
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+ convert_expr (value, expr->type, etype));
+ }
+ }
+
+ /* Now return the constructor as the correct type. For static arrays there
+ is nothing else to do. For dynamic arrays, return a two field struct.
+ For pointers, return the address. */
+ tree ctor = build_constructor (satype, elms);
+ tree type = build_ctype (e->type);
+
+ /* Nothing else to do for static arrays. */
+ if (tb->ty == Tsarray || this->constp_)
+ {
+ /* Can't take the address of the constructor, so create an anonymous
+ static symbol, and then refer to it. */
+ if (tb->ty != Tsarray)
+ {
+ tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor, "A");
+ ctor = build_address (decl);
+ if (tb->ty == Tarray)
+ ctor = d_array_value (type, size_int (e->elements->dim), ctor);
+
+ d_pushdecl (decl);
+ rest_of_decl_compilation (decl, 1, 0);
+ }
+
+ /* If the array literal is readonly or static. */
+ if (constant_p)
+ TREE_CONSTANT (ctor) = 1;
+ if (constant_p && initializer_constant_valid_p (ctor, TREE_TYPE (ctor)))
+ TREE_STATIC (ctor) = 1;
+
+ this->result_ = compound_expr (saved_elems, d_convert (type, ctor));
+ }
+ else
+ {
+ /* Allocate space on the memory managed heap. */
+ tree mem = build_libcall (LIBCALL_ARRAYLITERALTX,
+ etype->pointerTo (), 2,
+ build_typeinfo (etype->arrayOf ()),
+ size_int (e->elements->dim));
+ mem = d_save_expr (mem);
+
+ /* Now copy the constructor into memory. */
+ tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY);
+ tree size = size_mult_expr (size_int (e->elements->dim),
+ size_int (tb->nextOf ()->size ()));
+
+ tree result = build_call_expr (tmemcpy, 3, mem,
+ build_address (ctor), size);
+
+ /* Return the array pointed to by MEM. */
+ result = compound_expr (result, mem);
+
+ if (tb->ty == Tarray)
+ result = d_array_value (type, size_int (e->elements->dim), result);
+
+ this->result_ = compound_expr (saved_elems, result);
+ }
+ }
+
+ /* Build an associative array literal. The common type of the all keys is
+ taken to be the key type, and common type of all values the value type.
+ All keys and values are then implicitly converted as needed. */
+
+ void visit (AssocArrayLiteralExp *e)
+ {
+ /* Want the mutable type for typeinfo reference. */
+ Type *tb = e->type->toBasetype ()->mutableOf ();
+ gcc_assert (tb->ty == Taarray);
+
+ /* Handle empty assoc array literals. */
+ TypeAArray *ta = (TypeAArray *) tb;
+ if (e->keys->dim == 0)
+ {
+ this->result_ = build_constructor (build_ctype (ta), NULL);
+ return;
+ }
+
+ /* Build an expression that assigns all expressions in KEYS
+ to a constructor. */
+ vec<constructor_elt, va_gc> *kelts = NULL;
+ vec_safe_reserve (kelts, e->keys->dim);
+ for (size_t i = 0; i < e->keys->dim; i++)
+ {
+ Expression *key = (*e->keys)[i];
+ tree t = build_expr (key);
+ CONSTRUCTOR_APPEND_ELT (kelts, size_int (i),
+ convert_expr (t, key->type, ta->index));
+ }
+ tree tkeys = make_array_type (ta->index, e->keys->dim);
+ tree akeys = build_constructor (tkeys, kelts);
+
+ /* Do the same with all expressions in VALUES. */
+ vec<constructor_elt, va_gc> *velts = NULL;
+ vec_safe_reserve (velts, e->values->dim);
+ for (size_t i = 0; i < e->values->dim; i++)
+ {
+ Expression *value = (*e->values)[i];
+ tree t = build_expr (value);
+ CONSTRUCTOR_APPEND_ELT (velts, size_int (i),
+ convert_expr (t, value->type, ta->next));
+ }
+ tree tvals = make_array_type (ta->next, e->values->dim);
+ tree avals = build_constructor (tvals, velts);
+
+ /* Generate: _d_assocarrayliteralTX (ti, keys, vals); */
+ tree keys = d_array_value (build_ctype (ta->index->arrayOf ()),
+ size_int (e->keys->dim), build_address (akeys));
+ tree vals = d_array_value (build_ctype (ta->next->arrayOf ()),
+ size_int (e->values->dim),
+ build_address (avals));
+
+ tree mem = build_libcall (LIBCALL_ASSOCARRAYLITERALTX, Type::tvoidptr, 3,
+ build_typeinfo (ta), keys, vals);
+
+ /* Return an associative array pointed to by MEM. */
+ tree aatype = build_ctype (ta);
+ vec<constructor_elt, va_gc> *ce = NULL;
+ CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (aatype), mem);
+
+ this->result_ = build_nop (build_ctype (e->type),
+ build_constructor (aatype, ce));
+ }
+
+ /* Build a struct literal. */
+
+ void visit (StructLiteralExp *e)
+ {
+ /* Handle empty struct literals. */
+ if (e->elements == NULL || e->sd->fields.dim == 0)
+ {
+ this->result_ = build_constructor (build_ctype (e->type), NULL);
+ return;
+ }
+
+ /* Building sinit trees are delayed until after frontend semantic
+ processing has complete. Build the static initializer now. */
+ if (e->useStaticInit && !this->constp_)
+ {
+ this->result_ = aggregate_initializer_decl (e->sd);
+ return;
+ }
+
+ /* Build a constructor that assigns the expressions in ELEMENTS
+ at each field index that has been filled in. */
+ vec<constructor_elt, va_gc> *ve = NULL;
+ tree saved_elems = NULL_TREE;
+
+ /* CTFE may fill the hidden pointer by NullExp. */
+ gcc_assert (e->elements->dim <= e->sd->fields.dim);
+
+ Type *tb = e->type->toBasetype ();
+ gcc_assert (tb->ty == Tstruct);
+
+ for (size_t i = 0; i < e->elements->dim; i++)
+ {
+ Expression *exp = (*e->elements)[i];
+ if (!exp)
+ continue;
+
+ VarDeclaration *field = e->sd->fields[i];
+ Type *type = exp->type->toBasetype ();
+ Type *ftype = field->type->toBasetype ();
+ tree value = NULL_TREE;
+
+ if (ftype->ty == Tsarray && !same_type_p (type, ftype))
+ {
+ /* Initialize a static array with a single element. */
+ tree elem = build_expr (exp, this->constp_);
+ elem = d_save_expr (elem);
+
+ if (initializer_zerop (elem))
+ value = build_constructor (build_ctype (ftype), NULL);
+ else
+ value = build_array_from_val (ftype, elem);
+ }
+ else
+ {
+ value = convert_expr (build_expr (exp, this->constp_),
+ exp->type, field->type);
+ }
+
+ /* Split construction of values out of the constructor. */
+ tree init = stabilize_expr (&value);
+ if (init != NULL_TREE)
+ saved_elems = compound_expr (saved_elems, init);
+
+ CONSTRUCTOR_APPEND_ELT (ve, get_symbol_decl (field), value);
+ }
+
+ /* Maybe setup hidden pointer to outer scope context. */
+ if (e->sd->isNested () && e->elements->dim != e->sd->fields.dim
+ && this->constp_ == false)
+ {
+ tree field = get_symbol_decl (e->sd->vthis);
+ tree value = build_vthis (e->sd);
+ CONSTRUCTOR_APPEND_ELT (ve, field, value);
+ gcc_assert (e->useStaticInit == false);
+ }
+
+ /* Build a constructor in the correct shape of the aggregate type. */
+ tree ctor = build_struct_literal (build_ctype (e->type), ve);
+
+ /* Nothing more to do for constant literals. */
+ if (this->constp_)
+ {
+ /* If the struct literal is a valid for static data. */
+ if (TREE_CONSTANT (ctor)
+ && initializer_constant_valid_p (ctor, TREE_TYPE (ctor)))
+ TREE_STATIC (ctor) = 1;
+
+ this->result_ = compound_expr (saved_elems, ctor);
+ return;
+ }
+
+ if (e->sym != NULL)
+ {
+ tree var = build_deref (e->sym);
+ ctor = compound_expr (modify_expr (var, ctor), var);
+ this->result_ = compound_expr (saved_elems, ctor);
+ }
+ else if (e->sd->isUnionDeclaration ())
+ {
+ /* For unions, use memset to fill holes in the object. */
+ tree var = build_local_temp (TREE_TYPE (ctor));
+ tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
+ tree init = build_call_expr (tmemset, 3, build_address (var),
+ size_zero_node,
+ size_int (e->sd->structsize));
+
+ init = compound_expr (init, saved_elems);
+ init = compound_expr (init, modify_expr (var, ctor));
+ this->result_ = compound_expr (init, var);
+ }
+ else
+ this->result_ = compound_expr (saved_elems, ctor);
+ }
+
+ /* Build a null literal. */
+
+ void visit (NullExp *e)
+ {
+ Type *tb = e->type->toBasetype ();
+ tree value;
+
+ /* Handle certain special case conversions, where the underlying type is an
+ aggregate with a nullable interior pointer. */
+ if (tb->ty == Tarray)
+ {
+ /* For dynamic arrays, set length and pointer fields to zero. */
+ value = d_array_value (build_ctype (e->type), size_int (0),
+ null_pointer_node);
+ }
+ else if (tb->ty == Taarray)
+ {
+ /* For associative arrays, set the pointer field to null. */
+ value = build_constructor (build_ctype (e->type), NULL);
+ }
+ else if (tb->ty == Tdelegate)
+ {
+ /* For delegates, set the frame and function pointer to null. */
+ value = build_delegate_cst (null_pointer_node,
+ null_pointer_node, e->type);
+ }
+ else
+ value = d_convert (build_ctype (e->type), integer_zero_node);
+
+ TREE_CONSTANT (value) = 1;
+ this->result_ = value;
+ }
+
+ /* Build a vector literal. */
+
+ void visit (VectorExp *e)
+ {
+ tree type = build_ctype (e->type);
+ tree etype = TREE_TYPE (type);
+
+ /* First handle array literal expressions. */
+ if (e->e1->op == TOKarrayliteral)
+ {
+ ArrayLiteralExp *ale = ((ArrayLiteralExp *) e->e1);
+ vec<constructor_elt, va_gc> *elms = NULL;
+ bool constant_p = true;
+
+ vec_safe_reserve (elms, ale->elements->dim);
+ for (size_t i = 0; i < ale->elements->dim; i++)
+ {
+ Expression *expr = ale->getElement (i);
+ tree value = d_convert (etype, build_expr (expr, this->constp_));
+ if (!CONSTANT_CLASS_P (value))
+ constant_p = false;
+
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+ }
+
+ /* Build a VECTOR_CST from a constant vector constructor. */
+ if (constant_p)
+ this->result_ = build_vector_from_ctor (type, elms);
+ else
+ this->result_ = build_constructor (type, elms);
+ }
+ else
+ {
+ /* Build constructor from single value. */
+ tree val = d_convert (etype, build_expr (e->e1, this->constp_));
+ this->result_ = build_vector_from_val (type, val);
+ }
+ }
+
+ /* Build a static class literal, return its reference. */
+
+ void visit (ClassReferenceExp *e)
+ {
+ /* The result of build_new_class_expr is a RECORD_TYPE, we want
+ the reference. */
+ tree var = build_address (build_new_class_expr (e));
+
+ /* If the type of this literal is an interface, the we must add the
+ interface offset to symbol. */
+ if (this->constp_)
+ {
+ TypeClass *tc = (TypeClass *) e->type;
+ InterfaceDeclaration *to = tc->sym->isInterfaceDeclaration ();
+
+ if (to != NULL)
+ {
+ ClassDeclaration *from = e->originalClass ();
+ int offset = 0;
+
+ gcc_assert (to->isBaseOf (from, &offset) != 0);
+
+ if (offset != 0)
+ var = build_offset (var, size_int (offset));
+ }
+ }
+
+ this->result_ = var;
+ }
+
+ /* These expressions are mainly just a placeholders in the frontend.
+ We shouldn't see them here. */
+
+ void visit (ScopeExp *e)
+ {
+ error_at (make_location_t (e->loc), "%qs is not an expression",
+ e->toChars ());
+ this->result_ = error_mark_node;
+ }
+
+ void visit (TypeExp *e)
+ {
+ error_at (make_location_t (e->loc), "type %qs is not an expression",
+ e->toChars ());
+ this->result_ = error_mark_node;
+ }
+};
+
+
+/* Main entry point for ExprVisitor interface to generate code for
+ the Expression AST class E. If CONST_P is true, then E is a
+ constant expression. */
+
+tree
+build_expr (Expression *e, bool const_p)
+{
+ ExprVisitor v = ExprVisitor (const_p);
+ location_t saved_location = input_location;
+
+ input_location = make_location_t (e->loc);
+ e->accept (&v);
+ tree expr = v.result ();
+ input_location = saved_location;
+
+ /* Check if initializer expression is valid constant. */
+ if (const_p && !initializer_constant_valid_p (expr, TREE_TYPE (expr)))
+ {
+ error_at (make_location_t (e->loc), "non-constant expression %qs",
+ e->toChars ());
+ return error_mark_node;
+ }
+
+ return expr;
+}
+
+/* Same as build_expr, but also calls destructors on any temporaries. */
+
+tree
+build_expr_dtor (Expression *e)
+{
+ /* Codegen can be improved by determining if no exceptions can be thrown
+ between the ctor and dtor, and eliminating the ctor and dtor. */
+ size_t saved_vars = vec_safe_length (d_function_chain->vars_in_scope);
+ tree result = build_expr (e);
+
+ if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope))
+ {
+ result = fold_build_cleanup_point_expr (TREE_TYPE (result), result);
+ vec_safe_truncate (d_function_chain->vars_in_scope, saved_vars);
+ }
+
+ return result;
+}
+
+/* Same as build_expr_dtor, but handles the result of E as a return value. */
+
+tree
+build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
+{
+ size_t saved_vars = vec_safe_length (d_function_chain->vars_in_scope);
+ tree result = build_expr (e);
+
+ /* Convert for initializing the DECL_RESULT. */
+ result = convert_expr (result, e->type, type);
+
+ /* If we are returning a reference, take the address. */
+ if (tf->isref)
+ result = build_address (result);
+
+ /* The decl to store the return expression. */
+ tree decl = DECL_RESULT (cfun->decl);
+
+ /* Split comma expressions, so that the result is returned directly. */
+ tree expr = stabilize_expr (&result);
+ result = build_assign (INIT_EXPR, decl, result);
+ result = compound_expr (expr, return_expr (result));
+
+ /* May nest the return expression inside the try/finally expression. */
+ if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope))
+ {
+ result = fold_build_cleanup_point_expr (TREE_TYPE (result), result);
+ vec_safe_truncate (d_function_chain->vars_in_scope, saved_vars);
+ }
+
+ return result;
+}
+
diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi
new file mode 100644
index 0000000..36d9c59
--- /dev/null
+++ b/gcc/d/gdc.texi
@@ -0,0 +1,718 @@
+\input texinfo @c -*-texinfo-*-
+@setfilename gdc.info
+@settitle The GNU D Compiler
+
+@c Merge the standard indexes into a single one.
+@syncodeindex fn cp
+@syncodeindex vr cp
+@syncodeindex ky cp
+@syncodeindex pg cp
+@syncodeindex tp cp
+
+@include gcc-common.texi
+
+@c Copyright years for this manual.
+@set copyrights-d 2006-2018
+
+@copying
+@c man begin COPYRIGHT
+Copyright @copyright{} @value{copyrights-d} Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+A copy of the license is included in the
+@c man end
+section entitled ``GNU Free Documentation License''.
+@ignore
+@c man begin COPYRIGHT
+man page gfdl(7).
+@c man end
+@end ignore
+@end copying
+
+@ifinfo
+@format
+@dircategory Software development
+@direntry
+* gdc: (gdc). A GCC-based compiler for the D language
+@end direntry
+@end format
+
+@insertcopying
+@end ifinfo
+
+@titlepage
+@title The GNU D Compiler
+@versionsubtitle
+@author David Friedman, Iain Buclaw
+
+@page
+@vskip 0pt plus 1filll
+Published by the Free Software Foundation @*
+51 Franklin Street, Fifth Floor@*
+Boston, MA 02110-1301, USA@*
+@sp 1
+@insertcopying
+@end titlepage
+@contents
+@page
+
+@node Top
+@top Introduction
+
+This manual describes how to use @command{gdc}, the GNU compiler for
+the D programming language. This manual is specifically about
+@command{gdc}. For more information about the D programming
+language in general, including language specifications and standard
+package documentation, see @uref{http://dlang.org/}.
+
+@menu
+* Copying:: The GNU General Public License.
+* GNU Free Documentation License::
+ How you can share and copy this manual.
+* Invoking gdc:: How to run gdc.
+* Index:: Index.
+@end menu
+
+
+@include gpl_v3.texi
+
+@include fdl.texi
+
+
+@node Invoking gdc
+@chapter Invoking gdc
+
+@c man title gdc A GCC-based compiler for the D language
+
+@ignore
+@c man begin SYNOPSIS gdc
+gdc [@option{-c}|@option{-S}] [@option{-g}] [@option{-pg}]
+ [@option{-O}@var{level}] [@option{-W}@var{warn}@dots{}]
+ [@option{-I}@var{dir}@dots{}] [@option{-L}@var{dir}@dots{}]
+ [@option{-f}@var{option}@dots{}] [@option{-m}@var{machine-option}@dots{}]
+ [@option{-o} @var{outfile}] [@@@var{file}] @var{infile}@dots{}
+
+Only the most useful options are listed here; see below for the
+remainder.
+@c man end
+@c man begin SEEALSO
+gpl(7), gfdl(7), fsf-funding(7), gcc(1)
+and the Info entries for @file{gdc} and @file{gcc}.
+@c man end
+@end ignore
+
+@c man begin DESCRIPTION gdc
+
+The @command{gdc} command is the GNU compiler for the D language and
+supports many of the same options as @command{gcc}. @xref{Option Summary, ,
+Option Summary, gcc, Using the GNU Compiler Collection (GCC)}.
+This manual only documents the options specific to @command{gdc}.
+
+@c man end
+
+@menu
+* Input and Output files:: Controlling the kind of output:
+ an executable, object files, assembler files,
+* Runtime Options:: Options controlling runtime behavior
+* Directory Options:: Where to find module files
+* Code Generation:: Options controlling the output of gdc
+* Warnings:: Options controlling warnings specific to gdc
+* Linking:: Options influencing the linking step
+* Developer Options:: Options useful for developers of gdc
+@end menu
+
+@c man begin OPTIONS
+
+@node Input and Output files
+@section Input and Output files
+@cindex suffixes for D source
+@cindex D source file suffixes
+
+For any given input file, the file name suffix determines what kind of
+compilation is done. The following kinds of input file names are supported:
+
+@table @gcctabopt
+@item @var{file}.d
+D source files.
+@item @var{file}.dd
+Ddoc source files.
+@item @var{file}.di
+D interface files.
+@end table
+
+You can specify more than one input file on the @command{gdc} command line,
+each being compiled separately in the compilation process. If you specify a
+@code{-o @var{file}} option, all the input files are compiled together,
+producing a single output file, named @var{file}. This is allowed even
+when using @code{-S} or @code{-c}.
+
+@cindex D interface files.
+A D interface file contains only what an import of the module needs,
+rather than the whole implementation of that module. They can be created
+by @command{gdc} from a D source file by using the @code{-H} option.
+When the compiler resolves an import declaration, it searches for matching
+@file{.di} files first, then for @file{.d}.
+
+@cindex Ddoc source files.
+A Ddoc source file contains code in the D macro processor language. It is
+primarily designed for use in producing user documentation from embedded
+comments, with a slight affinity towards HTML generation. If a @file{.d}
+source file starts with the string @code{Ddoc} then it is treated as general
+purpose documentation, not as a D source file.
+
+@node Runtime Options
+@section Runtime Options
+@cindex options, runtime
+
+These options affect the runtime behavior of programs compiled with
+@command{gdc}.
+
+@table @gcctabopt
+
+@item -fall-instantiations
+@cindex @option{-fall-instantiations}
+@cindex @option{-fno-all-instantiations}
+Generate code for all template instantiations. The default template emission
+strategy is to not generate code for declarations that were either
+instantiated speculatively, such as from @code{__traits(compiles, ...)}, or
+that come from an imported module not being compiled.
+
+@item -fno-assert
+@cindex @option{-fassert}
+@cindex @option{-fno-assert}
+Turn off code generation for @code{assert} contracts.
+
+@item -fno-bounds-check
+@cindex @option{-fbounds-check}
+@cindex @option{-fno-bounds-check}
+Turns off array bounds checking for all functions, which can improve
+performance for code that uses arrays extensively. Note that this
+can result in unpredictable behavior if the code in question actually
+does violate array bounds constraints. It is safe to use this option
+if you are sure that your code never throws a @code{RangeError}.
+
+@item -fbounds-check=@var{value}
+@cindex @option{-fbounds-check=}
+An alternative to @option{-fbounds-check} that allows more control
+as to where bounds checking is turned on or off. The following values
+are supported:
+
+@table @samp
+@item on
+Turns on array bounds checking for all functions.
+@item safeonly
+Turns on array bounds checking only for @code{@@safe} functions.
+@item off
+Turns off array bounds checking completely.
+@end table
+
+@item -fno-builtin
+@cindex @option{-fbuiltin}
+@cindex @option{-fno-builtin}
+Don't recognize built-in functions unless they begin with the prefix
+@samp{__builtin_}. By default, the compiler will recognize when a
+function in the @code{core.stdc} package is a built-in function.
+
+@item -fdebug
+@item -fdebug=@var{value}
+@cindex @option{-fdebug}
+@cindex @option{-fno-debug}
+Turn on compilation of conditional @code{debug} code into the program.
+The @option{-fdebug} option itself sets the debug level to @code{1},
+while @option{-fdebug=} enables @code{debug} code that are identified
+by any of the following values:
+
+@table @samp
+@item level
+Sets the debug level to @var{level}, any @code{debug} code <= @var{level}
+is compiled into the program.
+@item ident
+Turns on compilation of any @code{debug} code identified by @var{ident}.
+@end table
+
+@item -fno-invariants
+@cindex @option{-finvariants}
+@cindex @option{-fno-invariants}
+Turns off code generation for class @code{invariant} contracts.
+
+@item -fno-moduleinfo
+@cindex @option{-fmoduleinfo}
+@cindex @option{-fno-moduleinfo}
+Turns off generation of the @code{ModuleInfo} and related functions
+that would become unreferenced without it, which may allow linking
+to programs not written in D. Functions that are not be generated
+include module constructors and destructors (@code{static this} and
+@code{static ~this}), @code{unittest} code, and @code{DSO} registry
+functions for dynamically linked code.
+
+@item -fonly=@var{filename}
+@cindex @option{-fonly}
+Tells the compiler to parse and run semantic analysis on all modules
+on the command line, but only generate code for the module specified
+by @var{filename}.
+
+@item -fno-postconditions
+@cindex @option{-fpostconditions}
+@cindex @option{-fno-postconditions}
+Turns off code generation for postcondition @code{out} contracts.
+
+@item -fno-preconditions
+@cindex @option{-fpreconditions}
+@cindex @option{-fno-preconditions}
+Turns off code generation for precondition @code{in} contracts.
+
+@item -frelease
+@cindex @option{-frelease}
+@cindex @option{-fno-release}
+Turns on compiling in release mode, which means not emitting runtime
+checks for contracts and asserts. Array bounds checking is not done
+for @code{@@system} and @code{@@trusted} functions, and assertion
+failures are undefined behavior.
+
+This is equivalent to compiling with the following options:
+
+@example
+gdc -fno-assert -fbounds-check=safe -fno-invariants \
+ -fno-postconditions -fno-preconditions -fno-switch-errors
+@end example
+
+@item -fno-switch-errors
+@cindex @option{-fswitch-errors}
+@cindex @option{-fno-switch-errors}
+This option controls what code is generated when no case is matched
+in a @code{final switch} statement. The default run time behavior
+is to throw a @code{SwitchError}. Turning off @option{-fswitch-errors}
+means that instead the execution of the program is immediately halted.
+
+@item -funittest
+@cindex @option{-funittest}
+@cindex @option{-fno-unittest}
+Turns on compilation of @code{unittest} code, and turns on the
+@code{version(unittest)} identifier. This implies @option{-fassert}.
+
+@item -fversion=@var{value}
+@cindex @option{-fversion}
+Turns on compilation of conditional @code{version} code into the program
+identified by any of the following values:
+
+@table @samp
+@item level
+Sets the version level to @var{level}, any @code{version} code >= @var{level}
+is compiled into the program.
+@item ident
+Turns on compilation of @code{version} code identified by @var{ident}.
+@end table
+
+@item -fno-weak
+@cindex @option{-fweak}
+@cindex @option{-fno-weak}
+Turns off emission of instantiated declarations that can be defined in multiple
+objects as weak or one-only symbols. The default is to emit all public symbols
+as weak, unless the target lacks support for weak symbols. Disabling this
+option means that common symbols are instead put in COMDAT or become private.
+
+@end table
+
+@node Directory Options
+@section Options for Directory Search
+@cindex directory options
+@cindex options, directory search
+@cindex search path
+
+These options specify directories to search for files, libraries, and
+other parts of the compiler:
+
+@table @gcctabopt
+
+@item -I@var{dir}
+@cindex @option{-I}
+Specify a directory to use when searching for imported modules at
+compile time. Multiple @option{-I} options can be used, and the
+paths are searched in the same order.
+
+@item -J@var{dir}
+@cindex @option{-J}
+Specify a directory to use when searching for files in string imports
+at compile time. This switch is required in order to use
+@code{import(file)} expressions. Multiple @option{-J} options can be
+used, and the paths are searched in the same order.
+
+@item -L@var{dir}
+@cindex @option{-L}
+When linking, specify a library search directory, as with @command{gcc}.
+
+@item -B@var{dir}
+@cindex @option{-B}
+This option specifies where to find the executables, libraries,
+source files, and data files of the compiler itself, as with @command{gcc}.
+
+@item -fmodule-file=@var{module}=@var{spec}
+@cindex @option{-fmodule-file}
+This option manipulates file paths of imported modules, such that if an
+imported module matches all or the leftmost part of @var{module}, the file
+path in @var{spec} is used as the location to search for D sources.
+This is used when the source file path and names are not the same as the
+package and module hierarchy. Consider the following examples:
+
+@example
+gdc test.d -fmodule-file=A.B=foo.d -fmodule-file=C=bar
+@end example
+
+This will tell the compiler to search in all import paths for the source
+file @var{foo.d} when importing @var{A.B}, and the directory @var{bar/}
+when importing @var{C}, as annotated in the following D code:
+
+@example
+module test;
+import A.B; // Matches A.B, searches for foo.d
+import C.D.E; // Matches C, searches for bar/D/E.d
+import A.B.C; // No match, searches for A/B/C.d
+@end example
+
+@item -imultilib @var{dir}
+@cindex @option{-imultilib}
+Use @var{dir} as a subdirectory of the gcc directory containing
+target-specific D sources and interfaces.
+
+@item -iprefix @var{prefix}
+@cindex @option{-iprefix}
+Specify @var{prefix} as the prefix for the gcc directory containing
+target-specific D sources and interfaces. If the @var{prefix} represents
+a directory, you should include the final @code{'/'}.
+
+@item -nostdinc
+@cindex @option{-nostdinc}
+Do not search the standard system directories for D source and interface
+files. Only the directories that have been specified with @option{-I} options
+(and the directory of the current file, if appropriate) are searched.
+
+@end table
+
+@node Code Generation
+@section Code Generation
+@cindex options, code generation
+
+In addition to the many @command{gcc} options controlling code generation,
+@command{gdc} has several options specific to itself.
+
+@table @gcctabopt
+
+@item -H
+@cindex @option{-H}
+Generates D interface files for all modules being compiled. The compiler
+determines the output file based on the name of the input file, removes
+any directory components and suffix, and applies the @file{.di} suffix.
+
+@item -Hd @var{dir}
+@cindex @option{-Hd}
+Same as @option{-H}, but writes interface files to directory @var{dir}.
+This option can be used with @option{-Hf @var{file}} to independently set the
+output file and directory path.
+
+@item -Hf @var{file}
+@cindex @option{-Hf}
+Same as @option{-H} but writes interface files to @var{file}. This option can
+be used with @option{-Hd @var{dir}} to independently set the output file and
+directory path.
+
+@item -M
+@cindex @option{-M}
+Output the module dependencies of all source files being compiled in a
+format suitable for @command{make}. The compiler outputs one
+@command{make} rule containing the object file name for that source file,
+a colon, and the names of all imported files.
+
+@item -MM
+@cindex @option{-MM}
+Like @option{-M} but does not mention imported modules from the D standard
+library package directories.
+
+@item -MF @var{file}
+@cindex @option{-MF}
+When used with @option{-M} or @option{-MM}, specifies a @var{file} to write
+the dependencies to. When used with the driver options @option{-MD} or
+@option{-MMD}, @option{-MF} overrides the default dependency output file.
+
+@item -MG
+@cindex @option{-MG}
+This option is for compatibility with @command{gcc}, and is ignored by the
+compiler.
+
+@item -MP
+@cindex @option{-MP}
+Outputs a phony target for each dependency other than the modules being
+compiled, causing each to depend on nothing.
+
+@item -MT @var{target}
+@cindex @option{-MT}
+Change the @var{target} of the rule emitted by dependency generation
+to be exactly the string you specify. If you want multiple targets,
+you can specify them as a single argument to @option{-MT}, or use
+multiple @option{-MT} options.
+
+@item -MQ @var{target}
+@cindex @option{-MQ}
+Same as @option{-MT}, but it quotes any characters which are special to
+@command{make}.
+
+@item -MD
+@cindex @option{-MD}
+This option is equivalent to @option{-M -MF @var{file}}. The driver
+determines @var{file} by removing any directory components and suffix
+from the input file, and then adding a @file{.deps} suffix.
+
+@item -MMD
+@cindex @option{-MMD}
+Like @option{-MD} but does not mention imported modules from the D standard
+library package directories.
+
+@item -X
+@cindex @option{-X}
+Output information describing the contents of all source files being
+compiled in JSON format to a file. The driver determines @var{file} by
+removing any directory components and suffix from the input file, and then
+adding a @file{.json} suffix.
+
+@item -Xf @var{file}
+@cindex @option{-Xf}
+Same as @option{-X}, but writes all JSON contents to the specified
+@var{file}.
+
+@item -fdoc
+@cindex @option{-fdoc}
+Generates @code{Ddoc} documentation and writes it to a file. The compiler
+determines @var{file} by removing any directory components and suffix
+from the input file, and then adding a @file{.html} suffix.
+
+@item -fdoc-dir=@var{dir}
+@cindex @option{-fdoc-dir}
+Same as @option{-fdoc}, but writes documentation to directory @var{dir}.
+This option can be used with @option{-fdoc-file=@var{file}} to
+independently set the output file and directory path.
+
+@item -fdoc-file=@var{file}
+@cindex @option{-fdoc-file}
+Same as @option{-fdoc}, but writes documentation to @var{file}. This
+option can be used with @option{-fdoc-dir=@var{dir}} to independently
+set the output file and directory path.
+
+@item -fdoc-inc=@var{file}
+@cindex @option{-fdoc-inc}
+Specify @var{file} as a @var{Ddoc} macro file to be read. Multiple
+@option{-fdoc-inc} options can be used, and files are read and processed
+in the same order.
+
+@end table
+
+@node Warnings
+@section Warnings
+@cindex options to control warnings
+@cindex warning messages
+@cindex messages, warning
+@cindex suppressing warnings
+
+Warnings are diagnostic messages that report constructions that
+are not inherently erroneous but that are risky or suggest there
+is likely to be a bug in the program. Unless @option{-Werror} is
+specified, they do not prevent compilation of the program.
+
+@table @gcctabopt
+
+@item -Wall
+@cindex @option{-Wall}
+@cindex @option{-Wno-all}
+Turns on all warnings messages. Warnings are not a defined part of
+the D language, and all constructs for which this may generate a
+warning message are valid code.
+
+@item -Walloca
+@cindex @option{-Walloca}
+This option warns on all uses of "alloca" in the source.
+
+@item -Walloca-larger-than=@var{n}
+@cindex @option{-Walloca-larger-than}
+@cindex @option{-Wno-alloca-larger-than}
+Warn on unbounded uses of alloca, and on bounded uses of alloca
+whose bound can be larger than @var{n} bytes.
+@option{-Wno-alloca-larger-than} disables
+@option{-Walloca-larger-than} warning and is equivalent to
+@option{-Walloca-larger-than=@var{SIZE_MAX}} or larger.
+
+@item -Wcast-result
+@cindex @option{-Wcast-result}
+@cindex @option{-Wno-cast-result}
+Warn about casts that will produce a null or zero result. Currently
+this is only done for casting between an imaginary and non-imaginary
+data type, or casting between a D and C++ class.
+
+@item -Wno-deprecated
+@cindex @option{-Wdeprecated}
+@cindex @option{-Wno-deprecated}
+Do not warn about usage of deprecated features and symbols with
+@code{deprecated} attributes.
+
+@item -Werror
+@cindex @option{-Werror}
+@cindex @option{-Wno-error}
+Turns all warnings into errors.
+
+@item -Wspeculative
+@cindex @option{-Wspeculative}
+@cindex @option{-Wno-speculative}
+List all error messages from speculative compiles, such as
+@code{__traits(compiles, ...)}. This option does not report
+messages as warnings, and these messages therefore never become
+errors when the @option{-Werror} option is also used.
+
+@item -Wtemplates
+@cindex @option{-Wtemplates}
+@cindex @option{-Wno-templates}
+Warn when a template instantiation is encountered. Some coding
+rules disallow templates, and this may be used to enforce that rule.
+
+@item -Wunknown-pragmas
+@cindex @option{-Wunknown-pragmas}
+@cindex @option{-Wno-unknown-pragmas}
+Warn when a @code{pragma()} is encountered that is not understood by
+@command{gdc}. This differs from @option{-fignore-unknown-pragmas}
+where a pragma that is part of the D language, but not implemented by
+the compiler, won't get reported.
+
+@item -fignore-unknown-pragmas
+@cindex @option{-fignore-unknown-pragmas}
+@cindex @option{-fno-ignore-unknown-pragmas}
+Turns off errors for unsupported pragmas.
+
+@item -fmax-errors=@var{n}
+@cindex @option{-fmax-errors}
+Limits the maximum number of error messages to @var{n}, at which point
+@command{gdc} bails out rather than attempting to continue processing the
+source code. If @var{n} is 0 (the default), there is no limit on the
+number of error messages produced.
+
+@item -fsyntax-only
+@cindex @option{-fsyntax-only}
+@cindex @option{-fno-syntax-only}
+Check the code for syntax errors, but do not actually compile it. This
+can be used in conjunction with @option{-fdoc} or @option{-H} to generate
+files for each module present on the command-line, but no other output
+file.
+
+@item -ftransition=@var{id}
+@cindex @option{-ftransition}
+Report additional information about D language changes identified by
+@var{id}. The following values are supported:
+
+@table @samp
+@item all
+List information on all language changes.
+@item checkimports
+Give deprecation messages about @option{-ftransition=import} anomalies.
+@item complex
+List all usages of complex or imaginary types.
+@item dip1000
+Implements @uref{http://wiki.dlang.org/DIP1000} (experimental).
+@item dip25
+Implements @uref{http://wiki.dlang.org/DIP25} (experimental).
+@item field
+List all non-mutable fields which occupy an object instance.
+@item import
+Tells the compiler to revert to using an old lookup behavior for resolving
+unqualified symbol names, where this was done in a single pass, ignoring
+any protection attributes. The default name lookup strategy is to use two
+passes, the first ignoring imported declarations, and the second only
+looking at imports. The protection (@code{private}, @code{package},
+@code{protected}) of symbols is also enforced to resolve any conflicts
+between private and public symbols.
+@item nogc
+List all hidden GC allocations.
+@item tls
+List all variables going into thread local storage.
+@end table
+
+@end table
+
+@node Linking
+@section Options for Linking
+@cindex options, linking
+@cindex linking, static
+
+These options come into play when the compiler links object files into an
+executable output file. They are meaningless if the compiler is not doing
+a link step.
+
+@table @gcctabopt
+
+@item -defaultlib @var{libname}
+@cindex @option{-defaultlib}
+Specify the library to use instead of libphobos when linking. Options
+specifying the linkage of libphobos, such as @option{-static-libphobos}
+or @option{-shared-libphobos}, are ignored.
+
+@item -debuglib
+@cindex @option{-debuglib}
+Specify the debug library to use instead of libphobos when linking.
+This option has no effect unless the @option{-g} option was also given
+on the command line. Options specifying the linkage of libphobos, such
+as @option{-static-libphobos} or @option{-shared-libphobos}, are ignored.
+
+@item -nophoboslib
+@cindex @option{-nophoboslib}
+Do not use the Phobos or D runtime library when linking. Options specifying
+the linkage of libphobos, such as @option{-static-libphobos} or
+@option{-shared-libphobos}, are ignored. The standard system libraries are
+used normally, unless @option{-nostdlib} or @option{-nodefaultlibs} is used.
+
+@item -shared-libphobos
+@cindex @option{-shared-libphobos}
+On systems that provide @file{libgphobos} and @file{libgdruntime} as a
+shared and a static library, this option forces the use of the shared
+version. If no shared version was built when the compiler was configured,
+this option has no effect.
+
+@item -static-libphobos
+@cindex @option{-static-libphobos}
+On systems that provide @file{libgphobos} and @file{libgdruntime} as a
+shared and a static library, this option forces the use of the static
+version. If no static version was built when the compiler was configured,
+this option has no effect.
+
+@end table
+
+@node Developer Options
+@section Developer Options
+@cindex developer options
+@cindex debug dump options
+@cindex dump options
+
+This section describes command-line options that are primarily of
+interest to developers or language tooling.
+
+@table @gcctabopt
+
+@item -fdump-d-original
+@cindex @option{-fdump-d-original}
+Output the internal front-end AST after the @code{semantic3} stage.
+This option is only useful for debugging the GNU D compiler itself.
+
+@item -v
+@cindex @option{-v}
+Dump information about the compiler language processing stages as the source
+program is being compiled. This includes listing all modules that are
+processed through the @code{parse}, @code{semantic}, @code{semantic2}, and
+@code{semantic3} stages; all @code{import} modules and their file paths;
+and all @code{function} bodies that are being compiled.
+
+@end table
+
+@c man end
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+
+@bye
diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc
new file mode 100644
index 0000000..5a2f4ef
--- /dev/null
+++ b/gcc/d/imports.cc
@@ -0,0 +1,208 @@
+/* imports.cc -- Build imported modules/declarations.
+ Copyright (C) 2014-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/declaration.h"
+#include "dmd/enum.h"
+#include "dmd/identifier.h"
+#include "dmd/import.h"
+#include "dmd/module.h"
+
+#include "tree.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+
+
+/* Implements the visitor interface to build debug trees for all
+ module and import declarations, where ISYM holds the cached
+ back-end representation to be returned. */
+class ImportVisitor : public Visitor
+{
+ using Visitor::visit;
+
+ /* Build the declaration DECL as an imported symbol. */
+ tree make_import (tree decl)
+ {
+ gcc_assert (decl != NULL_TREE);
+
+ tree import = build_decl (input_location, IMPORTED_DECL,
+ DECL_NAME (decl), void_type_node);
+ IMPORTED_DECL_ASSOCIATED_DECL (import) = decl;
+ d_keep (import);
+
+ return import;
+ }
+
+public:
+ ImportVisitor (void)
+ {
+ }
+
+ /* This should be overridden by each symbol class. */
+ void visit (Dsymbol *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* Build the module decl for M, this is considered toplevel, regardless
+ of whether there are any parent packages in the module system. */
+ void visit (Module *m)
+ {
+ Loc loc = (m->md != NULL) ? m->md->loc
+ : Loc (m->srcfile->toChars (), 1, 0);
+
+ m->isym = build_decl (make_location_t (loc), NAMESPACE_DECL,
+ get_identifier (m->toPrettyChars ()),
+ void_type_node);
+ d_keep (m->isym);
+
+ if (!m->isRoot ())
+ DECL_EXTERNAL (m->isym) = 1;
+
+ TREE_PUBLIC (m->isym) = 1;
+ DECL_CONTEXT (m->isym) = NULL_TREE;
+ }
+
+ /* Build an import of another module symbol. */
+
+ void visit (Import *m)
+ {
+ tree module = build_import_decl (m->mod);
+ m->isym = this->make_import (module);
+ }
+
+ /* Build an import for any kind of user defined type.
+ Use the TYPE_DECL associated with the type symbol. */
+ void visit (EnumDeclaration *d)
+ {
+ tree type = build_ctype (d->type);
+ /* Not all kinds of D enums create a TYPE_DECL. */
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ d->isym = this->make_import (TYPE_STUB_DECL (type));
+ }
+
+ void visit (AggregateDeclaration *d)
+ {
+ tree type = build_ctype (d->type);
+ d->isym = this->make_import (TYPE_STUB_DECL (type));
+ }
+
+ void visit (ClassDeclaration *d)
+ {
+ /* Want the RECORD_TYPE, not POINTER_TYPE. */
+ tree type = TREE_TYPE (build_ctype (d->type));
+ d->isym = this->make_import (TYPE_STUB_DECL (type));
+ }
+
+ /* For now, ignore importing other kinds of dsymbols. */
+ void visit (ScopeDsymbol *)
+ {
+ }
+
+ /* Alias symbols aren't imported, but their targets are. */
+ void visit (AliasDeclaration *d)
+ {
+ Dsymbol *dsym = d->toAlias ();
+
+ if (dsym == d)
+ {
+ Type *type = d->getType ();
+
+ /* Type imports should really be part of their own visit method. */
+ if (type != NULL)
+ {
+ if (type->ty == Tenum)
+ dsym = ((TypeEnum *) type)->sym;
+ else if (type->ty == Tstruct)
+ dsym = ((TypeStruct *) type)->sym;
+ else if (type->ty == Tclass)
+ dsym = ((TypeClass *) type)->sym;
+ }
+ }
+
+ /* This symbol is really an alias for another, visit the other. */
+ if (dsym != d)
+ {
+ dsym->accept (this);
+ d->isym = dsym->isym;
+ }
+ }
+
+ /* Visit the underlying alias symbol of overloadable aliases. */
+ void visit (OverDeclaration *d)
+ {
+ if (d->aliassym != NULL)
+ {
+ d->aliassym->accept (this);
+ d->isym = d->aliassym->isym;
+ }
+ }
+
+ /* Function aliases are the same as alias symbols. */
+ void visit (FuncAliasDeclaration *d)
+ {
+ FuncDeclaration *fd = d->toAliasFunc ();
+
+ if (fd != NULL)
+ {
+ fd->accept (this);
+ d->isym = fd->isym;
+ }
+ }
+
+ /* Skip over importing templates and tuples. */
+ void visit (TemplateDeclaration *)
+ {
+ }
+
+ void visit (TupleDeclaration *)
+ {
+ }
+
+ /* Import any other kind of declaration. If the class does not implement
+ symbol generation routines, the compiler will throw an error. */
+ void visit (Declaration *d)
+ {
+ d->isym = this->make_import (get_symbol_decl (d));
+ }
+};
+
+
+/* Build a declaration for the symbol D that can be used for the
+ debug_hook imported_module_or_decl. */
+tree
+build_import_decl (Dsymbol *d)
+{
+ if (!d->isym)
+ {
+ location_t saved_location = input_location;
+ ImportVisitor v;
+
+ input_location = make_location_t (d->loc);
+ d->accept (&v);
+ input_location = saved_location;
+ }
+
+ /* Not all visitors set 'isym'. */
+ return d->isym ? d->isym : NULL_TREE;
+}
+
diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc
new file mode 100644
index 0000000..e554606
--- /dev/null
+++ b/gcc/d/intrinsics.cc
@@ -0,0 +1,846 @@
+/* intrinsics.cc -- D language compiler intrinsics.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/declaration.h"
+#include "dmd/identifier.h"
+#include "dmd/mangle.h"
+#include "dmd/mangle.h"
+#include "dmd/module.h"
+#include "dmd/template.h"
+
+#include "tm.h"
+#include "function.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stringpool.h"
+#include "builtins.h"
+
+#include "d-tree.h"
+
+
+/* An internal struct used to hold information on D intrinsics. */
+
+struct intrinsic_decl
+{
+ /* The DECL_FUNCTION_CODE of this decl. */
+ intrinsic_code code;
+
+ /* The name of the intrinsic. */
+ const char *name;
+
+ /* The module where the intrinsic is located. */
+ const char *module;
+
+ /* The mangled signature decoration of the intrinsic. */
+ const char *deco;
+
+ /* True if the intrinsic is only handled in CTFE. */
+ bool ctfeonly;
+};
+
+static const intrinsic_decl intrinsic_decls[] =
+{
+#define DEF_D_INTRINSIC(CODE, ALIAS, NAME, MODULE, DECO, CTFE) \
+ { INTRINSIC_ ## ALIAS, NAME, MODULE, DECO, CTFE },
+
+#include "intrinsics.def"
+
+#undef DEF_D_INTRINSIC
+};
+
+/* Checks if DECL is an intrinsic or run time library function that requires
+ special processing. Sets DECL_INTRINSIC_CODE so it can be identified
+ later in maybe_expand_intrinsic. */
+
+void
+maybe_set_intrinsic (FuncDeclaration *decl)
+{
+ if (!decl->ident || decl->builtin != BUILTINunknown)
+ return;
+
+ /* The builtin flag is updated only if we can evaluate the intrinsic
+ at compile-time. Such as the math or bitop intrinsics. */
+ decl->builtin = BUILTINno;
+
+ /* Check if it's a compiler intrinsic. We only require that any
+ internally recognised intrinsics are declared in a module with
+ an explicit module declaration. */
+ Module *m = decl->getModule ();
+
+ if (!m || !m->md)
+ return;
+
+ TemplateInstance *ti = decl->isInstantiated ();
+ TemplateDeclaration *td = ti ? ti->tempdecl->isTemplateDeclaration () : NULL;
+
+ const char *tname = decl->ident->toChars ();
+ const char *tmodule = m->md->toChars ();
+ const char *tdeco = (td == NULL) ? decl->type->deco : NULL;
+
+ /* Look through all D intrinsics. */
+ for (size_t i = 0; i < (int) INTRINSIC_LAST; i++)
+ {
+ if (!intrinsic_decls[i].name)
+ continue;
+
+ if (strcmp (intrinsic_decls[i].name, tname) != 0
+ || strcmp (intrinsic_decls[i].module, tmodule) != 0)
+ continue;
+
+ /* Instantiated functions would have the wrong type deco, get it from the
+ template member instead. */
+ if (tdeco == NULL)
+ {
+ if (!td || !td->onemember)
+ return;
+
+ FuncDeclaration *fd = td->onemember->isFuncDeclaration ();
+ if (fd == NULL)
+ return;
+
+ OutBuffer buf;
+ mangleToBuffer (fd->type, &buf);
+ tdeco = buf.extractString ();
+ }
+
+ /* Matching the type deco may be a bit too strict, as it means that all
+ function attributes that end up in the signature must be kept aligned
+ between the compiler and library declaration. */
+ if (strcmp (intrinsic_decls[i].deco, tdeco) == 0)
+ {
+ intrinsic_code code = intrinsic_decls[i].code;
+
+ if (decl->csym == NULL)
+ get_symbol_decl (decl);
+
+ /* If there is no function body, then the implementation is always
+ provided by the compiler. */
+ if (!decl->fbody)
+ {
+ DECL_BUILT_IN_CLASS (decl->csym) = BUILT_IN_FRONTEND;
+ DECL_FUNCTION_CODE (decl->csym) = (built_in_function) code;
+ }
+
+ /* Infer whether the intrinsic can be used for CTFE, let the
+ front-end know that it can be evaluated at compile-time. */
+ switch (code)
+ {
+ case INTRINSIC_VA_ARG:
+ case INTRINSIC_C_VA_ARG:
+ case INTRINSIC_VASTART:
+ case INTRINSIC_ADDS:
+ case INTRINSIC_SUBS:
+ case INTRINSIC_MULS:
+ case INTRINSIC_NEGS:
+ case INTRINSIC_VLOAD:
+ case INTRINSIC_VSTORE:
+ break;
+
+ case INTRINSIC_POW:
+ {
+ /* Check that this overload of pow() is has an equivalent
+ built-in function. It could be `int pow(int, int)'. */
+ tree rettype = TREE_TYPE (TREE_TYPE (decl->csym));
+ if (mathfn_built_in (rettype, BUILT_IN_POW) != NULL_TREE)
+ decl->builtin = BUILTINyes;
+ break;
+ }
+
+ default:
+ decl->builtin = BUILTINyes;
+ break;
+ }
+
+ /* The intrinsic was marked as CTFE-only. */
+ if (intrinsic_decls[i].ctfeonly)
+ DECL_BUILT_IN_CTFE (decl->csym) = 1;
+
+ DECL_INTRINSIC_CODE (decl->csym) = code;
+ break;
+ }
+ }
+}
+
+/* Construct a function call to the built-in function CODE, N is the number of
+ arguments, and the `...' parameters are the argument expressions.
+ The original call expression is held in CALLEXP. */
+
+static tree
+call_builtin_fn (tree callexp, built_in_function code, int n, ...)
+{
+ tree *argarray = XALLOCAVEC (tree, n);
+ va_list ap;
+
+ va_start (ap, n);
+ for (int i = 0; i < n; i++)
+ argarray[i] = va_arg (ap, tree);
+ va_end (ap);
+
+ tree exp = build_call_expr_loc_array (EXPR_LOCATION (callexp),
+ builtin_decl_explicit (code),
+ n, argarray);
+ return convert (TREE_TYPE (callexp), fold (exp));
+}
+
+/* Expand a front-end instrinsic call to bsf(). This takes one argument,
+ the signature to which can be either:
+
+ int bsf (uint arg);
+ int bsf (ulong arg);
+
+ This scans all bits in the given argument starting with the first,
+ returning the bit number of the first bit set. The original call
+ expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_bsf (tree callexp)
+{
+ /* The bsr() intrinsic gets turned into __builtin_ctz(arg).
+ The return value is supposed to be undefined if arg is zero. */
+ tree arg = CALL_EXPR_ARG (callexp, 0);
+ int argsize = TYPE_PRECISION (TREE_TYPE (arg));
+
+ /* Which variant of __builtin_ctz* should we call? */
+ built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CTZ
+ : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CTZL
+ : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CTZLL
+ : END_BUILTINS;
+
+ gcc_assert (code != END_BUILTINS);
+
+ return call_builtin_fn (callexp, code, 1, arg);
+}
+
+/* Expand a front-end instrinsic call to bsr(). This takes one argument,
+ the signature to which can be either:
+
+ int bsr (uint arg);
+ int bsr (ulong arg);
+
+ This scans all bits in the given argument from the most significant bit
+ to the least significant, returning the bit number of the first bit set.
+ The original call expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_bsr (tree callexp)
+{
+ /* The bsr() intrinsic gets turned into (size - 1) - __builtin_clz(arg).
+ The return value is supposed to be undefined if arg is zero. */
+ tree arg = CALL_EXPR_ARG (callexp, 0);
+ tree type = TREE_TYPE (arg);
+ int argsize = TYPE_PRECISION (type);
+
+ /* Which variant of __builtin_clz* should we call? */
+ built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CLZ
+ : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CLZL
+ : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CLZLL
+ : END_BUILTINS;
+
+ gcc_assert (code != END_BUILTINS);
+
+ tree result = call_builtin_fn (callexp, code, 1, arg);
+
+ /* Handle int -> long conversions. */
+ if (TREE_TYPE (result) != type)
+ result = fold_convert (type, result);
+
+ result = fold_build2 (MINUS_EXPR, type,
+ build_integer_cst (argsize - 1, type), result);
+ return fold_convert (TREE_TYPE (callexp), result);
+}
+
+/* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
+ bt(), btc(), btr(), or bts(). These intrinsics expect to take two arguments,
+ the signature to which is:
+
+ int bt (size_t* ptr, size_t bitnum);
+
+ All intrinsics test if a bit is set and return the result of that condition.
+ Variants of `bt' will then update that bit. `btc' compliments the bit, `bts'
+ sets the bit, and `btr' resets the bit. The original call expression is
+ held in CALLEXP. */
+
+static tree
+expand_intrinsic_bt (intrinsic_code intrinsic, tree callexp)
+{
+ tree ptr = CALL_EXPR_ARG (callexp, 0);
+ tree bitnum = CALL_EXPR_ARG (callexp, 1);
+ tree type = TREE_TYPE (TREE_TYPE (ptr));
+
+ /* size_t bitsize = sizeof(*ptr) * BITS_PER_UNIT; */
+ tree bitsize = fold_convert (type, TYPE_SIZE (type));
+
+ /* ptr[bitnum / bitsize] */
+ ptr = build_array_index (ptr, fold_build2 (TRUNC_DIV_EXPR, type,
+ bitnum, bitsize));
+ ptr = indirect_ref (type, ptr);
+
+ /* mask = 1 << (bitnum % bitsize); */
+ bitnum = fold_build2 (TRUNC_MOD_EXPR, type, bitnum, bitsize);
+ bitnum = fold_build2 (LSHIFT_EXPR, type, size_one_node, bitnum);
+
+ /* cond = ptr[bitnum / size] & mask; */
+ tree cond = fold_build2 (BIT_AND_EXPR, type, ptr, bitnum);
+
+ /* cond ? -1 : 0; */
+ cond = build_condition (TREE_TYPE (callexp), d_truthvalue_conversion (cond),
+ integer_minus_one_node, integer_zero_node);
+
+ /* Update the bit as needed, only testing the bit for bt(). */
+ if (intrinsic == INTRINSIC_BT)
+ return cond;
+
+ tree_code code = (intrinsic == INTRINSIC_BTC) ? BIT_XOR_EXPR
+ : (intrinsic == INTRINSIC_BTR) ? BIT_AND_EXPR
+ : (intrinsic == INTRINSIC_BTS) ? BIT_IOR_EXPR
+ : ERROR_MARK;
+ gcc_assert (code != ERROR_MARK);
+
+ /* ptr[bitnum / size] op= mask; */
+ if (intrinsic == INTRINSIC_BTR)
+ bitnum = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (bitnum), bitnum);
+
+ ptr = modify_expr (ptr, fold_build2 (code, TREE_TYPE (ptr), ptr, bitnum));
+
+ /* Store the condition result in a temporary, and return expressions in
+ correct order of evaluation. */
+ tree tmp = build_local_temp (TREE_TYPE (callexp));
+ cond = modify_expr (tmp, cond);
+
+ return compound_expr (cond, compound_expr (ptr, tmp));
+}
+
+/* Expand a front-end intrinsic call to bswap(). This takes one argument, the
+ signature to which can be either:
+
+ int bswap (uint arg);
+ int bswap (ulong arg);
+
+ This swaps all bytes in an N byte type end-to-end. The original call
+ expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_bswap (tree callexp)
+{
+ tree arg = CALL_EXPR_ARG (callexp, 0);
+ int argsize = TYPE_PRECISION (TREE_TYPE (arg));
+
+ /* Which variant of __builtin_bswap* should we call? */
+ built_in_function code = (argsize == 32) ? BUILT_IN_BSWAP32
+ : (argsize == 64) ? BUILT_IN_BSWAP64
+ : END_BUILTINS;
+
+ gcc_assert (code != END_BUILTINS);
+
+ return call_builtin_fn (callexp, code, 1, arg);
+}
+
+/* Expand a front-end intrinsic call to popcnt(). This takes one argument, the
+ signature to which can be either:
+
+ int popcnt (uint arg);
+ int popcnt (ulong arg);
+
+ Calculates the number of set bits in an integer. The original call
+ expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_popcnt (tree callexp)
+{
+ tree arg = CALL_EXPR_ARG (callexp, 0);
+ int argsize = TYPE_PRECISION (TREE_TYPE (arg));
+
+ /* Which variant of __builtin_popcount* should we call? */
+ built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_POPCOUNT
+ : (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTL
+ : (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_POPCOUNTLL
+ : END_BUILTINS;
+
+ gcc_assert (code != END_BUILTINS);
+
+ return call_builtin_fn (callexp, code, 1, arg);
+}
+
+/* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
+ sqrt(), sqrtf(), sqrtl(). These intrinsics expect to take one argument,
+ the signature to which can be either:
+
+ float sqrt (float arg);
+ double sqrt (double arg);
+ real sqrt (real arg);
+
+ This computes the square root of the given argument. The original call
+ expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_sqrt (intrinsic_code intrinsic, tree callexp)
+{
+ tree arg = CALL_EXPR_ARG (callexp, 0);
+
+ /* Which variant of __builtin_sqrt* should we call? */
+ built_in_function code = (intrinsic == INTRINSIC_SQRT) ? BUILT_IN_SQRT
+ : (intrinsic == INTRINSIC_SQRTF) ? BUILT_IN_SQRTF
+ : (intrinsic == INTRINSIC_SQRTL) ? BUILT_IN_SQRTL
+ : END_BUILTINS;
+
+ gcc_assert (code != END_BUILTINS);
+ return call_builtin_fn (callexp, code, 1, arg);
+}
+
+/* Expand a front-end intrinsic call to copysign(). This takes two arguments,
+ the signature to which can be either:
+
+ float copysign (T to, float from);
+ double copysign (T to, double from);
+ real copysign (T to, real from);
+
+ This computes a value composed of TO with the sign bit of FROM. The original
+ call expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_copysign (tree callexp)
+{
+ tree to = CALL_EXPR_ARG (callexp, 0);
+ tree from = CALL_EXPR_ARG (callexp, 1);
+ tree type = TREE_TYPE (to);
+
+ /* Convert parameters to the same type. Prefer the first parameter unless it
+ is an integral type. */
+ if (INTEGRAL_TYPE_P (type))
+ {
+ to = fold_convert (TREE_TYPE (from), to);
+ type = TREE_TYPE (to);
+ }
+ else
+ from = fold_convert (type, from);
+
+ /* Which variant of __builtin_copysign* should we call? */
+ tree builtin = mathfn_built_in (type, BUILT_IN_COPYSIGN);
+ gcc_assert (builtin != NULL_TREE);
+
+ return call_builtin_fn (callexp, DECL_FUNCTION_CODE (builtin), 2,
+ to, from);
+}
+
+/* Expand a front-end intrinsic call to pow(). This takes two arguments, the
+ signature to which can be either:
+
+ float pow (float base, T exponent);
+ double pow (double base, T exponent);
+ real pow (real base, T exponent);
+
+ This computes the value of BASE raised to the power of EXPONENT.
+ The original call expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_pow (tree callexp)
+{
+ tree base = CALL_EXPR_ARG (callexp, 0);
+ tree exponent = CALL_EXPR_ARG (callexp, 1);
+ tree exptype = TREE_TYPE (exponent);
+
+ /* Which variant of __builtin_pow* should we call? */
+ built_in_function code = SCALAR_FLOAT_TYPE_P (exptype) ? BUILT_IN_POW
+ : INTEGRAL_TYPE_P (exptype) ? BUILT_IN_POWI
+ : END_BUILTINS;
+ gcc_assert (code != END_BUILTINS);
+
+ tree builtin = mathfn_built_in (TREE_TYPE (base), code);
+ gcc_assert (builtin != NULL_TREE);
+
+ return call_builtin_fn (callexp, DECL_FUNCTION_CODE (builtin), 2,
+ base, exponent);
+}
+
+/* Expand a front-end intrinsic call to va_arg(). This takes either one or two
+ arguments, the signature to which can be either:
+
+ T va_arg(T) (ref va_list ap);
+ void va_arg(T) (va_list ap, ref T parmn);
+
+ This retrieves the next variadic parameter that is type T from the given
+ va_list. If also given, store the value into parmn, otherwise return it.
+ The original call expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_vaarg (tree callexp)
+{
+ tree ap = CALL_EXPR_ARG (callexp, 0);
+ tree parmn = NULL_TREE;
+ tree type;
+
+ STRIP_NOPS (ap);
+
+ if (call_expr_nargs (callexp) == 1)
+ type = TREE_TYPE (callexp);
+ else
+ {
+ parmn = CALL_EXPR_ARG (callexp, 1);
+ STRIP_NOPS (parmn);
+ gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
+ parmn = TREE_OPERAND (parmn, 0);
+ type = TREE_TYPE (parmn);
+ }
+
+ /* (T) VA_ARG_EXP<ap>; */
+ tree exp = build1 (VA_ARG_EXPR, type, ap);
+
+ /* parmn = (T) VA_ARG_EXP<ap>; */
+ if (parmn != NULL_TREE)
+ exp = modify_expr (parmn, exp);
+
+ return exp;
+}
+
+/* Expand a front-end intrinsic call to va_start(), which takes two arguments,
+ the signature to which is:
+
+ void va_start(T) (out va_list ap, ref T parmn);
+
+ This initializes the va_list type, where parmn should be the last named
+ parameter. The original call expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_vastart (tree callexp)
+{
+ tree ap = CALL_EXPR_ARG (callexp, 0);
+ tree parmn = CALL_EXPR_ARG (callexp, 1);
+
+ STRIP_NOPS (ap);
+ STRIP_NOPS (parmn);
+
+ /* The va_list argument should already have its address taken. The second
+ argument, however, is inout and that needs to be fixed to prevent a
+ warning. Could be casting, so need to check type too? */
+ gcc_assert (TREE_CODE (ap) == ADDR_EXPR && TREE_CODE (parmn) == ADDR_EXPR);
+
+ /* Assuming nobody tries to change the return type. */
+ parmn = TREE_OPERAND (parmn, 0);
+
+ return call_builtin_fn (callexp, BUILT_IN_VA_START, 2, ap, parmn);
+}
+
+/* Expand a front-end instrinsic call to INTRINSIC, which is either a call to
+ adds(), addu(), subs(), subu(), negs(), muls(), or mulu(). These intrinsics
+ expect to take two or three arguments, the signature to which can be either:
+
+ int adds (int x, int y, ref bool overflow);
+ long adds (long x, long y, ref bool overflow);
+ int negs (int x, ref bool overflow);
+ long negs (long x, ref bool overflow);
+
+ This performs an operation on two signed or unsigned integers, checking for
+ overflow. The overflow is sticky, meaning that a sequence of operations
+ can be done and overflow need only be checked at the end. The original call
+ expression is held in CALLEXP. */
+
+static tree
+expand_intrinsic_checkedint (intrinsic_code intrinsic, tree callexp)
+{
+ tree type = TREE_TYPE (callexp);
+ tree x;
+ tree y;
+ tree overflow;
+
+ /* The negs() intrinsic gets turned into SUB_OVERFLOW (0, y). */
+ if (intrinsic == INTRINSIC_NEGS)
+ {
+ x = fold_convert (type, integer_zero_node);
+ y = CALL_EXPR_ARG (callexp, 0);
+ overflow = CALL_EXPR_ARG (callexp, 1);
+ }
+ else
+ {
+ x = CALL_EXPR_ARG (callexp, 0);
+ y = CALL_EXPR_ARG (callexp, 1);
+ overflow = CALL_EXPR_ARG (callexp, 2);
+ }
+
+ /* Which variant of *_OVERFLOW should we generate? */
+ internal_fn icode = (intrinsic == INTRINSIC_ADDS) ? IFN_ADD_OVERFLOW
+ : (intrinsic == INTRINSIC_SUBS) ? IFN_SUB_OVERFLOW
+ : (intrinsic == INTRINSIC_MULS) ? IFN_MUL_OVERFLOW
+ : (intrinsic == INTRINSIC_NEGS) ? IFN_SUB_OVERFLOW
+ : IFN_LAST;
+ gcc_assert (icode != IFN_LAST);
+
+ tree result
+ = build_call_expr_internal_loc (EXPR_LOCATION (callexp), icode,
+ build_complex_type (type), 2, x, y);
+
+ STRIP_NOPS (overflow);
+ overflow = build_deref (overflow);
+
+ /* Assign returned result to overflow parameter, however if overflow is
+ already true, maintain its value. */
+ type = TREE_TYPE (overflow);
+ result = save_expr (result);
+
+ tree exp = fold_build2 (BIT_IOR_EXPR, type, overflow,
+ fold_convert (type, imaginary_part (result)));
+ exp = modify_expr (overflow, exp);
+
+ /* Return the value of result. */
+ return compound_expr (exp, real_part (result));
+}
+
+/* Expand a front-end instrinsic call to volatileLoad(). This takes one
+ argument, the signature to which can be either:
+
+ ubyte volatileLoad (ubyte* ptr);
+ ushort volatileLoad (ushort* ptr);
+ uint volatileLoad (uint* ptr);
+ ulong volatileLoad (ulong* ptr);
+
+ This reads a value from the memory location indicated by ptr. Calls to
+ them are be guaranteed to not be removed (such as during DCE) or reordered
+ in the same thread. The original call expression is held in CALLEXP. */
+
+static tree
+expand_volatile_load (tree callexp)
+{
+ tree ptr = CALL_EXPR_ARG (callexp, 0);
+ tree ptrtype = TREE_TYPE (ptr);
+ gcc_assert (POINTER_TYPE_P (ptrtype));
+
+ /* (T) *(volatile T *) ptr; */
+ tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
+ tree result = indirect_ref (type, ptr);
+ TREE_THIS_VOLATILE (result) = 1;
+
+ return result;
+}
+
+/* Expand a front-end instrinsic call to volatileStore(). This takes two
+ arguments, the signature to which can be either:
+
+ void volatileStore (ubyte* ptr, ubyte value);
+ void volatileStore (ushort* ptr, ushort value);
+ void volatileStore (uint* ptr, uint value);
+ void volatileStore (ulong* ptr, ulong value);
+
+ This writes a value to the memory location indicated by ptr. Calls to
+ them are be guaranteed to not be removed (such as during DCE) or reordered
+ in the same thread. The original call expression is held in CALLEXP. */
+
+static tree
+expand_volatile_store (tree callexp)
+{
+ tree ptr = CALL_EXPR_ARG (callexp, 0);
+ tree ptrtype = TREE_TYPE (ptr);
+ gcc_assert (POINTER_TYPE_P (ptrtype));
+
+ /* (T) *(volatile T *) ptr; */
+ tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
+ tree result = indirect_ref (type, ptr);
+ TREE_THIS_VOLATILE (result) = 1;
+
+ /* (*(volatile T *) ptr) = value; */
+ tree value = CALL_EXPR_ARG (callexp, 1);
+ return modify_expr (result, value);
+}
+
+/* If CALLEXP is for an intrinsic , expand and return inlined compiler
+ generated instructions. Most map directly to GCC builtins, others
+ require a little extra work around them. */
+
+tree
+maybe_expand_intrinsic (tree callexp)
+{
+ tree callee = CALL_EXPR_FN (callexp);
+
+ if (TREE_CODE (callee) == ADDR_EXPR)
+ callee = TREE_OPERAND (callee, 0);
+
+ if (TREE_CODE (callee) != FUNCTION_DECL)
+ return callexp;
+
+ /* Don't expand CTFE-only intrinsics outside of semantic processing. */
+ if (DECL_BUILT_IN_CTFE (callee) && !doing_semantic_analysis_p)
+ return callexp;
+
+ intrinsic_code intrinsic = DECL_INTRINSIC_CODE (callee);
+ built_in_function code;
+
+ switch (intrinsic)
+ {
+ case INTRINSIC_NONE:
+ return callexp;
+
+ case INTRINSIC_BSF:
+ return expand_intrinsic_bsf (callexp);
+
+ case INTRINSIC_BSR:
+ return expand_intrinsic_bsr (callexp);
+
+ case INTRINSIC_BT:
+ case INTRINSIC_BTC:
+ case INTRINSIC_BTR:
+ case INTRINSIC_BTS:
+ return expand_intrinsic_bt (intrinsic, callexp);
+
+ case INTRINSIC_BSWAP:
+ return expand_intrinsic_bswap (callexp);
+
+ case INTRINSIC_POPCNT:
+ return expand_intrinsic_popcnt (callexp);
+
+ case INTRINSIC_COS:
+ return call_builtin_fn (callexp, BUILT_IN_COSL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_SIN:
+ return call_builtin_fn (callexp, BUILT_IN_SINL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_RNDTOL:
+ /* Not sure if llroundl stands as a good replacement for the
+ expected behavior of rndtol. */
+ return call_builtin_fn (callexp, BUILT_IN_LLROUNDL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_SQRT:
+ case INTRINSIC_SQRTF:
+ case INTRINSIC_SQRTL:
+ return expand_intrinsic_sqrt (intrinsic, callexp);
+
+ case INTRINSIC_LDEXP:
+ return call_builtin_fn (callexp, BUILT_IN_LDEXPL, 2,
+ CALL_EXPR_ARG (callexp, 0),
+ CALL_EXPR_ARG (callexp, 1));
+
+ case INTRINSIC_FABS:
+ return call_builtin_fn (callexp, BUILT_IN_FABSL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_RINT:
+ return call_builtin_fn (callexp, BUILT_IN_RINTL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_TAN:
+ return call_builtin_fn (callexp, BUILT_IN_TANL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_ISNAN:
+ return call_builtin_fn (callexp, BUILT_IN_ISNAN, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_ISINFINITY:
+ return call_builtin_fn (callexp, BUILT_IN_ISINF, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_ISFINITE:
+ return call_builtin_fn (callexp, BUILT_IN_ISFINITE, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_EXP:
+ return call_builtin_fn (callexp, BUILT_IN_EXPL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_EXPM1:
+ return call_builtin_fn (callexp, BUILT_IN_EXPM1L, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_EXP2:
+ return call_builtin_fn (callexp, BUILT_IN_EXP2L, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_LOG:
+ return call_builtin_fn (callexp, BUILT_IN_LOGL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_LOG2:
+ return call_builtin_fn (callexp, BUILT_IN_LOG2L, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_LOG10:
+ return call_builtin_fn (callexp, BUILT_IN_LOG10L, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_ROUND:
+ return call_builtin_fn (callexp, BUILT_IN_ROUNDL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_FLOORF:
+ case INTRINSIC_FLOOR:
+ case INTRINSIC_FLOORL:
+ code = (intrinsic == INTRINSIC_FLOOR) ? BUILT_IN_FLOOR
+ : (intrinsic == INTRINSIC_FLOORF) ? BUILT_IN_FLOORF
+ : BUILT_IN_FLOORL;
+ return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_CEILF:
+ case INTRINSIC_CEIL:
+ case INTRINSIC_CEILL:
+ code = (intrinsic == INTRINSIC_CEIL) ? BUILT_IN_CEIL
+ : (intrinsic == INTRINSIC_CEILF) ? BUILT_IN_CEILF
+ : BUILT_IN_CEILL;
+ return call_builtin_fn (callexp, code, 1, CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_TRUNC:
+ return call_builtin_fn (callexp, BUILT_IN_TRUNCL, 1,
+ CALL_EXPR_ARG (callexp, 0));
+
+ case INTRINSIC_FMIN:
+ return call_builtin_fn (callexp, BUILT_IN_FMINL, 2,
+ CALL_EXPR_ARG (callexp, 0),
+ CALL_EXPR_ARG (callexp, 1));
+
+ case INTRINSIC_FMAX:
+ return call_builtin_fn (callexp, BUILT_IN_FMAXL, 2,
+ CALL_EXPR_ARG (callexp, 0),
+ CALL_EXPR_ARG (callexp, 1));
+
+ case INTRINSIC_COPYSIGN:
+ return expand_intrinsic_copysign (callexp);
+
+ case INTRINSIC_POW:
+ return expand_intrinsic_pow (callexp);
+
+ case INTRINSIC_FMA:
+ return call_builtin_fn (callexp, BUILT_IN_FMAL, 3,
+ CALL_EXPR_ARG (callexp, 0),
+ CALL_EXPR_ARG (callexp, 1),
+ CALL_EXPR_ARG (callexp, 2));
+
+ case INTRINSIC_VA_ARG:
+ case INTRINSIC_C_VA_ARG:
+ return expand_intrinsic_vaarg (callexp);
+
+ case INTRINSIC_VASTART:
+ return expand_intrinsic_vastart (callexp);
+
+ case INTRINSIC_ADDS:
+ case INTRINSIC_SUBS:
+ case INTRINSIC_MULS:
+ case INTRINSIC_NEGS:
+ return expand_intrinsic_checkedint (intrinsic, callexp);
+
+ case INTRINSIC_VLOAD:
+ return expand_volatile_load (callexp);
+
+ case INTRINSIC_VSTORE:
+ return expand_volatile_store (callexp);
+
+ default:
+ gcc_unreachable ();
+ }
+}
diff --git a/gcc/d/intrinsics.def b/gcc/d/intrinsics.def
new file mode 100644
index 0000000..c8ad81b
--- /dev/null
+++ b/gcc/d/intrinsics.def
@@ -0,0 +1,154 @@
+/* intrinsics.def -- Definitions for D compiler intrinsics.
+ Copyright (C) 2014-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* DEF_D_INTRINSIC (CODE, ALIAS, NAME, MODULE, DECO, CTFE)
+ CODE The enum code used to refer to this intrinsic.
+ ALIAS The enum code used to reference the function DECL_FUNCTION_CODE,
+ if there are multiple modules or decos for a single intrinsic,
+ they would all refer to this code.
+ NAME The name of this intrinsic as a string.
+ MODULE The name of the module which the intrinsic belongs to as a string.
+ DECO The function signature decoration of the intrinsic.
+ CTFE True if the function is only handled as a built-in during CTFE,
+ otherwise the runtime implementation is used.
+
+ Used for declaring internally recognized functions that either map to a
+ GCC builtin, or are specially handled by the compiler. */
+
+/* A D built-in that has no runtime implementation. */
+#define DEF_D_BUILTIN(C, A, N, M, D) \
+ DEF_D_INTRINSIC (C, A, N, M, D, false)
+
+/* A D built-in that is specially recognized only during CTFE. */
+#define DEF_CTFE_BUILTIN(C, A, N, M, D) \
+ DEF_D_INTRINSIC (C, A, N, M, D, true)
+
+DEF_D_BUILTIN (NONE, NONE, 0, 0, 0)
+
+/* core.bitop intrinsics. */
+
+DEF_D_BUILTIN (BSF, BSF, "bsf", "core.bitop", "FNaNbNiNfkZi")
+DEF_D_BUILTIN (BSR, BSR, "bsr", "core.bitop", "FNaNbNiNfkZi")
+DEF_D_BUILTIN (BT, BT, "bt", "core.bitop", "FNaNbNixPkkZi")
+DEF_D_BUILTIN (BTC, BTC, "btc", "core.bitop", "FNaNbNiPkkZi")
+DEF_D_BUILTIN (BTR, BTR, "btr", "core.bitop", "FNaNbNiPkkZi")
+DEF_D_BUILTIN (BTS, BTS, "bts", "core.bitop", "FNaNbNiPkkZi")
+DEF_D_BUILTIN (BSF64, BSF, "bsf", "core.bitop", "FNaNbNiNfmZi")
+DEF_D_BUILTIN (BSR64, BSR, "bsr", "core.bitop", "FNaNbNiNfmZi")
+DEF_D_BUILTIN (BT64, BT, "bt", "core.bitop", "FNaNbNixPmmZi")
+DEF_D_BUILTIN (BTC64, BTC, "btc", "core.bitop", "FNaNbNiPmmZi")
+DEF_D_BUILTIN (BTR64, BTR, "btr", "core.bitop", "FNaNbNiPmmZi")
+DEF_D_BUILTIN (BTS64, BTS, "bts", "core.bitop", "FNaNbNiPmmZi")
+DEF_D_BUILTIN (BSWAP, BSWAP, "bswap", "core.bitop", "FNaNbNiNfkZk")
+DEF_D_BUILTIN (BSWAP64, BSWAP, "bswap", "core.bitop", "FNaNbNiNfmZm")
+DEF_D_BUILTIN (POPCNT, POPCNT, "popcnt", "core.bitop", "FNaNbNiNfkZi")
+DEF_D_BUILTIN (POPCNT64, POPCNT, "popcnt", "core.bitop", "FNaNbNiNfmZi")
+DEF_D_BUILTIN (VLOAD, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPhZh")
+DEF_D_BUILTIN (VLOAD16, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPtZt")
+DEF_D_BUILTIN (VLOAD32, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPkZk")
+DEF_D_BUILTIN (VLOAD64, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPmZm")
+DEF_D_BUILTIN (VSTORE, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPhhZv")
+DEF_D_BUILTIN (VSTORE16, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPttZv")
+DEF_D_BUILTIN (VSTORE32, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPkkZv")
+DEF_D_BUILTIN (VSTORE64, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPmmZv")
+
+/* core.checkedint intrinsics. */
+
+DEF_D_BUILTIN (ADDS, ADDS, "adds", "core.checkedint", "FNaNbNiNfiiKbZi")
+DEF_D_BUILTIN (ADDSL, ADDS, "adds", "core.checkedint", "FNaNbNiNfllKbZl")
+DEF_D_BUILTIN (ADDU, ADDS, "addu", "core.checkedint", "FNaNbNiNfkkKbZk")
+DEF_D_BUILTIN (ADDUL, ADDS, "addu", "core.checkedint", "FNaNbNiNfmmKbZm")
+DEF_D_BUILTIN (SUBS, SUBS, "subs", "core.checkedint", "FNaNbNiNfiiKbZi")
+DEF_D_BUILTIN (SUBSL, SUBS, "subs", "core.checkedint", "FNaNbNiNfllKbZl")
+DEF_D_BUILTIN (SUBU, SUBS, "subu", "core.checkedint", "FNaNbNiNfkkKbZk")
+DEF_D_BUILTIN (SUBUL, SUBS, "subu", "core.checkedint", "FNaNbNiNfmmKbZm")
+DEF_D_BUILTIN (MULS, MULS, "muls", "core.checkedint", "FNaNbNiNfiiKbZi")
+DEF_D_BUILTIN (MULSL, MULS, "muls", "core.checkedint", "FNaNbNiNfllKbZl")
+DEF_D_BUILTIN (MULU, MULS, "mulu", "core.checkedint", "FNaNbNiNfkkKbZk")
+DEF_D_BUILTIN (MULUI, MULS, "mulu", "core.checkedint", "FNaNbNiNfmkKbZm")
+DEF_D_BUILTIN (MULUL, MULS, "mulu", "core.checkedint", "FNaNbNiNfmmKbZm")
+DEF_D_BUILTIN (NEGS, NEGS, "negs", "core.checkedint", "FNaNbNiNfiKbZi")
+DEF_D_BUILTIN (NEGSL, NEGS, "negs", "core.checkedint", "FNaNbNiNflKbZl")
+
+/* core.math intrinsics. */
+
+DEF_D_BUILTIN (COS, COS, "cos", "core.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (FABS, FABS, "fabs", "core.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (LDEXP, LDEXP, "ldexp", "core.math", "FNaNbNiNfeiZe")
+DEF_D_BUILTIN (RINT, RINT, "rint", "core.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (RNDTOL, RNDTOL, "rndtol", "core.math", "FNaNbNiNfeZl")
+DEF_D_BUILTIN (SIN, SIN, "sin", "core.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (SQRTF, SQRTF, "sqrt", "core.math", "FNaNbNiNffZf")
+DEF_D_BUILTIN (SQRT, SQRT, "sqrt", "core.math", "FNaNbNiNfdZd")
+DEF_D_BUILTIN (SQRTL, SQRTL, "sqrt", "core.math", "FNaNbNiNfeZe")
+
+/* std.math intrinsics. */
+
+DEF_D_BUILTIN (STD_COS, COS, "cos", "std.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (STD_FABS, FABS, "fabs", "std.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (STD_LDEXP, LDEXP, "ldexp", "std.math", "FNaNbNiNfeiZe")
+DEF_D_BUILTIN (STD_RINT, RINT, "rint", "std.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (STD_RNDTOL, RNDTOL, "rndtol", "std.math", "FNaNbNiNfeZl")
+DEF_D_BUILTIN (STD_SIN, SIN, "sin", "std.math", "FNaNbNiNfeZe")
+DEF_D_BUILTIN (STD_SQRTF, SQRTF, "sqrt", "std.math", "FNaNbNiNffZf")
+DEF_D_BUILTIN (STD_SQRT, SQRT, "sqrt", "std.math", "FNaNbNiNfdZd")
+DEF_D_BUILTIN (STD_SQRTL, SQRTL, "sqrt", "std.math", "FNaNbNiNfeZe")
+
+DEF_CTFE_BUILTIN (TAN, TAN, "tan", "std.math", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (ISNAN, ISNAN, "isNaN", "std.math", "FNaNbNiNeI1XZb")
+DEF_CTFE_BUILTIN (ISINFINITY, ISINFINITY, "isInfinity", "std.math",
+ "FNaNbNiNeI1XZb")
+DEF_CTFE_BUILTIN (ISFINITE, ISFINITE, "isFinite", "std.math", "FNaNbNiNeI1XZb")
+
+DEF_CTFE_BUILTIN (EXP, EXP, "exp", "std.math", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (EXPM1, EXPM1, "expm1", "std.math", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (EXP2, EXP2, "exp2", "std.math", "FNaNbNiNeeZe")
+
+DEF_CTFE_BUILTIN (LOG, LOG, "log", "std.math", "FNaNbNiNfeZe")
+DEF_CTFE_BUILTIN (LOG2, LOG2, "log2", "std.math", "FNaNbNiNfeZe")
+DEF_CTFE_BUILTIN (LOG10, LOG10, "log10", "std.math", "FNaNbNiNfeZe")
+
+DEF_CTFE_BUILTIN (ROUND, ROUND, "round", "std.math", "FNbNiNeeZe")
+DEF_CTFE_BUILTIN (FLOORF, FLOORF, "floor", "std.math", "FNaNbNiNefZf")
+DEF_CTFE_BUILTIN (FLOOR, FLOOR, "floor", "std.math", "FNaNbNiNedZd")
+DEF_CTFE_BUILTIN (FLOORL, FLOORL, "floor", "std.math", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (CEILF, CEILF, "ceil", "std.math", "FNaNbNiNefZf")
+DEF_CTFE_BUILTIN (CEIL, CEIL, "ceil", "std.math", "FNaNbNiNedZd")
+DEF_CTFE_BUILTIN (CEILL, CEILL, "ceil", "std.math", "FNaNbNiNeeZe")
+
+DEF_CTFE_BUILTIN (TRUNC, TRUNC, "trunc", "std.math", "FNbNiNeeZe")
+DEF_CTFE_BUILTIN (FMIN, FMIN, "fmin", "std.math", "FNaNbNiNfeeZe")
+DEF_CTFE_BUILTIN (FMAX, FMAX, "fmax", "std.math", "FNaNbNiNfeeZe")
+DEF_CTFE_BUILTIN (COPYSIGN, COPYSIGN, "copysign", "std.math",
+ "FNaNbNiNeI1RI1XZI1R")
+DEF_CTFE_BUILTIN (COPYSIGNI, COPYSIGN, "copysign", "std.math",
+ "FNaNbNiNeI1XI1RZI1R")
+
+DEF_CTFE_BUILTIN (POW, POW, "pow", "std.math", "FNaNbNiNeI1FI1GZ@")
+DEF_CTFE_BUILTIN (FMA, FMA, "fma", "std.math", "FNaNbNiNfeeeZe")
+
+/* core.stdc.stdarg intrinsics. */
+
+DEF_D_BUILTIN (VA_ARG, VA_ARG, "va_arg", "core.stdc.stdarg",
+ "FKI7va_listKI1TZv")
+DEF_D_BUILTIN (C_VA_ARG, C_VA_ARG, "va_arg", "core.stdc.stdarg",
+ "FKI7va_listZI1T")
+DEF_D_BUILTIN (VASTART, VASTART, "va_start", "core.stdc.stdarg",
+ "FJI7va_listKI1TZv")
+
+#undef DEF_D_BUILTIN
+#undef DEF_CTFE_BUILTIN
diff --git a/gcc/d/lang-specs.h b/gcc/d/lang-specs.h
new file mode 100644
index 0000000..479fcca
--- /dev/null
+++ b/gcc/d/lang-specs.h
@@ -0,0 +1,29 @@
+/* lang-specs.h -- GCC driver specs for D frontend.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* This is the contribution to the `default_compilers' array in gcc.c
+ for the D language. */
+
+{".d", "@d", 0, 1, 0 },
+{".dd", "@d", 0, 1, 0 },
+{".di", "@d", 0, 1, 0 },
+{"@d",
+ "%{!E:d21 %i %(cc1_options) %I %{nostdinc*} %{i*} %{I*} %{J*} \
+ %{H} %{Hd*} %{Hf*} %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \
+ %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} \
+ %{X:-Xf %b.json} %{Xf*} \
+ %{v} %{!fsyntax-only:%(invoke_as)}}", 0, 1, 0 },
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
new file mode 100644
index 0000000..892e65b
--- /dev/null
+++ b/gcc/d/lang.opt
@@ -0,0 +1,346 @@
+; lang.opt -- Options for the D front end.
+; Copyright (C) 2006-2018 Free Software Foundation, Inc.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3. If not see
+; <http://www.gnu.org/licenses/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+D
+
+-dependencies
+D Alias(M)
+; Documented in C
+
+-print-missing-file-dependencies
+D Alias(MG)
+; Documented in C
+
+-user-dependencies
+D Alias(MM)
+; Documented in C
+
+-write-dependencies
+D NoDriverArg Separate Alias(MD)
+; Documented in C
+
+-write-user-dependencies
+D NoDriverArg Separate Alias(MMD)
+; Documented in C
+
+H
+D
+; Different from documented use in C.
+
+Hd
+D Joined Separate
+-Hd <dir> Write D interface files to directory <dir>.
+
+Hf
+D Joined Separate
+-Hf <file> Write D interface to <file>.
+
+I
+D Joined Separate
+; Documented in C
+
+J
+D Joined Separate
+; Different from documented use in Fortran.
+
+M
+D
+; Documented in C
+
+MD
+D Separate NoDriverArg
+; Documented in C
+
+MF
+D Joined Separate
+; Documented in C
+
+MG
+D
+; Documented in C
+
+MM
+D
+; Documented in C
+
+MMD
+D Separate NoDriverArg
+; Documented in C
+
+MP
+D
+; Documented in C
+
+MT
+D Joined Separate
+; Documented in C
+
+MQ
+D Joined Separate
+; Documented in C
+
+Waddress
+D Warning Var(warn_address)
+; Documented in C
+
+Wall
+D
+; Documented in C
+
+Walloca
+D
+; Documented in C
+
+Walloca-larger-than=
+D
+; Documented in C
+
+Wno-alloca-larger-than
+D
+; Documented in C
+
+Wcast-result
+D Warning Var(warn_cast_result)
+Warn about casts that will produce a null result.
+
+Wdeprecated
+D
+; Documented in C
+
+Werror
+D
+; Documented in common.opt
+
+Wspeculative
+D
+Warn from speculative compiles such as __traits(compiles).
+
+Wtemplates
+D
+; Documented in C
+
+Wunknown-pragmas
+D LangEnabledBy(D, Wall)
+; Documented in C
+
+X
+D
+Generate JSON file.
+
+Xf
+D Joined Separate
+-Xf <file> Write JSON output to the given <file>.
+
+debuglib=
+Driver Joined
+Debug library to use instead of phobos.
+
+defaultlib=
+Driver Joined
+Default library to use instead of phobos.
+
+-verbose
+D Alias(v)
+
+fall-instantiations
+D
+Generate code for all template instantiations.
+
+fassert
+D Var(flag_assert)
+Generate code for assert contracts.
+
+fbounds-check
+D
+; Documented in common.opt
+
+fbounds-check=
+D Joined RejectNegative Enum(bounds_check) Var(flag_bounds_check)
+-fbounds-check=[on|safeonly|off] Turn array bounds checks on, in @safe code only, or off.
+
+Enum
+Name(bounds_check) Type(int) UnknownError(unknown array bounds setting %qs)
+
+EnumValue
+Enum(bounds_check) String(off) Value(0)
+
+EnumValue
+Enum(bounds_check) String(safeonly) Value(1)
+
+EnumValue
+Enum(bounds_check) String(on) Value(2)
+
+fbuiltin
+D Var(flag_no_builtin, 0)
+; Documented in C
+
+fdebug
+D
+Compile in debug code.
+
+fdebug=
+D Joined RejectNegative
+-fdebug=<level|ident> Compile in debug code, code <= <level>, or code identified by <ident>.
+
+fdoc
+D
+Generate documentation.
+
+fdoc-dir=
+D Joined RejectNegative
+-fdoc-dir=<dir> Write documentation file to directory <dir>.
+
+fdoc-file=
+D Joined RejectNegative
+-fdoc-file=<file> Write documentation to <file>.
+
+fdoc-inc=
+D Joined RejectNegative
+-fdoc-inc=<file> Include a Ddoc macro <file>.
+
+fdump-d-original
+D
+Display the frontend AST after parsing and semantic passes.
+
+fignore-unknown-pragmas
+D
+Ignore unsupported pragmas.
+
+finvariants
+D Var(flag_invariants)
+Generate code for class invariant contracts.
+
+fmain
+D RejectNegative
+Generate a default D main() function when compiling.
+
+fmodule-file=
+D Joined RejectNegative
+-fmodule-file=<package.module>=<filespec> use <filespec> as source file for <package.module>.
+
+fmoduleinfo
+D
+Generate ModuleInfo struct for output module.
+
+fonly=
+D Joined RejectNegative
+Process all modules specified on the command line, but only generate code for the module specified by the argument.
+
+fpostconditions
+D Var(flag_postconditions)
+Generate code for postcondition contracts.
+
+fpreconditions
+D Var(flag_preconditions)
+Generate code for precondition contracts.
+
+frelease
+D
+Compile release version.
+
+fswitch-errors
+D Var(flag_switch_errors)
+Generate code for switches without a default case.
+
+ftransition=all
+D RejectNegative
+List information on all language changes.
+
+ftransition=checkimports
+D RejectNegative
+Give deprecation messages about -ftransition=import anomalies.
+
+ftransition=complex
+D RejectNegative
+List all usages of complex or imaginary types.
+
+ftransition=dip1000
+D RejectNegative
+Implement DIP1000: Scoped pointers (experimental).
+
+ftransition=dip25
+D RejectNegative
+Implement DIP25: Sealed references (experimental).
+
+ftransition=field
+D RejectNegative
+List all non-mutable fields which occupy an object instance.
+
+ftransition=import
+D RejectNegative
+Revert to single phase name lookup.
+
+ftransition=nogc
+D RejectNegative
+List all hidden GC allocations.
+
+ftransition=tls
+D RejectNegative
+List all variables going into thread local storage.
+
+funittest
+D
+Compile in unittest code.
+
+fversion=
+D Joined RejectNegative
+-fversion=<level|ident> Compile in version code >= <level> or identified by <ident>.
+
+fweak
+D Var(flag_weak) Init(1)
+Emit common-like symbols as weak symbols.
+
+imultilib
+D Joined Separate
+; Documented in C
+
+iprefix
+D Joined Separate
+; Documented in C
+
+isysroot
+D Joined Separate
+; Documented in C
+
+isystem
+D Joined Separate
+; Documented in C
+
+nophoboslib
+Driver
+Do not link the standard D library in the compilation.
+
+nostdinc
+D
+; Documented in C
+
+static-libphobos
+Driver
+Link the standard D library statically in the compilation.
+
+shared-libphobos
+Driver
+Link the standard D library dynamically in the compilation.
+
+v
+D
+; Documented in C
diff --git a/gcc/d/longdouble.h b/gcc/d/longdouble.h
new file mode 100644
index 0000000..89fc2b2
--- /dev/null
+++ b/gcc/d/longdouble.h
@@ -0,0 +1,136 @@
+/* longdouble.h -- Definitions of floating-point access for the frontend.
+ Copyright (C) 2015-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_D_LONGDOUBLE_H
+#define GCC_D_LONGDOUBLE_H
+
+struct real_value;
+class Type;
+
+struct longdouble
+{
+public:
+ /* Return the hidden real_value from the longdouble type. */
+ const real_value& rv (void) const
+ { return *(const real_value *) this; }
+
+ real_value& rv (void)
+ { return *(real_value *) this; }
+
+ /* Normalize the value to be the precision supported by target. */
+ longdouble normalize (void);
+
+ /* No constructor to be able to use this class in a union. */
+ template<typename T> longdouble& operator = (T x)
+ { set (x); return *this; }
+
+ /* Lvalue operators. */
+ void set (real_value& d);
+ void set (int32_t d);
+ void set (int64_t d);
+ void set (uint32_t d);
+ void set (uint64_t d);
+ void set (bool d);
+
+ /* Rvalue operators. */
+ bool to_bool () const;
+ int64_t to_int () const;
+ uint64_t to_uint () const;
+
+ operator int32_t (void)
+ { return (int32_t) this->to_int (); }
+
+ operator int64_t (void)
+ { return this->to_int (); }
+
+ operator uint32_t (void)
+ { return (uint32_t) this->to_uint (); }
+
+ operator uint64_t (void)
+ { return this->to_uint (); }
+
+ operator bool (void)
+ { return this->to_bool (); }
+
+ /* Arithmetic operators. */
+ longdouble add (const longdouble& r) const;
+ longdouble sub (const longdouble& r) const;
+ longdouble mul (const longdouble& r) const;
+ longdouble div (const longdouble& r) const;
+ longdouble mod (const longdouble& r) const;
+ longdouble neg () const;
+
+ longdouble operator + (const longdouble& r)
+ { return this->add (r); }
+
+ longdouble operator - (const longdouble& r)
+ { return this->sub (r); }
+
+ longdouble operator * (const longdouble& r)
+ { return this->mul (r); }
+
+ longdouble operator / (const longdouble& r)
+ { return this->div (r); }
+
+ longdouble operator % (const longdouble& r)
+ { return this->mod (r); }
+
+ longdouble operator -()
+ { return this->neg (); }
+
+ /* Comparison operators. */
+ int cmp (const longdouble& t) const;
+ int equals (const longdouble& t) const;
+
+ bool operator < (const longdouble& r)
+ { return this->cmp (r) < 0; }
+
+ bool operator <= (const longdouble& r)
+ { return this->cmp (r) <= 0; }
+
+ bool operator > (const longdouble& r)
+ { return this->cmp (r) > 0; }
+
+ bool operator >= (const longdouble& r)
+ { return this->cmp (r) >= 0; }
+
+ bool operator == (const longdouble& r)
+ { return this->equals (r); }
+
+ bool operator != (const longdouble& r)
+ { return !this->equals (r); }
+
+private:
+ /* Including gcc/real.h presents too many problems, so just
+ statically allocate enough space for REAL_VALUE_TYPE. */
+ long realvalue[(2 + (16 + sizeof (long)) / sizeof (long))];
+};
+
+/* Declared, but "volatile" is not required. */
+typedef longdouble volatile_longdouble;
+
+/* Use ldouble() to explicitly create a longdouble value. */
+template<typename T>
+inline longdouble
+ldouble (T x)
+{
+ longdouble d;
+ d.set (x);
+ return d;
+}
+
+#endif /* GCC_D_LONGDOUBLE_H */
diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc
new file mode 100644
index 0000000..80573e1
--- /dev/null
+++ b/gcc/d/modules.cc
@@ -0,0 +1,853 @@
+/* modules.cc -- D module initialization and termination.
+ Copyright (C) 2013-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/declaration.h"
+#include "dmd/identifier.h"
+#include "dmd/module.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "tm.h"
+#include "function.h"
+#include "cgraph.h"
+#include "stor-layout.h"
+#include "toplev.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+
+
+/* D generates module information to inform the runtime library which modules
+ need some kind of special handling. All `static this()', `static ~this()',
+ and `unittest' functions for a given module are aggregated into a single
+ function - one for each kind - and a pointer to that function is inserted
+ into the ModuleInfo instance for that module.
+
+ Module information for a particular module is indicated with an ABI defined
+ structure derived from ModuleInfo. ModuleInfo is a variably sized struct
+ with two fixed base fields. The first field `flags' determines what
+ information is packed immediately after the record type.
+
+ Like TypeInfo, the runtime library provides the definitions of the ModuleInfo
+ structure, as well as accessors for the variadic fields. So we only define
+ layout compatible POD_structs for ModuleInfo. */
+
+/* The internally represented ModuleInfo and CompilerDSO types. */
+static tree moduleinfo_type;
+static tree compiler_dso_type;
+static tree dso_registry_fn;
+
+/* The DSO slot for use by the druntime implementation. */
+static tree dso_slot_node;
+
+/* For registering and deregistering DSOs with druntime, we have one global
+ constructor and destructor per object that calls _d_dso_registry with the
+ respective DSO record. To ensure that this is only done once, a
+ `dso_initialized' variable is introduced to guard repeated calls. */
+static tree dso_initialized_node;
+
+/* The beginning and end of the `minfo' section. */
+static tree start_minfo_node;
+static tree stop_minfo_node;
+
+/* Record information about module initialization, termination,
+ unit testing, and thread local storage in the compilation. */
+
+struct GTY(()) module_info
+{
+ vec<tree, va_gc> *ctors;
+ vec<tree, va_gc> *dtors;
+ vec<tree, va_gc> *ctorgates;
+
+ vec<tree, va_gc> *sharedctors;
+ vec<tree, va_gc> *shareddtors;
+ vec<tree, va_gc> *sharedctorgates;
+
+ vec<tree, va_gc> *unitTests;
+};
+
+/* These must match the values in libdruntime/object_.d. */
+
+enum module_info_flags
+{
+ MIctorstart = 0x1,
+ MIctordone = 0x2,
+ MIstandalone = 0x4,
+ MItlsctor = 0x8,
+ MItlsdtor = 0x10,
+ MIctor = 0x20,
+ MIdtor = 0x40,
+ MIxgetMembers = 0x80,
+ MIictor = 0x100,
+ MIunitTest = 0x200,
+ MIimportedModules = 0x400,
+ MIlocalClasses = 0x800,
+ MIname = 0x1000
+};
+
+/* The ModuleInfo information structure for the module currently being compiled.
+ Assuming that only ever process one at a time. */
+
+static module_info *current_moduleinfo;
+
+/* The declaration of the current module being compiled. */
+
+static Module *current_module_decl;
+
+/* Static constructors and destructors (not D `static this'). */
+
+static GTY(()) vec<tree, va_gc> *static_ctor_list;
+static GTY(()) vec<tree, va_gc> *static_dtor_list;
+
+/* Returns an internal function identified by IDENT. This is used
+ by both module initialization and dso handlers. */
+
+static FuncDeclaration *
+get_internal_fn (tree ident)
+{
+ Module *mod = current_module_decl;
+ const char *name = IDENTIFIER_POINTER (ident);
+
+ if (!mod)
+ mod = Module::rootModule;
+
+ if (name[0] == '*')
+ {
+ tree s = mangle_internal_decl (mod, name + 1, "FZv");
+ name = IDENTIFIER_POINTER (s);
+ }
+
+ FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid,
+ Identifier::idPool (name));
+ fd->loc = Loc (mod->srcfile->toChars (), 1, 0);
+ fd->parent = mod;
+ fd->protection.kind = PROTprivate;
+ fd->semanticRun = PASSsemantic3done;
+
+ return fd;
+}
+
+/* Generate an internal function identified by IDENT.
+ The function body to add is in EXPR. */
+
+static tree
+build_internal_fn (tree ident, tree expr)
+{
+ FuncDeclaration *fd = get_internal_fn (ident);
+ tree decl = get_symbol_decl (fd);
+
+ tree old_context = start_function (fd);
+ rest_of_decl_compilation (decl, 1, 0);
+ add_stmt (expr);
+ finish_function (old_context);
+
+ /* D static ctors, static dtors, unittests, and the ModuleInfo
+ chain function are always private. */
+ TREE_PUBLIC (decl) = 0;
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ return decl;
+}
+
+/* Build and emit a function identified by IDENT that increments (in order)
+ all variables in GATES, then calls the list of functions in FUNCTIONS. */
+
+static tree
+build_funcs_gates_fn (tree ident, vec<tree, va_gc> *functions,
+ vec<tree, va_gc> *gates)
+{
+ tree expr_list = NULL_TREE;
+
+ /* Increment gates first. */
+ for (size_t i = 0; i < vec_safe_length (gates); i++)
+ {
+ tree decl = (*gates)[i];
+ tree value = build2 (PLUS_EXPR, TREE_TYPE (decl),
+ decl, integer_one_node);
+ tree var_expr = modify_expr (decl, value);
+ expr_list = compound_expr (expr_list, var_expr);
+ }
+
+ /* Call Functions. */
+ for (size_t i = 0; i < vec_safe_length (functions); i++)
+ {
+ tree decl = (*functions)[i];
+ tree call_expr = build_call_expr (decl, 0);
+ expr_list = compound_expr (expr_list, call_expr);
+ }
+
+ if (expr_list)
+ return build_internal_fn (ident, expr_list);
+
+ return NULL_TREE;
+}
+
+/* Return the type for ModuleInfo, create it if it doesn't already exist. */
+
+static tree
+get_moduleinfo_type (void)
+{
+ if (moduleinfo_type)
+ return moduleinfo_type;
+
+ /* Layout of ModuleInfo is:
+ uint flags;
+ uint index; */
+ tree fields = create_field_decl (d_uint_type, NULL, 1, 1);
+ DECL_CHAIN (fields) = create_field_decl (d_uint_type, NULL, 1, 1);
+
+ moduleinfo_type = make_node (RECORD_TYPE);
+ finish_builtin_struct (moduleinfo_type, "ModuleInfo", fields, NULL_TREE);
+
+ return moduleinfo_type;
+}
+
+/* Get the VAR_DECL of the ModuleInfo for DECL. If this does not yet exist,
+ create it. The ModuleInfo decl is used to keep track of constructors,
+ destructors, unittests, members, classes, and imports for the given module.
+ This is used by the D runtime for module initialization and termination. */
+
+static tree
+get_moduleinfo_decl (Module *decl)
+{
+ if (decl->csym)
+ return decl->csym;
+
+ tree ident = mangle_internal_decl (decl, "__ModuleInfo", "Z");
+ tree type = get_moduleinfo_type ();
+
+ decl->csym = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (NULL);
+
+ DECL_CONTEXT (decl->csym) = build_import_decl (decl);
+ /* Not readonly, moduleinit depends on this. */
+ TREE_READONLY (decl->csym) = 0;
+
+ return decl->csym;
+}
+
+/* Return the type for CompilerDSOData, create it if it doesn't exist. */
+
+static tree
+get_compiler_dso_type (void)
+{
+ if (compiler_dso_type)
+ return compiler_dso_type;
+
+ /* Layout of CompilerDSOData is:
+ size_t version;
+ void** slot;
+ ModuleInfo** _minfo_beg;
+ ModuleInfo** _minfo_end;
+ FuncTable* _deh_beg;
+ FuncTable* _deh_end;
+
+ Note, finish_builtin_struct() expects these fields in reverse order. */
+ tree fields = create_field_decl (ptr_type_node, NULL, 1, 1);
+ tree field = create_field_decl (ptr_type_node, NULL, 1, 1);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+
+ field = create_field_decl (build_pointer_type (get_moduleinfo_type ()),
+ NULL, 1, 1);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+ field = create_field_decl (build_pointer_type (get_moduleinfo_type ()),
+ NULL, 1, 1);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+
+ field = create_field_decl (build_pointer_type (ptr_type_node), NULL, 1, 1);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+
+ field = create_field_decl (size_type_node, NULL, 1, 1);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+
+ compiler_dso_type = make_node (RECORD_TYPE);
+ finish_builtin_struct (compiler_dso_type, "CompilerDSOData",
+ fields, NULL_TREE);
+
+ return compiler_dso_type;
+}
+
+/* Returns the _d_dso_registry FUNCTION_DECL. */
+
+static tree
+get_dso_registry_fn (void)
+{
+ if (dso_registry_fn)
+ return dso_registry_fn;
+
+ tree dso_type = get_compiler_dso_type ();
+ tree fntype = build_function_type_list (void_type_node,
+ build_pointer_type (dso_type),
+ NULL_TREE);
+ dso_registry_fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+ get_identifier ("_d_dso_registry"), fntype);
+ TREE_PUBLIC (dso_registry_fn) = 1;
+ DECL_EXTERNAL (dso_registry_fn) = 1;
+
+ return dso_registry_fn;
+}
+
+/* Depending on CTOR_P, builds and emits eiter a constructor or destructor
+ calling _d_dso_registry if `dso_initialized' is `false' in a constructor
+ or `true' in a destructor. */
+
+static tree
+build_dso_cdtor_fn (bool ctor_p)
+{
+ const char *name = ctor_p ? GDC_PREFIX ("dso_ctor") : GDC_PREFIX ("dso_dtor");
+ tree condition = ctor_p ? boolean_true_node : boolean_false_node;
+
+ /* Declaration of dso_ctor/dso_dtor is:
+
+ extern(C) void dso_{c,d}tor (void)
+ {
+ if (dso_initialized != condition)
+ {
+ dso_initialized = condition;
+ CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo};
+ _d_dso_registry (&dso);
+ }
+ }
+ */
+ FuncDeclaration *fd = get_internal_fn (get_identifier (name));
+ tree decl = get_symbol_decl (fd);
+
+ TREE_PUBLIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+ d_comdat_linkage (decl);
+
+ /* Start laying out the body. */
+ tree old_context = start_function (fd);
+ rest_of_decl_compilation (decl, 1, 0);
+
+ /* if (dso_initialized != condition). */
+ tree if_cond = build_boolop (NE_EXPR, dso_initialized_node, condition);
+
+ /* dso_initialized = condition; */
+ tree expr_list = modify_expr (dso_initialized_node, condition);
+
+ /* CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo}; */
+ tree dso_type = get_compiler_dso_type ();
+ tree dso = build_local_temp (dso_type);
+
+ vec<constructor_elt, va_gc> *ve = NULL;
+ CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_integer_cst (1, size_type_node));
+ CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (dso_slot_node));
+ CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (start_minfo_node));
+ CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (stop_minfo_node));
+
+ tree assign_expr = modify_expr (dso, build_struct_literal (dso_type, ve));
+ expr_list = compound_expr (expr_list, assign_expr);
+
+ /* _d_dso_registry (&dso); */
+ tree call_expr = build_call_expr (get_dso_registry_fn (), 1,
+ build_address (dso));
+ expr_list = compound_expr (expr_list, call_expr);
+
+ add_stmt (build_vcondition (if_cond, expr_list, void_node));
+ finish_function (old_context);
+
+ return decl;
+}
+
+/* Build a variable used in the dso_registry code identified by NAME,
+ and data type TYPE. The variable always has VISIBILITY_HIDDEN and
+ TREE_PUBLIC flags set. */
+
+static tree
+build_dso_registry_var (const char * name, tree type)
+{
+ tree var = declare_extern_var (get_identifier (name), type);
+ DECL_VISIBILITY (var) = VISIBILITY_HIDDEN;
+ DECL_VISIBILITY_SPECIFIED (var) = 1;
+ return var;
+}
+
+/* Place a reference to the ModuleInfo symbol MINFO for DECL into the
+ `minfo' section. Then create the global ctors/dtors to call the
+ _d_dso_registry function if necessary. */
+
+static void
+register_moduleinfo (Module *decl, tree minfo)
+{
+ gcc_assert (targetm_common.have_named_sections);
+
+ /* Build the ModuleInfo reference, this is done once for every Module. */
+ tree ident = mangle_internal_decl (decl, "__moduleRef", "Z");
+ tree mref = declare_extern_var (ident, ptr_type_node);
+
+ /* Build the initializer and emit. Do not start section with a `.' character
+ so that the linker will provide a __start_ and __stop_ symbol to indicate
+ the start and end address of the section respectively.
+ https://sourceware.org/binutils/docs-2.26/ld/Orphan-Sections.html. */
+ DECL_INITIAL (mref) = build_address (minfo);
+ DECL_EXTERNAL (mref) = 0;
+ DECL_PRESERVE_P (mref) = 1;
+
+ set_decl_section_name (mref, "minfo");
+ d_pushdecl (mref);
+ rest_of_decl_compilation (mref, 1, 0);
+
+ /* Only for the first D module being emitted do we need to generate a static
+ constructor and destructor for. These are only required once per shared
+ library, so it's safe to emit them only once per object file. */
+ static bool first_module = true;
+ if (!first_module)
+ return;
+
+ start_minfo_node = build_dso_registry_var ("__start_minfo", ptr_type_node);
+ rest_of_decl_compilation (start_minfo_node, 1, 0);
+
+ stop_minfo_node = build_dso_registry_var ("__stop_minfo", ptr_type_node);
+ rest_of_decl_compilation (stop_minfo_node, 1, 0);
+
+ /* Declare dso_slot and dso_initialized. */
+ dso_slot_node = build_dso_registry_var (GDC_PREFIX ("dso_slot"),
+ ptr_type_node);
+ DECL_EXTERNAL (dso_slot_node) = 0;
+ d_comdat_linkage (dso_slot_node);
+ rest_of_decl_compilation (dso_slot_node, 1, 0);
+
+ dso_initialized_node = build_dso_registry_var (GDC_PREFIX ("dso_initialized"),
+ boolean_type_node);
+ DECL_EXTERNAL (dso_initialized_node) = 0;
+ d_comdat_linkage (dso_initialized_node);
+ rest_of_decl_compilation (dso_initialized_node, 1, 0);
+
+ /* Declare dso_ctor() and dso_dtor(). */
+ tree dso_ctor = build_dso_cdtor_fn (true);
+ vec_safe_push (static_ctor_list, dso_ctor);
+
+ tree dso_dtor = build_dso_cdtor_fn (false);
+ vec_safe_push (static_dtor_list, dso_dtor);
+
+ first_module = false;
+}
+
+/* Convenience function for layout_moduleinfo_fields. Adds a field of TYPE to
+ the moduleinfo record at OFFSET, incrementing the offset to the next field
+ position. No alignment is taken into account, all fields are packed. */
+
+static void
+layout_moduleinfo_field (tree type, tree rec_type, HOST_WIDE_INT& offset)
+{
+ tree field = create_field_decl (type, NULL, 1, 1);
+ insert_aggregate_field (rec_type, field, offset);
+ offset += int_size_in_bytes (type);
+}
+
+/* Layout fields that immediately come after the moduleinfo TYPE for DECL.
+ Data relating to the module is packed into the type on an as-needed
+ basis, this is done to keep its size to a minimum. */
+
+static tree
+layout_moduleinfo_fields (Module *decl, tree type)
+{
+ HOST_WIDE_INT offset = int_size_in_bytes (type);
+ type = copy_aggregate_type (type);
+
+ /* First fields added are all the function pointers. */
+ if (decl->sctor)
+ layout_moduleinfo_field (ptr_type_node, type, offset);
+
+ if (decl->sdtor)
+ layout_moduleinfo_field (ptr_type_node, type, offset);
+
+ if (decl->ssharedctor)
+ layout_moduleinfo_field (ptr_type_node, type, offset);
+
+ if (decl->sshareddtor)
+ layout_moduleinfo_field (ptr_type_node, type, offset);
+
+ if (decl->findGetMembers ())
+ layout_moduleinfo_field (ptr_type_node, type, offset);
+
+ if (decl->sictor)
+ layout_moduleinfo_field (ptr_type_node, type, offset);
+
+ if (decl->stest)
+ layout_moduleinfo_field (ptr_type_node, type, offset);
+
+ /* Array of module imports is laid out as a length field, followed by
+ a static array of ModuleInfo pointers. */
+ size_t aimports_dim = decl->aimports.dim;
+ for (size_t i = 0; i < decl->aimports.dim; i++)
+ {
+ Module *mi = decl->aimports[i];
+ if (!mi->needmoduleinfo)
+ aimports_dim--;
+ }
+
+ if (aimports_dim)
+ {
+ layout_moduleinfo_field (size_type_node, type, offset);
+ layout_moduleinfo_field (make_array_type (Type::tvoidptr, aimports_dim),
+ type, offset);
+ }
+
+ /* Array of local ClassInfo decls are laid out in the same way. */
+ ClassDeclarations aclasses;
+ for (size_t i = 0; i < decl->members->dim; i++)
+ {
+ Dsymbol *member = (*decl->members)[i];
+ member->addLocalClass (&aclasses);
+ }
+
+ if (aclasses.dim)
+ {
+ layout_moduleinfo_field (size_type_node, type, offset);
+ layout_moduleinfo_field (make_array_type (Type::tvoidptr, aclasses.dim),
+ type, offset);
+ }
+
+ /* Lastly, the name of the module is a static char array. */
+ size_t namelen = strlen (decl->toPrettyChars ()) + 1;
+ layout_moduleinfo_field (make_array_type (Type::tchar, namelen),
+ type, offset);
+
+ finish_aggregate_type (offset, 1, type, NULL);
+
+ return type;
+}
+
+/* Output the ModuleInfo for module DECL and register it with druntime. */
+
+static void
+layout_moduleinfo (Module *decl)
+{
+ ClassDeclarations aclasses;
+ FuncDeclaration *sgetmembers;
+
+ for (size_t i = 0; i < decl->members->dim; i++)
+ {
+ Dsymbol *member = (*decl->members)[i];
+ member->addLocalClass (&aclasses);
+ }
+
+ size_t aimports_dim = decl->aimports.dim;
+ for (size_t i = 0; i < decl->aimports.dim; i++)
+ {
+ Module *mi = decl->aimports[i];
+ if (!mi->needmoduleinfo)
+ aimports_dim--;
+ }
+
+ sgetmembers = decl->findGetMembers ();
+
+ size_t flags = 0;
+ if (decl->sctor)
+ flags |= MItlsctor;
+ if (decl->sdtor)
+ flags |= MItlsdtor;
+ if (decl->ssharedctor)
+ flags |= MIctor;
+ if (decl->sshareddtor)
+ flags |= MIdtor;
+ if (sgetmembers)
+ flags |= MIxgetMembers;
+ if (decl->sictor)
+ flags |= MIictor;
+ if (decl->stest)
+ flags |= MIunitTest;
+ if (aimports_dim)
+ flags |= MIimportedModules;
+ if (aclasses.dim)
+ flags |= MIlocalClasses;
+ if (!decl->needmoduleinfo)
+ flags |= MIstandalone;
+
+ flags |= MIname;
+
+ tree minfo = get_moduleinfo_decl (decl);
+ tree type = layout_moduleinfo_fields (decl, TREE_TYPE (minfo));
+
+ /* Put out the two named fields in a ModuleInfo decl:
+ uint flags;
+ uint index; */
+ vec<constructor_elt, va_gc> *minit = NULL;
+
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+ build_integer_cst (flags, d_uint_type));
+
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+ build_integer_cst (0, d_uint_type));
+
+ /* Order of appearance, depending on flags:
+ void function() tlsctor;
+ void function() tlsdtor;
+ void* function() xgetMembers;
+ void function() ctor;
+ void function() dtor;
+ void function() ictor;
+ void function() unitTest;
+ ModuleInfo*[] importedModules;
+ TypeInfo_Class[] localClasses;
+ char[N] name;
+ */
+ if (flags & MItlsctor)
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sctor));
+
+ if (flags & MItlsdtor)
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sdtor));
+
+ if (flags & MIctor)
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+ build_address (decl->ssharedctor));
+
+ if (flags & MIdtor)
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+ build_address (decl->sshareddtor));
+
+ if (flags & MIxgetMembers)
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+ build_address (get_symbol_decl (sgetmembers)));
+
+ if (flags & MIictor)
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sictor));
+
+ if (flags & MIunitTest)
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->stest));
+
+ if (flags & MIimportedModules)
+ {
+ vec<constructor_elt, va_gc> *elms = NULL;
+ tree satype = make_array_type (Type::tvoidptr, aimports_dim);
+ size_t idx = 0;
+
+ for (size_t i = 0; i < decl->aimports.dim; i++)
+ {
+ Module *mi = decl->aimports[i];
+ if (mi->needmoduleinfo)
+ {
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (idx),
+ build_address (get_moduleinfo_decl (mi)));
+ idx++;
+ }
+ }
+
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aimports_dim));
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+ build_constructor (satype, elms));
+ }
+
+ if (flags & MIlocalClasses)
+ {
+ vec<constructor_elt, va_gc> *elms = NULL;
+ tree satype = make_array_type (Type::tvoidptr, aclasses.dim);
+
+ for (size_t i = 0; i < aclasses.dim; i++)
+ {
+ ClassDeclaration *cd = aclasses[i];
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+ build_address (get_classinfo_decl (cd)));
+ }
+
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aclasses.dim));
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+ build_constructor (satype, elms));
+ }
+
+ if (flags & MIname)
+ {
+ /* Put out module name as a 0-terminated C-string, to save bytes. */
+ const char *name = decl->toPrettyChars ();
+ size_t namelen = strlen (name) + 1;
+ tree strtree = build_string (namelen, name);
+ TREE_TYPE (strtree) = make_array_type (Type::tchar, namelen);
+ CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, strtree);
+ }
+
+ TREE_TYPE (minfo) = type;
+ DECL_INITIAL (minfo) = build_struct_literal (type, minit);
+ d_finish_decl (minfo);
+
+ /* Register the module against druntime. */
+ register_moduleinfo (decl, minfo);
+}
+
+/* Send the Module AST class DECL to GCC back-end. */
+
+void
+build_module_tree (Module *decl)
+{
+ /* There may be more than one module per object file, but should only
+ ever compile them one at a time. */
+ assert (!current_moduleinfo && !current_module_decl);
+
+ module_info mi = module_info ();
+
+ current_moduleinfo = &mi;
+ current_module_decl = decl;
+
+ /* Layout module members. */
+ if (decl->members)
+ {
+ for (size_t i = 0; i < decl->members->dim; i++)
+ {
+ Dsymbol *s = (*decl->members)[i];
+ build_decl_tree (s);
+ }
+ }
+
+ /* Default behavior is to always generate module info because of templates.
+ Can be switched off for not compiling against runtime library. */
+ if (!global.params.betterC
+ && decl->ident != Identifier::idPool ("__entrypoint"))
+ {
+ if (mi.ctors || mi.ctorgates)
+ decl->sctor = build_funcs_gates_fn (get_identifier ("*__modctor"),
+ mi.ctors, mi.ctorgates);
+
+ if (mi.dtors)
+ decl->sdtor = build_funcs_gates_fn (get_identifier ("*__moddtor"),
+ mi.dtors, NULL);
+
+ if (mi.sharedctors || mi.sharedctorgates)
+ decl->ssharedctor
+ = build_funcs_gates_fn (get_identifier ("*__modsharedctor"),
+ mi.sharedctors, mi.sharedctorgates);
+
+ if (mi.shareddtors)
+ decl->sshareddtor
+ = build_funcs_gates_fn (get_identifier ("*__modshareddtor"),
+ mi.shareddtors, NULL);
+
+ if (mi.unitTests)
+ decl->stest = build_funcs_gates_fn (get_identifier ("*__modtest"),
+ mi.unitTests, NULL);
+
+ layout_moduleinfo (decl);
+ }
+
+ current_moduleinfo = NULL;
+ current_module_decl = NULL;
+}
+
+/* Returns the current function or module context for the purpose
+ of imported_module_or_decl. */
+
+tree
+d_module_context (void)
+{
+ if (cfun != NULL)
+ return current_function_decl;
+
+ gcc_assert (current_module_decl != NULL);
+ return build_import_decl (current_module_decl);
+}
+
+/* Maybe record declaration D against our module information structure. */
+
+void
+register_module_decl (Declaration *d)
+{
+ FuncDeclaration *fd = d->isFuncDeclaration ();
+ if (fd != NULL)
+ {
+ tree decl = get_symbol_decl (fd);
+
+ /* If a static constructor, push into the current ModuleInfo.
+ Checks for `shared' first because it derives from the non-shared
+ constructor type in the front-end. */
+ if (fd->isSharedStaticCtorDeclaration ())
+ vec_safe_push (current_moduleinfo->sharedctors, decl);
+ else if (fd->isStaticCtorDeclaration ())
+ vec_safe_push (current_moduleinfo->ctors, decl);
+
+ /* If a static destructor, do same as with constructors, but also
+ increment the destructor's vgate at construction time. */
+ if (fd->isSharedStaticDtorDeclaration ())
+ {
+ VarDeclaration *vgate = ((SharedStaticDtorDeclaration *) fd)->vgate;
+ if (vgate != NULL)
+ {
+ tree gate = get_symbol_decl (vgate);
+ vec_safe_push (current_moduleinfo->sharedctorgates, gate);
+ }
+ vec_safe_insert (current_moduleinfo->shareddtors, 0, decl);
+ }
+ else if (fd->isStaticDtorDeclaration ())
+ {
+ VarDeclaration *vgate = ((StaticDtorDeclaration *) fd)->vgate;
+ if (vgate != NULL)
+ {
+ tree gate = get_symbol_decl (vgate);
+ vec_safe_push (current_moduleinfo->ctorgates, gate);
+ }
+ vec_safe_insert (current_moduleinfo->dtors, 0, decl);
+ }
+
+ /* If a unittest function. */
+ if (fd->isUnitTestDeclaration ())
+ vec_safe_push (current_moduleinfo->unitTests, decl);
+ }
+}
+
+/* Wrapup all global declarations and start the final compilation. */
+
+void
+d_finish_compilation (tree *vec, int len)
+{
+ /* Complete all generated thunks. */
+ symtab->process_same_body_aliases ();
+
+ /* Process all file scopes in this compilation, and the external_scope,
+ through wrapup_global_declarations. */
+ for (int i = 0; i < len; i++)
+ {
+ tree decl = vec[i];
+ wrapup_global_declarations (&decl, 1);
+ }
+
+ /* If the target does not directly support static constructors,
+ static_ctor_list contains a list of all static constructors defined
+ so far. This routine will create a function to call all of those
+ and is picked up by collect2. */
+ if (static_ctor_list)
+ {
+ tree decl = build_funcs_gates_fn (get_file_function_name ("I"),
+ static_ctor_list, NULL);
+ DECL_STATIC_CONSTRUCTOR (decl) = 1;
+ decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
+ }
+
+ if (static_dtor_list)
+ {
+ tree decl = build_funcs_gates_fn (get_file_function_name ("D"),
+ static_dtor_list, NULL);
+ DECL_STATIC_DESTRUCTOR (decl) = 1;
+ decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
+ }
+}
+
+
+#include "gt-d-modules.h"
diff --git a/gcc/d/runtime.cc b/gcc/d/runtime.cc
new file mode 100644
index 0000000..7f1e910
--- /dev/null
+++ b/gcc/d/runtime.cc
@@ -0,0 +1,315 @@
+/* runtime.cc -- D runtime functions called by generated code.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+
+
+/* During the codegen pass, the compiler may do lowering of expressions to call
+ various runtime library functions. Most are implemented in the `rt' package.
+ We represent them in the frontend here, however there's no guarantee that
+ the compiler implementation actually matches the actual implementation. */
+
+enum libcall_type
+{
+ LCT_VOID, /* void */
+ LCT_BYTE, /* byte */
+ LCT_INT, /* int */
+ LCT_UINT, /* uint */
+ LCT_BOOL, /* bool */
+ LCT_DCHAR, /* dchar */
+ LCT_VOIDPTR, /* void* */
+ LCT_STRING, /* string */
+ LCT_WSTRING, /* wstring */
+ LCT_DSTRING, /* dstring */
+ LCT_SIZE_T, /* size_t */
+ LCT_ASSOCARRAY, /* void[void] */
+ LCT_ARRAY_VOID, /* void[] */
+ LCT_ARRAY_SIZE_T, /* size_t[] */
+ LCT_ARRAY_BYTE, /* byte[] */
+ LCT_ARRAY_STRING, /* string[] */
+ LCT_ARRAY_WSTRING, /* wstring[] */
+ LCT_ARRAY_DSTRING, /* dstring[] */
+ LCT_ARRAYARRAY_BYTE, /* byte[][] */
+ LCT_POINTER_ASSOCARRAY, /* void[void]* */
+ LCT_POINTER_VOIDPTR, /* void** */
+ LCT_ARRAYPTR_VOID, /* void[]* */
+ LCT_ARRAYPTR_BYTE, /* byte[]* */
+ LCT_TYPEINFO, /* TypeInfo */
+ LCT_CLASSINFO, /* TypeInfo_Class */
+ LCT_OBJECT, /* Object */
+ LCT_CONST_TYPEINFO, /* const(TypeInfo) */
+ LCT_CONST_CLASSINFO, /* const(ClassInfo) */
+ LCT_END
+};
+
+/* An array of all types that are used by the runtime functions we need. */
+
+static Type *libcall_types[LCT_END];
+
+/* Our internal list of library functions. */
+
+static tree libcall_decls[LIBCALL_LAST];
+
+
+/* Return the frontend Type that is described by TYPE. Most are readily cached
+ by the frontend proper, and likewise the use of pointerTo(), constOf(), and
+ arrayOf() will return cached types if they have been requested before. */
+
+static Type *
+get_libcall_type (libcall_type type)
+{
+ if (libcall_types[type])
+ return libcall_types[type];
+
+ switch (type)
+ {
+ case LCT_VOID:
+ libcall_types[type] = Type::tvoid;
+ break;
+
+ case LCT_BYTE:
+ libcall_types[type] = Type::tint8;
+ break;
+
+ case LCT_INT:
+ libcall_types[type] = Type::tint32;
+ break;
+
+ case LCT_UINT:
+ libcall_types[type] = Type::tuns32;
+ break;
+
+ case LCT_BOOL:
+ libcall_types[type] = Type::tbool;
+ break;
+
+ case LCT_DCHAR:
+ libcall_types[type] = Type::tdchar;
+ break;
+
+ case LCT_VOIDPTR:
+ libcall_types[type] = Type::tvoidptr;
+ break;
+
+ case LCT_STRING:
+ libcall_types[type] = Type::tstring;
+ break;
+
+ case LCT_WSTRING:
+ libcall_types[type] = Type::twstring;
+ break;
+
+ case LCT_DSTRING:
+ libcall_types[type] = Type::tdstring;
+ break;
+
+ case LCT_SIZE_T:
+ libcall_types[type] = Type::tsize_t;
+ break;
+
+ case LCT_ASSOCARRAY:
+ libcall_types[type] = TypeAArray::create (Type::tvoid, Type::tvoid);
+ break;
+
+ case LCT_TYPEINFO:
+ libcall_types[type] = Type::dtypeinfo->type;
+ break;
+
+ case LCT_CLASSINFO:
+ libcall_types[type] = Type::typeinfoclass->type;
+ break;
+
+ case LCT_OBJECT:
+ libcall_types[type] = get_object_type ();
+ break;
+
+ case LCT_CONST_TYPEINFO:
+ libcall_types[type] = Type::dtypeinfo->type->constOf ();
+ break;
+
+ case LCT_CONST_CLASSINFO:
+ libcall_types[type] = Type::typeinfoclass->type->constOf ();
+ break;
+
+ case LCT_ARRAY_VOID:
+ libcall_types[type] = Type::tvoid->arrayOf ();
+ break;
+
+ case LCT_ARRAY_SIZE_T:
+ libcall_types[type] = Type::tsize_t->arrayOf ();
+ break;
+
+ case LCT_ARRAY_BYTE:
+ libcall_types[type] = Type::tint8->arrayOf ();
+ break;
+
+ case LCT_ARRAY_STRING:
+ libcall_types[type] = Type::tstring->arrayOf ();
+ break;
+
+ case LCT_ARRAY_WSTRING:
+ libcall_types[type] = Type::twstring->arrayOf ();
+ break;
+
+ case LCT_ARRAY_DSTRING:
+ libcall_types[type] = Type::tdstring->arrayOf ();
+ break;
+
+ case LCT_ARRAYARRAY_BYTE:
+ libcall_types[type] = Type::tint8->arrayOf ()->arrayOf ();
+ break;
+
+ case LCT_POINTER_ASSOCARRAY:
+ libcall_types[type] = get_libcall_type (LCT_ASSOCARRAY)->pointerTo ();
+ break;
+
+ case LCT_POINTER_VOIDPTR:
+ libcall_types[type] = Type::tvoidptr->arrayOf ();
+ break;
+
+ case LCT_ARRAYPTR_VOID:
+ libcall_types[type] = Type::tvoid->arrayOf ()->pointerTo ();
+ break;
+
+ case LCT_ARRAYPTR_BYTE:
+ libcall_types[type] = Type::tint8->arrayOf ()->pointerTo ();
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return libcall_types[type];
+}
+
+/* Builds and returns function declaration named NAME. The RETURN_TYPE is
+ the type returned, FLAGS are the expression call flags, and NPARAMS is
+ the number of arguments, the types of which are provided in `...'. */
+
+static tree
+build_libcall_decl (const char *name, libcall_type return_type,
+ int flags, int nparams, ...)
+{
+ tree *args = XALLOCAVEC (tree, nparams);
+ bool varargs = false;
+ tree fntype;
+
+ /* Add parameter types, using 'void' as the last parameter type
+ to mean this function accepts a variable list of arguments. */
+ va_list ap;
+ va_start (ap, nparams);
+
+ for (int i = 0; i < nparams; i++)
+ {
+ libcall_type ptype = (libcall_type) va_arg (ap, int);
+ Type *type = get_libcall_type (ptype);
+
+ if (type == Type::tvoid)
+ {
+ varargs = true;
+ nparams = i;
+ }
+ else
+ args[i] = build_ctype (type);
+ }
+
+ va_end (ap);
+
+ /* Build the function. */
+ tree tret = build_ctype (get_libcall_type (return_type));
+ if (varargs)
+ fntype = build_varargs_function_type_array (tret, nparams, args);
+ else
+ fntype = build_function_type_array (tret, nparams, args);
+
+ tree decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+ get_identifier (name), fntype);
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+ DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+ /* Set any attributes on the function, such as malloc or noreturn. */
+ set_call_expr_flags (decl, flags);
+
+ return decl;
+}
+
+/* Return or create the runtime library function declaration for LIBCALL.
+ Library functions are generated as needed. This could probably be changed in
+ the future to be done in the compiler init stage, like GCC builtin trees are,
+ however we depend on run-time initialization of types whose definitions are
+ in the library such as `Object' or `TypeInfo'. */
+
+static tree
+get_libcall (libcall_fn libcall)
+{
+ if (libcall_decls[libcall])
+ return libcall_decls[libcall];
+
+ switch (libcall)
+ {
+#define DEF_D_RUNTIME(CODE, NAME, TYPE, PARAMS, FLAGS) \
+ case LIBCALL_ ## CODE: \
+ libcall_decls[libcall] = build_libcall_decl (NAME, TYPE, FLAGS, PARAMS); \
+ break;
+
+#include "runtime.def"
+
+#undef DEF_D_RUNTIME
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return libcall_decls[libcall];
+}
+
+/* Generate a call to LIBCALL, returning the result as TYPE. NARGS is the
+ number of call arguments, the expressions of which are provided in `...'.
+ This does not perform conversions or promotions on the arguments. */
+
+tree
+build_libcall (libcall_fn libcall, Type *type, int nargs, ...)
+{
+ /* Build the call expression to the runtime function. */
+ tree decl = get_libcall (libcall);
+ tree *args = XALLOCAVEC (tree, nargs);
+ va_list ap;
+
+ va_start (ap, nargs);
+ for (int i = 0; i < nargs; i++)
+ args[i] = va_arg (ap, tree);
+ va_end (ap);
+
+ tree result = build_call_expr_loc_array (input_location, decl, nargs, args);
+
+ /* Assumes caller knows what it is doing. */
+ return convert (build_ctype (type), result);
+}
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
new file mode 100644
index 0000000..e135bc3
--- /dev/null
+++ b/gcc/d/runtime.def
@@ -0,0 +1,224 @@
+/* runtime.def -- Definitions for D runtime functions.
+ Copyright (C) 2014-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* D runtime library functions. */
+
+/* DEF_D_RUNTIME (CODE, NAME, FLAGS)
+ CODE The enum code used to refer to this function.
+ NAME The name of this function as a string.
+ FLAGS ECF flags to describe attributes of the function.
+
+ Used for declaring functions that are called by generated code. Most are
+ extern(C) - for those that are not, ensure to use correct mangling. */
+
+/* Helper macros for parameter building. */
+#define P0() 0
+#define P1(T1) 1, LCT_ ## T1
+#define P2(T1, T2) 2, LCT_ ## T1, LCT_ ## T2
+#define P3(T1, T2, T3) 3, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3
+#define P4(T1, T2, T3, T4) 4, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3, LCT_ ## T4
+#define RT(T1) LCT_ ## T1
+
+/* Used when an assert() contract fails. */
+DEF_D_RUNTIME (ASSERT, "_d_assert", RT(VOID), P2(STRING, UINT), ECF_NORETURN)
+DEF_D_RUNTIME (ASSERT_MSG, "_d_assert_msg", RT(VOID), P3(STRING, STRING, UINT),
+ ECF_NORETURN)
+
+/* Used when an assert() contract fails in a unittest function. */
+DEF_D_RUNTIME (UNITTEST, "_d_unittest", RT(VOID), P2(STRING, UINT),
+ ECF_NORETURN)
+DEF_D_RUNTIME (UNITTEST_MSG, "_d_unittest_msg", RT(VOID),
+ P3(STRING, STRING, UINT), ECF_NORETURN)
+
+/* Used when an array index outside the bounds of its range. */
+DEF_D_RUNTIME (ARRAY_BOUNDS, "_d_arraybounds", RT(VOID), P2(STRING, UINT),
+ ECF_NORETURN)
+
+/* Used when calling new on a class. */
+DEF_D_RUNTIME (NEWCLASS, "_d_newclass", RT(OBJECT), P1(CONST_CLASSINFO), 0)
+
+/* Used when calling delete on a class or interface. */
+DEF_D_RUNTIME (DELCLASS, "_d_delclass", RT(VOID), P1(VOIDPTR), 0)
+DEF_D_RUNTIME (DELINTERFACE, "_d_delinterface", RT(VOID), P1(VOIDPTR), 0)
+
+/* Same as deleting a class, but used for stack-allocated classes. */
+DEF_D_RUNTIME (CALLFINALIZER, "_d_callfinalizer", RT(VOID), P1(VOIDPTR), 0)
+DEF_D_RUNTIME (CALLINTERFACEFINALIZER, "_d_callinterfacefinalizer", RT(VOID),
+ P1(VOIDPTR), 0)
+
+/* Used for casting to a class or interface. */
+DEF_D_RUNTIME (DYNAMIC_CAST, "_d_dynamic_cast", RT(OBJECT),
+ P2(OBJECT, CLASSINFO), 0)
+DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT),
+ P2(OBJECT, CLASSINFO), 0)
+
+/* Used when calling new on a pointer. The `i' variant is for when the
+ initializer is nonzero. */
+DEF_D_RUNTIME (NEWITEMT, "_d_newitemT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
+DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
+
+/* Used when calling delete on a pointer. */
+DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0)
+DEF_D_RUNTIME (DELSTRUCT, "_d_delstruct", RT(VOID),
+ P2(POINTER_VOIDPTR, TYPEINFO), 0)
+
+/* Used when calling new on an array. The `i' variant is for when the
+ initializer is nonzero, and the `m' variant is when initializing a
+ multi-dimensional array. */
+DEF_D_RUNTIME (NEWARRAYT, "_d_newarrayT", RT(ARRAY_VOID),
+ P2(CONST_TYPEINFO, SIZE_T), 0)
+DEF_D_RUNTIME (NEWARRAYIT, "_d_newarrayiT", RT(ARRAY_VOID),
+ P2(CONST_TYPEINFO, SIZE_T), 0)
+DEF_D_RUNTIME (NEWARRAYMTX, "_d_newarraymTX", RT(ARRAY_VOID),
+ P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
+DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID),
+ P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
+
+/* Used for allocating an array literal on the GC heap. */
+DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR),
+ P2(CONST_TYPEINFO, SIZE_T), 0)
+
+/* Used when calling delete on an array. */
+DEF_D_RUNTIME (DELARRAYT, "_d_delarray_t", RT(VOID),
+ P2(ARRAYPTR_VOID, CONST_TYPEINFO), 0)
+
+/* Used for value equality (x == y) and comparisons (x < y) of non-trivial
+ arrays. Such as an array of structs or classes. */
+DEF_D_RUNTIME (ADEQ2, "_adEq2", RT(INT),
+ P3(ARRAY_VOID, ARRAY_VOID, CONST_TYPEINFO), 0)
+DEF_D_RUNTIME (ADCMP2, "_adCmp2", RT(INT),
+ P3(ARRAY_VOID, ARRAY_VOID, CONST_TYPEINFO), 0)
+
+/* Used when casting from one array type to another where the index type
+ sizes differ. Such as from int[] to short[]. */
+DEF_D_RUNTIME (ARRAYCAST, "_d_arraycast", RT(ARRAY_VOID),
+ P3(SIZE_T, SIZE_T, ARRAY_VOID), 0)
+
+/* Used for (array.length = n) expressions. The `i' variant is for when the
+ initializer is nonzero. */
+DEF_D_RUNTIME (ARRAYSETLENGTHT, "_d_arraysetlengthT", RT(ARRAY_VOID),
+ P3(CONST_TYPEINFO, SIZE_T, ARRAYPTR_VOID), 0)
+DEF_D_RUNTIME (ARRAYSETLENGTHIT, "_d_arraysetlengthiT", RT(ARRAY_VOID),
+ P3(CONST_TYPEINFO, SIZE_T, ARRAYPTR_VOID), 0)
+
+/* Used for allocating closures on the GC heap. */
+DEF_D_RUNTIME (ALLOCMEMORY, "_d_allocmemory", RT(VOIDPTR), P1(SIZE_T),
+ ECF_MALLOC)
+
+/* Used for copying an array into a slice, adds an enforcment that the source
+ and destination are equal in size and do not overlap. */
+DEF_D_RUNTIME (ARRAYCOPY, "_d_arraycopy", RT(ARRAY_VOID),
+ P3(SIZE_T, ARRAY_VOID, ARRAY_VOID), 0)
+
+/* Used for array assignments from an existing array. The `set' variant is for
+ when the assignment value is a single element. */
+DEF_D_RUNTIME (ARRAYASSIGN, "_d_arrayassign", RT(ARRAY_VOID),
+ P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
+DEF_D_RUNTIME (ARRAYASSIGN_L, "_d_arrayassign_l", RT(ARRAY_VOID),
+ P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0)
+DEF_D_RUNTIME (ARRAYASSIGN_R, "_d_arrayassign_r", RT(ARRAY_VOID),
+ P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0)
+DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR),
+ P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
+
+/* Used for constructing a new array from an existing array. The `set' variant
+ is for when the constructor value is a single element. */
+DEF_D_RUNTIME (ARRAYCTOR, "_d_arrayctor", RT(ARRAY_VOID),
+ P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
+DEF_D_RUNTIME (ARRAYSETCTOR, "_d_arraysetctor", RT(VOIDPTR),
+ P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
+
+/* Used for concatenating two or more arrays together. Then `n' variant is
+ for when there is more than two arrays to handle. */
+DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE),
+ P3(CONST_TYPEINFO, ARRAY_BYTE, ARRAY_BYTE), 0)
+DEF_D_RUNTIME (ARRAYCATNTX, "_d_arraycatnTX", RT(ARRAY_VOID),
+ P2(CONST_TYPEINFO, ARRAYARRAY_BYTE), 0)
+
+/* Used for appending a single element to an array. */
+DEF_D_RUNTIME (ARRAYAPPENDCTX, "_d_arrayappendcTX", RT(ARRAY_BYTE),
+ P3(CONST_TYPEINFO, ARRAYPTR_BYTE, SIZE_T), 0)
+
+/* Same as appending a single element to an array, but specific for when the
+ source is a UTF-32 character, and the destination is a UTF-8 or 16 array. */
+DEF_D_RUNTIME (ARRAYAPPENDCD, "_d_arrayappendcd", RT(ARRAY_VOID),
+ P2(ARRAYPTR_BYTE, DCHAR), 0)
+DEF_D_RUNTIME (ARRAYAPPENDWD, "_d_arrayappendwd", RT(ARRAY_VOID),
+ P2(ARRAYPTR_BYTE, DCHAR), 0)
+
+/* Used for appending an existing array to another. */
+DEF_D_RUNTIME (ARRAYAPPENDT, "_d_arrayappendT", RT(ARRAY_VOID),
+ P3(TYPEINFO, ARRAYPTR_BYTE, ARRAY_BYTE), 0)
+
+/* Used for allocating a new associative array. */
+DEF_D_RUNTIME (ASSOCARRAYLITERALTX, "_d_assocarrayliteralTX", RT(VOIDPTR),
+ P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
+
+/* Used for value equality of two associative arrays. */
+DEF_D_RUNTIME (AAEQUAL, "_aaEqual", RT(INT),
+ P3(CONST_TYPEINFO, ASSOCARRAY, ASSOCARRAY), 0)
+
+/* Used to determine is a key exists in an associative array. */
+DEF_D_RUNTIME (AAINX, "_aaInX", RT(VOIDPTR),
+ P3(ASSOCARRAY, CONST_TYPEINFO, VOIDPTR), 0)
+
+/* Used to retrieve a value from an associative array index by a key. The
+ `Rvalue' variant returns null if the key is not found, where as aaGetY
+ will create new key entry for assignment. */
+DEF_D_RUNTIME (AAGETY, "_aaGetY", RT(VOIDPTR),
+ P4(POINTER_ASSOCARRAY, CONST_TYPEINFO, SIZE_T, VOIDPTR), 0)
+DEF_D_RUNTIME (AAGETRVALUEX, "_aaGetRvalueX", RT(VOIDPTR),
+ P4(ASSOCARRAY, CONST_TYPEINFO, SIZE_T, VOIDPTR), 0)
+
+/* Used when calling delete on a key entry in an associative array. */
+DEF_D_RUNTIME (AADELX, "_aaDelX", RT(BOOL),
+ P3(ASSOCARRAY, CONST_TYPEINFO, VOIDPTR), 0)
+
+/* Used for throw() expressions. */
+DEF_D_RUNTIME (THROW, "_d_throw", RT(VOID), P1(OBJECT), ECF_NORETURN)
+DEF_D_RUNTIME (BEGIN_CATCH, "__gdc_begin_catch", RT(VOIDPTR), P1(VOIDPTR), 0)
+
+/* C++ exception handlers. */
+DEF_D_RUNTIME (CXA_BEGIN_CATCH, "__cxa_begin_catch", RT(VOIDPTR), P1(VOIDPTR),
+ ECF_NOTHROW)
+DEF_D_RUNTIME (CXA_END_CATCH, "__cxa_end_catch", RT(VOID), P0(), 0)
+
+/* When invariant() contracts are turned on, used after testing whether a
+ class != null for validating the state of a class. */
+DEF_D_RUNTIME (INVARIANT, "_D9invariant12_d_invariantFC6ObjectZv", RT(VOID),
+ P1(OBJECT), 0)
+
+/* Used when performing a switch/cases on a string. The `u' and `d' variants
+ are for UTF-16 and UTF-32 strings respectively. */
+DEF_D_RUNTIME (SWITCH_STRING, "_d_switch_string", RT(INT),
+ P2(ARRAY_STRING, STRING), 0)
+DEF_D_RUNTIME (SWITCH_USTRING, "_d_switch_ustring", RT(INT),
+ P2(ARRAY_WSTRING, WSTRING), 0)
+DEF_D_RUNTIME (SWITCH_DSTRING, "_d_switch_dstring", RT(INT),
+ P2(ARRAY_DSTRING, DSTRING), 0)
+
+/* Used when throwing an error that a switch statement has no default case,
+ and yet none of the existing cases matched. */
+DEF_D_RUNTIME (SWITCH_ERROR, "_d_switch_error", RT(VOID), P2(STRING, UINT),
+ ECF_NORETURN)
+
+#undef P0
+#undef P1
+#undef P2
+#undef P3
+#undef P4
+#undef RT
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
new file mode 100644
index 0000000..0d78fa6
--- /dev/null
+++ b/gcc/d/toir.cc
@@ -0,0 +1,1447 @@
+/* toir.cc -- Lower D frontend statements to GCC trees.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/declaration.h"
+#include "dmd/expression.h"
+#include "dmd/identifier.h"
+#include "dmd/init.h"
+#include "dmd/statement.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+#include "options.h"
+#include "stmt.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stringpool.h"
+#include "function.h"
+#include "toplev.h"
+
+#include "d-tree.h"
+
+
+/* Update data for defined and undefined labels when leaving a scope. */
+
+bool
+pop_binding_label (Statement * const &, d_label_entry *ent, binding_level *bl)
+{
+ binding_level *obl = bl->level_chain;
+
+ if (ent->level == bl)
+ {
+ if (bl->kind == level_try)
+ ent->in_try_scope = true;
+ else if (bl->kind == level_catch)
+ ent->in_catch_scope = true;
+
+ ent->level = obl;
+ }
+ else if (ent->fwdrefs)
+ {
+ for (d_label_use_entry *ref = ent->fwdrefs; ref; ref = ref->next)
+ ref->level = obl;
+ }
+
+ return true;
+}
+
+/* At the end of a function, all labels declared within the function
+ go out of scope. BLOCK is the top-level block for the function. */
+
+bool
+pop_label (Statement * const &s, d_label_entry *ent, tree block)
+{
+ if (!ent->bc_label)
+ {
+ /* Put the labels into the "variables" of the top-level block,
+ so debugger can see them. */
+ if (DECL_NAME (ent->label))
+ {
+ gcc_assert (DECL_INITIAL (ent->label) != NULL_TREE);
+ DECL_CHAIN (ent->label) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = ent->label;
+ }
+ }
+
+ d_function_chain->labels->remove (s);
+
+ return true;
+}
+
+/* The D front-end does not use the 'binding level' system for a symbol table,
+ however it has been the goto structure for tracking code flow.
+ Primarily it is only needed to get debugging information for local variables
+ and otherwise support the back-end. */
+
+void
+push_binding_level (level_kind kind)
+{
+ /* Add it to the front of currently active scopes stack. */
+ binding_level *new_level = ggc_cleared_alloc<binding_level> ();
+ new_level->level_chain = current_binding_level;
+ new_level->kind = kind;
+
+ current_binding_level = new_level;
+}
+
+tree
+pop_binding_level (void)
+{
+ binding_level *level = current_binding_level;
+ current_binding_level = level->level_chain;
+
+ tree block = make_node (BLOCK);
+ BLOCK_VARS (block) = level->names;
+ BLOCK_SUBBLOCKS (block) = level->blocks;
+
+ /* In each subblock, record that this is its superior. */
+ for (tree t = level->blocks; t; t = BLOCK_CHAIN (t))
+ BLOCK_SUPERCONTEXT (t) = block;
+
+ if (level->kind == level_function)
+ {
+ /* Dispose of the block that we just made inside some higher level. */
+ DECL_INITIAL (current_function_decl) = block;
+ BLOCK_SUPERCONTEXT (block) = current_function_decl;
+
+ /* Pop all the labels declared in the function. */
+ if (d_function_chain->labels)
+ d_function_chain->labels->traverse<tree, &pop_label> (block);
+ }
+ else
+ {
+ /* Any uses of undefined labels, and any defined labels, now operate
+ under constraints of next binding contour. */
+ if (d_function_chain && d_function_chain->labels)
+ {
+ language_function *f = d_function_chain;
+ f->labels->traverse<binding_level *, &pop_binding_label> (level);
+ }
+
+ current_binding_level->blocks
+ = block_chainon (current_binding_level->blocks, block);
+ }
+
+ TREE_USED (block) = 1;
+ return block;
+}
+
+/* Create an empty statement tree rooted at T. */
+
+void
+push_stmt_list (void)
+{
+ tree t = alloc_stmt_list ();
+ vec_safe_push (d_function_chain->stmt_list, t);
+ d_keep (t);
+}
+
+/* Finish the statement tree rooted at T. */
+
+tree
+pop_stmt_list (void)
+{
+ tree t = d_function_chain->stmt_list->pop ();
+
+ /* If the statement list is completely empty, just return it. This is just
+ as good as build_empty_stmt, with the advantage that statement lists
+ are merged when they are appended to one another. So using the
+ STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P statements. */
+ if (TREE_SIDE_EFFECTS (t))
+ {
+ /* If the statement list contained exactly one statement, then extract
+ it immediately. */
+ tree_stmt_iterator i = tsi_start (t);
+
+ if (tsi_one_before_end_p (i))
+ {
+ tree u = tsi_stmt (i);
+ tsi_delink (&i);
+ free_stmt_list (t);
+ t = u;
+ }
+ }
+
+ return t;
+}
+
+/* T is an expression statement. Add it to the statement-tree. */
+
+void
+add_stmt (tree t)
+{
+ /* Ignore (void) 0; expression statements received from the frontend.
+ Likewise void_node is used when contracts become nops in release code. */
+ if (t == void_node || IS_EMPTY_STMT (t))
+ return;
+
+ /* At this point, we no longer care about the value of expressions,
+ so if there's no side-effects, then don't add it. */
+ if (!TREE_SIDE_EFFECTS (t))
+ return;
+
+ if (TREE_CODE (t) == COMPOUND_EXPR)
+ {
+ /* Push out each comma expressions as separate statements. */
+ add_stmt (TREE_OPERAND (t, 0));
+ add_stmt (TREE_OPERAND (t, 1));
+ }
+ else
+ {
+ /* Force the type to be void so we don't need to create a temporary
+ variable to hold the inner expression. */
+ if (TREE_CODE (t) == CLEANUP_POINT_EXPR)
+ TREE_TYPE (t) = void_type_node;
+
+ /* Append the expression to the statement list.
+ Make sure it has a proper location. */
+ if (EXPR_P (t) && !EXPR_HAS_LOCATION (t))
+ SET_EXPR_LOCATION (t, input_location);
+
+ tree stmt_list = d_function_chain->stmt_list->last ();
+ append_to_statement_list_force (t, &stmt_list);
+ }
+}
+
+/* Implements the visitor interface to build the GCC trees of all Statement
+ AST classes emitted from the D Front-end.
+ All visit methods accept one parameter S, which holds the frontend AST
+ of the statement to compile. They also don't return any value, instead
+ generated code are pushed to add_stmt(), which appends them to the
+ statement list in the current_binding_level. */
+
+class IRVisitor : public Visitor
+{
+ using Visitor::visit;
+
+ FuncDeclaration *func_;
+
+ /* Stack of labels which are targets for "break" and "continue",
+ linked through TREE_CHAIN. */
+ tree break_label_;
+ tree continue_label_;
+
+public:
+ IRVisitor (FuncDeclaration *fd)
+ {
+ this->func_ = fd;
+ this->break_label_ = NULL_TREE;
+ this->continue_label_ = NULL_TREE;
+ }
+
+ /* Helper for generating code for the statement AST class S.
+ Sets up the location of the statement before lowering. */
+
+ void build_stmt (Statement *s)
+ {
+ location_t saved_location = input_location;
+ input_location = make_location_t (s->loc);
+ s->accept (this);
+ input_location = saved_location;
+ }
+
+ /* Start a new scope for a KIND statement.
+ Each user-declared variable will have a binding contour that begins
+ where the variable is declared and ends at its containing scope. */
+
+ void start_scope (level_kind kind)
+ {
+ push_binding_level (kind);
+ push_stmt_list ();
+ }
+
+ /* Leave scope pushed by start_scope, returning a new bind_expr if
+ any variables where declared in the scope. */
+
+ tree end_scope (void)
+ {
+ tree block = pop_binding_level ();
+ tree body = pop_stmt_list ();
+
+ if (! BLOCK_VARS (block))
+ return body;
+
+ tree bind = build3 (BIND_EXPR, void_type_node,
+ BLOCK_VARS (block), body, block);
+ TREE_SIDE_EFFECTS (bind) = 1;
+ return bind;
+ }
+
+ /* Like end_scope, but also push it into the outer statement-tree. */
+
+ void finish_scope (void)
+ {
+ tree scope = this->end_scope ();
+ add_stmt (scope);
+ }
+
+ /* Return TRUE if IDENT is the current function return label. */
+
+ bool is_return_label (Identifier *ident)
+ {
+ if (this->func_->returnLabel)
+ return this->func_->returnLabel->ident == ident;
+
+ return false;
+ }
+
+ /* Define a label, specifying the location in the source file.
+ Return the LABEL_DECL node for the label. */
+
+ tree define_label (Statement *s, Identifier *ident = NULL)
+ {
+ tree label = this->lookup_label (s, ident);
+ gcc_assert (DECL_INITIAL (label) == NULL_TREE);
+
+ d_label_entry *ent = d_function_chain->labels->get (s);
+ gcc_assert (ent != NULL);
+
+ /* Mark label as having been defined. */
+ DECL_INITIAL (label) = error_mark_node;
+
+ ent->level = current_binding_level;
+
+ for (d_label_use_entry *ref = ent->fwdrefs; ref ; ref = ref->next)
+ this->check_previous_goto (ent->statement, ref);
+ ent->fwdrefs = NULL;
+
+ return label;
+ }
+
+ /* Emit a LABEL expression. */
+
+ void do_label (tree label)
+ {
+ /* Don't write out label unless it is marked as used by the frontend.
+ This makes auto-vectorization possible in conditional loops.
+ The only excemption to this is in the LabelStatement visitor,
+ in which all computed labels are marked regardless. */
+ if (TREE_USED (label))
+ add_stmt (build1 (LABEL_EXPR, void_type_node, label));
+ }
+
+ /* Emit a goto expression to LABEL. */
+
+ void do_jump (tree label)
+ {
+ add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label));
+ TREE_USED (label) = 1;
+ }
+
+ /* Check that a new jump at statement scope FROM to a label declared in
+ statement scope TO is valid. */
+
+ void check_goto (Statement *from, Statement *to)
+ {
+ d_label_entry *ent = d_function_chain->labels->get (to);
+ gcc_assert (ent != NULL);
+
+ /* If the label hasn't been defined yet, defer checking. */
+ if (! DECL_INITIAL (ent->label))
+ {
+ d_label_use_entry *fwdref = ggc_alloc<d_label_use_entry> ();
+ fwdref->level = current_binding_level;
+ fwdref->statement = from;
+ fwdref->next = ent->fwdrefs;
+ ent->fwdrefs = fwdref;
+ return;
+ }
+
+ if (ent->in_try_scope)
+ error_at (make_location_t (from->loc), "cannot goto into try block");
+ else if (ent->in_catch_scope)
+ error_at (make_location_t (from->loc), "cannot goto into catch block");
+ }
+
+ /* Check that a previously seen jump to a newly defined label is valid.
+ S is the label statement; FWDREF is the jump context. This is called
+ for both user-defined and case labels. */
+
+ void check_previous_goto (Statement *s, d_label_use_entry *fwdref)
+ {
+ for (binding_level *b = current_binding_level; b ; b = b->level_chain)
+ {
+ if (b == fwdref->level)
+ break;
+
+ if (b->kind == level_try || b->kind == level_catch)
+ {
+ location_t location;
+
+ if (s->isLabelStatement ())
+ {
+ location = make_location_t (fwdref->statement->loc);
+ if (b->kind == level_try)
+ error_at (location, "cannot goto into try block");
+ else
+ error_at (location, "cannot goto into catch block");
+ }
+ else if (s->isCaseStatement ())
+ {
+ location = make_location_t (s->loc);
+ error_at (location, "case cannot be in different "
+ "try block level from switch");
+ }
+ else if (s->isDefaultStatement ())
+ {
+ location = make_location_t (s->loc);
+ error_at (location, "default cannot be in different "
+ "try block level from switch");
+ }
+ else
+ gcc_unreachable ();
+ }
+ }
+ }
+
+ /* Get or build LABEL_DECL using the IDENT and statement block S given. */
+
+ tree lookup_label (Statement *s, Identifier *ident = NULL)
+ {
+ /* You can't use labels at global scope. */
+ if (d_function_chain == NULL)
+ {
+ error ("label %s referenced outside of any function",
+ ident ? ident->toChars () : "(unnamed)");
+ return NULL_TREE;
+ }
+
+ /* Create the label htab for the function on demand. */
+ if (!d_function_chain->labels)
+ {
+ d_function_chain->labels
+ = hash_map<Statement *, d_label_entry>::create_ggc (13);
+ }
+
+ d_label_entry *ent = d_function_chain->labels->get (s);
+ if (ent != NULL)
+ return ent->label;
+ else
+ {
+ tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE;
+ tree decl = build_decl (make_location_t (s->loc), LABEL_DECL,
+ name, void_type_node);
+ DECL_CONTEXT (decl) = current_function_decl;
+ DECL_MODE (decl) = VOIDmode;
+
+ /* Create new empty slot. */
+ ent = ggc_cleared_alloc<d_label_entry> ();
+ ent->statement = s;
+ ent->label = decl;
+
+ bool existed = d_function_chain->labels->put (s, *ent);
+ gcc_assert (!existed);
+
+ return decl;
+ }
+ }
+
+ /* Get the LABEL_DECL to represent a break or continue for the
+ statement S given. BC indicates which. */
+
+ tree lookup_bc_label (Statement *s, bc_kind bc)
+ {
+ tree vec = this->lookup_label (s);
+
+ /* The break and continue labels are put into a TREE_VEC. */
+ if (TREE_CODE (vec) == LABEL_DECL)
+ {
+ d_label_entry *ent = d_function_chain->labels->get (s);
+ gcc_assert (ent != NULL);
+
+ vec = make_tree_vec (2);
+ TREE_VEC_ELT (vec, bc_break) = ent->label;
+
+ /* Build the continue label. */
+ tree label = build_decl (make_location_t (s->loc), LABEL_DECL,
+ NULL_TREE, void_type_node);
+ DECL_CONTEXT (label) = current_function_decl;
+ DECL_MODE (label) = VOIDmode;
+ TREE_VEC_ELT (vec, bc_continue) = label;
+
+ ent->label = vec;
+ ent->bc_label = true;
+ }
+
+ return TREE_VEC_ELT (vec, bc);
+ }
+
+ /* Set and return the current break label for the current block. */
+
+ tree push_break_label (Statement *s)
+ {
+ tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break);
+ DECL_CHAIN (label) = this->break_label_;
+ this->break_label_ = label;
+ return label;
+ }
+
+ /* Finish with the current break label. */
+
+ void pop_break_label (tree label)
+ {
+ gcc_assert (this->break_label_ == label);
+ this->break_label_ = DECL_CHAIN (this->break_label_);
+ this->do_label (label);
+ }
+
+ /* Set and return the continue label for the current block. */
+
+ tree push_continue_label (Statement *s)
+ {
+ tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue);
+ DECL_CHAIN (label) = this->continue_label_;
+ this->continue_label_ = label;
+ return label;
+ }
+
+ /* Finish with the current continue label. */
+
+ void pop_continue_label (tree label)
+ {
+ gcc_assert (this->continue_label_ == label);
+ this->continue_label_ = DECL_CHAIN (this->continue_label_);
+ this->do_label (label);
+ }
+
+ /* Visitor interfaces. */
+
+
+ /* This should be overridden by each statement class. */
+
+ void visit (Statement *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* The frontend lowers `scope (exit/failure/success)' statements as
+ try/catch/finally. At this point, this statement is just an empty
+ placeholder. Maybe the frontend shouldn't leak these. */
+
+ void visit (OnScopeStatement *)
+ {
+ }
+
+ /* If statements provide simple conditional execution of statements. */
+
+ void visit (IfStatement *s)
+ {
+ this->start_scope (level_cond);
+
+ /* Build the outer 'if' condition, which may produce temporaries
+ requiring scope destruction. */
+ tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
+ s->condition->type);
+ tree ifbody = void_node;
+ tree elsebody = void_node;
+
+ /* Build the 'then' branch. */
+ if (s->ifbody)
+ {
+ push_stmt_list ();
+ this->build_stmt (s->ifbody);
+ ifbody = pop_stmt_list ();
+ }
+
+ /* Now build the 'else' branch, which may have nested 'else if' parts. */
+ if (s->elsebody)
+ {
+ push_stmt_list ();
+ this->build_stmt (s->elsebody);
+ elsebody = pop_stmt_list ();
+ }
+
+ /* Wrap up our constructed if condition into a COND_EXPR. */
+ tree cond = build_vcondition (ifcond, ifbody, elsebody);
+ add_stmt (cond);
+
+ /* Finish the if-then scope. */
+ this->finish_scope ();
+ }
+
+ /* Should there be any `pragma (...)' statements requiring code generation,
+ here would be the place to do it. For now, all pragmas are handled
+ by the frontend. */
+
+ void visit (PragmaStatement *)
+ {
+ }
+
+ /* The frontend lowers `while (...)' statements as `for (...)' loops.
+ This visitor is not strictly required other than to enforce that
+ these kinds of statements never reach here. */
+
+ void visit (WhileStatement *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* Do while statments implement simple loops. The body is executed, then
+ the condition is evaluated. */
+
+ void visit (DoStatement *s)
+ {
+ tree lbreak = this->push_break_label (s);
+
+ this->start_scope (level_loop);
+ if (s->_body)
+ {
+ tree lcontinue = this->push_continue_label (s);
+ this->build_stmt (s->_body);
+ this->pop_continue_label (lcontinue);
+ }
+
+ /* Build the outer 'while' condition, which may produce temporaries
+ requiring scope destruction. */
+ tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
+ s->condition->type);
+ add_stmt (build_vcondition (exitcond, void_node,
+ build1 (GOTO_EXPR, void_type_node, lbreak)));
+ TREE_USED (lbreak) = 1;
+
+ tree body = this->end_scope ();
+ add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+ this->pop_break_label (lbreak);
+ }
+
+ /* For statements implement loops with initialization, test, and
+ increment clauses. */
+
+ void visit (ForStatement *s)
+ {
+ tree lbreak = this->push_break_label (s);
+ this->start_scope (level_loop);
+
+ if (s->_init)
+ this->build_stmt (s->_init);
+
+ if (s->condition)
+ {
+ tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
+ s->condition->type);
+ add_stmt (build_vcondition (exitcond, void_node,
+ build1 (GOTO_EXPR, void_type_node,
+ lbreak)));
+ TREE_USED (lbreak) = 1;
+ }
+
+ if (s->_body)
+ {
+ tree lcontinue = this->push_continue_label (s);
+ this->build_stmt (s->_body);
+ this->pop_continue_label (lcontinue);
+ }
+
+ if (s->increment)
+ {
+ /* Force side effects? */
+ add_stmt (build_expr_dtor (s->increment));
+ }
+
+ tree body = this->end_scope ();
+ add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+ this->pop_break_label (lbreak);
+ }
+
+ /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
+ This visitor is not strictly required other than to enforce that
+ these kinds of statements never reach here. */
+
+ void visit (ForeachStatement *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
+ loops. This visitor is not strictly required other than to enforce that
+ these kinds of statements never reach here. */
+
+ void visit (ForeachRangeStatement *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* Jump to the associated exit label for the current loop. If IDENT
+ for the Statement is not null, then the label is user defined. */
+
+ void visit (BreakStatement *s)
+ {
+ if (s->ident)
+ {
+ /* The break label may actually be some levels up.
+ eg: on a try/finally wrapping a loop. */
+ LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
+ gcc_assert (label != NULL);
+ Statement *stmt = label->statement->getRelatedLabeled ();
+ this->do_jump (this->lookup_bc_label (stmt, bc_break));
+ }
+ else
+ this->do_jump (this->break_label_);
+ }
+
+ /* Jump to the associated continue label for the current loop. If IDENT
+ for the Statement is not null, then the label is user defined. */
+
+ void visit (ContinueStatement *s)
+ {
+ if (s->ident)
+ {
+ LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
+ gcc_assert (label != NULL);
+ this->do_jump (this->lookup_bc_label (label->statement,
+ bc_continue));
+ }
+ else
+ this->do_jump (this->continue_label_);
+ }
+
+ /* A goto statement jumps to the statement identified by the given label. */
+
+ void visit (GotoStatement *s)
+ {
+ gcc_assert (s->label->statement != NULL);
+ gcc_assert (s->tf == s->label->statement->tf);
+
+ /* If no label found, there was an error. */
+ tree label = this->lookup_label (s->label->statement, s->label->ident);
+ this->do_jump (label);
+
+ /* Need to error if the goto is jumping into a try or catch block. */
+ this->check_goto (s, s->label->statement);
+ }
+
+ /* Statements can be labeled. A label is an identifier that precedes
+ a statement. */
+
+ void visit (LabelStatement *s)
+ {
+ LabelDsymbol *sym;
+
+ if (this->is_return_label (s->ident))
+ sym = this->func_->returnLabel;
+ else
+ sym = this->func_->searchLabel (s->ident);
+
+ /* If no label found, there was an error. */
+ tree label = this->define_label (sym->statement, sym->ident);
+ TREE_USED (label) = 1;
+
+ this->do_label (label);
+
+ if (this->is_return_label (s->ident) && this->func_->fensure != NULL)
+ this->build_stmt (this->func_->fensure);
+ else if (s->statement)
+ this->build_stmt (s->statement);
+ }
+
+ /* A switch statement goes to one of a collection of case statements
+ depending on the value of the switch expression. */
+
+ void visit (SwitchStatement *s)
+ {
+ this->start_scope (level_switch);
+ tree lbreak = this->push_break_label (s);
+
+ tree condition = build_expr_dtor (s->condition);
+ Type *condtype = s->condition->type->toBasetype ();
+
+ /* A switch statement on a string gets turned into a library call,
+ which does a binary lookup on list of string cases. */
+ if (s->condition->type->isString ())
+ {
+ Type *etype = condtype->nextOf ()->toBasetype ();
+ libcall_fn libcall;
+
+ switch (etype->ty)
+ {
+ case Tchar:
+ libcall = LIBCALL_SWITCH_STRING;
+ break;
+
+ case Twchar:
+ libcall = LIBCALL_SWITCH_USTRING;
+ break;
+
+ case Tdchar:
+ libcall = LIBCALL_SWITCH_DSTRING;
+ break;
+
+ default:
+ ::error ("switch statement value must be an array of "
+ "some character type, not %s", etype->toChars ());
+ gcc_unreachable ();
+ }
+
+ /* Apparently the backend is supposed to sort and set the indexes
+ on the case array, have to change them to be usable. */
+ Type *satype = condtype->sarrayOf (s->cases->dim);
+ vec<constructor_elt, va_gc> *elms = NULL;
+
+ s->cases->sort ();
+
+ for (size_t i = 0; i < s->cases->dim; i++)
+ {
+ CaseStatement *cs = (*s->cases)[i];
+ cs->index = i;
+
+ if (cs->exp->op != TOKstring)
+ s->error ("case '%s' is not a string", cs->exp->toChars ());
+ else
+ {
+ tree exp = build_expr (cs->exp, true);
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
+ }
+ }
+
+ /* Build static declaration to reference constructor. */
+ tree ctor = build_constructor (build_ctype (satype), elms);
+ tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
+ TREE_READONLY (decl) = 1;
+ d_pushdecl (decl);
+ rest_of_decl_compilation (decl, 1, 0);
+
+ /* Pass it as a dynamic array. */
+ decl = d_array_value (build_ctype (condtype->arrayOf ()),
+ size_int (s->cases->dim),
+ build_address (decl));
+
+ condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
+ }
+ else if (!condtype->isscalar ())
+ {
+ error ("cannot handle switch condition of type %s",
+ condtype->toChars ());
+ gcc_unreachable ();
+ }
+
+ condition = fold (condition);
+
+ /* Build LABEL_DECLs now so they can be refered to by goto case.
+ Also checking the jump from the switch to the label is allowed. */
+ if (s->cases)
+ {
+ for (size_t i = 0; i < s->cases->dim; i++)
+ {
+ CaseStatement *cs = (*s->cases)[i];
+ tree caselabel = this->lookup_label (cs);
+
+ /* Write cases as a series of if-then-else blocks.
+ if (condition == case)
+ goto caselabel; */
+ if (s->hasVars)
+ {
+ tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
+ condition, build_expr_dtor (cs->exp));
+ tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
+ caselabel);
+ tree cond = build_vcondition (ifcase, ifbody, void_node);
+ TREE_USED (caselabel) = 1;
+ LABEL_VARIABLE_CASE (caselabel) = 1;
+ add_stmt (cond);
+ }
+
+ this->check_goto (s, cs);
+ }
+
+ if (s->sdefault)
+ {
+ tree defaultlabel = this->lookup_label (s->sdefault);
+
+ /* The default label is the last 'else' block. */
+ if (s->hasVars)
+ {
+ this->do_jump (defaultlabel);
+ LABEL_VARIABLE_CASE (defaultlabel) = 1;
+ }
+
+ this->check_goto (s, s->sdefault);
+ }
+ }
+
+ /* Switch body goes in its own statement list. */
+ push_stmt_list ();
+ if (s->_body)
+ this->build_stmt (s->_body);
+
+ tree casebody = pop_stmt_list ();
+
+ /* Wrap up constructed body into a switch_expr, unless it was
+ converted to an if-then-else expression. */
+ if (s->hasVars)
+ add_stmt (casebody);
+ else
+ {
+ tree switchexpr = build2 (SWITCH_EXPR, TREE_TYPE (condition),
+ condition, casebody);
+ add_stmt (switchexpr);
+ SWITCH_ALL_CASES_P (switchexpr) = 1;
+ }
+
+ SWITCH_BREAK_LABEL_P (lbreak) = 1;
+
+ /* If the switch had any 'break' statements, emit the label now. */
+ this->pop_break_label (lbreak);
+ this->finish_scope ();
+ }
+
+ /* Declare the case label associated with the current SwitchStatement. */
+
+ void visit (CaseStatement *s)
+ {
+ /* Emit the case label. */
+ tree label = this->define_label (s);
+
+ if (LABEL_VARIABLE_CASE (label))
+ this->do_label (label);
+ else
+ {
+ tree casevalue;
+ if (s->exp->type->isscalar ())
+ casevalue = build_expr (s->exp);
+ else
+ casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
+
+ tree caselabel = build_case_label (casevalue, NULL_TREE, label);
+ add_stmt (caselabel);
+ }
+
+ /* Now do the body. */
+ if (s->statement)
+ this->build_stmt (s->statement);
+ }
+
+ /* Declare the default label associated with the current SwitchStatement. */
+
+ void visit (DefaultStatement *s)
+ {
+ /* Emit the default case label. */
+ tree label = this->define_label (s);
+
+ if (LABEL_VARIABLE_CASE (label))
+ this->do_label (label);
+ else
+ {
+ tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
+ add_stmt (caselabel);
+ }
+
+ /* Now do the body. */
+ if (s->statement)
+ this->build_stmt (s->statement);
+ }
+
+ /* Implements 'goto default' by jumping to the label associated with
+ the DefaultStatement in a switch block. */
+
+ void visit (GotoDefaultStatement *s)
+ {
+ tree label = this->lookup_label (s->sw->sdefault);
+ this->do_jump (label);
+ }
+
+ /* Implements 'goto case' by jumping to the label associated with the
+ CaseStatement in a switch block. */
+
+ void visit (GotoCaseStatement *s)
+ {
+ tree label = this->lookup_label (s->cs);
+ this->do_jump (label);
+ }
+
+ /* Throw a SwitchError exception, called when a switch statement has
+ no DefaultStatement, yet none of the cases match. */
+
+ void visit (SwitchErrorStatement *s)
+ {
+ add_stmt (d_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
+ }
+
+ /* A return statement exits the current function and supplies its return
+ value, if the return type is not void. */
+
+ void visit (ReturnStatement *s)
+ {
+ if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
+ {
+ /* Return has no value. */
+ add_stmt (return_expr (NULL_TREE));
+ return;
+ }
+
+ TypeFunction *tf = (TypeFunction *)this->func_->type;
+ Type *type = this->func_->tintro != NULL
+ ? this->func_->tintro->nextOf () : tf->nextOf ();
+
+ if ((this->func_->isMain () || this->func_->isCMain ())
+ && type->toBasetype ()->ty == Tvoid)
+ type = Type::tint32;
+
+ if (this->func_->nrvo_can && this->func_->nrvo_var)
+ {
+ /* Just refer to the DECL_RESULT; this differs from using
+ NULL_TREE in that it indicates that we care about the value
+ of the DECL_RESULT. */
+ tree decl = DECL_RESULT (get_symbol_decl (this->func_));
+ add_stmt (return_expr (decl));
+ }
+ else
+ {
+ /* Convert for initializing the DECL_RESULT. */
+ tree expr = build_return_dtor (s->exp, type, tf);
+ add_stmt (expr);
+ }
+ }
+
+ /* Evaluate the enclosed expression, and add it to the statement list. */
+
+ void visit (ExpStatement *s)
+ {
+ if (s->exp)
+ {
+ /* Expression may produce temporaries requiring scope destruction. */
+ tree exp = build_expr_dtor (s->exp);
+ add_stmt (exp);
+ }
+ }
+
+ /* Evaluate all enclosed statements. */
+
+ void visit (CompoundStatement *s)
+ {
+ if (s->statements == NULL)
+ return;
+
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ Statement *statement = (*s->statements)[i];
+
+ if (statement != NULL)
+ this->build_stmt (statement);
+ }
+ }
+
+ /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
+ These are compiled down as a `do ... while (0)', where each unrolled loop
+ is nested inside and given their own continue label to jump to. */
+
+ void visit (UnrolledLoopStatement *s)
+ {
+ if (s->statements == NULL)
+ return;
+
+ tree lbreak = this->push_break_label (s);
+ this->start_scope (level_loop);
+
+ for (size_t i = 0; i < s->statements->dim; i++)
+ {
+ Statement *statement = (*s->statements)[i];
+
+ if (statement != NULL)
+ {
+ tree lcontinue = this->push_continue_label (statement);
+ this->build_stmt (statement);
+ this->pop_continue_label (lcontinue);
+ }
+ }
+
+ this->do_jump (this->break_label_);
+
+ tree body = this->end_scope ();
+ add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+ this->pop_break_label (lbreak);
+ }
+
+ /* Start a new scope and visit all nested statements, wrapping
+ them up into a BIND_EXPR at the end of the scope. */
+
+ void visit (ScopeStatement *s)
+ {
+ if (s->statement == NULL)
+ return;
+
+ this->start_scope (level_block);
+ this->build_stmt (s->statement);
+ this->finish_scope ();
+ }
+
+ /* A with statement is a way to simplify repeated references to the same
+ object, where the handle is either a class or struct instance. */
+
+ void visit (WithStatement *s)
+ {
+ this->start_scope (level_with);
+
+ if (s->wthis)
+ {
+ /* Perform initialisation of the 'with' handle. */
+ ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
+ gcc_assert (ie != NULL);
+
+ declare_local_var (s->wthis);
+ tree init = build_expr_dtor (ie->exp);
+ add_stmt (init);
+ }
+
+ if (s->_body)
+ this->build_stmt (s->_body);
+
+ this->finish_scope ();
+ }
+
+ /* Implements 'throw Object'. Frontend already checks that the object
+ thrown is a class type, but does not check if it is derived from
+ Object. Foreign objects are not currently supported at run-time. */
+
+ void visit (ThrowStatement *s)
+ {
+ ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
+ InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
+ tree arg = build_expr_dtor (s->exp);
+
+ if (!flag_exceptions)
+ {
+ static int warned = 0;
+ if (!warned)
+ {
+ error_at (make_location_t (s->loc), "exception handling disabled, "
+ "use -fexceptions to enable");
+ warned = 1;
+ }
+ }
+
+ if (cd->isCPPclass () || (id != NULL && id->isCPPclass ()))
+ error_at (make_location_t (s->loc), "cannot throw C++ classes");
+ else if (cd->com || (id != NULL && id->com))
+ error_at (make_location_t (s->loc), "cannot throw COM objects");
+ else
+ arg = build_nop (build_ctype (get_object_type ()), arg);
+
+ add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
+ }
+
+ /* Build a try-catch statement, one of the building blocks for exception
+ handling generated by the frontend. This is also used to implement
+ `scope (failure)' statements. */
+
+ void visit (TryCatchStatement *s)
+ {
+ this->start_scope (level_try);
+ if (s->_body)
+ this->build_stmt (s->_body);
+
+ tree trybody = this->end_scope ();
+
+ /* Try handlers go in their own statement list. */
+ push_stmt_list ();
+
+ if (s->catches)
+ {
+ for (size_t i = 0; i < s->catches->dim; i++)
+ {
+ Catch *vcatch = (*s->catches)[i];
+
+ this->start_scope (level_catch);
+
+ tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
+ tree catchtype = build_ctype (vcatch->type);
+ tree object = NULL_TREE;
+
+ ehptr = build_call_expr (ehptr, 1, integer_zero_node);
+
+ /* Retrieve the internal exception object, which could be for a
+ D or C++ catch handler. This is different from the generic
+ exception pointer returned from gcc runtime. */
+ Type *tcatch = vcatch->type->toBasetype ();
+ ClassDeclaration *cd = tcatch->isClassHandle ();
+
+ libcall_fn libcall = (cd->isCPPclass ()) ? LIBCALL_CXA_BEGIN_CATCH
+ : LIBCALL_BEGIN_CATCH;
+ object = build_libcall (libcall, vcatch->type, 1, ehptr);
+
+ if (vcatch->var)
+ {
+ tree var = get_symbol_decl (vcatch->var);
+ tree init = build_assign (INIT_EXPR, var, object);
+
+ declare_local_var (vcatch->var);
+ add_stmt (init);
+ }
+ else
+ {
+ /* Still need to emit a call to __gdc_begin_catch() to
+ remove the object from the uncaught exceptions list. */
+ add_stmt (object);
+ }
+
+ if (vcatch->handler)
+ this->build_stmt (vcatch->handler);
+
+ tree catchbody = this->end_scope ();
+
+ /* Need to wrap C++ handlers in a try/finally block to signal
+ the end catch callback. */
+ if (cd->isCPPclass ())
+ {
+ tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
+ Type::tvoid, 0);
+ catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
+ catchbody, endcatch);
+ }
+
+ add_stmt (build2 (CATCH_EXPR, void_type_node,
+ catchtype, catchbody));
+ }
+ }
+
+ tree catches = pop_stmt_list ();
+
+ /* Back-end expects all catches in a TRY_CATCH_EXPR to be enclosed in a
+ statement list, however pop_stmt_list may optimize away the list
+ if there is only a single catch to push. */
+ if (TREE_CODE (catches) != STATEMENT_LIST)
+ {
+ tree stmt_list = alloc_stmt_list ();
+ append_to_statement_list_force (catches, &stmt_list);
+ catches = stmt_list;
+ }
+
+ add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
+ }
+
+ /* Build a try-finally statement, one of the building blocks for exception
+ handling generated by the frontend. This is also used to implement
+ `scope (exit)' statements. */
+
+ void visit (TryFinallyStatement *s)
+ {
+ this->start_scope (level_try);
+ if (s->_body)
+ this->build_stmt (s->_body);
+
+ tree trybody = this->end_scope ();
+
+ this->start_scope (level_finally);
+ if (s->finalbody)
+ this->build_stmt (s->finalbody);
+
+ tree finally = this->end_scope ();
+
+ add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
+ }
+
+ /* The frontend lowers `synchronized (...)' statements as a call to
+ monitor/critical enter and exit wrapped around try/finally.
+ This visitor is not strictly required other than to enforce that
+ these kinds of statements never reach here. */
+
+ void visit (SynchronizedStatement *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* D Inline Assembler is not implemented, as it would require writing
+ an assembly parser for each supported target. Instead we leverage
+ GCC extended assembler using the GccAsmStatement class. */
+
+ void visit (AsmStatement *)
+ {
+ sorry ("D inline assembler statements are not supported in GDC.");
+ }
+
+ /* Build a GCC extended assembler expression, whose components are
+ an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */
+
+ void visit (GccAsmStatement *s)
+ {
+ StringExp *insn = (StringExp *)s->insn;
+ tree outputs = NULL_TREE;
+ tree inputs = NULL_TREE;
+ tree clobbers = NULL_TREE;
+ tree labels = NULL_TREE;
+
+ /* Collect all arguments, which may be input or output operands. */
+ if (s->args)
+ {
+ for (size_t i = 0; i < s->args->dim; i++)
+ {
+ Identifier *name = (*s->names)[i];
+ const char *sname = name ? name->toChars () : NULL;
+ tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
+
+ StringExp *constr = (StringExp *)(*s->constraints)[i];
+ const char *cstring = (const char *)(constr->len
+ ? constr->string : "");
+ tree str = build_string (constr->len, cstring);
+
+ Expression *earg = (*s->args)[i];
+ tree val = build_expr (earg);
+
+ if (i < s->outputargs)
+ {
+ tree arg = build_tree_list (id, str);
+ outputs = chainon (outputs, build_tree_list (arg, val));
+ }
+ else
+ {
+ tree arg = build_tree_list (id, str);
+ inputs = chainon (inputs, build_tree_list (arg, val));
+ }
+ }
+ }
+
+ /* Collect all clobber arguments. */
+ if (s->clobbers)
+ {
+ for (size_t i = 0; i < s->clobbers->dim; i++)
+ {
+ StringExp *clobber = (StringExp *)(*s->clobbers)[i];
+ const char *cstring = (const char *)(clobber->len
+ ? clobber->string : "");
+
+ tree val = build_string (clobber->len, cstring);
+ clobbers = chainon (clobbers, build_tree_list (0, val));
+ }
+ }
+
+ /* Collect all goto labels, these should have been already checked
+ by the front-end, so pass down the label symbol to the back-end. */
+ if (s->labels)
+ {
+ for (size_t i = 0; i < s->labels->dim; i++)
+ {
+ Identifier *ident = (*s->labels)[i];
+ GotoStatement *gs = (*s->gotos)[i];
+
+ gcc_assert (gs->label->statement != NULL);
+ gcc_assert (gs->tf == gs->label->statement->tf);
+
+ const char *sident = ident->toChars ();
+ tree name = build_string (strlen (sident), sident);
+ tree label = this->lookup_label (gs->label->statement,
+ gs->label->ident);
+ TREE_USED (label) = 1;
+
+ labels = chainon (labels, build_tree_list (name, label));
+ }
+ }
+
+ /* Do some extra validation on all input and output operands. */
+ const char *insnstring = (const char *)(insn->len ? insn->string : "");
+ tree string = build_string (insn->len, insnstring);
+ string = resolve_asm_operand_names (string, outputs, inputs, labels);
+
+ if (s->args)
+ {
+ unsigned noutputs = s->outputargs;
+ unsigned ninputs = (s->args->dim - noutputs);
+ const char **oconstraints = XALLOCAVEC (const char *, noutputs);
+ bool allows_mem, allows_reg, is_inout;
+ size_t i;
+ tree t;
+
+ for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
+ {
+ tree output = TREE_VALUE (t);
+ const char *constraint
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+
+ oconstraints[i] = constraint;
+
+ if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+ &allows_mem, &allows_reg, &is_inout))
+ {
+ /* If the output argument is going to end up in memory. */
+ if (!allows_reg)
+ d_mark_addressable (output);
+ }
+ else
+ output = error_mark_node;
+
+ TREE_VALUE (t) = output;
+ }
+
+ for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
+ {
+ tree input = TREE_VALUE (t);
+ const char *constraint
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+
+ if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+ oconstraints, &allows_mem, &allows_reg))
+ {
+ /* If the input argument is going to end up in memory. */
+ if (!allows_reg && allows_mem)
+ d_mark_addressable (input);
+ }
+ else
+ input = error_mark_node;
+
+ TREE_VALUE (t) = input;
+ }
+ }
+
+ tree exp = build5 (ASM_EXPR, void_type_node, string,
+ outputs, inputs, clobbers, labels);
+ SET_EXPR_LOCATION (exp, make_location_t (s->loc));
+
+ /* If the extended syntax was not used, mark the ASM_EXPR. */
+ if (s->args == NULL && s->clobbers == NULL)
+ ASM_INPUT_P (exp) = 1;
+
+ /* Asm statements are treated as volatile unless 'pure'. */
+ ASM_VOLATILE_P (exp) = !(s->stc & STCpure);
+
+ add_stmt (exp);
+ }
+
+ /* Import symbols from another module. */
+
+ void visit (ImportStatement *s)
+ {
+ if (s->imports == NULL)
+ return;
+
+ for (size_t i = 0; i < s->imports->dim; i++)
+ {
+ Dsymbol *dsym = (*s->imports)[i];
+
+ if (dsym != NULL)
+ build_decl_tree (dsym);
+ }
+ }
+};
+
+/* Main entry point for the IRVisitor interface to generate
+ code for the body of function FD. */
+
+void
+build_function_body (FuncDeclaration *fd)
+{
+ IRVisitor v = IRVisitor (fd);
+ location_t saved_location = input_location;
+ input_location = make_location_t (fd->loc);
+ v.build_stmt (fd->fbody);
+ input_location = saved_location;
+}
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
new file mode 100644
index 0000000..0c2b695
--- /dev/null
+++ b/gcc/d/typeinfo.cc
@@ -0,0 +1,1676 @@
+/* typeinfo.cc -- D runtime type identification.
+ Copyright (C) 2013-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/aggregate.h"
+#include "dmd/enum.h"
+#include "dmd/errors.h"
+#include "dmd/expression.h"
+#include "dmd/globals.h"
+#include "dmd/identifier.h"
+#include "dmd/module.h"
+#include "dmd/mtype.h"
+#include "dmd/template.h"
+#include "dmd/target.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stringpool.h"
+#include "toplev.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "d-target.h"
+
+
+/* D returns type information to the user as TypeInfo class objects, and can
+ be retrieved for any type using `typeid()'. We also use type information
+ to implement many runtime library helpers, including `new', `delete', most
+ dynamic array operations, and all associative array operations.
+
+ Type information for a particular type is indicated with an ABI defined
+ structure derived from TypeInfo. This would all be very straight forward,
+ but for the fact that the runtime library provides the definitions of the
+ TypeInfo structure and the ABI defined derived classes in `object.d', as
+ well as having specific implementations of TypeInfo for built-in types
+ in `rt/typeinfo`. We cannot build declarations of these directly in the
+ compiler, but we need to layout objects of their type.
+
+ To get around this, we define layout compatible POD-structs and generate the
+ appropriate initializations for them. When we have to provide a TypeInfo to
+ the user, we cast the internal compiler type to TypeInfo.
+
+ It is only required that TypeInfo has a definition in `object.d'. It could
+ happen that we are generating a type information for a TypeInfo object that
+ has no declaration. We however only need the addresses of such incomplete
+ TypeInfo objects for static initialization. */
+
+enum tinfo_kind
+{
+ TK_TYPEINFO_TYPE, /* object.TypeInfo */
+ TK_CLASSINFO_TYPE, /* object.TypeInfo_Class */
+ TK_INTERFACE_TYPE, /* object.TypeInfo_Interface */
+ TK_STRUCT_TYPE, /* object.TypeInfo_Struct */
+ TK_POINTER_TYPE, /* object.TypeInfo_Pointer */
+ TK_ARRAY_TYPE, /* object.TypeInfo_Array */
+ TK_STATICARRAY_TYPE, /* object.TypeInfo_StaticArray */
+ TK_ASSOCIATIVEARRAY_TYPE, /* object.TypeInfo_AssociativeArray */
+ TK_VECTOR_TYPE, /* object.TypeInfo_Vector */
+ TK_ENUMERAL_TYPE, /* object.TypeInfo_Enum */
+ TK_FUNCTION_TYPE, /* object.TypeInfo_Function */
+ TK_DELEGATE_TYPE, /* object.TypeInfo_Delegate */
+ TK_TYPELIST_TYPE, /* object.TypeInfo_Tuple */
+ TK_CONST_TYPE, /* object.TypeInfo_Const */
+ TK_IMMUTABLE_TYPE, /* object.TypeInfo_Invariant */
+ TK_SHARED_TYPE, /* object.TypeInfo_Shared */
+ TK_INOUT_TYPE, /* object.TypeInfo_Inout */
+ TK_CPPTI_TYPE, /* object.__cpp_type_info_ptr */
+ TK_END
+};
+
+/* An array of all internal TypeInfo derived types we need.
+ The TypeInfo and ClassInfo types are created early, the
+ remainder are generated as needed. */
+
+static GTY(()) tree tinfo_types[TK_END];
+
+/* Return the kind of TypeInfo used to describe TYPE. */
+
+static tinfo_kind
+get_typeinfo_kind (Type *type)
+{
+ /* Check head shared/const modifiers first. */
+ if (type->isShared ())
+ return TK_SHARED_TYPE;
+ else if (type->isConst ())
+ return TK_CONST_TYPE;
+ else if (type->isImmutable ())
+ return TK_IMMUTABLE_TYPE;
+ else if (type->isWild ())
+ return TK_INOUT_TYPE;
+
+ switch (type->ty)
+ {
+ case Tpointer:
+ return TK_POINTER_TYPE;
+
+ case Tarray:
+ return TK_ARRAY_TYPE;
+
+ case Tsarray:
+ return TK_STATICARRAY_TYPE;
+
+ case Taarray:
+ return TK_ASSOCIATIVEARRAY_TYPE;
+
+ case Tstruct:
+ return TK_STRUCT_TYPE;
+
+ case Tvector:
+ return TK_VECTOR_TYPE;
+
+ case Tenum:
+ return TK_ENUMERAL_TYPE;
+
+ case Tfunction:
+ return TK_FUNCTION_TYPE;
+
+ case Tdelegate:
+ return TK_DELEGATE_TYPE;
+
+ case Ttuple:
+ return TK_TYPELIST_TYPE;
+
+ case Tclass:
+ if (((TypeClass *) type)->sym->isInterfaceDeclaration ())
+ return TK_INTERFACE_TYPE;
+ else
+ return TK_CLASSINFO_TYPE;
+
+ default:
+ return TK_TYPEINFO_TYPE;
+ }
+}
+
+/* Generate the RECORD_TYPE containing the data layout of a TypeInfo derivative
+ as used by the runtime. This layout must be consistent with that defined in
+ the `object.d' module. */
+
+static void
+make_internal_typeinfo (tinfo_kind tk, Identifier *ident, ...)
+{
+ va_list ap;
+
+ va_start (ap, ident);
+
+ /* First two fields are from the TypeInfo base class.
+ Note, finish_builtin_struct() expects these fields in reverse order. */
+ tree fields = create_field_decl (ptr_type_node, NULL, 1, 1);
+ DECL_CHAIN (fields) = create_field_decl (vtbl_ptr_type_node, NULL, 1, 1);
+
+ /* Now add the derived fields. */
+ tree field_type = va_arg (ap, tree);
+ while (field_type != NULL_TREE)
+ {
+ tree field = create_field_decl (field_type, NULL, 1, 1);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+ field_type = va_arg (ap, tree);
+ }
+
+ /* Create the TypeInfo type. */
+ tree type = make_node (RECORD_TYPE);
+ finish_builtin_struct (type, ident->toChars (), fields, NULL_TREE);
+
+ tinfo_types[tk] = type;
+
+ va_end (ap);
+}
+
+/* Helper for create_tinfo_types. Creates a typeinfo class declaration
+ incase one wasn't supplied by reading `object.d'. */
+
+static void
+make_frontend_typeinfo (Module *mod, Identifier *ident,
+ ClassDeclaration *base = NULL)
+{
+ if (!base)
+ base = Type::dtypeinfo;
+
+ /* Create object module in order to complete the semantic. */
+ if (!mod->_scope)
+ mod->importAll (NULL);
+
+ /* Assignment of global typeinfo variables is managed by the ClassDeclaration
+ constructor, so only need to new the declaration here. */
+ Loc loc = (mod->md) ? mod->md->loc : mod->loc;
+ ClassDeclaration *tinfo = ClassDeclaration::create (loc, ident, NULL, NULL,
+ true);
+ tinfo->parent = mod;
+ tinfo->semantic (mod->_scope);
+ tinfo->baseClass = base;
+}
+
+/* Make sure the required builtin types exist for generating the TypeInfo
+ variable definitions. */
+
+void
+create_tinfo_types (Module *mod)
+{
+ /* Build the internal TypeInfo and ClassInfo types.
+ See TypeInfoVisitor for documentation of field layout. */
+ make_internal_typeinfo (TK_TYPEINFO_TYPE, Identifier::idPool ("TypeInfo"),
+ NULL);
+
+ make_internal_typeinfo (TK_CLASSINFO_TYPE,
+ Identifier::idPool ("TypeInfo_Class"),
+ array_type_node, array_type_node, array_type_node,
+ array_type_node, ptr_type_node, ptr_type_node,
+ ptr_type_node, d_uint_type, ptr_type_node,
+ array_type_node, ptr_type_node, ptr_type_node, NULL);
+
+ /* Create all frontend TypeInfo classes declarations. We rely on all
+ existing, even if only just as stubs. */
+ if (!Type::dtypeinfo)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo"),
+ ClassDeclaration::object);
+
+ if (!Type::typeinfoclass)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Class"));
+
+ if (!Type::typeinfointerface)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Interface"));
+
+ if (!Type::typeinfostruct)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Struct"));
+
+ if (!Type::typeinfopointer)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Pointer"));
+
+ if (!Type::typeinfoarray)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Array"));
+
+ if (!Type::typeinfostaticarray)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_StaticArray"));
+
+ if (!Type::typeinfoassociativearray)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_AssociativeArray"));
+
+ if (!Type::typeinfoenum)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Enum"));
+
+ if (!Type::typeinfofunction)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Function"));
+
+ if (!Type::typeinfodelegate)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Delegate"));
+
+ if (!Type::typeinfotypelist)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Tuple"));
+
+ if (!Type::typeinfoconst)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Const"));
+
+ if (!Type::typeinfoinvariant)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Invariant"),
+ Type::typeinfoconst);
+
+ if (!Type::typeinfoshared)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Shared"),
+ Type::typeinfoconst);
+
+ if (!Type::typeinfowild)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Wild"),
+ Type::typeinfoconst);
+
+ if (!Type::typeinfovector)
+ make_frontend_typeinfo (mod, Identifier::idPool ("TypeInfo_Vector"));
+
+ if (!ClassDeclaration::cpp_type_info_ptr)
+ make_frontend_typeinfo (mod, Identifier::idPool ("__cpp_type_info_ptr"),
+ ClassDeclaration::object);
+}
+
+/* Implements the visitor interface to build the TypeInfo layout of all
+ TypeInfoDeclaration AST classes emitted from the D Front-end.
+ All visit methods accept one parameter D, which holds the frontend AST
+ of the TypeInfo class. They also don't return any value, instead the
+ generated symbol is cached internally and returned from the caller. */
+
+class TypeInfoVisitor : public Visitor
+{
+ using Visitor::visit;
+
+ tree type_;
+ vec<constructor_elt, va_gc> *init_;
+
+ /* Add VALUE to the constructor values list. */
+
+ void layout_field (tree value)
+ {
+ CONSTRUCTOR_APPEND_ELT (this->init_, NULL_TREE, value);
+ }
+
+ /* Write out STR as a static D string literal. */
+
+ void layout_string (const char *str)
+ {
+ unsigned len = strlen (str);
+ tree value = build_string (len, str);
+
+ TREE_TYPE (value) = make_array_type (Type::tchar, len);
+ TREE_CONSTANT (value) = 1;
+ TREE_READONLY (value) = 1;
+ TREE_STATIC (value) = 1;
+
+ /* Taking the address, so assign the literal to a static var. */
+ tree decl = build_artificial_decl (TREE_TYPE (value), value);
+ TREE_READONLY (decl) = 1;
+ DECL_EXTERNAL (decl) = 0;
+ d_pushdecl (decl);
+
+ value = d_array_value (build_ctype (Type::tchar->arrayOf ()),
+ size_int (len), build_address (decl));
+ this->layout_field (value);
+ }
+
+
+ /* Write out the __vptr and __monitor fields of class CD. */
+
+ void layout_base (ClassDeclaration *cd)
+ {
+ gcc_assert (cd != NULL);
+ this->layout_field (build_address (get_vtable_decl (cd)));
+ this->layout_field (null_pointer_node);
+ }
+
+ /* Write out the interfaces field of class CD.
+ Returns the array of interfaces that the field is pointing to. */
+
+ tree layout_interfaces (ClassDeclaration *cd)
+ {
+ size_t offset = int_size_in_bytes (tinfo_types[TK_CLASSINFO_TYPE]);
+ tree csym = build_address (get_classinfo_decl (cd));
+
+ /* Put out the offset to where vtblInterfaces are written. */
+ tree value = d_array_value (array_type_node,
+ size_int (cd->vtblInterfaces->dim),
+ build_offset (csym, size_int (offset)));
+ this->layout_field (value);
+
+ /* Internally, the compiler sees Interface as:
+ void*[4] interface;
+
+ The run-time layout of Interface is:
+ TypeInfo_Class classinfo;
+ void*[] vtbl;
+ size_t offset; */
+ vec<constructor_elt, va_gc> *elms = NULL;
+
+ for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+ {
+ BaseClass *b = (*cd->vtblInterfaces)[i];
+ ClassDeclaration *id = b->sym;
+ vec<constructor_elt, va_gc> *v = NULL;
+
+ /* Fill in the vtbl[]. */
+ if (!cd->isInterfaceDeclaration ())
+ b->fillVtbl (cd, &b->vtbl, 1);
+
+ /* ClassInfo for the interface. */
+ value = build_address (get_classinfo_decl (id));
+ CONSTRUCTOR_APPEND_ELT (v, size_int (0), value);
+
+ if (!cd->isInterfaceDeclaration ())
+ {
+ /* The vtable of the interface length and ptr. */
+ unsigned voffset = base_vtable_offset (cd, b);
+ gcc_assert (voffset != 0u);
+ value = build_offset (csym, size_int (voffset));
+
+ CONSTRUCTOR_APPEND_ELT (v, size_int (1), size_int (id->vtbl.dim));
+ CONSTRUCTOR_APPEND_ELT (v, size_int (2), value);
+ }
+
+ /* The 'this' offset. */
+ CONSTRUCTOR_APPEND_ELT (v, size_int (3), size_int (b->offset));
+
+ /* Add to the array of interfaces. */
+ value = build_constructor (vtbl_interface_type_node, v);
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+ }
+
+ tree domain = size_int (cd->vtblInterfaces->dim - 1);
+ tree arrtype = build_array_type (vtbl_interface_type_node,
+ build_index_type (domain));
+ return build_constructor (arrtype, elms);
+ }
+
+ /* Write out the interfacing vtable[] of base class BCD that will be accessed
+ from the overriding class CD. If both are the same class, then this will
+ be its own vtable. INDEX is the offset in the interfaces array of the
+ base class where the Interface reference can be found.
+ This must be mirrored with base_vtable_offset(). */
+
+ void layout_base_vtable (ClassDeclaration *cd, ClassDeclaration *bcd,
+ size_t index)
+ {
+ BaseClass *bs = (*bcd->vtblInterfaces)[index];
+ ClassDeclaration *id = bs->sym;
+ vec<constructor_elt, va_gc> *elms = NULL;
+ FuncDeclarations bvtbl;
+
+ if (id->vtbl.dim == 0 || base_vtable_offset (cd, bs) == ~0u)
+ return;
+
+ /* Fill bvtbl with the functions we want to put out. */
+ if (cd != bcd && !bs->fillVtbl (cd, &bvtbl, 0))
+ return;
+
+ /* First entry is struct Interface reference. */
+ if (id->vtblOffset ())
+ {
+ size_t offset = int_size_in_bytes (tinfo_types[TK_CLASSINFO_TYPE]);
+ offset += (index * int_size_in_bytes (vtbl_interface_type_node));
+ tree value = build_offset (build_address (get_classinfo_decl (bcd)),
+ size_int (offset));
+ CONSTRUCTOR_APPEND_ELT (elms, size_zero_node, value);
+ }
+
+ for (size_t i = id->vtblOffset () ? 1 : 0; i < id->vtbl.dim; i++)
+ {
+ FuncDeclaration *fd = (cd == bcd) ? bs->vtbl[i] : bvtbl[i];
+ if (fd != NULL)
+ {
+ tree value = build_address (make_thunk (fd, bs->offset));
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+ }
+ }
+
+ tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1));
+ tree vtbltype = build_array_type (vtable_entry_type, vtbldomain);
+ tree value = build_constructor (vtbltype, elms);
+ this->layout_field (value);
+ }
+
+
+public:
+ TypeInfoVisitor (tree type)
+ {
+ this->type_ = type;
+ this->init_ = NULL;
+ }
+
+ /* Return the completed constructor for the TypeInfo record. */
+
+ tree result (void)
+ {
+ return build_struct_literal (this->type_, this->init_);
+ }
+
+ /* Layout of TypeInfo is:
+ void **__vptr;
+ void *__monitor; */
+
+ void visit (TypeInfoDeclaration *)
+ {
+ /* The vtable for TypeInfo. */
+ this->layout_base (Type::dtypeinfo);
+ }
+
+ /* Layout of TypeInfo_Const is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo base; */
+
+ void visit (TypeInfoConstDeclaration *d)
+ {
+ Type *tm = d->tinfo->mutableOf ();
+ tm = tm->merge2 ();
+
+ /* The vtable for TypeInfo_Const. */
+ this->layout_base (Type::typeinfoconst);
+
+ /* TypeInfo for the mutable type. */
+ this->layout_field (build_typeinfo (tm));
+ }
+
+ /* Layout of TypeInfo_Immutable is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo base; */
+
+ void visit (TypeInfoInvariantDeclaration *d)
+ {
+ Type *tm = d->tinfo->mutableOf ();
+ tm = tm->merge2 ();
+
+ /* The vtable for TypeInfo_Invariant. */
+ this->layout_base (Type::typeinfoinvariant);
+
+ /* TypeInfo for the mutable type. */
+ this->layout_field (build_typeinfo (tm));
+ }
+
+ /* Layout of TypeInfo_Shared is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo base; */
+
+ void visit (TypeInfoSharedDeclaration *d)
+ {
+ Type *tm = d->tinfo->unSharedOf ();
+ tm = tm->merge2 ();
+
+ /* The vtable for TypeInfo_Shared. */
+ this->layout_base (Type::typeinfoshared);
+
+ /* TypeInfo for the unshared type. */
+ this->layout_field (build_typeinfo (tm));
+ }
+
+ /* Layout of TypeInfo_Inout is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo base; */
+
+ void visit (TypeInfoWildDeclaration *d)
+ {
+ Type *tm = d->tinfo->mutableOf ();
+ tm = tm->merge2 ();
+
+ /* The vtable for TypeInfo_Inout. */
+ this->layout_base (Type::typeinfowild);
+
+ /* TypeInfo for the mutable type. */
+ this->layout_field (build_typeinfo (tm));
+ }
+
+ /* Layout of TypeInfo_Enum is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo base;
+ string name;
+ void[] m_init; */
+
+ void visit (TypeInfoEnumDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tenum);
+ TypeEnum *ti = (TypeEnum *) d->tinfo;
+ EnumDeclaration *ed = ti->sym;
+
+ /* The vtable for TypeInfo_Enum. */
+ this->layout_base (Type::typeinfoenum);
+
+ /* TypeInfo for enum members. */
+ tree memtype = (ed->memtype) ? build_typeinfo (ed->memtype)
+ : null_pointer_node;
+ this->layout_field (memtype);
+
+ /* Name of the enum declaration. */
+ this->layout_string (ed->toPrettyChars ());
+
+ /* Default initializer for enum. */
+ if (ed->members && !d->tinfo->isZeroInit ())
+ {
+ tree length = size_int (ed->type->size ());
+ tree ptr = build_address (enum_initializer_decl (ed));
+ this->layout_field (d_array_value (array_type_node, length, ptr));
+ }
+ else
+ this->layout_field (null_array_node);
+ }
+
+ /* Layout of TypeInfo_Pointer is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo m_next; */
+
+ void visit (TypeInfoPointerDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tpointer);
+ TypePointer *ti = (TypePointer *) d->tinfo;
+
+ /* The vtable for TypeInfo_Pointer. */
+ this->layout_base (Type::typeinfopointer);
+
+ /* TypeInfo for pointer-to type. */
+ this->layout_field (build_typeinfo (ti->next));
+ }
+
+ /* Layout of TypeInfo_Array is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo value; */
+
+ void visit (TypeInfoArrayDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tarray);
+ TypeDArray *ti = (TypeDArray *) d->tinfo;
+
+ /* The vtable for TypeInfo_Array. */
+ this->layout_base (Type::typeinfoarray);
+
+ /* TypeInfo for array of type. */
+ this->layout_field (build_typeinfo (ti->next));
+ }
+
+ /* Layout of TypeInfo_StaticArray is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo value;
+ size_t len; */
+
+ void visit (TypeInfoStaticArrayDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tsarray);
+ TypeSArray *ti = (TypeSArray *) d->tinfo;
+
+ /* The vtable for TypeInfo_StaticArray. */
+ this->layout_base (Type::typeinfostaticarray);
+
+ /* TypeInfo for array of type. */
+ this->layout_field (build_typeinfo (ti->next));
+
+ /* Static array length. */
+ this->layout_field (size_int (ti->dim->toInteger ()));
+ }
+
+ /* Layout of TypeInfo_AssociativeArray is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo value;
+ TypeInfo key; */
+
+ void visit (TypeInfoAssociativeArrayDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Taarray);
+ TypeAArray *ti = (TypeAArray *) d->tinfo;
+
+ /* The vtable for TypeInfo_AssociativeArray. */
+ this->layout_base (Type::typeinfoassociativearray);
+
+ /* TypeInfo for value of type. */
+ this->layout_field (build_typeinfo (ti->next));
+
+ /* TypeInfo for index of type. */
+ this->layout_field (build_typeinfo (ti->index));
+ }
+
+ /* Layout of TypeInfo_Vector is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo base; */
+
+ void visit (TypeInfoVectorDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tvector);
+ TypeVector *ti = (TypeVector *) d->tinfo;
+
+ /* The vtable for TypeInfo_Vector. */
+ this->layout_base (Type::typeinfovector);
+
+ /* TypeInfo for equivalent static array. */
+ this->layout_field (build_typeinfo (ti->basetype));
+ }
+
+ /* Layout of TypeInfo_Function is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo next;
+ string deco; */
+
+ void visit (TypeInfoFunctionDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tfunction && d->tinfo->deco != NULL);
+ TypeFunction *ti = (TypeFunction *) d->tinfo;
+
+ /* The vtable for TypeInfo_Function. */
+ this->layout_base (Type::typeinfofunction);
+
+ /* TypeInfo for function return value. */
+ this->layout_field (build_typeinfo (ti->next));
+
+ /* Mangled name of function declaration. */
+ this->layout_string (d->tinfo->deco);
+ }
+
+ /* Layout of TypeInfo_Delegate is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo next;
+ string deco; */
+
+ void visit (TypeInfoDelegateDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tdelegate && d->tinfo->deco != NULL);
+ TypeDelegate *ti = (TypeDelegate *) d->tinfo;
+
+ /* The vtable for TypeInfo_Delegate. */
+ this->layout_base (Type::typeinfodelegate);
+
+ /* TypeInfo for delegate return value. */
+ this->layout_field (build_typeinfo (ti->next));
+
+ /* Mangled name of delegate declaration. */
+ this->layout_string (d->tinfo->deco);
+ }
+
+ /* Layout of ClassInfo/TypeInfo_Class is:
+ void **__vptr;
+ void *__monitor;
+ byte[] m_init;
+ string name;
+ void*[] vtbl;
+ Interface[] interfaces;
+ TypeInfo_Class base;
+ void *destructor;
+ void function(Object) classInvariant;
+ ClassFlags m_flags;
+ void *deallocator;
+ OffsetTypeInfo[] m_offTi;
+ void function(Object) defaultConstructor;
+ immutable(void)* m_RTInfo;
+
+ Information relating to interfaces, and their vtables are laid out
+ immediately after the named fields, if there is anything to write. */
+
+ void visit (TypeInfoClassDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tclass);
+ TypeClass *ti = (TypeClass *) d->tinfo;
+ ClassDeclaration *cd = ti->sym;
+
+ /* The vtable for ClassInfo. */
+ this->layout_base (Type::typeinfoclass);
+
+ if (!cd->members)
+ return;
+
+ tree interfaces = NULL_TREE;
+
+ if (!cd->isInterfaceDeclaration ())
+ {
+ /* Default initializer for class. */
+ tree init = aggregate_initializer_decl (cd);
+ tree value = d_array_value (array_type_node, size_int (cd->structsize),
+ build_address (init));
+ this->layout_field (value);
+
+ /* Name of the class declaration. */
+ const char *name = cd->ident->toChars ();
+ if (!(strlen (name) > 9 && memcmp (name, "TypeInfo_", 9) == 0))
+ name = cd->toPrettyChars ();
+ this->layout_string (name);
+
+ /* The vtable of the class declaration. */
+ value = d_array_value (array_type_node, size_int (cd->vtbl.dim),
+ build_address (get_vtable_decl (cd)));
+ this->layout_field (value);
+
+ /* Array of base interfaces that have their own vtable. */
+ if (cd->vtblInterfaces->dim)
+ interfaces = this->layout_interfaces (cd);
+ else
+ this->layout_field (null_array_node);
+
+ /* TypeInfo_Class base; */
+ tree base = (cd->baseClass)
+ ? build_address (get_classinfo_decl (cd->baseClass))
+ : null_pointer_node;
+ this->layout_field (base);
+
+ /* void *destructor; */
+ tree dtor = (cd->dtor) ? build_address (get_symbol_decl (cd->dtor))
+ : null_pointer_node;
+ this->layout_field (dtor);
+
+ /* void function(Object) classInvariant; */
+ tree inv = (cd->inv) ? build_address (get_symbol_decl (cd->inv))
+ : null_pointer_node;
+ this->layout_field (inv);
+
+ /* ClassFlags m_flags; */
+ ClassFlags::Type flags = ClassFlags::hasOffTi;
+ if (cd->isCOMclass ())
+ flags |= ClassFlags::isCOMclass;
+
+ if (cd->isCPPclass ())
+ flags |= ClassFlags::isCPPclass;
+
+ flags |= ClassFlags::hasGetMembers;
+ flags |= ClassFlags::hasTypeInfo;
+
+ if (cd->ctor)
+ flags |= ClassFlags::hasCtor;
+
+ for (ClassDeclaration *bcd = cd; bcd; bcd = bcd->baseClass)
+ {
+ if (bcd->dtor)
+ {
+ flags |= ClassFlags::hasDtor;
+ break;
+ }
+ }
+
+ if (cd->isAbstract ())
+ flags |= ClassFlags::isAbstract;
+
+ for (ClassDeclaration *bcd = cd; bcd; bcd = bcd->baseClass)
+ {
+ if (!bcd->members)
+ continue;
+
+ for (size_t i = 0; i < bcd->members->dim; i++)
+ {
+ Dsymbol *sm = (*bcd->members)[i];
+ if (sm->hasPointers ())
+ goto Lhaspointers;
+ }
+ }
+
+ flags |= ClassFlags::noPointers;
+
+ Lhaspointers:
+ this->layout_field (size_int (flags));
+
+ /* void *deallocator; */
+ tree ddtor = (cd->aggDelete)
+ ? build_address (get_symbol_decl (cd->aggDelete))
+ : null_pointer_node;
+ this->layout_field (ddtor);
+
+ /* OffsetTypeInfo[] m_offTi; (not implemented) */
+ this->layout_field (null_array_node);
+
+ /* void function(Object) defaultConstructor; */
+ if (cd->defaultCtor && !(cd->defaultCtor->storage_class & STCdisable))
+ {
+ tree dctor = get_symbol_decl (cd->defaultCtor);
+ this->layout_field (build_address (dctor));
+ }
+ else
+ this->layout_field (null_pointer_node);
+
+ /* immutable(void)* m_RTInfo; */
+ if (cd->getRTInfo)
+ this->layout_field (build_expr (cd->getRTInfo, true));
+ else if (!(flags & ClassFlags::noPointers))
+ this->layout_field (size_one_node);
+ }
+ else
+ {
+ /* No initializer for interface. */
+ this->layout_field (null_array_node);
+
+ /* Name of the interface declaration. */
+ this->layout_string (cd->toPrettyChars ());
+
+ /* No vtable for interface declaration. */
+ this->layout_field (null_array_node);
+
+ /* Array of base interfaces that have their own vtable. */
+ if (cd->vtblInterfaces->dim)
+ interfaces = this->layout_interfaces (cd);
+ else
+ this->layout_field (null_array_node);
+
+ /* TypeInfo_Class base;
+ void *destructor;
+ void function(Object) classInvariant; */
+ this->layout_field (null_pointer_node);
+ this->layout_field (null_pointer_node);
+ this->layout_field (null_pointer_node);
+
+ /* ClassFlags m_flags; */
+ ClassFlags::Type flags = ClassFlags::hasOffTi;
+ flags |= ClassFlags::hasTypeInfo;
+ if (cd->isCOMinterface ())
+ flags |= ClassFlags::isCOMclass;
+
+ this->layout_field (size_int (flags));
+
+ /* void *deallocator;
+ OffsetTypeInfo[] m_offTi; (not implemented)
+ void function(Object) defaultConstructor; */
+ this->layout_field (null_pointer_node);
+ this->layout_field (null_array_node);
+ this->layout_field (null_pointer_node);
+
+ /* immutable(void)* m_RTInfo; */
+ if (cd->getRTInfo)
+ this->layout_field (build_expr (cd->getRTInfo, true));
+ else
+ this->layout_field (null_pointer_node);
+ }
+
+ /* Put out array of Interfaces. */
+ if (interfaces != NULL_TREE)
+ this->layout_field (interfaces);
+
+ if (!cd->isInterfaceDeclaration ())
+ {
+ /* Put out this class' interface vtables[]. */
+ for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+ this->layout_base_vtable (cd, cd, i);
+
+ /* Put out the overriding interface vtables[]. */
+ for (ClassDeclaration *bcd = cd->baseClass; bcd; bcd = bcd->baseClass)
+ {
+ for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++)
+ this->layout_base_vtable (cd, bcd, i);
+ }
+ }
+ }
+
+ /* Layout of TypeInfo_Interface is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo_Class info; */
+
+ void visit (TypeInfoInterfaceDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tclass);
+ TypeClass *ti = (TypeClass *) d->tinfo;
+
+ if (!ti->sym->vclassinfo)
+ ti->sym->vclassinfo = TypeInfoClassDeclaration::create (ti);
+
+ /* The vtable for TypeInfo_Interface. */
+ this->layout_base (Type::typeinfointerface);
+
+ /* TypeInfo for class inheriting the interface. */
+ tree tidecl = get_typeinfo_decl (ti->sym->vclassinfo);
+ this->layout_field (build_address (tidecl));
+ }
+
+ /* Layout of TypeInfo_Struct is:
+ void **__vptr;
+ void *__monitor;
+ string name;
+ void[] m_init;
+ hash_t function(in void*) xtoHash;
+ bool function(in void*, in void*) xopEquals;
+ int function(in void*, in void*) xopCmp;
+ string function(const(void)*) xtoString;
+ StructFlags m_flags;
+ void function(void*) xdtor;
+ void function(void*) xpostblit;
+ uint m_align;
+ version (X86_64)
+ TypeInfo m_arg1;
+ TypeInfo m_arg2;
+ immutable(void)* xgetRTInfo; */
+
+ void visit (TypeInfoStructDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Tstruct);
+ TypeStruct *ti = (TypeStruct *) d->tinfo;
+ StructDeclaration *sd = ti->sym;
+
+ /* The vtable for TypeInfo_Struct. */
+ this->layout_base (Type::typeinfostruct);
+
+ if (!sd->members)
+ return;
+
+ /* Name of the struct declaration. */
+ this->layout_string (sd->toPrettyChars ());
+
+ /* Default initializer for struct. */
+ tree ptr = (sd->zeroInit) ? null_pointer_node
+ : build_address (aggregate_initializer_decl (sd));
+ this->layout_field (d_array_value (array_type_node,
+ size_int (sd->structsize), ptr));
+
+ /* hash_t function (in void*) xtoHash; */
+ tree xhash = (sd->xhash) ? build_address (get_symbol_decl (sd->xhash))
+ : null_pointer_node;
+ this->layout_field (xhash);
+
+ if (sd->xhash)
+ {
+ TypeFunction *tf = (TypeFunction *) sd->xhash->type;
+ gcc_assert (tf->ty == Tfunction);
+ if (!tf->isnothrow || tf->trust == TRUSTsystem)
+ {
+ warning (sd->xhash->loc, "toHash() must be declared as "
+ "extern (D) size_t toHash() const nothrow @safe, "
+ "not %s", tf->toChars ());
+ }
+ }
+
+ /* bool function(in void*, in void*) xopEquals; */
+ tree xeq = (sd->xeq) ? build_address (get_symbol_decl (sd->xeq))
+ : null_pointer_node;
+ this->layout_field (xeq);
+
+ /* int function(in void*, in void*) xopCmp; */
+ tree xcmp = (sd->xcmp) ? build_address (get_symbol_decl (sd->xcmp))
+ : null_pointer_node;
+ this->layout_field (xcmp);
+
+ /* string function(const(void)*) xtoString; */
+ FuncDeclaration *fdx = search_toString (sd);
+ if (fdx)
+ this->layout_field (build_address (get_symbol_decl (fdx)));
+ else
+ this->layout_field (null_pointer_node);
+
+ /* StructFlags m_flags; */
+ StructFlags::Type m_flags = 0;
+ if (ti->hasPointers ())
+ m_flags |= StructFlags::hasPointers;
+ this->layout_field (size_int (m_flags));
+
+ /* void function(void*) xdtor; */
+ tree dtor = (sd->dtor) ? build_address (get_symbol_decl (sd->dtor))
+ : null_pointer_node;
+ this->layout_field (dtor);
+
+ /* void function(void*) xpostblit; */
+ if (sd->postblit && !(sd->postblit->storage_class & STCdisable))
+ this->layout_field (build_address (get_symbol_decl (sd->postblit)));
+ else
+ this->layout_field (null_pointer_node);
+
+ /* uint m_align; */
+ this->layout_field (size_int (ti->alignsize ()));
+
+ if (global.params.is64bit)
+ {
+ /* TypeInfo m_arg1; */
+ tree arg1type = (sd->arg1type) ? build_typeinfo (sd->arg1type)
+ : null_pointer_node;
+ this->layout_field (arg1type);
+
+ /* TypeInfo m_arg2; */
+ tree arg2type = (sd->arg2type) ? build_typeinfo (sd->arg2type)
+ : null_pointer_node;
+ this->layout_field (arg2type);
+ }
+
+ /* immutable(void)* xgetRTInfo; */
+ if (sd->getRTInfo)
+ this->layout_field (build_expr (sd->getRTInfo, true));
+ else if (m_flags & StructFlags::hasPointers)
+ this->layout_field (size_one_node);
+ }
+
+ /* Layout of TypeInfo_Tuple is:
+ void **__vptr;
+ void *__monitor;
+ TypeInfo[] elements; */
+
+ void visit (TypeInfoTupleDeclaration *d)
+ {
+ gcc_assert (d->tinfo->ty == Ttuple);
+ TypeTuple *ti = (TypeTuple *) d->tinfo;
+
+ /* The vtable for TypeInfo_Tuple. */
+ this->layout_base (Type::typeinfotypelist);
+
+ /* TypeInfo[] elements; */
+ Type *satype = Type::tvoidptr->sarrayOf (ti->arguments->dim);
+ vec<constructor_elt, va_gc> *elms = NULL;
+ for (size_t i = 0; i < ti->arguments->dim; i++)
+ {
+ Parameter *arg = (*ti->arguments)[i];
+ CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+ build_typeinfo (arg->type));
+ }
+ tree ctor = build_constructor (build_ctype (satype), elms);
+ tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
+
+ /* The internal pointer reference should be public, but not visible outside
+ the compilation unit, as it's referencing COMDAT decls. */
+ TREE_PUBLIC (decl) = 1;
+ DECL_VISIBILITY (decl) = VISIBILITY_INTERNAL;
+ DECL_COMDAT (decl) = 1;
+
+ tree length = size_int (ti->arguments->dim);
+ tree ptr = build_address (decl);
+ this->layout_field (d_array_value (array_type_node, length, ptr));
+
+ d_pushdecl (decl);
+ rest_of_decl_compilation (decl, 1, 0);
+ }
+};
+
+
+/* Main entry point for TypeInfoVisitor interface to generate
+ TypeInfo constructor for the TypeInfoDeclaration AST class D. */
+
+tree
+layout_typeinfo (TypeInfoDeclaration *d)
+{
+ tree type = TREE_TYPE (get_typeinfo_decl (d));
+ TypeInfoVisitor v = TypeInfoVisitor (type);
+ d->accept (&v);
+ return v.result ();
+}
+
+/* Like layout_typeinfo, but generates the TypeInfo_Class for
+ the class or interface declaration CD. */
+
+tree
+layout_classinfo (ClassDeclaration *cd)
+{
+ TypeInfoClassDeclaration *d = TypeInfoClassDeclaration::create (cd->type);
+ tree type = TREE_TYPE (get_classinfo_decl (cd));
+ TypeInfoVisitor v = TypeInfoVisitor (type);
+ d->accept (&v);
+ return v.result ();
+}
+
+/* Layout fields that immediately come after the classinfo type for DECL if
+ there's any interfaces or interface vtables to be added.
+ This must be mirrored with base_vtable_offset(). */
+
+static tree
+layout_classinfo_interfaces (ClassDeclaration *decl)
+{
+ tree type = tinfo_types[TK_CLASSINFO_TYPE];
+ size_t structsize = int_size_in_bytes (type);
+
+ if (decl->vtblInterfaces->dim)
+ {
+ size_t interfacesize = int_size_in_bytes (vtbl_interface_type_node);
+ tree field;
+
+ type = copy_aggregate_type (type);
+
+ /* First layout the static array of Interface, which provides information
+ about the vtables that follow. */
+ tree domain = size_int (decl->vtblInterfaces->dim - 1);
+ tree arrtype = build_array_type (vtbl_interface_type_node,
+ build_index_type (domain));
+ field = create_field_decl (arrtype, NULL, 1, 1);
+ insert_aggregate_field (type, field, structsize);
+ structsize += decl->vtblInterfaces->dim * interfacesize;
+
+ /* For each interface, layout each vtable. */
+ for (size_t i = 0; i < decl->vtblInterfaces->dim; i++)
+ {
+ BaseClass *b = (*decl->vtblInterfaces)[i];
+ ClassDeclaration *id = b->sym;
+ unsigned offset = base_vtable_offset (decl, b);
+
+ if (id->vtbl.dim && offset != ~0u)
+ {
+ tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1));
+ tree vtbltype = build_array_type (vtable_entry_type, vtbldomain);
+
+ field = create_field_decl (vtbltype, NULL, 1, 1);
+ insert_aggregate_field (type, field, offset);
+ structsize += id->vtbl.dim * Target::ptrsize;
+ }
+ }
+ }
+
+ /* Layout the arrays of overriding interface vtables. */
+ for (ClassDeclaration *bcd = decl->baseClass; bcd; bcd = bcd->baseClass)
+ {
+ for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++)
+ {
+ BaseClass *b = (*bcd->vtblInterfaces)[i];
+ ClassDeclaration *id = b->sym;
+ unsigned offset = base_vtable_offset (decl, b);
+
+ if (id->vtbl.dim && offset != ~0u)
+ {
+ if (type == tinfo_types[TK_CLASSINFO_TYPE])
+ type = copy_aggregate_type (type);
+
+ tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1));
+ tree vtbltype = build_array_type (vtable_entry_type, vtbldomain);
+
+ tree field = create_field_decl (vtbltype, NULL, 1, 1);
+ insert_aggregate_field (type, field, offset);
+ structsize += id->vtbl.dim * Target::ptrsize;
+ }
+ }
+ }
+
+ /* Update the type size and record mode for the classinfo type. */
+ if (type != tinfo_types[TK_CLASSINFO_TYPE])
+ finish_aggregate_type (structsize, TYPE_ALIGN_UNIT (type), type, NULL);
+
+ return type;
+}
+
+/* Returns true if the TypeInfo for TYPE should be placed in
+ the runtime library. */
+
+static bool
+builtin_typeinfo_p (Type *type)
+{
+ if (type->isTypeBasic () || type->ty == Tclass || type->ty == Tnull)
+ return !type->mod;
+
+ if (type->ty == Tarray)
+ {
+ /* Strings are so common, make them builtin. */
+ Type *next = type->nextOf ();
+ return !type->mod
+ && ((next->isTypeBasic () != NULL && !next->mod)
+ || (next->ty == Tchar && next->mod == MODimmutable)
+ || (next->ty == Tchar && next->mod == MODconst));
+ }
+
+ return false;
+}
+
+/* Implements a visitor interface to create the decl tree for TypeInfo decls.
+ TypeInfo_Class objects differ in that they also have information about
+ the class type packed immediately after the TypeInfo symbol.
+
+ If the frontend had an interface to allow distinguishing being these two
+ AST types, then that would be better for us. */
+
+class TypeInfoDeclVisitor : public Visitor
+{
+ using Visitor::visit;
+
+public:
+ TypeInfoDeclVisitor (void)
+ {
+ }
+
+ void visit (TypeInfoDeclaration *tid)
+ {
+ tree ident = get_identifier (tid->ident->toChars ());
+ tree type = tinfo_types[get_typeinfo_kind (tid->tinfo)];
+ gcc_assert (type != NULL_TREE);
+
+ tid->csym = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (tid->csym) = build_lang_decl (tid);
+
+ DECL_CONTEXT (tid->csym) = d_decl_context (tid);
+ TREE_READONLY (tid->csym) = 1;
+
+ /* Built-in typeinfo will be referenced as one-only. */
+ gcc_assert (!tid->isInstantiated ());
+
+ if (builtin_typeinfo_p (tid->tinfo))
+ d_linkonce_linkage (tid->csym);
+ else
+ d_comdat_linkage (tid->csym);
+ }
+
+ void visit (TypeInfoClassDeclaration *tid)
+ {
+ gcc_assert (tid->tinfo->ty == Tclass);
+ TypeClass *tc = (TypeClass *) tid->tinfo;
+ tid->csym = get_classinfo_decl (tc->sym);
+ }
+};
+
+/* Get the VAR_DECL of the TypeInfo for DECL. If this does not yet exist,
+ create it. The TypeInfo decl provides information about the type of a given
+ expression or object. */
+
+tree
+get_typeinfo_decl (TypeInfoDeclaration *decl)
+{
+ if (decl->csym)
+ return decl->csym;
+
+ gcc_assert (decl->tinfo->ty != Terror);
+
+ TypeInfoDeclVisitor v = TypeInfoDeclVisitor ();
+ decl->accept (&v);
+ gcc_assert (decl->csym != NULL_TREE);
+
+ return decl->csym;
+}
+
+/* Get the VAR_DECL of the ClassInfo for DECL. If this does not yet exist,
+ create it. The ClassInfo decl provides information about the dynamic type
+ of a given class type or object. */
+
+tree
+get_classinfo_decl (ClassDeclaration *decl)
+{
+ if (decl->csym)
+ return decl->csym;
+
+ InterfaceDeclaration *id = decl->isInterfaceDeclaration ();
+ tree ident = mangle_internal_decl (decl, id ? "__Interface" : "__Class", "Z");
+ tree type = layout_classinfo_interfaces (decl);
+
+ decl->csym = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (NULL);
+
+ /* Class is a reference, want the record type. */
+ DECL_CONTEXT (decl->csym) = TREE_TYPE (build_ctype (decl->type));
+ /* ClassInfo cannot be const data, because we use the monitor on it. */
+ TREE_READONLY (decl->csym) = 0;
+
+ return decl->csym;
+}
+
+/* Returns typeinfo reference for TYPE. */
+
+tree
+build_typeinfo (Type *type)
+{
+ gcc_assert (type->ty != Terror);
+ create_typeinfo (type, NULL);
+ return build_address (get_typeinfo_decl (type->vtinfo));
+}
+
+/* Like layout_classinfo, but generates an Object that wraps around a
+ pointer to C++ type_info so it can be distinguished from D TypeInfo. */
+
+void
+layout_cpp_typeinfo (ClassDeclaration *cd)
+{
+ gcc_assert (cd->isCPPclass ());
+
+ tree decl = get_cpp_typeinfo_decl (cd);
+ vec<constructor_elt, va_gc> *init = NULL;
+
+ /* Use the vtable of __cpp_type_info_ptr, the EH personality routine
+ expects this, as it uses .classinfo identity comparison to test for
+ C++ catch handlers. */
+ tree vptr = get_vtable_decl (ClassDeclaration::cpp_type_info_ptr);
+ CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, build_address (vptr));
+ CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, null_pointer_node);
+
+ /* Let C++ do the RTTI generation, and just reference the symbol as
+ extern, knowing the underlying type is not required. */
+ const char *ident = Target::cppTypeInfoMangle (cd);
+ tree typeinfo = declare_extern_var (get_identifier (ident),
+ unknown_type_node);
+ TREE_READONLY (typeinfo) = 1;
+ CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, build_address (typeinfo));
+
+ /* Build the initializer and emit. */
+ DECL_INITIAL (decl) = build_struct_literal (TREE_TYPE (decl), init);
+ DECL_EXTERNAL (decl) = 0;
+ d_pushdecl (decl);
+ rest_of_decl_compilation (decl, 1, 0);
+}
+
+/* Get the VAR_DECL of the __cpp_type_info_ptr for DECL. If this does not yet
+ exist, create it. The __cpp_type_info_ptr decl is then initialized with a
+ pointer to the C++ type_info for the given class. */
+
+tree
+get_cpp_typeinfo_decl (ClassDeclaration *decl)
+{
+ gcc_assert (decl->isCPPclass ());
+
+ if (decl->cpp_type_info_ptr_sym)
+ return decl->cpp_type_info_ptr_sym;
+
+ if (!tinfo_types[TK_CPPTI_TYPE])
+ make_internal_typeinfo (TK_CPPTI_TYPE,
+ Identifier::idPool ("__cpp_type_info_ptr"),
+ ptr_type_node, NULL);
+
+ tree ident = mangle_internal_decl (decl, "_cpp_type_info_ptr", "");
+ tree type = tinfo_types[TK_CPPTI_TYPE];
+
+ decl->cpp_type_info_ptr_sym = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (decl->cpp_type_info_ptr_sym) = build_lang_decl (NULL);
+
+ /* Class is a reference, want the record type. */
+ DECL_CONTEXT (decl->cpp_type_info_ptr_sym)
+ = TREE_TYPE (build_ctype (decl->type));
+ TREE_READONLY (decl->cpp_type_info_ptr_sym) = 1;
+
+ d_comdat_linkage (decl->cpp_type_info_ptr_sym);
+
+ /* Layout the initializer and emit the symbol. */
+ layout_cpp_typeinfo (decl);
+
+ return decl->cpp_type_info_ptr_sym;
+}
+
+/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it. */
+
+void
+create_typeinfo (Type *type, Module *mod)
+{
+ /* Do this since not all Type's are merged. */
+ Type *t = type->merge2 ();
+ Identifier *ident;
+
+ if (!t->vtinfo)
+ {
+ tinfo_kind tk = get_typeinfo_kind (t);
+ switch (tk)
+ {
+ case TK_SHARED_TYPE:
+ case TK_CONST_TYPE:
+ case TK_IMMUTABLE_TYPE:
+ case TK_INOUT_TYPE:
+ case TK_POINTER_TYPE:
+ case TK_ARRAY_TYPE:
+ case TK_VECTOR_TYPE:
+ case TK_INTERFACE_TYPE:
+ /* Kinds of TypeInfo that add one extra pointer field. */
+ if (tk == TK_SHARED_TYPE)
+ {
+ /* Does both 'shared' and 'shared const'. */
+ t->vtinfo = TypeInfoSharedDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Shared");
+ }
+ else if (tk == TK_CONST_TYPE)
+ {
+ t->vtinfo = TypeInfoConstDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Const");
+ }
+ else if (tk == TK_IMMUTABLE_TYPE)
+ {
+ t->vtinfo = TypeInfoInvariantDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Invariant");
+ }
+ else if (tk == TK_INOUT_TYPE)
+ {
+ t->vtinfo = TypeInfoWildDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Wild");
+ }
+ else if (tk == TK_POINTER_TYPE)
+ {
+ t->vtinfo = TypeInfoPointerDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Pointer");
+ }
+ else if (tk == TK_ARRAY_TYPE)
+ {
+ t->vtinfo = TypeInfoArrayDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Array");
+ }
+ else if (tk == TK_VECTOR_TYPE)
+ {
+ t->vtinfo = TypeInfoVectorDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Vector");
+ }
+ else if (tk == TK_INTERFACE_TYPE)
+ {
+ t->vtinfo = TypeInfoInterfaceDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Interface");
+ }
+ else
+ gcc_unreachable ();
+
+ if (!tinfo_types[tk])
+ make_internal_typeinfo (tk, ident, ptr_type_node, NULL);
+ break;
+
+ case TK_STATICARRAY_TYPE:
+ if (!tinfo_types[tk])
+ {
+ ident = Identifier::idPool ("TypeInfo_StaticArray");
+ make_internal_typeinfo (tk, ident, ptr_type_node, size_type_node,
+ NULL);
+ }
+ t->vtinfo = TypeInfoStaticArrayDeclaration::create (t);
+ break;
+
+ case TK_ASSOCIATIVEARRAY_TYPE:
+ if (!tinfo_types[tk])
+ {
+ ident = Identifier::idPool ("TypeInfo_AssociativeArray");
+ make_internal_typeinfo (tk, ident, ptr_type_node, ptr_type_node,
+ NULL);
+ }
+ t->vtinfo = TypeInfoAssociativeArrayDeclaration::create (t);
+ break;
+
+ case TK_STRUCT_TYPE:
+ if (!tinfo_types[tk])
+ {
+ /* Some ABIs add extra TypeInfo fields on the end. */
+ tree argtype = global.params.is64bit ? ptr_type_node : NULL_TREE;
+
+ ident = Identifier::idPool ("TypeInfo_Struct");
+ make_internal_typeinfo (tk, ident,
+ array_type_node, array_type_node,
+ ptr_type_node, ptr_type_node,
+ ptr_type_node, ptr_type_node,
+ size_type_node, ptr_type_node,
+ ptr_type_node, size_type_node,
+ ptr_type_node, argtype, argtype, NULL);
+ }
+ t->vtinfo = TypeInfoStructDeclaration::create (t);
+ break;
+
+ case TK_ENUMERAL_TYPE:
+ if (!tinfo_types[tk])
+ {
+ ident = Identifier::idPool ("TypeInfo_Enum");
+ make_internal_typeinfo (tk, ident,
+ ptr_type_node, array_type_node,
+ array_type_node, NULL);
+ }
+ t->vtinfo = TypeInfoEnumDeclaration::create (t);
+ break;
+
+ case TK_FUNCTION_TYPE:
+ case TK_DELEGATE_TYPE:
+ /* Functions and delegates share a common TypeInfo layout. */
+ if (tk == TK_FUNCTION_TYPE)
+ {
+ t->vtinfo = TypeInfoFunctionDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Function");
+ }
+ else if (tk == TK_DELEGATE_TYPE)
+ {
+ t->vtinfo = TypeInfoDelegateDeclaration::create (t);
+ ident = Identifier::idPool ("TypeInfo_Delegate");
+ }
+ else
+ gcc_unreachable ();
+
+ if (!tinfo_types[tk])
+ make_internal_typeinfo (tk, ident, ptr_type_node,
+ array_type_node, NULL);
+ break;
+
+ case TK_TYPELIST_TYPE:
+ if (!tinfo_types[tk])
+ {
+ ident = Identifier::idPool ("TypeInfo_Tuple");
+ make_internal_typeinfo (tk, ident, array_type_node, NULL);
+ }
+ t->vtinfo = TypeInfoTupleDeclaration::create (t);
+ break;
+
+ case TK_CLASSINFO_TYPE:
+ t->vtinfo = TypeInfoClassDeclaration::create (t);
+ break;
+
+ default:
+ t->vtinfo = TypeInfoDeclaration::create (t);
+ }
+ gcc_assert (t->vtinfo);
+
+ /* If this has a custom implementation in rt/typeinfo, then
+ do not generate a COMDAT for it. */
+ if (!builtin_typeinfo_p (t))
+ {
+ /* Find module that will go all the way to an object file. */
+ if (mod)
+ mod->members->push (t->vtinfo);
+ else
+ build_decl_tree (t->vtinfo);
+ }
+ }
+ /* Types aren't merged, but we can share the vtinfo's. */
+ if (!type->vtinfo)
+ type->vtinfo = t->vtinfo;
+
+ gcc_assert (type->vtinfo != NULL);
+}
+
+/* Implements a visitor interface to check whether a type is speculative.
+ TypeInfo_Struct would reference the members of the struct it is representing
+ (e.g: opEquals via xopEquals field), so if it's instantiated in speculative
+ context, TypeInfo creation should also be stopped to avoid possible
+ `unresolved symbol' linker errors. */
+
+class SpeculativeTypeVisitor : public Visitor
+{
+ using Visitor::visit;
+
+ bool result_;
+
+public:
+ SpeculativeTypeVisitor (void)
+ {
+ this->result_ = false;
+ }
+
+ bool result (void)
+ {
+ return this->result_;
+ }
+
+ void visit (Type *t)
+ {
+ Type *tb = t->toBasetype ();
+ if (tb != t)
+ tb->accept (this);
+ }
+
+ void visit (TypeNext *t)
+ {
+ if (t->next)
+ t->next->accept (this);
+ }
+
+ void visit (TypeBasic *)
+ {
+ }
+
+ void visit (TypeVector *t)
+ {
+ t->basetype->accept (this);
+ }
+
+ void visit (TypeAArray *t)
+ {
+ t->index->accept (this);
+ visit ((TypeNext *)t);
+ }
+
+ void visit (TypeFunction *t)
+ {
+ visit ((TypeNext *)t);
+ }
+
+ void visit (TypeStruct *t)
+ {
+ StructDeclaration *sd = t->sym;
+ if (TemplateInstance *ti = sd->isInstantiated ())
+ {
+ if (!ti->needsCodegen ())
+ {
+ if (ti->minst || sd->requestTypeInfo)
+ return;
+
+ this->result_ |= true;
+ }
+ }
+ }
+
+ void visit (TypeClass *t)
+ {
+ ClassDeclaration *cd = t->sym;
+ if (TemplateInstance *ti = cd->isInstantiated ())
+ {
+ if (!ti->needsCodegen () && !ti->minst)
+ {
+ this->result_ |= true;
+ }
+ }
+ }
+
+ void visit (TypeTuple *t)
+ {
+ if (!t->arguments)
+ return;
+
+ for (size_t i = 0; i < t->arguments->dim; i++)
+ {
+ Type *tprm = (*t->arguments)[i]->type;
+ if (tprm)
+ tprm->accept (this);
+ if (this->result_)
+ return;
+ }
+ }
+};
+
+/* Return true if type was instantiated in a speculative context. */
+
+bool
+speculative_type_p (Type *t)
+{
+ SpeculativeTypeVisitor v = SpeculativeTypeVisitor ();
+ t->accept (&v);
+ return v.result ();
+}
+
+#include "gt-d-typeinfo.h"
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
new file mode 100644
index 0000000..d5eac2d
--- /dev/null
+++ b/gcc/d/types.cc
@@ -0,0 +1,986 @@
+/* types.cc -- Lower D frontend types to GCC trees.
+ Copyright (C) 2006-2018 Free Software Foundation, Inc.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dmd/attrib.h"
+#include "dmd/aggregate.h"
+#include "dmd/enum.h"
+#include "dmd/expression.h"
+#include "dmd/identifier.h"
+#include "dmd/mtype.h"
+#include "dmd/target.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "tm.h"
+#include "function.h"
+#include "toplev.h"
+#include "target.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "attribs.h"
+
+#include "d-tree.h"
+
+
+/* Return TRUE if TYPE is a static array va_list. This is for compatibility
+ with the C ABI, where va_list static arrays are passed by reference.
+ However for every other case in D, static arrays are passed by value. */
+
+bool
+valist_array_p (Type *type)
+{
+ if (Type::tvalist->ty == Tsarray)
+ {
+ Type *tb = type->toBasetype ();
+ if (same_type_p (tb, Type::tvalist))
+ return true;
+ }
+
+ return false;
+}
+
+/* Returns true if TYPE contains no actual data, just various
+ possible combinations of empty aggregates. */
+
+bool
+empty_aggregate_p (tree type)
+{
+ if (!AGGREGATE_TYPE_P (type))
+ return false;
+
+ /* Want the element type for arrays. */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return empty_aggregate_p (TREE_TYPE (type));
+
+ /* Recursively check all fields. */
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL
+ && !empty_aggregate_p (TREE_TYPE (field)))
+ return false;
+ }
+
+ return true;
+}
+
+/* Returns true if T1 and T2 are related to each other. */
+
+bool
+same_type_p (Type *t1, Type *t2)
+{
+ /* Types are equal. */
+ if (t1 == t2)
+ return true;
+
+ /* Types derive from the same base. */
+ Type *tb1 = t1->toBasetype ();
+ Type *tb2 = t2->toBasetype ();
+ if (tb1 == tb2)
+ return true;
+
+ /* Types are mutably the same type. */
+ if (tb1->ty == tb2->ty && tb1->equivalent (tb2))
+ return true;
+
+ return false;
+}
+
+/* Returns 'Object' type which all D classes are derived from. */
+
+Type *
+get_object_type (void)
+{
+ if (ClassDeclaration::object)
+ return ClassDeclaration::object->type;
+
+ error ("missing or corrupt object.d");
+ return Type::terror;
+}
+
+
+/* Returns a static array of TYPE which has SIZE number of elements. */
+
+tree
+make_array_type (Type *type, unsigned HOST_WIDE_INT size)
+{
+ /* In [arrays/void-arrays], void arrays can also be static, the length is
+ specified in bytes. */
+ if (type->toBasetype ()->ty == Tvoid)
+ type = Type::tuns8;
+
+ /* In [arrays/static-arrays], a static array with a dimension of 0 is allowed,
+ but no space is allocated for it. */
+ if (size == 0)
+ {
+ tree range = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
+ TYPE_UNSIGNED (sizetype));
+ tree index = build_range_type (range, size_zero_node, NULL_TREE);
+
+ tree t = build_array_type (build_ctype (type), index);
+ TYPE_SIZE (t) = bitsize_zero_node;
+ TYPE_SIZE_UNIT (t) = size_zero_node;
+ return t;
+ }
+
+ return build_array_type (build_ctype (type),
+ build_index_type (size_int (size - 1)));
+}
+
+/* Builds a record type whose name is NAME. NFIELDS is the number of fields,
+ provided as field ident/type pairs. */
+
+tree
+make_struct_type (const char *name, int nfields, ...)
+{
+ tree fields = NULL_TREE;
+ va_list ap;
+
+ va_start (ap, nfields);
+
+ for (int i = 0; i < nfields; i++)
+ {
+ tree ident = va_arg (ap, tree);
+ tree type = va_arg (ap, tree);
+ tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, ident, type);
+ DECL_CHAIN (field) = fields;
+ fields = field;
+ }
+
+ va_end (ap);
+
+ tree type = make_node (RECORD_TYPE);
+ finish_builtin_struct (type, name, fields, NULL_TREE);
+
+ return type;
+}
+
+/* Return qualified type variant of TYPE determined by modifier value MOD. */
+
+tree
+insert_type_modifiers (tree type, unsigned mod)
+{
+ int quals = 0;
+
+ switch (mod)
+ {
+ case MODconst:
+ case MODwild:
+ case MODwildconst:
+ case MODimmutable:
+ case MODshared | MODconst:
+ case MODshared | MODwild:
+ case MODshared | MODwildconst:
+ quals |= TYPE_QUAL_CONST;
+ break;
+
+ case 0:
+ case MODshared:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ tree qualtype = build_qualified_type (type, quals);
+
+ /* Mark whether the type is qualified 'shared'. */
+ if (mod & MODshared)
+ TYPE_SHARED (qualtype) = 1;
+
+ return qualtype;
+}
+
+/* Adds FIELD into the aggregate TYPE at OFFSET. */
+
+void
+insert_aggregate_field (tree type, tree field, size_t offset)
+{
+ DECL_FIELD_CONTEXT (field) = type;
+ SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (TREE_TYPE (field)));
+ DECL_FIELD_OFFSET (field) = size_int (offset);
+ DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
+
+ TREE_ADDRESSABLE (field) = TYPE_SHARED (TREE_TYPE (field));
+
+ layout_decl (field, 0);
+ TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), field);
+}
+
+/* For all decls in the FIELDS chain, adjust their field offset by OFFSET.
+ This is done as the frontend puts fields into the outer struct, and so
+ their offset is from the beginning of the aggregate.
+ We want the offset to be from the beginning of the anonymous aggregate. */
+
+static void
+fixup_anonymous_offset (tree fields, tree offset)
+{
+ while (fields != NULL_TREE)
+ {
+ /* Traverse all nested anonymous aggregates to update their offset.
+ Set the anonymous decl offset to its first member. */
+ tree ftype = TREE_TYPE (fields);
+ if (TYPE_NAME (ftype) && anon_aggrname_p (TYPE_IDENTIFIER (ftype)))
+ {
+ tree vfields = TYPE_FIELDS (ftype);
+ fixup_anonymous_offset (vfields, offset);
+ DECL_FIELD_OFFSET (fields) = DECL_FIELD_OFFSET (vfields);
+ }
+ else
+ {
+ tree voffset = DECL_FIELD_OFFSET (fields);
+ DECL_FIELD_OFFSET (fields) = size_binop (MINUS_EXPR, voffset, offset);
+ }
+
+ fields = DECL_CHAIN (fields);
+ }
+}
+
+/* Iterate over all MEMBERS of an aggregate, and add them as fields to CONTEXT.
+ If INHERITED_P is true, then the members derive from a base class.
+ Returns the number of fields found. */
+
+static size_t
+layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
+{
+ size_t fields = 0;
+
+ for (size_t i = 0; i < members->dim; i++)
+ {
+ Dsymbol *sym = (*members)[i];
+ VarDeclaration *var = sym->isVarDeclaration ();
+ if (var != NULL)
+ {
+ /* Skip fields that have already been added. */
+ if (!inherited_p && var->csym != NULL)
+ continue;
+
+ /* If this variable was really a tuple, add all tuple fields. */
+ if (var->aliassym)
+ {
+ TupleDeclaration *td = var->aliassym->isTupleDeclaration ();
+ Dsymbols tmembers;
+ /* No other way to coerce the underlying type out of the tuple.
+ Frontend should have already validated this. */
+ for (size_t j = 0; j < td->objects->dim; j++)
+ {
+ RootObject *ro = (*td->objects)[j];
+ gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION);
+ Expression *e = (Expression *) ro;
+ gcc_assert (e->op == TOKdsymbol);
+ DsymbolExp *se = (DsymbolExp *) e;
+
+ tmembers.push (se->s);
+ }
+
+ fields += layout_aggregate_members (&tmembers, context,
+ inherited_p);
+ continue;
+ }
+
+ /* Insert the field declaration at its given offset. */
+ if (var->isField ())
+ {
+ const char *ident = var->ident ? var->ident->toChars () : NULL;
+ tree field = create_field_decl (declaration_type (var), ident,
+ inherited_p, inherited_p);
+ insert_aggregate_field (context, field, var->offset);
+
+ /* Because the front-end shares field decls across classes, don't
+ create the corresponding back-end symbol unless we are adding
+ it to the aggregate it is defined in. */
+ if (!inherited_p)
+ {
+ DECL_LANG_SPECIFIC (field) = build_lang_decl (var);
+ var->csym = field;
+ }
+
+ fields += 1;
+ continue;
+ }
+ }
+
+ /* Anonymous struct/union are flattened by the frontend. However, we
+ want to keep the record layout in-tact when building the type. */
+ AnonDeclaration *ad = sym->isAnonDeclaration ();
+ if (ad != NULL)
+ {
+ /* Use a counter to create anonymous type names. */
+ static int anon_cnt = 0;
+ char buf[32];
+ sprintf (buf, anon_aggrname_format (), anon_cnt++);
+
+ tree ident = get_identifier (buf);
+ tree type = make_node (ad->isunion ? UNION_TYPE : RECORD_TYPE);
+ ANON_AGGR_TYPE_P (type) = 1;
+ d_keep (type);
+
+ /* Build the type declaration. */
+ tree decl = build_decl (make_location_t (ad->loc),
+ TYPE_DECL, ident, type);
+ DECL_CONTEXT (decl) = context;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ TYPE_CONTEXT (type) = context;
+ TYPE_NAME (type) = decl;
+ TYPE_STUB_DECL (type) = decl;
+
+ /* Recursively iterator over the anonymous members. */
+ fields += layout_aggregate_members (ad->decl, type, inherited_p);
+
+ /* Remove from the anon fields the base offset of this anonymous
+ aggregate. Undoes what is set-up in setFieldOffset, but doesn't
+ affect field accesses. */
+ tree offset = size_int (ad->anonoffset);
+ fixup_anonymous_offset (TYPE_FIELDS (type), offset);
+
+ finish_aggregate_type (ad->anonstructsize, ad->anonalignsize,
+ type, NULL);
+
+ /* And make the corresponding data member. */
+ tree field = create_field_decl (type, NULL, 0, 0);
+ insert_aggregate_field (context, field, ad->anonoffset);
+ continue;
+ }
+
+ /* Other kinds of attributes don't create a scope. */
+ AttribDeclaration *attrib = sym->isAttribDeclaration ();
+ if (attrib != NULL)
+ {
+ Dsymbols *decls = attrib->include (NULL, NULL);
+ if (decls != NULL)
+ {
+ fields += layout_aggregate_members (decls, context, inherited_p);
+ continue;
+ }
+ }
+
+ /* Same with template mixins and namespaces. */
+ if (sym->isTemplateMixin () || sym->isNspace ())
+ {
+ ScopeDsymbol *scopesym = sym->isScopeDsymbol ();
+ if (scopesym->members)
+ {
+ fields += layout_aggregate_members (scopesym->members, context,
+ inherited_p);
+ continue;
+ }
+ }
+ }
+
+ return fields;
+}
+
+/* Write out all fields for aggregate BASE. For classes, write out all
+ interfaces first, then the base class fields. */
+
+static void
+layout_aggregate_type (AggregateDeclaration *decl, tree type,
+ AggregateDeclaration *base)
+{
+ ClassDeclaration *cd = base->isClassDeclaration ();
+ bool inherited_p = (decl != base);
+
+ if (cd != NULL)
+ {
+ if (cd->baseClass)
+ layout_aggregate_type (decl, type, cd->baseClass);
+ else
+ {
+ /* This is the base class (Object) or interface. */
+ tree objtype = TREE_TYPE (build_ctype (cd->type));
+
+ /* Add the vtable pointer, and optionally the monitor fields. */
+ InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
+ if (!id || id->vtblInterfaces->dim == 0)
+ {
+ tree field = create_field_decl (vtbl_ptr_type_node, "__vptr", 1,
+ inherited_p);
+ DECL_VIRTUAL_P (field) = 1;
+ TYPE_VFIELD (type) = field;
+ DECL_FCONTEXT (field) = objtype;
+ insert_aggregate_field (type, field, 0);
+ }
+
+ if (!id && !cd->isCPPclass ())
+ {
+ tree field = create_field_decl (ptr_type_node, "__monitor", 1,
+ inherited_p);
+ insert_aggregate_field (type, field, Target::ptrsize);
+ }
+ }
+
+ if (cd->vtblInterfaces)
+ {
+ for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+ {
+ BaseClass *bc = (*cd->vtblInterfaces)[i];
+ tree field = create_field_decl (vtbl_ptr_type_node, NULL, 1, 1);
+ insert_aggregate_field (type, field, bc->offset);
+ }
+ }
+ }
+
+ if (base->members)
+ {
+ size_t fields = layout_aggregate_members (base->members, type,
+ inherited_p);
+ gcc_assert (fields == base->fields.dim);
+
+ /* Make sure that all fields have been created. */
+ if (!inherited_p)
+ {
+ for (size_t i = 0; i < base->fields.dim; i++)
+ {
+ VarDeclaration *var = base->fields[i];
+ gcc_assert (var->csym != NULL);
+ }
+ }
+ }
+}
+
+/* Given a record type TYPE, whose size and alignment are determined by
+ STRUCTSIZE and ALIGNSIZE. Apply any type attributes ATTRS and compute
+ the finalized record mode. */
+
+void
+finish_aggregate_type (unsigned structsize, unsigned alignsize,
+ tree type, UserAttributeDeclaration *attrs)
+{
+ TYPE_SIZE (type) = NULL_TREE;
+
+ /* Write out any GCC attributes that were applied to the type declaration. */
+ if (attrs)
+ {
+ Expressions *eattrs = attrs->getAttributes ();
+ decl_attributes (&type, build_attributes (eattrs),
+ ATTR_FLAG_TYPE_IN_PLACE);
+ }
+
+ /* Set size and alignment as requested by frontend. */
+ TYPE_SIZE (type) = bitsize_int (structsize * BITS_PER_UNIT);
+ TYPE_SIZE_UNIT (type) = size_int (structsize);
+ SET_TYPE_ALIGN (type, alignsize * BITS_PER_UNIT);
+ TYPE_PACKED (type) = (alignsize == 1);
+
+ /* Set the back-end type mode. */
+ compute_record_mode (type);
+
+ /* Fix up all variants of this aggregate type. */
+ for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ {
+ if (t == type)
+ continue;
+
+ TYPE_FIELDS (t) = TYPE_FIELDS (type);
+ TYPE_LANG_SPECIFIC (t) = TYPE_LANG_SPECIFIC (type);
+ SET_TYPE_ALIGN (t, TYPE_ALIGN (type));
+ TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type);
+ gcc_assert (TYPE_MODE (t) == TYPE_MODE (type));
+ }
+}
+
+
+/* Implements the visitor interface to build the GCC trees of all
+ Type AST classes emitted from the D Front-end, where CTYPE holds
+ the cached back-end representation to be returned. */
+
+class TypeVisitor : public Visitor
+{
+ using Visitor::visit;
+
+public:
+ TypeVisitor (void)
+ {
+ }
+
+ /* This should be overridden by each type class. */
+
+ void visit (Type *)
+ {
+ gcc_unreachable ();
+ }
+
+ /* Type assigned to erroneous expressions or constructs that
+ failed during the semantic stage. */
+
+ void visit (TypeError *t)
+ {
+ t->ctype = error_mark_node;
+ }
+
+ /* Type assigned to generic nullable types. */
+
+ void visit (TypeNull *t)
+ {
+ t->ctype = ptr_type_node;
+ }
+
+
+ /* Basic Data Types. */
+
+ void visit (TypeBasic *t)
+ {
+ /* [type/basic-data-types]
+
+ void no type.
+ bool 8-bit boolean value.
+ byte 8-bit signed value.
+ ubyte 8-bit unsigned value.
+ short 16-bit signed value.
+ ushort 16-bit unsigned value.
+ int 32-bit signed value.
+ uint 32-bit unsigned value.
+ long 64-bit signed value.
+ ulong 64-bit unsigned value.
+ cent 128-bit signed value.
+ ucent 128-bit unsigned value.
+ float 32-bit IEEE 754 floating-point value.
+ double 64-bit IEEE 754 floating-point value.
+ real largest FP size implemented in hardware.
+ ifloat imaginary float.
+ idouble imaginary double.
+ ireal imaginary real.
+ cfloat complex float.
+ cdouble complex double.
+ creal complex real.
+ char UTF-8 code unit.
+ wchar UTF-16 code unit.
+ dchar UTF-32 code unit. */
+
+ switch (t->ty)
+ {
+ case Tvoid: t->ctype = void_type_node; break;
+ case Tbool: t->ctype = d_bool_type; break;
+ case Tint8: t->ctype = d_byte_type; break;
+ case Tuns8: t->ctype = d_ubyte_type; break;
+ case Tint16: t->ctype = d_short_type; break;
+ case Tuns16: t->ctype = d_ushort_type; break;
+ case Tint32: t->ctype = d_int_type; break;
+ case Tuns32: t->ctype = d_uint_type; break;
+ case Tint64: t->ctype = d_long_type; break;
+ case Tuns64: t->ctype = d_ulong_type; break;
+ case Tint128: t->ctype = d_cent_type; break;
+ case Tuns128: t->ctype = d_ucent_type; break;
+ case Tfloat32: t->ctype = float_type_node; break;
+ case Tfloat64: t->ctype = double_type_node; break;
+ case Tfloat80: t->ctype = long_double_type_node; break;
+ case Timaginary32: t->ctype = ifloat_type_node; break;
+ case Timaginary64: t->ctype = idouble_type_node; break;
+ case Timaginary80: t->ctype = ireal_type_node; break;
+ case Tcomplex32: t->ctype = complex_float_type_node; break;
+ case Tcomplex64: t->ctype = complex_double_type_node; break;
+ case Tcomplex80: t->ctype = complex_long_double_type_node; break;
+ case Tchar: t->ctype = char8_type_node; break;
+ case Twchar: t->ctype = char16_type_node; break;
+ case Tdchar: t->ctype = char32_type_node; break;
+ default: gcc_unreachable ();
+ }
+
+ TYPE_NAME (t->ctype) = get_identifier (t->toChars ());
+ }
+
+
+ /* Derived Data Types. */
+
+ /* Build a simple pointer to data type, analogous to C pointers. */
+
+ void visit (TypePointer *t)
+ {
+ t->ctype = build_pointer_type (build_ctype (t->next));
+ }
+
+ /* Build a dynamic array type, consisting of a length and a pointer
+ to the array data. */
+
+ void visit (TypeDArray *t)
+ {
+ /* In [abi/arrays], dynamic array layout is:
+ .length array dimension.
+ .ptr pointer to array data. */
+ t->ctype = make_struct_type (t->toChars (), 2,
+ get_identifier ("length"),
+ build_ctype (Type::tsize_t),
+ get_identifier ("ptr"),
+ build_pointer_type (build_ctype (t->next)));
+ TYPE_DYNAMIC_ARRAY (t->ctype) = 1;
+ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
+ d_keep (t->ctype);
+ }
+
+ /* Build a static array type, distinguished from dynamic arrays by
+ having a length fixed at compile-time, analogous to C arrays. */
+
+ void visit (TypeSArray *t)
+ {
+ if (t->dim->isConst () && t->dim->type->isintegral ())
+ {
+ uinteger_t size = t->dim->toUInteger ();
+ t->ctype = make_array_type (t->next, size);
+ }
+ else
+ {
+ error ("invalid expression for static array dimension: %s",
+ t->dim->toChars ());
+ gcc_unreachable ();
+ }
+ }
+
+ /* Build a vector type, a fixed array of floating or integer types. */
+
+ void visit (TypeVector *t)
+ {
+ int nunits = ((TypeSArray *) t->basetype)->dim->toUInteger ();
+ tree inner = build_ctype (t->elementType ());
+
+ /* Same rationale as void static arrays. */
+ if (inner == void_type_node)
+ inner = build_ctype (Type::tuns8);
+
+ t->ctype = build_vector_type (inner, nunits);
+ TYPE_NAME (t->ctype) = get_identifier (t->toChars ());
+ layout_type (t->ctype);
+ }
+
+ /* Build an associative array type, distinguished from arrays by having an
+ index that's not necessarily an integer, and can be sparsely populated. */
+
+ void visit (TypeAArray *t)
+ {
+ /* In [abi/associative-arrays], associative arrays are a struct that only
+ consist of a pointer to an opaque, implementation defined type. */
+ t->ctype = make_struct_type (t->toChars (), 1,
+ get_identifier ("ptr"), ptr_type_node);
+ TYPE_ASSOCIATIVE_ARRAY (t->ctype) = 1;
+ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
+ d_keep (t->ctype);
+ }
+
+ /* Build type for a function declaration, which consists of a return type,
+ and a list of parameter types, and a linkage attribute. */
+
+ void visit (TypeFunction *t)
+ {
+ tree fnparams = NULL_TREE;
+ tree fntype;
+
+ /* [function/variadic]
+
+ Variadic functions with D linkage have an additional hidden argument
+ with the name _arguments passed to the function. */
+ if (t->varargs == 1 && t->linkage == LINKd)
+ {
+ tree type = build_ctype (Type::typeinfotypelist->type);
+ fnparams = chainon (fnparams, build_tree_list (0, type));
+ }
+
+ if (t->parameters)
+ {
+ size_t n_args = Parameter::dim (t->parameters);
+
+ for (size_t i = 0; i < n_args; i++)
+ {
+ tree type = type_passed_as (Parameter::getNth (t->parameters, i));
+ fnparams = chainon (fnparams, build_tree_list (0, type));
+ }
+ }
+
+ /* When the last parameter is void_list_node, that indicates a fixed length
+ parameter list, otherwise function is treated as variadic. */
+ if (t->varargs != 1)
+ fnparams = chainon (fnparams, void_list_node);
+
+ if (t->next != NULL)
+ {
+ fntype = build_ctype (t->next);
+ if (t->isref)
+ fntype = build_reference_type (fntype);
+ }
+ else
+ fntype = void_type_node;
+
+ /* Could the function type be self referenced by parameters? */
+ t->ctype = build_function_type (fntype, fnparams);
+ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
+ d_keep (t->ctype);
+
+ /* Handle any special support for calling conventions. */
+ switch (t->linkage)
+ {
+ case LINKpascal:
+ case LINKwindows:
+ /* [attribute/linkage]
+
+ The Windows convention is distinct from the C convention only
+ on Win32, where it is equivalent to the stdcall convention. */
+ if (!global.params.is64bit)
+ t->ctype = insert_type_attribute (t->ctype, "stdcall");
+ break;
+
+ case LINKc:
+ case LINKcpp:
+ case LINKd:
+ case LINKobjc:
+ /* [abi/function-calling-conventions]
+
+ The extern (C) and extern (D) calling convention matches
+ the C calling convention used by the supported C compiler
+ on the host system. */
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ /* Build a delegate type, an aggregate of two pieces of data, an object
+ reference and a pointer to a non-static member function, or a pointer
+ to a closure and a pointer to a nested function. */
+
+ void visit (TypeDelegate *t)
+ {
+ /* In [abi/delegates], delegate layout is:
+ .ptr context pointer.
+ .funcptr pointer to function. */
+ tree fntype = build_ctype (t->next);
+ tree dgtype = build_vthis_function (void_type_node, fntype);
+
+ TYPE_ATTRIBUTES (dgtype) = TYPE_ATTRIBUTES (fntype);
+ TYPE_LANG_SPECIFIC (dgtype) = TYPE_LANG_SPECIFIC (fntype);
+
+ t->ctype = make_struct_type (t->toChars (), 2,
+ get_identifier ("ptr"),
+ build_ctype (Type::tvoidptr),
+ get_identifier ("funcptr"),
+ build_pointer_type (dgtype));
+ TYPE_DELEGATE (t->ctype) = 1;
+ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
+ d_keep (t->ctype);
+ }
+
+
+ /* User Defined Types. */
+
+ /* Build a named enum type, a distinct value whose values are restrict to
+ a group of constants of the same underlying base type. */
+
+ void visit (TypeEnum *t)
+ {
+ tree basetype = (t->sym->memtype)
+ ? build_ctype (t->sym->memtype) : void_type_node;
+
+ if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
+ {
+ /* Enums in D2 can have a base type that is not necessarily integral.
+ For these, we simplify this a little by using the base type directly
+ instead of building an ENUMERAL_TYPE. */
+ t->ctype = build_variant_type_copy (basetype);
+ }
+ else
+ {
+ t->ctype = make_node (ENUMERAL_TYPE);
+ ENUM_IS_SCOPED (t->ctype) = 1;
+ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
+ d_keep (t->ctype);
+
+ if (flag_short_enums)
+ TYPE_PACKED (t->ctype) = 1;
+
+ TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8;
+ TYPE_SIZE (t->ctype) = 0;
+
+ TYPE_MIN_VALUE (t->ctype) = TYPE_MIN_VALUE (basetype);
+ TYPE_MAX_VALUE (t->ctype) = TYPE_MAX_VALUE (basetype);
+ layout_type (t->ctype);
+
+ tree values = NULL_TREE;
+ if (t->sym->members)
+ {
+ for (size_t i = 0; i < t->sym->members->dim; i++)
+ {
+ EnumMember *member = (*t->sym->members)[i]->isEnumMember ();
+ /* Templated functions can seep through to the back-end
+ just ignore for now. */
+ if (member == NULL)
+ continue;
+
+ tree ident = get_identifier (member->ident->toChars ());
+ tree value = build_integer_cst (member->value ()->toInteger (),
+ basetype);
+
+ /* Build an identifier for the enumeration constant. */
+ tree decl = build_decl (make_location_t (member->loc),
+ CONST_DECL, ident, basetype);
+ DECL_CONTEXT (decl) = t->ctype;
+ TREE_CONSTANT (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ DECL_INITIAL (decl) = value;
+
+ /* Add this enumeration constant to the list for this type. */
+ values = chainon (values, build_tree_list (ident, decl));
+ }
+ }
+
+ TYPE_VALUES (t->ctype) = values;
+ TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype);
+ build_type_decl (t->ctype, t->sym);
+ }
+
+ if (t->sym->userAttribDecl)
+ {
+ Expressions *eattrs = t->sym->userAttribDecl->getAttributes ();
+ decl_attributes (&t->ctype, build_attributes (eattrs),
+ ATTR_FLAG_TYPE_IN_PLACE);
+ }
+ }
+
+ /* Build a struct or union type. Layout should be exactly represented
+ as an equivalent C struct, except for non-POD or nested structs. */
+
+ void visit (TypeStruct *t)
+ {
+ /* Need to set this right away in case of self-references. */
+ t->ctype = make_node (t->sym->isUnionDeclaration ()
+ ? UNION_TYPE : RECORD_TYPE);
+ d_keep (t->ctype);
+
+ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
+
+ if (t->sym->members)
+ {
+ /* Must set up the overall size and alignment before determining
+ the context or laying out fields as those types may make
+ recursive references to this type. */
+ unsigned structsize = t->sym->structsize;
+ unsigned alignsize = (t->sym->alignment != STRUCTALIGN_DEFAULT)
+ ? t->sym->alignment : t->sym->alignsize;
+
+ TYPE_SIZE (t->ctype) = bitsize_int (structsize * BITS_PER_UNIT);
+ TYPE_SIZE_UNIT (t->ctype) = size_int (structsize);
+ SET_TYPE_ALIGN (t->ctype, alignsize * BITS_PER_UNIT);
+ TYPE_PACKED (t->ctype) = (alignsize == 1);
+ compute_record_mode (t->ctype);
+
+ /* Put out all fields. */
+ layout_aggregate_type (t->sym, t->ctype, t->sym);
+ finish_aggregate_type (structsize, alignsize, t->ctype,
+ t->sym->userAttribDecl);
+ }
+
+ TYPE_CONTEXT (t->ctype) = d_decl_context (t->sym);
+ build_type_decl (t->ctype, t->sym);
+
+ /* For structs with a user defined postblit or a destructor,
+ also set TREE_ADDRESSABLE on the type and all variants.
+ This will make the struct be passed around by reference. */
+ if (t->sym->postblit || t->sym->dtor)
+ {
+ for (tree tv = t->ctype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv))
+ TREE_ADDRESSABLE (tv) = 1;
+ }
+ }
+
+ /* Build a class type. Whereas structs are value types, classes are
+ reference types, with all the object-orientated features. */
+
+ void visit (TypeClass *t)
+ {
+ /* Need to set ctype right away in case of self-references to
+ the type during this call. */
+ tree basetype = make_node (RECORD_TYPE);
+ t->ctype = build_pointer_type (basetype);
+ d_keep (t->ctype);
+
+ /* Note that lang_specific data is assigned to both the reference
+ and the underlying record type. */
+ TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
+ TYPE_LANG_SPECIFIC (basetype) = TYPE_LANG_SPECIFIC (t->ctype);
+ CLASS_TYPE_P (basetype) = 1;
+
+ /* Put out all fields, including from each base class. */
+ layout_aggregate_type (t->sym, basetype, t->sym);
+ finish_aggregate_type (t->sym->structsize, t->sym->alignsize,
+ basetype, t->sym->userAttribDecl);
+
+ /* Classes only live in memory, so always set the TREE_ADDRESSABLE bit. */
+ for (tree tv = basetype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv))
+ TREE_ADDRESSABLE (tv) = 1;
+
+ /* Type is final, there are no derivations. */
+ if (t->sym->storage_class & STCfinal)
+ TYPE_FINAL_P (basetype) = 1;
+
+ /* Create BINFO even if debugging is off. This is needed to keep
+ references to inherited types. */
+ if (!t->sym->isInterfaceDeclaration ())
+ TYPE_BINFO (basetype) = build_class_binfo (NULL_TREE, t->sym);
+ else
+ {
+ unsigned offset = 0;
+
+ TYPE_BINFO (basetype) = build_interface_binfo (NULL_TREE, t->sym,
+ offset);
+ }
+
+ /* Associate all virtual methods with the class too. */
+ for (size_t i = 0; i < t->sym->vtbl.dim; i++)
+ {
+ FuncDeclaration *fd = t->sym->vtbl[i]->isFuncDeclaration ();
+ tree method = fd ? get_symbol_decl (fd) : error_mark_node;
+
+ if (!error_operand_p (method)
+ && DECL_CONTEXT (method) == basetype
+ && !chain_member (method, TYPE_FIELDS (basetype)))
+ TYPE_FIELDS (basetype) = chainon (TYPE_FIELDS (basetype), method);
+ }
+
+ TYPE_CONTEXT (basetype) = d_decl_context (t->sym);
+ build_type_decl (basetype, t->sym);
+ }
+};
+
+
+/* Build a tree from a frontend Type. */
+
+tree
+build_ctype (Type *t)
+{
+ if (!t->ctype)
+ {
+ TypeVisitor v;
+
+ /* Strip const modifiers from type before building. This is done
+ to ensure that back-end treats e.g: const (T) as a variant of T,
+ and not as two distinct types. */
+ if (t->isNaked ())
+ t->accept (&v);
+ else
+ {
+ Type *tb = t->castMod (0);
+ if (!tb->ctype)
+ tb->accept (&v);
+ t->ctype = insert_type_modifiers (tb->ctype, t->mod);
+ }
+ }
+
+ return t->ctype;
+}
diff --git a/gcc/d/verstr.h b/gcc/d/verstr.h
new file mode 100644
index 0000000..0dd41ee
--- /dev/null
+++ b/gcc/d/verstr.h
@@ -0,0 +1 @@
+"2.076.1"