From b4c522fabd0df7be08882d2207df8b2765026110 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sun, 28 Oct 2018 19:51:47 +0000 Subject: [PATCH] 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 --- ChangeLog | 24 + Makefile.def | 14 + Makefile.in | 526 +- Makefile.tpl | 21 + config-ml.in | 16 +- config/ChangeLog | 4 + config/multi.m4 | 3 +- configure | 217 +- configure.ac | 9 +- gcc/ChangeLog | 102 + gcc/Makefile.in | 37 +- gcc/config.gcc | 29 + gcc/config/aarch64/aarch64-d.c | 31 + gcc/config/aarch64/aarch64-linux.h | 2 + gcc/config/aarch64/aarch64-protos.h | 3 + gcc/config/aarch64/aarch64.h | 3 + gcc/config/aarch64/t-aarch64 | 4 + gcc/config/arm/arm-d.c | 53 + gcc/config/arm/arm-protos.h | 3 + gcc/config/arm/arm.h | 3 + gcc/config/arm/linux-eabi.h | 3 + gcc/config/arm/t-arm | 4 + gcc/config/default-d.c | 25 + gcc/config/glibc-d.c | 64 + gcc/config/gnu.h | 6 + gcc/config/i386/i386-d.c | 44 + gcc/config/i386/i386-protos.h | 3 + gcc/config/i386/i386.h | 3 + gcc/config/i386/linux-common.h | 6 + gcc/config/i386/t-i386 | 4 + gcc/config/kfreebsd-gnu.h | 6 + gcc/config/kopensolaris-gnu.h | 6 + gcc/config/linux-android.h | 6 + gcc/config/linux.h | 13 + gcc/config/mips/linux-common.h | 3 + gcc/config/mips/mips-d.c | 56 + gcc/config/mips/mips-protos.h | 3 + gcc/config/mips/mips.h | 3 + gcc/config/mips/t-mips | 4 + gcc/config/powerpcspe/linux.h | 13 + gcc/config/powerpcspe/linux64.h | 13 + gcc/config/powerpcspe/powerpcspe-d.c | 45 + gcc/config/powerpcspe/powerpcspe-protos.h | 3 + gcc/config/powerpcspe/powerpcspe.c | 5 +- gcc/config/powerpcspe/powerpcspe.h | 3 + gcc/config/powerpcspe/t-powerpcspe | 4 + gcc/config/riscv/riscv-d.c | 39 + gcc/config/riscv/riscv-protos.h | 3 + gcc/config/riscv/riscv.h | 3 + gcc/config/riscv/t-riscv | 5 + gcc/config/rs6000/linux.h | 13 + gcc/config/rs6000/linux64.h | 13 + gcc/config/rs6000/rs6000-d.c | 45 + gcc/config/rs6000/rs6000-protos.h | 3 + gcc/config/rs6000/rs6000.c | 5 +- gcc/config/rs6000/rs6000.h | 3 + gcc/config/rs6000/t-rs6000 | 4 + gcc/config/s390/s390-d.c | 41 + gcc/config/s390/s390-protos.h | 3 + gcc/config/s390/s390.h | 3 + gcc/config/s390/t-s390 | 4 + gcc/config/sparc/sparc-d.c | 48 + gcc/config/sparc/sparc-protos.h | 3 + gcc/config/sparc/sparc.h | 3 + gcc/config/sparc/t-sparc | 4 + gcc/config/t-glibc | 4 + gcc/configure | 26 +- gcc/configure.ac | 19 + gcc/d/ChangeLog | 617 + gcc/d/ChangeLog-2006 | 954 + gcc/d/ChangeLog-2007 | 1340 ++ gcc/d/ChangeLog-2008 | 331 + gcc/d/ChangeLog-2009 | 185 + gcc/d/ChangeLog-2010 | 1484 ++ gcc/d/ChangeLog-2011 | 1248 ++ gcc/d/ChangeLog-2012 | 857 + gcc/d/ChangeLog-2013 | 1221 ++ gcc/d/ChangeLog-2014 | 660 + gcc/d/ChangeLog-2015 | 771 + gcc/d/ChangeLog-2016 | 1262 ++ gcc/d/ChangeLog-2017 | 1175 ++ gcc/d/Make-lang.in | 337 + gcc/d/config-lang.in | 33 + gcc/d/d-attribs.cc | 835 + gcc/d/d-builtins.cc | 1169 ++ gcc/d/d-codegen.cc | 2660 +++ gcc/d/d-convert.cc | 805 + gcc/d/d-diagnostic.cc | 358 + gcc/d/d-frontend.cc | 628 + gcc/d/d-incpath.cc | 195 + gcc/d/d-lang.cc | 1797 ++ gcc/d/d-longdouble.cc | 204 + gcc/d/d-spec.cc | 503 + gcc/d/d-target-def.h | 20 + gcc/d/d-target.cc | 394 + gcc/d/d-target.def | 60 + gcc/d/d-target.h | 34 + gcc/d/d-tree.def | 29 + gcc/d/d-tree.h | 675 + gcc/d/decl.cc | 2312 +++ gcc/d/dmd/access.c | 572 + gcc/d/dmd/aggregate.h | 336 + gcc/d/dmd/aliasthis.c | 169 + gcc/d/dmd/aliasthis.h | 30 + gcc/d/dmd/apply.c | 150 + gcc/d/dmd/argtypes.c | 486 + gcc/d/dmd/arrayop.c | 638 + gcc/d/dmd/arraytypes.h | 62 + gcc/d/dmd/attrib.c | 1602 ++ gcc/d/dmd/attrib.h | 275 + gcc/d/dmd/blockexit.c | 502 + gcc/d/dmd/boostlicense.txt | 23 + gcc/d/dmd/canthrow.c | 317 + gcc/d/dmd/checkedint.c | 238 + gcc/d/dmd/checkedint.h | 35 + gcc/d/dmd/clone.c | 1198 ++ gcc/d/dmd/compiler.h | 29 + gcc/d/dmd/complex_t.h | 71 + gcc/d/dmd/cond.c | 369 + gcc/d/dmd/cond.h | 107 + gcc/d/dmd/constfold.c | 1918 ++ gcc/d/dmd/cppmangle.c | 1103 + gcc/d/dmd/ctfe.h | 267 + gcc/d/dmd/ctfeexpr.c | 2108 ++ gcc/d/dmd/dcast.c | 3732 ++++ gcc/d/dmd/dclass.c | 1947 ++ gcc/d/dmd/declaration.c | 2534 +++ gcc/d/dmd/declaration.h | 899 + gcc/d/dmd/delegatize.c | 210 + gcc/d/dmd/denum.c | 748 + gcc/d/dmd/dimport.c | 480 + gcc/d/dmd/dinterpret.c | 6801 ++++++ gcc/d/dmd/dmacro.c | 463 + gcc/d/dmd/dmangle.c | 865 + gcc/d/dmd/dmodule.c | 1436 ++ gcc/d/dmd/doc.c | 2741 +++ gcc/d/dmd/doc.h | 14 + gcc/d/dmd/dscope.c | 702 + gcc/d/dmd/dstruct.c | 1463 ++ gcc/d/dmd/dsymbol.c | 1781 ++ gcc/d/dmd/dsymbol.h | 406 + gcc/d/dmd/dtemplate.c | 8602 ++++++++ gcc/d/dmd/dversion.c | 202 + gcc/d/dmd/entity.c | 2392 +++ gcc/d/dmd/enum.h | 95 + gcc/d/dmd/errors.h | 50 + gcc/d/dmd/escape.c | 1234 ++ gcc/d/dmd/expression.c | 6945 +++++++ gcc/d/dmd/expression.h | 1559 ++ gcc/d/dmd/expressionsem.c | 8740 ++++++++ gcc/d/dmd/func.c | 5626 +++++ gcc/d/dmd/globals.h | 317 + gcc/d/dmd/hdrgen.c | 3414 +++ gcc/d/dmd/hdrgen.h | 54 + gcc/d/dmd/iasm.c | 44 + gcc/d/dmd/iasmgcc.c | 356 + gcc/d/dmd/identifier.c | 190 + gcc/d/dmd/identifier.h | 49 + gcc/d/dmd/idgen.c | 503 + gcc/d/dmd/impcnvgen.c | 599 + gcc/d/dmd/imphint.c | 56 + gcc/d/dmd/import.h | 60 + gcc/d/dmd/init.c | 286 + gcc/d/dmd/init.h | 119 + gcc/d/dmd/initsem.c | 920 + gcc/d/dmd/intrange.c | 460 + gcc/d/dmd/intrange.h | 149 + gcc/d/dmd/json.c | 890 + gcc/d/dmd/json.h | 17 + gcc/d/dmd/lexer.c | 2401 +++ gcc/d/dmd/lexer.h | 75 + gcc/d/dmd/macro.h | 42 + gcc/d/dmd/mangle.h | 33 + gcc/d/dmd/mars.h | 95 + gcc/d/dmd/module.h | 179 + gcc/d/dmd/mtype.c | 9410 +++++++++ gcc/d/dmd/mtype.h | 934 + gcc/d/dmd/nogc.c | 241 + gcc/d/dmd/nspace.c | 234 + gcc/d/dmd/nspace.h | 38 + gcc/d/dmd/objc.c | 84 + gcc/d/dmd/objc.h | 53 + gcc/d/dmd/opover.c | 1966 ++ gcc/d/dmd/optimize.c | 1268 ++ gcc/d/dmd/parse.c | 7992 +++++++ gcc/d/dmd/parse.h | 188 + gcc/d/dmd/readme.txt | 13 + gcc/d/dmd/root/aav.c | 175 + gcc/d/dmd/root/aav.h | 20 + gcc/d/dmd/root/array.h | 232 + gcc/d/dmd/root/ctfloat.h | 47 + gcc/d/dmd/root/dcompat.h | 18 + gcc/d/dmd/root/file.c | 265 + gcc/d/dmd/root/file.h | 54 + gcc/d/dmd/root/filename.c | 673 + gcc/d/dmd/root/filename.h | 51 + gcc/d/dmd/root/hash.h | 77 + gcc/d/dmd/root/object.h | 60 + gcc/d/dmd/root/outbuffer.c | 401 + gcc/d/dmd/root/outbuffer.h | 77 + gcc/d/dmd/root/port.h | 43 + gcc/d/dmd/root/rmem.c | 162 + gcc/d/dmd/root/rmem.h | 35 + gcc/d/dmd/root/root.h | 19 + gcc/d/dmd/root/rootobject.c | 49 + gcc/d/dmd/root/speller.c | 240 + gcc/d/dmd/root/speller.h | 16 + gcc/d/dmd/root/stringtable.c | 200 + gcc/d/dmd/root/stringtable.h | 57 + gcc/d/dmd/safe.c | 168 + gcc/d/dmd/sapply.c | 156 + gcc/d/dmd/scope.h | 158 + gcc/d/dmd/sideeffect.c | 439 + gcc/d/dmd/statement.c | 1661 ++ gcc/d/dmd/statement.h | 783 + gcc/d/dmd/statementsem.c | 3574 ++++ gcc/d/dmd/staticassert.c | 104 + gcc/d/dmd/staticassert.h | 32 + gcc/d/dmd/staticcond.c | 100 + gcc/d/dmd/target.h | 74 + gcc/d/dmd/template.h | 397 + gcc/d/dmd/tokens.c | 476 + gcc/d/dmd/tokens.h | 233 + gcc/d/dmd/traits.c | 1451 ++ gcc/d/dmd/typesem.c | 123 + gcc/d/dmd/unittests.c | 26 + gcc/d/dmd/utf.c | 307 + gcc/d/dmd/utf.h | 117 + gcc/d/dmd/utils.c | 122 + gcc/d/dmd/version.h | 45 + gcc/d/dmd/visitor.h | 599 + gcc/d/expr.cc | 3138 +++ gcc/d/gdc.texi | 718 + gcc/d/imports.cc | 208 + gcc/d/intrinsics.cc | 846 + gcc/d/intrinsics.def | 154 + gcc/d/lang-specs.h | 29 + gcc/d/lang.opt | 346 + gcc/d/longdouble.h | 136 + gcc/d/modules.cc | 853 + gcc/d/runtime.cc | 315 + gcc/d/runtime.def | 224 + gcc/d/toir.cc | 1447 ++ gcc/d/typeinfo.cc | 1676 ++ gcc/d/types.cc | 986 + gcc/d/verstr.h | 1 + gcc/doc/contrib.texi | 3 + gcc/doc/frontends.texi | 3 +- gcc/doc/install.texi | 10 +- gcc/doc/invoke.texi | 10 + gcc/doc/sourcebuild.texi | 4 + gcc/doc/standards.texi | 6 + gcc/doc/tm.texi | 32 + gcc/doc/tm.texi.in | 19 + gcc/dwarf2out.c | 23 +- gcc/gcc.c | 1 + gcc/genhooks.c | 1 + gcc/po/ChangeLog | 4 + gcc/po/EXCLUDES | 40 + gcc/testsuite/ChangeLog | 36 + gcc/testsuite/gcc.misc-tests/help.exp | 2 +- gcc/testsuite/gdc.dg/asan/asan.exp | 32 + gcc/testsuite/gdc.dg/asan/gdc272.d | 15 + gcc/testsuite/gdc.dg/compilable.d | 444 + gcc/testsuite/gdc.dg/dg.exp | 50 + gcc/testsuite/gdc.dg/gdc254.d | 15 + gcc/testsuite/gdc.dg/gdc260.d | 10 + gcc/testsuite/gdc.dg/gdc270a.d | 11 + gcc/testsuite/gdc.dg/gdc270b.d | 7 + gcc/testsuite/gdc.dg/gdc282.d | 48 + gcc/testsuite/gdc.dg/gdc283.d | 102 + gcc/testsuite/gdc.dg/imports/gdc170.d | 18 + gcc/testsuite/gdc.dg/imports/gdc231.d | 24 + gcc/testsuite/gdc.dg/imports/gdc239.d | 9 + gcc/testsuite/gdc.dg/imports/gdc241a.d | 6 + gcc/testsuite/gdc.dg/imports/gdc241b.d | 8 + gcc/testsuite/gdc.dg/imports/gdc251a.d | 6 + gcc/testsuite/gdc.dg/imports/gdc251b.d | 3 + gcc/testsuite/gdc.dg/imports/gdc253.d | 23 + gcc/testsuite/gdc.dg/imports/gdc254a.d | 10 + gcc/testsuite/gdc.dg/imports/gdc256.d | 1 + gcc/testsuite/gdc.dg/imports/gdc27.d | 14 + .../gdc.dg/imports/gdcpkg256/package.d | 3 + gcc/testsuite/gdc.dg/imports/runnable.d | 23 + gcc/testsuite/gdc.dg/link.d | 39 + gcc/testsuite/gdc.dg/lto/lto.exp | 56 + gcc/testsuite/gdc.dg/lto/ltotests_0.d | 90 + gcc/testsuite/gdc.dg/lto/ltotests_1.d | 9 + gcc/testsuite/gdc.dg/runnable.d | 1575 ++ gcc/testsuite/gdc.dg/simd.d | 1734 ++ gcc/testsuite/gdc.test/compilable/99bottles.d | 52 + gcc/testsuite/gdc.test/compilable/a3682.d | 20 + .../gdc.test/compilable/aggr_alignment.d | 28 + gcc/testsuite/gdc.test/compilable/aliasdecl.d | 40 + gcc/testsuite/gdc.test/compilable/alignment.d | 12 + gcc/testsuite/gdc.test/compilable/art4769.d | 19 + gcc/testsuite/gdc.test/compilable/b11118.d | 12 + gcc/testsuite/gdc.test/compilable/b1215.d | 146 + gcc/testsuite/gdc.test/compilable/b15428.d | 13 + gcc/testsuite/gdc.test/compilable/b16244.d | 12 + gcc/testsuite/gdc.test/compilable/b16346.d | 3 + gcc/testsuite/gdc.test/compilable/b16355.d | 14 + gcc/testsuite/gdc.test/compilable/b16382.d | 6 + gcc/testsuite/gdc.test/compilable/b16483.d | 12 + gcc/testsuite/gdc.test/compilable/b16598.d | 15 + gcc/testsuite/gdc.test/compilable/b16697.d | 13 + gcc/testsuite/gdc.test/compilable/b16967.d | 33 + gcc/testsuite/gdc.test/compilable/b17111.d | 13 + gcc/testsuite/gdc.test/compilable/b33.d | 12 + gcc/testsuite/gdc.test/compilable/b6227.d | 18 + gcc/testsuite/gdc.test/compilable/b6395.d | 25 + gcc/testsuite/gdc.test/compilable/b6400.d | 37 + .../gdc.test/compilable/betterCarray.d | 17 + .../gdc.test/compilable/betterCswitch.d | 16 + gcc/testsuite/gdc.test/compilable/bug11735.d | 36 + gcc/testsuite/gdc.test/compilable/bug6963.d | 73 + gcc/testsuite/gdc.test/compilable/callconv.d | 75 + gcc/testsuite/gdc.test/compilable/compile1.d | 964 + gcc/testsuite/gdc.test/compilable/const.d | 41 + gcc/testsuite/gdc.test/compilable/cppmangle.d | 353 + gcc/testsuite/gdc.test/compilable/ctfe_math.d | 25 + gcc/testsuite/gdc.test/compilable/ddoc1.d | 69 + gcc/testsuite/gdc.test/compilable/ddoc10.d | 210 + gcc/testsuite/gdc.test/compilable/ddoc10236.d | 59 + .../gdc.test/compilable/ddoc10236b.d | 69 + gcc/testsuite/gdc.test/compilable/ddoc10325.d | 17 + gcc/testsuite/gdc.test/compilable/ddoc10334.d | 29 + gcc/testsuite/gdc.test/compilable/ddoc10366.d | 20 + gcc/testsuite/gdc.test/compilable/ddoc10367.d | 28 + gcc/testsuite/gdc.test/compilable/ddoc10869.d | 27 + gcc/testsuite/gdc.test/compilable/ddoc10870.d | 10 + gcc/testsuite/gdc.test/compilable/ddoc11.d | 69 + gcc/testsuite/gdc.test/compilable/ddoc11479.d | 96 + gcc/testsuite/gdc.test/compilable/ddoc11511.d | 20 + gcc/testsuite/gdc.test/compilable/ddoc11823.d | 7 + gcc/testsuite/gdc.test/compilable/ddoc12.d | 20 + gcc/testsuite/gdc.test/compilable/ddoc12706.d | 9 + gcc/testsuite/gdc.test/compilable/ddoc12745.d | 25 + gcc/testsuite/gdc.test/compilable/ddoc13.d | 26 + gcc/testsuite/gdc.test/compilable/ddoc13270.d | 18 + gcc/testsuite/gdc.test/compilable/ddoc13502.d | 24 + gcc/testsuite/gdc.test/compilable/ddoc13645.d | 9 + gcc/testsuite/gdc.test/compilable/ddoc14.d | 97 + gcc/testsuite/gdc.test/compilable/ddoc14383.d | 14 + gcc/testsuite/gdc.test/compilable/ddoc14413.d | 12 + gcc/testsuite/gdc.test/compilable/ddoc14633.d | 23 + gcc/testsuite/gdc.test/compilable/ddoc14778.d | 42 + gcc/testsuite/gdc.test/compilable/ddoc15475.d | 12 + gcc/testsuite/gdc.test/compilable/ddoc17697.d | 29 + gcc/testsuite/gdc.test/compilable/ddoc198.d | 35 + gcc/testsuite/gdc.test/compilable/ddoc2.d | 42 + gcc/testsuite/gdc.test/compilable/ddoc2273.d | 37 + gcc/testsuite/gdc.test/compilable/ddoc3.d | 71 + gcc/testsuite/gdc.test/compilable/ddoc4.d | 11 + gcc/testsuite/gdc.test/compilable/ddoc4162.d | 17 + gcc/testsuite/gdc.test/compilable/ddoc4899.d | 23 + gcc/testsuite/gdc.test/compilable/ddoc5.d | 31 + gcc/testsuite/gdc.test/compilable/ddoc5446.d | 69 + gcc/testsuite/gdc.test/compilable/ddoc5446a.d | 15 + gcc/testsuite/gdc.test/compilable/ddoc5446b.d | 6 + gcc/testsuite/gdc.test/compilable/ddoc6.d | 25 + gcc/testsuite/gdc.test/compilable/ddoc648.d | 90 + gcc/testsuite/gdc.test/compilable/ddoc6491.d | 14 + gcc/testsuite/gdc.test/compilable/ddoc7.d | 59 + gcc/testsuite/gdc.test/compilable/ddoc7555.d | 53 + gcc/testsuite/gdc.test/compilable/ddoc7656.d | 24 + gcc/testsuite/gdc.test/compilable/ddoc7715.d | 16 + gcc/testsuite/gdc.test/compilable/ddoc7795.d | 17 + gcc/testsuite/gdc.test/compilable/ddoc8.d | 9 + gcc/testsuite/gdc.test/compilable/ddoc8271.d | 15 + gcc/testsuite/gdc.test/compilable/ddoc8739.d | 19 + gcc/testsuite/gdc.test/compilable/ddoc9.d | 26 + gcc/testsuite/gdc.test/compilable/ddoc9037.d | 18 + gcc/testsuite/gdc.test/compilable/ddoc9155.d | 81 + gcc/testsuite/gdc.test/compilable/ddoc9305.d | 38 + gcc/testsuite/gdc.test/compilable/ddoc9369.d | 18 + gcc/testsuite/gdc.test/compilable/ddoc9475.d | 29 + gcc/testsuite/gdc.test/compilable/ddoc9497a.d | 12 + gcc/testsuite/gdc.test/compilable/ddoc9497b.d | 12 + gcc/testsuite/gdc.test/compilable/ddoc9497c.d | 12 + gcc/testsuite/gdc.test/compilable/ddoc9497d.d | 12 + gcc/testsuite/gdc.test/compilable/ddoc9676a.d | 9 + gcc/testsuite/gdc.test/compilable/ddoc9676b.d | 8 + gcc/testsuite/gdc.test/compilable/ddoc9727.d | 25 + gcc/testsuite/gdc.test/compilable/ddoc9789.d | 11 + gcc/testsuite/gdc.test/compilable/ddoc9903.d | 35 + gcc/testsuite/gdc.test/compilable/ddocYear.d | 6 + .../gdc.test/compilable/ddocbackticks.d | 24 + .../gdc.test/compilable/ddocunittest.d | 496 + gcc/testsuite/gdc.test/compilable/debuginfo.d | 20 + gcc/testsuite/gdc.test/compilable/defa.d | 19 + gcc/testsuite/gdc.test/compilable/depmsg.d | 33 + .../gdc.test/compilable/deprecate12979a.d | 27 + .../gdc.test/compilable/deprecate14283.d | 18 + .../gdc.test/compilable/depsOutput9948.d | 12 + .../gdc.test/compilable/derivedarray.d | 130 + gcc/testsuite/gdc.test/compilable/diag11066.d | 13 + gcc/testsuite/gdc.test/compilable/diag3243.d | 19 + gcc/testsuite/gdc.test/compilable/dip22.d | 20 + .../gdc.test/compilable/empty_file.d | 0 gcc/testsuite/gdc.test/compilable/exception.d | 18 + .../gdc.test/compilable/extra-files/c6395.d | 20 + .../compilable/extra-files/ddoc10367.ddoc | 1 + .../compilable/extra-files/ddoc198.ddoc | 2 + .../compilable/extra-files/ddoc3.ddoc | 3 + .../compilable/extra-files/ddoc9369.ddoc | 3 + .../compilable/extra-files/ddoc9497a.ddoc | 1 + .../compilable/extra-files/ddoc9497b.ddoc | 1 + .../compilable/extra-files/ddoc9497c.ddoc | 1 + .../compilable/extra-files/ddoc9497d.ddoc | 1 + .../compilable/extra-files/ddoc9676a.ddoc | 1 + .../compilable/extra-files/depsOutput9948a.d | 6 + .../gdc.test/compilable/extra-files/e6815.d | 7 + .../example7190/controllers/HomeController.d | 7 + .../example7190/models/HomeModel.d | 11 + .../gdc.test/compilable/extra-files/header1.d | 521 + .../gdc.test/compilable/extra-files/header2.d | 152 + .../gdc.test/compilable/extra-files/header3.d | 14 + .../compilable/extra-files/imp12624.d | 27 + .../gdc.test/compilable/extra-files/imp9057.d | 5 + .../compilable/extra-files/imp9057_2.d | 5 + .../extra-files/pkgDIP37/datetime/common.d | 3 + .../extra-files/pkgDIP37/datetime/package.d | 3 + .../extra-files/pkgDIP37/test17629/common.di | 3 + .../extra-files/pkgDIP37/test17629/package.di | 2 + .../extra-files/pkgDIP37_10302/liba.d | 2 + .../extra-files/pkgDIP37_10302/libb.d | 11 + .../extra-files/pkgDIP37_10302/package.d | 2 + .../extra-files/pkgDIP37_10354/mbar.d | 2 + .../extra-files/pkgDIP37_10354/mfoo.d | 2 + .../extra-files/pkgDIP37_10354/package.d | 3 + .../extra-files/pkgDIP37_10421/algo/mod.d | 8 + .../extra-files/pkgDIP37_10421/algo/package.d | 7 + .../extra-files/pkgDIP37_10421/except.d | 3 + .../serenity7190/core/Controller.d | 8 + .../extra-files/serenity7190/core/Model.d | 5 + .../compilable/extra-files/test16080b.d | 6 + gcc/testsuite/gdc.test/compilable/fail260.d | 37 + gcc/testsuite/gdc.test/compilable/fix17123.d | 14 + gcc/testsuite/gdc.test/compilable/fix17335.d | 28 + gcc/testsuite/gdc.test/compilable/fix17349.d | 40 + gcc/testsuite/gdc.test/compilable/fix17686.d | 45 + gcc/testsuite/gdc.test/compilable/forward1.d | 7 + gcc/testsuite/gdc.test/compilable/future.d | 47 + gcc/testsuite/gdc.test/compilable/futurexf.d | 12 + .../gdc.test/compilable/iasm_labeloperand.d | 48 + gcc/testsuite/gdc.test/compilable/ice10040.d | 15 + gcc/testsuite/gdc.test/compilable/ice10431a.d | 19 + gcc/testsuite/gdc.test/compilable/ice10431b.d | 11 + gcc/testsuite/gdc.test/compilable/ice10486.d | 5 + gcc/testsuite/gdc.test/compilable/ice10598.d | 3 + gcc/testsuite/gdc.test/compilable/ice11054.d | 8 + gcc/testsuite/gdc.test/compilable/ice11300.d | 5 + gcc/testsuite/gdc.test/compilable/ice11596.d | 17 + gcc/testsuite/gdc.test/compilable/ice11610.d | 79 + gcc/testsuite/gdc.test/compilable/ice11777.d | 14 + gcc/testsuite/gdc.test/compilable/ice11906.d | 10 + gcc/testsuite/gdc.test/compilable/ice11925.d | 38 + gcc/testsuite/gdc.test/compilable/ice12002.d | 24 + gcc/testsuite/gdc.test/compilable/ice12554.d | 46 + gcc/testsuite/gdc.test/compilable/ice12956.d | 30 + gcc/testsuite/gdc.test/compilable/ice13071.d | 13 + gcc/testsuite/gdc.test/compilable/ice13088.d | 19 + gcc/testsuite/gdc.test/compilable/ice13245.d | 5 + gcc/testsuite/gdc.test/compilable/ice13323.d | 10 + gcc/testsuite/gdc.test/compilable/ice13403.d | 5 + gcc/testsuite/gdc.test/compilable/ice13792.d | 6 + gcc/testsuite/gdc.test/compilable/ice13874.d | 20 + gcc/testsuite/gdc.test/compilable/ice13886.d | 14 + gcc/testsuite/gdc.test/compilable/ice13920.d | 25 + gcc/testsuite/gdc.test/compilable/ice13968.d | 18 + gcc/testsuite/gdc.test/compilable/ice14075.d | 15 + gcc/testsuite/gdc.test/compilable/ice1524.d | 22 + gcc/testsuite/gdc.test/compilable/ice15333.d | 14 + gcc/testsuite/gdc.test/compilable/ice15760.d | 11 + gcc/testsuite/gdc.test/compilable/ice15789.d | 30 + gcc/testsuite/gdc.test/compilable/ice15992.d | 34 + gcc/testsuite/gdc.test/compilable/ice6538.d | 43 + gcc/testsuite/gdc.test/compilable/ice8392.d | 12 + gcc/testsuite/gdc.test/compilable/ice854.d | 43 + gcc/testsuite/gdc.test/compilable/ice9663.d | 13 + .../gdc.test/compilable/imports/a12506.d | 3 + .../gdc.test/compilable/imports/a12567.d | 4 + .../gdc.test/compilable/imports/a13226.d | 18 + .../gdc.test/compilable/imports/a14528.d | 6 + .../gdc.test/compilable/imports/a15333.d | 12 + .../gdc.test/compilable/imports/a15760.d | 8 + .../gdc.test/compilable/imports/a15856.d | 3 + .../gdc.test/compilable/imports/a313.d | 8 + .../compilable/imports/a313templatemixin1.d | 3 + .../compilable/imports/a313templatemixin2.d | 3 + .../gdc.test/compilable/imports/a314.d | 5 + .../gdc.test/compilable/imports/a8392.d | 15 + .../gdc.test/compilable/imports/art4769a.d | 15 + .../gdc.test/compilable/imports/art4769b.d | 9 + .../gdc.test/compilable/imports/b313.d | 7 + .../gdc.test/compilable/imports/b33a.d | 28 + .../gdc.test/compilable/imports/b3682.d | 5 + .../gdc.test/compilable/imports/bug8922.d | 1 + .../gdc.test/compilable/imports/c314.d | 4 + .../gdc.test/compilable/imports/defaa.d | 15 + .../gdc.test/compilable/imports/defab.d | 15 + .../gdc.test/compilable/imports/defac.d | 13 + .../gdc.test/compilable/imports/defad.d | 14 + .../gdc.test/compilable/imports/dip22.d | 21 + .../gdc.test/compilable/imports/f313.d | 6 + .../compilable/imports/fwdref12201a.d | 1 + .../compilable/imports/fwdref2_test17548.d | 9 + .../gdc.test/compilable/imports/fwdref9514.d | 4 + .../gdc.test/compilable/imports/g313.d | 24 + .../gdc.test/compilable/imports/g313public.d | 3 + .../compilable/imports/g313staticif.d | 3 + .../compilable/imports/g313stringmixin.d | 3 + .../compilable/imports/g313templatemixin.d | 3 + .../gdc.test/compilable/imports/ice10598a.d | 5 + .../gdc.test/compilable/imports/ice10598b.d | 3 + .../gdc.test/compilable/imports/ice11054a.d | 21 + .../gdc.test/compilable/imports/ice11300a.d | 3 + .../gdc.test/compilable/imports/ice13403a.d | 7 + .../gdc.test/compilable/imports/imp12242a.d | 17 + .../gdc.test/compilable/imports/imp12242a1.d | 8 + .../gdc.test/compilable/imports/imp12242a2.d | 11 + .../gdc.test/compilable/imports/imp12242b.d | 17 + .../gdc.test/compilable/imports/imp12242b1.d | 8 + .../gdc.test/compilable/imports/imp12242b2.d | 11 + .../gdc.test/compilable/imports/imp15490a.d | 8 + .../gdc.test/compilable/imports/imp15490b.d | 12 + .../gdc.test/compilable/imports/imp15907.d | 23 + .../gdc.test/compilable/imports/imp15925.d | 1 + .../gdc.test/compilable/imports/imp16080.d | 4 + .../gdc.test/compilable/imports/imp16085.d | 29 + .../gdc.test/compilable/imports/imp16085b.d | 25 + .../gdc.test/compilable/imports/imp16460.d | 3 + .../gdc.test/compilable/imports/imp16798.d | 4 + .../gdc.test/compilable/imports/jsonimport1.d | 3 + .../gdc.test/compilable/imports/jsonimport2.d | 3 + .../gdc.test/compilable/imports/jsonimport3.d | 3 + .../gdc.test/compilable/imports/jsonimport4.d | 1 + .../gdc.test/compilable/imports/pkg313/c313.d | 5 + .../compilable/imports/pkgmod313/mod.d | 3 + .../compilable/imports/pkgmod313/package.d | 5 + .../compilable/imports/protectionimp.d | 30 + .../gdc.test/compilable/imports/stdio4003.d | 3 + .../gdc.test/compilable/imports/test10375a.d | 6 + .../gdc.test/compilable/imports/test10752.d | 2 + .../gdc.test/compilable/imports/test11225b.d | 13 + .../gdc.test/compilable/imports/test11225c.d | 2 + .../compilable/imports/test11563core_bitop.d | 1 + .../compilable/imports/test11563std_array.d | 6 + .../compilable/imports/test11563std_range.d | 12 + .../compilable/imports/test11563std_traits.d | 22 + .../gdc.test/compilable/imports/test1238a.d | 3 + .../gdc.test/compilable/imports/test1238b.d | 3 + .../gdc.test/compilable/imports/test13242a.d | 19 + .../gdc.test/compilable/imports/test13242b.d | 13 + .../gdc.test/compilable/imports/test14666a.d | 9 + .../gdc.test/compilable/imports/test14666b.d | 8 + .../gdc.test/compilable/imports/test15117a.d | 9 + .../gdc.test/compilable/imports/test15150a.d | 6 + .../gdc.test/compilable/imports/test15150b.d | 3 + .../gdc.test/compilable/imports/test15785.d | 13 + .../gdc.test/compilable/imports/test15857a.d | 2 + .../gdc.test/compilable/imports/test15857b.d | 1 + .../gdc.test/compilable/imports/test15857c.d | 1 + .../gdc.test/compilable/imports/test16348.d | 6 + .../gdc.test/compilable/imports/test1754a.d | 5 + .../gdc.test/compilable/imports/test1754b.d | 5 + .../gdc.test/compilable/imports/test1imp.d | 2 + .../gdc.test/compilable/imports/test25a.d | 12 + .../gdc.test/compilable/imports/test25b.d | 9 + .../gdc.test/compilable/imports/test2991.d | 5 + .../gdc.test/compilable/imports/test4003a.d | 6 + .../gdc.test/compilable/imports/test50a.d | 6 + .../gdc.test/compilable/imports/test55a.d | 14 + .../gdc.test/compilable/imports/test59a.d | 5 + .../gdc.test/compilable/imports/test59b.d | 3 + .../gdc.test/compilable/imports/test6013.d | 11 + .../gdc.test/compilable/imports/test61a.d | 4 + .../gdc.test/compilable/imports/test62a.d | 15 + .../gdc.test/compilable/imports/test63a.d | 10 + .../gdc.test/compilable/imports/test66a.d | 7 + .../gdc.test/compilable/imports/test67a.d | 19 + .../gdc.test/compilable/imports/test68a.d | 9 + .../gdc.test/compilable/imports/test70.d | 5 + .../gdc.test/compilable/imports/test71.d | 6 + .../gdc.test/compilable/imports/test72a.d | 2 + .../gdc.test/compilable/imports/test72b.d | 2 + .../gdc.test/compilable/imports/test72c.d | 5 + .../gdc.test/compilable/imports/test7491a.d | 1 + .../gdc.test/compilable/imports/test7491b.d | 1 + .../compilable/imports/test9276decl.d | 14 + .../compilable/imports/test9276expr.d | 15 + .../compilable/imports/test9276hash.d | 1 + .../compilable/imports/test9276parser.d | 4 + .../gdc.test/compilable/imports/test9276sem.d | 25 + .../compilable/imports/test9276type.d | 12 + .../compilable/imports/test9276util.d | 13 + .../compilable/imports/test9276visitors.d | 16 + .../gdc.test/compilable/imports/test9399a.d | 5 + .../compilable/imports/test9436aggr.d | 11 + .../compilable/imports/test9436interp.d | 16 + .../compilable/imports/test9436node.d | 7 + .../compilable/imports/test9436type.d | 13 + .../gdc.test/compilable/imports/test9672a.d | 32 + .../gdc.test/compilable/imports/test9692b.d | 2 + .../gdc.test/compilable/imports/test9919a.d | 3 + .../gdc.test/compilable/imports/test9919b.d | 19 + .../gdc.test/compilable/imports/test9919c.d | 5 + .../compilable/imports/testcontracts.d | 32 + .../compilable/imports/typecons4003.d | 22 + .../gdc.test/compilable/imports/udamodule1.d | 5 + .../gdc.test/compilable/imports/udamodule2.d | 7 + .../gdc.test/compilable/imports/udamodule2a.d | 6 + .../gdc.test/compilable/imports/wax16798.d | 4 + .../gdc.test/compilable/interpret3.d | 7733 +++++++ gcc/testsuite/gdc.test/compilable/json.d | 113 + gcc/testsuite/gdc.test/compilable/line.d | 30 + gcc/testsuite/gdc.test/compilable/noderef.d | 53 + gcc/testsuite/gdc.test/compilable/nogc.d | 111 + gcc/testsuite/gdc.test/compilable/protattr.d | 5 + .../gdc.test/compilable/protection.d | 96 + .../protection/aggregate/mod14275.d | 11 + .../compilable/protection/basic/mod1.d | 13 + .../compilable/protection/basic/tests.d | 23 + .../compilable/protection/bug/bug14275.d | 12 + .../compilable/protection/subpkg/explicit.d | 4 + .../compilable/protection/subpkg/tests.d | 12 + .../compilable/protection/subpkg2/tests.d | 5 + gcc/testsuite/gdc.test/compilable/pull6815.d | 9 + gcc/testsuite/gdc.test/compilable/riia_ctor.d | 44 + gcc/testsuite/gdc.test/compilable/scope.d | 14 + .../gdc.test/compilable/shared_destructor.d | 21 + .../compilable/sw_transition_complex.d | 136 + .../gdc.test/compilable/sw_transition_field.d | 25 + .../gdc.test/compilable/sw_transition_tls.d | 16 + gcc/testsuite/gdc.test/compilable/test1.d | 13 + gcc/testsuite/gdc.test/compilable/test10056.d | 66 + gcc/testsuite/gdc.test/compilable/test10066.d | 66 + gcc/testsuite/gdc.test/compilable/test10073.d | 24 + gcc/testsuite/gdc.test/compilable/test10186.d | 27 + gcc/testsuite/gdc.test/compilable/test10312.d | 11 + gcc/testsuite/gdc.test/compilable/test10375.d | 13 + gcc/testsuite/gdc.test/compilable/test10520.d | 11 + gcc/testsuite/gdc.test/compilable/test10695.d | 9 + gcc/testsuite/gdc.test/compilable/test10726.d | 53 + gcc/testsuite/gdc.test/compilable/test10752.d | 6 + gcc/testsuite/gdc.test/compilable/test10981.d | 24 + gcc/testsuite/gdc.test/compilable/test10992.d | 11 + .../gdc.test/compilable/test10992b.d | 16 + gcc/testsuite/gdc.test/compilable/test10993.d | 33 + gcc/testsuite/gdc.test/compilable/test11169.d | 45 + .../gdc.test/compilable/test11225a.d | 9 + gcc/testsuite/gdc.test/compilable/test11237.d | 4 + gcc/testsuite/gdc.test/compilable/test11371.d | 11 + gcc/testsuite/gdc.test/compilable/test11471.d | 10 + .../compilable/test11559upgradeoptlink.d | 16 + gcc/testsuite/gdc.test/compilable/test11563.d | 9 + gcc/testsuite/gdc.test/compilable/test11656.d | 10 + gcc/testsuite/gdc.test/compilable/test11824.d | 72 + gcc/testsuite/gdc.test/compilable/test11914.d | 118 + gcc/testsuite/gdc.test/compilable/test11980.d | 2 + gcc/testsuite/gdc.test/compilable/test12009.d | 36 + gcc/testsuite/gdc.test/compilable/test1238.d | 10 + gcc/testsuite/gdc.test/compilable/test12523.d | 15 + gcc/testsuite/gdc.test/compilable/test12527.d | 10 + gcc/testsuite/gdc.test/compilable/test12558.d | 39 + .../gdc.test/compilable/test12567a.d | 11 + .../gdc.test/compilable/test12567b.d | 11 + .../gdc.test/compilable/test12567c.d | 11 + .../gdc.test/compilable/test12567d.d | 10 + gcc/testsuite/gdc.test/compilable/test12593.d | 12 + gcc/testsuite/gdc.test/compilable/test12624.d | 31 + gcc/testsuite/gdc.test/compilable/test12967.d | 64 + .../gdc.test/compilable/test12979a.d | 5 + .../gdc.test/compilable/test12979b.d | 64 + gcc/testsuite/gdc.test/compilable/test13008.d | 10 + gcc/testsuite/gdc.test/compilable/test13053.d | 13 + gcc/testsuite/gdc.test/compilable/test13193.d | 126 + gcc/testsuite/gdc.test/compilable/test13194.d | 17 + gcc/testsuite/gdc.test/compilable/test13226.d | 32 + gcc/testsuite/gdc.test/compilable/test13242.d | 34 + gcc/testsuite/gdc.test/compilable/test13281.d | 47 + gcc/testsuite/gdc.test/compilable/test13512.d | 8 + gcc/testsuite/gdc.test/compilable/test1353.d | 14 + gcc/testsuite/gdc.test/compilable/test13600.d | 13 + gcc/testsuite/gdc.test/compilable/test13668.d | 38 + gcc/testsuite/gdc.test/compilable/test13858.d | 20 + gcc/testsuite/gdc.test/compilable/test13902.d | 8 + gcc/testsuite/gdc.test/compilable/test14275.d | 4 + gcc/testsuite/gdc.test/compilable/test14317.d | 15 + gcc/testsuite/gdc.test/compilable/test14375.d | 15 + gcc/testsuite/gdc.test/compilable/test14528.d | 14 + gcc/testsuite/gdc.test/compilable/test14666.d | 8 + gcc/testsuite/gdc.test/compilable/test14747.d | 31 + gcc/testsuite/gdc.test/compilable/test14781.d | 38 + gcc/testsuite/gdc.test/compilable/test14838.d | 91 + gcc/testsuite/gdc.test/compilable/test14962.d | 41 + gcc/testsuite/gdc.test/compilable/test14973.d | 104 + gcc/testsuite/gdc.test/compilable/test15019.d | 74 + gcc/testsuite/gdc.test/compilable/test15056.d | 28 + gcc/testsuite/gdc.test/compilable/test15150.d | 8 + gcc/testsuite/gdc.test/compilable/test15177.d | 23 + gcc/testsuite/gdc.test/compilable/test15326.d | 23 + gcc/testsuite/gdc.test/compilable/test1537.d | 106 + .../gdc.test/compilable/test15389_x.d | 7 + .../gdc.test/compilable/test15389_y.d | 8 + gcc/testsuite/gdc.test/compilable/test15402.d | 12 + gcc/testsuite/gdc.test/compilable/test15464.d | 22 + gcc/testsuite/gdc.test/compilable/test15490.d | 12 + .../gdc.test/compilable/test15519_x.d | 7 + .../gdc.test/compilable/test15519_y.d | 8 + gcc/testsuite/gdc.test/compilable/test15550.d | 16 + gcc/testsuite/gdc.test/compilable/test15565.d | 3 + gcc/testsuite/gdc.test/compilable/test15578.d | 10 + gcc/testsuite/gdc.test/compilable/test15618.d | 19 + gcc/testsuite/gdc.test/compilable/test15668.d | 9 + gcc/testsuite/gdc.test/compilable/test15762.d | 13 + gcc/testsuite/gdc.test/compilable/test15780.d | 17 + gcc/testsuite/gdc.test/compilable/test15784.d | 47 + gcc/testsuite/gdc.test/compilable/test15785.d | 22 + gcc/testsuite/gdc.test/compilable/test15802.d | 10 + gcc/testsuite/gdc.test/compilable/test15856.d | 17 + gcc/testsuite/gdc.test/compilable/test15898.d | 27 + gcc/testsuite/gdc.test/compilable/test15907.d | 18 + gcc/testsuite/gdc.test/compilable/test15925.d | 18 + gcc/testsuite/gdc.test/compilable/test16031.d | 33 + gcc/testsuite/gdc.test/compilable/test16080.d | 7 + gcc/testsuite/gdc.test/compilable/test16083.d | 15 + gcc/testsuite/gdc.test/compilable/test16085.d | 13 + gcc/testsuite/gdc.test/compilable/test16225.d | 14 + gcc/testsuite/gdc.test/compilable/test16292.d | 19 + gcc/testsuite/gdc.test/compilable/test16303.d | 13 + gcc/testsuite/gdc.test/compilable/test16340.d | 9 + gcc/testsuite/gdc.test/compilable/test16348.d | 13 + gcc/testsuite/gdc.test/compilable/test16460.d | 13 + gcc/testsuite/gdc.test/compilable/test16525.d | 19 + gcc/testsuite/gdc.test/compilable/test16540.d | 14 + gcc/testsuite/gdc.test/compilable/test16563.d | 10 + gcc/testsuite/gdc.test/compilable/test16570.d | 8 + gcc/testsuite/gdc.test/compilable/test16572.d | 15 + gcc/testsuite/gdc.test/compilable/test16574.d | 34 + gcc/testsuite/gdc.test/compilable/test16607.d | 15 + gcc/testsuite/gdc.test/compilable/test16627.d | 18 + gcc/testsuite/gdc.test/compilable/test1673.d | 52 + gcc/testsuite/gdc.test/compilable/test16747.d | 13 + gcc/testsuite/gdc.test/compilable/test16798.d | 13 + gcc/testsuite/gdc.test/compilable/test17057.d | 12 + gcc/testsuite/gdc.test/compilable/test17059.d | 11 + gcc/testsuite/gdc.test/compilable/test17130.d | 38 + gcc/testsuite/gdc.test/compilable/test17143.d | 4 + gcc/testsuite/gdc.test/compilable/test17168.d | 4 + gcc/testsuite/gdc.test/compilable/test17215.d | 9 + gcc/testsuite/gdc.test/compilable/test17339.d | 19 + gcc/testsuite/gdc.test/compilable/test17349.d | 30 + gcc/testsuite/gdc.test/compilable/test17352.d | 18 + gcc/testsuite/gdc.test/compilable/test17399.d | 18 + gcc/testsuite/gdc.test/compilable/test17419.d | 37 + gcc/testsuite/gdc.test/compilable/test17421.d | 19 + gcc/testsuite/gdc.test/compilable/test17468.d | 12 + gcc/testsuite/gdc.test/compilable/test1754.d | 9 + gcc/testsuite/gdc.test/compilable/test17545.d | 16 + gcc/testsuite/gdc.test/compilable/test17548.d | 12 + gcc/testsuite/gdc.test/compilable/test17590.d | 40 + gcc/testsuite/gdc.test/compilable/test1878a.d | 16 + gcc/testsuite/gdc.test/compilable/test25.d | 10 + gcc/testsuite/gdc.test/compilable/test2991.d | 12 + gcc/testsuite/gdc.test/compilable/test313a.d | 36 + gcc/testsuite/gdc.test/compilable/test313b.d | 6 + gcc/testsuite/gdc.test/compilable/test313c.d | 8 + gcc/testsuite/gdc.test/compilable/test313d.d | 9 + gcc/testsuite/gdc.test/compilable/test313e.d | 9 + gcc/testsuite/gdc.test/compilable/test313f.d | 7 + gcc/testsuite/gdc.test/compilable/test313g.d | 12 + gcc/testsuite/gdc.test/compilable/test314.d | 11 + gcc/testsuite/gdc.test/compilable/test3673.d | 48 + gcc/testsuite/gdc.test/compilable/test3775.d | 9 + gcc/testsuite/gdc.test/compilable/test4003.d | 6 + gcc/testsuite/gdc.test/compilable/test4090.d | 235 + gcc/testsuite/gdc.test/compilable/test4364.d | 8 + gcc/testsuite/gdc.test/compilable/test4375.d | 473 + gcc/testsuite/gdc.test/compilable/test50.d | 10 + gcc/testsuite/gdc.test/compilable/test5227.d | 124 + gcc/testsuite/gdc.test/compilable/test55.d | 20 + gcc/testsuite/gdc.test/compilable/test59.d | 4 + gcc/testsuite/gdc.test/compilable/test6013.d | 9 + gcc/testsuite/gdc.test/compilable/test602.d | 412 + gcc/testsuite/gdc.test/compilable/test6056a.d | 3 + gcc/testsuite/gdc.test/compilable/test6056b.d | 5 + gcc/testsuite/gdc.test/compilable/test6056c.d | 3 + gcc/testsuite/gdc.test/compilable/test6089.d | 6 + gcc/testsuite/gdc.test/compilable/test61.d | 15 + gcc/testsuite/gdc.test/compilable/test62.d | 7 + gcc/testsuite/gdc.test/compilable/test63.d | 7 + gcc/testsuite/gdc.test/compilable/test6319.d | 13 + gcc/testsuite/gdc.test/compilable/test6395.d | 7 + gcc/testsuite/gdc.test/compilable/test6534.d | 39 + gcc/testsuite/gdc.test/compilable/test6552.d | 26 + gcc/testsuite/gdc.test/compilable/test66.d | 21 + gcc/testsuite/gdc.test/compilable/test67.d | 12 + gcc/testsuite/gdc.test/compilable/test68.d | 19 + gcc/testsuite/gdc.test/compilable/test69.d | 54 + gcc/testsuite/gdc.test/compilable/test6999.d | 29 + gcc/testsuite/gdc.test/compilable/test70.d | 10 + gcc/testsuite/gdc.test/compilable/test7065.d | 38 + gcc/testsuite/gdc.test/compilable/test71.d | 6 + gcc/testsuite/gdc.test/compilable/test7172.d | 23 + gcc/testsuite/gdc.test/compilable/test7190.d | 8 + gcc/testsuite/gdc.test/compilable/test72.d | 8 + gcc/testsuite/gdc.test/compilable/test7252.d | 10 + gcc/testsuite/gdc.test/compilable/test7399.d | 6 + gcc/testsuite/gdc.test/compilable/test7491.d | 53 + gcc/testsuite/gdc.test/compilable/test7524.d | 3 + gcc/testsuite/gdc.test/compilable/test7569.d | 9 + gcc/testsuite/gdc.test/compilable/test7754.d | 14 + gcc/testsuite/gdc.test/compilable/test8038.d | 13 + gcc/testsuite/gdc.test/compilable/test8041.d | 10 + gcc/testsuite/gdc.test/compilable/test8296.d | 33 + gcc/testsuite/gdc.test/compilable/test8509.d | 11 + gcc/testsuite/gdc.test/compilable/test8513.d | 32 + gcc/testsuite/gdc.test/compilable/test8543.d | 32 + gcc/testsuite/gdc.test/compilable/test8631.d | 12 + gcc/testsuite/gdc.test/compilable/test8675.d | 17 + gcc/testsuite/gdc.test/compilable/test8696.d | 14 + gcc/testsuite/gdc.test/compilable/test8717.d | 63 + gcc/testsuite/gdc.test/compilable/test8802.d | 39 + gcc/testsuite/gdc.test/compilable/test8898.d | 11 + gcc/testsuite/gdc.test/compilable/test8922a.d | 9 + gcc/testsuite/gdc.test/compilable/test8922b.d | 9 + gcc/testsuite/gdc.test/compilable/test8922c.d | 10 + gcc/testsuite/gdc.test/compilable/test8922d.d | 10 + gcc/testsuite/gdc.test/compilable/test8922e.d | 11 + gcc/testsuite/gdc.test/compilable/test8922f.d | 10 + gcc/testsuite/gdc.test/compilable/test8937.d | 60 + gcc/testsuite/gdc.test/compilable/test8959.d | 55 + gcc/testsuite/gdc.test/compilable/test9057.d | 20 + gcc/testsuite/gdc.test/compilable/test9209.d | 16 + gcc/testsuite/gdc.test/compilable/test9276.d | 6 + gcc/testsuite/gdc.test/compilable/test9278a.d | 16 + gcc/testsuite/gdc.test/compilable/test9278b.d | 16 + gcc/testsuite/gdc.test/compilable/test9399.d | 10 + gcc/testsuite/gdc.test/compilable/test9434.d | 19 + gcc/testsuite/gdc.test/compilable/test9435.d | 17 + gcc/testsuite/gdc.test/compilable/test9436.d | 5 + gcc/testsuite/gdc.test/compilable/test9526.d | 21 + gcc/testsuite/gdc.test/compilable/test9554.d | 22 + gcc/testsuite/gdc.test/compilable/test9565.d | 86 + gcc/testsuite/gdc.test/compilable/test9570.d | 59 + gcc/testsuite/gdc.test/compilable/test9613.d | 32 + gcc/testsuite/gdc.test/compilable/test9639.d | 19 + gcc/testsuite/gdc.test/compilable/test9672.d | 7 + gcc/testsuite/gdc.test/compilable/test9692.d | 7 + gcc/testsuite/gdc.test/compilable/test9692a.d | 2 + gcc/testsuite/gdc.test/compilable/test9766.d | 77 + gcc/testsuite/gdc.test/compilable/test9818.d | 76 + gcc/testsuite/gdc.test/compilable/test9919.d | 9 + gcc/testsuite/gdc.test/compilable/testDIP37.d | 42 + .../gdc.test/compilable/testDIP37_10302.d | 8 + .../gdc.test/compilable/testDIP37_10354.d | 12 + .../gdc.test/compilable/testDIP37_10421.d | 7 + .../gdc.test/compilable/testDIP37a.d | 8 + gcc/testsuite/gdc.test/compilable/testDIP42.d | 97 + .../gdc.test/compilable/testInference.d | 817 + gcc/testsuite/gdc.test/compilable/testVRP.d | 331 + .../gdc.test/compilable/testcheckimports.d | 33 + .../gdc.test/compilable/testcontracts.d | 174 + .../gdc.test/compilable/testexpression.d | 121 + gcc/testsuite/gdc.test/compilable/testfptr.d | 423 + .../gdc.test/compilable/testfwdref.d | 716 + .../gdc.test/compilable/testheader1.d | 6 + .../gdc.test/compilable/testheader12567a.d | 7 + .../gdc.test/compilable/testheader12567b.d | 7 + .../gdc.test/compilable/testheader1i.d | 6 + .../gdc.test/compilable/testheader2.d | 6 + .../gdc.test/compilable/testheader2i.d | 6 + .../gdc.test/compilable/testheader3.d | 8 + .../gdc.test/compilable/testheaderudamodule.d | 13 + .../gdc.test/compilable/testimport12242.d | 26 + gcc/testsuite/gdc.test/compilable/testparse.d | 168 + .../gdc.test/compilable/testpostblit.d | 17 + .../gdc.test/compilable/testprofile.d | 23 + gcc/testsuite/gdc.test/compilable/uda.d | 7 + .../gdc.test/compilable/udamodule1.d | 11 + .../gdc.test/compilable/udamodule2.d | 5 + .../gdc.test/compilable/verrors_spec.d | 14 + gcc/testsuite/gdc.test/compilable/vgc1.d | 87 + gcc/testsuite/gdc.test/compilable/vgc2.d | 104 + gcc/testsuite/gdc.test/compilable/vgc3.d | 68 + gcc/testsuite/gdc.test/compilable/warn3882.d | 84 + .../gdc.test/fail_compilation/aacmp10381.d | 13 + .../gdc.test/fail_compilation/b3841.d | 78 + .../gdc.test/fail_compilation/bug4283.d | 12 + .../gdc.test/fail_compilation/bug5.d | 8 + .../gdc.test/fail_compilation/bug5b.d | 6 + .../gdc.test/fail_compilation/bug8150a.d | 13 + .../gdc.test/fail_compilation/bug8150b.d | 13 + .../gdc.test/fail_compilation/bug8891.d | 22 + .../fail_compilation/checkimports1a.d | 20 + .../fail_compilation/checkimports1b.d | 20 + .../fail_compilation/checkimports1c.d | 20 + .../fail_compilation/checkimports2a.d | 37 + .../fail_compilation/checkimports2b.d | 38 + .../fail_compilation/checkimports2c.d | 39 + .../gdc.test/fail_compilation/checkimports3.d | 15 + .../gdc.test/fail_compilation/circ10280.d | 12 + .../gdc.test/fail_compilation/class1.d | 12 + .../gdc.test/fail_compilation/class2.d | 12 + .../gdc.test/fail_compilation/commaexp.d | 43 + .../gdc.test/fail_compilation/cppeh1.d | 30 + .../gdc.test/fail_compilation/cppeh2.d | 33 + .../gdc.test/fail_compilation/ctfe10989.d | 36 + .../gdc.test/fail_compilation/ctfe10995.d | 25 + .../gdc.test/fail_compilation/ctfe11467.d | 52 + .../gdc.test/fail_compilation/ctfe13612.d | 23 + .../gdc.test/fail_compilation/ctfe14207.d | 22 + .../gdc.test/fail_compilation/ctfe14465.d | 22 + .../gdc.test/fail_compilation/ctfe14731.d | 18 + .../gdc.test/fail_compilation/cwords.d | 17 + .../gdc.test/fail_compilation/depmsg.d | 106 + .../gdc.test/fail_compilation/depmsg15814.d | 9 + .../gdc.test/fail_compilation/depmsg15815.d | 23 + .../fail_compilation/deprecate12979a.d | 18 + .../fail_compilation/deprecate12979b.d | 17 + .../fail_compilation/deprecate12979c.d | 17 + .../fail_compilation/deprecate12979d.d | 16 + .../gdc.test/fail_compilation/deprecate1553.d | 20 + .../fail_compilation/deprecated6760.d | 20 + .../gdc.test/fail_compilation/diag10089.d | 18 + .../gdc.test/fail_compilation/diag10099.d | 16 + .../gdc.test/fail_compilation/diag10141.d | 14 + .../gdc.test/fail_compilation/diag10169.d | 13 + .../gdc.test/fail_compilation/diag10221.d | 11 + .../gdc.test/fail_compilation/diag10221a.d | 11 + .../gdc.test/fail_compilation/diag10319.d | 27 + .../gdc.test/fail_compilation/diag10327.d | 1 + .../gdc.test/fail_compilation/diag10359.d | 11 + .../gdc.test/fail_compilation/diag10405.d | 11 + .../gdc.test/fail_compilation/diag10415.d | 40 + .../gdc.test/fail_compilation/diag10688.d | 15 + .../gdc.test/fail_compilation/diag10768.d | 42 + .../gdc.test/fail_compilation/diag10783.d | 18 + .../gdc.test/fail_compilation/diag10792.d | 8 + .../gdc.test/fail_compilation/diag10805.d | 13 + .../gdc.test/fail_compilation/diag10862.d | 90 + .../gdc.test/fail_compilation/diag10926.d | 12 + .../gdc.test/fail_compilation/diag10984.d | 16 + .../gdc.test/fail_compilation/diag11078.d | 20 + .../gdc.test/fail_compilation/diag11132.d | 23 + .../gdc.test/fail_compilation/diag11198.d | 13 + .../gdc.test/fail_compilation/diag11423.d | 10 + .../gdc.test/fail_compilation/diag11425.d | 15 + .../gdc.test/fail_compilation/diag11727.d | 39 + .../gdc.test/fail_compilation/diag11756.d | 39 + .../gdc.test/fail_compilation/diag11759.d | 8 + .../gdc.test/fail_compilation/diag11769.d | 19 + .../gdc.test/fail_compilation/diag11819a.d | 51 + .../gdc.test/fail_compilation/diag11819b.d | 47 + .../gdc.test/fail_compilation/diag11840.d | 13 + .../gdc.test/fail_compilation/diag12063.d | 15 + .../gdc.test/fail_compilation/diag12124.d | 21 + .../gdc.test/fail_compilation/diag12280.d | 18 + .../gdc.test/fail_compilation/diag12312.d | 11 + .../gdc.test/fail_compilation/diag12380.d | 13 + .../gdc.test/fail_compilation/diag12432.d | 61 + .../gdc.test/fail_compilation/diag12480.d | 12 + .../gdc.test/fail_compilation/diag12487.d | 28 + .../gdc.test/fail_compilation/diag12598.d | 22 + .../gdc.test/fail_compilation/diag12640.d | 30 + .../gdc.test/fail_compilation/diag12678.d | 27 + .../gdc.test/fail_compilation/diag12777.d | 23 + .../gdc.test/fail_compilation/diag12829.d | 37 + .../gdc.test/fail_compilation/diag13028.d | 30 + .../gdc.test/fail_compilation/diag13082.d | 24 + .../gdc.test/fail_compilation/diag13142.d | 27 + .../gdc.test/fail_compilation/diag13281.d | 32 + .../gdc.test/fail_compilation/diag13320.d | 14 + .../gdc.test/fail_compilation/diag13333.d | 40 + .../gdc.test/fail_compilation/diag13528.d | 25 + .../gdc.test/fail_compilation/diag13609a.d | 10 + .../gdc.test/fail_compilation/diag13609b.d | 10 + .../gdc.test/fail_compilation/diag13787.d | 14 + .../gdc.test/fail_compilation/diag13884.d | 34 + .../gdc.test/fail_compilation/diag13942.d | 27 + .../gdc.test/fail_compilation/diag14102.d | 18 + .../gdc.test/fail_compilation/diag14163.d | 19 + .../gdc.test/fail_compilation/diag14235.d | 13 + .../gdc.test/fail_compilation/diag14818.d | 37 + .../gdc.test/fail_compilation/diag14875.d | 76 + .../gdc.test/fail_compilation/diag14876.d | 25 + .../gdc.test/fail_compilation/diag15001.d | 14 + .../gdc.test/fail_compilation/diag15186.d | 16 + .../gdc.test/fail_compilation/diag15209.d | 22 + .../gdc.test/fail_compilation/diag15340.d | 13 + .../gdc.test/fail_compilation/diag15411.d | 15 + .../gdc.test/fail_compilation/diag1566.d | 30 + .../gdc.test/fail_compilation/diag15669.d | 15 + .../gdc.test/fail_compilation/diag15713.d | 49 + .../gdc.test/fail_compilation/diag15974.d | 28 + .../gdc.test/fail_compilation/diag16499.d | 25 + .../gdc.test/fail_compilation/diag16977.d | 31 + .../gdc.test/fail_compilation/diag1730.d | 90 + .../gdc.test/fail_compilation/diag2452.d | 17 + .../gdc.test/fail_compilation/diag3013.d | 12 + .../gdc.test/fail_compilation/diag3438.d | 21 + .../gdc.test/fail_compilation/diag3438b.d | 9 + .../gdc.test/fail_compilation/diag3672.d | 57 + .../gdc.test/fail_compilation/diag3672a.d | 34 + .../gdc.test/fail_compilation/diag3673.d | 9 + .../gdc.test/fail_compilation/diag3869.d | 13 + .../gdc.test/fail_compilation/diag3913.d | 14 + .../gdc.test/fail_compilation/diag4479.d | 11 + .../gdc.test/fail_compilation/diag4528.d | 19 + .../gdc.test/fail_compilation/diag4540.d | 15 + .../gdc.test/fail_compilation/diag4596.d | 21 + .../gdc.test/fail_compilation/diag5385.d | 35 + .../gdc.test/fail_compilation/diag5450.d | 20 + .../gdc.test/fail_compilation/diag6373.d | 20 + .../gdc.test/fail_compilation/diag6539.d | 23 + .../gdc.test/fail_compilation/diag6677.d | 28 + .../gdc.test/fail_compilation/diag6699.d | 19 + .../gdc.test/fail_compilation/diag6707.d | 18 + .../gdc.test/fail_compilation/diag6717.d | 14 + .../gdc.test/fail_compilation/diag6796.d | 13 + .../gdc.test/fail_compilation/diag7050a.d | 15 + .../gdc.test/fail_compilation/diag7050b.d | 14 + .../gdc.test/fail_compilation/diag7050c.d | 21 + .../gdc.test/fail_compilation/diag7420.d | 24 + .../gdc.test/fail_compilation/diag7477.d | 22 + .../gdc.test/fail_compilation/diag7747.d | 13 + .../gdc.test/fail_compilation/diag7998.d | 10 + .../gdc.test/fail_compilation/diag8101.d | 63 + .../gdc.test/fail_compilation/diag8101b.d | 34 + .../gdc.test/fail_compilation/diag8178.d | 15 + .../gdc.test/fail_compilation/diag8318.d | 51 + .../gdc.test/fail_compilation/diag8425.d | 16 + .../gdc.test/fail_compilation/diag8510.d | 17 + .../gdc.test/fail_compilation/diag8559.d | 14 + .../gdc.test/fail_compilation/diag8648.d | 33 + .../gdc.test/fail_compilation/diag8697.d | 12 + .../gdc.test/fail_compilation/diag8714.d | 21 + .../gdc.test/fail_compilation/diag8777.d | 44 + .../gdc.test/fail_compilation/diag8787.d | 13 + .../gdc.test/fail_compilation/diag8825.d | 21 + .../gdc.test/fail_compilation/diag8892.d | 15 + .../gdc.test/fail_compilation/diag8894.d | 20 + .../gdc.test/fail_compilation/diag8928.d | 20 + .../gdc.test/fail_compilation/diag9004.d | 22 + .../gdc.test/fail_compilation/diag9148.d | 55 + .../gdc.test/fail_compilation/diag9191.d | 41 + .../gdc.test/fail_compilation/diag9210a.d | 12 + .../gdc.test/fail_compilation/diag9247.d | 12 + .../gdc.test/fail_compilation/diag9250.d | 24 + .../gdc.test/fail_compilation/diag9312.d | 13 + .../gdc.test/fail_compilation/diag9357.d | 20 + .../gdc.test/fail_compilation/diag9358.d | 18 + .../gdc.test/fail_compilation/diag9398.d | 12 + .../gdc.test/fail_compilation/diag9420.d | 21 + .../gdc.test/fail_compilation/diag9451.d | 27 + .../gdc.test/fail_compilation/diag9479.d | 11 + .../gdc.test/fail_compilation/diag9574.d | 19 + .../gdc.test/fail_compilation/diag9620.d | 21 + .../gdc.test/fail_compilation/diag9635.d | 20 + .../gdc.test/fail_compilation/diag9679.d | 13 + .../gdc.test/fail_compilation/diag9765.d | 10 + .../gdc.test/fail_compilation/diag9831.d | 13 + .../gdc.test/fail_compilation/diag9861.d | 9 + .../gdc.test/fail_compilation/diag9880.d | 9 + .../gdc.test/fail_compilation/diag9961.d | 16 + .../gdc.test/fail_compilation/diag_cstyle.d | 21 + .../gdc.test/fail_compilation/diag_err1.d | 25 + .../gdc.test/fail_compilation/dip22a.d | 26 + .../gdc.test/fail_compilation/dip22b.d | 12 + .../gdc.test/fail_compilation/dip22d.d | 12 + .../gdc.test/fail_compilation/dip22e.d | 18 + .../gdc.test/fail_compilation/disable.d | 77 + .../gdc.test/fail_compilation/enum9921.d | 11 + .../fail_compilation/extra-files/a14446.d | 6 + .../fail_compilation/extra-files/bar11453.d | 1 + .../fail_compilation/extra-files/foo11453.d | 1 + .../gdc.test/fail_compilation/fail10.d | 19 + .../gdc.test/fail_compilation/fail100.d | 38 + .../gdc.test/fail_compilation/fail10082.d | 25 + .../gdc.test/fail_compilation/fail101.d | 8 + .../gdc.test/fail_compilation/fail10102.d | 52 + .../gdc.test/fail_compilation/fail10115.d | 48 + .../gdc.test/fail_compilation/fail10207.d | 7 + .../gdc.test/fail_compilation/fail10254.d | 20 + .../gdc.test/fail_compilation/fail10277.d | 29 + .../gdc.test/fail_compilation/fail10285.d | 10 + .../gdc.test/fail_compilation/fail10299.d | 11 + .../gdc.test/fail_compilation/fail10346.d | 14 + .../gdc.test/fail_compilation/fail104.d | 25 + .../gdc.test/fail_compilation/fail10481.d | 16 + .../gdc.test/fail_compilation/fail105.d | 11 + .../gdc.test/fail_compilation/fail10528.d | 34 + .../gdc.test/fail_compilation/fail10534.d | 41 + .../gdc.test/fail_compilation/fail106.d | 13 + .../gdc.test/fail_compilation/fail10630.d | 12 + .../gdc.test/fail_compilation/fail10666.d | 22 + .../gdc.test/fail_compilation/fail109.d | 92 + .../gdc.test/fail_compilation/fail10905.d | 16 + .../gdc.test/fail_compilation/fail10947.d | 31 + .../gdc.test/fail_compilation/fail10964.d | 36 + .../gdc.test/fail_compilation/fail10968.d | 74 + .../gdc.test/fail_compilation/fail10980.d | 44 + .../gdc.test/fail_compilation/fail11.d | 14 + .../gdc.test/fail_compilation/fail110.d | 19 + .../gdc.test/fail_compilation/fail11042.d | 9 + .../gdc.test/fail_compilation/fail111.d | 17 + .../gdc.test/fail_compilation/fail11125.d | 22 + .../gdc.test/fail_compilation/fail11151.d | 36 + .../gdc.test/fail_compilation/fail11163.d | 15 + .../gdc.test/fail_compilation/fail11169.d | 28 + .../gdc.test/fail_compilation/fail113.d | 10 + .../gdc.test/fail_compilation/fail11355.d | 29 + .../gdc.test/fail_compilation/fail11375.d | 18 + .../gdc.test/fail_compilation/fail114.d | 12 + .../gdc.test/fail_compilation/fail11426.d | 20 + .../gdc.test/fail_compilation/fail11445.d | 12 + .../gdc.test/fail_compilation/fail11453a.d | 10 + .../gdc.test/fail_compilation/fail11453b.d | 10 + .../gdc.test/fail_compilation/fail115.d | 11 + .../gdc.test/fail_compilation/fail11503a.d | 21 + .../gdc.test/fail_compilation/fail11503b.d | 13 + .../gdc.test/fail_compilation/fail11503c.d | 15 + .../gdc.test/fail_compilation/fail11503d.d | 22 + .../gdc.test/fail_compilation/fail11510.d | 40 + .../gdc.test/fail_compilation/fail11532.d | 21 + .../gdc.test/fail_compilation/fail11542.d | 73 + .../gdc.test/fail_compilation/fail11545.d | 20 + .../gdc.test/fail_compilation/fail11552.d | 13 + .../gdc.test/fail_compilation/fail11562.d | 67 + .../gdc.test/fail_compilation/fail11591b.d | 34 + .../gdc.test/fail_compilation/fail116.d | 16 + .../gdc.test/fail_compilation/fail11653.d | 27 + .../gdc.test/fail_compilation/fail117.d | 37 + .../gdc.test/fail_compilation/fail11717.d | 14 + .../gdc.test/fail_compilation/fail11720.d | 33 + .../gdc.test/fail_compilation/fail11746.d | 27 + .../gdc.test/fail_compilation/fail11748.d | 13 + .../gdc.test/fail_compilation/fail11751.d | 10 + .../gdc.test/fail_compilation/fail118.d | 28 + .../gdc.test/fail_compilation/fail12.d | 13 + .../gdc.test/fail_compilation/fail120.d | 14 + .../gdc.test/fail_compilation/fail12047.d | 21 + .../gdc.test/fail_compilation/fail121.d | 17 + .../gdc.test/fail_compilation/fail122.d | 14 + .../gdc.test/fail_compilation/fail12236.d | 33 + .../gdc.test/fail_compilation/fail12255.d | 139 + .../gdc.test/fail_compilation/fail123.d | 17 + .../gdc.test/fail_compilation/fail12378.d | 145 + .../gdc.test/fail_compilation/fail12390.d | 15 + .../gdc.test/fail_compilation/fail124.d | 24 + .../gdc.test/fail_compilation/fail12436.d | 77 + .../gdc.test/fail_compilation/fail12485.d | 11 + .../gdc.test/fail_compilation/fail125.d | 26 + .../gdc.test/fail_compilation/fail12567.d | 8 + .../gdc.test/fail_compilation/fail126.d | 10 + .../gdc.test/fail_compilation/fail12604.d | 79 + .../gdc.test/fail_compilation/fail12622.d | 30 + .../gdc.test/fail_compilation/fail12635.d | 21 + .../gdc.test/fail_compilation/fail12636.d | 24 + .../gdc.test/fail_compilation/fail127.d | 10 + .../gdc.test/fail_compilation/fail12744.d | 69 + .../gdc.test/fail_compilation/fail12749.d | 62 + .../gdc.test/fail_compilation/fail12809.d | 80 + .../gdc.test/fail_compilation/fail129.d | 14 + .../gdc.test/fail_compilation/fail12901.d | 14 + .../gdc.test/fail_compilation/fail12908.d | 16 + .../gdc.test/fail_compilation/fail12932.d | 19 + .../gdc.test/fail_compilation/fail13064.d | 8 + .../gdc.test/fail_compilation/fail131.d | 11 + .../gdc.test/fail_compilation/fail13116.d | 29 + .../gdc.test/fail_compilation/fail13120.d | 35 + .../gdc.test/fail_compilation/fail13187.d | 13 + .../gdc.test/fail_compilation/fail132.d | 20 + .../gdc.test/fail_compilation/fail13203.d | 45 + .../gdc.test/fail_compilation/fail133.d | 16 + .../gdc.test/fail_compilation/fail13336a.d | 29 + .../gdc.test/fail_compilation/fail13336b.d | 31 + .../gdc.test/fail_compilation/fail134.d | 14 + .../gdc.test/fail_compilation/fail13424.d | 23 + .../gdc.test/fail_compilation/fail13434_m32.d | 14 + .../gdc.test/fail_compilation/fail13434_m64.d | 14 + .../gdc.test/fail_compilation/fail13498.d | 17 + .../gdc.test/fail_compilation/fail13574.d | 29 + .../gdc.test/fail_compilation/fail136.d | 11 + .../gdc.test/fail_compilation/fail13601.d | 17 + .../gdc.test/fail_compilation/fail137.d | 23 + .../gdc.test/fail_compilation/fail13701.d | 25 + .../gdc.test/fail_compilation/fail13756.d | 14 + .../gdc.test/fail_compilation/fail13775.d | 21 + .../gdc.test/fail_compilation/fail139.d | 15 + .../gdc.test/fail_compilation/fail13902.d | 337 + .../gdc.test/fail_compilation/fail13938.d | 16 + .../gdc.test/fail_compilation/fail13939.d | 17 + .../gdc.test/fail_compilation/fail14.d | 11 + .../gdc.test/fail_compilation/fail14009.d | 14 + .../gdc.test/fail_compilation/fail14089.d | 46 + .../gdc.test/fail_compilation/fail142.d | 21 + .../gdc.test/fail_compilation/fail14249.d | 40 + .../gdc.test/fail_compilation/fail143.d | 36 + .../gdc.test/fail_compilation/fail14304.d | 70 + .../gdc.test/fail_compilation/fail144.d | 30 + .../gdc.test/fail_compilation/fail14406.d | 26 + .../gdc.test/fail_compilation/fail14407.d | 47 + .../gdc.test/fail_compilation/fail14416.d | 13 + .../gdc.test/fail_compilation/fail14486.d | 149 + .../gdc.test/fail_compilation/fail145.d | 30 + .../gdc.test/fail_compilation/fail14554.d | 30 + .../gdc.test/fail_compilation/fail14669.d | 43 + .../gdc.test/fail_compilation/fail14965.d | 38 + .../gdc.test/fail_compilation/fail15.d | 21 + .../gdc.test/fail_compilation/fail150.d | 24 + .../gdc.test/fail_compilation/fail15044.d | 32 + .../gdc.test/fail_compilation/fail15089.d | 10 + .../gdc.test/fail_compilation/fail152.d | 29 + .../gdc.test/fail_compilation/fail15292.d | 28 + .../gdc.test/fail_compilation/fail153.d | 10 + .../gdc.test/fail_compilation/fail154.d | 18 + .../gdc.test/fail_compilation/fail155.d | 19 + .../gdc.test/fail_compilation/fail15535.d | 22 + .../gdc.test/fail_compilation/fail15550.d | 27 + .../gdc.test/fail_compilation/fail156.d | 46 + .../gdc.test/fail_compilation/fail15616a.d | 42 + .../gdc.test/fail_compilation/fail15616b.d | 44 + .../gdc.test/fail_compilation/fail15626.d | 16 + .../gdc.test/fail_compilation/fail15667.d | 13 + .../gdc.test/fail_compilation/fail158.d | 18 + .../gdc.test/fail_compilation/fail159.d | 25 + .../gdc.test/fail_compilation/fail16.d | 20 + .../gdc.test/fail_compilation/fail160.d | 26 + .../gdc.test/fail_compilation/fail161.d | 17 + .../gdc.test/fail_compilation/fail162.d | 32 + .../gdc.test/fail_compilation/fail163.d | 90 + .../gdc.test/fail_compilation/fail16600.d | 26 + .../gdc.test/fail_compilation/fail169.d | 8 + .../gdc.test/fail_compilation/fail17.d | 8 + .../gdc.test/fail_compilation/fail170.d | 8 + .../gdc.test/fail_compilation/fail172.d | 32 + .../gdc.test/fail_compilation/fail17275.d | 20 + .../gdc.test/fail_compilation/fail17354.d | 19 + .../gdc.test/fail_compilation/fail17419.d | 12 + .../gdc.test/fail_compilation/fail17421.d | 16 + .../gdc.test/fail_compilation/fail17491.d | 41 + .../gdc.test/fail_compilation/fail17492.d | 23 + .../gdc.test/fail_compilation/fail17502.d | 19 + .../gdc.test/fail_compilation/fail176.d | 20 + .../gdc.test/fail_compilation/fail17612.d | 17 + .../gdc.test/fail_compilation/fail17646.d | 19 + .../gdc.test/fail_compilation/fail17689.d | 11 + .../gdc.test/fail_compilation/fail177.d | 31 + .../gdc.test/fail_compilation/fail17722a.d | 13 + .../gdc.test/fail_compilation/fail17722b.d | 13 + .../gdc.test/fail_compilation/fail179.d | 15 + .../gdc.test/fail_compilation/fail18.d | 15 + .../gdc.test/fail_compilation/fail180.d | 65 + .../gdc.test/fail_compilation/fail183.d | 11 + .../gdc.test/fail_compilation/fail184.d | 8 + .../gdc.test/fail_compilation/fail185.d | 13 + .../gdc.test/fail_compilation/fail187.d | 28 + .../gdc.test/fail_compilation/fail188.d | 16 + .../gdc.test/fail_compilation/fail189.d | 14 + .../gdc.test/fail_compilation/fail190.d | 18 + .../gdc.test/fail_compilation/fail1900.d | 66 + .../gdc.test/fail_compilation/fail192.d | 27 + .../gdc.test/fail_compilation/fail193.d | 16 + .../gdc.test/fail_compilation/fail194.d | 19 + .../gdc.test/fail_compilation/fail195.d | 23 + .../gdc.test/fail_compilation/fail196.d | 21 + .../gdc.test/fail_compilation/fail198.d | 8 + .../gdc.test/fail_compilation/fail199.d | 13 + .../gdc.test/fail_compilation/fail20.d | 19 + .../gdc.test/fail_compilation/fail200.d | 16 + .../gdc.test/fail_compilation/fail201.d | 5 + .../gdc.test/fail_compilation/fail202.d | 5 + .../gdc.test/fail_compilation/fail203.d | 5 + .../gdc.test/fail_compilation/fail204.d | 5 + .../gdc.test/fail_compilation/fail205.d | 5 + .../gdc.test/fail_compilation/fail206.d | 5 + .../gdc.test/fail_compilation/fail207.d | 9 + .../gdc.test/fail_compilation/fail208.d | 21 + .../gdc.test/fail_compilation/fail209.d | 21 + .../gdc.test/fail_compilation/fail212.d | 17 + .../gdc.test/fail_compilation/fail213.d | 27 + .../gdc.test/fail_compilation/fail215.d | 11 + .../gdc.test/fail_compilation/fail216.d | 19 + .../gdc.test/fail_compilation/fail217.d | 18 + .../gdc.test/fail_compilation/fail218.d | 16 + .../gdc.test/fail_compilation/fail22.d | 14 + .../gdc.test/fail_compilation/fail220.d | 8 + .../gdc.test/fail_compilation/fail221.d | 12 + .../gdc.test/fail_compilation/fail222.d | 20 + .../gdc.test/fail_compilation/fail223.d | 25 + .../gdc.test/fail_compilation/fail224.d | 36 + .../gdc.test/fail_compilation/fail225.d | 10 + .../gdc.test/fail_compilation/fail228.d | 23 + .../gdc.test/fail_compilation/fail229.d | 11 + .../gdc.test/fail_compilation/fail23.d | 19 + .../gdc.test/fail_compilation/fail231.d | 17 + .../gdc.test/fail_compilation/fail232.d | 7 + .../gdc.test/fail_compilation/fail233.d | 12 + .../gdc.test/fail_compilation/fail235.d | 24 + .../gdc.test/fail_compilation/fail2350.d | 15 + .../gdc.test/fail_compilation/fail236.d | 23 + .../gdc.test/fail_compilation/fail2361.d | 14 + .../gdc.test/fail_compilation/fail237.d | 11 + .../gdc.test/fail_compilation/fail238_m32.d | 36 + .../gdc.test/fail_compilation/fail238_m64.d | 36 + .../gdc.test/fail_compilation/fail239.d | 2 + .../gdc.test/fail_compilation/fail24.d | 19 + .../gdc.test/fail_compilation/fail240.d | 9 + .../gdc.test/fail_compilation/fail241.d | 19 + .../gdc.test/fail_compilation/fail243.d | 28 + .../gdc.test/fail_compilation/fail244.d | 39 + .../gdc.test/fail_compilation/fail245.d | 39 + .../gdc.test/fail_compilation/fail246.d | 12 + .../gdc.test/fail_compilation/fail247.d | 9 + .../gdc.test/fail_compilation/fail248.d | 9 + .../gdc.test/fail_compilation/fail249.d | 20 + .../gdc.test/fail_compilation/fail25.d | 16 + .../gdc.test/fail_compilation/fail250.d | 16 + .../gdc.test/fail_compilation/fail251.d | 16 + .../gdc.test/fail_compilation/fail252.d | 10 + .../gdc.test/fail_compilation/fail253.d | 19 + .../gdc.test/fail_compilation/fail254.d | 16 + .../gdc.test/fail_compilation/fail256.d | 8 + .../gdc.test/fail_compilation/fail257.d | 1 + .../gdc.test/fail_compilation/fail258.d | 5 + .../gdc.test/fail_compilation/fail259.d | 13 + .../gdc.test/fail_compilation/fail261.d | 22 + .../gdc.test/fail_compilation/fail262.d | 34 + .../gdc.test/fail_compilation/fail263.d | 19 + .../gdc.test/fail_compilation/fail264.d | 16 + .../gdc.test/fail_compilation/fail265.d | 11 + .../gdc.test/fail_compilation/fail2656.d | 34 + .../gdc.test/fail_compilation/fail267.d | 15 + .../gdc.test/fail_compilation/fail27.d | 22 + .../gdc.test/fail_compilation/fail270.d | 14 + .../gdc.test/fail_compilation/fail272.d | 10 + .../gdc.test/fail_compilation/fail273.d | 13 + .../gdc.test/fail_compilation/fail274.d | 11 + .../gdc.test/fail_compilation/fail2740.d | 15 + .../gdc.test/fail_compilation/fail275.d | 11 + .../gdc.test/fail_compilation/fail276.d | 19 + .../gdc.test/fail_compilation/fail278.d | 13 + .../gdc.test/fail_compilation/fail279.d | 8 + .../gdc.test/fail_compilation/fail280.d | 12 + .../gdc.test/fail_compilation/fail281.d | 18 + .../gdc.test/fail_compilation/fail282.d | 18 + .../gdc.test/fail_compilation/fail284.d | 20 + .../gdc.test/fail_compilation/fail285.d | 21 + .../gdc.test/fail_compilation/fail287.d | 20 + .../gdc.test/fail_compilation/fail288.d | 17 + .../gdc.test/fail_compilation/fail289.d | 13 + .../gdc.test/fail_compilation/fail290.d | 16 + .../gdc.test/fail_compilation/fail291.d | 9 + .../gdc.test/fail_compilation/fail296.d | 10 + .../gdc.test/fail_compilation/fail2962.d | 41 + .../gdc.test/fail_compilation/fail297.d | 31 + .../gdc.test/fail_compilation/fail298.d | 13 + .../gdc.test/fail_compilation/fail299.d | 15 + .../gdc.test/fail_compilation/fail3.d | 43 + .../gdc.test/fail_compilation/fail301.d | 23 + .../gdc.test/fail_compilation/fail302.d | 23 + .../gdc.test/fail_compilation/fail303.d | 26 + .../gdc.test/fail_compilation/fail304.d | 16 + .../gdc.test/fail_compilation/fail305.d | 11 + .../gdc.test/fail_compilation/fail306.d | 12 + .../gdc.test/fail_compilation/fail307.d | 12 + .../gdc.test/fail_compilation/fail308.d | 15 + .../gdc.test/fail_compilation/fail309.d | 11 + .../gdc.test/fail_compilation/fail310.d | 14 + .../gdc.test/fail_compilation/fail311.d | 26 + .../gdc.test/fail_compilation/fail312.d | 15 + .../gdc.test/fail_compilation/fail313.d | 31 + .../gdc.test/fail_compilation/fail314.d | 12 + .../gdc.test/fail_compilation/fail3144.d | 16 + .../gdc.test/fail_compilation/fail315.d | 22 + .../gdc.test/fail_compilation/fail3150.d | 5 + .../gdc.test/fail_compilation/fail316.d | 17 + .../gdc.test/fail_compilation/fail317.d | 13 + .../gdc.test/fail_compilation/fail318.d | 8 + .../gdc.test/fail_compilation/fail319.d | 14 + .../gdc.test/fail_compilation/fail320.d | 10 + .../gdc.test/fail_compilation/fail322.d | 17 + .../gdc.test/fail_compilation/fail324.d | 17 + .../gdc.test/fail_compilation/fail325.d | 13 + .../gdc.test/fail_compilation/fail327.d | 17 + .../gdc.test/fail_compilation/fail328.d | 13 + .../gdc.test/fail_compilation/fail329.d | 63 + .../gdc.test/fail_compilation/fail3290.d | 9 + .../gdc.test/fail_compilation/fail330.d | 10 + .../gdc.test/fail_compilation/fail331.d | 12 + .../gdc.test/fail_compilation/fail332.d | 15 + .../gdc.test/fail_compilation/fail333.d | 8 + .../gdc.test/fail_compilation/fail334.d | 11 + .../gdc.test/fail_compilation/fail335.d | 14 + .../gdc.test/fail_compilation/fail3354.d | 12 + .../gdc.test/fail_compilation/fail336.d | 16 + .../gdc.test/fail_compilation/fail337.d | 42 + .../gdc.test/fail_compilation/fail34.d | 42 + .../gdc.test/fail_compilation/fail340.d | 19 + .../gdc.test/fail_compilation/fail341.d | 28 + .../gdc.test/fail_compilation/fail343.d | 23 + .../gdc.test/fail_compilation/fail344.d | 17 + .../gdc.test/fail_compilation/fail346.d | 15 + .../gdc.test/fail_compilation/fail347.d | 24 + .../gdc.test/fail_compilation/fail349.d | 17 + .../gdc.test/fail_compilation/fail35.d | 17 + .../gdc.test/fail_compilation/fail351.d | 21 + .../gdc.test/fail_compilation/fail352.d | 19 + .../gdc.test/fail_compilation/fail353.d | 42 + .../gdc.test/fail_compilation/fail354.d | 13 + .../gdc.test/fail_compilation/fail355.d | 8 + .../gdc.test/fail_compilation/fail356a.d | 2 + .../gdc.test/fail_compilation/fail356b.d | 2 + .../gdc.test/fail_compilation/fail356c.d | 2 + .../gdc.test/fail_compilation/fail3581a.d | 5 + .../gdc.test/fail_compilation/fail3581b.d | 5 + .../gdc.test/fail_compilation/fail359.d | 3 + .../gdc.test/fail_compilation/fail36.d | 19 + .../gdc.test/fail_compilation/fail3672.d | 38 + .../gdc.test/fail_compilation/fail3673a.d | 2 + .../gdc.test/fail_compilation/fail3673b.d | 2 + .../gdc.test/fail_compilation/fail3703.d | 27 + .../gdc.test/fail_compilation/fail3731.d | 8 + .../gdc.test/fail_compilation/fail3753.d | 47 + .../gdc.test/fail_compilation/fail37_m32.d | 9 + .../gdc.test/fail_compilation/fail37_m64.d | 9 + .../gdc.test/fail_compilation/fail38.d | 19 + .../gdc.test/fail_compilation/fail3882.d | 48 + .../gdc.test/fail_compilation/fail3895.d | 9 + .../gdc.test/fail_compilation/fail39.d | 12 + .../gdc.test/fail_compilation/fail3990.d | 15 + .../gdc.test/fail_compilation/fail40.d | 12 + .../gdc.test/fail_compilation/fail4082.d | 34 + .../gdc.test/fail_compilation/fail41.d | 18 + .../gdc.test/fail_compilation/fail42.d | 23 + .../gdc.test/fail_compilation/fail4206.d | 5 + .../gdc.test/fail_compilation/fail4269a.d | 7 + .../gdc.test/fail_compilation/fail4269b.d | 7 + .../gdc.test/fail_compilation/fail4269c.d | 7 + .../gdc.test/fail_compilation/fail4269d.d | 5 + .../gdc.test/fail_compilation/fail4269e.d | 5 + .../gdc.test/fail_compilation/fail4269f.d | 5 + .../gdc.test/fail_compilation/fail4269g.d | 6 + .../gdc.test/fail_compilation/fail4374.d | 11 + .../gdc.test/fail_compilation/fail4375a.d | 11 + .../gdc.test/fail_compilation/fail4375b.d | 13 + .../gdc.test/fail_compilation/fail4375c.d | 13 + .../gdc.test/fail_compilation/fail4375d.d | 12 + .../gdc.test/fail_compilation/fail4375e.d | 11 + .../gdc.test/fail_compilation/fail4375f.d | 11 + .../gdc.test/fail_compilation/fail4375g.d | 11 + .../gdc.test/fail_compilation/fail4375h.d | 15 + .../gdc.test/fail_compilation/fail4375i.d | 13 + .../gdc.test/fail_compilation/fail4375j.d | 13 + .../gdc.test/fail_compilation/fail4375k.d | 13 + .../gdc.test/fail_compilation/fail4375l.d | 12 + .../gdc.test/fail_compilation/fail4375m.d | 13 + .../gdc.test/fail_compilation/fail4375o.d | 12 + .../gdc.test/fail_compilation/fail4375p.d | 15 + .../gdc.test/fail_compilation/fail4375q.d | 13 + .../gdc.test/fail_compilation/fail4375r.d | 14 + .../gdc.test/fail_compilation/fail4375s.d | 14 + .../gdc.test/fail_compilation/fail4375t.d | 11 + .../gdc.test/fail_compilation/fail4375u.d | 9 + .../gdc.test/fail_compilation/fail4375v.d | 9 + .../gdc.test/fail_compilation/fail4375w.d | 9 + .../gdc.test/fail_compilation/fail4375x.d | 10 + .../gdc.test/fail_compilation/fail4375y.d | 12 + .../gdc.test/fail_compilation/fail44.d | 21 + .../gdc.test/fail_compilation/fail4421.d | 40 + .../gdc.test/fail_compilation/fail4448.d | 26 + .../gdc.test/fail_compilation/fail45.d | 11 + .../gdc.test/fail_compilation/fail4510.d | 9 + .../gdc.test/fail_compilation/fail4511.d | 16 + .../gdc.test/fail_compilation/fail4517.d | 15 + .../gdc.test/fail_compilation/fail4559.d | 22 + .../gdc.test/fail_compilation/fail46.d | 21 + .../gdc.test/fail_compilation/fail4611.d | 15 + .../gdc.test/fail_compilation/fail47.d | 9 + .../gdc.test/fail_compilation/fail4958.d | 2 + .../gdc.test/fail_compilation/fail50.d | 13 + .../gdc.test/fail_compilation/fail51.d | 11 + .../gdc.test/fail_compilation/fail52.d | 10 + .../gdc.test/fail_compilation/fail53.d | 30 + .../gdc.test/fail_compilation/fail54.d | 23 + .../gdc.test/fail_compilation/fail5435.d | 13 + .../gdc.test/fail_compilation/fail55.d | 23 + .../gdc.test/fail_compilation/fail56.d | 21 + .../gdc.test/fail_compilation/fail5634.d | 3 + .../gdc.test/fail_compilation/fail57.d | 6 + .../gdc.test/fail_compilation/fail5733.d | 6 + .../gdc.test/fail_compilation/fail58.d | 27 + .../gdc.test/fail_compilation/fail5851.d | 10 + .../gdc.test/fail_compilation/fail59.d | 51 + .../gdc.test/fail_compilation/fail5953a1.d | 4 + .../gdc.test/fail_compilation/fail5953a2.d | 4 + .../gdc.test/fail_compilation/fail5953s1.d | 5 + .../gdc.test/fail_compilation/fail5953s2.d | 5 + .../gdc.test/fail_compilation/fail60.d | 10 + .../gdc.test/fail_compilation/fail6029.d | 15 + .../gdc.test/fail_compilation/fail61.d | 43 + .../gdc.test/fail_compilation/fail6107.d | 16 + .../gdc.test/fail_compilation/fail62.d | 11 + .../gdc.test/fail_compilation/fail6242.d | 3 + .../gdc.test/fail_compilation/fail63.d | 11 + .../gdc.test/fail_compilation/fail6334.d | 18 + .../gdc.test/fail_compilation/fail6451.d | 18 + .../gdc.test/fail_compilation/fail6453.d | 24 + .../gdc.test/fail_compilation/fail6458.d | 5 + .../gdc.test/fail_compilation/fail6497.d | 6 + .../gdc.test/fail_compilation/fail6561.d | 8 + .../gdc.test/fail_compilation/fail66.d | 91 + .../gdc.test/fail_compilation/fail6611.d | 6 + .../gdc.test/fail_compilation/fail6652.d | 37 + .../gdc.test/fail_compilation/fail6781.d | 9 + .../gdc.test/fail_compilation/fail6795.d | 34 + .../gdc.test/fail_compilation/fail6889.d | 130 + .../gdc.test/fail_compilation/fail6968.d | 22 + .../gdc.test/fail_compilation/fail7077.d | 12 + .../gdc.test/fail_compilation/fail7173.d | 18 + .../gdc.test/fail_compilation/fail7178.d | 6 + .../gdc.test/fail_compilation/fail72.d | 15 + .../gdc.test/fail_compilation/fail7234.d | 10 + .../gdc.test/fail_compilation/fail73.d | 29 + .../gdc.test/fail_compilation/fail7369.d | 5 + .../gdc.test/fail_compilation/fail74.d | 15 + .../gdc.test/fail_compilation/fail7424b.d | 5 + .../gdc.test/fail_compilation/fail7424c.d | 6 + .../gdc.test/fail_compilation/fail7424d.d | 6 + .../gdc.test/fail_compilation/fail7424e.d | 6 + .../gdc.test/fail_compilation/fail7424f.d | 6 + .../gdc.test/fail_compilation/fail7424g.d | 6 + .../gdc.test/fail_compilation/fail7424h.d | 6 + .../gdc.test/fail_compilation/fail7424i.d | 6 + .../gdc.test/fail_compilation/fail75.d | 15 + .../gdc.test/fail_compilation/fail7524a.d | 4 + .../gdc.test/fail_compilation/fail7524b.d | 3 + .../gdc.test/fail_compilation/fail76.d | 14 + .../gdc.test/fail_compilation/fail7603a.d | 1 + .../gdc.test/fail_compilation/fail7603b.d | 1 + .../gdc.test/fail_compilation/fail7603c.d | 2 + .../gdc.test/fail_compilation/fail77.d | 8 + .../gdc.test/fail_compilation/fail7702.d | 9 + .../gdc.test/fail_compilation/fail7751.d | 17 + .../gdc.test/fail_compilation/fail78.d | 10 + .../gdc.test/fail_compilation/fail7815.d | 65 + .../gdc.test/fail_compilation/fail7848.d | 53 + .../gdc.test/fail_compilation/fail7851.d | 33 + .../gdc.test/fail_compilation/fail7859.d | 8 + .../gdc.test/fail_compilation/fail7861.d | 12 + .../gdc.test/fail_compilation/fail7862.d | 30 + .../gdc.test/fail_compilation/fail7886.d | 5 + .../gdc.test/fail_compilation/fail79.d | 15 + .../gdc.test/fail_compilation/fail7903.d | 28 + .../gdc.test/fail_compilation/fail8009.d | 3 + .../gdc.test/fail_compilation/fail8032.d | 17 + .../gdc.test/fail_compilation/fail80_m32.d | 31 + .../gdc.test/fail_compilation/fail80_m64.d | 31 + .../gdc.test/fail_compilation/fail8168.d | 6 + .../gdc.test/fail_compilation/fail8179b.d | 12 + .../gdc.test/fail_compilation/fail8217.d | 25 + .../gdc.test/fail_compilation/fail8313.d | 3 + .../gdc.test/fail_compilation/fail8373.d | 23 + .../gdc.test/fail_compilation/fail86.d | 13 + .../gdc.test/fail_compilation/fail8631.d | 16 + .../gdc.test/fail_compilation/fail8691.d | 4 + .../gdc.test/fail_compilation/fail8724.d | 16 + .../gdc.test/fail_compilation/fail9.d | 27 + .../gdc.test/fail_compilation/fail9063.d | 9 + .../gdc.test/fail_compilation/fail9081.d | 14 + .../gdc.test/fail_compilation/fail91.d | 13 + .../gdc.test/fail_compilation/fail9199.d | 40 + .../gdc.test/fail_compilation/fail92.d | 24 + .../gdc.test/fail_compilation/fail9279.d | 13 + .../gdc.test/fail_compilation/fail93.d | 14 + .../gdc.test/fail_compilation/fail9301.d | 9 + .../gdc.test/fail_compilation/fail9346.d | 28 + .../gdc.test/fail_compilation/fail9368.d | 49 + .../gdc.test/fail_compilation/fail94.d | 56 + .../gdc.test/fail_compilation/fail9413.d | 85 + .../gdc.test/fail_compilation/fail9414a.d | 88 + .../gdc.test/fail_compilation/fail9414b.d | 88 + .../gdc.test/fail_compilation/fail9414c.d | 88 + .../gdc.test/fail_compilation/fail9414d.d | 88 + .../gdc.test/fail_compilation/fail95.d | 22 + .../gdc.test/fail_compilation/fail9537.d | 27 + .../gdc.test/fail_compilation/fail9562.d | 22 + .../gdc.test/fail_compilation/fail9572.d | 11 + .../gdc.test/fail_compilation/fail96.d | 22 + .../gdc.test/fail_compilation/fail9613.d | 6 + .../gdc.test/fail_compilation/fail9665a.d | 166 + .../gdc.test/fail_compilation/fail9665b.d | 77 + .../gdc.test/fail_compilation/fail97.d | 13 + .../gdc.test/fail_compilation/fail9710.d | 9 + .../gdc.test/fail_compilation/fail9735.d | 12 + .../gdc.test/fail_compilation/fail9766.d | 27 + .../gdc.test/fail_compilation/fail9773.d | 10 + .../gdc.test/fail_compilation/fail9790.d | 21 + .../gdc.test/fail_compilation/fail98.d | 36 + .../gdc.test/fail_compilation/fail9891.d | 26 + .../gdc.test/fail_compilation/fail9892.d | 13 + .../gdc.test/fail_compilation/fail99.d | 23 + .../gdc.test/fail_compilation/fail9936.d | 31 + .../gdc.test/fail_compilation/fail_arrayop1.d | 150 + .../gdc.test/fail_compilation/fail_arrayop2.d | 369 + .../gdc.test/fail_compilation/fail_casting.d | 223 + .../gdc.test/fail_compilation/fail_casting1.d | 259 + .../gdc.test/fail_compilation/fail_casting2.d | 21 + .../gdc.test/fail_compilation/fail_circular.d | 137 + .../fail_compilation/fail_circular2.d | 27 + .../gdc.test/fail_compilation/fail_opover.d | 58 + .../gdc.test/fail_compilation/fail_scope.d | 145 + .../gdc.test/fail_compilation/failattr.d | 34 + .../gdc.test/fail_compilation/failcontracts.d | 24 + .../gdc.test/fail_compilation/faildeleteaa.d | 12 + .../fail_compilation/faildottypeinfo.d | 13 + .../gdc.test/fail_compilation/failescape.d | 8 + .../gdc.test/fail_compilation/failinout1.d | 5 + .../gdc.test/fail_compilation/failinout2.d | 1 + .../fail_compilation/failinout3748a.d | 4 + .../fail_compilation/failinout3748b.d | 4 + .../gdc.test/fail_compilation/failmemalloc.d | 13 + .../gdc.test/fail_compilation/failoffset.d | 13 + .../gdc.test/fail_compilation/failsafea.d | 8 + .../gdc.test/fail_compilation/failsafeb.d | 8 + .../gdc.test/fail_compilation/failsafec.d | 9 + .../gdc.test/fail_compilation/fix350a.d | 7 + .../gdc.test/fail_compilation/fix350b.d | 10 + .../gdc.test/fail_compilation/gag4269a.d | 13 + .../gdc.test/fail_compilation/gag4269b.d | 10 + .../gdc.test/fail_compilation/gag4269c.d | 10 + .../gdc.test/fail_compilation/gag4269d.d | 10 + .../gdc.test/fail_compilation/gag4269e.d | 10 + .../gdc.test/fail_compilation/gag4269f.d | 11 + .../gdc.test/fail_compilation/gag4269g.d | 10 + .../gdc.test/fail_compilation/ice10016.d | 48 + .../gdc.test/fail_compilation/ice10076.d | 25 + .../gdc.test/fail_compilation/ice10212.d | 15 + .../gdc.test/fail_compilation/ice10259.d | 27 + .../gdc.test/fail_compilation/ice10273.d | 12 + .../gdc.test/fail_compilation/ice10283.d | 10 + .../gdc.test/fail_compilation/ice10341.d | 11 + .../gdc.test/fail_compilation/ice10382.d | 15 + .../gdc.test/fail_compilation/ice10419.d | 13 + .../gdc.test/fail_compilation/ice10599.d | 12 + .../gdc.test/fail_compilation/ice10600.d | 32 + .../gdc.test/fail_compilation/ice10616.d | 11 + .../gdc.test/fail_compilation/ice10624.d | 51 + .../gdc.test/fail_compilation/ice10651.d | 12 + .../gdc.test/fail_compilation/ice10713.d | 11 + .../gdc.test/fail_compilation/ice10727a.d | 9 + .../gdc.test/fail_compilation/ice10727b.d | 9 + .../gdc.test/fail_compilation/ice10770.d | 13 + .../gdc.test/fail_compilation/ice10922.d | 16 + .../gdc.test/fail_compilation/ice10938.d | 23 + .../gdc.test/fail_compilation/ice10949.d | 12 + .../gdc.test/fail_compilation/ice11086.d | 11 + .../gdc.test/fail_compilation/ice11136.d | 9 + .../gdc.test/fail_compilation/ice11153.d | 15 + .../gdc.test/fail_compilation/ice11404.d | 11 + .../gdc.test/fail_compilation/ice1144.d | 24 + .../gdc.test/fail_compilation/ice11472.d | 19 + .../gdc.test/fail_compilation/ice11513a.d | 10 + .../gdc.test/fail_compilation/ice11513b.d | 10 + .../gdc.test/fail_compilation/ice11518.d | 18 + .../gdc.test/fail_compilation/ice11552.d | 17 + .../gdc.test/fail_compilation/ice11553.d | 22 + .../gdc.test/fail_compilation/ice11626.d | 8 + .../gdc.test/fail_compilation/ice11726.d | 17 + .../gdc.test/fail_compilation/ice11755.d | 30 + .../gdc.test/fail_compilation/ice11790.d | 8 + .../gdc.test/fail_compilation/ice11793.d | 12 + .../gdc.test/fail_compilation/ice11822.d | 33 + .../gdc.test/fail_compilation/ice11849b.d | 19 + .../gdc.test/fail_compilation/ice11850.d | 15 + .../gdc.test/fail_compilation/ice11919.d | 26 + .../gdc.test/fail_compilation/ice11922.d | 18 + .../gdc.test/fail_compilation/ice11926.d | 13 + .../gdc.test/fail_compilation/ice11944.d | 12 + .../gdc.test/fail_compilation/ice11963.d | 1 + .../gdc.test/fail_compilation/ice11965.d | 1 + .../gdc.test/fail_compilation/ice11967.d | 1 + .../gdc.test/fail_compilation/ice11968.d | 1 + .../gdc.test/fail_compilation/ice11969.d | 11 + .../gdc.test/fail_compilation/ice11974.d | 1 + .../gdc.test/fail_compilation/ice11982.d | 1 + .../gdc.test/fail_compilation/ice12040.d | 8 + .../gdc.test/fail_compilation/ice12158.d | 8 + .../gdc.test/fail_compilation/ice12174.d | 51 + .../gdc.test/fail_compilation/ice12235.d | 17 + .../gdc.test/fail_compilation/ice12350.d | 31 + .../gdc.test/fail_compilation/ice12362.d | 13 + .../gdc.test/fail_compilation/ice12397.d | 16 + .../gdc.test/fail_compilation/ice12497.d | 18 + .../gdc.test/fail_compilation/ice12501.d | 44 + .../gdc.test/fail_compilation/ice12534.d | 15 + .../gdc.test/fail_compilation/ice12539.d | 16 + .../gdc.test/fail_compilation/ice12574.d | 54 + .../gdc.test/fail_compilation/ice12581.d | 22 + .../gdc.test/fail_compilation/ice12673.d | 4 + .../gdc.test/fail_compilation/ice12727.d | 28 + .../gdc.test/fail_compilation/ice12827.d | 15 + .../gdc.test/fail_compilation/ice12836.d | 9 + .../gdc.test/fail_compilation/ice12838.d | 28 + .../gdc.test/fail_compilation/ice12841.d | 25 + .../gdc.test/fail_compilation/ice12850.d | 13 + .../gdc.test/fail_compilation/ice12902.d | 21 + .../gdc.test/fail_compilation/ice12907.d | 11 + .../gdc.test/fail_compilation/ice13024.d | 16 + .../gdc.test/fail_compilation/ice13027.d | 10 + .../gdc.test/fail_compilation/ice13081.d | 29 + .../gdc.test/fail_compilation/ice13131.d | 20 + .../gdc.test/fail_compilation/ice13220.d | 23 + .../gdc.test/fail_compilation/ice13221.d | 23 + .../gdc.test/fail_compilation/ice13225.d | 17 + .../gdc.test/fail_compilation/ice13311.d | 12 + .../gdc.test/fail_compilation/ice13356.d | 41 + .../gdc.test/fail_compilation/ice13382.d | 26 + .../gdc.test/fail_compilation/ice13385.d | 9 + .../gdc.test/fail_compilation/ice13459.d | 19 + .../gdc.test/fail_compilation/ice13465a.d | 20 + .../gdc.test/fail_compilation/ice13465b.d | 20 + .../gdc.test/fail_compilation/ice13563.d | 27 + .../gdc.test/fail_compilation/ice1358.d | 29 + .../gdc.test/fail_compilation/ice13644.d | 19 + .../gdc.test/fail_compilation/ice13788.d | 14 + .../gdc.test/fail_compilation/ice13816.d | 23 + .../gdc.test/fail_compilation/ice13835.d | 22 + .../gdc.test/fail_compilation/ice13921.d | 27 + .../gdc.test/fail_compilation/ice13987.d | 9 + .../gdc.test/fail_compilation/ice14055.d | 18 + .../gdc.test/fail_compilation/ice14096.d | 41 + .../gdc.test/fail_compilation/ice14116.d | 11 + .../gdc.test/fail_compilation/ice14130.d | 15 + .../gdc.test/fail_compilation/ice14146.d | 24 + .../gdc.test/fail_compilation/ice14177.d | 15 + .../gdc.test/fail_compilation/ice14185.d | 24 + .../gdc.test/fail_compilation/ice14272.d | 14 + .../gdc.test/fail_compilation/ice14424.d | 13 + .../gdc.test/fail_compilation/ice14446.d | 14 + .../gdc.test/fail_compilation/ice14621.d | 30 + .../gdc.test/fail_compilation/ice14642.d | 52 + .../gdc.test/fail_compilation/ice14844.d | 23 + .../gdc.test/fail_compilation/ice14923.d | 28 + .../gdc.test/fail_compilation/ice14929.d | 96 + .../gdc.test/fail_compilation/ice15002.d | 10 + .../gdc.test/fail_compilation/ice15092.d | 20 + .../gdc.test/fail_compilation/ice15127.d | 20 + .../gdc.test/fail_compilation/ice15172.d | 33 + .../gdc.test/fail_compilation/ice15239.d | 23 + .../gdc.test/fail_compilation/ice15317.d | 13 + .../gdc.test/fail_compilation/ice15332.d | 19 + .../gdc.test/fail_compilation/ice15441.d | 28 + .../gdc.test/fail_compilation/ice15688.d | 13 + .../gdc.test/fail_compilation/ice15788.d | 18 + .../gdc.test/fail_compilation/ice15816.d | 11 + .../gdc.test/fail_compilation/ice15855.d | 3 + .../gdc.test/fail_compilation/ice15922.d | 26 + .../gdc.test/fail_compilation/ice16035.d | 22 + .../gdc.test/fail_compilation/ice17074.d | 39 + .../gdc.test/fail_compilation/ice17690.d | 10 + .../gdc.test/fail_compilation/ice17831.d | 78 + .../gdc.test/fail_compilation/ice2843.d | 22 + .../gdc.test/fail_compilation/ice4094.d | 19 + .../gdc.test/fail_compilation/ice4983.d | 15 + .../gdc.test/fail_compilation/ice5996.d | 11 + .../gdc.test/fail_compilation/ice6538.d | 30 + .../gdc.test/fail_compilation/ice7645.d | 32 + .../gdc.test/fail_compilation/ice7782.d | 4 + .../gdc.test/fail_compilation/ice8100.d | 12 + .../gdc.test/fail_compilation/ice8255.d | 10 + .../gdc.test/fail_compilation/ice8309.d | 11 + .../gdc.test/fail_compilation/ice8499.d | 19 + .../gdc.test/fail_compilation/ice8511.d | 13 + .../gdc.test/fail_compilation/ice8604.d | 7 + .../gdc.test/fail_compilation/ice8630.d | 3 + .../gdc.test/fail_compilation/ice8711.d | 8 + .../gdc.test/fail_compilation/ice8742.d | 11 + .../gdc.test/fail_compilation/ice8795.d | 16 + .../gdc.test/fail_compilation/ice8795b.d | 8 + .../gdc.test/fail_compilation/ice9013.d | 5 + .../gdc.test/fail_compilation/ice9254a.d | 12 + .../gdc.test/fail_compilation/ice9254b.d | 15 + .../gdc.test/fail_compilation/ice9254c.d | 14 + .../gdc.test/fail_compilation/ice9273a.d | 24 + .../gdc.test/fail_compilation/ice9273b.d | 15 + .../gdc.test/fail_compilation/ice9284.d | 21 + .../gdc.test/fail_compilation/ice9291.d | 11 + .../gdc.test/fail_compilation/ice9338.d | 21 + .../gdc.test/fail_compilation/ice9406.d | 22 + .../gdc.test/fail_compilation/ice9439.d | 21 + .../gdc.test/fail_compilation/ice9494.d | 20 + .../gdc.test/fail_compilation/ice9540.d | 37 + .../gdc.test/fail_compilation/ice9545.d | 14 + .../gdc.test/fail_compilation/ice9759.d | 25 + .../gdc.test/fail_compilation/ice9806.d | 49 + .../gdc.test/fail_compilation/ice9865.d | 9 + .../gdc.test/fail_compilation/imphint.d | 20 + .../fail_compilation/imports/a10169.d | 6 + .../fail_compilation/imports/a10528.d | 6 + .../fail_compilation/imports/a11850.d | 51 + .../fail_compilation/imports/a11919.d | 17 + .../imports/a13131checkpoint.d | 18 + .../fail_compilation/imports/a13131elec.d | 10 + .../imports/a13131parameters.d | 14 + .../fail_compilation/imports/a13311.d | 9 + .../fail_compilation/imports/a13465.d | 22 + .../fail_compilation/imports/a14116.d | 5 + .../fail_compilation/imports/a14235.d | 7 + .../fail_compilation/imports/a14407.d | 19 + .../fail_compilation/imports/a14424.d | 3 + .../fail_compilation/imports/a15667.d | 18 + .../fail_compilation/imports/a15816.d | 5 + .../gdc.test/fail_compilation/imports/a313.d | 9 + .../gdc.test/fail_compilation/imports/a314.d | 5 + .../fail_compilation/imports/b13465.d | 22 + .../gdc.test/fail_compilation/imports/b313.d | 4 + .../gdc.test/fail_compilation/imports/b314.d | 4 + .../fail_compilation/imports/bar11136.d | 1 + .../gdc.test/fail_compilation/imports/c314.d | 4 + .../fail_compilation/imports/checkimports3a.d | 1 + .../fail_compilation/imports/checkimports3b.d | 1 + .../fail_compilation/imports/checkimports3c.d | 1 + .../fail_compilation/imports/diag10089a.d | 8 + .../fail_compilation/imports/diag10089b.d | 5 + .../fail_compilation/imports/diag10141a.d | 26 + .../fail_compilation/imports/diag10141b.d | 55 + .../fail_compilation/imports/diag12598a.d | 3 + .../fail_compilation/imports/diag9210b.d | 6 + .../fail_compilation/imports/diag9210c.d | 4 + .../imports/diag9210stdcomplex.d | 17 + .../imports/diag9210stdtraits.d | 33 + .../fail_compilation/imports/dip22a.d | 20 + .../fail_compilation/imports/dip22b.d | 3 + .../fail_compilation/imports/dip22c.d | 3 + .../fail_compilation/imports/dip22d.d | 5 + .../fail_compilation/imports/dip22e.d | 4 + .../fail_compilation/imports/fail10277.d | 23 + .../fail_compilation/imports/fail17646.d | 10 + .../fail_compilation/imports/fail1900a.d | 2 + .../fail_compilation/imports/fail1900b.d | 2 + .../fail_compilation/imports/fail2962a.d | 7 + .../fail_compilation/imports/fail320a.d | 1 + .../fail_compilation/imports/fail320b.d | 1 + .../fail_compilation/imports/fail347a.d | 3 + .../fail_compilation/imports/fail355.d | 1 + .../fail_compilation/imports/fail356.d | 2 + .../fail_compilation/imports/fail4479.d | 1 + .../fail_compilation/imports/fail5385.d | 17 + .../fail_compilation/imports/foo10727a.d | 34 + .../fail_compilation/imports/foo10727b.d | 25 + .../fail_compilation/imports/ice10600a.d | 11 + .../fail_compilation/imports/ice10600b.d | 36 + .../fail_compilation/imports/ice11513x.d | 1 + .../fail_compilation/imports/ice11513y.d | 1 + .../imports/ice7782algorithm.d | 3 + .../fail_compilation/imports/ice7782range.d | 3 + .../fail_compilation/imports/ice9865b.d | 2 + .../gdc.test/fail_compilation/imports/imp1.d | 5 + .../gdc.test/fail_compilation/imports/imp2.d | 5 + .../fail_compilation/imports/pkg313/package.d | 4 + .../fail_compilation/imports/range15788.d | 5 + .../fail_compilation/imports/spell9644a.d | 7 + .../fail_compilation/imports/spell9644b.d | 3 + .../fail_compilation/imports/stdtraits10727.d | 46 + .../imports/test10327/empty.d | 1 + .../fail_compilation/imports/test13152a.d | 26 + .../fail_compilation/imports/test13152b.d | 26 + .../fail_compilation/imports/test13152c.d | 26 + .../fail_compilation/imports/test13152d.d | 26 + .../fail_compilation/imports/test13152e.d | 26 + .../fail_compilation/imports/test13152f.d | 26 + .../fail_compilation/imports/test13152g.d | 26 + .../fail_compilation/imports/test13152h.d | 26 + .../fail_compilation/imports/test13152i.d | 26 + .../fail_compilation/imports/test13152j.d | 26 + .../fail_compilation/imports/test13152k.d | 26 + .../fail_compilation/imports/test13152l.d | 26 + .../fail_compilation/imports/test13152m.d | 26 + .../fail_compilation/imports/test13152n.d | 26 + .../fail_compilation/imports/test13152o.d | 26 + .../fail_compilation/imports/test13152p.d | 26 + .../fail_compilation/imports/test13152q.d | 26 + .../fail_compilation/imports/test13152r.d | 26 + .../fail_compilation/imports/test13152s.d | 26 + .../fail_compilation/imports/test13152t.d | 26 + .../fail_compilation/imports/test13152u.d | 26 + .../fail_compilation/imports/test13152v.d | 26 + .../fail_compilation/imports/test13152w.d | 26 + .../fail_compilation/imports/test13152x.d | 26 + .../fail_compilation/imports/test13152y.d | 26 + .../fail_compilation/imports/test13152z.d | 26 + .../fail_compilation/imports/test143.d | 3 + .../fail_compilation/imports/test15785.d | 13 + .../fail_compilation/imports/test15897.d | 6 + .../fail_compilation/imports/test5412a.d | 1 + .../fail_compilation/imports/test5412b.d | 1 + .../fail_compilation/imports/test64a.d | 4 + .../gdc.test/fail_compilation/issue3827.d | 14 + .../gdc.test/fail_compilation/lexer1.d | 52 + .../gdc.test/fail_compilation/lexer2.d | 19 + .../gdc.test/fail_compilation/lexer3.d | 9 + .../gdc.test/fail_compilation/lexer4.d | 43 + .../gdc.test/fail_compilation/lookup.d | 28 + .../gdc.test/fail_compilation/mangle1.d | 8 + .../gdc.test/fail_compilation/mangle2.d | 42 + .../fail_compilation/moduleundefuda.d | 7 + .../gdc.test/fail_compilation/nogc1.d | 85 + .../gdc.test/fail_compilation/nogc2.d | 104 + .../gdc.test/fail_compilation/nogc3.d | 95 + .../gdc.test/fail_compilation/parse12924.d | 20 + .../gdc.test/fail_compilation/parse12967a.d | 43 + .../gdc.test/fail_compilation/parse12967b.d | 41 + .../gdc.test/fail_compilation/parse13361.d | 16 + .../gdc.test/fail_compilation/parse14285.d | 11 + .../gdc.test/fail_compilation/parse14745.d | 13 + .../gdc.test/fail_compilation/parseStc.d | 38 + .../gdc.test/fail_compilation/parseStc2.d | 77 + .../gdc.test/fail_compilation/parseStc3.d | 62 + .../gdc.test/fail_compilation/parseStc4.d | 42 + .../gdc.test/fail_compilation/parseStc5.d | 88 + .../gdc.test/fail_compilation/pragmainline.d | 11 + .../gdc.test/fail_compilation/pragmas.d | 40 + .../gdc.test/fail_compilation/protattr1.d | 7 + .../gdc.test/fail_compilation/protattr2.d | 7 + .../gdc.test/fail_compilation/protattr3.d | 7 + .../protection/subpkg/test1.d | 3 + .../protection/subpkg/test2.d | 3 + .../protection/subpkg/test3.d | 3 + .../fail_compilation/reserved_version.d | 298 + .../reserved_version_switch.d | 284 + .../gdc.test/fail_compilation/retref2.d | 23 + .../gdc.test/fail_compilation/retscope.d | 662 + .../gdc.test/fail_compilation/retscope2.d | 295 + .../gdc.test/fail_compilation/skip.d | 52 + .../gdc.test/fail_compilation/spell9644.d | 36 + .../fail_compilation/staticarrayoverflow.d | 23 + .../gdc.test/fail_compilation/switches.d | 74 + .../gdc.test/fail_compilation/test1.d | 1 + .../gdc.test/fail_compilation/test11047.d | 19 + .../gdc.test/fail_compilation/test11176.d | 18 + .../gdc.test/fail_compilation/test12822.d | 17 + .../gdc.test/fail_compilation/test12979.d | 16 + .../gdc.test/fail_compilation/test13152.d | 12 + .../gdc.test/fail_compilation/test13536.d | 27 + .../gdc.test/fail_compilation/test13537.d | 61 + .../gdc.test/fail_compilation/test13786.d | 20 + .../gdc.test/fail_compilation/test13867.d | 40 + .../gdc.test/fail_compilation/test14238.d | 30 + .../gdc.test/fail_compilation/test143.d | 13 + .../gdc.test/fail_compilation/test14496.d | 53 + .../gdc.test/fail_compilation/test14538.d | 20 + .../gdc.test/fail_compilation/test15191.d | 18 + .../gdc.test/fail_compilation/test15306.d | 29 + .../gdc.test/fail_compilation/test15399.d | 46 + .../gdc.test/fail_compilation/test15544.d | 51 + .../gdc.test/fail_compilation/test15672.d | 38 + .../gdc.test/fail_compilation/test15703.d | 32 + .../gdc.test/fail_compilation/test15704.d | 17 + .../gdc.test/fail_compilation/test15785.d | 20 + .../gdc.test/fail_compilation/test15785b.d | 18 + .../gdc.test/fail_compilation/test15897.d | 19 + .../gdc.test/fail_compilation/test15989.d | 52 + .../gdc.test/fail_compilation/test16095.d | 44 + .../gdc.test/fail_compilation/test16116.d | 16 + .../gdc.test/fail_compilation/test16188.d | 25 + .../gdc.test/fail_compilation/test16193.d | 45 + .../gdc.test/fail_compilation/test16195.d | 14 + .../gdc.test/fail_compilation/test16228.d | 24 + .../gdc.test/fail_compilation/test16365.d | 30 + .../gdc.test/fail_compilation/test16381.d | 18 + .../gdc.test/fail_compilation/test16523.d | 16 + .../gdc.test/fail_compilation/test16589.d | 65 + .../gdc.test/fail_compilation/test17380.d | 21 + .../gdc.test/fail_compilation/test17422.d | 24 + .../gdc.test/fail_compilation/test17425.d | 32 + .../gdc.test/fail_compilation/test17450.d | 58 + .../gdc.test/fail_compilation/test17451.d | 45 + .../gdc.test/fail_compilation/test314.d | 24 + .../gdc.test/fail_compilation/test4682.d | 13 + .../gdc.test/fail_compilation/test4682a.d | 13 + .../gdc.test/fail_compilation/test4838.d | 18 + .../gdc.test/fail_compilation/test5412a.d | 4 + .../gdc.test/fail_compilation/test5412b.d | 4 + .../gdc.test/fail_compilation/test5412c.d | 4 + .../gdc.test/fail_compilation/test64.d | 19 + .../gdc.test/fail_compilation/test6883.d | 25 + .../gdc.test/fail_compilation/test8509.d | 8 + .../gdc.test/fail_compilation/test8556.d | 56 + .../gdc.test/fail_compilation/test8751.d | 3 + .../gdc.test/fail_compilation/test9150.d | 21 + .../gdc.test/fail_compilation/test9176.d | 18 + .../gdc.test/fail_compilation/testCols.d | 14 + .../gdc.test/fail_compilation/testInference.d | 226 + .../gdc.test/fail_compilation/testpull1810.d | 21 + .../fail_compilation/testscopestatic.d | 24 + .../gdc.test/fail_compilation/typeerrors.d | 58 + .../gdc.test/fail_compilation/verrors0.d | 60 + .../gdc.test/fail_compilation/verrors5.d | 40 + .../gdc.test/fail_compilation/warn12809.d | 34 + .../gdc.test/fail_compilation/warn13679.d | 15 + .../gdc.test/fail_compilation/warn7444.d | 83 + gcc/testsuite/gdc.test/gdc-test.exp | 416 + gcc/testsuite/gdc.test/runnable/A16.d | 12 + gcc/testsuite/gdc.test/runnable/Same.d | 12 + gcc/testsuite/gdc.test/runnable/a17.d | 21 + gcc/testsuite/gdc.test/runnable/a18.d | 16 + gcc/testsuite/gdc.test/runnable/a19.d | 12 + gcc/testsuite/gdc.test/runnable/a21.d | 29 + gcc/testsuite/gdc.test/runnable/aliasthis.d | 2034 ++ gcc/testsuite/gdc.test/runnable/argufilem.d | 22 + gcc/testsuite/gdc.test/runnable/arrayop.d | 956 + gcc/testsuite/gdc.test/runnable/auto1.d | 125 + gcc/testsuite/gdc.test/runnable/b17073.d | 13 + gcc/testsuite/gdc.test/runnable/b26.d | 14 + gcc/testsuite/gdc.test/runnable/bench1.d | 30 + gcc/testsuite/gdc.test/runnable/bitops.d | 148 + gcc/testsuite/gdc.test/runnable/bug11155.d | 19 + gcc/testsuite/gdc.test/runnable/bug12928.d | 13 + gcc/testsuite/gdc.test/runnable/bug16146.d | 26 + gcc/testsuite/gdc.test/runnable/bug5.d | 20 + gcc/testsuite/gdc.test/runnable/bug7068.d | 11 + gcc/testsuite/gdc.test/runnable/bug846.d | 11 + gcc/testsuite/gdc.test/runnable/builtin.d | 118 + gcc/testsuite/gdc.test/runnable/c22.d | 15 + gcc/testsuite/gdc.test/runnable/cabi1.d | 262 + gcc/testsuite/gdc.test/runnable/cassert.d | 17 + gcc/testsuite/gdc.test/runnable/casting.d | 248 + gcc/testsuite/gdc.test/runnable/circular.d | 25 + gcc/testsuite/gdc.test/runnable/closure.d | 988 + gcc/testsuite/gdc.test/runnable/complex.d | 462 + gcc/testsuite/gdc.test/runnable/constfold.d | 674 + .../gdc.test/runnable/cpp_abi_tests.d | 157 + gcc/testsuite/gdc.test/runnable/cppa.d | 1258 ++ .../gdc.test/runnable/ctorpowtests.d | 248 + gcc/testsuite/gdc.test/runnable/declaration.d | 412 + gcc/testsuite/gdc.test/runnable/delegate.d | 357 + gcc/testsuite/gdc.test/runnable/dhry.d | 927 + gcc/testsuite/gdc.test/runnable/eh.d | 866 + gcc/testsuite/gdc.test/runnable/eh2.d | 85 + gcc/testsuite/gdc.test/runnable/entity1.d | 144 + gcc/testsuite/gdc.test/runnable/evalorder.d | 164 + gcc/testsuite/gdc.test/runnable/extern1.d | 14 + .../gdc.test/runnable/externmangle.d | 314 + .../gdc.test/runnable/externmangle2.d | 164 + .../gdc.test/runnable/extra-files/alice30.txt | 3603 ++++ .../gdc.test/runnable/extra-files/cabi2.cpp | 255 + .../runnable/extra-files/cpp_abi_tests.cpp | 60 + .../gdc.test/runnable/extra-files/cppb.cpp | 812 + .../runnable/extra-files/externmangle.cpp | 404 + .../runnable/extra-files/externmangle2.cpp | 145 + .../gdc.test/runnable/extra-files/foo37.txt | 2 + .../runnable/extra-files/std14198/array.d | 27 + .../runnable/extra-files/std14198/conv.d | 34 + .../runnable/extra-files/std14198/format.d | 11 + .../runnable/extra-files/std14198/uni.d | 12 + .../gdc.test/runnable/extra-files/test15.txt | 815 + .../runnable/extra-files/teststdio.txt | 6 + gcc/testsuite/gdc.test/runnable/fix17429.d | 17 + gcc/testsuite/gdc.test/runnable/foreach.d | 299 + gcc/testsuite/gdc.test/runnable/foreach2.d | 268 + gcc/testsuite/gdc.test/runnable/foreach3.d | 285 + gcc/testsuite/gdc.test/runnable/foreach4.d | 930 + gcc/testsuite/gdc.test/runnable/foreach5.d | 1122 + gcc/testsuite/gdc.test/runnable/funclit.d | 1289 ++ gcc/testsuite/gdc.test/runnable/functype.d | 341 + gcc/testsuite/gdc.test/runnable/future.d | 43 + gcc/testsuite/gdc.test/runnable/hello.d | 12 + gcc/testsuite/gdc.test/runnable/helloUTF8.d | 10 + gcc/testsuite/gdc.test/runnable/ice10086a.d | 6 + gcc/testsuite/gdc.test/runnable/ice10086b.d | 6 + gcc/testsuite/gdc.test/runnable/ice10857.d | 3 + gcc/testsuite/gdc.test/runnable/ice15030.d | 92 + gcc/testsuite/gdc.test/runnable/ice15138.d | 11 + gcc/testsuite/gdc.test/runnable/ice15176.d | 9 + gcc/testsuite/gdc.test/runnable/ice15200.d | 11 + gcc/testsuite/gdc.test/runnable/ice4481.d | 10 + gcc/testsuite/gdc.test/runnable/ifti.d | 120 + gcc/testsuite/gdc.test/runnable/implicit.d | 481 + .../gdc.test/runnable/imports/A16a.d | 20 + .../gdc.test/runnable/imports/Other.d | 18 + .../gdc.test/runnable/imports/a11447.d | 14 + .../gdc.test/runnable/imports/a12010.d | 3 + .../gdc.test/runnable/imports/a12037.d | 77 + .../gdc.test/runnable/imports/a12874.d | 13 + .../gdc.test/runnable/imports/a14267.d | 19 + .../gdc.test/runnable/imports/a14992.d | 5 + .../gdc.test/runnable/imports/a15030.d | 3 + .../gdc.test/runnable/imports/a15079.d | 50 + .../gdc.test/runnable/imports/a17a.d | 7 + .../gdc.test/runnable/imports/a18a.d | 28 + .../gdc.test/runnable/imports/a19a.d | 15 + .../gdc.test/runnable/imports/a20a.d | 1 + .../gdc.test/runnable/imports/a21a.d | 21 + .../gdc.test/runnable/imports/a7595.d | 27 + .../gdc.test/runnable/imports/a9546.d | 12 + .../gdc.test/runnable/imports/a9741.d | 7 + .../gdc.test/runnable/imports/argufile.d | 146 + .../gdc.test/runnable/imports/b11447.d | 15 + .../gdc.test/runnable/imports/b15030.d | 17 + .../gdc.test/runnable/imports/b26a.d | 5 + .../gdc.test/runnable/imports/bar10378.d | 4 + .../gdc.test/runnable/imports/bug10425.d | 32 + .../gdc.test/runnable/imports/bug846.d | 39 + .../gdc.test/runnable/imports/c11447.d | 67 + .../gdc.test/runnable/imports/c22a.d | 5 + .../gdc.test/runnable/imports/c22b.d | 6 + .../gdc.test/runnable/imports/circularA.d | 30 + .../runnable/imports/depsprot_default.d | 1 + .../runnable/imports/depsprot_private.d | 1 + .../runnable/imports/depsprot_public.d | 1 + .../gdc.test/runnable/imports/extern1a.d | 4 + .../gdc.test/runnable/imports/ice10086x.d | 34 + .../gdc.test/runnable/imports/ice10086y.d | 10 + .../gdc.test/runnable/imports/ice10857a.d | 19 + .../gdc.test/runnable/imports/ice10857b.d | 14 + .../gdc.test/runnable/imports/ice15138a.d | 28 + .../gdc.test/runnable/imports/ice15176a.d | 13 + .../gdc.test/runnable/imports/ice15176b.d | 8 + .../gdc.test/runnable/imports/ice15200a.d | 13 + .../gdc.test/runnable/imports/ice15200b.d | 41 + .../gdc.test/runnable/imports/ice4481a.d | 9 + .../gdc.test/runnable/imports/ice4481b.d | 14 + .../gdc.test/runnable/imports/inc11239.d | 12 + .../gdc.test/runnable/imports/link10920a.d | 19 + .../gdc.test/runnable/imports/link11069x.d | 10 + .../gdc.test/runnable/imports/link11069y.d | 10 + .../gdc.test/runnable/imports/link11069z.d | 22 + .../gdc.test/runnable/imports/link11127a.d | 21 + .../gdc.test/runnable/imports/link11395a.d | 15 + .../gdc.test/runnable/imports/link12144a.d | 50 + .../gdc.test/runnable/imports/link13043a.d | 17 + .../gdc.test/runnable/imports/link13394a.d | 24 + .../gdc.test/runnable/imports/link13400a.d | 16 + .../gdc.test/runnable/imports/link13415a.d | 20 + .../gdc.test/runnable/imports/link14074x.d | 5 + .../gdc.test/runnable/imports/link14074y.d | 31 + .../gdc.test/runnable/imports/link14074z.d | 56 + .../runnable/imports/link14541traits.d | 54 + .../gdc.test/runnable/imports/link14588a.d | 15 + .../gdc.test/runnable/imports/link14814a.d | 11 + .../gdc.test/runnable/imports/link15194b.d | 7 + .../gdc.test/runnable/imports/link15194std.d | 67 + .../gdc.test/runnable/imports/link2500a.d | 9 + .../gdc.test/runnable/imports/link2500b.d | 6 + .../gdc.test/runnable/imports/link2644a.d | 9 + .../gdc.test/runnable/imports/link2644b.d | 9 + .../gdc.test/runnable/imports/link2644c.d | 5 + .../gdc.test/runnable/imports/link7745b.d | 7 + .../gdc.test/runnable/imports/link8023b.d | 2 + .../gdc.test/runnable/imports/link9571a.d | 11 + .../runnable/imports/linktypeinfo_file.d | 33 + gcc/testsuite/gdc.test/runnable/imports/m1a.d | 11 + .../gdc.test/runnable/imports/m8668a.d | 6 + .../gdc.test/runnable/imports/m8668b.d | 6 + .../gdc.test/runnable/imports/m8668c.d | 4 + .../gdc.test/runnable/imports/mangle10077.d | 9 + .../gdc.test/runnable/imports/mod2.d | 12 + .../gdc.test/runnable/imports/ovs1528a.d | 12 + .../gdc.test/runnable/imports/ovs1528b.d | 12 + .../gdc.test/runnable/imports/std11069array.d | 16 + .../runnable/imports/std11069container.d | 11 + .../gdc.test/runnable/imports/std11069range.d | 15 + .../runnable/imports/std11069typecons.d | 34 + .../runnable/imports/std11863bitmanip.d | 11 + .../gdc.test/runnable/imports/std11863conv.d | 90 + .../runnable/imports/std11863format.d | 13 + .../runnable/imports/std12010container.d | 70 + .../runnable/imports/std15017variant.d | 25 + .../gdc.test/runnable/imports/std15021conv.d | 13 + .../runnable/imports/std15021format.d | 12 + .../gdc.test/runnable/imports/std15030algo.d | 35 + .../runnable/imports/template13478a.d | 9 + .../runnable/imports/template13478b.d | 7 + .../gdc.test/runnable/imports/template2962a.d | 10 + .../gdc.test/runnable/imports/template_ovs1.d | 58 + .../gdc.test/runnable/imports/template_ovs2.d | 58 + .../gdc.test/runnable/imports/template_ovs3.d | 36 + .../gdc.test/runnable/imports/test10441b.d | 9 + .../gdc.test/runnable/imports/test10441c.d | 6 + .../gdc.test/runnable/imports/test10573a.d | 13 + .../gdc.test/runnable/imports/test10736a.d | 4 + .../gdc.test/runnable/imports/test10736b.d | 13 + .../gdc.test/runnable/imports/test10736c.d | 24 + .../gdc.test/runnable/imports/test10a.d | 9 + .../gdc.test/runnable/imports/test11039b.d | 7 + .../gdc.test/runnable/imports/test11745b.d | 17 + .../gdc.test/runnable/imports/test11931a.d | 14 + .../gdc.test/runnable/imports/test11931b.d | 21 + .../gdc.test/runnable/imports/test11931c.d | 3 + .../gdc.test/runnable/imports/test11931d.d | 30 + .../gdc.test/runnable/imports/test13a.d | 55 + .../gdc.test/runnable/imports/test14901a.d | 21 + .../gdc.test/runnable/imports/test14901b.d | 13 + .../gdc.test/runnable/imports/test14901c.d | 10 + .../gdc.test/runnable/imports/test14901d.d | 8 + .../gdc.test/runnable/imports/test21a.d | 21 + .../gdc.test/runnable/imports/test24a.d | 3 + .../gdc.test/runnable/imports/test24b.d | 3 + .../gdc.test/runnable/imports/test27a.d | 11 + .../gdc.test/runnable/imports/test29a.d | 6 + .../gdc.test/runnable/imports/test29b.d | 3 + .../gdc.test/runnable/imports/test31a.d | 6 + .../gdc.test/runnable/imports/test32a.d | 10 + .../gdc.test/runnable/imports/test35a.d | 39 + .../gdc.test/runnable/imports/test38a.d | 6 + .../gdc.test/runnable/imports/test39a.d | 13 + .../gdc.test/runnable/imports/test3a.d | 13 + .../gdc.test/runnable/imports/test3b.d | 7 + .../gdc.test/runnable/imports/test40a.d | 41 + .../gdc.test/runnable/imports/test41a.d | 12 + .../gdc.test/runnable/imports/test44a.d | 5 + .../gdc.test/runnable/imports/test45a.d | 17 + .../gdc.test/runnable/imports/test45b.d | 16 + .../gdc.test/runnable/imports/test46a.d | 15 + .../gdc.test/runnable/imports/test46b.d | 10 + .../gdc.test/runnable/imports/test46c.d | 7 + .../gdc.test/runnable/imports/test48a.d | 9 + .../gdc.test/runnable/imports/test49a.d | 28 + .../gdc.test/runnable/imports/test57a.d | 10 + .../gdc.test/runnable/imports/test57b.d | 3 + .../gdc.test/runnable/imports/test58a.d | 7 + .../gdc.test/runnable/imports/test61a.d | 6 + .../gdc.test/runnable/imports/test7494a.d | 13 + .../gdc.test/runnable/imports/test8997a.d | 6 + .../gdc.test/runnable/imports/test9271a.d | 6 + .../gdc.test/runnable/imports/testkwd_file.d | 37 + .../gdc.test/runnable/imports/testminitAA.d | 11 + .../gdc.test/runnable/imports/testminitBB.d | 11 + .../gdc.test/runnable/imports/testmod1a.d | 7 + .../gdc.test/runnable/imports/testmod1b.d | 8 + .../gdc.test/runnable/imports/testmod2a.d | 11 + .../gdc.test/runnable/imports/tlsa.d | 35 + .../imports/traits_getUnitTests_import.d | 6 + .../gdc.test/runnable/imports/ufcs5a.d | 13 + .../gdc.test/runnable/imports/ufcs5b.d | 19 + .../gdc.test/runnable/imports/ufcs5c.d | 19 + .../gdc.test/runnable/imports/ufcs5d.d | 13 + .../gdc.test/runnable/imports/ufcs5e.d | 13 + gcc/testsuite/gdc.test/runnable/inline.d | 1138 + gcc/testsuite/gdc.test/runnable/inline14560.d | 17 + gcc/testsuite/gdc.test/runnable/inner.d | 918 + gcc/testsuite/gdc.test/runnable/interface.d | 95 + gcc/testsuite/gdc.test/runnable/interface1.d | 203 + gcc/testsuite/gdc.test/runnable/interface2.d | 1233 ++ gcc/testsuite/gdc.test/runnable/interface3.d | 75 + gcc/testsuite/gdc.test/runnable/interpret.d | 3611 ++++ gcc/testsuite/gdc.test/runnable/interpret2.d | 148 + gcc/testsuite/gdc.test/runnable/issue8671.d | 5 + gcc/testsuite/gdc.test/runnable/lazy.d | 310 + .../gdc.test/runnable/ldc_github_1677.d | 29 + gcc/testsuite/gdc.test/runnable/lexer.d | 91 + gcc/testsuite/gdc.test/runnable/link10425.d | 22 + gcc/testsuite/gdc.test/runnable/link10920.d | 19 + gcc/testsuite/gdc.test/runnable/link11069a.d | 13 + gcc/testsuite/gdc.test/runnable/link11069b.d | 15 + gcc/testsuite/gdc.test/runnable/link11127.d | 6 + gcc/testsuite/gdc.test/runnable/link11395.d | 13 + gcc/testsuite/gdc.test/runnable/link11931.d | 11 + gcc/testsuite/gdc.test/runnable/link12010.d | 7 + gcc/testsuite/gdc.test/runnable/link12037.d | 8 + gcc/testsuite/gdc.test/runnable/link12144.d | 20 + gcc/testsuite/gdc.test/runnable/link13043.d | 5 + gcc/testsuite/gdc.test/runnable/link13350.d | 139 + gcc/testsuite/gdc.test/runnable/link13394.d | 13 + gcc/testsuite/gdc.test/runnable/link13400.d | 13 + gcc/testsuite/gdc.test/runnable/link13415.d | 11 + gcc/testsuite/gdc.test/runnable/link13843.d | 44 + gcc/testsuite/gdc.test/runnable/link14074a.d | 21 + gcc/testsuite/gdc.test/runnable/link14074b.d | 6 + gcc/testsuite/gdc.test/runnable/link14425.d | 9 + gcc/testsuite/gdc.test/runnable/link14541.d | 42 + gcc/testsuite/gdc.test/runnable/link14588.d | 10 + gcc/testsuite/gdc.test/runnable/link14814.d | 10 + gcc/testsuite/gdc.test/runnable/link14992.d | 22 + gcc/testsuite/gdc.test/runnable/link15017.d | 45 + gcc/testsuite/gdc.test/runnable/link15021.d | 18 + gcc/testsuite/gdc.test/runnable/link15149.d | 16 + gcc/testsuite/gdc.test/runnable/link2500.d | 19 + gcc/testsuite/gdc.test/runnable/link2644.d | 14 + gcc/testsuite/gdc.test/runnable/link6574.d | 45 + gcc/testsuite/gdc.test/runnable/link7745.d | 20 + gcc/testsuite/gdc.test/runnable/link7966.d | 17 + gcc/testsuite/gdc.test/runnable/link8023.d | 19 + gcc/testsuite/gdc.test/runnable/link9571.d | 9 + .../gdc.test/runnable/linktypeinfo.d | 34 + gcc/testsuite/gdc.test/runnable/literal.d | 238 + gcc/testsuite/gdc.test/runnable/loopunroll.d | 285 + gcc/testsuite/gdc.test/runnable/m1.d | 22 + gcc/testsuite/gdc.test/runnable/manboy.d | 20 + gcc/testsuite/gdc.test/runnable/mangle.d | 582 + gcc/testsuite/gdc.test/runnable/mars1.d | 1725 ++ gcc/testsuite/gdc.test/runnable/mixin1.d | 1470 ++ gcc/testsuite/gdc.test/runnable/mixin2.d | 363 + gcc/testsuite/gdc.test/runnable/mod1.d | 17 + gcc/testsuite/gdc.test/runnable/nan.d | 57 + gcc/testsuite/gdc.test/runnable/nested.d | 2806 +++ gcc/testsuite/gdc.test/runnable/newdel.d | 110 + gcc/testsuite/gdc.test/runnable/nogc.d | 74 + gcc/testsuite/gdc.test/runnable/nulltype.d | 185 + gcc/testsuite/gdc.test/runnable/opdisp.d | 297 + gcc/testsuite/gdc.test/runnable/opover.d | 1111 + gcc/testsuite/gdc.test/runnable/opover2.d | 2064 ++ gcc/testsuite/gdc.test/runnable/opover3.d | 184 + gcc/testsuite/gdc.test/runnable/overload.d | 1252 ++ gcc/testsuite/gdc.test/runnable/pi.d | 174 + gcc/testsuite/gdc.test/runnable/polysemous.d | 71 + gcc/testsuite/gdc.test/runnable/printargs.d | 18 + gcc/testsuite/gdc.test/runnable/property.d | 50 + gcc/testsuite/gdc.test/runnable/property2.d | 611 + gcc/testsuite/gdc.test/runnable/s2ir.d | 97 + gcc/testsuite/gdc.test/runnable/sctor.d | 432 + gcc/testsuite/gdc.test/runnable/sdtor.d | 4656 +++++ gcc/testsuite/gdc.test/runnable/statictor.d | 67 + gcc/testsuite/gdc.test/runnable/stress.d | 727 + gcc/testsuite/gdc.test/runnable/structlit.d | 1528 ++ gcc/testsuite/gdc.test/runnable/template1.d | 2124 ++ .../gdc.test/runnable/template13478.d | 10 + gcc/testsuite/gdc.test/runnable/template2.d | 114 + .../gdc.test/runnable/template2962.d | 30 + gcc/testsuite/gdc.test/runnable/template3.d | 241 + gcc/testsuite/gdc.test/runnable/template4.d | 1166 ++ gcc/testsuite/gdc.test/runnable/template8.d | 128 + gcc/testsuite/gdc.test/runnable/template9.d | 4967 +++++ gcc/testsuite/gdc.test/runnable/test10.d | 13 + gcc/testsuite/gdc.test/runnable/test10378.d | 13 + gcc/testsuite/gdc.test/runnable/test10441.d | 10 + gcc/testsuite/gdc.test/runnable/test10573.d | 4 + gcc/testsuite/gdc.test/runnable/test10736.d | 4 + gcc/testsuite/gdc.test/runnable/test10942.d | 26 + gcc/testsuite/gdc.test/runnable/test11.d | 1392 ++ gcc/testsuite/gdc.test/runnable/test11039.d | 23 + gcc/testsuite/gdc.test/runnable/test11239.d | 11 + gcc/testsuite/gdc.test/runnable/test11447a.d | 11 + gcc/testsuite/gdc.test/runnable/test11447b.d | 11 + gcc/testsuite/gdc.test/runnable/test11447c.d | 11 + gcc/testsuite/gdc.test/runnable/test11745.d | 14 + gcc/testsuite/gdc.test/runnable/test11863.d | 10 + gcc/testsuite/gdc.test/runnable/test12.d | 1249 ++ gcc/testsuite/gdc.test/runnable/test12197.d | 12 + gcc/testsuite/gdc.test/runnable/test12874.d | 18 + gcc/testsuite/gdc.test/runnable/test13.d | 13 + gcc/testsuite/gdc.test/runnable/test13504.d | 11 + gcc/testsuite/gdc.test/runnable/test13613.d | 74 + gcc/testsuite/gdc.test/runnable/test13944.d | 36 + gcc/testsuite/gdc.test/runnable/test14613.d | 19 + gcc/testsuite/gdc.test/runnable/test14874.d | 38 + gcc/testsuite/gdc.test/runnable/test14901.d | 20 + gcc/testsuite/gdc.test/runnable/test14903.d | 86 + gcc/testsuite/gdc.test/runnable/test15.d | 1441 ++ gcc/testsuite/gdc.test/runnable/test15079.d | 5 + gcc/testsuite/gdc.test/runnable/test15913.d | 7 + gcc/testsuite/gdc.test/runnable/test16.d | 386 + gcc/testsuite/gdc.test/runnable/test16115.d | 38 + gcc/testsuite/gdc.test/runnable/test16640.d | 11 + gcc/testsuite/gdc.test/runnable/test16980.d | 22 + gcc/testsuite/gdc.test/runnable/test17.d | 43 + gcc/testsuite/gdc.test/runnable/test17072.d | 13 + gcc/testsuite/gdc.test/runnable/test17073.d | 13 + gcc/testsuite/gdc.test/runnable/test17338.d | 25 + gcc/testsuite/gdc.test/runnable/test17684.d | 132 + gcc/testsuite/gdc.test/runnable/test17899.d | 19 + gcc/testsuite/gdc.test/runnable/test19.d | 480 + gcc/testsuite/gdc.test/runnable/test20.d | 1297 ++ gcc/testsuite/gdc.test/runnable/test21.d | 10 + gcc/testsuite/gdc.test/runnable/test22.d | 1308 ++ gcc/testsuite/gdc.test/runnable/test23.d | 1575 ++ gcc/testsuite/gdc.test/runnable/test24.d | 10 + gcc/testsuite/gdc.test/runnable/test27.d | 13 + gcc/testsuite/gdc.test/runnable/test28.d | 1320 ++ gcc/testsuite/gdc.test/runnable/test29.d | 13 + gcc/testsuite/gdc.test/runnable/test3.d | 41 + gcc/testsuite/gdc.test/runnable/test30.d | 10 + gcc/testsuite/gdc.test/runnable/test31.d | 18 + gcc/testsuite/gdc.test/runnable/test32.d | 11 + gcc/testsuite/gdc.test/runnable/test34.d | 1311 ++ gcc/testsuite/gdc.test/runnable/test3449.d | 112 + gcc/testsuite/gdc.test/runnable/test3574a.d | 13 + gcc/testsuite/gdc.test/runnable/test3574b.d | 13 + gcc/testsuite/gdc.test/runnable/test3574c.d | 13 + gcc/testsuite/gdc.test/runnable/test3574d.d | 13 + gcc/testsuite/gdc.test/runnable/test36.d | 109 + gcc/testsuite/gdc.test/runnable/test37.d | 13 + gcc/testsuite/gdc.test/runnable/test38.d | 13 + gcc/testsuite/gdc.test/runnable/test4.d | 1503 ++ gcc/testsuite/gdc.test/runnable/test40.d | 16 + gcc/testsuite/gdc.test/runnable/test41.d | 29 + gcc/testsuite/gdc.test/runnable/test42.d | 6494 ++++++ gcc/testsuite/gdc.test/runnable/test42a.d | 315 + gcc/testsuite/gdc.test/runnable/test435.d | 143 + gcc/testsuite/gdc.test/runnable/test45.d | 31 + gcc/testsuite/gdc.test/runnable/test46.d | 6 + gcc/testsuite/gdc.test/runnable/test48.d | 43 + gcc/testsuite/gdc.test/runnable/test49.d | 12 + gcc/testsuite/gdc.test/runnable/test5.d | 65 + gcc/testsuite/gdc.test/runnable/test52.d | 29 + gcc/testsuite/gdc.test/runnable/test5305.d | 7 + gcc/testsuite/gdc.test/runnable/test57.d | 10 + gcc/testsuite/gdc.test/runnable/test58.d | 9 + gcc/testsuite/gdc.test/runnable/test5943.d | 77 + gcc/testsuite/gdc.test/runnable/test60.d | 22 + gcc/testsuite/gdc.test/runnable/test61.d | 11 + gcc/testsuite/gdc.test/runnable/test6423.d | 25 + gcc/testsuite/gdc.test/runnable/test7.d | 734 + gcc/testsuite/gdc.test/runnable/test7452.d | 75 + gcc/testsuite/gdc.test/runnable/test7453.d | 14 + gcc/testsuite/gdc.test/runnable/test7494.d | 20 + gcc/testsuite/gdc.test/runnable/test7511.d | 421 + gcc/testsuite/gdc.test/runnable/test7595.d | 26 + gcc/testsuite/gdc.test/runnable/test7603.d | 30 + gcc/testsuite/gdc.test/runnable/test7618.d | 17 + gcc/testsuite/gdc.test/runnable/test7932.d | 31 + gcc/testsuite/gdc.test/runnable/test8.d | 977 + gcc/testsuite/gdc.test/runnable/test8182.d | 16 + gcc/testsuite/gdc.test/runnable/test8544.d | 17 + gcc/testsuite/gdc.test/runnable/test8997.d | 15 + gcc/testsuite/gdc.test/runnable/test9259.d | 13 + gcc/testsuite/gdc.test/runnable/test9271.d | 14 + gcc/testsuite/gdc.test/runnable/test9309.d | 37 + gcc/testsuite/gdc.test/runnable/test9495.d | 31 + gcc/testsuite/gdc.test/runnable/testaa.d | 1385 ++ gcc/testsuite/gdc.test/runnable/testaa2.d | 292 + gcc/testsuite/gdc.test/runnable/testaa3.d | 374 + gcc/testsuite/gdc.test/runnable/testabi.d | 926 + gcc/testsuite/gdc.test/runnable/testappend.d | 68 + .../gdc.test/runnable/testargtypes.d | 113 + gcc/testsuite/gdc.test/runnable/testarray.d | 65 + gcc/testsuite/gdc.test/runnable/testassign.d | 1199 ++ .../gdc.test/runnable/testbitarray.d | 16 + gcc/testsuite/gdc.test/runnable/testbounds.d | 510 + .../gdc.test/runnable/testbounds_off.d | 27 + .../gdc.test/runnable/testbounds_on.d | 27 + .../gdc.test/runnable/testbounds_safeonly.d | 27 + gcc/testsuite/gdc.test/runnable/testclass.d | 78 + gcc/testsuite/gdc.test/runnable/testconst.d | 3881 ++++ .../gdc.test/runnable/testconstsection.d | 61 + .../gdc.test/runnable/testcontracts.d | 1057 + gcc/testsuite/gdc.test/runnable/testdstress.d | 932 + gcc/testsuite/gdc.test/runnable/testdt.d | 172 + gcc/testsuite/gdc.test/runnable/testenum.d | 447 + gcc/testsuite/gdc.test/runnable/testfile.d | 24 + gcc/testsuite/gdc.test/runnable/testformat.d | 125 + gcc/testsuite/gdc.test/runnable/testgc2.d | 45 + gcc/testsuite/gdc.test/runnable/testgc3.d | 24 + .../gdc.test/runnable/testinvariant.d | 188 + gcc/testsuite/gdc.test/runnable/testkeyword.d | 152 + gcc/testsuite/gdc.test/runnable/testline.d | 43 + gcc/testsuite/gdc.test/runnable/testmain.d | 5 + gcc/testsuite/gdc.test/runnable/testminit.d | 20 + gcc/testsuite/gdc.test/runnable/testmmfile.d | 119 + gcc/testsuite/gdc.test/runnable/testmod1.d | 13 + gcc/testsuite/gdc.test/runnable/testmod2.d | 12 + gcc/testsuite/gdc.test/runnable/testmodule.d | 21 + gcc/testsuite/gdc.test/runnable/testpic.d | 54 + gcc/testsuite/gdc.test/runnable/testptrref.d | 168 + gcc/testsuite/gdc.test/runnable/testreturn.d | 200 + .../gdc.test/runnable/testrightthis.d | 687 + gcc/testsuite/gdc.test/runnable/testsafe.d | 507 + gcc/testsuite/gdc.test/runnable/testscope.d | 364 + gcc/testsuite/gdc.test/runnable/testscope2.d | 248 + gcc/testsuite/gdc.test/runnable/testsignals.d | 113 + gcc/testsuite/gdc.test/runnable/testsocket.d | 50 + gcc/testsuite/gdc.test/runnable/teststdio.d | 33 + gcc/testsuite/gdc.test/runnable/testswitch.d | 738 + gcc/testsuite/gdc.test/runnable/testthread.d | 63 + gcc/testsuite/gdc.test/runnable/testthread2.d | 108 + gcc/testsuite/gdc.test/runnable/testtypeid.d | 686 + gcc/testsuite/gdc.test/runnable/testv.d | 147 + gcc/testsuite/gdc.test/runnable/tls.d | 99 + gcc/testsuite/gdc.test/runnable/tls_dup.d | 104 + gcc/testsuite/gdc.test/runnable/traits.d | 1572 ++ .../runnable/traits_getPointerBitmap.d | 268 + .../gdc.test/runnable/traits_getUnitTests.d | 76 + .../runnable/traits_getVirtualIndex.d | 100 + gcc/testsuite/gdc.test/runnable/uda.d | 488 + gcc/testsuite/gdc.test/runnable/ufcs.d | 858 + gcc/testsuite/gdc.test/runnable/uniformctor.d | 157 + gcc/testsuite/gdc.test/runnable/variadic.d | 1174 ++ gcc/testsuite/gdc.test/runnable/version.d | 67 + gcc/testsuite/gdc.test/runnable/warning1.d | 191 + gcc/testsuite/gdc.test/runnable/wc.d | 50 + gcc/testsuite/gdc.test/runnable/wc2.d | 74 + gcc/testsuite/gdc.test/runnable/wc3.d | 72 + gcc/testsuite/gdc.test/runnable/xdtor.d | 86 + gcc/testsuite/gdc.test/runnable/xpostblit.d | 77 + gcc/testsuite/gdc.test/runnable/xtest46.d | 8285 ++++++++ gcc/testsuite/gdc.test/runnable/xtest55.d | 24 + gcc/testsuite/gdc.test/runnable/xtestenum.d | 165 + gcc/testsuite/lib/gdc-dg.exp | 88 + gcc/testsuite/lib/gdc.exp | 277 + libphobos/ChangeLog | 50 + libphobos/Makefile.am | 69 + libphobos/Makefile.in | 668 + libphobos/acinclude.m4 | 18 + libphobos/aclocal.m4 | 704 + libphobos/config.h.in | 56 + libphobos/configure | 17172 ++++++++++++++++ libphobos/configure.ac | 212 + libphobos/d_rules.am | 74 + libphobos/libdruntime/LICENSE | 26 + libphobos/libdruntime/Makefile.am | 386 + libphobos/libdruntime/Makefile.in | 2934 +++ libphobos/libdruntime/__entrypoint.di | 56 + libphobos/libdruntime/__main.di | 26 + libphobos/libdruntime/core/atomic.d | 1765 ++ libphobos/libdruntime/core/attribute.d | 57 + libphobos/libdruntime/core/bitop.d | 1004 + libphobos/libdruntime/core/checkedint.d | 781 + libphobos/libdruntime/core/cpuid.d | 1132 + libphobos/libdruntime/core/demangle.d | 2630 +++ libphobos/libdruntime/core/exception.d | 721 + libphobos/libdruntime/core/internal/abort.d | 45 + libphobos/libdruntime/core/internal/arrayop.d | 451 + libphobos/libdruntime/core/internal/convert.d | 638 + libphobos/libdruntime/core/internal/hash.d | 534 + .../libdruntime/core/internal/spinlock.d | 103 + libphobos/libdruntime/core/internal/string.d | 213 + libphobos/libdruntime/core/internal/traits.d | 212 + libphobos/libdruntime/core/math.d | 166 + libphobos/libdruntime/core/memory.d | 920 + libphobos/libdruntime/core/runtime.d | 908 + libphobos/libdruntime/core/simd.d | 553 + libphobos/libdruntime/core/stdc/assert_.d | 96 + libphobos/libdruntime/core/stdc/complex.d | 177 + libphobos/libdruntime/core/stdc/config.d | 233 + libphobos/libdruntime/core/stdc/ctype.d | 49 + libphobos/libdruntime/core/stdc/errno.d | 2085 ++ libphobos/libdruntime/core/stdc/errno_.c | 25 + libphobos/libdruntime/core/stdc/fenv.d | 850 + libphobos/libdruntime/core/stdc/float_.d | 92 + libphobos/libdruntime/core/stdc/inttypes.d | 443 + libphobos/libdruntime/core/stdc/limits.d | 61 + libphobos/libdruntime/core/stdc/locale.d | 292 + libphobos/libdruntime/core/stdc/math.d | 4789 +++++ libphobos/libdruntime/core/stdc/signal.d | 78 + libphobos/libdruntime/core/stdc/stdarg.d | 687 + libphobos/libdruntime/core/stdc/stddef.d | 36 + libphobos/libdruntime/core/stdc/stdint.d | 307 + libphobos/libdruntime/core/stdc/stdio.d | 1900 ++ libphobos/libdruntime/core/stdc/stdlib.d | 236 + libphobos/libdruntime/core/stdc/string.d | 126 + libphobos/libdruntime/core/stdc/tgmath.d | 2217 ++ libphobos/libdruntime/core/stdc/time.d | 254 + libphobos/libdruntime/core/stdc/wchar_.d | 269 + libphobos/libdruntime/core/stdc/wctype.d | 65 + libphobos/libdruntime/core/stdcpp/exception.d | 100 + libphobos/libdruntime/core/stdcpp/typeinfo.d | 147 + libphobos/libdruntime/core/sync/barrier.d | 151 + libphobos/libdruntime/core/sync/condition.d | 606 + libphobos/libdruntime/core/sync/config.d | 68 + libphobos/libdruntime/core/sync/exception.d | 32 + libphobos/libdruntime/core/sync/mutex.d | 425 + libphobos/libdruntime/core/sync/rwmutex.d | 528 + libphobos/libdruntime/core/sync/semaphore.d | 454 + libphobos/libdruntime/core/sys/bionic/fcntl.d | 5 + .../libdruntime/core/sys/bionic/unistd.d | 5 + libphobos/libdruntime/core/sys/darwin/dlfcn.d | 40 + .../libdruntime/core/sys/darwin/execinfo.d | 26 + .../libdruntime/core/sys/darwin/mach/dyld.d | 38 + .../core/sys/darwin/mach/getsect.d | 471 + .../core/sys/darwin/mach/kern_return.d | 82 + .../libdruntime/core/sys/darwin/mach/loader.d | 410 + .../libdruntime/core/sys/darwin/mach/port.d | 36 + .../core/sys/darwin/mach/semaphore.d | 67 + .../core/sys/darwin/mach/thread_act.d | 137 + .../libdruntime/core/sys/darwin/netinet/in_.d | 611 + .../libdruntime/core/sys/darwin/pthread.d | 60 + .../libdruntime/core/sys/darwin/sys/cdefs.d | 25 + .../libdruntime/core/sys/darwin/sys/event.d | 187 + .../libdruntime/core/sys/darwin/sys/mman.d | 112 + .../libdruntime/core/sys/dragonflybsd/dlfcn.d | 107 + .../core/sys/dragonflybsd/execinfo.d | 133 + .../core/sys/dragonflybsd/netinet/in_.d | 550 + .../core/sys/dragonflybsd/pthread_np.d | 45 + .../core/sys/dragonflybsd/sys/_bitset.d | 46 + .../core/sys/dragonflybsd/sys/_cpuset.d | 29 + .../core/sys/dragonflybsd/sys/cdefs.d | 16 + .../core/sys/dragonflybsd/sys/elf.d | 12 + .../core/sys/dragonflybsd/sys/elf32.d | 187 + .../core/sys/dragonflybsd/sys/elf64.d | 193 + .../core/sys/dragonflybsd/sys/elf_common.d | 676 + .../core/sys/dragonflybsd/sys/event.d | 124 + .../core/sys/dragonflybsd/sys/link_elf.d | 82 + .../core/sys/dragonflybsd/sys/mman.d | 127 + .../libdruntime/core/sys/dragonflybsd/time.d | 29 + .../libdruntime/core/sys/freebsd/dlfcn.d | 114 + .../libdruntime/core/sys/freebsd/execinfo.d | 133 + .../core/sys/freebsd/netinet/in_.d | 570 + .../libdruntime/core/sys/freebsd/pthread_np.d | 44 + .../core/sys/freebsd/sys/_bitset.d | 45 + .../core/sys/freebsd/sys/_cpuset.d | 29 + .../libdruntime/core/sys/freebsd/sys/cdefs.d | 16 + .../libdruntime/core/sys/freebsd/sys/elf.d | 11 + .../libdruntime/core/sys/freebsd/sys/elf32.d | 187 + .../libdruntime/core/sys/freebsd/sys/elf64.d | 193 + .../core/sys/freebsd/sys/elf_common.d | 854 + .../libdruntime/core/sys/freebsd/sys/event.d | 149 + .../core/sys/freebsd/sys/link_elf.d | 79 + .../libdruntime/core/sys/freebsd/sys/mman.d | 143 + .../libdruntime/core/sys/freebsd/sys/mount.d | 304 + libphobos/libdruntime/core/sys/freebsd/time.d | 25 + libphobos/libdruntime/core/sys/linux/config.d | 32 + libphobos/libdruntime/core/sys/linux/dlfcn.d | 331 + libphobos/libdruntime/core/sys/linux/elf.d | 2533 +++ libphobos/libdruntime/core/sys/linux/epoll.d | 147 + libphobos/libdruntime/core/sys/linux/errno.d | 19 + .../libdruntime/core/sys/linux/execinfo.d | 16 + libphobos/libdruntime/core/sys/linux/fcntl.d | 59 + .../libdruntime/core/sys/linux/ifaddrs.d | 54 + libphobos/libdruntime/core/sys/linux/link.d | 183 + .../libdruntime/core/sys/linux/netinet/in_.d | 393 + .../libdruntime/core/sys/linux/netinet/tcp.d | 79 + libphobos/libdruntime/core/sys/linux/sched.d | 80 + libphobos/libdruntime/core/sys/linux/stdio.d | 105 + .../libdruntime/core/sys/linux/sys/auxv.d | 223 + .../libdruntime/core/sys/linux/sys/eventfd.d | 91 + .../libdruntime/core/sys/linux/sys/file.d | 34 + .../libdruntime/core/sys/linux/sys/inotify.d | 112 + .../libdruntime/core/sys/linux/sys/mman.d | 734 + .../core/sys/linux/sys/netinet/tcp.d | 9 + .../libdruntime/core/sys/linux/sys/prctl.d | 162 + .../libdruntime/core/sys/linux/sys/signalfd.d | 42 + .../libdruntime/core/sys/linux/sys/socket.d | 158 + .../libdruntime/core/sys/linux/sys/sysinfo.d | 39 + .../libdruntime/core/sys/linux/sys/time.d | 68 + .../libdruntime/core/sys/linux/sys/xattr.d | 68 + .../libdruntime/core/sys/linux/termios.d | 30 + libphobos/libdruntime/core/sys/linux/time.d | 23 + .../libdruntime/core/sys/linux/timerfd.d | 24 + libphobos/libdruntime/core/sys/linux/tipc.d | 210 + libphobos/libdruntime/core/sys/linux/unistd.d | 20 + libphobos/libdruntime/core/sys/netbsd/dlfcn.d | 115 + .../libdruntime/core/sys/netbsd/execinfo.d | 133 + .../libdruntime/core/sys/netbsd/sys/elf.d | 10 + .../libdruntime/core/sys/netbsd/sys/elf32.d | 187 + .../libdruntime/core/sys/netbsd/sys/elf64.d | 193 + .../core/sys/netbsd/sys/elf_common.d | 859 + .../libdruntime/core/sys/netbsd/sys/event.d | 110 + .../core/sys/netbsd/sys/link_elf.d | 71 + .../libdruntime/core/sys/netbsd/sys/mman.d | 125 + libphobos/libdruntime/core/sys/netbsd/time.d | 21 + .../libdruntime/core/sys/openbsd/dlfcn.d | 30 + libphobos/libdruntime/core/sys/posix/aio.d | 251 + .../libdruntime/core/sys/posix/arpa/inet.d | 342 + libphobos/libdruntime/core/sys/posix/config.d | 128 + libphobos/libdruntime/core/sys/posix/dirent.d | 603 + libphobos/libdruntime/core/sys/posix/dlfcn.d | 348 + libphobos/libdruntime/core/sys/posix/fcntl.d | 1010 + libphobos/libdruntime/core/sys/posix/grp.d | 288 + libphobos/libdruntime/core/sys/posix/iconv.d | 59 + .../libdruntime/core/sys/posix/inttypes.d | 40 + libphobos/libdruntime/core/sys/posix/libgen.d | 22 + libphobos/libdruntime/core/sys/posix/mqueue.d | 218 + .../libdruntime/core/sys/posix/net/if_.d | 145 + libphobos/libdruntime/core/sys/posix/netdb.d | 1065 + .../libdruntime/core/sys/posix/netinet/in_.d | 1594 ++ .../libdruntime/core/sys/posix/netinet/tcp.d | 65 + libphobos/libdruntime/core/sys/posix/poll.d | 364 + .../libdruntime/core/sys/posix/pthread.d | 1710 ++ libphobos/libdruntime/core/sys/posix/pwd.d | 340 + libphobos/libdruntime/core/sys/posix/sched.d | 319 + .../libdruntime/core/sys/posix/semaphore.d | 226 + libphobos/libdruntime/core/sys/posix/setjmp.d | 483 + libphobos/libdruntime/core/sys/posix/signal.d | 3716 ++++ libphobos/libdruntime/core/sys/posix/stdio.d | 438 + libphobos/libdruntime/core/sys/posix/stdlib.d | 680 + .../libdruntime/core/sys/posix/sys/filio.d | 26 + .../libdruntime/core/sys/posix/sys/ioccom.d | 68 + .../libdruntime/core/sys/posix/sys/ioctl.d | 740 + .../libdruntime/core/sys/posix/sys/ipc.d | 265 + .../libdruntime/core/sys/posix/sys/mman.d | 839 + .../libdruntime/core/sys/posix/sys/msg.d | 381 + .../libdruntime/core/sys/posix/sys/resource.d | 654 + .../libdruntime/core/sys/posix/sys/select.d | 562 + .../libdruntime/core/sys/posix/sys/shm.d | 251 + .../libdruntime/core/sys/posix/sys/socket.d | 2327 +++ .../libdruntime/core/sys/posix/sys/stat.d | 1860 ++ .../libdruntime/core/sys/posix/sys/statvfs.d | 267 + .../libdruntime/core/sys/posix/sys/time.d | 266 + .../libdruntime/core/sys/posix/sys/ttycom.d | 110 + .../libdruntime/core/sys/posix/sys/types.d | 1378 ++ .../libdruntime/core/sys/posix/sys/uio.d | 151 + libphobos/libdruntime/core/sys/posix/sys/un.d | 97 + .../libdruntime/core/sys/posix/sys/utsname.d | 177 + .../libdruntime/core/sys/posix/sys/wait.d | 385 + libphobos/libdruntime/core/sys/posix/syslog.d | 461 + .../libdruntime/core/sys/posix/termios.d | 1213 ++ libphobos/libdruntime/core/sys/posix/time.d | 618 + .../libdruntime/core/sys/posix/ucontext.d | 1235 ++ libphobos/libdruntime/core/sys/posix/unistd.d | 2354 +++ libphobos/libdruntime/core/sys/posix/utime.d | 136 + .../libdruntime/core/sys/solaris/dlfcn.d | 112 + libphobos/libdruntime/core/sys/solaris/elf.d | 12 + .../libdruntime/core/sys/solaris/execinfo.d | 18 + .../libdruntime/core/sys/solaris/libelf.d | 166 + libphobos/libdruntime/core/sys/solaris/link.d | 173 + .../libdruntime/core/sys/solaris/sys/elf.d | 658 + .../core/sys/solaris/sys/elf_386.d | 82 + .../core/sys/solaris/sys/elf_SPARC.d | 181 + .../core/sys/solaris/sys/elf_amd64.d | 111 + .../core/sys/solaris/sys/elf_notes.d | 14 + .../core/sys/solaris/sys/elftypes.d | 28 + .../libdruntime/core/sys/solaris/sys/link.d | 426 + .../core/sys/solaris/sys/priocntl.d | 116 + .../core/sys/solaris/sys/procset.d | 53 + .../libdruntime/core/sys/solaris/sys/types.d | 24 + libphobos/libdruntime/core/sys/solaris/time.d | 18 + .../libdruntime/core/sys/windows/accctrl.d | 422 + .../libdruntime/core/sys/windows/aclapi.d | 139 + .../libdruntime/core/sys/windows/aclui.d | 120 + .../libdruntime/core/sys/windows/basetsd.d | 173 + .../libdruntime/core/sys/windows/basetyps.d | 27 + .../libdruntime/core/sys/windows/cderr.d | 50 + .../libdruntime/core/sys/windows/cguid.d | 13 + libphobos/libdruntime/core/sys/windows/com.d | 104 + .../libdruntime/core/sys/windows/comcat.d | 73 + .../libdruntime/core/sys/windows/commctrl.d | 6301 ++++++ .../libdruntime/core/sys/windows/commdlg.d | 728 + libphobos/libdruntime/core/sys/windows/core.d | 30 + libphobos/libdruntime/core/sys/windows/cpl.d | 85 + .../libdruntime/core/sys/windows/cplext.d | 19 + .../libdruntime/core/sys/windows/custcntl.d | 124 + .../libdruntime/core/sys/windows/dbghelp.d | 107 + .../core/sys/windows/dbghelp_types.d | 233 + libphobos/libdruntime/core/sys/windows/dbt.d | 191 + libphobos/libdruntime/core/sys/windows/dde.d | 215 + .../libdruntime/core/sys/windows/ddeml.d | 379 + .../libdruntime/core/sys/windows/dhcpcsdk.d | 58 + libphobos/libdruntime/core/sys/windows/dlgs.d | 191 + libphobos/libdruntime/core/sys/windows/dll.d | 515 + .../libdruntime/core/sys/windows/docobj.d | 133 + .../libdruntime/core/sys/windows/errorrep.d | 42 + .../libdruntime/core/sys/windows/exdisp.d | 127 + .../libdruntime/core/sys/windows/exdispid.d | 20 + .../libdruntime/core/sys/windows/httpext.d | 114 + .../libdruntime/core/sys/windows/idispids.d | 16 + .../libdruntime/core/sys/windows/imagehlp.d | 379 + libphobos/libdruntime/core/sys/windows/imm.d | 486 + .../libdruntime/core/sys/windows/intshcut.d | 91 + .../libdruntime/core/sys/windows/ipexport.d | 108 + .../libdruntime/core/sys/windows/iphlpapi.d | 62 + .../libdruntime/core/sys/windows/ipifcons.d | 38 + .../libdruntime/core/sys/windows/iprtrmib.d | 267 + .../libdruntime/core/sys/windows/iptypes.d | 96 + .../libdruntime/core/sys/windows/isguids.d | 17 + libphobos/libdruntime/core/sys/windows/lm.d | 47 + .../libdruntime/core/sys/windows/lmaccess.d | 759 + .../libdruntime/core/sys/windows/lmalert.d | 77 + .../libdruntime/core/sys/windows/lmapibuf.d | 21 + libphobos/libdruntime/core/sys/windows/lmat.d | 50 + .../libdruntime/core/sys/windows/lmaudit.d | 302 + .../libdruntime/core/sys/windows/lmbrowsr.d | 85 + .../libdruntime/core/sys/windows/lmchdev.d | 90 + .../libdruntime/core/sys/windows/lmconfig.d | 30 + .../libdruntime/core/sys/windows/lmcons.d | 88 + .../libdruntime/core/sys/windows/lmerr.d | 313 + .../libdruntime/core/sys/windows/lmerrlog.d | 222 + .../libdruntime/core/sys/windows/lmmsg.d | 43 + .../libdruntime/core/sys/windows/lmremutl.d | 60 + .../libdruntime/core/sys/windows/lmrepl.d | 134 + .../libdruntime/core/sys/windows/lmserver.d | 941 + .../libdruntime/core/sys/windows/lmshare.d | 197 + .../libdruntime/core/sys/windows/lmsname.d | 65 + .../libdruntime/core/sys/windows/lmstats.d | 121 + .../libdruntime/core/sys/windows/lmsvc.d | 156 + .../libdruntime/core/sys/windows/lmuse.d | 80 + .../libdruntime/core/sys/windows/lmuseflg.d | 16 + .../libdruntime/core/sys/windows/lmwksta.d | 390 + .../libdruntime/core/sys/windows/lzexpand.d | 50 + libphobos/libdruntime/core/sys/windows/mapi.d | 170 + .../libdruntime/core/sys/windows/mciavi.d | 40 + libphobos/libdruntime/core/sys/windows/mcx.d | 99 + .../libdruntime/core/sys/windows/mgmtapi.d | 47 + .../libdruntime/core/sys/windows/mmsystem.d | 2298 +++ .../libdruntime/core/sys/windows/msacm.d | 173 + .../libdruntime/core/sys/windows/mshtml.d | 536 + .../libdruntime/core/sys/windows/mswsock.d | 191 + libphobos/libdruntime/core/sys/windows/nb30.d | 240 + .../libdruntime/core/sys/windows/nddeapi.d | 164 + .../libdruntime/core/sys/windows/nspapi.d | 143 + .../libdruntime/core/sys/windows/ntdef.d | 80 + .../libdruntime/core/sys/windows/ntdll.d | 22 + .../libdruntime/core/sys/windows/ntldap.d | 60 + .../libdruntime/core/sys/windows/ntsecapi.d | 796 + .../libdruntime/core/sys/windows/ntsecpkg.d | 446 + .../libdruntime/core/sys/windows/oaidl.d | 677 + .../libdruntime/core/sys/windows/objbase.d | 207 + .../libdruntime/core/sys/windows/objfwd.d | 103 + .../libdruntime/core/sys/windows/objidl.d | 1307 ++ .../libdruntime/core/sys/windows/objsafe.d | 23 + .../libdruntime/core/sys/windows/ocidl.d | 472 + .../libdruntime/core/sys/windows/odbcinst.d | 168 + libphobos/libdruntime/core/sys/windows/ole.d | 366 + libphobos/libdruntime/core/sys/windows/ole2.d | 118 + .../libdruntime/core/sys/windows/ole2ver.d | 14 + .../libdruntime/core/sys/windows/oleacc.d | 216 + .../libdruntime/core/sys/windows/oleauto.d | 684 + .../libdruntime/core/sys/windows/olectl.d | 402 + .../libdruntime/core/sys/windows/olectlid.d | 13 + .../libdruntime/core/sys/windows/oledlg.d | 994 + .../libdruntime/core/sys/windows/oleidl.d | 270 + libphobos/libdruntime/core/sys/windows/pbt.d | 30 + .../libdruntime/core/sys/windows/powrprof.d | 140 + .../libdruntime/core/sys/windows/prsht.d | 448 + .../libdruntime/core/sys/windows/psapi.d | 160 + libphobos/libdruntime/core/sys/windows/rapi.d | 54 + libphobos/libdruntime/core/sys/windows/ras.d | 1025 + .../libdruntime/core/sys/windows/rasdlg.d | 166 + .../libdruntime/core/sys/windows/raserror.d | 215 + .../libdruntime/core/sys/windows/rassapi.d | 220 + .../libdruntime/core/sys/windows/reason.d | 63 + .../libdruntime/core/sys/windows/regstr.d | 816 + .../libdruntime/core/sys/windows/richedit.d | 604 + .../libdruntime/core/sys/windows/richole.d | 101 + libphobos/libdruntime/core/sys/windows/rpc.d | 31 + .../libdruntime/core/sys/windows/rpcdce.d | 414 + .../libdruntime/core/sys/windows/rpcdce2.d | 83 + .../libdruntime/core/sys/windows/rpcdcep.d | 153 + .../libdruntime/core/sys/windows/rpcndr.d | 576 + .../libdruntime/core/sys/windows/rpcnsi.d | 151 + .../libdruntime/core/sys/windows/rpcnsip.d | 29 + .../libdruntime/core/sys/windows/rpcnterr.d | 31 + .../libdruntime/core/sys/windows/schannel.d | 106 + .../libdruntime/core/sys/windows/secext.d | 54 + .../libdruntime/core/sys/windows/security.d | 46 + .../libdruntime/core/sys/windows/servprov.d | 16 + .../libdruntime/core/sys/windows/setupapi.d | 1984 ++ .../libdruntime/core/sys/windows/shellapi.d | 433 + .../libdruntime/core/sys/windows/shldisp.d | 27 + .../libdruntime/core/sys/windows/shlguid.d | 18 + .../libdruntime/core/sys/windows/shlobj.d | 1358 ++ .../libdruntime/core/sys/windows/shlwapi.d | 732 + libphobos/libdruntime/core/sys/windows/snmp.d | 274 + libphobos/libdruntime/core/sys/windows/sql.d | 434 + .../libdruntime/core/sys/windows/sqlext.d | 1295 ++ .../libdruntime/core/sys/windows/sqltypes.d | 144 + .../libdruntime/core/sys/windows/sqlucode.d | 158 + libphobos/libdruntime/core/sys/windows/sspi.d | 382 + .../libdruntime/core/sys/windows/stacktrace.d | 417 + libphobos/libdruntime/core/sys/windows/stat.d | 50 + .../libdruntime/core/sys/windows/subauth.d | 275 + .../libdruntime/core/sys/windows/threadaux.d | 385 + .../libdruntime/core/sys/windows/tlhelp32.d | 172 + .../libdruntime/core/sys/windows/tmschema.d | 758 + .../libdruntime/core/sys/windows/unknwn.d | 55 + libphobos/libdruntime/core/sys/windows/uuid.d | 4077 ++++ libphobos/libdruntime/core/sys/windows/vfw.d | 2400 +++ .../libdruntime/core/sys/windows/w32api.d | 97 + .../libdruntime/core/sys/windows/winbase.d | 2842 +++ .../libdruntime/core/sys/windows/winber.d | 70 + .../libdruntime/core/sys/windows/wincon.d | 316 + .../libdruntime/core/sys/windows/wincrypt.d | 902 + .../libdruntime/core/sys/windows/windef.d | 151 + .../libdruntime/core/sys/windows/windows.d | 65 + .../libdruntime/core/sys/windows/winerror.d | 2312 +++ .../libdruntime/core/sys/windows/wingdi.d | 4585 +++++ .../libdruntime/core/sys/windows/winhttp.d | 848 + .../libdruntime/core/sys/windows/wininet.d | 1249 ++ .../libdruntime/core/sys/windows/winioctl.d | 712 + .../libdruntime/core/sys/windows/winldap.d | 861 + .../libdruntime/core/sys/windows/winnetwk.d | 440 + .../libdruntime/core/sys/windows/winnls.d | 811 + .../libdruntime/core/sys/windows/winnt.d | 4132 ++++ .../libdruntime/core/sys/windows/winperf.d | 168 + .../libdruntime/core/sys/windows/winreg.d | 255 + .../libdruntime/core/sys/windows/winsock2.d | 722 + .../libdruntime/core/sys/windows/winspool.d | 964 + .../libdruntime/core/sys/windows/winsvc.d | 427 + .../libdruntime/core/sys/windows/winuser.d | 4909 +++++ .../libdruntime/core/sys/windows/winver.d | 174 + .../libdruntime/core/sys/windows/wtsapi32.d | 435 + .../libdruntime/core/sys/windows/wtypes.d | 235 + libphobos/libdruntime/core/thread.d | 5569 +++++ libphobos/libdruntime/core/threadasm.S | 658 + libphobos/libdruntime/core/time.d | 4718 +++++ libphobos/libdruntime/core/vararg.d | 19 + libphobos/libdruntime/gc/bits.d | 129 + libphobos/libdruntime/gc/config.d | 291 + libphobos/libdruntime/gc/gcinterface.d | 190 + .../libdruntime/gc/impl/conservative/gc.d | 3419 +++ libphobos/libdruntime/gc/impl/manual/gc.d | 274 + libphobos/libdruntime/gc/os.d | 210 + libphobos/libdruntime/gc/pooltable.d | 285 + libphobos/libdruntime/gc/proxy.d | 239 + libphobos/libdruntime/gcc/attribute.d | 33 + libphobos/libdruntime/gcc/backtrace.d | 613 + libphobos/libdruntime/gcc/builtins.d | 44 + libphobos/libdruntime/gcc/config.d.in | 48 + libphobos/libdruntime/gcc/deh.d | 991 + libphobos/libdruntime/gcc/libbacktrace.d.in | 73 + libphobos/libdruntime/gcc/unwind/arm.d | 71 + libphobos/libdruntime/gcc/unwind/arm_common.d | 244 + libphobos/libdruntime/gcc/unwind/c6x.d | 52 + libphobos/libdruntime/gcc/unwind/generic.d | 274 + libphobos/libdruntime/gcc/unwind/package.d | 37 + libphobos/libdruntime/gcc/unwind/pe.d | 238 + libphobos/libdruntime/gcstub/gc.d | 388 + libphobos/libdruntime/object.d | 4011 ++++ libphobos/libdruntime/rt/aApply.d | 904 + libphobos/libdruntime/rt/aApplyR.d | 958 + libphobos/libdruntime/rt/aaA.d | 1015 + libphobos/libdruntime/rt/adi.d | 332 + libphobos/libdruntime/rt/arrayassign.d | 261 + libphobos/libdruntime/rt/arraycast.d | 52 + libphobos/libdruntime/rt/arraycat.d | 30 + libphobos/libdruntime/rt/bss_section.c | 21 + libphobos/libdruntime/rt/cast_.d | 141 + libphobos/libdruntime/rt/config.d | 147 + libphobos/libdruntime/rt/critical_.d | 68 + libphobos/libdruntime/rt/deh.d | 42 + libphobos/libdruntime/rt/dmain2.d | 631 + libphobos/libdruntime/rt/dylib_fixes.c | 28 + libphobos/libdruntime/rt/invariant.d | 36 + libphobos/libdruntime/rt/lifetime.d | 2712 +++ libphobos/libdruntime/rt/memory.d | 26 + libphobos/libdruntime/rt/minfo.d | 1117 + libphobos/libdruntime/rt/monitor_.d | 326 + libphobos/libdruntime/rt/obj.d | 35 + libphobos/libdruntime/rt/qsort.d | 118 + libphobos/libdruntime/rt/sections.d | 91 + libphobos/libdruntime/rt/sections_android.d | 188 + .../libdruntime/rt/sections_elf_shared.d | 1000 + libphobos/libdruntime/rt/sections_osx.d | 277 + libphobos/libdruntime/rt/sections_solaris.d | 114 + libphobos/libdruntime/rt/sections_win32.d | 173 + libphobos/libdruntime/rt/sections_win64.d | 311 + libphobos/libdruntime/rt/switch_.d | 424 + libphobos/libdruntime/rt/tlsgc.d | 81 + .../libdruntime/rt/typeinfo/ti_Acdouble.d | 47 + .../libdruntime/rt/typeinfo/ti_Acfloat.d | 47 + libphobos/libdruntime/rt/typeinfo/ti_Acreal.d | 47 + .../libdruntime/rt/typeinfo/ti_Adouble.d | 61 + libphobos/libdruntime/rt/typeinfo/ti_Afloat.d | 61 + libphobos/libdruntime/rt/typeinfo/ti_Ag.d | 199 + libphobos/libdruntime/rt/typeinfo/ti_Aint.d | 151 + libphobos/libdruntime/rt/typeinfo/ti_Along.d | 103 + libphobos/libdruntime/rt/typeinfo/ti_Areal.d | 61 + libphobos/libdruntime/rt/typeinfo/ti_Ashort.d | 113 + libphobos/libdruntime/rt/typeinfo/ti_C.d | 75 + libphobos/libdruntime/rt/typeinfo/ti_byte.d | 60 + .../libdruntime/rt/typeinfo/ti_cdouble.d | 74 + libphobos/libdruntime/rt/typeinfo/ti_cent.d | 73 + libphobos/libdruntime/rt/typeinfo/ti_cfloat.d | 73 + libphobos/libdruntime/rt/typeinfo/ti_char.d | 62 + libphobos/libdruntime/rt/typeinfo/ti_creal.d | 74 + libphobos/libdruntime/rt/typeinfo/ti_dchar.d | 62 + .../libdruntime/rt/typeinfo/ti_delegate.d | 64 + libphobos/libdruntime/rt/typeinfo/ti_double.d | 76 + libphobos/libdruntime/rt/typeinfo/ti_float.d | 71 + .../libdruntime/rt/typeinfo/ti_idouble.d | 27 + libphobos/libdruntime/rt/typeinfo/ti_ifloat.d | 27 + libphobos/libdruntime/rt/typeinfo/ti_int.d | 64 + libphobos/libdruntime/rt/typeinfo/ti_ireal.d | 27 + libphobos/libdruntime/rt/typeinfo/ti_long.d | 71 + libphobos/libdruntime/rt/typeinfo/ti_n.d | 58 + libphobos/libdruntime/rt/typeinfo/ti_ptr.d | 64 + libphobos/libdruntime/rt/typeinfo/ti_real.d | 67 + libphobos/libdruntime/rt/typeinfo/ti_short.d | 60 + libphobos/libdruntime/rt/typeinfo/ti_ubyte.d | 70 + libphobos/libdruntime/rt/typeinfo/ti_ucent.d | 73 + libphobos/libdruntime/rt/typeinfo/ti_uint.d | 64 + libphobos/libdruntime/rt/typeinfo/ti_ulong.d | 71 + libphobos/libdruntime/rt/typeinfo/ti_ushort.d | 60 + libphobos/libdruntime/rt/typeinfo/ti_void.d | 65 + libphobos/libdruntime/rt/typeinfo/ti_wchar.d | 62 + libphobos/libdruntime/rt/util/array.d | 72 + .../libdruntime/rt/util/container/array.d | 232 + .../libdruntime/rt/util/container/common.d | 66 + .../libdruntime/rt/util/container/hashtab.d | 330 + .../libdruntime/rt/util/container/treap.d | 338 + libphobos/libdruntime/rt/util/hash.d | 107 + libphobos/libdruntime/rt/util/random.d | 51 + libphobos/libdruntime/rt/util/typeinfo.d | 291 + libphobos/libdruntime/rt/util/utf.d | 920 + libphobos/m4/autoconf.m4 | 132 + libphobos/m4/druntime.m4 | 115 + libphobos/m4/druntime/cpu.m4 | 95 + libphobos/m4/druntime/libraries.m4 | 163 + libphobos/m4/druntime/os.m4 | 184 + libphobos/m4/gcc_support.m4 | 33 + libphobos/m4/gdc.m4 | 18 + libphobos/m4/libtool.m4 | 78 + libphobos/src/LICENSE_1_0.txt | 23 + libphobos/src/Makefile.am | 180 + libphobos/src/Makefile.in | 1824 ++ libphobos/src/etc/c/curl.d | 2336 +++ libphobos/src/etc/c/sqlite3.d | 2126 ++ libphobos/src/etc/c/zlib.d | 1788 ++ libphobos/src/index.d | 526 + libphobos/src/libgphobos.spec.in | 8 + libphobos/src/std/algorithm/comparison.d | 2159 ++ libphobos/src/std/algorithm/internal.d | 77 + libphobos/src/std/algorithm/iteration.d | 5187 +++++ libphobos/src/std/algorithm/mutation.d | 2909 +++ libphobos/src/std/algorithm/package.d | 198 + libphobos/src/std/algorithm/searching.d | 4600 +++++ libphobos/src/std/algorithm/setops.d | 1521 ++ libphobos/src/std/algorithm/sorting.d | 4468 ++++ libphobos/src/std/array.d | 3775 ++++ libphobos/src/std/ascii.d | 729 + libphobos/src/std/base64.d | 2099 ++ libphobos/src/std/bigint.d | 1705 ++ libphobos/src/std/bitmanip.d | 4009 ++++ libphobos/src/std/compiler.d | 58 + libphobos/src/std/complex.d | 994 + libphobos/src/std/concurrency.d | 2531 +++ libphobos/src/std/container/array.d | 2419 +++ libphobos/src/std/container/binaryheap.d | 595 + libphobos/src/std/container/dlist.d | 1039 + libphobos/src/std/container/package.d | 1156 ++ libphobos/src/std/container/rbtree.d | 2065 ++ libphobos/src/std/container/slist.d | 846 + libphobos/src/std/container/util.d | 189 + libphobos/src/std/conv.d | 6290 ++++++ libphobos/src/std/csv.d | 1701 ++ libphobos/src/std/datetime/date.d | 10580 ++++++++++ libphobos/src/std/datetime/interval.d | 9131 ++++++++ libphobos/src/std/datetime/package.d | 733 + libphobos/src/std/datetime/stopwatch.d | 428 + libphobos/src/std/datetime/systime.d | 11151 ++++++++++ libphobos/src/std/datetime/timezone.d | 4235 ++++ libphobos/src/std/demangle.d | 89 + libphobos/src/std/digest/crc.d | 705 + libphobos/src/std/digest/digest.d | 21 + libphobos/src/std/digest/hmac.d | 336 + libphobos/src/std/digest/md.d | 590 + libphobos/src/std/digest/murmurhash.d | 755 + libphobos/src/std/digest/package.d | 1171 ++ libphobos/src/std/digest/ripemd.d | 762 + libphobos/src/std/digest/sha.d | 1291 ++ libphobos/src/std/encoding.d | 3662 ++++ libphobos/src/std/exception.d | 2316 +++ .../building_blocks/affix_allocator.d | 441 + .../building_blocks/allocator_list.d | 640 + .../building_blocks/bitmapped_block.d | 1423 ++ .../allocator/building_blocks/bucketizer.d | 241 + .../building_blocks/fallback_allocator.d | 355 + .../allocator/building_blocks/free_list.d | 1205 ++ .../allocator/building_blocks/free_tree.d | 487 + .../building_blocks/kernighan_ritchie.d | 882 + .../building_blocks/null_allocator.d | 85 + .../allocator/building_blocks/package.d | 313 + .../allocator/building_blocks/quantizer.d | 234 + .../allocator/building_blocks/region.d | 784 + .../building_blocks/scoped_allocator.d | 221 + .../allocator/building_blocks/segregator.d | 361 + .../building_blocks/stats_collector.d | 735 + .../src/std/experimental/allocator/common.d | 683 + .../std/experimental/allocator/gc_allocator.d | 167 + .../std/experimental/allocator/mallocator.d | 387 + .../experimental/allocator/mmap_allocator.d | 79 + .../src/std/experimental/allocator/package.d | 3028 +++ .../src/std/experimental/allocator/showcase.d | 92 + .../src/std/experimental/allocator/typed.d | 423 + libphobos/src/std/experimental/checkedint.d | 3063 +++ libphobos/src/std/experimental/logger/core.d | 3187 +++ .../src/std/experimental/logger/filelogger.d | 265 + .../src/std/experimental/logger/multilogger.d | 197 + .../src/std/experimental/logger/nulllogger.d | 39 + .../src/std/experimental/logger/package.d | 185 + libphobos/src/std/experimental/note.md | 1 + libphobos/src/std/experimental/typecons.d | 1078 + libphobos/src/std/file.d | 4325 ++++ libphobos/src/std/format.d | 6028 ++++++ libphobos/src/std/functional.d | 1564 ++ libphobos/src/std/getopt.d | 1857 ++ libphobos/src/std/internal/cstring.d | 267 + libphobos/src/std/internal/digest/sha_SSSE3.d | 729 + libphobos/src/std/internal/math/biguintcore.d | 2571 +++ .../src/std/internal/math/biguintnoasm.d | 370 + libphobos/src/std/internal/math/biguintx86.d | 1353 ++ .../src/std/internal/math/errorfunction.d | 1145 ++ .../src/std/internal/math/gammafunction.d | 1834 ++ libphobos/src/std/internal/scopebuffer.d | 398 + libphobos/src/std/internal/test/dummyrange.d | 565 + libphobos/src/std/internal/test/range.d | 25 + libphobos/src/std/internal/test/uda.d | 16 + libphobos/src/std/internal/unicode_comp.d | 2984 +++ libphobos/src/std/internal/unicode_decomp.d | 5301 +++++ libphobos/src/std/internal/unicode_grapheme.d | 293 + libphobos/src/std/internal/unicode_norm.d | 548 + libphobos/src/std/internal/unicode_tables.d | 11081 ++++++++++ libphobos/src/std/internal/windows/advapi32.d | 69 + libphobos/src/std/json.d | 1859 ++ libphobos/src/std/math.d | 8413 ++++++++ libphobos/src/std/mathspecial.d | 361 + libphobos/src/std/meta.d | 1679 ++ libphobos/src/std/mmfile.d | 721 + libphobos/src/std/net/curl.d | 5109 +++++ libphobos/src/std/net/isemail.d | 1864 ++ libphobos/src/std/numeric.d | 3467 ++++ libphobos/src/std/outbuffer.d | 418 + libphobos/src/std/parallelism.d | 4636 +++++ libphobos/src/std/path.d | 4115 ++++ libphobos/src/std/process.d | 4047 ++++ libphobos/src/std/random.d | 3344 +++ libphobos/src/std/range/interfaces.d | 567 + libphobos/src/std/range/package.d | 12019 +++++++++++ libphobos/src/std/range/primitives.d | 2320 +++ .../src/std/regex/internal/backtracking.d | 1495 ++ libphobos/src/std/regex/internal/generator.d | 187 + libphobos/src/std/regex/internal/ir.d | 788 + libphobos/src/std/regex/internal/kickstart.d | 579 + libphobos/src/std/regex/internal/parser.d | 1751 ++ libphobos/src/std/regex/internal/tests.d | 1120 + libphobos/src/std/regex/internal/thompson.d | 1188 ++ libphobos/src/std/regex/package.d | 1735 ++ libphobos/src/std/signals.d | 708 + libphobos/src/std/socket.d | 3670 ++++ libphobos/src/std/stdint.d | 131 + libphobos/src/std/stdio.d | 5159 +++++ libphobos/src/std/string.d | 6952 +++++++ libphobos/src/std/system.d | 74 + libphobos/src/std/traits.d | 8058 ++++++++ libphobos/src/std/typecons.d | 8029 ++++++++ libphobos/src/std/typetuple.d | 40 + libphobos/src/std/uni.d | 9756 +++++++++ libphobos/src/std/uri.d | 592 + libphobos/src/std/utf.d | 4058 ++++ libphobos/src/std/uuid.d | 1731 ++ libphobos/src/std/variant.d | 2771 +++ libphobos/src/std/windows/charset.d | 122 + libphobos/src/std/windows/registry.d | 1868 ++ libphobos/src/std/windows/syserror.d | 201 + libphobos/src/std/xml.d | 3103 +++ libphobos/src/std/zip.d | 990 + libphobos/src/std/zlib.d | 760 + libphobos/testsuite/Makefile.am | 32 + libphobos/testsuite/Makefile.in | 454 + libphobos/testsuite/config/default.exp | 17 + libphobos/testsuite/lib/libphobos-dg.exp | 52 + libphobos/testsuite/lib/libphobos.exp | 193 + .../libphobos.allocations/allocations.exp | 29 + .../overflow_from_existing.d | 8 + .../overflow_from_zero.d | 8 + .../testsuite/libphobos.cycles/cycles.exp | 53 + libphobos/testsuite/libphobos.cycles/mod1.d | 9 + libphobos/testsuite/libphobos.cycles/mod2.d | 9 + libphobos/testsuite/libphobos.cycles/mod3.d | 9 + .../testsuite/libphobos.exceptions/chain.d | 79 + .../libphobos.exceptions/exceptions.exp | 29 + .../invalid_memory_operation.d | 14 + .../libphobos.exceptions/line_trace.d | 19 + .../libphobos.exceptions/static_dtor.d | 16 + .../libphobos.exceptions/stderr_msg.d | 6 + .../libphobos.exceptions/unittest_assert.d | 11 + .../libphobos.exceptions/unknown_gc.d | 9 + .../libphobos.init_fini/init_fini.exp | 29 + .../libphobos.init_fini/runtime_args.d | 13 + .../libphobos.init_fini/thread_join.d | 18 + .../testsuite/libphobos.shared/finalize.d | 63 + libphobos/testsuite/libphobos.shared/host.c | 60 + libphobos/testsuite/libphobos.shared/lib.d | 133 + .../testsuite/libphobos.shared/lib_13414.d | 4 + .../testsuite/libphobos.shared/liblinkdep.d | 6 + .../testsuite/libphobos.shared/libloaddep.d | 13 + libphobos/testsuite/libphobos.shared/link.d | 64 + libphobos/testsuite/libphobos.shared/linkD.c | 14 + libphobos/testsuite/libphobos.shared/linkDR.c | 28 + .../testsuite/libphobos.shared/link_linkdep.d | 6 + .../testsuite/libphobos.shared/link_loaddep.d | 7 + .../libphobos.shared/link_mod_collision.d | 5 + libphobos/testsuite/libphobos.shared/load.d | 147 + libphobos/testsuite/libphobos.shared/loadDR.c | 39 + .../testsuite/libphobos.shared/load_13414.d | 30 + .../testsuite/libphobos.shared/load_linkdep.d | 18 + .../testsuite/libphobos.shared/load_loaddep.d | 17 + .../libphobos.shared/load_mod_collision.d | 14 + libphobos/testsuite/libphobos.shared/plugin.d | 73 + .../testsuite/libphobos.shared/shared.exp | 108 + .../libphobos.thread/fiber_guard_page.d | 47 + .../testsuite/libphobos.thread/thread.exp | 29 + .../testsuite/libphobos.typeinfo/comparison.d | 78 + .../testsuite/libphobos.typeinfo/typeinfo.exp | 29 + .../libphobos.unittests/unittests.exp | 53 + libphobos/testsuite/test_runner.d | 95 + libphobos/testsuite/testsuite_flags.in | 52 + 3180 files changed, 859714 insertions(+), 26 deletions(-) create mode 100644 gcc/config/aarch64/aarch64-d.c create mode 100644 gcc/config/arm/arm-d.c create mode 100644 gcc/config/default-d.c create mode 100644 gcc/config/glibc-d.c create mode 100644 gcc/config/i386/i386-d.c create mode 100644 gcc/config/mips/mips-d.c create mode 100644 gcc/config/powerpcspe/powerpcspe-d.c create mode 100644 gcc/config/riscv/riscv-d.c create mode 100644 gcc/config/rs6000/rs6000-d.c create mode 100644 gcc/config/s390/s390-d.c create mode 100644 gcc/config/sparc/sparc-d.c create mode 100644 gcc/d/ChangeLog create mode 100644 gcc/d/ChangeLog-2006 create mode 100644 gcc/d/ChangeLog-2007 create mode 100644 gcc/d/ChangeLog-2008 create mode 100644 gcc/d/ChangeLog-2009 create mode 100644 gcc/d/ChangeLog-2010 create mode 100644 gcc/d/ChangeLog-2011 create mode 100644 gcc/d/ChangeLog-2012 create mode 100644 gcc/d/ChangeLog-2013 create mode 100644 gcc/d/ChangeLog-2014 create mode 100644 gcc/d/ChangeLog-2015 create mode 100644 gcc/d/ChangeLog-2016 create mode 100644 gcc/d/ChangeLog-2017 create mode 100644 gcc/d/Make-lang.in create mode 100644 gcc/d/config-lang.in create mode 100644 gcc/d/d-attribs.cc create mode 100644 gcc/d/d-builtins.cc create mode 100644 gcc/d/d-codegen.cc create mode 100644 gcc/d/d-convert.cc create mode 100644 gcc/d/d-diagnostic.cc create mode 100644 gcc/d/d-frontend.cc create mode 100644 gcc/d/d-incpath.cc create mode 100644 gcc/d/d-lang.cc create mode 100644 gcc/d/d-longdouble.cc create mode 100644 gcc/d/d-spec.cc create mode 100644 gcc/d/d-target-def.h create mode 100644 gcc/d/d-target.cc create mode 100644 gcc/d/d-target.def create mode 100644 gcc/d/d-target.h create mode 100644 gcc/d/d-tree.def create mode 100644 gcc/d/d-tree.h create mode 100644 gcc/d/decl.cc create mode 100644 gcc/d/dmd/access.c create mode 100644 gcc/d/dmd/aggregate.h create mode 100644 gcc/d/dmd/aliasthis.c create mode 100644 gcc/d/dmd/aliasthis.h create mode 100644 gcc/d/dmd/apply.c create mode 100644 gcc/d/dmd/argtypes.c create mode 100644 gcc/d/dmd/arrayop.c create mode 100644 gcc/d/dmd/arraytypes.h create mode 100644 gcc/d/dmd/attrib.c create mode 100644 gcc/d/dmd/attrib.h create mode 100644 gcc/d/dmd/blockexit.c create mode 100644 gcc/d/dmd/boostlicense.txt create mode 100644 gcc/d/dmd/canthrow.c create mode 100644 gcc/d/dmd/checkedint.c create mode 100644 gcc/d/dmd/checkedint.h create mode 100644 gcc/d/dmd/clone.c create mode 100644 gcc/d/dmd/compiler.h create mode 100644 gcc/d/dmd/complex_t.h create mode 100644 gcc/d/dmd/cond.c create mode 100644 gcc/d/dmd/cond.h create mode 100644 gcc/d/dmd/constfold.c create mode 100644 gcc/d/dmd/cppmangle.c create mode 100644 gcc/d/dmd/ctfe.h create mode 100644 gcc/d/dmd/ctfeexpr.c create mode 100644 gcc/d/dmd/dcast.c create mode 100644 gcc/d/dmd/dclass.c create mode 100644 gcc/d/dmd/declaration.c create mode 100644 gcc/d/dmd/declaration.h create mode 100644 gcc/d/dmd/delegatize.c create mode 100644 gcc/d/dmd/denum.c create mode 100644 gcc/d/dmd/dimport.c create mode 100644 gcc/d/dmd/dinterpret.c create mode 100644 gcc/d/dmd/dmacro.c create mode 100644 gcc/d/dmd/dmangle.c create mode 100644 gcc/d/dmd/dmodule.c create mode 100644 gcc/d/dmd/doc.c create mode 100644 gcc/d/dmd/doc.h create mode 100644 gcc/d/dmd/dscope.c create mode 100644 gcc/d/dmd/dstruct.c create mode 100644 gcc/d/dmd/dsymbol.c create mode 100644 gcc/d/dmd/dsymbol.h create mode 100644 gcc/d/dmd/dtemplate.c create mode 100644 gcc/d/dmd/dversion.c create mode 100644 gcc/d/dmd/entity.c create mode 100644 gcc/d/dmd/enum.h create mode 100644 gcc/d/dmd/errors.h create mode 100644 gcc/d/dmd/escape.c create mode 100644 gcc/d/dmd/expression.c create mode 100644 gcc/d/dmd/expression.h create mode 100644 gcc/d/dmd/expressionsem.c create mode 100644 gcc/d/dmd/func.c create mode 100644 gcc/d/dmd/globals.h create mode 100644 gcc/d/dmd/hdrgen.c create mode 100644 gcc/d/dmd/hdrgen.h create mode 100644 gcc/d/dmd/iasm.c create mode 100644 gcc/d/dmd/iasmgcc.c create mode 100644 gcc/d/dmd/identifier.c create mode 100644 gcc/d/dmd/identifier.h create mode 100644 gcc/d/dmd/idgen.c create mode 100644 gcc/d/dmd/impcnvgen.c create mode 100644 gcc/d/dmd/imphint.c create mode 100644 gcc/d/dmd/import.h create mode 100644 gcc/d/dmd/init.c create mode 100644 gcc/d/dmd/init.h create mode 100644 gcc/d/dmd/initsem.c create mode 100644 gcc/d/dmd/intrange.c create mode 100644 gcc/d/dmd/intrange.h create mode 100644 gcc/d/dmd/json.c create mode 100644 gcc/d/dmd/json.h create mode 100644 gcc/d/dmd/lexer.c create mode 100644 gcc/d/dmd/lexer.h create mode 100644 gcc/d/dmd/macro.h create mode 100644 gcc/d/dmd/mangle.h create mode 100644 gcc/d/dmd/mars.h create mode 100644 gcc/d/dmd/module.h create mode 100644 gcc/d/dmd/mtype.c create mode 100644 gcc/d/dmd/mtype.h create mode 100644 gcc/d/dmd/nogc.c create mode 100644 gcc/d/dmd/nspace.c create mode 100644 gcc/d/dmd/nspace.h create mode 100644 gcc/d/dmd/objc.c create mode 100644 gcc/d/dmd/objc.h create mode 100644 gcc/d/dmd/opover.c create mode 100644 gcc/d/dmd/optimize.c create mode 100644 gcc/d/dmd/parse.c create mode 100644 gcc/d/dmd/parse.h create mode 100644 gcc/d/dmd/readme.txt create mode 100644 gcc/d/dmd/root/aav.c create mode 100644 gcc/d/dmd/root/aav.h create mode 100644 gcc/d/dmd/root/array.h create mode 100644 gcc/d/dmd/root/ctfloat.h create mode 100644 gcc/d/dmd/root/dcompat.h create mode 100644 gcc/d/dmd/root/file.c create mode 100644 gcc/d/dmd/root/file.h create mode 100644 gcc/d/dmd/root/filename.c create mode 100644 gcc/d/dmd/root/filename.h create mode 100644 gcc/d/dmd/root/hash.h create mode 100644 gcc/d/dmd/root/object.h create mode 100644 gcc/d/dmd/root/outbuffer.c create mode 100644 gcc/d/dmd/root/outbuffer.h create mode 100644 gcc/d/dmd/root/port.h create mode 100644 gcc/d/dmd/root/rmem.c create mode 100644 gcc/d/dmd/root/rmem.h create mode 100644 gcc/d/dmd/root/root.h create mode 100644 gcc/d/dmd/root/rootobject.c create mode 100644 gcc/d/dmd/root/speller.c create mode 100644 gcc/d/dmd/root/speller.h create mode 100644 gcc/d/dmd/root/stringtable.c create mode 100644 gcc/d/dmd/root/stringtable.h create mode 100644 gcc/d/dmd/safe.c create mode 100644 gcc/d/dmd/sapply.c create mode 100644 gcc/d/dmd/scope.h create mode 100644 gcc/d/dmd/sideeffect.c create mode 100644 gcc/d/dmd/statement.c create mode 100644 gcc/d/dmd/statement.h create mode 100644 gcc/d/dmd/statementsem.c create mode 100644 gcc/d/dmd/staticassert.c create mode 100644 gcc/d/dmd/staticassert.h create mode 100644 gcc/d/dmd/staticcond.c create mode 100644 gcc/d/dmd/target.h create mode 100644 gcc/d/dmd/template.h create mode 100644 gcc/d/dmd/tokens.c create mode 100644 gcc/d/dmd/tokens.h create mode 100644 gcc/d/dmd/traits.c create mode 100644 gcc/d/dmd/typesem.c create mode 100644 gcc/d/dmd/unittests.c create mode 100644 gcc/d/dmd/utf.c create mode 100644 gcc/d/dmd/utf.h create mode 100644 gcc/d/dmd/utils.c create mode 100644 gcc/d/dmd/version.h create mode 100644 gcc/d/dmd/visitor.h create mode 100644 gcc/d/expr.cc create mode 100644 gcc/d/gdc.texi create mode 100644 gcc/d/imports.cc create mode 100644 gcc/d/intrinsics.cc create mode 100644 gcc/d/intrinsics.def create mode 100644 gcc/d/lang-specs.h create mode 100644 gcc/d/lang.opt create mode 100644 gcc/d/longdouble.h create mode 100644 gcc/d/modules.cc create mode 100644 gcc/d/runtime.cc create mode 100644 gcc/d/runtime.def create mode 100644 gcc/d/toir.cc create mode 100644 gcc/d/typeinfo.cc create mode 100644 gcc/d/types.cc create mode 100644 gcc/d/verstr.h create mode 100644 gcc/testsuite/gdc.dg/asan/asan.exp create mode 100644 gcc/testsuite/gdc.dg/asan/gdc272.d create mode 100644 gcc/testsuite/gdc.dg/compilable.d create mode 100644 gcc/testsuite/gdc.dg/dg.exp create mode 100644 gcc/testsuite/gdc.dg/gdc254.d create mode 100644 gcc/testsuite/gdc.dg/gdc260.d create mode 100644 gcc/testsuite/gdc.dg/gdc270a.d create mode 100644 gcc/testsuite/gdc.dg/gdc270b.d create mode 100644 gcc/testsuite/gdc.dg/gdc282.d create mode 100644 gcc/testsuite/gdc.dg/gdc283.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc170.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc231.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc239.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc241a.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc241b.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc251a.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc251b.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc253.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc254a.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc256.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdc27.d create mode 100644 gcc/testsuite/gdc.dg/imports/gdcpkg256/package.d create mode 100644 gcc/testsuite/gdc.dg/imports/runnable.d create mode 100644 gcc/testsuite/gdc.dg/link.d create mode 100644 gcc/testsuite/gdc.dg/lto/lto.exp create mode 100644 gcc/testsuite/gdc.dg/lto/ltotests_0.d create mode 100644 gcc/testsuite/gdc.dg/lto/ltotests_1.d create mode 100644 gcc/testsuite/gdc.dg/runnable.d create mode 100644 gcc/testsuite/gdc.dg/simd.d create mode 100644 gcc/testsuite/gdc.test/compilable/99bottles.d create mode 100644 gcc/testsuite/gdc.test/compilable/a3682.d create mode 100644 gcc/testsuite/gdc.test/compilable/aggr_alignment.d create mode 100644 gcc/testsuite/gdc.test/compilable/aliasdecl.d create mode 100644 gcc/testsuite/gdc.test/compilable/alignment.d create mode 100644 gcc/testsuite/gdc.test/compilable/art4769.d create mode 100644 gcc/testsuite/gdc.test/compilable/b11118.d create mode 100644 gcc/testsuite/gdc.test/compilable/b1215.d create mode 100644 gcc/testsuite/gdc.test/compilable/b15428.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16244.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16346.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16355.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16382.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16483.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16598.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16697.d create mode 100644 gcc/testsuite/gdc.test/compilable/b16967.d create mode 100644 gcc/testsuite/gdc.test/compilable/b17111.d create mode 100644 gcc/testsuite/gdc.test/compilable/b33.d create mode 100644 gcc/testsuite/gdc.test/compilable/b6227.d create mode 100644 gcc/testsuite/gdc.test/compilable/b6395.d create mode 100644 gcc/testsuite/gdc.test/compilable/b6400.d create mode 100644 gcc/testsuite/gdc.test/compilable/betterCarray.d create mode 100644 gcc/testsuite/gdc.test/compilable/betterCswitch.d create mode 100644 gcc/testsuite/gdc.test/compilable/bug11735.d create mode 100644 gcc/testsuite/gdc.test/compilable/bug6963.d create mode 100644 gcc/testsuite/gdc.test/compilable/callconv.d create mode 100644 gcc/testsuite/gdc.test/compilable/compile1.d create mode 100644 gcc/testsuite/gdc.test/compilable/const.d create mode 100644 gcc/testsuite/gdc.test/compilable/cppmangle.d create mode 100644 gcc/testsuite/gdc.test/compilable/ctfe_math.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc1.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10236.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10236b.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10325.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10334.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10366.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10367.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10869.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc10870.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc11.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc11479.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc11511.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc11823.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc12.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc12706.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc12745.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc13.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc13270.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc13502.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc13645.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc14.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc14383.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc14413.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc14633.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc14778.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc15475.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc17697.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc198.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc2.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc2273.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc3.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc4.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc4162.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc4899.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc5.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc5446.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc5446a.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc5446b.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc6.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc648.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc6491.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc7.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc7555.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc7656.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc7715.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc7795.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc8.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc8271.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc8739.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9037.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9155.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9305.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9369.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9475.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9497a.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9497b.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9497c.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9497d.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9676a.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9676b.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9727.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9789.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddoc9903.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddocYear.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddocbackticks.d create mode 100644 gcc/testsuite/gdc.test/compilable/ddocunittest.d create mode 100644 gcc/testsuite/gdc.test/compilable/debuginfo.d create mode 100644 gcc/testsuite/gdc.test/compilable/defa.d create mode 100644 gcc/testsuite/gdc.test/compilable/depmsg.d create mode 100644 gcc/testsuite/gdc.test/compilable/deprecate12979a.d create mode 100644 gcc/testsuite/gdc.test/compilable/deprecate14283.d create mode 100644 gcc/testsuite/gdc.test/compilable/depsOutput9948.d create mode 100644 gcc/testsuite/gdc.test/compilable/derivedarray.d create mode 100644 gcc/testsuite/gdc.test/compilable/diag11066.d create mode 100644 gcc/testsuite/gdc.test/compilable/diag3243.d create mode 100644 gcc/testsuite/gdc.test/compilable/dip22.d create mode 100644 gcc/testsuite/gdc.test/compilable/empty_file.d create mode 100644 gcc/testsuite/gdc.test/compilable/exception.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/c6395.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc10367.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc198.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc3.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc9369.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497a.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497b.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497c.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497d.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/ddoc9676a.ddoc create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/e6815.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/example7190/controllers/HomeController.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/example7190/models/HomeModel.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/header1.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/header2.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/header3.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/imp12624.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/imp9057_2.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/common.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/package.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/common.di create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/package.di create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/liba.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/libb.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/package.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mbar.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mfoo.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/package.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/mod.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/package.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/except.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Controller.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Model.d create mode 100644 gcc/testsuite/gdc.test/compilable/extra-files/test16080b.d create mode 100644 gcc/testsuite/gdc.test/compilable/fail260.d create mode 100644 gcc/testsuite/gdc.test/compilable/fix17123.d create mode 100644 gcc/testsuite/gdc.test/compilable/fix17335.d create mode 100644 gcc/testsuite/gdc.test/compilable/fix17349.d create mode 100644 gcc/testsuite/gdc.test/compilable/fix17686.d create mode 100644 gcc/testsuite/gdc.test/compilable/forward1.d create mode 100644 gcc/testsuite/gdc.test/compilable/future.d create mode 100644 gcc/testsuite/gdc.test/compilable/futurexf.d create mode 100644 gcc/testsuite/gdc.test/compilable/iasm_labeloperand.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice10040.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice10431a.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice10431b.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice10486.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice10598.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice11054.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice11300.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice11596.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice11610.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice11777.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice11906.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice11925.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice12002.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice12554.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice12956.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13071.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13088.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13245.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13323.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13403.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13792.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13874.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13886.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13920.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice13968.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice14075.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice1524.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice15333.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice15760.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice15789.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice15992.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice6538.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice8392.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice854.d create mode 100644 gcc/testsuite/gdc.test/compilable/ice9663.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a12506.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a12567.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a13226.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a14528.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a15333.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a15760.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a15856.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a313.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a313templatemixin1.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a313templatemixin2.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a314.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/a8392.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/art4769a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/art4769b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/b313.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/b33a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/b3682.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/bug8922.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/c314.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/defaa.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/defab.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/defac.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/defad.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/dip22.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/f313.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/fwdref12201a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/fwdref2_test17548.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/fwdref9514.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/g313.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/g313public.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/g313staticif.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/g313stringmixin.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/g313templatemixin.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/ice10598a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/ice10598b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/ice11054a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/ice11300a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/ice13403a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp12242a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp12242a1.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp12242a2.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp12242b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp12242b1.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp12242b2.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp15490a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp15490b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp15907.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp15925.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp16080.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp16085.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp16085b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp16460.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/imp16798.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/jsonimport1.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/jsonimport2.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/jsonimport3.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/jsonimport4.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/pkg313/c313.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/pkgmod313/mod.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/pkgmod313/package.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/protectionimp.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/stdio4003.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test10375a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test10752.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test11225b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test11225c.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test11563core_bitop.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test11563std_array.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test11563std_range.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test1238a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test1238b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test13242a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test13242b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test14666a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test14666b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test15117a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test15150a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test15150b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test15785.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test15857a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test15857b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test15857c.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test16348.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test1754a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test1754b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test1imp.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test25a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test25b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test2991.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test4003a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test50a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test55a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test59a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test59b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test6013.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test61a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test62a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test63a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test66a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test67a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test68a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test70.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test71.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test72a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test72b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test72c.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test7491a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test7491b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276decl.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276expr.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276hash.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276parser.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276sem.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276type.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276util.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9276visitors.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9399a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9436aggr.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9436interp.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9436node.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9436type.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9672a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9692b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9919a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9919b.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test9919c.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/testcontracts.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/typecons4003.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/udamodule1.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/udamodule2.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/udamodule2a.d create mode 100644 gcc/testsuite/gdc.test/compilable/imports/wax16798.d create mode 100644 gcc/testsuite/gdc.test/compilable/interpret3.d create mode 100644 gcc/testsuite/gdc.test/compilable/json.d create mode 100644 gcc/testsuite/gdc.test/compilable/line.d create mode 100644 gcc/testsuite/gdc.test/compilable/noderef.d create mode 100644 gcc/testsuite/gdc.test/compilable/nogc.d create mode 100644 gcc/testsuite/gdc.test/compilable/protattr.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection/aggregate/mod14275.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection/basic/mod1.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection/basic/tests.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection/bug/bug14275.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection/subpkg/explicit.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection/subpkg/tests.d create mode 100644 gcc/testsuite/gdc.test/compilable/protection/subpkg2/tests.d create mode 100644 gcc/testsuite/gdc.test/compilable/pull6815.d create mode 100644 gcc/testsuite/gdc.test/compilable/riia_ctor.d create mode 100644 gcc/testsuite/gdc.test/compilable/scope.d create mode 100644 gcc/testsuite/gdc.test/compilable/shared_destructor.d create mode 100644 gcc/testsuite/gdc.test/compilable/sw_transition_complex.d create mode 100644 gcc/testsuite/gdc.test/compilable/sw_transition_field.d create mode 100644 gcc/testsuite/gdc.test/compilable/sw_transition_tls.d create mode 100644 gcc/testsuite/gdc.test/compilable/test1.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10056.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10066.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10073.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10186.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10312.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10375.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10520.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10695.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10726.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10752.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10981.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10992.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10992b.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10993.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11169.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11225a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11237.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11371.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11471.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11559upgradeoptlink.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11563.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11656.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11824.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11914.d create mode 100644 gcc/testsuite/gdc.test/compilable/test11980.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12009.d create mode 100644 gcc/testsuite/gdc.test/compilable/test1238.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12523.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12527.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12558.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12567a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12567b.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12567c.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12567d.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12593.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12624.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12967.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12979a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test12979b.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13008.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13053.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13193.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13194.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13226.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13242.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13281.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13512.d create mode 100644 gcc/testsuite/gdc.test/compilable/test1353.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13600.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13668.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13858.d create mode 100644 gcc/testsuite/gdc.test/compilable/test13902.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14275.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14317.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14375.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14528.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14666.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14747.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14781.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14838.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14962.d create mode 100644 gcc/testsuite/gdc.test/compilable/test14973.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15019.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15056.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15150.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15177.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15326.d create mode 100644 gcc/testsuite/gdc.test/compilable/test1537.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15389_x.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15389_y.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15402.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15464.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15490.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15519_x.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15519_y.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15550.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15565.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15578.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15618.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15668.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15762.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15780.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15784.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15785.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15802.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15856.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15898.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15907.d create mode 100644 gcc/testsuite/gdc.test/compilable/test15925.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16031.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16080.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16083.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16085.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16225.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16292.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16303.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16340.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16348.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16460.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16525.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16540.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16563.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16570.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16572.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16574.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16607.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16627.d create mode 100644 gcc/testsuite/gdc.test/compilable/test1673.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16747.d create mode 100644 gcc/testsuite/gdc.test/compilable/test16798.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17057.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17059.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17130.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17143.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17168.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17215.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17339.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17349.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17352.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17399.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17419.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17421.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17468.d create mode 100644 gcc/testsuite/gdc.test/compilable/test1754.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17545.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17548.d create mode 100644 gcc/testsuite/gdc.test/compilable/test17590.d create mode 100644 gcc/testsuite/gdc.test/compilable/test1878a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test25.d create mode 100644 gcc/testsuite/gdc.test/compilable/test2991.d create mode 100644 gcc/testsuite/gdc.test/compilable/test313a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test313b.d create mode 100644 gcc/testsuite/gdc.test/compilable/test313c.d create mode 100644 gcc/testsuite/gdc.test/compilable/test313d.d create mode 100644 gcc/testsuite/gdc.test/compilable/test313e.d create mode 100644 gcc/testsuite/gdc.test/compilable/test313f.d create mode 100644 gcc/testsuite/gdc.test/compilable/test313g.d create mode 100644 gcc/testsuite/gdc.test/compilable/test314.d create mode 100644 gcc/testsuite/gdc.test/compilable/test3673.d create mode 100644 gcc/testsuite/gdc.test/compilable/test3775.d create mode 100644 gcc/testsuite/gdc.test/compilable/test4003.d create mode 100644 gcc/testsuite/gdc.test/compilable/test4090.d create mode 100644 gcc/testsuite/gdc.test/compilable/test4364.d create mode 100644 gcc/testsuite/gdc.test/compilable/test4375.d create mode 100644 gcc/testsuite/gdc.test/compilable/test50.d create mode 100644 gcc/testsuite/gdc.test/compilable/test5227.d create mode 100644 gcc/testsuite/gdc.test/compilable/test55.d create mode 100644 gcc/testsuite/gdc.test/compilable/test59.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6013.d create mode 100644 gcc/testsuite/gdc.test/compilable/test602.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6056a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6056b.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6056c.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6089.d create mode 100644 gcc/testsuite/gdc.test/compilable/test61.d create mode 100644 gcc/testsuite/gdc.test/compilable/test62.d create mode 100644 gcc/testsuite/gdc.test/compilable/test63.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6319.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6395.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6534.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6552.d create mode 100644 gcc/testsuite/gdc.test/compilable/test66.d create mode 100644 gcc/testsuite/gdc.test/compilable/test67.d create mode 100644 gcc/testsuite/gdc.test/compilable/test68.d create mode 100644 gcc/testsuite/gdc.test/compilable/test69.d create mode 100644 gcc/testsuite/gdc.test/compilable/test6999.d create mode 100644 gcc/testsuite/gdc.test/compilable/test70.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7065.d create mode 100644 gcc/testsuite/gdc.test/compilable/test71.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7172.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7190.d create mode 100644 gcc/testsuite/gdc.test/compilable/test72.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7252.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7399.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7491.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7524.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7569.d create mode 100644 gcc/testsuite/gdc.test/compilable/test7754.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8038.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8041.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8296.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8509.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8513.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8543.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8631.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8675.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8696.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8717.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8802.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8898.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8922a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8922b.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8922c.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8922d.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8922e.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8922f.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8937.d create mode 100644 gcc/testsuite/gdc.test/compilable/test8959.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9057.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9209.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9276.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9278a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9278b.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9399.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9434.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9435.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9436.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9526.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9554.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9565.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9570.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9613.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9639.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9672.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9692.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9692a.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9766.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9818.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9919.d create mode 100644 gcc/testsuite/gdc.test/compilable/testDIP37.d create mode 100644 gcc/testsuite/gdc.test/compilable/testDIP37_10302.d create mode 100644 gcc/testsuite/gdc.test/compilable/testDIP37_10354.d create mode 100644 gcc/testsuite/gdc.test/compilable/testDIP37_10421.d create mode 100644 gcc/testsuite/gdc.test/compilable/testDIP37a.d create mode 100644 gcc/testsuite/gdc.test/compilable/testDIP42.d create mode 100644 gcc/testsuite/gdc.test/compilable/testInference.d create mode 100644 gcc/testsuite/gdc.test/compilable/testVRP.d create mode 100644 gcc/testsuite/gdc.test/compilable/testcheckimports.d create mode 100644 gcc/testsuite/gdc.test/compilable/testcontracts.d create mode 100644 gcc/testsuite/gdc.test/compilable/testexpression.d create mode 100644 gcc/testsuite/gdc.test/compilable/testfptr.d create mode 100644 gcc/testsuite/gdc.test/compilable/testfwdref.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheader1.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheader12567a.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheader12567b.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheader1i.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheader2.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheader2i.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheader3.d create mode 100644 gcc/testsuite/gdc.test/compilable/testheaderudamodule.d create mode 100644 gcc/testsuite/gdc.test/compilable/testimport12242.d create mode 100644 gcc/testsuite/gdc.test/compilable/testparse.d create mode 100644 gcc/testsuite/gdc.test/compilable/testpostblit.d create mode 100644 gcc/testsuite/gdc.test/compilable/testprofile.d create mode 100644 gcc/testsuite/gdc.test/compilable/uda.d create mode 100644 gcc/testsuite/gdc.test/compilable/udamodule1.d create mode 100644 gcc/testsuite/gdc.test/compilable/udamodule2.d create mode 100644 gcc/testsuite/gdc.test/compilable/verrors_spec.d create mode 100644 gcc/testsuite/gdc.test/compilable/vgc1.d create mode 100644 gcc/testsuite/gdc.test/compilable/vgc2.d create mode 100644 gcc/testsuite/gdc.test/compilable/vgc3.d create mode 100644 gcc/testsuite/gdc.test/compilable/warn3882.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/b3841.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/bug4283.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/bug5.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/bug5b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/bug8150a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/bug8150b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/bug8891.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/checkimports1a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/checkimports1b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/checkimports1c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/checkimports3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/circ10280.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/class1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/class2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/commaexp.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/cppeh1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/cppeh2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/cwords.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/depmsg.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/deprecate12979a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/deprecate12979b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/deprecate12979c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/deprecate12979d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10089.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10099.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10141.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10169.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10221.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10221a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10319.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10327.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10359.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10405.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10415.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10688.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10768.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10783.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10792.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10805.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10862.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10926.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag10984.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11078.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11132.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11198.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11423.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11425.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11727.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11756.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11759.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11769.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11819a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11819b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag11840.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12063.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12124.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12280.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12312.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12380.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12432.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12480.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12487.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12598.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12640.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12678.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12777.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag12829.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13028.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13082.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13142.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13281.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13320.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13333.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13528.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13609a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13609b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13787.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13884.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag13942.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag14102.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag14163.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag14235.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag14818.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag14875.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag14876.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15001.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15186.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15209.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15340.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15411.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag1566.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15669.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15713.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag15974.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag16499.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag16977.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag1730.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag2452.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3013.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3438.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3438b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3672.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3672a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3673.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3869.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag3913.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag4479.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag4528.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag4540.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag4596.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag5385.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag5450.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag6373.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag6539.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag6677.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag6699.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag6707.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag6717.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag6796.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag7050a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag7050b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag7050c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag7420.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag7477.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag7747.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag7998.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8101.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8101b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8178.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8318.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8425.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8510.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8559.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8648.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8697.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8714.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8777.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8787.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8825.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8892.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8894.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag8928.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9004.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9148.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9191.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9210a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9247.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9250.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9312.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9357.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9358.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9398.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9420.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9451.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9479.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9574.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9620.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9635.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9679.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9765.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9831.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9861.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9880.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag9961.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/diag_err1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/dip22a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/dip22b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/dip22d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/dip22e.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/disable.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/enum9921.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/extra-files/bar11453.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/extra-files/foo11453.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail100.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10082.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail101.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10102.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10115.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10207.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10254.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10277.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10285.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10299.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10346.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail104.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10481.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail105.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10528.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10534.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail106.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10630.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10666.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail109.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10905.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10947.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10964.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10968.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail10980.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail110.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11042.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail111.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11125.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11151.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11163.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11169.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail113.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11355.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11375.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail114.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11426.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11445.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11453a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11453b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail115.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11503a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11503b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11503c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11503d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11510.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11532.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11542.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11545.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11552.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11562.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11591b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail116.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11653.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail117.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11717.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11720.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11746.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11748.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail11751.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail118.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail120.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12047.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail121.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail122.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12236.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12255.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail123.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12378.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12390.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail124.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12436.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12485.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail125.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12567.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail126.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12604.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12622.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12635.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12636.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail127.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12744.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12749.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12809.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail129.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12901.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12908.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail12932.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13064.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail131.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13116.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13120.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13187.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail132.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13203.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail133.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13336a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13336b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail134.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13424.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13434_m32.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13434_m64.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13498.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13574.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail136.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13601.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail137.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13701.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13756.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13775.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail139.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13902.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13938.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail13939.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14009.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14089.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail142.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14249.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail143.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14304.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail144.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14406.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14407.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14416.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14486.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail145.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14554.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14669.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail14965.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail150.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15044.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15089.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail152.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15292.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail153.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail154.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail155.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15535.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15550.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail156.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15616a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15616b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15626.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail15667.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail158.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail159.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail16.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail160.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail161.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail162.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail163.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail16600.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail169.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail170.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail172.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17275.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17354.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17419.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17421.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17491.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17492.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17502.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail176.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17612.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17646.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17689.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail177.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17722a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail17722b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail179.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail18.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail180.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail183.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail184.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail185.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail187.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail188.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail189.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail190.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail1900.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail192.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail193.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail194.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail195.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail196.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail198.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail199.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail20.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail200.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail201.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail202.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail203.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail204.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail205.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail206.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail207.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail208.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail209.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail212.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail213.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail215.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail216.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail217.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail218.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail220.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail221.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail222.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail223.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail224.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail225.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail228.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail229.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail23.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail231.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail232.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail233.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail235.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail2350.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail236.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail2361.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail237.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail239.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail240.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail241.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail243.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail244.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail245.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail246.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail247.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail248.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail249.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail25.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail250.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail251.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail252.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail253.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail254.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail256.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail257.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail258.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail259.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail261.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail262.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail263.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail264.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail265.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail2656.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail267.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail27.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail270.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail272.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail273.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail274.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail2740.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail275.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail276.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail278.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail279.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail280.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail281.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail282.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail284.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail285.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail287.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail288.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail289.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail290.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail291.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail296.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail2962.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail297.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail298.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail299.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail301.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail302.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail303.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail304.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail305.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail306.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail307.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail308.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail309.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail310.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail311.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail312.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail313.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail314.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3144.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail315.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3150.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail316.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail317.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail318.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail319.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail320.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail322.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail324.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail325.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail327.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail328.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail329.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3290.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail330.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail331.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail332.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail333.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail334.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail335.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3354.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail336.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail337.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail34.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail340.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail341.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail343.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail344.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail346.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail347.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail349.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail35.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail351.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail352.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail353.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail354.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail355.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail356a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail356b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail356c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3581a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3581b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail359.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail36.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3672.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3673a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3673b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3703.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3731.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3753.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail38.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3882.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3895.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail39.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail3990.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail40.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4082.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail41.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail42.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4206.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4269a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4269b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4269c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4269d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4269e.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4269f.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4269g.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4374.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375e.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375f.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375g.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375h.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375i.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375j.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375k.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375l.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375m.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375o.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375p.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375q.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375r.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375s.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375t.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375u.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375v.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375w.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375x.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4375y.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail44.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4421.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4448.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail45.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4510.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4511.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4517.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4559.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail46.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4611.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail47.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail4958.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail50.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail51.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail52.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail53.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail54.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5435.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail55.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail56.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5634.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail57.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5733.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail58.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5851.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail59.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5953a1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5953a2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5953s1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail5953s2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail60.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6029.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail61.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6107.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail62.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6242.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail63.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6334.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6451.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6453.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6458.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6497.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6561.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail66.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6611.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6652.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6781.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6795.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6889.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail6968.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7077.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7173.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7178.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail72.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7234.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail73.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7369.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail74.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424e.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424f.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424g.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424h.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7424i.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail75.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7524a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7524b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail76.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7603a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7603b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7603c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail77.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7702.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7751.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail78.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7815.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7848.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7851.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7859.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7861.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7862.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7886.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail79.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail7903.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8009.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8032.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8168.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8179b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8217.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8313.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8373.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail86.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8631.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8691.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail8724.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9063.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9081.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail91.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9199.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail92.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9279.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail93.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9301.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9346.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9368.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail94.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9413.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9414a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9414b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9414c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9414d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail95.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9537.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9562.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9572.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail96.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9613.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9665a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9665b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail97.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9710.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9735.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9766.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9773.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9790.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail98.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9891.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9892.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail99.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail9936.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_casting.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_casting1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_circular.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_opover.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_scope.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failattr.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failcontracts.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failescape.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failinout1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failinout2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failinout3748a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failinout3748b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failoffset.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failsafea.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failsafeb.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/failsafec.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fix350a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fix350b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/gag4269a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/gag4269b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/gag4269c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/gag4269d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/gag4269e.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/gag4269f.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/gag4269g.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10016.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10076.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10212.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10259.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10273.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10283.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10341.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10382.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10419.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10599.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10600.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10616.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10624.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10651.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10713.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10727a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10727b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10770.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10922.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10938.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice10949.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11086.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11136.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11153.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11404.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice1144.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11472.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11513a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11513b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11518.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11552.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11553.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11626.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11726.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11755.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11790.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11793.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11822.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11849b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11850.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11919.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11922.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11926.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11944.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11963.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11965.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11967.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11968.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11969.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11974.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice11982.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12040.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12158.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12174.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12235.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12350.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12362.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12397.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12497.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12501.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12534.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12539.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12574.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12581.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12673.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12727.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12827.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12836.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12838.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12841.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12850.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12902.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice12907.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13024.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13027.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13081.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13131.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13220.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13221.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13225.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13311.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13356.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13382.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13385.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13459.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13465a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13465b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13563.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice1358.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13644.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13788.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13816.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13835.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13921.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice13987.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14055.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14096.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14116.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14130.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14146.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14177.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14185.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14272.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14424.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14446.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14621.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14642.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14844.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14923.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice14929.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15002.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15092.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15127.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15172.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15239.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15317.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15332.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15441.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15688.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15788.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15816.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15855.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice15922.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice16035.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice17074.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice17690.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice17831.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice2843.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice4094.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice4983.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice5996.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice6538.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice7645.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice7782.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8100.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8255.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8309.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8499.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8511.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8604.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8630.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8711.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8742.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8795.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice8795b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9013.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9254a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9254b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9254c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9273a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9273b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9284.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9291.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9338.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9406.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9439.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9494.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9540.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9545.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9759.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9806.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice9865.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imphint.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a10169.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a10528.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a11850.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a11919.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a13131checkpoint.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a13131elec.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a13131parameters.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a13311.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a13465.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a14116.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a14235.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a14424.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a15667.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a15816.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a313.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/a314.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/b13465.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/b313.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/b314.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/bar11136.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/c314.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag10089a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag10089b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag10141a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag10141b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag12598a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag9210b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag9210c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdtraits.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/dip22a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/dip22b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/dip22c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/dip22d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/dip22e.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail10277.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail17646.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail1900a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail1900b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail2962a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail320a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail320b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail347a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail355.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail356.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail4479.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/fail5385.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/foo10727a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/foo10727b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/ice10600a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/ice10600b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/ice11513x.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/ice11513y.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/ice7782algorithm.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/ice7782range.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/ice9865b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/imp1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/imp2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/pkg313/package.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/range15788.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/spell9644a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/spell9644b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/stdtraits10727.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test10327/empty.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152d.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152e.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152f.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152g.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152h.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152i.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152j.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152k.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152l.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152m.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152n.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152o.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152p.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152q.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152r.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152s.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152t.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152u.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152v.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152w.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152x.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152y.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test13152z.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test143.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test15785.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test15897.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test5412a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test5412b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/imports/test64a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/issue3827.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/lexer1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/lexer2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/lexer3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/lexer4.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/lookup.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/mangle1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/mangle2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/moduleundefuda.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/nogc1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/nogc2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/nogc3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parse12924.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parse12967a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parse12967b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parse13361.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parse14285.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parse14745.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parseStc.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parseStc2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parseStc3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parseStc4.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/parseStc5.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/pragmainline.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/pragmas.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/protattr1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/protattr2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/protattr3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/reserved_version.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/retref2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/retscope.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/retscope2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/skip.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/spell9644.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/switches.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test11047.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test11176.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test12822.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test12979.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test13152.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test13536.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test13537.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test13786.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test13867.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test14238.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test143.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test14496.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test14538.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15191.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15306.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15399.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15544.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15672.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15703.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15704.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15785.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15785b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15897.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test15989.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16095.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16116.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16188.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16193.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16195.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16228.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16365.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16381.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16523.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test16589.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17380.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17422.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17425.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17450.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17451.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test314.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test4682.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test4682a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test4838.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test5412a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test5412b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test5412c.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test64.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test6883.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test8509.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test8556.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test8751.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test9150.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test9176.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/testCols.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/testInference.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/testpull1810.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/typeerrors.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/verrors0.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/verrors5.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/warn12809.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/warn13679.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/warn7444.d create mode 100644 gcc/testsuite/gdc.test/gdc-test.exp create mode 100644 gcc/testsuite/gdc.test/runnable/A16.d create mode 100644 gcc/testsuite/gdc.test/runnable/Same.d create mode 100644 gcc/testsuite/gdc.test/runnable/a17.d create mode 100644 gcc/testsuite/gdc.test/runnable/a18.d create mode 100644 gcc/testsuite/gdc.test/runnable/a19.d create mode 100644 gcc/testsuite/gdc.test/runnable/a21.d create mode 100644 gcc/testsuite/gdc.test/runnable/aliasthis.d create mode 100644 gcc/testsuite/gdc.test/runnable/argufilem.d create mode 100644 gcc/testsuite/gdc.test/runnable/arrayop.d create mode 100644 gcc/testsuite/gdc.test/runnable/auto1.d create mode 100644 gcc/testsuite/gdc.test/runnable/b17073.d create mode 100644 gcc/testsuite/gdc.test/runnable/b26.d create mode 100644 gcc/testsuite/gdc.test/runnable/bench1.d create mode 100644 gcc/testsuite/gdc.test/runnable/bitops.d create mode 100644 gcc/testsuite/gdc.test/runnable/bug11155.d create mode 100644 gcc/testsuite/gdc.test/runnable/bug12928.d create mode 100644 gcc/testsuite/gdc.test/runnable/bug16146.d create mode 100644 gcc/testsuite/gdc.test/runnable/bug5.d create mode 100644 gcc/testsuite/gdc.test/runnable/bug7068.d create mode 100644 gcc/testsuite/gdc.test/runnable/bug846.d create mode 100644 gcc/testsuite/gdc.test/runnable/builtin.d create mode 100644 gcc/testsuite/gdc.test/runnable/c22.d create mode 100644 gcc/testsuite/gdc.test/runnable/cabi1.d create mode 100644 gcc/testsuite/gdc.test/runnable/cassert.d create mode 100644 gcc/testsuite/gdc.test/runnable/casting.d create mode 100644 gcc/testsuite/gdc.test/runnable/circular.d create mode 100644 gcc/testsuite/gdc.test/runnable/closure.d create mode 100644 gcc/testsuite/gdc.test/runnable/complex.d create mode 100644 gcc/testsuite/gdc.test/runnable/constfold.d create mode 100644 gcc/testsuite/gdc.test/runnable/cpp_abi_tests.d create mode 100644 gcc/testsuite/gdc.test/runnable/cppa.d create mode 100644 gcc/testsuite/gdc.test/runnable/ctorpowtests.d create mode 100644 gcc/testsuite/gdc.test/runnable/declaration.d create mode 100644 gcc/testsuite/gdc.test/runnable/delegate.d create mode 100644 gcc/testsuite/gdc.test/runnable/dhry.d create mode 100644 gcc/testsuite/gdc.test/runnable/eh.d create mode 100644 gcc/testsuite/gdc.test/runnable/eh2.d create mode 100644 gcc/testsuite/gdc.test/runnable/entity1.d create mode 100644 gcc/testsuite/gdc.test/runnable/evalorder.d create mode 100644 gcc/testsuite/gdc.test/runnable/extern1.d create mode 100644 gcc/testsuite/gdc.test/runnable/externmangle.d create mode 100644 gcc/testsuite/gdc.test/runnable/externmangle2.d create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/alice30.txt create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/cabi2.cpp create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/cpp_abi_tests.cpp create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/cppb.cpp create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/externmangle.cpp create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/externmangle2.cpp create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/foo37.txt create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/std14198/array.d create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/std14198/conv.d create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/std14198/format.d create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/std14198/uni.d create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/test15.txt create mode 100644 gcc/testsuite/gdc.test/runnable/extra-files/teststdio.txt create mode 100644 gcc/testsuite/gdc.test/runnable/fix17429.d create mode 100644 gcc/testsuite/gdc.test/runnable/foreach.d create mode 100644 gcc/testsuite/gdc.test/runnable/foreach2.d create mode 100644 gcc/testsuite/gdc.test/runnable/foreach3.d create mode 100644 gcc/testsuite/gdc.test/runnable/foreach4.d create mode 100644 gcc/testsuite/gdc.test/runnable/foreach5.d create mode 100644 gcc/testsuite/gdc.test/runnable/funclit.d create mode 100644 gcc/testsuite/gdc.test/runnable/functype.d create mode 100644 gcc/testsuite/gdc.test/runnable/future.d create mode 100644 gcc/testsuite/gdc.test/runnable/hello.d create mode 100644 gcc/testsuite/gdc.test/runnable/helloUTF8.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice10086a.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice10086b.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice10857.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice15030.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice15138.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice15176.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice15200.d create mode 100644 gcc/testsuite/gdc.test/runnable/ice4481.d create mode 100644 gcc/testsuite/gdc.test/runnable/ifti.d create mode 100644 gcc/testsuite/gdc.test/runnable/implicit.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/A16a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/Other.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a11447.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a12010.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a12037.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a12874.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a14267.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a14992.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a15030.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a15079.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a17a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a18a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a19a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a20a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a21a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a7595.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a9546.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/a9741.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/argufile.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/b11447.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/b15030.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/b26a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/bar10378.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/bug10425.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/bug846.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/c11447.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/c22a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/c22b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/circularA.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/depsprot_default.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/depsprot_private.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/depsprot_public.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/extern1a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice10086x.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice10086y.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice10857a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice10857b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice15138a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice15176a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice15176b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice15200a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice15200b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice4481a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ice4481b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/inc11239.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link10920a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link11069x.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link11069y.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link11069z.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link11127a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link11395a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link12144a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link13043a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link13394a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link13400a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link13415a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link14074x.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link14074y.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link14074z.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link14541traits.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link14588a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link14814a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link15194b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link15194std.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link2500a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link2500b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link2644a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link2644b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link2644c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link7745b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link8023b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/link9571a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/linktypeinfo_file.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/m1a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/m8668a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/m8668b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/m8668c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/mangle10077.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/mod2.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ovs1528a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ovs1528b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std11069array.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std11069container.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std11069range.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std11069typecons.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std11863bitmanip.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std11863conv.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std11863format.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std12010container.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std15017variant.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std15021conv.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std15021format.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/std15030algo.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/template13478a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/template13478b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/template2962a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/template_ovs1.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/template_ovs2.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/template_ovs3.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test10441b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test10441c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test10573a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test10736a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test10736b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test10736c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test10a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test11039b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test11745b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test11931a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test11931b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test11931c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test11931d.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test13a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test14901a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test14901b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test14901c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test14901d.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test21a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test24a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test24b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test27a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test29a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test29b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test31a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test32a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test35a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test38a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test39a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test3a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test3b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test40a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test41a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test44a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test45a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test45b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test46a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test46b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test46c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test48a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test49a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test57a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test57b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test58a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test61a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test7494a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test8997a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/test9271a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/testkwd_file.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/testminitAA.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/testminitBB.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/testmod1a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/testmod1b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/testmod2a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/tlsa.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/traits_getUnitTests_import.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ufcs5a.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ufcs5b.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ufcs5c.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ufcs5d.d create mode 100644 gcc/testsuite/gdc.test/runnable/imports/ufcs5e.d create mode 100644 gcc/testsuite/gdc.test/runnable/inline.d create mode 100644 gcc/testsuite/gdc.test/runnable/inline14560.d create mode 100644 gcc/testsuite/gdc.test/runnable/inner.d create mode 100644 gcc/testsuite/gdc.test/runnable/interface.d create mode 100644 gcc/testsuite/gdc.test/runnable/interface1.d create mode 100644 gcc/testsuite/gdc.test/runnable/interface2.d create mode 100644 gcc/testsuite/gdc.test/runnable/interface3.d create mode 100644 gcc/testsuite/gdc.test/runnable/interpret.d create mode 100644 gcc/testsuite/gdc.test/runnable/interpret2.d create mode 100644 gcc/testsuite/gdc.test/runnable/issue8671.d create mode 100644 gcc/testsuite/gdc.test/runnable/lazy.d create mode 100644 gcc/testsuite/gdc.test/runnable/ldc_github_1677.d create mode 100644 gcc/testsuite/gdc.test/runnable/lexer.d create mode 100644 gcc/testsuite/gdc.test/runnable/link10425.d create mode 100644 gcc/testsuite/gdc.test/runnable/link10920.d create mode 100644 gcc/testsuite/gdc.test/runnable/link11069a.d create mode 100644 gcc/testsuite/gdc.test/runnable/link11069b.d create mode 100644 gcc/testsuite/gdc.test/runnable/link11127.d create mode 100644 gcc/testsuite/gdc.test/runnable/link11395.d create mode 100644 gcc/testsuite/gdc.test/runnable/link11931.d create mode 100644 gcc/testsuite/gdc.test/runnable/link12010.d create mode 100644 gcc/testsuite/gdc.test/runnable/link12037.d create mode 100644 gcc/testsuite/gdc.test/runnable/link12144.d create mode 100644 gcc/testsuite/gdc.test/runnable/link13043.d create mode 100644 gcc/testsuite/gdc.test/runnable/link13350.d create mode 100644 gcc/testsuite/gdc.test/runnable/link13394.d create mode 100644 gcc/testsuite/gdc.test/runnable/link13400.d create mode 100644 gcc/testsuite/gdc.test/runnable/link13415.d create mode 100644 gcc/testsuite/gdc.test/runnable/link13843.d create mode 100644 gcc/testsuite/gdc.test/runnable/link14074a.d create mode 100644 gcc/testsuite/gdc.test/runnable/link14074b.d create mode 100644 gcc/testsuite/gdc.test/runnable/link14425.d create mode 100644 gcc/testsuite/gdc.test/runnable/link14541.d create mode 100644 gcc/testsuite/gdc.test/runnable/link14588.d create mode 100644 gcc/testsuite/gdc.test/runnable/link14814.d create mode 100644 gcc/testsuite/gdc.test/runnable/link14992.d create mode 100644 gcc/testsuite/gdc.test/runnable/link15017.d create mode 100644 gcc/testsuite/gdc.test/runnable/link15021.d create mode 100644 gcc/testsuite/gdc.test/runnable/link15149.d create mode 100644 gcc/testsuite/gdc.test/runnable/link2500.d create mode 100644 gcc/testsuite/gdc.test/runnable/link2644.d create mode 100644 gcc/testsuite/gdc.test/runnable/link6574.d create mode 100644 gcc/testsuite/gdc.test/runnable/link7745.d create mode 100644 gcc/testsuite/gdc.test/runnable/link7966.d create mode 100644 gcc/testsuite/gdc.test/runnable/link8023.d create mode 100644 gcc/testsuite/gdc.test/runnable/link9571.d create mode 100644 gcc/testsuite/gdc.test/runnable/linktypeinfo.d create mode 100644 gcc/testsuite/gdc.test/runnable/literal.d create mode 100644 gcc/testsuite/gdc.test/runnable/loopunroll.d create mode 100644 gcc/testsuite/gdc.test/runnable/m1.d create mode 100644 gcc/testsuite/gdc.test/runnable/manboy.d create mode 100644 gcc/testsuite/gdc.test/runnable/mangle.d create mode 100644 gcc/testsuite/gdc.test/runnable/mars1.d create mode 100644 gcc/testsuite/gdc.test/runnable/mixin1.d create mode 100644 gcc/testsuite/gdc.test/runnable/mixin2.d create mode 100644 gcc/testsuite/gdc.test/runnable/mod1.d create mode 100644 gcc/testsuite/gdc.test/runnable/nan.d create mode 100644 gcc/testsuite/gdc.test/runnable/nested.d create mode 100644 gcc/testsuite/gdc.test/runnable/newdel.d create mode 100644 gcc/testsuite/gdc.test/runnable/nogc.d create mode 100644 gcc/testsuite/gdc.test/runnable/nulltype.d create mode 100644 gcc/testsuite/gdc.test/runnable/opdisp.d create mode 100644 gcc/testsuite/gdc.test/runnable/opover.d create mode 100644 gcc/testsuite/gdc.test/runnable/opover2.d create mode 100644 gcc/testsuite/gdc.test/runnable/opover3.d create mode 100644 gcc/testsuite/gdc.test/runnable/overload.d create mode 100644 gcc/testsuite/gdc.test/runnable/pi.d create mode 100644 gcc/testsuite/gdc.test/runnable/polysemous.d create mode 100644 gcc/testsuite/gdc.test/runnable/printargs.d create mode 100644 gcc/testsuite/gdc.test/runnable/property.d create mode 100644 gcc/testsuite/gdc.test/runnable/property2.d create mode 100644 gcc/testsuite/gdc.test/runnable/s2ir.d create mode 100644 gcc/testsuite/gdc.test/runnable/sctor.d create mode 100644 gcc/testsuite/gdc.test/runnable/sdtor.d create mode 100644 gcc/testsuite/gdc.test/runnable/statictor.d create mode 100644 gcc/testsuite/gdc.test/runnable/stress.d create mode 100644 gcc/testsuite/gdc.test/runnable/structlit.d create mode 100644 gcc/testsuite/gdc.test/runnable/template1.d create mode 100644 gcc/testsuite/gdc.test/runnable/template13478.d create mode 100644 gcc/testsuite/gdc.test/runnable/template2.d create mode 100644 gcc/testsuite/gdc.test/runnable/template2962.d create mode 100644 gcc/testsuite/gdc.test/runnable/template3.d create mode 100644 gcc/testsuite/gdc.test/runnable/template4.d create mode 100644 gcc/testsuite/gdc.test/runnable/template8.d create mode 100644 gcc/testsuite/gdc.test/runnable/template9.d create mode 100644 gcc/testsuite/gdc.test/runnable/test10.d create mode 100644 gcc/testsuite/gdc.test/runnable/test10378.d create mode 100644 gcc/testsuite/gdc.test/runnable/test10441.d create mode 100644 gcc/testsuite/gdc.test/runnable/test10573.d create mode 100644 gcc/testsuite/gdc.test/runnable/test10736.d create mode 100644 gcc/testsuite/gdc.test/runnable/test10942.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11039.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11239.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11447a.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11447b.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11447c.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11745.d create mode 100644 gcc/testsuite/gdc.test/runnable/test11863.d create mode 100644 gcc/testsuite/gdc.test/runnable/test12.d create mode 100644 gcc/testsuite/gdc.test/runnable/test12197.d create mode 100644 gcc/testsuite/gdc.test/runnable/test12874.d create mode 100644 gcc/testsuite/gdc.test/runnable/test13.d create mode 100644 gcc/testsuite/gdc.test/runnable/test13504.d create mode 100644 gcc/testsuite/gdc.test/runnable/test13613.d create mode 100644 gcc/testsuite/gdc.test/runnable/test13944.d create mode 100644 gcc/testsuite/gdc.test/runnable/test14613.d create mode 100644 gcc/testsuite/gdc.test/runnable/test14874.d create mode 100644 gcc/testsuite/gdc.test/runnable/test14901.d create mode 100644 gcc/testsuite/gdc.test/runnable/test14903.d create mode 100644 gcc/testsuite/gdc.test/runnable/test15.d create mode 100644 gcc/testsuite/gdc.test/runnable/test15079.d create mode 100644 gcc/testsuite/gdc.test/runnable/test15913.d create mode 100644 gcc/testsuite/gdc.test/runnable/test16.d create mode 100644 gcc/testsuite/gdc.test/runnable/test16115.d create mode 100644 gcc/testsuite/gdc.test/runnable/test16640.d create mode 100644 gcc/testsuite/gdc.test/runnable/test16980.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17072.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17073.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17338.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17684.d create mode 100644 gcc/testsuite/gdc.test/runnable/test17899.d create mode 100644 gcc/testsuite/gdc.test/runnable/test19.d create mode 100644 gcc/testsuite/gdc.test/runnable/test20.d create mode 100644 gcc/testsuite/gdc.test/runnable/test21.d create mode 100644 gcc/testsuite/gdc.test/runnable/test22.d create mode 100644 gcc/testsuite/gdc.test/runnable/test23.d create mode 100644 gcc/testsuite/gdc.test/runnable/test24.d create mode 100644 gcc/testsuite/gdc.test/runnable/test27.d create mode 100644 gcc/testsuite/gdc.test/runnable/test28.d create mode 100644 gcc/testsuite/gdc.test/runnable/test29.d create mode 100644 gcc/testsuite/gdc.test/runnable/test3.d create mode 100644 gcc/testsuite/gdc.test/runnable/test30.d create mode 100644 gcc/testsuite/gdc.test/runnable/test31.d create mode 100644 gcc/testsuite/gdc.test/runnable/test32.d create mode 100644 gcc/testsuite/gdc.test/runnable/test34.d create mode 100644 gcc/testsuite/gdc.test/runnable/test3449.d create mode 100644 gcc/testsuite/gdc.test/runnable/test3574a.d create mode 100644 gcc/testsuite/gdc.test/runnable/test3574b.d create mode 100644 gcc/testsuite/gdc.test/runnable/test3574c.d create mode 100644 gcc/testsuite/gdc.test/runnable/test3574d.d create mode 100644 gcc/testsuite/gdc.test/runnable/test36.d create mode 100644 gcc/testsuite/gdc.test/runnable/test37.d create mode 100644 gcc/testsuite/gdc.test/runnable/test38.d create mode 100644 gcc/testsuite/gdc.test/runnable/test4.d create mode 100644 gcc/testsuite/gdc.test/runnable/test40.d create mode 100644 gcc/testsuite/gdc.test/runnable/test41.d create mode 100644 gcc/testsuite/gdc.test/runnable/test42.d create mode 100644 gcc/testsuite/gdc.test/runnable/test42a.d create mode 100644 gcc/testsuite/gdc.test/runnable/test435.d create mode 100644 gcc/testsuite/gdc.test/runnable/test45.d create mode 100644 gcc/testsuite/gdc.test/runnable/test46.d create mode 100644 gcc/testsuite/gdc.test/runnable/test48.d create mode 100644 gcc/testsuite/gdc.test/runnable/test49.d create mode 100644 gcc/testsuite/gdc.test/runnable/test5.d create mode 100644 gcc/testsuite/gdc.test/runnable/test52.d create mode 100644 gcc/testsuite/gdc.test/runnable/test5305.d create mode 100644 gcc/testsuite/gdc.test/runnable/test57.d create mode 100644 gcc/testsuite/gdc.test/runnable/test58.d create mode 100644 gcc/testsuite/gdc.test/runnable/test5943.d create mode 100644 gcc/testsuite/gdc.test/runnable/test60.d create mode 100644 gcc/testsuite/gdc.test/runnable/test61.d create mode 100644 gcc/testsuite/gdc.test/runnable/test6423.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7452.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7453.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7494.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7511.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7595.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7603.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7618.d create mode 100644 gcc/testsuite/gdc.test/runnable/test7932.d create mode 100644 gcc/testsuite/gdc.test/runnable/test8.d create mode 100644 gcc/testsuite/gdc.test/runnable/test8182.d create mode 100644 gcc/testsuite/gdc.test/runnable/test8544.d create mode 100644 gcc/testsuite/gdc.test/runnable/test8997.d create mode 100644 gcc/testsuite/gdc.test/runnable/test9259.d create mode 100644 gcc/testsuite/gdc.test/runnable/test9271.d create mode 100644 gcc/testsuite/gdc.test/runnable/test9309.d create mode 100644 gcc/testsuite/gdc.test/runnable/test9495.d create mode 100644 gcc/testsuite/gdc.test/runnable/testaa.d create mode 100644 gcc/testsuite/gdc.test/runnable/testaa2.d create mode 100644 gcc/testsuite/gdc.test/runnable/testaa3.d create mode 100644 gcc/testsuite/gdc.test/runnable/testabi.d create mode 100644 gcc/testsuite/gdc.test/runnable/testappend.d create mode 100644 gcc/testsuite/gdc.test/runnable/testargtypes.d create mode 100644 gcc/testsuite/gdc.test/runnable/testarray.d create mode 100644 gcc/testsuite/gdc.test/runnable/testassign.d create mode 100644 gcc/testsuite/gdc.test/runnable/testbitarray.d create mode 100644 gcc/testsuite/gdc.test/runnable/testbounds.d create mode 100644 gcc/testsuite/gdc.test/runnable/testbounds_off.d create mode 100644 gcc/testsuite/gdc.test/runnable/testbounds_on.d create mode 100644 gcc/testsuite/gdc.test/runnable/testbounds_safeonly.d create mode 100644 gcc/testsuite/gdc.test/runnable/testclass.d create mode 100644 gcc/testsuite/gdc.test/runnable/testconst.d create mode 100644 gcc/testsuite/gdc.test/runnable/testconstsection.d create mode 100644 gcc/testsuite/gdc.test/runnable/testcontracts.d create mode 100644 gcc/testsuite/gdc.test/runnable/testdstress.d create mode 100644 gcc/testsuite/gdc.test/runnable/testdt.d create mode 100644 gcc/testsuite/gdc.test/runnable/testenum.d create mode 100644 gcc/testsuite/gdc.test/runnable/testfile.d create mode 100644 gcc/testsuite/gdc.test/runnable/testformat.d create mode 100644 gcc/testsuite/gdc.test/runnable/testgc2.d create mode 100644 gcc/testsuite/gdc.test/runnable/testgc3.d create mode 100644 gcc/testsuite/gdc.test/runnable/testinvariant.d create mode 100644 gcc/testsuite/gdc.test/runnable/testkeyword.d create mode 100644 gcc/testsuite/gdc.test/runnable/testline.d create mode 100644 gcc/testsuite/gdc.test/runnable/testmain.d create mode 100644 gcc/testsuite/gdc.test/runnable/testminit.d create mode 100644 gcc/testsuite/gdc.test/runnable/testmmfile.d create mode 100644 gcc/testsuite/gdc.test/runnable/testmod1.d create mode 100644 gcc/testsuite/gdc.test/runnable/testmod2.d create mode 100644 gcc/testsuite/gdc.test/runnable/testmodule.d create mode 100644 gcc/testsuite/gdc.test/runnable/testpic.d create mode 100644 gcc/testsuite/gdc.test/runnable/testptrref.d create mode 100644 gcc/testsuite/gdc.test/runnable/testreturn.d create mode 100644 gcc/testsuite/gdc.test/runnable/testrightthis.d create mode 100644 gcc/testsuite/gdc.test/runnable/testsafe.d create mode 100644 gcc/testsuite/gdc.test/runnable/testscope.d create mode 100644 gcc/testsuite/gdc.test/runnable/testscope2.d create mode 100644 gcc/testsuite/gdc.test/runnable/testsignals.d create mode 100644 gcc/testsuite/gdc.test/runnable/testsocket.d create mode 100644 gcc/testsuite/gdc.test/runnable/teststdio.d create mode 100644 gcc/testsuite/gdc.test/runnable/testswitch.d create mode 100644 gcc/testsuite/gdc.test/runnable/testthread.d create mode 100644 gcc/testsuite/gdc.test/runnable/testthread2.d create mode 100644 gcc/testsuite/gdc.test/runnable/testtypeid.d create mode 100644 gcc/testsuite/gdc.test/runnable/testv.d create mode 100644 gcc/testsuite/gdc.test/runnable/tls.d create mode 100644 gcc/testsuite/gdc.test/runnable/tls_dup.d create mode 100644 gcc/testsuite/gdc.test/runnable/traits.d create mode 100644 gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d create mode 100644 gcc/testsuite/gdc.test/runnable/traits_getUnitTests.d create mode 100644 gcc/testsuite/gdc.test/runnable/traits_getVirtualIndex.d create mode 100644 gcc/testsuite/gdc.test/runnable/uda.d create mode 100644 gcc/testsuite/gdc.test/runnable/ufcs.d create mode 100644 gcc/testsuite/gdc.test/runnable/uniformctor.d create mode 100644 gcc/testsuite/gdc.test/runnable/variadic.d create mode 100644 gcc/testsuite/gdc.test/runnable/version.d create mode 100644 gcc/testsuite/gdc.test/runnable/warning1.d create mode 100644 gcc/testsuite/gdc.test/runnable/wc.d create mode 100644 gcc/testsuite/gdc.test/runnable/wc2.d create mode 100644 gcc/testsuite/gdc.test/runnable/wc3.d create mode 100644 gcc/testsuite/gdc.test/runnable/xdtor.d create mode 100644 gcc/testsuite/gdc.test/runnable/xpostblit.d create mode 100644 gcc/testsuite/gdc.test/runnable/xtest46.d create mode 100644 gcc/testsuite/gdc.test/runnable/xtest55.d create mode 100644 gcc/testsuite/gdc.test/runnable/xtestenum.d create mode 100644 gcc/testsuite/lib/gdc-dg.exp create mode 100644 gcc/testsuite/lib/gdc.exp create mode 100644 libphobos/ChangeLog create mode 100644 libphobos/Makefile.am create mode 100644 libphobos/Makefile.in create mode 100644 libphobos/acinclude.m4 create mode 100644 libphobos/aclocal.m4 create mode 100644 libphobos/config.h.in create mode 100755 libphobos/configure create mode 100644 libphobos/configure.ac create mode 100644 libphobos/d_rules.am create mode 100644 libphobos/libdruntime/LICENSE create mode 100644 libphobos/libdruntime/Makefile.am create mode 100644 libphobos/libdruntime/Makefile.in create mode 100644 libphobos/libdruntime/__entrypoint.di create mode 100644 libphobos/libdruntime/__main.di create mode 100644 libphobos/libdruntime/core/atomic.d create mode 100644 libphobos/libdruntime/core/attribute.d create mode 100644 libphobos/libdruntime/core/bitop.d create mode 100644 libphobos/libdruntime/core/checkedint.d create mode 100644 libphobos/libdruntime/core/cpuid.d create mode 100644 libphobos/libdruntime/core/demangle.d create mode 100644 libphobos/libdruntime/core/exception.d create mode 100644 libphobos/libdruntime/core/internal/abort.d create mode 100644 libphobos/libdruntime/core/internal/arrayop.d create mode 100644 libphobos/libdruntime/core/internal/convert.d create mode 100644 libphobos/libdruntime/core/internal/hash.d create mode 100644 libphobos/libdruntime/core/internal/spinlock.d create mode 100644 libphobos/libdruntime/core/internal/string.d create mode 100644 libphobos/libdruntime/core/internal/traits.d create mode 100644 libphobos/libdruntime/core/math.d create mode 100644 libphobos/libdruntime/core/memory.d create mode 100644 libphobos/libdruntime/core/runtime.d create mode 100644 libphobos/libdruntime/core/simd.d create mode 100644 libphobos/libdruntime/core/stdc/assert_.d create mode 100644 libphobos/libdruntime/core/stdc/complex.d create mode 100644 libphobos/libdruntime/core/stdc/config.d create mode 100644 libphobos/libdruntime/core/stdc/ctype.d create mode 100644 libphobos/libdruntime/core/stdc/errno.d create mode 100644 libphobos/libdruntime/core/stdc/errno_.c create mode 100644 libphobos/libdruntime/core/stdc/fenv.d create mode 100644 libphobos/libdruntime/core/stdc/float_.d create mode 100644 libphobos/libdruntime/core/stdc/inttypes.d create mode 100644 libphobos/libdruntime/core/stdc/limits.d create mode 100644 libphobos/libdruntime/core/stdc/locale.d create mode 100644 libphobos/libdruntime/core/stdc/math.d create mode 100644 libphobos/libdruntime/core/stdc/signal.d create mode 100644 libphobos/libdruntime/core/stdc/stdarg.d create mode 100644 libphobos/libdruntime/core/stdc/stddef.d create mode 100644 libphobos/libdruntime/core/stdc/stdint.d create mode 100644 libphobos/libdruntime/core/stdc/stdio.d create mode 100644 libphobos/libdruntime/core/stdc/stdlib.d create mode 100644 libphobos/libdruntime/core/stdc/string.d create mode 100644 libphobos/libdruntime/core/stdc/tgmath.d create mode 100644 libphobos/libdruntime/core/stdc/time.d create mode 100644 libphobos/libdruntime/core/stdc/wchar_.d create mode 100644 libphobos/libdruntime/core/stdc/wctype.d create mode 100644 libphobos/libdruntime/core/stdcpp/exception.d create mode 100644 libphobos/libdruntime/core/stdcpp/typeinfo.d create mode 100644 libphobos/libdruntime/core/sync/barrier.d create mode 100644 libphobos/libdruntime/core/sync/condition.d create mode 100644 libphobos/libdruntime/core/sync/config.d create mode 100644 libphobos/libdruntime/core/sync/exception.d create mode 100644 libphobos/libdruntime/core/sync/mutex.d create mode 100644 libphobos/libdruntime/core/sync/rwmutex.d create mode 100644 libphobos/libdruntime/core/sync/semaphore.d create mode 100644 libphobos/libdruntime/core/sys/bionic/fcntl.d create mode 100644 libphobos/libdruntime/core/sys/bionic/unistd.d create mode 100644 libphobos/libdruntime/core/sys/darwin/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/darwin/execinfo.d create mode 100644 libphobos/libdruntime/core/sys/darwin/mach/dyld.d create mode 100644 libphobos/libdruntime/core/sys/darwin/mach/getsect.d create mode 100644 libphobos/libdruntime/core/sys/darwin/mach/kern_return.d create mode 100644 libphobos/libdruntime/core/sys/darwin/mach/loader.d create mode 100644 libphobos/libdruntime/core/sys/darwin/mach/port.d create mode 100644 libphobos/libdruntime/core/sys/darwin/mach/semaphore.d create mode 100644 libphobos/libdruntime/core/sys/darwin/mach/thread_act.d create mode 100644 libphobos/libdruntime/core/sys/darwin/netinet/in_.d create mode 100644 libphobos/libdruntime/core/sys/darwin/pthread.d create mode 100644 libphobos/libdruntime/core/sys/darwin/sys/cdefs.d create mode 100644 libphobos/libdruntime/core/sys/darwin/sys/event.d create mode 100644 libphobos/libdruntime/core/sys/darwin/sys/mman.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/execinfo.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/netinet/in_.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/pthread_np.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/_bitset.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/_cpuset.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/cdefs.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/elf.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/elf32.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/elf64.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/elf_common.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/event.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/link_elf.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/sys/mman.d create mode 100644 libphobos/libdruntime/core/sys/dragonflybsd/time.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/execinfo.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/netinet/in_.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/pthread_np.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/_bitset.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/_cpuset.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/cdefs.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/elf.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/elf32.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/elf64.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/elf_common.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/event.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/link_elf.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/mman.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/sys/mount.d create mode 100644 libphobos/libdruntime/core/sys/freebsd/time.d create mode 100644 libphobos/libdruntime/core/sys/linux/config.d create mode 100644 libphobos/libdruntime/core/sys/linux/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/linux/elf.d create mode 100644 libphobos/libdruntime/core/sys/linux/epoll.d create mode 100644 libphobos/libdruntime/core/sys/linux/errno.d create mode 100644 libphobos/libdruntime/core/sys/linux/execinfo.d create mode 100644 libphobos/libdruntime/core/sys/linux/fcntl.d create mode 100644 libphobos/libdruntime/core/sys/linux/ifaddrs.d create mode 100644 libphobos/libdruntime/core/sys/linux/link.d create mode 100644 libphobos/libdruntime/core/sys/linux/netinet/in_.d create mode 100644 libphobos/libdruntime/core/sys/linux/netinet/tcp.d create mode 100644 libphobos/libdruntime/core/sys/linux/sched.d create mode 100644 libphobos/libdruntime/core/sys/linux/stdio.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/auxv.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/eventfd.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/file.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/inotify.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/mman.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/netinet/tcp.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/prctl.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/signalfd.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/socket.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/sysinfo.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/time.d create mode 100644 libphobos/libdruntime/core/sys/linux/sys/xattr.d create mode 100644 libphobos/libdruntime/core/sys/linux/termios.d create mode 100644 libphobos/libdruntime/core/sys/linux/time.d create mode 100644 libphobos/libdruntime/core/sys/linux/timerfd.d create mode 100644 libphobos/libdruntime/core/sys/linux/tipc.d create mode 100644 libphobos/libdruntime/core/sys/linux/unistd.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/execinfo.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/sys/elf.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/sys/elf32.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/sys/elf64.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/sys/elf_common.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/sys/event.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/sys/link_elf.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/sys/mman.d create mode 100644 libphobos/libdruntime/core/sys/netbsd/time.d create mode 100644 libphobos/libdruntime/core/sys/openbsd/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/posix/aio.d create mode 100644 libphobos/libdruntime/core/sys/posix/arpa/inet.d create mode 100644 libphobos/libdruntime/core/sys/posix/config.d create mode 100644 libphobos/libdruntime/core/sys/posix/dirent.d create mode 100644 libphobos/libdruntime/core/sys/posix/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/posix/fcntl.d create mode 100644 libphobos/libdruntime/core/sys/posix/grp.d create mode 100644 libphobos/libdruntime/core/sys/posix/iconv.d create mode 100644 libphobos/libdruntime/core/sys/posix/inttypes.d create mode 100644 libphobos/libdruntime/core/sys/posix/libgen.d create mode 100644 libphobos/libdruntime/core/sys/posix/mqueue.d create mode 100644 libphobos/libdruntime/core/sys/posix/net/if_.d create mode 100644 libphobos/libdruntime/core/sys/posix/netdb.d create mode 100644 libphobos/libdruntime/core/sys/posix/netinet/in_.d create mode 100644 libphobos/libdruntime/core/sys/posix/netinet/tcp.d create mode 100644 libphobos/libdruntime/core/sys/posix/poll.d create mode 100644 libphobos/libdruntime/core/sys/posix/pthread.d create mode 100644 libphobos/libdruntime/core/sys/posix/pwd.d create mode 100644 libphobos/libdruntime/core/sys/posix/sched.d create mode 100644 libphobos/libdruntime/core/sys/posix/semaphore.d create mode 100644 libphobos/libdruntime/core/sys/posix/setjmp.d create mode 100644 libphobos/libdruntime/core/sys/posix/signal.d create mode 100644 libphobos/libdruntime/core/sys/posix/stdio.d create mode 100644 libphobos/libdruntime/core/sys/posix/stdlib.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/filio.d create mode 100755 libphobos/libdruntime/core/sys/posix/sys/ioccom.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/ioctl.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/ipc.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/mman.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/msg.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/resource.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/select.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/shm.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/socket.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/stat.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/statvfs.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/time.d create mode 100755 libphobos/libdruntime/core/sys/posix/sys/ttycom.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/types.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/uio.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/un.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/utsname.d create mode 100644 libphobos/libdruntime/core/sys/posix/sys/wait.d create mode 100644 libphobos/libdruntime/core/sys/posix/syslog.d create mode 100644 libphobos/libdruntime/core/sys/posix/termios.d create mode 100644 libphobos/libdruntime/core/sys/posix/time.d create mode 100644 libphobos/libdruntime/core/sys/posix/ucontext.d create mode 100644 libphobos/libdruntime/core/sys/posix/unistd.d create mode 100644 libphobos/libdruntime/core/sys/posix/utime.d create mode 100644 libphobos/libdruntime/core/sys/solaris/dlfcn.d create mode 100644 libphobos/libdruntime/core/sys/solaris/elf.d create mode 100644 libphobos/libdruntime/core/sys/solaris/execinfo.d create mode 100644 libphobos/libdruntime/core/sys/solaris/libelf.d create mode 100644 libphobos/libdruntime/core/sys/solaris/link.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/elf.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/elf_386.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/elf_amd64.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/elf_notes.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/elftypes.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/link.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/priocntl.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/procset.d create mode 100644 libphobos/libdruntime/core/sys/solaris/sys/types.d create mode 100644 libphobos/libdruntime/core/sys/solaris/time.d create mode 100644 libphobos/libdruntime/core/sys/windows/accctrl.d create mode 100644 libphobos/libdruntime/core/sys/windows/aclapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/aclui.d create mode 100644 libphobos/libdruntime/core/sys/windows/basetsd.d create mode 100644 libphobos/libdruntime/core/sys/windows/basetyps.d create mode 100644 libphobos/libdruntime/core/sys/windows/cderr.d create mode 100644 libphobos/libdruntime/core/sys/windows/cguid.d create mode 100644 libphobos/libdruntime/core/sys/windows/com.d create mode 100644 libphobos/libdruntime/core/sys/windows/comcat.d create mode 100644 libphobos/libdruntime/core/sys/windows/commctrl.d create mode 100644 libphobos/libdruntime/core/sys/windows/commdlg.d create mode 100644 libphobos/libdruntime/core/sys/windows/core.d create mode 100644 libphobos/libdruntime/core/sys/windows/cpl.d create mode 100644 libphobos/libdruntime/core/sys/windows/cplext.d create mode 100644 libphobos/libdruntime/core/sys/windows/custcntl.d create mode 100644 libphobos/libdruntime/core/sys/windows/dbghelp.d create mode 100644 libphobos/libdruntime/core/sys/windows/dbghelp_types.d create mode 100644 libphobos/libdruntime/core/sys/windows/dbt.d create mode 100644 libphobos/libdruntime/core/sys/windows/dde.d create mode 100644 libphobos/libdruntime/core/sys/windows/ddeml.d create mode 100644 libphobos/libdruntime/core/sys/windows/dhcpcsdk.d create mode 100644 libphobos/libdruntime/core/sys/windows/dlgs.d create mode 100644 libphobos/libdruntime/core/sys/windows/dll.d create mode 100644 libphobos/libdruntime/core/sys/windows/docobj.d create mode 100644 libphobos/libdruntime/core/sys/windows/errorrep.d create mode 100644 libphobos/libdruntime/core/sys/windows/exdisp.d create mode 100644 libphobos/libdruntime/core/sys/windows/exdispid.d create mode 100644 libphobos/libdruntime/core/sys/windows/httpext.d create mode 100644 libphobos/libdruntime/core/sys/windows/idispids.d create mode 100644 libphobos/libdruntime/core/sys/windows/imagehlp.d create mode 100644 libphobos/libdruntime/core/sys/windows/imm.d create mode 100644 libphobos/libdruntime/core/sys/windows/intshcut.d create mode 100644 libphobos/libdruntime/core/sys/windows/ipexport.d create mode 100644 libphobos/libdruntime/core/sys/windows/iphlpapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/ipifcons.d create mode 100644 libphobos/libdruntime/core/sys/windows/iprtrmib.d create mode 100644 libphobos/libdruntime/core/sys/windows/iptypes.d create mode 100644 libphobos/libdruntime/core/sys/windows/isguids.d create mode 100644 libphobos/libdruntime/core/sys/windows/lm.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmaccess.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmalert.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmapibuf.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmat.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmaudit.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmbrowsr.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmchdev.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmconfig.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmcons.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmerr.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmerrlog.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmmsg.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmremutl.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmrepl.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmserver.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmshare.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmsname.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmstats.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmsvc.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmuse.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmuseflg.d create mode 100644 libphobos/libdruntime/core/sys/windows/lmwksta.d create mode 100644 libphobos/libdruntime/core/sys/windows/lzexpand.d create mode 100644 libphobos/libdruntime/core/sys/windows/mapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/mciavi.d create mode 100644 libphobos/libdruntime/core/sys/windows/mcx.d create mode 100644 libphobos/libdruntime/core/sys/windows/mgmtapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/mmsystem.d create mode 100644 libphobos/libdruntime/core/sys/windows/msacm.d create mode 100644 libphobos/libdruntime/core/sys/windows/mshtml.d create mode 100644 libphobos/libdruntime/core/sys/windows/mswsock.d create mode 100644 libphobos/libdruntime/core/sys/windows/nb30.d create mode 100644 libphobos/libdruntime/core/sys/windows/nddeapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/nspapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/ntdef.d create mode 100644 libphobos/libdruntime/core/sys/windows/ntdll.d create mode 100644 libphobos/libdruntime/core/sys/windows/ntldap.d create mode 100644 libphobos/libdruntime/core/sys/windows/ntsecapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/ntsecpkg.d create mode 100644 libphobos/libdruntime/core/sys/windows/oaidl.d create mode 100644 libphobos/libdruntime/core/sys/windows/objbase.d create mode 100644 libphobos/libdruntime/core/sys/windows/objfwd.d create mode 100644 libphobos/libdruntime/core/sys/windows/objidl.d create mode 100644 libphobos/libdruntime/core/sys/windows/objsafe.d create mode 100644 libphobos/libdruntime/core/sys/windows/ocidl.d create mode 100644 libphobos/libdruntime/core/sys/windows/odbcinst.d create mode 100644 libphobos/libdruntime/core/sys/windows/ole.d create mode 100644 libphobos/libdruntime/core/sys/windows/ole2.d create mode 100644 libphobos/libdruntime/core/sys/windows/ole2ver.d create mode 100644 libphobos/libdruntime/core/sys/windows/oleacc.d create mode 100644 libphobos/libdruntime/core/sys/windows/oleauto.d create mode 100644 libphobos/libdruntime/core/sys/windows/olectl.d create mode 100644 libphobos/libdruntime/core/sys/windows/olectlid.d create mode 100644 libphobos/libdruntime/core/sys/windows/oledlg.d create mode 100644 libphobos/libdruntime/core/sys/windows/oleidl.d create mode 100644 libphobos/libdruntime/core/sys/windows/pbt.d create mode 100644 libphobos/libdruntime/core/sys/windows/powrprof.d create mode 100644 libphobos/libdruntime/core/sys/windows/prsht.d create mode 100644 libphobos/libdruntime/core/sys/windows/psapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/rapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/ras.d create mode 100644 libphobos/libdruntime/core/sys/windows/rasdlg.d create mode 100644 libphobos/libdruntime/core/sys/windows/raserror.d create mode 100644 libphobos/libdruntime/core/sys/windows/rassapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/reason.d create mode 100644 libphobos/libdruntime/core/sys/windows/regstr.d create mode 100644 libphobos/libdruntime/core/sys/windows/richedit.d create mode 100644 libphobos/libdruntime/core/sys/windows/richole.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpc.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpcdce.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpcdce2.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpcdcep.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpcndr.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpcnsi.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpcnsip.d create mode 100644 libphobos/libdruntime/core/sys/windows/rpcnterr.d create mode 100644 libphobos/libdruntime/core/sys/windows/schannel.d create mode 100644 libphobos/libdruntime/core/sys/windows/secext.d create mode 100644 libphobos/libdruntime/core/sys/windows/security.d create mode 100644 libphobos/libdruntime/core/sys/windows/servprov.d create mode 100644 libphobos/libdruntime/core/sys/windows/setupapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/shellapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/shldisp.d create mode 100644 libphobos/libdruntime/core/sys/windows/shlguid.d create mode 100644 libphobos/libdruntime/core/sys/windows/shlobj.d create mode 100644 libphobos/libdruntime/core/sys/windows/shlwapi.d create mode 100644 libphobos/libdruntime/core/sys/windows/snmp.d create mode 100644 libphobos/libdruntime/core/sys/windows/sql.d create mode 100644 libphobos/libdruntime/core/sys/windows/sqlext.d create mode 100644 libphobos/libdruntime/core/sys/windows/sqltypes.d create mode 100644 libphobos/libdruntime/core/sys/windows/sqlucode.d create mode 100644 libphobos/libdruntime/core/sys/windows/sspi.d create mode 100644 libphobos/libdruntime/core/sys/windows/stacktrace.d create mode 100644 libphobos/libdruntime/core/sys/windows/stat.d create mode 100644 libphobos/libdruntime/core/sys/windows/subauth.d create mode 100644 libphobos/libdruntime/core/sys/windows/threadaux.d create mode 100644 libphobos/libdruntime/core/sys/windows/tlhelp32.d create mode 100644 libphobos/libdruntime/core/sys/windows/tmschema.d create mode 100644 libphobos/libdruntime/core/sys/windows/unknwn.d create mode 100644 libphobos/libdruntime/core/sys/windows/uuid.d create mode 100644 libphobos/libdruntime/core/sys/windows/vfw.d create mode 100644 libphobos/libdruntime/core/sys/windows/w32api.d create mode 100644 libphobos/libdruntime/core/sys/windows/winbase.d create mode 100644 libphobos/libdruntime/core/sys/windows/winber.d create mode 100644 libphobos/libdruntime/core/sys/windows/wincon.d create mode 100644 libphobos/libdruntime/core/sys/windows/wincrypt.d create mode 100644 libphobos/libdruntime/core/sys/windows/windef.d create mode 100644 libphobos/libdruntime/core/sys/windows/windows.d create mode 100644 libphobos/libdruntime/core/sys/windows/winerror.d create mode 100644 libphobos/libdruntime/core/sys/windows/wingdi.d create mode 100644 libphobos/libdruntime/core/sys/windows/winhttp.d create mode 100644 libphobos/libdruntime/core/sys/windows/wininet.d create mode 100644 libphobos/libdruntime/core/sys/windows/winioctl.d create mode 100644 libphobos/libdruntime/core/sys/windows/winldap.d create mode 100644 libphobos/libdruntime/core/sys/windows/winnetwk.d create mode 100644 libphobos/libdruntime/core/sys/windows/winnls.d create mode 100644 libphobos/libdruntime/core/sys/windows/winnt.d create mode 100644 libphobos/libdruntime/core/sys/windows/winperf.d create mode 100644 libphobos/libdruntime/core/sys/windows/winreg.d create mode 100644 libphobos/libdruntime/core/sys/windows/winsock2.d create mode 100644 libphobos/libdruntime/core/sys/windows/winspool.d create mode 100644 libphobos/libdruntime/core/sys/windows/winsvc.d create mode 100644 libphobos/libdruntime/core/sys/windows/winuser.d create mode 100644 libphobos/libdruntime/core/sys/windows/winver.d create mode 100644 libphobos/libdruntime/core/sys/windows/wtsapi32.d create mode 100644 libphobos/libdruntime/core/sys/windows/wtypes.d create mode 100644 libphobos/libdruntime/core/thread.d create mode 100644 libphobos/libdruntime/core/threadasm.S create mode 100644 libphobos/libdruntime/core/time.d create mode 100644 libphobos/libdruntime/core/vararg.d create mode 100644 libphobos/libdruntime/gc/bits.d create mode 100644 libphobos/libdruntime/gc/config.d create mode 100644 libphobos/libdruntime/gc/gcinterface.d create mode 100644 libphobos/libdruntime/gc/impl/conservative/gc.d create mode 100644 libphobos/libdruntime/gc/impl/manual/gc.d create mode 100644 libphobos/libdruntime/gc/os.d create mode 100644 libphobos/libdruntime/gc/pooltable.d create mode 100644 libphobos/libdruntime/gc/proxy.d create mode 100644 libphobos/libdruntime/gcc/attribute.d create mode 100644 libphobos/libdruntime/gcc/backtrace.d create mode 100644 libphobos/libdruntime/gcc/builtins.d create mode 100644 libphobos/libdruntime/gcc/config.d.in create mode 100644 libphobos/libdruntime/gcc/deh.d create mode 100644 libphobos/libdruntime/gcc/libbacktrace.d.in create mode 100644 libphobos/libdruntime/gcc/unwind/arm.d create mode 100644 libphobos/libdruntime/gcc/unwind/arm_common.d create mode 100644 libphobos/libdruntime/gcc/unwind/c6x.d create mode 100644 libphobos/libdruntime/gcc/unwind/generic.d create mode 100644 libphobos/libdruntime/gcc/unwind/package.d create mode 100644 libphobos/libdruntime/gcc/unwind/pe.d create mode 100644 libphobos/libdruntime/gcstub/gc.d create mode 100644 libphobos/libdruntime/object.d create mode 100644 libphobos/libdruntime/rt/aApply.d create mode 100644 libphobos/libdruntime/rt/aApplyR.d create mode 100644 libphobos/libdruntime/rt/aaA.d create mode 100644 libphobos/libdruntime/rt/adi.d create mode 100644 libphobos/libdruntime/rt/arrayassign.d create mode 100644 libphobos/libdruntime/rt/arraycast.d create mode 100644 libphobos/libdruntime/rt/arraycat.d create mode 100644 libphobos/libdruntime/rt/bss_section.c create mode 100644 libphobos/libdruntime/rt/cast_.d create mode 100644 libphobos/libdruntime/rt/config.d create mode 100644 libphobos/libdruntime/rt/critical_.d create mode 100644 libphobos/libdruntime/rt/deh.d create mode 100644 libphobos/libdruntime/rt/dmain2.d create mode 100644 libphobos/libdruntime/rt/dylib_fixes.c create mode 100644 libphobos/libdruntime/rt/invariant.d create mode 100644 libphobos/libdruntime/rt/lifetime.d create mode 100644 libphobos/libdruntime/rt/memory.d create mode 100644 libphobos/libdruntime/rt/minfo.d create mode 100644 libphobos/libdruntime/rt/monitor_.d create mode 100644 libphobos/libdruntime/rt/obj.d create mode 100644 libphobos/libdruntime/rt/qsort.d create mode 100644 libphobos/libdruntime/rt/sections.d create mode 100644 libphobos/libdruntime/rt/sections_android.d create mode 100644 libphobos/libdruntime/rt/sections_elf_shared.d create mode 100644 libphobos/libdruntime/rt/sections_osx.d create mode 100644 libphobos/libdruntime/rt/sections_solaris.d create mode 100644 libphobos/libdruntime/rt/sections_win32.d create mode 100644 libphobos/libdruntime/rt/sections_win64.d create mode 100644 libphobos/libdruntime/rt/switch_.d create mode 100644 libphobos/libdruntime/rt/tlsgc.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Acdouble.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Acfloat.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Acreal.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Adouble.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Afloat.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Ag.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Aint.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Along.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Areal.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_Ashort.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_C.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_byte.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_cdouble.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_cent.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_cfloat.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_char.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_creal.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_dchar.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_delegate.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_double.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_float.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_idouble.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_ifloat.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_int.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_ireal.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_long.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_n.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_ptr.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_real.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_short.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_ubyte.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_ucent.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_uint.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_ulong.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_ushort.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_void.d create mode 100644 libphobos/libdruntime/rt/typeinfo/ti_wchar.d create mode 100644 libphobos/libdruntime/rt/util/array.d create mode 100644 libphobos/libdruntime/rt/util/container/array.d create mode 100644 libphobos/libdruntime/rt/util/container/common.d create mode 100644 libphobos/libdruntime/rt/util/container/hashtab.d create mode 100644 libphobos/libdruntime/rt/util/container/treap.d create mode 100644 libphobos/libdruntime/rt/util/hash.d create mode 100644 libphobos/libdruntime/rt/util/random.d create mode 100644 libphobos/libdruntime/rt/util/typeinfo.d create mode 100644 libphobos/libdruntime/rt/util/utf.d create mode 100644 libphobos/m4/autoconf.m4 create mode 100644 libphobos/m4/druntime.m4 create mode 100644 libphobos/m4/druntime/cpu.m4 create mode 100644 libphobos/m4/druntime/libraries.m4 create mode 100644 libphobos/m4/druntime/os.m4 create mode 100644 libphobos/m4/gcc_support.m4 create mode 100644 libphobos/m4/gdc.m4 create mode 100644 libphobos/m4/libtool.m4 create mode 100644 libphobos/src/LICENSE_1_0.txt create mode 100644 libphobos/src/Makefile.am create mode 100644 libphobos/src/Makefile.in create mode 100644 libphobos/src/etc/c/curl.d create mode 100644 libphobos/src/etc/c/sqlite3.d create mode 100644 libphobos/src/etc/c/zlib.d create mode 100644 libphobos/src/index.d create mode 100644 libphobos/src/libgphobos.spec.in create mode 100644 libphobos/src/std/algorithm/comparison.d create mode 100644 libphobos/src/std/algorithm/internal.d create mode 100644 libphobos/src/std/algorithm/iteration.d create mode 100644 libphobos/src/std/algorithm/mutation.d create mode 100644 libphobos/src/std/algorithm/package.d create mode 100644 libphobos/src/std/algorithm/searching.d create mode 100644 libphobos/src/std/algorithm/setops.d create mode 100644 libphobos/src/std/algorithm/sorting.d create mode 100644 libphobos/src/std/array.d create mode 100644 libphobos/src/std/ascii.d create mode 100644 libphobos/src/std/base64.d create mode 100644 libphobos/src/std/bigint.d create mode 100644 libphobos/src/std/bitmanip.d create mode 100644 libphobos/src/std/compiler.d create mode 100644 libphobos/src/std/complex.d create mode 100644 libphobos/src/std/concurrency.d create mode 100644 libphobos/src/std/container/array.d create mode 100644 libphobos/src/std/container/binaryheap.d create mode 100644 libphobos/src/std/container/dlist.d create mode 100644 libphobos/src/std/container/package.d create mode 100644 libphobos/src/std/container/rbtree.d create mode 100644 libphobos/src/std/container/slist.d create mode 100644 libphobos/src/std/container/util.d create mode 100644 libphobos/src/std/conv.d create mode 100644 libphobos/src/std/csv.d create mode 100644 libphobos/src/std/datetime/date.d create mode 100644 libphobos/src/std/datetime/interval.d create mode 100644 libphobos/src/std/datetime/package.d create mode 100644 libphobos/src/std/datetime/stopwatch.d create mode 100644 libphobos/src/std/datetime/systime.d create mode 100644 libphobos/src/std/datetime/timezone.d create mode 100644 libphobos/src/std/demangle.d create mode 100644 libphobos/src/std/digest/crc.d create mode 100644 libphobos/src/std/digest/digest.d create mode 100644 libphobos/src/std/digest/hmac.d create mode 100644 libphobos/src/std/digest/md.d create mode 100644 libphobos/src/std/digest/murmurhash.d create mode 100644 libphobos/src/std/digest/package.d create mode 100644 libphobos/src/std/digest/ripemd.d create mode 100644 libphobos/src/std/digest/sha.d create mode 100644 libphobos/src/std/encoding.d create mode 100644 libphobos/src/std/exception.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/affix_allocator.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/bitmapped_block.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/bucketizer.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/fallback_allocator.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/free_list.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/free_tree.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/kernighan_ritchie.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/null_allocator.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/package.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/quantizer.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/region.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/scoped_allocator.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/segregator.d create mode 100644 libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d create mode 100644 libphobos/src/std/experimental/allocator/common.d create mode 100644 libphobos/src/std/experimental/allocator/gc_allocator.d create mode 100644 libphobos/src/std/experimental/allocator/mallocator.d create mode 100644 libphobos/src/std/experimental/allocator/mmap_allocator.d create mode 100644 libphobos/src/std/experimental/allocator/package.d create mode 100644 libphobos/src/std/experimental/allocator/showcase.d create mode 100644 libphobos/src/std/experimental/allocator/typed.d create mode 100644 libphobos/src/std/experimental/checkedint.d create mode 100644 libphobos/src/std/experimental/logger/core.d create mode 100644 libphobos/src/std/experimental/logger/filelogger.d create mode 100644 libphobos/src/std/experimental/logger/multilogger.d create mode 100644 libphobos/src/std/experimental/logger/nulllogger.d create mode 100644 libphobos/src/std/experimental/logger/package.d create mode 100644 libphobos/src/std/experimental/note.md create mode 100644 libphobos/src/std/experimental/typecons.d create mode 100644 libphobos/src/std/file.d create mode 100644 libphobos/src/std/format.d create mode 100644 libphobos/src/std/functional.d create mode 100644 libphobos/src/std/getopt.d create mode 100644 libphobos/src/std/internal/cstring.d create mode 100644 libphobos/src/std/internal/digest/sha_SSSE3.d create mode 100644 libphobos/src/std/internal/math/biguintcore.d create mode 100644 libphobos/src/std/internal/math/biguintnoasm.d create mode 100644 libphobos/src/std/internal/math/biguintx86.d create mode 100644 libphobos/src/std/internal/math/errorfunction.d create mode 100644 libphobos/src/std/internal/math/gammafunction.d create mode 100644 libphobos/src/std/internal/scopebuffer.d create mode 100644 libphobos/src/std/internal/test/dummyrange.d create mode 100644 libphobos/src/std/internal/test/range.d create mode 100644 libphobos/src/std/internal/test/uda.d create mode 100644 libphobos/src/std/internal/unicode_comp.d create mode 100644 libphobos/src/std/internal/unicode_decomp.d create mode 100644 libphobos/src/std/internal/unicode_grapheme.d create mode 100644 libphobos/src/std/internal/unicode_norm.d create mode 100644 libphobos/src/std/internal/unicode_tables.d create mode 100644 libphobos/src/std/internal/windows/advapi32.d create mode 100644 libphobos/src/std/json.d create mode 100644 libphobos/src/std/math.d create mode 100644 libphobos/src/std/mathspecial.d create mode 100644 libphobos/src/std/meta.d create mode 100644 libphobos/src/std/mmfile.d create mode 100644 libphobos/src/std/net/curl.d create mode 100644 libphobos/src/std/net/isemail.d create mode 100644 libphobos/src/std/numeric.d create mode 100644 libphobos/src/std/outbuffer.d create mode 100644 libphobos/src/std/parallelism.d create mode 100644 libphobos/src/std/path.d create mode 100644 libphobos/src/std/process.d create mode 100644 libphobos/src/std/random.d create mode 100644 libphobos/src/std/range/interfaces.d create mode 100644 libphobos/src/std/range/package.d create mode 100644 libphobos/src/std/range/primitives.d create mode 100644 libphobos/src/std/regex/internal/backtracking.d create mode 100644 libphobos/src/std/regex/internal/generator.d create mode 100644 libphobos/src/std/regex/internal/ir.d create mode 100644 libphobos/src/std/regex/internal/kickstart.d create mode 100644 libphobos/src/std/regex/internal/parser.d create mode 100644 libphobos/src/std/regex/internal/tests.d create mode 100644 libphobos/src/std/regex/internal/thompson.d create mode 100644 libphobos/src/std/regex/package.d create mode 100644 libphobos/src/std/signals.d create mode 100644 libphobos/src/std/socket.d create mode 100644 libphobos/src/std/stdint.d create mode 100644 libphobos/src/std/stdio.d create mode 100644 libphobos/src/std/string.d create mode 100644 libphobos/src/std/system.d create mode 100644 libphobos/src/std/traits.d create mode 100644 libphobos/src/std/typecons.d create mode 100644 libphobos/src/std/typetuple.d create mode 100644 libphobos/src/std/uni.d create mode 100644 libphobos/src/std/uri.d create mode 100644 libphobos/src/std/utf.d create mode 100644 libphobos/src/std/uuid.d create mode 100644 libphobos/src/std/variant.d create mode 100644 libphobos/src/std/windows/charset.d create mode 100644 libphobos/src/std/windows/registry.d create mode 100644 libphobos/src/std/windows/syserror.d create mode 100644 libphobos/src/std/xml.d create mode 100644 libphobos/src/std/zip.d create mode 100644 libphobos/src/std/zlib.d create mode 100644 libphobos/testsuite/Makefile.am create mode 100644 libphobos/testsuite/Makefile.in create mode 100644 libphobos/testsuite/config/default.exp create mode 100644 libphobos/testsuite/lib/libphobos-dg.exp create mode 100644 libphobos/testsuite/lib/libphobos.exp create mode 100644 libphobos/testsuite/libphobos.allocations/allocations.exp create mode 100644 libphobos/testsuite/libphobos.allocations/overflow_from_existing.d create mode 100644 libphobos/testsuite/libphobos.allocations/overflow_from_zero.d create mode 100644 libphobos/testsuite/libphobos.cycles/cycles.exp create mode 100644 libphobos/testsuite/libphobos.cycles/mod1.d create mode 100644 libphobos/testsuite/libphobos.cycles/mod2.d create mode 100644 libphobos/testsuite/libphobos.cycles/mod3.d create mode 100644 libphobos/testsuite/libphobos.exceptions/chain.d create mode 100644 libphobos/testsuite/libphobos.exceptions/exceptions.exp create mode 100644 libphobos/testsuite/libphobos.exceptions/invalid_memory_operation.d create mode 100644 libphobos/testsuite/libphobos.exceptions/line_trace.d create mode 100644 libphobos/testsuite/libphobos.exceptions/static_dtor.d create mode 100644 libphobos/testsuite/libphobos.exceptions/stderr_msg.d create mode 100644 libphobos/testsuite/libphobos.exceptions/unittest_assert.d create mode 100644 libphobos/testsuite/libphobos.exceptions/unknown_gc.d create mode 100644 libphobos/testsuite/libphobos.init_fini/init_fini.exp create mode 100644 libphobos/testsuite/libphobos.init_fini/runtime_args.d create mode 100644 libphobos/testsuite/libphobos.init_fini/thread_join.d create mode 100644 libphobos/testsuite/libphobos.shared/finalize.d create mode 100644 libphobos/testsuite/libphobos.shared/host.c create mode 100644 libphobos/testsuite/libphobos.shared/lib.d create mode 100644 libphobos/testsuite/libphobos.shared/lib_13414.d create mode 100644 libphobos/testsuite/libphobos.shared/liblinkdep.d create mode 100644 libphobos/testsuite/libphobos.shared/libloaddep.d create mode 100644 libphobos/testsuite/libphobos.shared/link.d create mode 100644 libphobos/testsuite/libphobos.shared/linkD.c create mode 100644 libphobos/testsuite/libphobos.shared/linkDR.c create mode 100644 libphobos/testsuite/libphobos.shared/link_linkdep.d create mode 100644 libphobos/testsuite/libphobos.shared/link_loaddep.d create mode 100644 libphobos/testsuite/libphobos.shared/link_mod_collision.d create mode 100644 libphobos/testsuite/libphobos.shared/load.d create mode 100644 libphobos/testsuite/libphobos.shared/loadDR.c create mode 100644 libphobos/testsuite/libphobos.shared/load_13414.d create mode 100644 libphobos/testsuite/libphobos.shared/load_linkdep.d create mode 100644 libphobos/testsuite/libphobos.shared/load_loaddep.d create mode 100644 libphobos/testsuite/libphobos.shared/load_mod_collision.d create mode 100644 libphobos/testsuite/libphobos.shared/plugin.d create mode 100644 libphobos/testsuite/libphobos.shared/shared.exp create mode 100644 libphobos/testsuite/libphobos.thread/fiber_guard_page.d create mode 100644 libphobos/testsuite/libphobos.thread/thread.exp create mode 100644 libphobos/testsuite/libphobos.typeinfo/comparison.d create mode 100644 libphobos/testsuite/libphobos.typeinfo/typeinfo.exp create mode 100644 libphobos/testsuite/libphobos.unittests/unittests.exp create mode 100644 libphobos/testsuite/test_runner.d create mode 100755 libphobos/testsuite/testsuite_flags.in diff --git a/ChangeLog b/ChangeLog index dff4aadb24c..3ad23042bdd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2018-10-28 Iain Buclaw + + * 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. + 2018-10-24 Ilya Leoshkevich * MAINTAINERS (Write After Approval): Add myself. diff --git a/Makefile.def b/Makefile.def index 31c2bbcd549..1aab271d8aa 100644 --- a/Makefile.def +++ b/Makefile.def @@ -153,6 +153,8 @@ target_modules = { module= libgfortran; }; target_modules = { module= libobjc; }; target_modules = { module= libgo; }; target_modules = { module= libhsail-rt; }; +target_modules = { module= libphobos; + lib_path=src/.libs; }; target_modules = { module= libtermcap; no_check=true; missing=mostlyclean; missing=clean; @@ -265,6 +267,8 @@ flags_to_pass = { flag= STAGE1_CHECKING ; }; flags_to_pass = { flag= STAGE1_LANGUAGES ; }; flags_to_pass = { flag= GNATBIND ; }; flags_to_pass = { flag= GNATMAKE ; }; +flags_to_pass = { flag= GDC ; }; +flags_to_pass = { flag= GDCFLAGS ; }; // Target tools flags_to_pass = { flag= AR_FOR_TARGET ; }; @@ -278,6 +282,8 @@ flags_to_pass = { flag= FLAGS_FOR_TARGET ; }; flags_to_pass = { flag= GFORTRAN_FOR_TARGET ; }; flags_to_pass = { flag= GOC_FOR_TARGET ; }; flags_to_pass = { flag= GOCFLAGS_FOR_TARGET ; }; +flags_to_pass = { flag= GDC_FOR_TARGET ; }; +flags_to_pass = { flag= GDCFLAGS_FOR_TARGET ; }; flags_to_pass = { flag= LD_FOR_TARGET ; }; flags_to_pass = { flag= LIPO_FOR_TARGET ; }; flags_to_pass = { flag= LDFLAGS_FOR_TARGET ; }; @@ -544,6 +550,11 @@ dependencies = { module=configure-target-libgo; on=all-target-libstdc++-v3; }; dependencies = { module=all-target-libgo; on=all-target-libbacktrace; }; dependencies = { module=all-target-libgo; on=all-target-libffi; }; dependencies = { module=all-target-libgo; on=all-target-libatomic; }; +dependencies = { module=configure-target-libphobos; on=configure-target-libbacktrace; }; +dependencies = { module=configure-target-libphobos; on=configure-target-zlib; }; +dependencies = { module=all-target-libphobos; on=all-target-libbacktrace; }; +dependencies = { module=all-target-libphobos; on=all-target-zlib; }; +dependencies = { module=all-target-libphobos; on=all-target-libatomic; }; dependencies = { module=configure-target-libstdc++-v3; on=configure-target-libgomp; }; dependencies = { module=configure-target-liboffloadmic; on=configure-target-libgomp; }; dependencies = { module=configure-target-libsanitizer; on=all-target-libstdc++-v3; }; @@ -557,6 +568,7 @@ dependencies = { module=all-target-liboffloadmic; on=all-target-libgomp; }; dependencies = { module=install-target-libgo; on=install-target-libatomic; }; dependencies = { module=install-target-libgfortran; on=install-target-libquadmath; }; dependencies = { module=install-target-libgfortran; on=install-target-libgcc; }; +dependencies = { module=install-target-libphobos; on=install-target-libatomic; }; dependencies = { module=install-target-libsanitizer; on=install-target-libstdc++-v3; }; dependencies = { module=install-target-libsanitizer; on=install-target-libgcc; }; dependencies = { module=install-target-libvtv; on=install-target-libstdc++-v3; }; @@ -598,6 +610,8 @@ languages = { language=go; gcc-check-target=check-go; lib-check-target=check-gotools; }; languages = { language=brig; gcc-check-target=check-brig; lib-check-target=check-target-libhsail-rt; }; +languages = { language=d; gcc-check-target=check-d; + lib-check-target=check-target-libphobos; }; // Toplevel bootstrap bootstrap_stage = { id=1 ; }; diff --git a/Makefile.in b/Makefile.in index e0dfad337a6..899f4332ce0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -156,6 +156,8 @@ BUILD_EXPORTS = \ GFORTRAN="$(GFORTRAN_FOR_BUILD)"; export GFORTRAN; \ GOC="$(GOC_FOR_BUILD)"; export GOC; \ GOCFLAGS="$(GOCFLAGS_FOR_BUILD)"; export GOCFLAGS; \ + GDC="$(GDC_FOR_BUILD)"; export GDC; \ + GDCFLAGS="$(GDCFLAGS_FOR_BUILD)"; export GDCFLAGS; \ DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \ LD="$(LD_FOR_BUILD)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \ @@ -192,6 +194,7 @@ HOST_EXPORTS = \ CXXFLAGS="$(CXXFLAGS)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN)"; export GFORTRAN; \ GOC="$(GOC)"; export GOC; \ + GDC="$(GDC)"; export GDC; \ AR="$(AR)"; export AR; \ AS="$(AS)"; export AS; \ CC_FOR_BUILD="$(CC_FOR_BUILD)"; export CC_FOR_BUILD; \ @@ -256,6 +259,14 @@ POSTSTAGE1_HOST_EXPORTS = \ CC_FOR_BUILD="$$CC"; export CC_FOR_BUILD; \ $(POSTSTAGE1_CXX_EXPORT) \ $(LTO_EXPORTS) \ + GDC="$$r/$(HOST_SUBDIR)/prev-gcc/gdc$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ \ + -B$(build_tooldir)/bin/ $(GDC_FLAGS_FOR_TARGET) \ + -B$$r/prev-$(TARGET_SUBDIR)/libphobos/src \ + -I$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime -I$$s/libphobos/libdruntime \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/src/.libs \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime/.libs"; \ + export GDC; \ + GDC_FOR_BUILD="$$GDC"; export GDC_FOR_BUILD; \ GNATBIND="$$r/$(HOST_SUBDIR)/prev-gcc/gnatbind"; export GNATBIND; \ LDFLAGS="$(POSTSTAGE1_LDFLAGS) $(BOOT_LDFLAGS)"; export LDFLAGS; \ HOST_LIBS="$(POSTSTAGE1_LIBS)"; export HOST_LIBS; @@ -278,6 +289,7 @@ BASE_TARGET_EXPORTS = \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GFORTRAN; \ GOC="$(GOC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GOC; \ + GDC="$(GDC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GDC; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -342,6 +354,7 @@ CXX_FOR_BUILD = @CXX_FOR_BUILD@ DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ GFORTRAN_FOR_BUILD = @GFORTRAN_FOR_BUILD@ GOC_FOR_BUILD = @GOC_FOR_BUILD@ +GDC_FOR_BUILD = @GDC_FOR_BUILD@ LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ LD_FOR_BUILD = @LD_FOR_BUILD@ NM_FOR_BUILD = @NM_FOR_BUILD@ @@ -399,6 +412,7 @@ STRIP = @STRIP@ WINDRES = @WINDRES@ WINDMC = @WINDMC@ +GDC = @GDC@ GNATBIND = @GNATBIND@ GNATMAKE = @GNATMAKE@ @@ -408,6 +422,7 @@ LIBCFLAGS = $(CFLAGS) CXXFLAGS = @CXXFLAGS@ LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates GOCFLAGS = $(CFLAGS) +GDCFLAGS = $(CFLAGS) CREATE_GCOV = create_gcov @@ -574,6 +589,7 @@ CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @CXX_FOR_TARGET@ RAW_CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @RAW_CXX_FOR_TARGET@ GFORTRAN_FOR_TARGET=$(STAGE_CC_WRAPPER) @GFORTRAN_FOR_TARGET@ GOC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GOC_FOR_TARGET@ +GDC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GDC_FOR_TARGET@ DLLTOOL_FOR_TARGET=@DLLTOOL_FOR_TARGET@ LD_FOR_TARGET=@LD_FOR_TARGET@ @@ -598,6 +614,7 @@ LIBCFLAGS_FOR_TARGET = $(CFLAGS_FOR_TARGET) LIBCXXFLAGS_FOR_TARGET = $(CXXFLAGS_FOR_TARGET) -fno-implicit-templates LDFLAGS_FOR_TARGET = @LDFLAGS_FOR_TARGET@ GOCFLAGS_FOR_TARGET = -O2 -g +GDCFLAGS_FOR_TARGET = -O2 -g FLAGS_FOR_TARGET = @FLAGS_FOR_TARGET@ SYSROOT_CFLAGS_FOR_TARGET = @SYSROOT_CFLAGS_FOR_TARGET@ @@ -622,7 +639,7 @@ all: # This is the list of directories that may be needed in RPATH_ENVVAR # so that programs built for the target machine work. -TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libsanitizer)$(TARGET_LIB_PATH_libvtv)$(TARGET_LIB_PATH_liboffloadmic)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc) +TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libsanitizer)$(TARGET_LIB_PATH_libvtv)$(TARGET_LIB_PATH_liboffloadmic)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libphobos)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc) @if target-libstdc++-v3 TARGET_LIB_PATH_libstdc++-v3 = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs: @@ -644,6 +661,10 @@ TARGET_LIB_PATH_liboffloadmic = $$r/$(TARGET_SUBDIR)/liboffloadmic/.libs: TARGET_LIB_PATH_libssp = $$r/$(TARGET_SUBDIR)/libssp/.libs: @endif target-libssp +@if target-libphobos +TARGET_LIB_PATH_libphobos = $$r/$(TARGET_SUBDIR)/libphobos/src/.libs: +@endif target-libphobos + @if target-libgomp TARGET_LIB_PATH_libgomp = $$r/$(TARGET_SUBDIR)/libgomp/.libs: @endif target-libgomp @@ -778,6 +799,8 @@ BASE_FLAGS_TO_PASS = \ "STAGE1_LANGUAGES=$(STAGE1_LANGUAGES)" \ "GNATBIND=$(GNATBIND)" \ "GNATMAKE=$(GNATMAKE)" \ + "GDC=$(GDC)" \ + "GDCFLAGS=$(GDCFLAGS)" \ "AR_FOR_TARGET=$(AR_FOR_TARGET)" \ "AS_FOR_TARGET=$(AS_FOR_TARGET)" \ "CC_FOR_TARGET=$(CC_FOR_TARGET)" \ @@ -789,6 +812,8 @@ BASE_FLAGS_TO_PASS = \ "GFORTRAN_FOR_TARGET=$(GFORTRAN_FOR_TARGET)" \ "GOC_FOR_TARGET=$(GOC_FOR_TARGET)" \ "GOCFLAGS_FOR_TARGET=$(GOCFLAGS_FOR_TARGET)" \ + "GDC_FOR_TARGET=$(GDC_FOR_TARGET)" \ + "GDCFLAGS_FOR_TARGET=$(GDCFLAGS_FOR_TARGET)" \ "LD_FOR_TARGET=$(LD_FOR_TARGET)" \ "LIPO_FOR_TARGET=$(LIPO_FOR_TARGET)" \ "LDFLAGS_FOR_TARGET=$(LDFLAGS_FOR_TARGET)" \ @@ -851,6 +876,7 @@ EXTRA_HOST_FLAGS = \ 'DLLTOOL=$(DLLTOOL)' \ 'GFORTRAN=$(GFORTRAN)' \ 'GOC=$(GOC)' \ + 'GDC=$(GDC)' \ 'LD=$(LD)' \ 'LIPO=$(LIPO)' \ 'NM=$(NM)' \ @@ -875,6 +901,7 @@ STAGE1_FLAGS_TO_PASS = \ POSTSTAGE1_FLAGS_TO_PASS = \ CC="$${CC}" CC_FOR_BUILD="$${CC_FOR_BUILD}" \ CXX="$${CXX}" CXX_FOR_BUILD="$${CXX_FOR_BUILD}" \ + GDC="$${GDC}" GDC_FOR_BUILD="$${GDC_FOR_BUILD}" \ GNATBIND="$${GNATBIND}" \ LDFLAGS="$${LDFLAGS}" \ HOST_LIBS="$${HOST_LIBS}" \ @@ -907,6 +934,8 @@ EXTRA_TARGET_FLAGS = \ 'GFORTRAN=$$(GFORTRAN_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOC=$$(GOC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOCFLAGS=$$(GOCFLAGS_FOR_TARGET)' \ + 'GDC=$$(GDC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ + 'GDCFLAGS=$$(GDCFLAGS_FOR_TARGET)' \ 'LD=$(COMPILER_LD_FOR_TARGET)' \ 'LDFLAGS=$$(LDFLAGS_FOR_TARGET)' \ 'LIBCFLAGS=$$(LIBCFLAGS_FOR_TARGET)' \ @@ -1008,6 +1037,7 @@ configure-target: \ maybe-configure-target-libobjc \ maybe-configure-target-libgo \ maybe-configure-target-libhsail-rt \ + maybe-configure-target-libphobos \ maybe-configure-target-libtermcap \ maybe-configure-target-winsup \ maybe-configure-target-libgloss \ @@ -1170,6 +1200,7 @@ all-target: maybe-all-target-libgfortran all-target: maybe-all-target-libobjc all-target: maybe-all-target-libgo all-target: maybe-all-target-libhsail-rt +all-target: maybe-all-target-libphobos all-target: maybe-all-target-libtermcap all-target: maybe-all-target-winsup all-target: maybe-all-target-libgloss @@ -1261,6 +1292,7 @@ info-target: maybe-info-target-libgfortran info-target: maybe-info-target-libobjc info-target: maybe-info-target-libgo info-target: maybe-info-target-libhsail-rt +info-target: maybe-info-target-libphobos info-target: maybe-info-target-libtermcap info-target: maybe-info-target-winsup info-target: maybe-info-target-libgloss @@ -1345,6 +1377,7 @@ dvi-target: maybe-dvi-target-libgfortran dvi-target: maybe-dvi-target-libobjc dvi-target: maybe-dvi-target-libgo dvi-target: maybe-dvi-target-libhsail-rt +dvi-target: maybe-dvi-target-libphobos dvi-target: maybe-dvi-target-libtermcap dvi-target: maybe-dvi-target-winsup dvi-target: maybe-dvi-target-libgloss @@ -1429,6 +1462,7 @@ pdf-target: maybe-pdf-target-libgfortran pdf-target: maybe-pdf-target-libobjc pdf-target: maybe-pdf-target-libgo pdf-target: maybe-pdf-target-libhsail-rt +pdf-target: maybe-pdf-target-libphobos pdf-target: maybe-pdf-target-libtermcap pdf-target: maybe-pdf-target-winsup pdf-target: maybe-pdf-target-libgloss @@ -1513,6 +1547,7 @@ html-target: maybe-html-target-libgfortran html-target: maybe-html-target-libobjc html-target: maybe-html-target-libgo html-target: maybe-html-target-libhsail-rt +html-target: maybe-html-target-libphobos html-target: maybe-html-target-libtermcap html-target: maybe-html-target-winsup html-target: maybe-html-target-libgloss @@ -1597,6 +1632,7 @@ TAGS-target: maybe-TAGS-target-libgfortran TAGS-target: maybe-TAGS-target-libobjc TAGS-target: maybe-TAGS-target-libgo TAGS-target: maybe-TAGS-target-libhsail-rt +TAGS-target: maybe-TAGS-target-libphobos TAGS-target: maybe-TAGS-target-libtermcap TAGS-target: maybe-TAGS-target-winsup TAGS-target: maybe-TAGS-target-libgloss @@ -1681,6 +1717,7 @@ install-info-target: maybe-install-info-target-libgfortran install-info-target: maybe-install-info-target-libobjc install-info-target: maybe-install-info-target-libgo install-info-target: maybe-install-info-target-libhsail-rt +install-info-target: maybe-install-info-target-libphobos install-info-target: maybe-install-info-target-libtermcap install-info-target: maybe-install-info-target-winsup install-info-target: maybe-install-info-target-libgloss @@ -1765,6 +1802,7 @@ install-pdf-target: maybe-install-pdf-target-libgfortran install-pdf-target: maybe-install-pdf-target-libobjc install-pdf-target: maybe-install-pdf-target-libgo install-pdf-target: maybe-install-pdf-target-libhsail-rt +install-pdf-target: maybe-install-pdf-target-libphobos install-pdf-target: maybe-install-pdf-target-libtermcap install-pdf-target: maybe-install-pdf-target-winsup install-pdf-target: maybe-install-pdf-target-libgloss @@ -1849,6 +1887,7 @@ install-html-target: maybe-install-html-target-libgfortran install-html-target: maybe-install-html-target-libobjc install-html-target: maybe-install-html-target-libgo install-html-target: maybe-install-html-target-libhsail-rt +install-html-target: maybe-install-html-target-libphobos install-html-target: maybe-install-html-target-libtermcap install-html-target: maybe-install-html-target-winsup install-html-target: maybe-install-html-target-libgloss @@ -1933,6 +1972,7 @@ installcheck-target: maybe-installcheck-target-libgfortran installcheck-target: maybe-installcheck-target-libobjc installcheck-target: maybe-installcheck-target-libgo installcheck-target: maybe-installcheck-target-libhsail-rt +installcheck-target: maybe-installcheck-target-libphobos installcheck-target: maybe-installcheck-target-libtermcap installcheck-target: maybe-installcheck-target-winsup installcheck-target: maybe-installcheck-target-libgloss @@ -2017,6 +2057,7 @@ mostlyclean-target: maybe-mostlyclean-target-libgfortran mostlyclean-target: maybe-mostlyclean-target-libobjc mostlyclean-target: maybe-mostlyclean-target-libgo mostlyclean-target: maybe-mostlyclean-target-libhsail-rt +mostlyclean-target: maybe-mostlyclean-target-libphobos mostlyclean-target: maybe-mostlyclean-target-libtermcap mostlyclean-target: maybe-mostlyclean-target-winsup mostlyclean-target: maybe-mostlyclean-target-libgloss @@ -2101,6 +2142,7 @@ clean-target: maybe-clean-target-libgfortran clean-target: maybe-clean-target-libobjc clean-target: maybe-clean-target-libgo clean-target: maybe-clean-target-libhsail-rt +clean-target: maybe-clean-target-libphobos clean-target: maybe-clean-target-libtermcap clean-target: maybe-clean-target-winsup clean-target: maybe-clean-target-libgloss @@ -2185,6 +2227,7 @@ distclean-target: maybe-distclean-target-libgfortran distclean-target: maybe-distclean-target-libobjc distclean-target: maybe-distclean-target-libgo distclean-target: maybe-distclean-target-libhsail-rt +distclean-target: maybe-distclean-target-libphobos distclean-target: maybe-distclean-target-libtermcap distclean-target: maybe-distclean-target-winsup distclean-target: maybe-distclean-target-libgloss @@ -2269,6 +2312,7 @@ maintainer-clean-target: maybe-maintainer-clean-target-libgfortran maintainer-clean-target: maybe-maintainer-clean-target-libobjc maintainer-clean-target: maybe-maintainer-clean-target-libgo maintainer-clean-target: maybe-maintainer-clean-target-libhsail-rt +maintainer-clean-target: maybe-maintainer-clean-target-libphobos maintainer-clean-target: maybe-maintainer-clean-target-libtermcap maintainer-clean-target: maybe-maintainer-clean-target-winsup maintainer-clean-target: maybe-maintainer-clean-target-libgloss @@ -2409,6 +2453,7 @@ check-target: \ maybe-check-target-libobjc \ maybe-check-target-libgo \ maybe-check-target-libhsail-rt \ + maybe-check-target-libphobos \ maybe-check-target-libtermcap \ maybe-check-target-winsup \ maybe-check-target-libgloss \ @@ -2589,6 +2634,7 @@ install-target: \ maybe-install-target-libobjc \ maybe-install-target-libgo \ maybe-install-target-libhsail-rt \ + maybe-install-target-libphobos \ maybe-install-target-libtermcap \ maybe-install-target-winsup \ maybe-install-target-libgloss \ @@ -2693,6 +2739,7 @@ install-strip-target: \ maybe-install-strip-target-libobjc \ maybe-install-strip-target-libgo \ maybe-install-strip-target-libhsail-rt \ + maybe-install-strip-target-libphobos \ maybe-install-strip-target-libtermcap \ maybe-install-strip-target-winsup \ maybe-install-strip-target-libgloss \ @@ -46944,6 +46991,464 @@ maintainer-clean-target-libhsail-rt: +.PHONY: configure-target-libphobos maybe-configure-target-libphobos +maybe-configure-target-libphobos: +@if gcc-bootstrap +configure-target-libphobos: stage_current +@endif gcc-bootstrap +@if target-libphobos +maybe-configure-target-libphobos: configure-target-libphobos +configure-target-libphobos: + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + echo "Checking multilib configuration for libphobos..."; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + $(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libphobos/multilib.tmp 2> /dev/null; \ + if test -r $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + if cmp -s $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; then \ + rm -f $(TARGET_SUBDIR)/libphobos/multilib.tmp; \ + else \ + rm -f $(TARGET_SUBDIR)/libphobos/Makefile; \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + else \ + mv $(TARGET_SUBDIR)/libphobos/multilib.tmp $(TARGET_SUBDIR)/libphobos/multilib.out; \ + fi; \ + test ! -f $(TARGET_SUBDIR)/libphobos/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libphobos; \ + $(NORMAL_TARGET_EXPORTS) \ + echo Configuring in $(TARGET_SUBDIR)/libphobos; \ + cd "$(TARGET_SUBDIR)/libphobos" || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \ + *) topdir=`echo $(TARGET_SUBDIR)/libphobos/ | \ + sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \ + esac; \ + module_srcdir=libphobos; \ + rm -f no-such-file || : ; \ + CONFIG_SITE=no-such-file $(SHELL) \ + $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \ + --target=${target_alias} \ + || exit 1 +@endif target-libphobos + + + + + +.PHONY: all-target-libphobos maybe-all-target-libphobos +maybe-all-target-libphobos: +@if gcc-bootstrap +all-target-libphobos: stage_current +@endif gcc-bootstrap +@if target-libphobos +TARGET-target-libphobos=all +maybe-all-target-libphobos: all-target-libphobos +all-target-libphobos: configure-target-libphobos + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS) \ + $(TARGET-target-libphobos)) +@endif target-libphobos + + + + + +.PHONY: check-target-libphobos maybe-check-target-libphobos +maybe-check-target-libphobos: +@if target-libphobos +maybe-check-target-libphobos: check-target-libphobos + +check-target-libphobos: + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) check) + +@endif target-libphobos + +.PHONY: install-target-libphobos maybe-install-target-libphobos +maybe-install-target-libphobos: +@if target-libphobos +maybe-install-target-libphobos: install-target-libphobos + +install-target-libphobos: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install) + +@endif target-libphobos + +.PHONY: install-strip-target-libphobos maybe-install-strip-target-libphobos +maybe-install-strip-target-libphobos: +@if target-libphobos +maybe-install-strip-target-libphobos: install-strip-target-libphobos + +install-strip-target-libphobos: installdirs + @: $(MAKE); $(unstage) + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install-strip) + +@endif target-libphobos + +# Other targets (info, dvi, pdf, etc.) + +.PHONY: maybe-info-target-libphobos info-target-libphobos +maybe-info-target-libphobos: +@if target-libphobos +maybe-info-target-libphobos: info-target-libphobos + +info-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing info in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + info) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-dvi-target-libphobos dvi-target-libphobos +maybe-dvi-target-libphobos: +@if target-libphobos +maybe-dvi-target-libphobos: dvi-target-libphobos + +dvi-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing dvi in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + dvi) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-pdf-target-libphobos pdf-target-libphobos +maybe-pdf-target-libphobos: +@if target-libphobos +maybe-pdf-target-libphobos: pdf-target-libphobos + +pdf-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing pdf in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + pdf) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-html-target-libphobos html-target-libphobos +maybe-html-target-libphobos: +@if target-libphobos +maybe-html-target-libphobos: html-target-libphobos + +html-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing html in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + html) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-TAGS-target-libphobos TAGS-target-libphobos +maybe-TAGS-target-libphobos: +@if target-libphobos +maybe-TAGS-target-libphobos: TAGS-target-libphobos + +TAGS-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing TAGS in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + TAGS) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-install-info-target-libphobos install-info-target-libphobos +maybe-install-info-target-libphobos: +@if target-libphobos +maybe-install-info-target-libphobos: install-info-target-libphobos + +install-info-target-libphobos: \ + configure-target-libphobos \ + info-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-info in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-info) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-install-pdf-target-libphobos install-pdf-target-libphobos +maybe-install-pdf-target-libphobos: +@if target-libphobos +maybe-install-pdf-target-libphobos: install-pdf-target-libphobos + +install-pdf-target-libphobos: \ + configure-target-libphobos \ + pdf-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-pdf in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-pdf) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-install-html-target-libphobos install-html-target-libphobos +maybe-install-html-target-libphobos: +@if target-libphobos +maybe-install-html-target-libphobos: install-html-target-libphobos + +install-html-target-libphobos: \ + configure-target-libphobos \ + html-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing install-html in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + install-html) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-installcheck-target-libphobos installcheck-target-libphobos +maybe-installcheck-target-libphobos: +@if target-libphobos +maybe-installcheck-target-libphobos: installcheck-target-libphobos + +installcheck-target-libphobos: \ + configure-target-libphobos + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing installcheck in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + installcheck) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-mostlyclean-target-libphobos mostlyclean-target-libphobos +maybe-mostlyclean-target-libphobos: +@if target-libphobos +maybe-mostlyclean-target-libphobos: mostlyclean-target-libphobos + +mostlyclean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing mostlyclean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + mostlyclean) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-clean-target-libphobos clean-target-libphobos +maybe-clean-target-libphobos: +@if target-libphobos +maybe-clean-target-libphobos: clean-target-libphobos + +clean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing clean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + clean) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-distclean-target-libphobos distclean-target-libphobos +maybe-distclean-target-libphobos: +@if target-libphobos +maybe-distclean-target-libphobos: distclean-target-libphobos + +distclean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing distclean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + distclean) \ + || exit 1 + +@endif target-libphobos + +.PHONY: maybe-maintainer-clean-target-libphobos maintainer-clean-target-libphobos +maybe-maintainer-clean-target-libphobos: +@if target-libphobos +maybe-maintainer-clean-target-libphobos: maintainer-clean-target-libphobos + +maintainer-clean-target-libphobos: + @: $(MAKE); $(unstage) + @[ -f $(TARGET_SUBDIR)/libphobos/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(NORMAL_TARGET_EXPORTS) \ + echo "Doing maintainer-clean in $(TARGET_SUBDIR)/libphobos"; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libphobos && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \ + maintainer-clean) \ + || exit 1 + +@endif target-libphobos + + + + + .PHONY: configure-target-libtermcap maybe-configure-target-libtermcap maybe-configure-target-libtermcap: @if gcc-bootstrap @@ -52329,6 +52834,14 @@ check-gcc-brig: (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-brig); check-brig: check-gcc-brig check-target-libhsail-rt +.PHONY: check-gcc-d check-d +check-gcc-d: + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(HOST_EXPORTS) \ + (cd gcc && $(MAKE) $(GCC_FLAGS_TO_PASS) check-d); +check-d: check-gcc-d check-target-libphobos + # The gcc part of install-no-fixedincludes, which relies on an intimate # knowledge of how a number of gcc internal targets (inter)operate. Delegate. @@ -55521,6 +56034,7 @@ configure-target-libgfortran: stage_last configure-target-libobjc: stage_last configure-target-libgo: stage_last configure-target-libhsail-rt: stage_last +configure-target-libphobos: stage_last configure-target-libtermcap: stage_last configure-target-winsup: stage_last configure-target-libgloss: stage_last @@ -55555,6 +56069,7 @@ configure-target-libgfortran: maybe-all-gcc configure-target-libobjc: maybe-all-gcc configure-target-libgo: maybe-all-gcc configure-target-libhsail-rt: maybe-all-gcc +configure-target-libphobos: maybe-all-gcc configure-target-libtermcap: maybe-all-gcc configure-target-winsup: maybe-all-gcc configure-target-libgloss: maybe-all-gcc @@ -56550,6 +57065,11 @@ configure-target-libgo: maybe-configure-target-libffi all-target-libgo: maybe-all-target-libbacktrace all-target-libgo: maybe-all-target-libffi all-target-libgo: maybe-all-target-libatomic +configure-target-libphobos: maybe-configure-target-libbacktrace +configure-target-libphobos: maybe-configure-target-zlib +all-target-libphobos: maybe-all-target-libbacktrace +all-target-libphobos: maybe-all-target-zlib +all-target-libphobos: maybe-all-target-libatomic configure-target-libstdc++-v3: maybe-configure-target-libgomp configure-stage1-target-libstdc++-v3: maybe-configure-stage1-target-libgomp configure-stage2-target-libstdc++-v3: maybe-configure-stage2-target-libgomp @@ -56593,6 +57113,7 @@ all-stageautofeedback-target-libstdc++-v3: maybe-configure-stageautofeedback-tar install-target-libgo: maybe-install-target-libatomic install-target-libgfortran: maybe-install-target-libquadmath install-target-libgfortran: maybe-install-target-libgcc +install-target-libphobos: maybe-install-target-libatomic install-target-libsanitizer: maybe-install-target-libstdc++-v3 install-target-libsanitizer: maybe-install-target-libgcc install-target-libvtv: maybe-install-target-libstdc++-v3 @@ -56717,6 +57238,7 @@ configure-target-libgfortran: maybe-all-target-libgcc configure-target-libobjc: maybe-all-target-libgcc configure-target-libgo: maybe-all-target-libgcc configure-target-libhsail-rt: maybe-all-target-libgcc +configure-target-libphobos: maybe-all-target-libgcc configure-target-libtermcap: maybe-all-target-libgcc configure-target-winsup: maybe-all-target-libgcc configure-target-libgloss: maybe-all-target-libgcc @@ -56755,6 +57277,8 @@ configure-target-libgo: maybe-all-target-newlib maybe-all-target-libgloss configure-target-libhsail-rt: maybe-all-target-newlib maybe-all-target-libgloss +configure-target-libphobos: maybe-all-target-newlib maybe-all-target-libgloss + configure-target-libtermcap: maybe-all-target-newlib maybe-all-target-libgloss configure-target-winsup: maybe-all-target-newlib maybe-all-target-libgloss diff --git a/Makefile.tpl b/Makefile.tpl index 447d324595f..add7bb1052b 100644 --- a/Makefile.tpl +++ b/Makefile.tpl @@ -159,6 +159,8 @@ BUILD_EXPORTS = \ GFORTRAN="$(GFORTRAN_FOR_BUILD)"; export GFORTRAN; \ GOC="$(GOC_FOR_BUILD)"; export GOC; \ GOCFLAGS="$(GOCFLAGS_FOR_BUILD)"; export GOCFLAGS; \ + GDC="$(GDC_FOR_BUILD)"; export GDC; \ + GDCFLAGS="$(GDCFLAGS_FOR_BUILD)"; export GDCFLAGS; \ DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \ LD="$(LD_FOR_BUILD)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \ @@ -195,6 +197,7 @@ HOST_EXPORTS = \ CXXFLAGS="$(CXXFLAGS)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN)"; export GFORTRAN; \ GOC="$(GOC)"; export GOC; \ + GDC="$(GDC)"; export GDC; \ AR="$(AR)"; export AR; \ AS="$(AS)"; export AS; \ CC_FOR_BUILD="$(CC_FOR_BUILD)"; export CC_FOR_BUILD; \ @@ -259,6 +262,14 @@ POSTSTAGE1_HOST_EXPORTS = \ CC_FOR_BUILD="$$CC"; export CC_FOR_BUILD; \ $(POSTSTAGE1_CXX_EXPORT) \ $(LTO_EXPORTS) \ + GDC="$$r/$(HOST_SUBDIR)/prev-gcc/gdc$(exeext) -B$$r/$(HOST_SUBDIR)/prev-gcc/ \ + -B$(build_tooldir)/bin/ $(GDC_FLAGS_FOR_TARGET) \ + -B$$r/prev-$(TARGET_SUBDIR)/libphobos/src \ + -I$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime -I$$s/libphobos/libdruntime \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/src/.libs \ + -L$$r/prev-$(TARGET_SUBDIR)/libphobos/libdruntime/.libs"; \ + export GDC; \ + GDC_FOR_BUILD="$$GDC"; export GDC_FOR_BUILD; \ GNATBIND="$$r/$(HOST_SUBDIR)/prev-gcc/gnatbind"; export GNATBIND; \ LDFLAGS="$(POSTSTAGE1_LDFLAGS) $(BOOT_LDFLAGS)"; export LDFLAGS; \ HOST_LIBS="$(POSTSTAGE1_LIBS)"; export HOST_LIBS; @@ -281,6 +292,7 @@ BASE_TARGET_EXPORTS = \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GFORTRAN="$(GFORTRAN_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GFORTRAN; \ GOC="$(GOC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GOC; \ + GDC="$(GDC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GDC; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -345,6 +357,7 @@ CXX_FOR_BUILD = @CXX_FOR_BUILD@ DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@ GFORTRAN_FOR_BUILD = @GFORTRAN_FOR_BUILD@ GOC_FOR_BUILD = @GOC_FOR_BUILD@ +GDC_FOR_BUILD = @GDC_FOR_BUILD@ LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ LD_FOR_BUILD = @LD_FOR_BUILD@ NM_FOR_BUILD = @NM_FOR_BUILD@ @@ -402,6 +415,7 @@ STRIP = @STRIP@ WINDRES = @WINDRES@ WINDMC = @WINDMC@ +GDC = @GDC@ GNATBIND = @GNATBIND@ GNATMAKE = @GNATMAKE@ @@ -411,6 +425,7 @@ LIBCFLAGS = $(CFLAGS) CXXFLAGS = @CXXFLAGS@ LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates GOCFLAGS = $(CFLAGS) +GDCFLAGS = $(CFLAGS) CREATE_GCOV = create_gcov @@ -497,6 +512,7 @@ CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @CXX_FOR_TARGET@ RAW_CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @RAW_CXX_FOR_TARGET@ GFORTRAN_FOR_TARGET=$(STAGE_CC_WRAPPER) @GFORTRAN_FOR_TARGET@ GOC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GOC_FOR_TARGET@ +GDC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GDC_FOR_TARGET@ DLLTOOL_FOR_TARGET=@DLLTOOL_FOR_TARGET@ LD_FOR_TARGET=@LD_FOR_TARGET@ @@ -521,6 +537,7 @@ LIBCFLAGS_FOR_TARGET = $(CFLAGS_FOR_TARGET) LIBCXXFLAGS_FOR_TARGET = $(CXXFLAGS_FOR_TARGET) -fno-implicit-templates LDFLAGS_FOR_TARGET = @LDFLAGS_FOR_TARGET@ GOCFLAGS_FOR_TARGET = -O2 -g +GDCFLAGS_FOR_TARGET = -O2 -g FLAGS_FOR_TARGET = @FLAGS_FOR_TARGET@ SYSROOT_CFLAGS_FOR_TARGET = @SYSROOT_CFLAGS_FOR_TARGET@ @@ -622,6 +639,7 @@ EXTRA_HOST_FLAGS = \ 'DLLTOOL=$(DLLTOOL)' \ 'GFORTRAN=$(GFORTRAN)' \ 'GOC=$(GOC)' \ + 'GDC=$(GDC)' \ 'LD=$(LD)' \ 'LIPO=$(LIPO)' \ 'NM=$(NM)' \ @@ -646,6 +664,7 @@ STAGE1_FLAGS_TO_PASS = \ POSTSTAGE1_FLAGS_TO_PASS = \ CC="$${CC}" CC_FOR_BUILD="$${CC_FOR_BUILD}" \ CXX="$${CXX}" CXX_FOR_BUILD="$${CXX_FOR_BUILD}" \ + GDC="$${GDC}" GDC_FOR_BUILD="$${GDC_FOR_BUILD}" \ GNATBIND="$${GNATBIND}" \ LDFLAGS="$${LDFLAGS}" \ HOST_LIBS="$${HOST_LIBS}" \ @@ -678,6 +697,8 @@ EXTRA_TARGET_FLAGS = \ 'GFORTRAN=$$(GFORTRAN_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOC=$$(GOC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ 'GOCFLAGS=$$(GOCFLAGS_FOR_TARGET)' \ + 'GDC=$$(GDC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \ + 'GDCFLAGS=$$(GDCFLAGS_FOR_TARGET)' \ 'LD=$(COMPILER_LD_FOR_TARGET)' \ 'LDFLAGS=$$(LDFLAGS_FOR_TARGET)' \ 'LIBCFLAGS=$$(LIBCFLAGS_FOR_TARGET)' \ diff --git a/config-ml.in b/config-ml.in index 47f153350e4..3e37f875c88 100644 --- a/config-ml.in +++ b/config-ml.in @@ -512,6 +512,7 @@ multi-do: prefix="$(prefix)" \ exec_prefix="$(exec_prefix)" \ GOCFLAGS="$(GOCFLAGS) $${flags}" \ + GDCFLAGS="$(GDCFLAGS) $${flags}" \ CXXFLAGS="$(CXXFLAGS) $${flags}" \ LIBCFLAGS="$(LIBCFLAGS) $${flags}" \ LIBCXXFLAGS="$(LIBCXXFLAGS) $${flags}" \ @@ -745,7 +746,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then break fi done - ml_config_env='CC="${CC_}$flags" CXX="${CXX_}$flags" F77="${F77_}$flags" GFORTRAN="${GFORTRAN_}$flags" GOC="${GOC_}$flags"' + ml_config_env='CC="${CC_}$flags" CXX="${CXX_}$flags" F77="${F77_}$flags" GFORTRAN="${GFORTRAN_}$flags" GOC="${GOC_}$flags" GDC="${GDC_}$flags"' if [ "${with_target_subdir}" = "." ]; then CC_=$CC' ' @@ -753,6 +754,7 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then F77_=$F77' ' GFORTRAN_=$GFORTRAN' ' GOC_=$GOC' ' + GDC_=$GDC' ' else # Create a regular expression that matches any string as long # as ML_POPDIR. @@ -817,6 +819,18 @@ if [ -n "${multidirs}" ] && [ -z "${ml_norecursion}" ]; then esac done + GDC_= + for arg in ${GDC}; do + case $arg in + -[BIL]"${ML_POPDIR}"/*) + GDC_="${GDC_}"`echo "X${arg}" | sed -n "s/X\\(-[BIL]${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X-[BIL]${popdir_rx}\\(.*\\)/\\1/p"`' ' ;; + "${ML_POPDIR}"/*) + GDC_="${GDC_}"`echo "X${arg}" | sed -n "s/X\\(${popdir_rx}\\).*/\\1/p"`/${ml_dir}`echo "X${arg}" | sed -n "s/X${popdir_rx}\\(.*\\)/\\1/p"`' ' ;; + *) + GDC_="${GDC_}${arg} " ;; + esac + done + if test "x${LD_LIBRARY_PATH+set}" = xset; then LD_LIBRARY_PATH_= for arg in `echo "$LD_LIBRARY_PATH" | tr ':' ' '`; do diff --git a/config/ChangeLog b/config/ChangeLog index 70b3f724026..edfcb6058c0 100644 --- a/config/ChangeLog +++ b/config/ChangeLog @@ -1,3 +1,7 @@ +2018-10-28 Iain Buclaw + + * multi.m4: Set GDC. + 2018-07-05 James Clarke * dfp.m4 (enable_decimal_float): Enable for x86_64*-*-gnu* to diff --git a/config/multi.m4 b/config/multi.m4 index bba338a8265..10680a5b32b 100644 --- a/config/multi.m4 +++ b/config/multi.m4 @@ -64,4 +64,5 @@ multi_basedir="$multi_basedir" CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} CC="$CC" CXX="$CXX" -GFORTRAN="$GFORTRAN"])])dnl +GFORTRAN="$GFORTRAN" +GDC="$GDC"])])dnl diff --git a/configure b/configure index dd9fbe4d322..77e7e1869ba 100755 --- a/configure +++ b/configure @@ -580,6 +580,7 @@ LD_FOR_TARGET DLLTOOL_FOR_TARGET AS_FOR_TARGET AR_FOR_TARGET +GDC_FOR_TARGET GOC_FOR_TARGET GFORTRAN_FOR_TARGET GCC_FOR_TARGET @@ -612,6 +613,7 @@ RANLIB_FOR_BUILD NM_FOR_BUILD LD_FOR_BUILD LDFLAGS_FOR_BUILD +GDC_FOR_BUILD GOC_FOR_BUILD GFORTRAN_FOR_BUILD DLLTOOL_FOR_BUILD @@ -830,6 +832,7 @@ CXX_FOR_TARGET GCC_FOR_TARGET GFORTRAN_FOR_TARGET GOC_FOR_TARGET +GDC_FOR_TARGET AR_FOR_TARGET AS_FOR_TARGET DLLTOOL_FOR_TARGET @@ -1613,6 +1616,8 @@ Some influential environment variables: GFORTRAN for the target GOC_FOR_TARGET GOC for the target + GDC_FOR_TARGET + GDC for the target AR_FOR_TARGET AR for the target AS_FOR_TARGET @@ -2764,7 +2769,8 @@ target_libraries="target-libgcc \ target-libffi \ target-libobjc \ target-libada \ - target-libgo" + target-libgo \ + target-libphobos" # these tools are built using the target libraries, and are intended to # run only in the target environment @@ -3920,6 +3926,7 @@ if test "${build}" != "${host}" ; then CXX_FOR_BUILD=${CXX_FOR_BUILD-g++} GFORTRAN_FOR_BUILD=${GFORTRAN_FOR_BUILD-gfortran} GOC_FOR_BUILD=${GOC_FOR_BUILD-gccgo} + GDC_FOR_BUILD=${GDC_FOR_BUILD-gdc} DLLTOOL_FOR_BUILD=${DLLTOOL_FOR_BUILD-dlltool} LD_FOR_BUILD=${LD_FOR_BUILD-ld} NM_FOR_BUILD=${NM_FOR_BUILD-nm} @@ -3933,6 +3940,7 @@ else CXX_FOR_BUILD="\$(CXX)" GFORTRAN_FOR_BUILD="\$(GFORTRAN)" GOC_FOR_BUILD="\$(GOC)" + GDC_FOR_BUILD="\$(GDC)" DLLTOOL_FOR_BUILD="\$(DLLTOOL)" LD_FOR_BUILD="\$(LD)" NM_FOR_BUILD="\$(NM)" @@ -7650,6 +7658,7 @@ done + # Generate default definitions for YACC, M4, LEX and other programs that run # on the build machine. These are used if the Makefile can't locate these # programs in objdir. @@ -10704,6 +10713,167 @@ fi +if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET=$GDC_FOR_TARGET +elif test -n "$ac_cv_prog_GDC_FOR_TARGET"; then + GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +fi + +if test -n "$ac_cv_prog_GDC_FOR_TARGET"; then + for ncn_progname in gdc; do + # Extract the first word of "${ncn_progname}", so it can be a program name with args. +set dummy ${ncn_progname}; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC_FOR_TARGET+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET="$GDC_FOR_TARGET" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC_FOR_TARGET="${ncn_progname}" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +if test -n "$GDC_FOR_TARGET"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC_FOR_TARGET" >&5 +$as_echo "$GDC_FOR_TARGET" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + done +fi + +if test -z "$ac_cv_prog_GDC_FOR_TARGET" && test -n "$with_build_time_tools"; then + for ncn_progname in gdc; do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ncn_progname} in $with_build_time_tools" >&5 +$as_echo_n "checking for ${ncn_progname} in $with_build_time_tools... " >&6; } + if test -x $with_build_time_tools/${ncn_progname}; then + ac_cv_prog_GDC_FOR_TARGET=$with_build_time_tools/${ncn_progname} + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + done +fi + +if test -z "$ac_cv_prog_GDC_FOR_TARGET"; then + for ncn_progname in gdc; do + if test -n "$ncn_target_tool_prefix"; then + # Extract the first word of "${ncn_target_tool_prefix}${ncn_progname}", so it can be a program name with args. +set dummy ${ncn_target_tool_prefix}${ncn_progname}; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC_FOR_TARGET+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET="$GDC_FOR_TARGET" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC_FOR_TARGET="${ncn_target_tool_prefix}${ncn_progname}" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +if test -n "$GDC_FOR_TARGET"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC_FOR_TARGET" >&5 +$as_echo "$GDC_FOR_TARGET" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + if test -z "$ac_cv_prog_GDC_FOR_TARGET" && test $build = $target ; then + # Extract the first word of "${ncn_progname}", so it can be a program name with args. +set dummy ${ncn_progname}; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_GDC_FOR_TARGET+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GDC_FOR_TARGET"; then + ac_cv_prog_GDC_FOR_TARGET="$GDC_FOR_TARGET" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_GDC_FOR_TARGET="${ncn_progname}" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GDC_FOR_TARGET=$ac_cv_prog_GDC_FOR_TARGET +if test -n "$GDC_FOR_TARGET"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC_FOR_TARGET" >&5 +$as_echo "$GDC_FOR_TARGET" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + test -n "$ac_cv_prog_GDC_FOR_TARGET" && break + done +fi + +if test -z "$ac_cv_prog_GDC_FOR_TARGET" ; then + set dummy gdc + if test $build = $target ; then + GDC_FOR_TARGET="$2" + else + GDC_FOR_TARGET="${ncn_target_tool_prefix}$2" + fi +else + GDC_FOR_TARGET="$ac_cv_prog_GDC_FOR_TARGET" +fi + + + cat > conftest.c << \EOF #ifdef __GNUC__ gcc_yay; @@ -14100,6 +14270,51 @@ $as_echo "pre-installed" >&6; } fi fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target gdc" >&5 +$as_echo_n "checking where to find the target gdc... " >&6; } +if test "x${build}" != "x${host}" ; then + if expr "x$GDC_FOR_TARGET" : "x/" > /dev/null; then + # We already found the complete path + ac_dir=`dirname $GDC_FOR_TARGET` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5 +$as_echo "pre-installed in $ac_dir" >&6; } + else + # Canadian cross, just use what we found + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5 +$as_echo "pre-installed" >&6; } + fi +else + ok=yes + case " ${configdirs} " in + *" gcc "*) ;; + *) ok=no ;; + esac + case ,${enable_languages}, in + *,d,*) ;; + *) ok=no ;; + esac + if test $ok = yes; then + # An in-tree tool is available and we can use it + GDC_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/gdc -B$$r/$(HOST_SUBDIR)/gcc/' + { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5 +$as_echo "just compiled" >&6; } + elif expr "x$GDC_FOR_TARGET" : "x/" > /dev/null; then + # We already found the complete path + ac_dir=`dirname $GDC_FOR_TARGET` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5 +$as_echo "pre-installed in $ac_dir" >&6; } + elif test "x$target" = "x$host"; then + # We can use an host tool + GDC_FOR_TARGET='$(GDC)' + { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5 +$as_echo "host tool" >&6; } + else + # We need a cross tool + { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5 +$as_echo "pre-installed" >&6; } + fi +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target ld" >&5 $as_echo_n "checking where to find the target ld... " >&6; } if test "x${build}" != "x${host}" ; then diff --git a/configure.ac b/configure.ac index a0b0917dd55..1e5979dc043 100644 --- a/configure.ac +++ b/configure.ac @@ -163,7 +163,8 @@ target_libraries="target-libgcc \ target-libffi \ target-libobjc \ target-libada \ - target-libgo" + target-libgo \ + target-libphobos" # these tools are built using the target libraries, and are intended to # run only in the target environment @@ -1235,6 +1236,7 @@ if test "${build}" != "${host}" ; then CXX_FOR_BUILD=${CXX_FOR_BUILD-g++} GFORTRAN_FOR_BUILD=${GFORTRAN_FOR_BUILD-gfortran} GOC_FOR_BUILD=${GOC_FOR_BUILD-gccgo} + GDC_FOR_BUILD=${GDC_FOR_BUILD-gdc} DLLTOOL_FOR_BUILD=${DLLTOOL_FOR_BUILD-dlltool} LD_FOR_BUILD=${LD_FOR_BUILD-ld} NM_FOR_BUILD=${NM_FOR_BUILD-nm} @@ -1248,6 +1250,7 @@ else CXX_FOR_BUILD="\$(CXX)" GFORTRAN_FOR_BUILD="\$(GFORTRAN)" GOC_FOR_BUILD="\$(GOC)" + GDC_FOR_BUILD="\$(GDC)" DLLTOOL_FOR_BUILD="\$(DLLTOOL)" LD_FOR_BUILD="\$(LD)" NM_FOR_BUILD="\$(NM)" @@ -3235,6 +3238,7 @@ AC_SUBST(CXX_FOR_BUILD) AC_SUBST(DLLTOOL_FOR_BUILD) AC_SUBST(GFORTRAN_FOR_BUILD) AC_SUBST(GOC_FOR_BUILD) +AC_SUBST(GDC_FOR_BUILD) AC_SUBST(LDFLAGS_FOR_BUILD) AC_SUBST(LD_FOR_BUILD) AC_SUBST(NM_FOR_BUILD) @@ -3344,6 +3348,7 @@ NCN_STRICT_CHECK_TARGET_TOOLS(CXX_FOR_TARGET, c++ g++ cxx gxx) NCN_STRICT_CHECK_TARGET_TOOLS(GCC_FOR_TARGET, gcc, ${CC_FOR_TARGET}) NCN_STRICT_CHECK_TARGET_TOOLS(GFORTRAN_FOR_TARGET, gfortran) NCN_STRICT_CHECK_TARGET_TOOLS(GOC_FOR_TARGET, gccgo) +NCN_STRICT_CHECK_TARGET_TOOLS(GDC_FOR_TARGET, gdc) ACX_CHECK_INSTALLED_TARGET_TOOL(AR_FOR_TARGET, ar) ACX_CHECK_INSTALLED_TARGET_TOOL(AS_FOR_TARGET, as) @@ -3377,6 +3382,8 @@ GCC_TARGET_TOOL(gfortran, GFORTRAN_FOR_TARGET, GFORTRAN, [gcc/gfortran -B$$r/$(HOST_SUBDIR)/gcc/], fortran) GCC_TARGET_TOOL(gccgo, GOC_FOR_TARGET, GOC, [gcc/gccgo -B$$r/$(HOST_SUBDIR)/gcc/], go) +GCC_TARGET_TOOL(gdc, GDC_FOR_TARGET, GDC, + [gcc/gdc -B$$r/$(HOST_SUBDIR)/gcc/], d) GCC_TARGET_TOOL(ld, LD_FOR_TARGET, LD, [ld/ld-new]) GCC_TARGET_TOOL(lipo, LIPO_FOR_TARGET, LIPO) GCC_TARGET_TOOL(nm, NM_FOR_TARGET, NM, [binutils/nm-new]) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 349716f74cb..4ac333abc98 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,105 @@ +2018-10-28 Iain Buclaw + + * 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. + 2018-10-28 Iain Sandoe PR target/85669 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index d2da9ff5f07..a1643321408 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -554,6 +554,8 @@ tm_include_list=@tm_include_list@ tm_defines=@tm_defines@ tm_p_file_list=@tm_p_file_list@ tm_p_include_list=@tm_p_include_list@ +tm_d_file_list=@tm_d_file_list@ +tm_d_include_list=@tm_d_include_list@ build_xm_file_list=@build_xm_file_list@ build_xm_include_list=@build_xm_include_list@ build_xm_defines=@build_xm_defines@ @@ -848,6 +850,7 @@ BCONFIG_H = bconfig.h $(build_xm_file_list) CONFIG_H = config.h $(host_xm_file_list) TCONFIG_H = tconfig.h $(xm_file_list) TM_P_H = tm_p.h $(tm_p_file_list) +TM_D_H = tm_d.h $(tm_d_file_list) GTM_H = tm.h $(tm_file_list) insn-constants.h TM_H = $(GTM_H) insn-flags.h $(OPTIONS_H) @@ -905,9 +908,11 @@ EXCEPT_H = except.h $(HASHTAB_H) TARGET_DEF = target.def target-hooks-macros.h target-insns.def C_TARGET_DEF = c-family/c-target.def target-hooks-macros.h COMMON_TARGET_DEF = common/common-target.def target-hooks-macros.h +D_TARGET_DEF = d/d-target.def target-hooks-macros.h TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h insn-codes.h C_TARGET_H = c-family/c-target.h $(C_TARGET_DEF) COMMON_TARGET_H = common/common-target.h $(INPUT_H) $(COMMON_TARGET_DEF) +D_TARGET_H = d/d-target.h $(D_TARGET_DEF) MACHMODE_H = machmode.h mode-classes.def HOOKS_H = hooks.h HOSTHOOKS_DEF_H = hosthooks-def.h $(HOOKS_H) @@ -1187,6 +1192,9 @@ C_TARGET_OBJS=@c_target_objs@ # Target specific, C++ specific object file CXX_TARGET_OBJS=@cxx_target_objs@ +# Target specific, D specific object file +D_TARGET_OBJS=@d_target_objs@ + # Target specific, Fortran specific object file FORTRAN_TARGET_OBJS=@fortran_target_objs@ @@ -1786,6 +1794,7 @@ bconfig.h: cs-bconfig.h ; @true tconfig.h: cs-tconfig.h ; @true tm.h: cs-tm.h ; @true tm_p.h: cs-tm_p.h ; @true +tm_d.h: cs-tm_d.h ; @true cs-config.h: Makefile TARGET_CPU_DEFAULT="" \ @@ -1812,6 +1821,11 @@ cs-tm_p.h: Makefile HEADERS="$(tm_p_include_list)" DEFINES="" \ $(SHELL) $(srcdir)/mkconfig.sh tm_p.h +cs-tm_d.h: Makefile + TARGET_CPU_DEFAULT="" \ + HEADERS="$(tm_d_include_list)" DEFINES="" \ + $(SHELL) $(srcdir)/mkconfig.sh tm_d.h + # Don't automatically run autoconf, since configure.ac might be accidentally # newer than configure. Also, this writes into the source directory which # might be on a read-only file system. If configured for maintainer mode @@ -2136,6 +2150,12 @@ default-c.o: config/default-c.c CFLAGS-prefix.o += -DPREFIX=\"$(prefix)\" -DBASEVER=$(BASEVER_s) prefix.o: $(BASEVER) +# Files used by the D language front end. + +default-d.o: config/default-d.c + $(COMPILE) $< + $(POSTCOMPILE) + # Language-independent files. DRIVER_DEFINES = \ @@ -2432,6 +2452,15 @@ s-common-target-hooks-def-h: build/genhooks$(build_exeext) common/common-target-hooks-def.h $(STAMP) s-common-target-hooks-def-h +d/d-target-hooks-def.h: s-d-target-hooks-def-h; @true + +s-d-target-hooks-def-h: build/genhooks$(build_exeext) + $(RUN_GEN) build/genhooks$(build_exeext) "D Target Hook" \ + > tmp-d-target-hooks-def.h + $(SHELL) $(srcdir)/../move-if-change tmp-d-target-hooks-def.h \ + d/d-target-hooks-def.h + $(STAMP) s-d-target-hooks-def-h + # check if someone mistakenly only changed tm.texi. # We use a different pathname here to avoid a circular dependency. s-tm-texi: $(srcdir)/doc/../doc/tm.texi @@ -2455,6 +2484,7 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in && ( test $(srcdir)/doc/tm.texi -nt $(srcdir)/target.def \ || test $(srcdir)/doc/tm.texi -nt $(srcdir)/c-family/c-target.def \ || test $(srcdir)/doc/tm.texi -nt $(srcdir)/common/common-target.def \ + || test $(srcdir)/doc/tm.texi -nt $(srcdir)/d/d-target.def \ ); then \ echo >&2 ; \ echo You should edit $(srcdir)/doc/tm.texi.in rather than $(srcdir)/doc/tm.texi . >&2 ; \ @@ -2592,14 +2622,15 @@ s-gtype: build/gengtype$(build_exeext) $(filter-out [%], $(GTFILES)) \ -r gtype.state $(STAMP) s-gtype -generated_files = config.h tm.h $(TM_P_H) $(TM_H) multilib.h \ +generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \ $(simple_generated_h) specs.h \ tree-check.h genrtl.h insn-modes.h insn-modes-inline.h \ tm-preds.h tm-constrs.h \ $(ALL_GTFILES_H) gtype-desc.c gtype-desc.h gcov-iov.h \ options.h target-hooks-def.h insn-opinit.h \ common/common-target-hooks-def.h pass-instances.def \ - c-family/c-target-hooks-def.h params.list params.options case-cfn-macros.h \ + c-family/c-target-hooks-def.h d/d-target-hooks-def.h \ + params.list params.options case-cfn-macros.h \ cfn-operators.pd # @@ -2743,7 +2774,7 @@ build/genrecog.o : genrecog.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) \ $(HASH_TABLE_H) inchash.h build/genhooks.o : genhooks.c $(TARGET_DEF) $(C_TARGET_DEF) \ - $(COMMON_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h + $(COMMON_TARGET_DEF) $(D_TARGET_DEF) $(BCONFIG_H) $(SYSTEM_H) errors.h build/genmddump.o : genmddump.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \ $(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H) build/genmatch.o : genmatch.c $(BCONFIG_H) $(SYSTEM_H) \ diff --git a/gcc/config.gcc b/gcc/config.gcc index 71f62a2aba2..93dc2978603 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -86,6 +86,9 @@ # tm_p_file Location of file with declarations for functions # in $out_file. # +# tm_d_file A list of headers with definitions of target hook +# macros for the D compiler. +# # out_file The name of the machine description C support # file, if different from "$cpu_type/$cpu_type.c". # @@ -139,6 +142,9 @@ # cxx_target_objs List of extra target-dependent objects that be # linked into the C++ compiler only. # +# d_target_objs List of extra target-dependent objects that be +# linked into the D compiler only. +# # fortran_target_objs List of extra target-dependent objects that be # linked into the fortran compiler only. # @@ -191,6 +197,9 @@ # # target_has_targetm_common Set to yes or no depending on whether the # target has its own definition of targetm_common. +# +# target_has_targetdm Set to yes or no depending on whether the target +# has its own definition of targetdm. out_file= common_out_file= @@ -206,9 +215,11 @@ extra_gcc_objs= extra_options= c_target_objs= cxx_target_objs= +d_target_objs= fortran_target_objs= target_has_targetcm=no target_has_targetm_common=yes +target_has_targetdm=no tm_defines= xm_defines= # Set this to force installation and use of collect2. @@ -305,6 +316,7 @@ aarch64*-*-*) extra_headers="arm_fp16.h arm_neon.h arm_acle.h" c_target_objs="aarch64-c.o" cxx_target_objs="aarch64-c.o" + d_target_objs="aarch64-d.o" extra_objs="aarch64-builtins.o aarch-common.o cortex-a57-fma-steering.o aarch64-speculation.o falkor-tag-collision-avoidance.o" target_gtfiles="\$(srcdir)/config/aarch64/aarch64-builtins.c" target_has_targetm_common=yes @@ -330,6 +342,7 @@ arm*-*-*) target_type_format_char='%' c_target_objs="arm-c.o" cxx_target_objs="arm-c.o" + d_target_objs="arm-d.o" extra_options="${extra_options} arm/arm-tables.opt" target_gtfiles="\$(srcdir)/config/arm/arm-builtins.c" ;; @@ -362,6 +375,7 @@ i[34567]86-*-*) cpu_type=i386 c_target_objs="i386-c.o" cxx_target_objs="i386-c.o" + d_target_objs="i386-d.o" extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o" extra_options="${extra_options} fused-madd.opt" extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h @@ -392,6 +406,7 @@ x86_64-*-*) cpu_type=i386 c_target_objs="i386-c.o" cxx_target_objs="i386-c.o" + d_target_objs="i386-d.o" extra_options="${extra_options} fused-madd.opt" extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o" extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h @@ -442,6 +457,7 @@ microblaze*-*-*) ;; mips*-*-*) cpu_type=mips + d_target_objs="mips-d.o" extra_headers="loongson.h msa.h" extra_objs="frame-header-opt.o" extra_options="${extra_options} g.opt fused-madd.opt mips/mips-tables.opt" @@ -498,6 +514,7 @@ powerpc*-*-*) riscv*) cpu_type=riscv extra_objs="riscv-builtins.o riscv-c.o" + d_target_objs="riscv-d.o" ;; rs6000*-*-*) extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt" @@ -507,6 +524,7 @@ sparc*-*-*) cpu_type=sparc c_target_objs="sparc-c.o" cxx_target_objs="sparc-c.o" + d_target_objs="sparc-d.o" extra_headers="visintrin.h" ;; spu*-*-*) @@ -514,6 +532,7 @@ spu*-*-*) ;; s390*-*-*) cpu_type=s390 + d_target_objs="s390-d.o" extra_options="${extra_options} fused-madd.opt" extra_headers="s390intrin.h htmintrin.h htmxlintrin.h vecintrin.h" ;; @@ -543,10 +562,13 @@ tilepro*-*-*) esac tm_file=${cpu_type}/${cpu_type}.h +tm_d_file=${cpu_type}/${cpu_type}.h if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-protos.h then tm_p_file=${cpu_type}/${cpu_type}-protos.h + tm_d_file="${tm_d_file} ${cpu_type}/${cpu_type}-protos.h" fi + extra_modes= if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-modes.def then @@ -810,8 +832,10 @@ case ${target} in esac c_target_objs="${c_target_objs} glibc-c.o" cxx_target_objs="${cxx_target_objs} glibc-c.o" + d_target_objs="${d_target_objs} glibc-d.o" tmake_file="${tmake_file} t-glibc" target_has_targetcm=yes + target_has_targetdm=yes ;; *-*-netbsd*) tm_p_file="${tm_p_file} netbsd-protos.h" @@ -3232,6 +3256,10 @@ if [ "$common_out_file" = "" ]; then fi fi +if [ "$target_has_targetdm" = "no" ]; then + d_target_objs="$d_target_objs default-d.o" +fi + # Support for --with-cpu and related options (and a few unrelated options, # too). case ${with_cpu} in @@ -4858,6 +4886,7 @@ case ${target} in out_file="${cpu_type}/${cpu_type}.c" c_target_objs="${c_target_objs} ${cpu_type}-c.o" cxx_target_objs="${cxx_target_objs} ${cpu_type}-c.o" + d_target_objs="${d_target_objs} ${cpu_type}-d.o" tmake_file="${cpu_type}/t-${cpu_type} ${tmake_file}" ;; diff --git a/gcc/config/aarch64/aarch64-d.c b/gcc/config/aarch64/aarch64-d.c new file mode 100644 index 00000000000..1394f1fb7d3 --- /dev/null +++ b/gcc/config/aarch64/aarch64-d.c @@ -0,0 +1,31 @@ +/* Subroutines for the D front end on the AArch64 architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for AArch64 targets. */ + +void +aarch64_d_target_versions (void) +{ + d_add_builtin_version ("AArch64"); + d_add_builtin_version ("D_HardFloat"); +} diff --git a/gcc/config/aarch64/aarch64-linux.h b/gcc/config/aarch64/aarch64-linux.h index bf1327e98cc..2bee7e5baea 100644 --- a/gcc/config/aarch64/aarch64-linux.h +++ b/gcc/config/aarch64/aarch64-linux.h @@ -81,6 +81,8 @@ } \ while (0) +#define GNU_USER_TARGET_D_CRITSEC_SIZE 48 + #define TARGET_ASM_FILE_END file_end_indicate_exec_stack /* Uninitialized common symbols in non-PIE executables, even with diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 5f18837418e..776e8696ebe 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -620,6 +620,9 @@ enum aarch64_parse_opt_result aarch64_parse_extension (const char *, std::string aarch64_get_extension_string_for_isa_flags (unsigned long, unsigned long); +/* Defined in aarch64-d.c */ +extern void aarch64_d_target_versions (void); + rtl_opt_pass *make_pass_fma_steering (gcc::context *); rtl_opt_pass *make_pass_track_speculation (gcc::context *); rtl_opt_pass *make_pass_tag_collision_avoidance (gcc::context *); diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index fa9af26fd40..0c833a8fdfd 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -26,6 +26,9 @@ #define TARGET_CPU_CPP_BUILTINS() \ aarch64_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS aarch64_d_target_versions + #define REGISTER_TARGET_PRAGMAS() aarch64_register_pragmas () diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64 index 1576d05ba9d..e91dccea995 100644 --- a/gcc/config/aarch64/t-aarch64 +++ b/gcc/config/aarch64/t-aarch64 @@ -56,6 +56,10 @@ aarch64-c.o: $(srcdir)/config/aarch64/aarch64-c.c $(CONFIG_H) $(SYSTEM_H) \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/aarch64/aarch64-c.c +aarch64-d.o: $(srcdir)/config/aarch64/aarch64-d.c + $(COMPILE) $< + $(POSTCOMPILE) + PASSES_EXTRA += $(srcdir)/config/aarch64/aarch64-passes.def cortex-a57-fma-steering.o: $(srcdir)/config/aarch64/cortex-a57-fma-steering.c \ diff --git a/gcc/config/arm/arm-d.c b/gcc/config/arm/arm-d.c new file mode 100644 index 00000000000..dbcf07efbc8 --- /dev/null +++ b/gcc/config/arm/arm-d.c @@ -0,0 +1,53 @@ +/* Subroutines for the D front end on the ARM architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tm_p.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for ARM targets. */ + +void +arm_d_target_versions (void) +{ + d_add_builtin_version ("ARM"); + + if (TARGET_THUMB || TARGET_THUMB2) + { + d_add_builtin_version ("Thumb"); + d_add_builtin_version ("ARM_Thumb"); + } + + if (TARGET_HARD_FLOAT_ABI) + d_add_builtin_version ("ARM_HardFloat"); + else + { + if (TARGET_SOFT_FLOAT) + d_add_builtin_version ("ARM_SoftFloat"); + else if (TARGET_HARD_FLOAT) + d_add_builtin_version ("ARM_SoftFP"); + } + + if (TARGET_SOFT_FLOAT) + d_add_builtin_version ("D_SoftFloat"); + else if (TARGET_HARD_FLOAT) + d_add_builtin_version ("D_HardFloat"); +} diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 0dfb3ac59a6..cea98669111 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -375,6 +375,9 @@ extern void arm_lang_object_attributes_init (void); extern void arm_register_target_pragmas (void); extern void arm_cpu_cpp_builtins (struct cpp_reader *); +/* Defined in arm-d.c */ +extern void arm_d_target_versions (void); + extern bool arm_is_constant_pool_ref (rtx); /* The bits in this mask specify which instruction scheduling options should diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 34894c090dd..8472312487b 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -47,6 +47,9 @@ extern char arm_arch_name[]; /* Target CPU builtins. */ #define TARGET_CPU_CPP_BUILTINS() arm_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS arm_d_target_versions + #include "config/arm/arm-opts.h" /* The processor for which instructions should be scheduled. */ diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h index 8585fde3d41..4254b19212d 100644 --- a/gcc/config/arm/linux-eabi.h +++ b/gcc/config/arm/linux-eabi.h @@ -30,6 +30,9 @@ } \ while (false) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + ANDROID_TARGET_D_OS_VERSIONS(); + /* We default to a soft-float ABI so that binaries can run on all target hardware. If you override this to use the hard-float ABI then change the setting of GLIBC_DYNAMIC_LINKER_DEFAULT as well. */ diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm index c3a8c7773ba..02b46260686 100644 --- a/gcc/config/arm/t-arm +++ b/gcc/config/arm/t-arm @@ -152,6 +152,10 @@ arm-c.o: $(srcdir)/config/arm/arm-c.c $(CONFIG_H) $(SYSTEM_H) \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/arm/arm-c.c +arm-d.o: $(srcdir)/config/arm/arm-d.c + $(COMPILE) $< + $(POSTCOMPILE) + arm-common.o: arm-cpu-cdata.h driver-arm.o: arm-native.h diff --git a/gcc/config/default-d.c b/gcc/config/default-d.c new file mode 100644 index 00000000000..6c952052088 --- /dev/null +++ b/gcc/config/default-d.c @@ -0,0 +1,25 @@ +/* Default D language target hooks initializer. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm_d.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; diff --git a/gcc/config/glibc-d.c b/gcc/config/glibc-d.c new file mode 100644 index 00000000000..b73ee01f21d --- /dev/null +++ b/gcc/config/glibc-d.c @@ -0,0 +1,64 @@ +/* Glibc support needed only by D front-end. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "memmodel.h" +#include "tm_p.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_OS_VERSIONS for Glibc targets. */ + +static void +glibc_d_os_builtins (void) +{ + d_add_builtin_version ("Posix"); + +#define builtin_version(TXT) d_add_builtin_version (TXT) + +#ifdef GNU_USER_TARGET_D_OS_VERSIONS + GNU_USER_TARGET_D_OS_VERSIONS (); +#endif + +#ifdef EXTRA_TARGET_D_OS_VERSIONS + EXTRA_TARGET_D_OS_VERSIONS (); +#endif +} + +/* Implement TARGET_D_CRITSEC_SIZE for Glibc targets. */ + +static unsigned +glibc_d_critsec_size (void) +{ + /* This is the sizeof pthread_mutex_t. */ +#ifdef GNU_USER_TARGET_D_CRITSEC_SIZE + return GNU_USER_TARGET_D_CRITSEC_SIZE; +#else + return (POINTER_SIZE == 64) ? 40 : 24; +#endif +} + +#undef TARGET_D_OS_VERSIONS +#define TARGET_D_OS_VERSIONS glibc_d_os_builtins + +#undef TARGET_D_CRITSEC_SIZE +#define TARGET_D_CRITSEC_SIZE glibc_d_critsec_size + +struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; diff --git a/gcc/config/gnu.h b/gcc/config/gnu.h index 1cc744b13be..3aca4e35983 100644 --- a/gcc/config/gnu.h +++ b/gcc/config/gnu.h @@ -31,3 +31,9 @@ along with GCC. If not, see . builtin_assert ("system=unix"); \ builtin_assert ("system=posix"); \ } while (0) + +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("Hurd"); \ + builtin_version ("CRuntime_Glibc"); \ + } while (0) diff --git a/gcc/config/i386/i386-d.c b/gcc/config/i386/i386-d.c new file mode 100644 index 00000000000..34304b84a36 --- /dev/null +++ b/gcc/config/i386/i386-d.c @@ -0,0 +1,44 @@ +/* Subroutines for the D front end on the x86 architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for x86 targets. */ + +void +ix86_d_target_versions (void) +{ + if (TARGET_64BIT) + { + d_add_builtin_version ("X86_64"); + + if (TARGET_X32) + d_add_builtin_version ("D_X32"); + } + else + d_add_builtin_version ("X86"); + + if (TARGET_80387) + d_add_builtin_version ("D_HardFloat"); + else + d_add_builtin_version ("D_SoftFloat"); +} diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index d1d59633dc0..258bdd18cb5 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -236,6 +236,9 @@ extern void ix86_expand_sse2_abs (rtx, rtx); extern void ix86_target_macros (void); extern void ix86_register_pragmas (void); +/* In i386-d.c */ +extern void ix86_d_target_versions (void); + /* In winnt.c */ extern void i386_pe_unique_section (tree, int); extern void i386_pe_declare_function_type (FILE *, const char *, int); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index b0d2f249db7..01d49a7263b 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -718,6 +718,9 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); /* Target Pragmas. */ #define REGISTER_TARGET_PRAGMAS() ix86_register_pragmas () +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS ix86_d_target_versions + #ifndef CC1_SPEC #define CC1_SPEC "%(cc1_cpu) " #endif diff --git a/gcc/config/i386/linux-common.h b/gcc/config/i386/linux-common.h index 3eeb66c1618..1e7a0550839 100644 --- a/gcc/config/i386/linux-common.h +++ b/gcc/config/i386/linux-common.h @@ -27,6 +27,12 @@ along with GCC; see the file COPYING3. If not see } \ while (0) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + ANDROID_TARGET_D_OS_VERSIONS(); + +#define GNU_USER_TARGET_D_CRITSEC_SIZE \ + (TARGET_64BIT ? (POINTER_SIZE == 64 ? 40 : 32) : 24) + #undef CC1_SPEC #define CC1_SPEC \ LINUX_OR_ANDROID_CC (GNU_USER_TARGET_CC1_SPEC, \ diff --git a/gcc/config/i386/t-i386 b/gcc/config/i386/t-i386 index 8a5808cfe79..261739e8778 100644 --- a/gcc/config/i386/t-i386 +++ b/gcc/config/i386/t-i386 @@ -40,6 +40,10 @@ x86-tune-sched-core.o: $(srcdir)/config/i386/x86-tune-sched-core.c $(COMPILE) $< $(POSTCOMPILE) +i386-d.o: $(srcdir)/config/i386/i386-d.c + $(COMPILE) $< + $(POSTCOMPILE) + i386.o: i386-builtin-types.inc i386-builtin-types.inc: s-i386-bt ; @true diff --git a/gcc/config/kfreebsd-gnu.h b/gcc/config/kfreebsd-gnu.h index aaeea44da75..923e7e41508 100644 --- a/gcc/config/kfreebsd-gnu.h +++ b/gcc/config/kfreebsd-gnu.h @@ -29,6 +29,12 @@ along with GCC; see the file COPYING3. If not see } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("FreeBSD"); \ + builtin_version ("CRuntime_Glibc"); \ + } while (0) + #define GNU_USER_DYNAMIC_LINKER GLIBC_DYNAMIC_LINKER #define GNU_USER_DYNAMIC_LINKER32 GLIBC_DYNAMIC_LINKER32 #define GNU_USER_DYNAMIC_LINKER64 GLIBC_DYNAMIC_LINKER64 diff --git a/gcc/config/kopensolaris-gnu.h b/gcc/config/kopensolaris-gnu.h index 541f749be9f..4b303ccf544 100644 --- a/gcc/config/kopensolaris-gnu.h +++ b/gcc/config/kopensolaris-gnu.h @@ -30,5 +30,11 @@ along with GCC; see the file COPYING3. If not see } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("Solaris"); \ + builtin_version ("CRuntime_Glibc"); \ + } while (0) + #undef GNU_USER_DYNAMIC_LINKER #define GNU_USER_DYNAMIC_LINKER "/lib/ld.so.1" diff --git a/gcc/config/linux-android.h b/gcc/config/linux-android.h index 9f3985d23b8..40da4c178e8 100644 --- a/gcc/config/linux-android.h +++ b/gcc/config/linux-android.h @@ -25,6 +25,12 @@ builtin_define ("__ANDROID__"); \ } while (0) +#define ANDROID_TARGET_D_OS_VERSIONS() \ + do { \ + if (TARGET_ANDROID) \ + builtin_version ("Android"); \ + } while (0) + #if ANDROID_DEFAULT # define NOANDROID "mno-android" #else diff --git a/gcc/config/linux.h b/gcc/config/linux.h index 2ea4ff92c1d..02553599024 100644 --- a/gcc/config/linux.h +++ b/gcc/config/linux.h @@ -53,6 +53,19 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see builtin_assert ("system=posix"); \ } while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + builtin_version ("CRuntime_Musl"); \ + } while (0) + /* Determine which dynamic linker to use depending on whether GLIBC or uClibc or Bionic or musl is the default C library and whether -muclibc or -mglibc or -mbionic or -mmusl has been passed to change diff --git a/gcc/config/mips/linux-common.h b/gcc/config/mips/linux-common.h index 570151f6a87..da9be6b369d 100644 --- a/gcc/config/mips/linux-common.h +++ b/gcc/config/mips/linux-common.h @@ -27,6 +27,9 @@ along with GCC; see the file COPYING3. If not see ANDROID_TARGET_OS_CPP_BUILTINS(); \ } while (0) +#define EXTRA_TARGET_D_OS_VERSIONS() \ + ANDROID_TARGET_D_OS_VERSIONS(); + #undef LINK_SPEC #define LINK_SPEC \ LINUX_OR_ANDROID_LD (GNU_USER_TARGET_LINK_SPEC, \ diff --git a/gcc/config/mips/mips-d.c b/gcc/config/mips/mips-d.c new file mode 100644 index 00000000000..8f0d9679456 --- /dev/null +++ b/gcc/config/mips/mips-d.c @@ -0,0 +1,56 @@ +/* Subroutines for the D front end on the MIPS architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for MIPS targets. */ + +void +mips_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("MIPS64"); + else + d_add_builtin_version ("MIPS32"); + + if (mips_abi == ABI_32) + d_add_builtin_version ("MIPS_O32"); + else if (mips_abi == ABI_EABI) + d_add_builtin_version ("MIPS_EABI"); + else if (mips_abi == ABI_N32) + d_add_builtin_version ("MIPS_N32"); + else if (mips_abi == ABI_64) + d_add_builtin_version ("MIPS_N64"); + else if (mips_abi == ABI_O64) + d_add_builtin_version ("MIPS_O64"); + + if (TARGET_HARD_FLOAT_ABI) + { + d_add_builtin_version ("MIPS_HardFloat"); + d_add_builtin_version ("D_HardFloat"); + } + else if (TARGET_SOFT_FLOAT_ABI) + { + d_add_builtin_version ("MIPS_SoftFloat"); + d_add_builtin_version ("D_SoftFloat"); + } +} diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index d9d6e92cb67..099120db7b4 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -385,4 +385,7 @@ extern mulsidi3_gen_fn mips_mulsidi3_gen_fn (enum rtx_code); extern void mips_register_frame_header_opt (void); extern void mips_expand_vec_cond_expr (machine_mode, machine_mode, rtx *); +/* Routines implemented in mips-d.c */ +extern void mips_d_target_versions (void); + #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 6804b792ff1..32a88edc910 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -645,6 +645,9 @@ struct mips_cpu_info { } \ while (0) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS mips_d_target_versions + /* Default target_flags if no switches are specified */ #ifndef TARGET_DEFAULT diff --git a/gcc/config/mips/t-mips b/gcc/config/mips/t-mips index 7bdf83ccee7..0466ba2a97d 100644 --- a/gcc/config/mips/t-mips +++ b/gcc/config/mips/t-mips @@ -24,3 +24,7 @@ $(srcdir)/config/mips/mips-tables.opt: $(srcdir)/config/mips/genopt.sh \ frame-header-opt.o: $(srcdir)/config/mips/frame-header-opt.c $(COMPILE) $< $(POSTCOMPILE) + +mips-d.o: $(srcdir)/config/mips/mips-d.c + $(COMPILE) $< + $(POSTCOMPILE) diff --git a/gcc/config/powerpcspe/linux.h b/gcc/config/powerpcspe/linux.h index c899f9dd4d2..fe755ef08da 100644 --- a/gcc/config/powerpcspe/linux.h +++ b/gcc/config/powerpcspe/linux.h @@ -57,6 +57,19 @@ } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" diff --git a/gcc/config/powerpcspe/linux64.h b/gcc/config/powerpcspe/linux64.h index b3a0cc4e46c..f0e3f09eea5 100644 --- a/gcc/config/powerpcspe/linux64.h +++ b/gcc/config/powerpcspe/linux64.h @@ -391,6 +391,19 @@ extern int dot_symbols; } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux) %(include_extra)" diff --git a/gcc/config/powerpcspe/powerpcspe-d.c b/gcc/config/powerpcspe/powerpcspe-d.c new file mode 100644 index 00000000000..84eb4e93df9 --- /dev/null +++ b/gcc/config/powerpcspe/powerpcspe-d.c @@ -0,0 +1,45 @@ +/* Subroutines for the D front end on the PowerPC architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for PowerPC targets. */ + +void +rs6000_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("PPC64"); + else + d_add_builtin_version ("PPC"); + + if (TARGET_HARD_FLOAT) + { + d_add_builtin_version ("PPC_HardFloat"); + d_add_builtin_version ("D_HardFloat"); + } + else if (TARGET_SOFT_FLOAT) + { + d_add_builtin_version ("PPC_SoftFloat"); + d_add_builtin_version ("D_SoftFloat"); + } +} diff --git a/gcc/config/powerpcspe/powerpcspe-protos.h b/gcc/config/powerpcspe/powerpcspe-protos.h index 8ff9f4b0df3..575a3ed3e6a 100644 --- a/gcc/config/powerpcspe/powerpcspe-protos.h +++ b/gcc/config/powerpcspe/powerpcspe-protos.h @@ -231,6 +231,9 @@ extern void rs6000_target_modify_macros (bool, HOST_WIDE_INT, HOST_WIDE_INT); extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT, HOST_WIDE_INT); +/* Declare functions in powerpcspe-d.c */ +extern void rs6000_d_target_versions (void); + #if TARGET_MACHO char *output_call (rtx_insn *, rtx *, int, int); #endif diff --git a/gcc/config/powerpcspe/powerpcspe.c b/gcc/config/powerpcspe/powerpcspe.c index 90170c35c8f..b05b89c13e6 100644 --- a/gcc/config/powerpcspe/powerpcspe.c +++ b/gcc/config/powerpcspe/powerpcspe.c @@ -31965,11 +31965,12 @@ rs6000_output_function_epilogue (FILE *file) use language_string. C is 0. Fortran is 1. Ada is 3. C++ is 9. Java is 13. Objective-C is 14. Objective-C++ isn't assigned - a number, so for now use 9. LTO, Go and JIT aren't assigned numbers - either, so for now use 0. */ + a number, so for now use 9. LTO, Go, D and JIT aren't assigned + numbers either, so for now use 0. */ if (lang_GNU_C () || ! strcmp (language_string, "GNU GIMPLE") || ! strcmp (language_string, "GNU Go") + || ! strcmp (language_string, "GNU D") || ! strcmp (language_string, "libgccjit")) i = 0; else if (! strcmp (language_string, "GNU F77") diff --git a/gcc/config/powerpcspe/powerpcspe.h b/gcc/config/powerpcspe/powerpcspe.h index df0676a72a4..2305ce3c327 100644 --- a/gcc/config/powerpcspe/powerpcspe.h +++ b/gcc/config/powerpcspe/powerpcspe.h @@ -702,6 +702,9 @@ extern unsigned char rs6000_recip_bits[]; #define TARGET_CPU_CPP_BUILTINS() \ rs6000_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS rs6000_d_target_versions + /* This is used by rs6000_cpu_cpp_builtins to indicate the byte order we're compiling for. Some configurations may need to override it. */ #define RS6000_CPU_CPP_ENDIAN_BUILTINS() \ diff --git a/gcc/config/powerpcspe/t-powerpcspe b/gcc/config/powerpcspe/t-powerpcspe index 460dd5d71c0..e67c21cf6a5 100644 --- a/gcc/config/powerpcspe/t-powerpcspe +++ b/gcc/config/powerpcspe/t-powerpcspe @@ -26,6 +26,10 @@ powerpcspe-c.o: $(srcdir)/config/powerpcspe/powerpcspe-c.c $(COMPILE) $< $(POSTCOMPILE) +powerpcspe-d.o: $(srcdir)/config/powerpcspe/powerpcspe-d.c + $(COMPILE) $< + $(POSTCOMPILE) + $(srcdir)/config/powerpcspe/powerpcspe-tables.opt: $(srcdir)/config/powerpcspe/genopt.sh \ $(srcdir)/config/powerpcspe/powerpcspe-cpus.def $(SHELL) $(srcdir)/config/powerpcspe/genopt.sh $(srcdir)/config/powerpcspe > \ diff --git a/gcc/config/riscv/riscv-d.c b/gcc/config/riscv/riscv-d.c new file mode 100644 index 00000000000..9cad9dd8f5e --- /dev/null +++ b/gcc/config/riscv/riscv-d.c @@ -0,0 +1,39 @@ +/* Subroutines for the D front end on the RISC-V architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for RISC-V targets. */ + +void +riscv_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("RISCV64"); + else + d_add_builtin_version ("RISCV32"); + + if (TARGET_HARD_FLOAT) + d_add_builtin_version ("D_HardFloat"); + else + d_add_builtin_version ("D_SoftFloat"); +} diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index f158ed007dd..5dce9c43398 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -75,6 +75,9 @@ extern bool riscv_expand_block_move (rtx, rtx, rtx); /* Routines implemented in riscv-c.c. */ void riscv_cpu_cpp_builtins (cpp_reader *); +/* Routines implemented in riscv-d.c */ +extern void riscv_d_target_versions (void); + /* Routines implemented in riscv-builtins.c. */ extern void riscv_atomic_assign_expand_fenv (tree *, tree *, tree *); extern rtx riscv_expand_builtin (tree, rtx, rtx, machine_mode, int); diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 3c9f96d6b4d..13e15cc852b 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -27,6 +27,9 @@ along with GCC; see the file COPYING3. If not see /* Target CPU builtins. */ #define TARGET_CPU_CPP_BUILTINS() riscv_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS riscv_d_target_versions + /* Default target_flags if no switches are specified */ #ifndef TARGET_DEFAULT diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 0765b49f90f..ece3a75d512 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -9,3 +9,8 @@ riscv-c.o: $(srcdir)/config/riscv/riscv-c.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) $(TARGET_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/riscv/riscv-c.c + +riscv-d.o: $(srcdir)/config/riscv/riscv-d.c + $(COMPILE) $< + $(POSTCOMPILE) + diff --git a/gcc/config/rs6000/linux.h b/gcc/config/rs6000/linux.h index 01b40c762f6..fd06b14d837 100644 --- a/gcc/config/rs6000/linux.h +++ b/gcc/config/rs6000/linux.h @@ -57,6 +57,19 @@ } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux)" diff --git a/gcc/config/rs6000/linux64.h b/gcc/config/rs6000/linux64.h index 44eab40a234..e6b4fd22d73 100644 --- a/gcc/config/rs6000/linux64.h +++ b/gcc/config/rs6000/linux64.h @@ -391,6 +391,19 @@ extern int dot_symbols; } \ while (0) +#define GNU_USER_TARGET_D_OS_VERSIONS() \ + do { \ + builtin_version ("linux"); \ + if (OPTION_GLIBC) \ + builtin_version ("CRuntime_Glibc"); \ + else if (OPTION_UCLIBC) \ + builtin_version ("CRuntime_UClibc"); \ + else if (OPTION_BIONIC) \ + builtin_version ("CRuntime_Bionic"); \ + else if (OPTION_MUSL) \ + builtin_version ("CRuntime_Musl"); \ + } while (0) + #undef CPP_OS_DEFAULT_SPEC #define CPP_OS_DEFAULT_SPEC "%(cpp_os_linux) %(include_extra)" diff --git a/gcc/config/rs6000/rs6000-d.c b/gcc/config/rs6000/rs6000-d.c new file mode 100644 index 00000000000..84eb4e93df9 --- /dev/null +++ b/gcc/config/rs6000/rs6000-d.c @@ -0,0 +1,45 @@ +/* Subroutines for the D front end on the PowerPC architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for PowerPC targets. */ + +void +rs6000_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("PPC64"); + else + d_add_builtin_version ("PPC"); + + if (TARGET_HARD_FLOAT) + { + d_add_builtin_version ("PPC_HardFloat"); + d_add_builtin_version ("D_HardFloat"); + } + else if (TARGET_SOFT_FLOAT) + { + d_add_builtin_version ("PPC_SoftFloat"); + d_add_builtin_version ("D_SoftFloat"); + } +} diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index f1d5dff5788..bb2584b7b48 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -224,6 +224,9 @@ extern void rs6000_target_modify_macros (bool, HOST_WIDE_INT, HOST_WIDE_INT); extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT, HOST_WIDE_INT); +/* Declare functions in rs6000-d.c */ +extern void rs6000_d_target_versions (void); + #if TARGET_MACHO char *output_call (rtx_insn *, rtx *, int, int); #endif diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 726038ef2b7..a9d038829b7 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -28633,11 +28633,12 @@ rs6000_output_function_epilogue (FILE *file) use language_string. C is 0. Fortran is 1. Ada is 3. C++ is 9. Java is 13. Objective-C is 14. Objective-C++ isn't assigned - a number, so for now use 9. LTO, Go and JIT aren't assigned numbers - either, so for now use 0. */ + a number, so for now use 9. LTO, Go, D, and JIT aren't assigned + numbers either, so for now use 0. */ if (lang_GNU_C () || ! strcmp (language_string, "GNU GIMPLE") || ! strcmp (language_string, "GNU Go") + || ! strcmp (language_string, "GNU D") || ! strcmp (language_string, "libgccjit")) i = 0; else if (! strcmp (language_string, "GNU F77") diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 4ab027ca3ea..f59c0b6b685 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -613,6 +613,9 @@ extern unsigned char rs6000_recip_bits[]; #define TARGET_CPU_CPP_BUILTINS() \ rs6000_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS rs6000_d_target_versions + /* This is used by rs6000_cpu_cpp_builtins to indicate the byte order we're compiling for. Some configurations may need to override it. */ #define RS6000_CPU_CPP_ENDIAN_BUILTINS() \ diff --git a/gcc/config/rs6000/t-rs6000 b/gcc/config/rs6000/t-rs6000 index ad274d9d162..d9249b079f2 100644 --- a/gcc/config/rs6000/t-rs6000 +++ b/gcc/config/rs6000/t-rs6000 @@ -35,6 +35,10 @@ rs6000-p8swap.o: $(srcdir)/config/rs6000/rs6000-p8swap.c $(COMPILE) $< $(POSTCOMPILE) +rs6000-d.o: $(srcdir)/config/rs6000/rs6000-d.c + $(COMPILE) $< + $(POSTCOMPILE) + $(srcdir)/config/rs6000/rs6000-tables.opt: $(srcdir)/config/rs6000/genopt.sh \ $(srcdir)/config/rs6000/rs6000-cpus.def $(SHELL) $(srcdir)/config/rs6000/genopt.sh $(srcdir)/config/rs6000 > \ diff --git a/gcc/config/s390/s390-d.c b/gcc/config/s390/s390-d.c new file mode 100644 index 00000000000..1ea0a9d3379 --- /dev/null +++ b/gcc/config/s390/s390-d.c @@ -0,0 +1,41 @@ +/* Subroutines for the D front end on the IBM S/390 and zSeries architectures. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for S/390 and zSeries targets. */ + +void +s390_d_target_versions (void) +{ + if (TARGET_ZARCH) + d_add_builtin_version ("SystemZ"); + else if (TARGET_64BIT) + d_add_builtin_version ("S390X"); + else + d_add_builtin_version ("S390"); + + if (TARGET_SOFT_FLOAT) + d_add_builtin_version ("D_SoftFloat"); + else if (TARGET_HARD_FLOAT) + d_add_builtin_version ("D_HardFloat"); +} diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 45fce6ce865..96fa705f879 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -166,6 +166,9 @@ extern void s390_register_target_pragmas (void); /* Routines for s390-c.c */ extern bool s390_const_operand_ok (tree, int, int, tree); +/* s390-d.c routines */ +extern void s390_d_target_versions (void); + /* Pass management. */ namespace gcc { class context; } class rtl_opt_pass; diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index bf40b4c0644..3cfd3452d48 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -200,6 +200,9 @@ enum processor_flags /* Target CPU builtins. */ #define TARGET_CPU_CPP_BUILTINS() s390_cpu_cpp_builtins (pfile) +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS s390_d_target_versions + #ifdef DEFAULT_TARGET_64BIT #define TARGET_DEFAULT (MASK_64BIT | MASK_ZARCH | MASK_HARD_DFP \ | MASK_OPT_HTM | MASK_OPT_VX) diff --git a/gcc/config/s390/t-s390 b/gcc/config/s390/t-s390 index 8ca0c7879c9..97e6bf7d9eb 100644 --- a/gcc/config/s390/t-s390 +++ b/gcc/config/s390/t-s390 @@ -26,3 +26,7 @@ s390-c.o: $(srcdir)/config/s390/s390-c.c \ $(TARGET_H) $(TARGET_DEF_H) $(CPPLIB_H) $(C_PRAGMA_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/s390/s390-c.c + +s390-d.o: $(srcdir)/config/s390/s390-d.c + $(COMPILE) $< + $(POSTCOMPILE) diff --git a/gcc/config/sparc/sparc-d.c b/gcc/config/sparc/sparc-d.c new file mode 100644 index 00000000000..19fe5be6d73 --- /dev/null +++ b/gcc/config/sparc/sparc-d.c @@ -0,0 +1,48 @@ +/* Subroutines for the D front end on the SPARC architecture. + 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "d/d-target.h" +#include "d/d-target-def.h" + +/* Implement TARGET_D_CPU_VERSIONS for SPARC targets. */ + +void +sparc_d_target_versions (void) +{ + if (TARGET_64BIT) + d_add_builtin_version ("SPARC64"); + else + d_add_builtin_version ("SPARC"); + + if (TARGET_V8PLUS) + d_add_builtin_version ("SPARC_V8Plus"); + + if (TARGET_FPU) + { + d_add_builtin_version ("D_HardFloat"); + d_add_builtin_version ("SPARC_HardFloat"); + } + else + { + d_add_builtin_version ("D_SoftFloat"); + d_add_builtin_version ("SPARC_SoftFloat"); + } +} diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index 12613dbc516..59c9b2a90b5 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -111,4 +111,7 @@ unsigned int sparc_regmode_natural_size (machine_mode); extern rtl_opt_pass *make_pass_work_around_errata (gcc::context *); +/* Routines implemented in sparc-d.c */ +extern void sparc_d_target_versions (void); + #endif /* __SPARC_PROTOS_H__ */ diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 520a6b32083..8c15e2a958d 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -27,6 +27,9 @@ along with GCC; see the file COPYING3. If not see #define TARGET_CPU_CPP_BUILTINS() sparc_target_macros () +/* Target CPU versions for D. */ +#define TARGET_D_CPU_VERSIONS sparc_d_target_versions + /* Specify this in a cover file to provide bi-architecture (32/64) support. */ /* #define SPARC_BI_ARCH */ diff --git a/gcc/config/sparc/t-sparc b/gcc/config/sparc/t-sparc index 7fb3029fa54..30f15c9005a 100644 --- a/gcc/config/sparc/t-sparc +++ b/gcc/config/sparc/t-sparc @@ -23,3 +23,7 @@ PASSES_EXTRA += $(srcdir)/config/sparc/sparc-passes.def sparc-c.o: $(srcdir)/config/sparc/sparc-c.c $(COMPILE) $< $(POSTCOMPILE) + +sparc-d.o: $(srcdir)/config/sparc/sparc-d.c + $(COMPILE) $< + $(POSTCOMPILE) diff --git a/gcc/config/t-glibc b/gcc/config/t-glibc index 582215f9a7d..29d70867e63 100644 --- a/gcc/config/t-glibc +++ b/gcc/config/t-glibc @@ -19,3 +19,7 @@ glibc-c.o: config/glibc-c.c $(COMPILE) $< $(POSTCOMPILE) + +glibc-d.o: config/glibc-d.c + $(COMPILE) $< + $(POSTCOMPILE) diff --git a/gcc/configure b/gcc/configure index c49b4b264e8..03461f1e275 100755 --- a/gcc/configure +++ b/gcc/configure @@ -612,6 +612,7 @@ ISLLIBS GMPINC GMPLIBS target_cpu_default +d_target_objs fortran_target_objs cxx_target_objs c_target_objs @@ -619,6 +620,8 @@ use_gcc_stdint xm_defines xm_include_list xm_file_list +tm_d_include_list +tm_d_file_list tm_p_include_list tm_p_file_list tm_defines @@ -11858,6 +11861,7 @@ fi tm_file="${tm_file} defaults.h" tm_p_file="${tm_p_file} tm-preds.h" +tm_d_file="${tm_d_file} defaults.h" host_xm_file="auto-host.h ansidecl.h ${host_xm_file}" build_xm_file="${build_auto} ansidecl.h ${build_xm_file}" # We don't want ansidecl.h in target files, write code there in ISO/GNU C. @@ -12241,6 +12245,21 @@ for f in $tm_p_file; do esac done +tm_d_file_list= +tm_d_include_list="options.h insn-constants.h" +for f in $tm_d_file; do + case $f in + defaults.h ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/$f" + tm_d_include_list="${tm_d_include_list} $f" + ;; + * ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/config/$f" + tm_d_include_list="${tm_d_include_list} config/$f" + ;; + esac +done + xm_file_list= xm_include_list= for f in $xm_file; do @@ -18510,7 +18529,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18513 "configure" +#line 18532 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -18616,7 +18635,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 18619 "configure" +#line 18638 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -29504,6 +29523,9 @@ fi + + + diff --git a/gcc/configure.ac b/gcc/configure.ac index f43af0b8d20..1ac290e3c6e 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -1752,6 +1752,7 @@ AC_SUBST(build_subdir) tm_file="${tm_file} defaults.h" tm_p_file="${tm_p_file} tm-preds.h" +tm_d_file="${tm_d_file} defaults.h" host_xm_file="auto-host.h ansidecl.h ${host_xm_file}" build_xm_file="${build_auto} ansidecl.h ${build_xm_file}" # We don't want ansidecl.h in target files, write code there in ISO/GNU C. @@ -1984,6 +1985,21 @@ for f in $tm_p_file; do esac done +tm_d_file_list= +tm_d_include_list="options.h insn-constants.h" +for f in $tm_d_file; do + case $f in + defaults.h ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/$f" + tm_d_include_list="${tm_d_include_list} $f" + ;; + * ) + tm_d_file_list="${tm_d_file_list} \$(srcdir)/config/$f" + tm_d_include_list="${tm_d_include_list} config/$f" + ;; + esac +done + xm_file_list= xm_include_list= for f in $xm_file; do @@ -6343,6 +6359,8 @@ AC_SUBST(tm_include_list) AC_SUBST(tm_defines) AC_SUBST(tm_p_file_list) AC_SUBST(tm_p_include_list) +AC_SUBST(tm_d_file_list) +AC_SUBST(tm_d_include_list) AC_SUBST(xm_file_list) AC_SUBST(xm_include_list) AC_SUBST(xm_defines) @@ -6350,6 +6368,7 @@ AC_SUBST(use_gcc_stdint) AC_SUBST(c_target_objs) AC_SUBST(cxx_target_objs) AC_SUBST(fortran_target_objs) +AC_SUBST(d_target_objs) AC_SUBST(target_cpu_default) AC_SUBST_FILE(language_hooks) diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog new file mode 100644 index 00000000000..b90ba711e8d --- /dev/null +++ b/gcc/d/ChangeLog @@ -0,0 +1,617 @@ +2018-10-26 Eugene Wissner + + * Make-lang.in (selftest-d): New. + * d-diagnostic.cc (vwarning): Fix warning emitting. + +2018-10-22 Iain Buclaw + + * d-spec.cc (lang_specific_driver): Always link against phobos if any + input file is given. + +2018-10-21 Iain Buclaw + + * d-lang.cc (d_get_alias_set): Always return zero. + +2018-10-21 Iain Buclaw + + * intrinsics.cc (maybe_set_intrinsic): Don't set built-in flag on + unsupported pow() overloads. + +2018-10-20 Iain Buclaw + + * expr.cc (ExprVisitor::binop_assignment): Call stabilize_reference on + LHS construct if it has side effects. + +2018-10-20 Iain Buclaw + + * intrinsics.cc (clear_intrinsic_flag): Remove function. + (maybe_expand_intrinsic): Remove clear_intrinsic_flag call. + +2018-10-20 Iain Buclaw + + * 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 + + * intrinsics.cc (expand_intrinsic_sqrt): Remove implicit int to double + conversion. + (expand_intrinsic_pow): Likewise. + +2018-10-20 Iain Buclaw + + * 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 + + * 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 + + * d-diagnostic.cc (d_diagnostic_report_diagnostic): Skip translation + by instead calling diagnostic_set_info_translated. + +2018-10-20 Iain Buclaw + + * 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 + + * expr.cc (ExprVisitor::visit(PowExp)): Remove function. + +2018-10-19 Iain Buclaw + + * d-attribs.c: Rename to d-attribs.cc. + * d-spec.c: Rename to d-spec.cc. + +2018-10-19 Iain Buclaw + + * d-lang.cc (d_gimplify_expr): Don't handle TREE_THIS_VOLATILE. + +2018-10-19 Iain Buclaw + + * 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 + + * d-diagnostic.cc (expand_format): Rename to expand_d_format. + Updated all callers. + +2018-10-17 Iain Buclaw + + * 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 + + * expr.cc (ExprVisitor::binary_op): Use POINTER_DIFF_EXPR. + +2018-10-17 Iain Buclaw + + * 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 + + * 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 + + * d-spec.c (lang_specific_driver): Use strrchr and strcmp to check + input file suffix. + +2018-10-17 Iain Buclaw + + * 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 + + * d-frontend.cc (Port::writelongLE): Remove function. + (Port::writelongBE): Remove function. + +2018-10-16 Iain Buclaw + + * d-convert.cc (convert): Remove goto maybe_fold. + +2018-10-16 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * lang.opt: Add missing periods to the ends of sentences. + +2018-10-16 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * decl.cc (finish_thunk): Adjust call to cgraph_node::create_thunk. + +2018-09-25 Eugene Wissner + + * 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 + + * 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 + + * 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 + + * intrinsics.cc (maybe_expand_intrinsic): Handle INTRINSIC_EXP. + * intrinsics.def (EXP): Add CTFE intrinsic. + +2018-09-07 Iain Buclaw + + * 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 + + * d-frontend.cc (eval_builtin): Replace DECL_BUILT_IN with + fndecl_built_in_p. + +2018-08-29 Iain Buclaw + + * d-target.cc (Target::prefixName): Remove function. + (Target::cppParameterType): New function. + +2018-08-25 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * types.cc (same_type_p): Check type codes match before checking + equivalence. + +2018-07-09 Iain Buclaw + + * Makefile.in (d/verstr.h): Remove recipe. + (d.mostlyclean): Remove cleanup of verstr.h. + * verstr.h: New file. + +2018-07-06 Iain Buclaw + + * d-codegen.cc (lower_struct_comparison): Evaluate side effects of + empty struct. + (build_struct_comparison): Likewise. + +2018-07-06 Iain Buclaw + + * typeinfo.cc (TypeInfoVisitor::layout_interfaces): Only generate an + interface vtable for classes. + (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): Likewise. + +2018-07-05 Iain Buclaw + + * 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 + + * d-builtins.cc (d_build_builtins_module): Export __builtin_clonglong + and __builtin_culonglong to gcc builtins module. + +2018-07-04 Eugene Wissner + + * d-spec.c: Include opt-suggestions.h containing option_proposer used by + gcc.h. + +2018-07-01 Iain Buclaw + + * 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 + + * expr.cc (ExprVisitor::visit(FuncExp)): Don't error about nested + delegate literals. + +2018-06-29 Iain Buclaw + + * 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 + + * 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 + + * types.cc (TypeVisitor::visit(TypeClass)): Handle get_symbol_decl + returning an error_mark_node. + +2018-06-22 Iain Buclaw + + * decl.cc (DeclVisitor::visit(FuncDeclaration)): Move function + unnesting to... + (get_symbol_decl): ... here. + +2018-06-22 Iain Buclaw + + * d-lang.cc (d_post_options): Set global showColumns parameter. + +2018-06-22 Iain Buclaw + + * 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 + + * 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 + + * expr.cc (ExprVisitor::visit(StringExp)): Copy string literal from + the frontend to a null terminated string. + +2018-05-21 Iain Buclaw + + * expr.cc (ExprVisitor::binary_op): Don't do complex conversions if + already handling excess precision. + +2018-04-02 Iain Buclaw + + * 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 + + * d-codegen.cc (stabilize_expr): Move modify expression rewrite... + * expr.cc (ExprVisitor::binop_assignment): ... here. + +2018-03-11 Iain Buclaw + + * 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 + + * 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 + + * lang.opt (fdeps, fdeps=): Deprecate options. + * gdc.texi (Code Generation): Remove deprecated fdeps options. + +2018-02-25 Iain Buclaw + + * Make-lang.in (D_FRONTEND_OBJS): Remove inline.o and inlinecost.o. + +2018-02-24 Iain Buclaw + + * 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 + + * Make-lang.in (DMD_WARN_CXXFLAGS): Only filter out + -Wmissing-format-attribute from WARN_CXXFLAGS. + +2018-02-18 Iain Buclaw + + * d-builtins.cc (build_frontend_type): Set alignment of structs in + frontend. + +2018-02-17 Iain Buclaw + + * d-incpath.cc (add_environment_paths): Remove function. + * gdc.texi (Environment Variables): Remove section. + +2018-02-10 Iain Buclaw + + * expr.cc (ExprVisitor::AssertExp): Use builtin expect to mark assert + condition as being likely true. + +2018-02-11 Iain Buclaw + + * 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 + + * gdc.texi (Runtime Options): Remove deprecated -fproperty option. + +2018-01-27 Iain Buclaw + + * d-lang.cc (d_gimplify_expr): Gimplify all CALL_EXPR_ARGS_ORDERED + call arguments, not just non-constant. + +2018-01-27 Iain Buclaw + + * 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 + + * toir.cc (build_function_body): Set input_location. + +2018-01-23 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * decls.cc (get_symbol_decl): Use attribute to mark naked functions. + +2018-01-08 Eugene Wissner + + * 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 + + 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 00000000000..4160b0ffe97 --- /dev/null +++ b/gcc/d/ChangeLog-2006 @@ -0,0 +1,954 @@ +2006-12-27 DF + + * 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 + + * phobos/configure.in: actually use value of + --enable-phobos-config-dir + +2006-12-26 David Friedman + + 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 + + * 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 + + * dmd/parse.h, dmd/parse.c(parseStatement, parseExtAsm), + dmd/statement.h, asmstmt.cc: Implement GCC extended assembler. + +2006-12-20 David Friedman + + * 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 + + 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 + + * package/simple.sh: use MAKE environment variable + +2006-12-11 David Friedman + + * patch-build_gcc-4.0: don't disable Objective C + +2006-12-09 David Friedman + + * 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 + + * 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 + + * 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 + + 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 + + * 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 + + * 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 + + * d-gcc-real.h: cleanup for warnings + +2006-11-24 David Friedman + + * 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 + + 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 + + * package/simple.sh: enhancements + + * dmd/attrib.c: fix message + +2006-11-16 David Friedman + + * d-codegen.cc (continueHere): fix error + * d-glue.cc (d_gcc_aggregate_dtors): " + +2006-11-14 David Friedman + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * phobos/config/unix-mid: add sysconf + +2006-10-11 David Friedman + + * 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 + + * 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 + + 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 + + * d-glue.cc (FuncDelaration::toObjFile): + Assert isMember for synchronized functions. + (NewExp::toElem): Correct some cases for nested classes + +2006-09-04 David Friedman + + * 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 + + * 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 + + Release GDC 0.19 + + * dmd/template.c: don't use ehfilter + * gdc-version: update + +2006-07-11 David Friedman + + 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 + + * 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 + + * ../../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 + + * 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 + + * d-glue.cc (TypeStruct::toCtype, TypeEnum::toCtype): Move + initTypeDecl call to after size calculation. + +2006-06-24 David Friedman + + * 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 + + * 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 + + * Make-lang.in: use BUILD_LDFLAGS for generator progs + +2006-06-21 David Friedman + + * d-asm-i386.h: implement offset/offsetof + +2006-06-20 David Friedman + + 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 + + * 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 + + * 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 + + * 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 + + * phobos/config/skyos/frag-unix: update for SkyOS beta 10 + +2006-06-05 David Friedman + + 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 + + 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 + + * 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 + + * 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 00000000000..a2e504362c3 --- /dev/null +++ b/gcc/d/ChangeLog-2007 @@ -0,0 +1,1340 @@ +2007-12-15 David Friedman + + * 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 + + * 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 + + * 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 + + * d-cppmngl.cc: Use base-36 in substitutions. Other fixes. + +2007-10-17 David Friedman + + * d-cppmngl.cc: More C++ mangling fixes and cleanups. + +2007-10-16 David Friedman + + * d-glue.cc (EqualExp::toElem): Convert result to libcall + to expression type. (Bugzilla 1573) + +2007-10-15 David Friedman + + * d-cppmngl.cc: Improve C++ mangling. + +2007-10-14 David Friedman + + 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 + + * 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 + + 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 + + * 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 + + * 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 + + + * d-codegen.cc (convertTo, call): Prevent multiple re-evaluation + of delgate. (Bugzilla 1492) + +2007-09-13 David Friedman + + * 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 + + * 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 + + * phobos/std/c/stdio.d: Define fpos_t correctly for Drawin + (Bugzilla 1469) + +2007-09-05 David Friedman + + 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 + + * d-objfile.cc (outdata): Do not set TREE_CONSTANT on initializers + (Bugzilla 1453) + +2007-08-29 David Friedman + + * d-decls.cc (uniqueName): Allow multiple static declaration with + the same name if in a function. (SF 1783085) + +2007-08-28 David Friedman + + * 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 + + Release GDC 0.24 + + --- + + * rdmd.d: Fix for Windows + +2007-08-21 David Friedman + + * 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 + + * patch-gcc-4.1.x, patch-gcc-4.0.x: Fix botched patches. + +2007-08-05 David Friedman + + * 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 + + * phobos/std/stdio: Fix breakage from last commit. + (SF 1761989) + +2007-07-26 David Friedman + + * 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 + + * 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 + + 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 + + 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 + + * 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 + + * 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 + + * d-codegen.cc (ArrayScope::setArrayExp, finish): Handle + constant lengths. (Bugzilla 1031) + +2007-07-13 David Friedman + + * 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 + + * 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 + + * 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 + + * 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 + + 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 + + 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 + + * 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 + + 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 + + * d-decls.cc (ClassDeclaration::toSymbol): Do not set TREE_READONLY. + (Bugzilla 1037) + +2007-03-10 David Friedman + + * 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 + + 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 + + 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 + + * 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 + + * 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 + + * phobos/std/loader.d: Fix error + +2007-02-27 David Friedman + + * 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 + + * setup-gcc.sh: Copy the removed files from the top-level + directory. + +2007-02-10 David Friedman + + * 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 + + * 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 + + * 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 + + 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 + + * phobos/gcc/cbridge_time.c (_d_gnu_cbridge_tza), + phobos/std/date.d: Fix timezone adjust sign + +2007-02-03 David Friedman + + * 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 + + 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 + + * 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 + + 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 + + * 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 + + * 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 + + * INSTALL.html: fix corruption + +2007-01-03 David Friedman + + 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 + + * 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 00000000000..23dc712dbf3 --- /dev/null +++ b/gcc/d/ChangeLog-2008 @@ -0,0 +1,331 @@ +2008-12-12 Arthur Loiret + + 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 + + * 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 + + * dmd/expression.c, dmd2/expression.c: Make integer conversion + fix work for other hosts/targets. + +2008-07-20 Arthur Loiret + + * dmd/expression.c: Fix integer conversion routines on x86_64. + Patch from downs , thanks! + * dmd2/expression.c: Likewise. + + * config-lang.in: Add lang_requires="c c++". + +2008-07-19 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 + + * 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 + + * d-decls.cc: Correct logic for output constanting vars for V1. + +2008-06-01 David Friedman + + 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 + + * 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 + + * 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 + + * 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 + + * d-dmd-gcc.h, d-glue.cc, dmd*/toobj.c: Cleanup: Remove unused + d_gcc_aggregate_dtors. + +2008-05-02 David Friedman + + 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 + + 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 + + * asmstmt.cc, d-asm-i386.h: Handle some other cases + for constant floating point operands. + +2008-04-19 David Friedman + + * 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 + + * dmd/toobj.c (InterfaceDeclaration::toObjFile): Fix error. + (Bugzilla 1844) + +2008-04-16 David Friedman + + * 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 + + * 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 + + * 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 00000000000..90a204d0497 --- /dev/null +++ b/gcc/d/ChangeLog-2009 @@ -0,0 +1,185 @@ +2009-12-28 michaelp + + 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 + + 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 + + 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 + + Changes to GCC-4.4.x branch: + + * tools/makewebstatistics.d: Added d tool to generate webstats about + dstress in D2. + +2009-10-25 michaelp + + 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 + + * 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 + + * 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 + + Changes to 2.032 branch: + + * dmd2/..., phobos2/...: Force merge with 2.032 - NOT WORKING AT ALL. + - Adding new files. + +2009-10-04 michaelp + + 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 + + * 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 + + Merge with DMD 1.036 + +2009-09-28 Vincenzo Ampolo + + 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 + + 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 + + Merge with DMD 1.033 + +2009-09-17 Vincenzo Ampolo + + * dmd2.032/...: Initial import of version 2.032. + + * setup-gcc.sh, dmd/.svn/...: Removed .svn directory. + +2009-09-13 michaelp + + * 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 + + * 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 + + 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 + + * trunk/...: Import of gdc 0.24 stable into bitbucket. + +2009-01-31 Arthur Loiret + + * 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 00000000000..40c8fa45cd3 --- /dev/null +++ b/gcc/d/ChangeLog-2010 @@ -0,0 +1,1484 @@ +2010-12-28 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d/d-codegen.cc: Issue #76 - odd error message when casting between + non-convertable types. + [0c78536565d6] + +2010-11-01 Iain Buclaw + + * 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 + + * 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 ' + 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 + + * 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 + + * d/d-glue.cc, d/druntime/*, d/phobos2/*: Issue #77 - porting D2 + Phobos to x86_64. + [cf5f02e03fda] + +2010-10-23 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * d/d-glue.cc, d/dmd2/*, d/druntime/*: Updated D2 frontend to 2.029. + [082c04bad0c3] + +2010-10-07 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-codegen.cc: + Issue #14: STATIC_CHAIN_EXPR not caught in estimate_num_insns_1() + [63c14701ccde] + +2010-08-29 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * patches/patch-gcc-4.4.x: + Regenerate gcc-4.4.x patch + [4dfe5494460a] + +2010-08-25 Iain Buclaw + + * 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 + + * d-lang.cc: + Issue #58 - Fixed stack overflow in gdc-4.4 + [c02f5ac787a8] + +2010-08-23 Iain Buclaw + + * d-codegen.cc: + Bugzilla 1813 - ICE on static function parametrized with alias. + [2e06ca97b873] + +2010-08-22 michaelp + + * 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 + + * 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 + + * phobos2/*: + Updated phobos2 to 2.020 (not working) + [08d9a5b24ff4] + +2010-08-20 Iain Buclaw + + * d-glue.cc: + Fix ICE on shorthand if statements. + [ef2959fa8184] + +2010-08-20 michaelp + + * d-glue.cc: + Fixed problem with continue statements in D2 + [511f3176ec0d] + +2010-08-20 Iain Buclaw + + * 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 + + * 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 + + * phobos/*: + Updated Phobos to 1.063 - expanded tabs. + [bbe96bfd09dd] + +2010-08-17 michaelp + + * d-glue.cc: + One of Issue #56. Cannot goto into finally block + [22792e6a6253] + +2010-08-17 Iain Buclaw + + * 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 + + * d-glue.cc, dmd/func.c, dmd/statement.c, dmd/statement.h: + Temporarily reverted 1.063 change + [d89d1a46125d] + +2010-08-16 Iain Buclaw + + * 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 + + * d-codegen.cc: + Some more type conversion updates in glue. + [4567e417c0b3] + +2010-08-14 Iain Buclaw + + * 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 + + * phobos/std/thread.d: + Updated thread_attach bug in Windows + [de30c34ef79d] + +2010-08-14 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-codegen.cc: + Issue 33 - Sefault with nested array allocation + [be805cb4fb58] + +2010-08-09 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d/dmd-script: + More updates to gdmd + [d77ee89f6174] + +2010-08-05 michaelp + + * d/dmd-script: + Small changes to gdmd; some fixes for Issue 46 + [9269acda0b86] + +2010-08-05 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-glue.cc, dmd/*, phobos/std/date.d: + Updated to 1.062 + [9f7927e5f551] + +2010-07-30 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-codegen.cc, d-glue.cc: + D2 postblit on struct literals finished! + [9ee37bd66bca] + +2010-07-25 michaelp + + * d-lang.cc, d/dmd-script, dmd/*, + phobos/internal/arrayfloat.d: + Updated to 1.056 + [4ff162deda23] + +2010-07-24 Iain Buclaw + + * d-glue.cc: + D2 postblit updates. + [d53a8be7c0ed] + +2010-07-23 michaelp + + * 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 + + * 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 + + * 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 + + * d-builtins2.cc, d-codegen.cc, d-codegen.h, d-glue.cc, + dmd/*, phobos/*: + Updated to 1.053 + [f02a96cfc1de] + +2010-07-20 Iain Buclaw + + * d-glue.cc: + Quick revision updates + [c79811b4f1fc] + +2010-07-19 Iain Buclaw + + * 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 + + * phobos2/Makefile.in: + libgphobos2 Makefile fixes. + [c4acdacfddd2] + +2010-07-16 Iain Buclaw + + 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 + + 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 + + * 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 + + * dmd/arrayop.c: Fix problem with float array operations. + - Added linear search for the array op library functions. + +2010-07-05 Iain Buclaw + + * 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 + + Merge DMD 2.017 + +2010-07-04 Iain Buclaw + + 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 + + * setup-gcc.sh: D1 is default in setup-gcc.sh now. + +2010-06-27 Iain Buclaw + + 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 + + * 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 + + 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 + + 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 + + * d-asm-i386.h: Apply patch to compile tango (thanks to venix1). + +2010-04-05 michaelp + + 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 + + * d-glue.cc: Make d1 classinfo like d2 ones. + + * dmd/expression.c, phobos/std/process.d: Apply feep (downs) patch. + +2010-02-07 michaelp + + 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 + + * 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 00000000000..a5c155821d1 --- /dev/null +++ b/gcc/d/ChangeLog-2011 @@ -0,0 +1,1248 @@ +2011-12-31 Iain Buclaw + + * 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 + + * 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 + + * d/phobos2/Makefile.am, d/phobos2/Makefile.in: Add + std/internal/windows/advapi32.o to WINDOWS_OBJS. + [e7639c523add] + +2011-12-28 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d/d-objfile.cc: Issue #268 - ICE with -flto and -g + [3da453291dc3] + +2011-11-24 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d/d-lang.cc: Arm -> ARM and darwin -> Darwin in d-lang.cc. + [51e67c38af0c] + +2011-10-30 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d/d-glue.cc: Issue #235 - ICE in feep's tools library + [17da3d28ba17] + +2011-09-15 Daniel Green + + * 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 + + * 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 + + * d/d-lang.cc: Convert Array to Strings required by DMD 1.070/2.055 + [fc0033715683] + +2011-09-12 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d/druntime/core/sys/windows/stacktrace.d: Issue #227. build error + libphobos/core/sys/windows/stacktrace.d. + [b1c34b7e7764] + +2011-08-15 Iain Buclaw + + * d/d-decls.cc: Issue #225 - Array ops should be COMDAT. + [dda1c10c8c7b] + +2011-08-12 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d/d-asm-i386.h: Fixes issue #213. + [71737ec293cb] + +2011-06-20 Daniel Green + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d/Make-lang.in, d/d-gcc-real.cc, d/d-gcc-real.h: Fix strict-aliasing + warning. + [79ed94287f94] + +2011-03-30 Daniel Green + + * d/asmstmt.cc: An unitialized array was forcing GDC to mark all + registers as clobbered. + [007de89f7694] + +2011-03-27 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 00000000000..741747b06e5 --- /dev/null +++ b/gcc/d/ChangeLog-2012 @@ -0,0 +1,857 @@ +2013-02-15 Iain Buclaw + + * Make-lang.in (GDC_EXTENDED_ASM_SYNTAX): Remove macro. + +2013-02-14 Iain Buclaw + + * d-lang.h (D_DECL_IS_CONTRACT): Remove macro. + * d-decls.cc (FuncDeclaration::toSymbol): Likewise. + +2013-02-13 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * d-decls.cc (FuncDeclaration::toSymbol): Don't optimise PUREconst + calls. + +2012-10-27 Iain Buclaw + + * d-codegen.cc (IRState::buildAssignOp): Handle case where LHS type is + not compatible with expression type. + +2012-10-26 Iain Buclaw + + * 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 + + * d-codegen.cc (IRState::getFrameInfo): Use vthis to determine whether + function is nested. + +2012-10-21 Iain Buclaw + + * 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 + + * d-objfile.cc (ObjectFile::outputThunk): Mark thunk as DECL_WEAK + rather than using weakref attribute. + +2012-10-14 Iain Buclaw + + * 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 + + * d-glue.cc (VectorExp::toElem): Handle non-constant array literals as + vector expressions. + +2012-10-04 Iain Buclaw + + * d-glue.cc (VectorExp::toElem): Handle both array literal as well as + single element constructors for vector expressions. + +2012-09-27 Iain Buclaw + + * d-convert.cc (convert): Remove assert. + +2012-09-22 Iain Buclaw + + * 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 + + * 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 + + * d-codegen.h (CtorEltMaker::cons): Adjust call to VEC_safe_push. + * d-objfile.cc (ObjectFile::stripVarDecl): Clean-up. + +2012-09-16 Iain Buclaw + + * 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 + + * d-codegen.cc (AggLayout::doFields): Propagate volatile out of type. + (AggLayout::addField): Likewise. + * d-decls.cc (VarDeclaration::toSymbol): Likewise. + +2012-09-06 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-decls.cc (Dsymbol::toSymbolX): Remove use of PRIuSIZE format macro. + (FuncDeclaration::toThunkSymbol): Likewise. + +2012-07-12 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * d-glue.cc (StructLiteralExp::toElem): Stop after first assignment for + constructors built for union types. + +2012-07-01 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 00000000000..eeb12c9665d --- /dev/null +++ b/gcc/d/ChangeLog-2013 @@ -0,0 +1,1221 @@ +2013-12-27 Iain Buclaw + + * 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 + + * d-decls.cc (EnumDeclaration::toDebug): Don't send array types to + rest_of_type_compilation. + +2013-12-16 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-elem.cc (ArrayLiteralExp::toElem): Build empty constructor for zero + sized arrays. + +2013-10-23 Iain Buclaw + + * 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 + + * d-builtins.c (DEF_FUNCTION_TYPE_8): Define. + +2013-10-10 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-elem.cc (SliceExp::toElem): Don't build D array for slices that + return a static array. + +2013-09-03 Iain Buclaw + + * d-codegen.cc (IRState::buildOp): Rename to build_binary_op. + +2013-09-01 Iain Buclaw + + * 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 + + * d-spec.c (lang_specific_spec_functions): Remove. + +2013-08-28 Iain Buclaw + + * 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 + + * 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 + + * d-elem.cc (ArrayLiteralExp::toElem): Return null for zero length + array literals. + +2013-08-07 Iain Buclaw + + * 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 + + * 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 + + * d-elem.cc (Expression::toElemDtor): Wrap temp variables destructor + calls in a try/finally expression. + +2013-07-05 Johannes Pfau + + * 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 + + * 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 + + * 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 + + * 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 + + * d-objfile.cc (make_alias_for_thunk): Do not set + TREE_SYMBOL_REFERENCED. + +2013-06-17 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-codegen.cc (maybe_set_builtin_frontend): Check parameter and + return types of intrinsics. + +2013-06-01 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-incpath.cc (prefixed_path): use cpp_PREFIX instead of + cpp_GCC_INCLUDE_DIR for relocation. + +2013-05-16 Iain Buclaw + + * d-codegen.cc (IRState::convertForAssignment): Remove use of + CtorEltMaker wrapper for vec. + (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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-elem.cc (IdentityExp::toElem): Remove special handling of class, + reference and array types. + +2013-04-12 Iain Buclaw + + * 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 + + * d-decls.cc (FuncDeclaration::toSymbol): Harden logic for marking + functions pure as in 'has no side effects'. + +2013-04-07 Iain Buclaw + + * 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 + + * d-elem.cc (FuncExp::toElem): Defer function literals and lambdas + until parent function has finished processing. + +2013-04-04 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-ir.cc (SynchronizedStatement::toIR): Remove implementation as is + now handled by the frontend. + +2013-03-15 Iain Buclaw + + * d-codegen.cc (IRState::maybeExpandSpecialCall): Handle ref argptr + arguments. + +2013-03-13 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Make-lang.in (GDC_EXTENDED_ASM_SYNTAX): Remove macro. + +2013-02-14 Iain Buclaw + + * d-lang.h (D_DECL_IS_CONTRACT): Remove macro. + * d-decls.cc (FuncDeclaration::toSymbol): Likewise. + +2013-02-13 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 00000000000..cf8c8ac2c06 --- /dev/null +++ b/gcc/d/ChangeLog-2014 @@ -0,0 +1,660 @@ +2014-12-14 Iain Buclaw + + * 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 + + * d-elem.cc (CatExp::toElem): Split dynamic arrays when passing as + varargs to arraycatT and arraycatnT. + +2014-11-09 Iain Buclaw + + * d-codegen.cc (build_vthis): Handle getting static chain for nested + templated structs. + +2014-09-07 Iain Buclaw + + * d-elem.cc (ArrayLiteralExp::toElem): Remove special handling for + immutable arrays. + +2014-08-03 Iain Buclaw + + * d-longdouble.cc (longdouble::formatHex): Convert buffer to uppercase + for use in mangling templates. + +2014-07-29 Iain Buclaw + + * 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 + + * d-ctype.cc (TypeFunction::toCtype): Only check for ref return for + functions returning non-void. + +2014-07-21 Iain Buclaw + + * 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 + + * d-lang.cc (d_init_options_struct): Set flag_wrapv as on by default. + +2014-07-14 Iain Buclaw + + * 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 + + * d-objfile.cc (d_finish_symbol): Always set TREE_STATIC for symbols + being sent to the backend here. + +2014-07-12 Iain Buclaw + + * d-objfile.cc (d_finish_symbol): Don't set DECL_INITIAL if the + initialiser is all zeros. + +2014-07-10 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-lang.cc (d_init): Define GNU_SEH_Exceptions and + GNU_DWARF2_Exceptions versions. + +2014-04-21 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * d-decls.cc (Dsymbol::toImport): Prevent GC from collecting + IMPORTED_DECL nodes whilst front-end compilation in progress. + +2014-03-19 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-codegen.cc (build_attributes): Ensure D-specific attributes have + their value interpreted through CTFE. + +2014-02-21 Iain Buclaw + + * 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 + + * d-objfile.cc (build_call_function): Call set_input_location + to set debug info correctly + +2014-02-18 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + + * 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 + + * 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 + + * d-decls.cc (EnumDeclaration::toDebug): Build TYPE_DECL only for + enumeral types. + +2014-01-06 Iain Buclaw + + * 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 + + * 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 + + * 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 00000000000..918068bfecb --- /dev/null +++ b/gcc/d/ChangeLog-2015 @@ -0,0 +1,771 @@ +2015-10-07 Iain Buclaw + + * d-decls.cc (StructLiteralExp::toSymbol): Use letter prefix for + anonymous name. Don't set TREE_READONLY. + (ClassReferenceExp::toSymbol): Likewise. + +2015-10-06 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * toir.cc (IRVisitor::visit): Set input location in all visitors that + either throw an ICE or sorry message. + +2015-08-19 Iain Buclaw + + * Make-lang.in: Replace uses of $(target_alias) with + $(target_noncanonical). + +2015-08-17 Iain Buclaw + + * 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 + + * d-elem.cc (HaltExp::toElem): Use __builtin_trap to halt execution, + rather than the library abort() call. + +2015-08-07 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-lang.cc (deps_write): Use StringTable instead of hash_set of string + pointers. + +2015-07-23 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-lang.cc (d_parse_file): Set ref flag on the module and make deps + file handle. + +2015-07-11 Iain Buclaw + + * 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 + + * d-codegen.cc (expand_intrinsic_arith): Use build_deref to handle + ref parameters being used for the 'overflow' parameter. + +2015-07-03 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-objfile.cc (setup_symbol_storage): Mark functions without + body as DECL_EXTERNAL. + +2015-04-08 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-lang.cc: Remove d-confdef.h header. + * d-incpath.cc: Ditto. + * d-spec.cc: Ditto. + +2015-01-31 Iain Buclaw + + * d-incpath.cc (add_phobos_versyms): Remove function. + * d-lang.cc (d_init): Remove call to add_phobos_versyms. + +2015-01-28 Iain Buclaw + + * d-builtins.cc (DEF_FUNCTION_TYPE_VAR_8) + (DEF_FUNCTION_TYPE_VAR_12): New macros. + +2015-01-24 Johannes Pfau + + * d-builtins.cc (d_build_builtins_module): Mark builtin functions + as @nogc. + +2015-01-18 Iain Buclaw + + * 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 + + * d-elem.cc (UshrAssignExp::toElem): Remove integer promotion on left + hand side of unsigned right shift expression. + +2015-01-13 Iain Buclaw + + * 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 + + * 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 00000000000..dbd75733803 --- /dev/null +++ b/gcc/d/ChangeLog-2016 @@ -0,0 +1,1262 @@ +2016-12-28 Iain Buclaw + + * expr.cc (ExprVisitor::visit(VarExp)): Remove type forced conversion. + +2016-12-28 Iain Buclaw + + * d-lang.cc (d_handle_option): Handle -ftransition=safe. + * lang.opt (ftransition=safe): Add compiler option. + +2016-12-28 Iain Buclaw + + * d-lang.cc (d_init_options): Initialize hdrStripPlainFunctions. + (d_post_options): Add post option handling of flag. + +2016-12-27 Iain Buclaw + + * 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 + + * d-lang.cc (d_parse_file): Run runDeferredSemantic2 after semantic2. + +2016-12-26 Iain Buclaw + + * expr.cc (ExprVisitor::visit(ArrayLiteralExp)): Use getElement to + index elements array. + (ExprVisitor::visit(VectorExp)): Likewise. + +2016-12-25 Iain Buclaw + + * Make-lang.in (D_DMD_OBJS): Add d/objc.o + * types.cc (TypeVisitor::visit(TypeFunction)): Handle ObjC linkage. + +2016-12-25 Iain Buclaw + + * d-decls.cc (mangle_decl): New function. + (make_internal_name): Update. + (get_symbol_decl): Update. + +2016-12-24 Iain Buclaw + + * 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 + + * 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 + + * d-target.cc (Target::cppExceptions): New variable. + (Target::init): Initialize it. + (Target::prefixName): New function. + +2016-12-19 Iain Buclaw + + * 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 + + * 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 + + * d-decls.cc (layout_moduleinfo_fields): Use finish_aggregate_type + instead of layout_type. + (layout_classinfo_interfaces): Likewise. + +2016-12-17 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-builtins.cc (build_dtype): Set type modifiers on frontend type. + +2016-12-12 Iain Buclaw + + * d-builtins.cc (build_dtype): Don't set default parameter storage + class as const. + +2016-12-12 Iain Buclaw + + * 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 + + * 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 + + * d-builtins.cc (build_dtype): Don't build generic function types. + (d_build_builtins_module): Remove check. + +2016-12-10 Iain Buclaw + + * 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 + + * d-spec.c (lang_specific_driver): Remove error handling. + * d-lang.cc (d_parse_file): Don't error twice. + +2016-12-06 Iain Buclaw + + * d-spec.c (lang_specific_driver): Remove 'added' variable. + +2016-12-04 Iain Buclaw + + * d-decls.cc (get_symbol_decl): Use needsCodegen to determine whether + template instance is extern or not. + +2016-12-02 Iain Buclaw + + * d-glue.cc (escapePath): Move to dfrontend. + (readFile): Likewise. + (writeFile): Likewise. + (ensurePathToNameExists): Likewise. + +2016-12-01 Iain Buclaw + + * 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 + + * types.cc (TypeVisitor::visit(Type)): Update. + +2016-11-24 Iain Buclaw + + * 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 + + * d-decls.cc (get_symbol_decl): Don't set alignment if + STRUCTALIGN_DEFAULT. + +2016-11-21 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-decls.cc (get_template_storage_info): Remove function. + (setup_symbol_storage): Use Dsymbol::isInstantiated instead. + +2016-11-05 Iain Buclaw + + * 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 + + * d-tree.h (lang_decl): Remove readonly field. + (DECL_LANG_READONLY): Remove macro. All callers updated. + +2016-10-29 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * d-codegen.h (d_types_same): Return early if types are identical. + +2016-10-09 Iain Buclaw + + * d-decls.cc (FuncDeclaration::toThunkSymbol): Rename to make_thunk. + All callers updated. + (finish_thunk): Update signature. + +2016-10-09 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-decls.cc (setup_symbol_storage): Remove unused parameters. + +2016-10-07 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * d-decls.cc (ClassDeclaration::toVtblSymbol): Rename to + get_vtable_decl. All callers updated. + +2016-10-03 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-tree.h (DECL_LANG_TREE): Remove macro. All callers updated. + +2016-10-02 Iain Buclaw + + * 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 + + * 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 + + * d-objfile.cc (d_finish_function): Handle template mixins (issue 231). + +2016-09-25 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * imports.cc (ImportVisitor::visit(ScopeDsymbol)): New visit method. + +2016-09-17 Iain Buclaw + + * 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 + + * d-codegen.cc (lower_struct_comparison): Don't compare vectors in the + same way as integers. + +2016-09-11 Iain Buclaw + + * d-todt.cc (Type::toDt): Remove function, inline into callers. + (TypeVector::toDt): Likewise. + (TypeSArray::toDt): Likewise. + (TypeStruct::toDt): Likewise. + +2016-09-11 Iain Buclaw + + * d-decls.cc (FuncDeclaration::toSymbol): Save current module decl + before calling function semantic. + * d-objfile.cc (FuncDeclaration::toObjFile): Likewise. + +2016-09-11 Iain Buclaw + + * types.cc: Document and reformat file. + +2016-09-10 Johannes Pfau + + * 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 + + * d-codegen.cc (get_frameinfo): Use hasNestedFrameRefs to determine + whether a frame should be created. + +2016-07-02 Iain Buclaw + + * d-objfile.cc (FuncDeclaration::toObjFile): Always convert the + DECL_RESULT of NRVO-capable functions into reference decls. + +2016-06-21 Iain Buclaw + + * 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 + + * d-lang.cc (d_handle_option): Add new -ftransition=dip25 and + -fmax-error-messages switches. + * lang.opt: Likewise. + +2016-06-19 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * d-convert.cc (d_build_truthvalue_op): Fold truthvalue operation. + (d_truthvalue_conversion): Use zero constant of expression type. + +2016-06-09 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-codegen.cc (build_deref): Handle ERROR_MARK nodes early. + (build_array_index): Likewise. + +2016-05-29 Johannes Pfau + + * toir.cc (IRVisitor::visit(SwitchStatement)): Set correct type for the + string table for switch(string) statements. + +2016-05-24 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * expr.cc (ExprVisitor::visit(IdentityExp*)): Remove side-effects + before comparing two dynamic arrays. + +2016-05-14 Iain Buclaw + + * 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 + + * 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 + + * d-codegen.cc (build_array_from_val): New function. + * expr.cc (ExprVisitor::visit(StructLiteralExp)): Use it. + +2016-05-11 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-target.cc (Target::init): Target::realpad value should be size + minus precision. + +2016-04-29 Iain Buclaw + + * 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 + + * d-todt.cc (TypeSArray::toDtElem): Remove special handling for + arrays of vectors. + +2016-04-23 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * imports.cc (ImportVisitor::visit(Declaration)): Don't assume toSymbol + method will cache it's result. + +2016-03-06 Iain Buclaw + + * 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 + + * 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 + + * imports.cc: New file. + * d-decls.cc (Dsymbol::toImport): Remove function, update all callers + to use build_import_decl. + +2016-03-03 Iain Buclaw + + * 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 + + * d-lang.cc (d_init): Remove short_double parameter from + build_common_tree_nodes. + +2016-02-20 Iain Buclaw + + * 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 + + * 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 + + * d-elem.cc: Remove redundant IRState parameter from all lowering + routines for expressions, update all callers. + +2016-02-07 Iain Buclaw + + * 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 + + * d-elem.cc (AssignExp::toElem): Pass parameters for arraycopy and + arrayassign in the correct order. + +2016-01-31 Iain Buclaw + + * longdouble.h (longdouble): Use one contiguous array for the + real_value data payload. + +2016-01-23 Iain Buclaw + + * toir.cc (IRVisitor::visit (ExtAsmStatement): Do validation of input + and output constraints, marking operands as addressable if requested. + +2016-01-10 Iain Buclaw + + * 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 + + * 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 + + * 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 00000000000..4f64c317a9e --- /dev/null +++ b/gcc/d/ChangeLog-2017 @@ -0,0 +1,1175 @@ +2017-12-23 Iain Buclaw + + * intrinsics.def (INTRINSIC_MULUI): Declare. + +2017-12-19 Iain Buclaw + + * 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 to vec. + (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 + + * 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 + + * 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 + + * 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 + + * types.cc (TypeVisitor::visit(TypeClass)): Check for duplicate + declarations before adding method. + +2017-12-09 Iain Buclaw + + * expr.cc (ExprVisitor::visit(AddrExp)): Build internal struct literal + symbol before generating its initializer. + +2017-12-09 Iain Buclaw + + * d-lang.cc (d_parse_file): Set first_global_object_name. + +2017-12-09 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * toir.cc (IRVisitor::visit(SwitchStatement)): Build SWITCH_EXPR using build2 instead + of build3. + +2017-11-14 Eugene Wissner + + * 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 + + * 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 + + * d-codegen.cc (build_address): Store CST nodes into a TARGET_EXPR + before taking its address. + +2017-10-08 Iain Buclaw + + * Make-lang.in (D_FRONTEND_OBJS): Remove newdelete.o. + * d-incpath.cc (add_globalpaths): Handle NULL target path. + +2017-10-01 Iain Buclaw + + * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoClassDeclaration)): + Properly check base classes for pointers. + +2017-09-28 Iain Buclaw + + * expr.cc (ExprVisitor::visit(StringExp)): Add extra null terminator + onto string type, not the literal. + +2017-09-26 Iain Buclaw + + * types.cc (make_array_type): Move checking of void static arrays + here. + +2017-09-24 Iain Buclaw + + * 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 + + * 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 + + * typeinfo.cc (TypeInfoVisitor::visit(TypeInfoStructDeclaration)): Do + not send member functions to backend here. + +2017-08-19 Iain Buclaw + + * d-convert.cc (convert_expr): Use build_zero_cst for casts from + typeof(null). + +2017-08-13 Iain Buclaw + + * d-target.cc (Target::isVectorOpSupported): Disallow vectors in + conditional and logical operators. + +2017-08-08 Iain Buclaw + + * 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 + + * intrinsics.cc (expand_intrinsic_popcnt): New function. + (maybe_expand_intrinsic): Handle INTRINSIC_POPCNT. + * intrinsics.def (INTRINSIC_POPCNT): Declare. + +2017-08-06 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * typeinfo.cc (SpeculativeTypeVisitor::visit(TypeClass)): Don't emit + typeinfo for speculative class types. + +2017-07-29 Iain Buclaw + + * 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 + + * decl.cc (d_finish_decl): Replace ENABLE_TREE_CHECKING macro with + flag_checking. + +2017-07-28 Iain Buclaw + + * 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 + + * d-spec.c (lang_specific_driver): Always add `-o' option when + compiling D sources. + +2017-07-28 Iain Buclaw + + * d-frontend.cc (genCmain): Don't error if entrypoint not found. + +2017-07-18 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-frontend.cc (CTFloat::hash): New function. + +2017-06-25 Iain Buclaw + + * 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 + + * toir.cc (IRVisitor::visit(ExtAsmStatement)): Set ASM_VOLATILE_P only + if statement is not marked with pure attribute. + +2017-06-25 Iain Buclaw + + * d-lang.cc (d_parse_file): Print all predefined version identifiers + if verbose. + +2017-06-24 Iain Buclaw + + * d-frontend.cc (Global::_init): Remove memset for global.params. + +2017-06-24 Iain Buclaw + + * 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 + + * expr.cc (ExprVisitor::visit(BinAssignExp)): Strip promotions from + both signed and unsigned rshift assignments. + +2017-06-17 Iain Buclaw + + * 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 + + * expr.cc (ExprVisitor::visit(AssertExp)): Don't call invariant on + interface objects. + +2017-06-12 Iain Buclaw + + * expr.cc (ExprVisitor::visit(DelegateExp)): Convert object to right + type before using it. + +2017-06-12 Iain Buclaw + + * d-decls.cc (get_decl_tree): Find the first parent member function + before constructing non-local `this' decl. + +2017-06-10 Iain Buclaw + + * d-builtins.cc (build_frontend_type): Allow all vector types to be + included in builtins module. + +2017-06-09 Iain Buclaw + + * types.cc (TypeVisitor::visit(TypeStruct)): Let struct alignment + override the alignsize. + +2017-06-09 Iain Buclaw + + * d-codegen.cc (d_decl_context): Use origin template declaration as + context for instantiated type symbols. + +2017-06-08 Iain Buclaw + + * 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 + + * expr.cc (ExprVisitor::visit(StringExp)): Create string type that is + same length as string value literal. + +2017-05-27 Iain Buclaw + + * Make-lang.in (D_FRONTEND_OBJS): Rename object.o to rootobject.o. + +2017-05-26 Iain Buclaw + + * decl.cc: Remove include for dumpfile.h. + (finish_function): Use dump_function to for dumping original ASTs. + +2017-05-24 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * imports.cc (ImportVisitor::visit(Import)): New function. + +2017-05-06 Iain Buclaw + + * 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 + + * 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 + + * d-diagnostic.cc (verror): Use xvasprintf. + (verrorSupplemental): Likewise. + (vwarning): Likewise. + (vwarningSupplemental): Likewise. + (vdeprecation): Likewise. + (vdeprecationSupplemental): Likewise. + +2017-04-24 Iain Buclaw + + * 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 + + * d-tree.h (d_function_chain): Declare macro. Update all uses of + `cfun->language' to use it. + +2017-04-22 Iain Buclaw + + * 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 + + * 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 + + * d-target.cc: Update includes. + +2017-04-19 Iain Buclaw + + * lang-specs.h: Remove capitalized D source suffixes. + +2017-04-19 Iain Buclaw + + * lang-specs.h: Add rule for forwarding -iprefix and -imultilib to the + compiler proper. + +2017-04-19 Iain Buclaw + + * lang-specs.h: Remove cc1d spec. + +2017-04-19 Iain Buclaw + + * lang-specs.h: Remove +e handling. + +2017-04-18 Iain Buclaw + + * d-diagnostic.cc: New file. + * d-frontend.cc: New file. + * d-glue.cc: Remove file. + * d-port.cc: Remove file. + * d-longdouble.h (template operator): Remove operators. + +2017-04-17 Iain Buclaw + + * 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 + + * 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 + + * Make-lang.in (D_FRONTEND_OBJS): Update to match new source names. + +2017-04-11 Iain Buclaw + + * gdc.texi: Rewrite documentation for manpages. + +2017-04-08 Iain Buclaw + + * d-objfile.cc (DeclVisitor::visit(FuncDeclaration)): Remove logic + that parent needs to be compiled before nested. + +2017-04-08 Iain Buclaw + + * 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 + + * d-lang.cc (d_parse_file): Remove invalid file name checks. + +2017-04-08 Iain Buclaw + + * d-glue.cc (Global::_init): Set global.stdmsg to stderr. + +2017-04-07 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-builtins.cc (d_build_builtins_module): Always mark gcc builtins as + nothrow functions. + +2017-03-11 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * 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::max): Define. + (Target::FPTypeProperties::min_normal): Define. + (Target::FPTypeProperties::nan): Define. + (Target::FPTypeProperties::snan): Define. + (Target::FPTypeProperties::infinity): Define. + (Target::FPTypeProperties::epsilon): Define. + (Target::FPTypeProperties::dig): Define. + (Target::FPTypeProperties::mant_dig): Define. + (Target::FPTypeProperties::max_exp): Define. + (Target::FPTypeProperties::min_exp): Define. + (Target::FPTypeProperties::max_10_exp): Define. + (Target::FPTypeProperties::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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * d-decls.cc (make_thunk): Don't build thunks for functions that + failed to compile. + +2017-03-04 Iain Buclaw + + * d-objfile.cc (emit_dso_registry_hooks): Set DECL_PRESERVE_P. + +2017-02-26 Iain Buclaw + + * 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 + + * d-glue.cc (warningSupplemental): New function. + (vwarningSupplemental): New function. + (deprecationSupplemental): New function. + (vdeprecationSupplemental): New function. + +2017-02-23 Iain Buclaw + + * imports.cc (ImportVisitor::visit(OverDeclaration)): New function. + (ImportVisitor::visit(FuncAliasDeclaration)): New function. + +2017-02-21 Iain Buclaw + + * 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 + + * lang.opt (fd-vgc): Comment out help test. + (fd-verbose): Likewise. + (fd-vtls): Likewise. + (femit-modules): Likewise. + +2017-02-20 Iain Buclaw + + * d-target.cc (Target::fieldalign): Adjust. + +2017-02-19 Iain Buclaw + + * 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 + + * d-lang.cc (is_system_module): Remove. + (deps_write): Always ignore entrypoint module. + +2017-02-19 Iain Buclaw + + * d-lang.cc (write_one_dep): Remove. + (deps_write): Update signature. + +2017-02-19 Iain Buclaw + + * 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 + + * 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 + + * 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 + + * d-objfile.cc (PragmaDeclaration::toObjFile): Warn about unknown + pragmas only if -Wunknown-pragmas. + +2017-02-18 Iain Buclaw + + * 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 + + * 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 + + * lang.opt (fassert): Update help text. + (fin): Likewise. + (finvariants): Likewise. + (fout): Likewise. + +2017-02-11 Iain Buclaw + + * d-objfile.cc (VarDeclaration::toObjFile): Error if a variable covers + more than half the address space. + +2017-02-04 Iain Buclaw + + * d-objfile.cc (Module::genmoduleinfo): Ignore symbol visibility when + looking up module DSO symbols. + +2017-01-29 Iain Buclaw + + * d-lang.cc (d_handle_option): Handle -ftransition=all. + * lang.opt (ftransition=all): Add compiler option. + +2017-01-29 Iain Buclaw + + * d-lang.cc (d_handle_option): Handle -ftransition=checkimports. + * lang.opt (ftransition=checkimports): Add compiler option. + +2017-01-28 Iain Buclaw + + * d-lang.cc (d_handle_option): Handle -ftransition=import. + * lang.opt (ftransition=import): Add compiler option. + +2017-01-25 Iain Buclaw + + * 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 + + * expr.cc (ExprVisitor::visit(EqualExp)): Don't use memcmp on arrays + of structs that define xopEquals. + +2017-01-15 Iain Buclaw + + * d-spec.cc (lang_specific_driver): Add missing break. + +2017-01-13 Iain Buclaw + + * d-codegen.cc (build_class_instance): Don't check for void + initialized fields. + * expr.cc (ExprVisitor::visit(StructLiteralExp)): Likewise. + +2017-01-11 Iain Buclaw + + * typeinfo.cc (layout_classinfo): Use placement new to initialize + typeinfo class declaration. + +2017-01-02 Iain Buclaw + + * 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 00000000000..79baf018889 --- /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 +# . + +# 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 00000000000..745ad7e68d5 --- /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 +# . + +# 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 00000000000..4f5d3e6cedf --- /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 +. */ + +/* 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 00000000000..a4a31e69db8 --- /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 +. */ + +#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 *gcc_builtins_functions = NULL; +static GTY(()) vec *gcc_builtins_libfuncs = NULL; +static GTY(()) vec *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_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 00000000000..74edb3680e7 --- /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 +. */ + +#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 *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 *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 *init) +{ + /* If the initializer was empty, use default zero initialization. */ + if (vec_safe_is_empty (init)) + return build_constructor (type, NULL); + + vec *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 %", + 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 ; */ + 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 *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 % 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 *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 *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 00000000000..7e073668b30 --- /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 +. */ + +#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 %", + 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 .ptr to cast (void *). + 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 *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 **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 00000000000..a21e7d6c40d --- /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 +. */ + +#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 00000000000..3cba25b1c5d --- /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 +. */ + +#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 *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 00000000000..be08ccb5f3b --- /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 +. */ + +#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 00000000000..42fefaf6409 --- /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 +. */ + +#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= */ + const char *multilib; /* -imultilib */ + const char *prefix; /* -iprefix */ + + bool deps; /* -M */ + bool deps_skip_system; /* -MM */ + const char *deps_filename; /* -M[M]D */ + const char *deps_filename_user; /* -MF */ + OutBuffer *deps_target; /* -M[QT] */ + 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 *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 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 (); + 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 (""); + 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 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 (); + 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 *ld = (d->csym) ? DECL_LANG_SPECIFIC (d->csym) : NULL; + if (ld == NULL) + ld = ggc_cleared_alloc (); + + 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 (); + 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 00000000000..fdea91f9d83 --- /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 +. */ + +#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 00000000000..d0b78445836 --- /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 +. */ + +#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 00000000000..ef3e948189c --- /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 + . */ + +#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 00000000000..3ae791b5f70 --- /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 +. */ + +#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 real_t Target::FPTypeProperties::max; +template real_t Target::FPTypeProperties::min_normal; +template real_t Target::FPTypeProperties::nan; +template real_t Target::FPTypeProperties::snan; +template real_t Target::FPTypeProperties::infinity; +template real_t Target::FPTypeProperties::epsilon; +template d_int64 Target::FPTypeProperties::dig; +template d_int64 Target::FPTypeProperties::mant_dig; +template d_int64 Target::FPTypeProperties::max_exp; +template d_int64 Target::FPTypeProperties::min_exp; +template d_int64 Target::FPTypeProperties::max_10_exp; +template d_int64 Target::FPTypeProperties::min_10_exp; + + +/* Initialize the floating-point constants for TYPE. */ + +template +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 (float_type_node); + define_float_constants (double_type_node); + define_float_constants (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 (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 00000000000..d2ff07f2952 --- /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 + . */ + +/* 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 00000000000..283eb24a881 --- /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 + . */ + +#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 00000000000..86b64612186 --- /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 +. */ + +/* 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 00000000000..6f18e40c2fa --- /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 +. */ + +#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 struct Array; +typedef Array 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 *stmt_list; + + /* Variables that are in scope that will need destruction later. */ + vec *vars_in_scope; + + /* Table of all used or defined labels in the function. */ + hash_map *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 *); +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 **); + +/* 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 00000000000..6fd0808123f --- /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 +. */ + +#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 % 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 *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 ("", 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 (); + 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 *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 00000000000..37e9c8681d3 --- /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 +#include +#include + +#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 00000000000..d7db82b0f0e --- /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 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 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 00000000000..50921ecb300 --- /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 +#include + +#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 00000000000..e5b0280d9e1 --- /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 00000000000..f20e411228f --- /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 +#include + +#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 00000000000..cad8d4ec92f --- /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 +#include + +#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 00000000000..0ea0d329399 --- /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 +#include +#include + +#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 00000000000..a3d305ed8e3 --- /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 TemplateParameters; + +typedef Array Expressions; + +typedef Array Statements; + +typedef Array BaseClasses; + +typedef Array ClassDeclarations; + +typedef Array Dsymbols; + +typedef Array Objects; + +typedef Array FuncDeclarations; + +typedef Array Parameters; + +typedef Array Identifiers; + +typedef Array Initializers; + +typedef Array VarDeclarations; + +typedef Array Types; +typedef Array Catches; + +typedef Array StaticDtorDeclarations; + +typedef Array SharedStaticDtorDeclarations; + +typedef Array AliasDeclarations; + +typedef Array Modules; + +typedef Array Files; + +typedef Array CaseStatements; + +typedef Array ScopeStatements; + +typedef Array GotoCaseStatements; + +typedef Array ReturnStatements; + +typedef Array GotoStatements; + +typedef Array TemplateInstances; diff --git a/gcc/d/dmd/attrib.c b/gcc/d/dmd/attrib.c new file mode 100644 index 00000000000..c4270ea63e6 --- /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 +#include +#include +#include // 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 00000000000..83486a95431 --- /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 00000000000..0516f139001 --- /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 00000000000..36b7cd93cdf --- /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 00000000000..a00741b7d72 --- /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 +#include + +#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 00000000000..b9ccb5b2397 --- /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 + +#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 00000000000..1f6545b6c62 --- /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 + + +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 00000000000..9105d114eaa --- /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 +#include +#include + +#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(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 00000000000..cfcc317ff9c --- /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 00000000000..b4ee395ec5b --- /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 00000000000..047eca261d8 --- /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 +#include +#include // 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 00000000000..e7727ccb6fb --- /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 00000000000..43e831f1dfe --- /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 +#include +#include +#include // mem{cpy|set|cmp}() +#include +#include + +#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 00000000000..bb919a5f2bb --- /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 +#include +#include + +#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 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) + { + /* ::= I + 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]; + + /* + * ::= # type or template + * ::= X E # expression + * ::= # simple expressions + * ::= I * 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()) + { + // ::= L 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 + static bool isChar_traits_char(RootObject *o) + { + return isIdent_char(Id::char_traits, o); + } + + // Detect type ::std::allocator + static bool isAllocator_char(RootObject *o) + { + return isIdent_char(Id::allocator, o); + } + + // Detect type ::std::ident + 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 > + * 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, ::std::allocator> + 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> + if (s->ident == Id::basic_istream && + char_std_char_traits_char(ti, "Si")) + return; + + // ::std::basic_ostream> + if (s->ident == Id::basic_ostream && + char_std_char_traits_char(ti, "So")) + return; + + // ::std::basic_iostream> + 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, ::std::allocator> + 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> + 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()); + /* + * ::= _Z + * ::= + * ::= + * ::= + */ + 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) + { + /* ::= N [] E + * ::= N [] E + */ + buf->writeByte('N'); + CV_qualifiers(d->type); + + /* ::= + * ::= + * ::= + * ::= # empty + * ::= + * ::= + */ + 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); + + /* : + * 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 # 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) + { + /* + * ::= F [Y] E + * ::= + + * # 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 + */ + 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 00000000000..f7f7c8547f4 --- /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 00000000000..ad5b827dcd3 --- /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 +#include +#include +#include // mem{cpy|set}() +#include + +#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 ""; + case TOKvoidexp: return ""; + case TOKbreak: return ""; + case TOKcontinue: return ""; + case TOKgoto: return ""; + 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 +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(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(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(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(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 00000000000..ee3bfd9d888 --- /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 +#include +#include // 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 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 00000000000..414332ccd34 --- /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 +#include +#include +#include // 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 00000000000..76132b9458e --- /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 +#include + +#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 00000000000..071ce2ca206 --- /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 00000000000..99fe93828a6 --- /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 +#include + +#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 00000000000..4107f11738e --- /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 +#include + +#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 00000000000..03b3d1f2c57 --- /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 +#include + +#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 00000000000..54bf00d5a41 --- /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 +#include +#include +#include // mem{cpy|set}() +#include + +#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 savedId; // id of the previous state of that var + + Array 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 00000000000..a5d8da10c36 --- /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 +#include +#include +#include +#include + +#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(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(arg)); + *pend = end; + nest--; +} diff --git a/gcc/d/dmd/dmangle.c b/gcc/d/dmd/dmangle.c new file mode 100644 index 00000000000..9734624b288 --- /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 +#include +#include +#include + +#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, ¶msToDecoBufferDg, (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 00000000000..a374aac73a7 --- /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 +#include +#include + +#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 +#endif +#if POSIX +#include +#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 *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 *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 00000000000..92ce33cd546 --- /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 +#include +#include +#include +#include + +#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
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 = \n\ + \n\ + $(TITLE)\n\ + \n\ +

$(TITLE)

\n\ + $(BODY)\n\ +
$(SMALL Page generated by $(LINK2 http://dlang.org/ddoc.html, Ddoc). $(COPYRIGHT))\n\ + \n\ +\n\ +B = $0\n\ +I = $0\n\ +U = $0\n\ +P =

$0

\n\ +DL =
$0
\n\ +DT =
$0
\n\ +DD =
$0
\n\ +TABLE = $0
\n\ +TR = $0\n\ +TH = $0\n\ +TD = $0\n\ +OL =
    $0
\n\ +UL =
    $0
\n\ +LI =
  • $0
  • \n\ +BIG = $0\n\ +SMALL = $0\n\ +BR =
    \n\ +LINK = $0\n\ +LINK2 = $+\n\ +LPAREN= (\n\ +RPAREN= )\n\ +BACKTICK= `\n\ +DOLLAR= $\n\ +DEPRECATED= $0\n\ +\n\ +RED = $0\n\ +BLUE = $0\n\ +GREEN = $0\n\ +YELLOW =$0\n\ +BLACK = $0\n\ +WHITE = $0\n\ +\n\ +D_CODE =
    $0
    \n\ +DDOC_BACKQUOTED = $(D_INLINECODE $0)\n\ +D_INLINECODE =
    $0
    \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 = \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 = \n\ +DDOC_PSYMBOL = $(U $0)\n\ +DDOC_PSUPER_SYMBOL = $(U $0)\n\ +DDOC_KEYWORD = $(B $0)\n\ +DDOC_PARAM = $(I $0)\n\ +\n\ +ESCAPES = //>/\n\ + /&/&/\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, "<") == 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 '<' 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 '>' 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 '&' 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 00000000000..7f3ef5127de --- /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 00000000000..924a3764c00 --- /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 +#include +#include // 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 00000000000..c99abcea9aa --- /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 +#include + +#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 00000000000..0f0a0dc6904 --- /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 +#include +#include +#include + +#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((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((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 00000000000..0f2f03de4f1 --- /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 00000000000..f2b3b2f7b21 --- /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 +#include + +#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(o); + if (!o || o->dyncast() != DYNCAST_EXPRESSION) + return NULL; + return (Expression *)o; +} + +Dsymbol *isDsymbol(RootObject *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_DSYMBOL) + return NULL; + return (Dsymbol *)o; +} + +Type *isType(RootObject *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TYPE) + return NULL; + return (Type *)o; +} + +Tuple *isTuple(RootObject *o) +{ + //return dynamic_cast(o); + if (!o || o->dyncast() != DYNCAST_TUPLE) + return NULL; + return (Tuple *)o; +} + +Parameter *isParameter(RootObject *o) +{ + //return dynamic_cast(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 = ≺ // 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 = ≺ // 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 00000000000..47374868674 --- /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 +#include + +#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 00000000000..38fd2d8713e --- /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 +#include + +#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 00000000000..072eacf583e --- /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 00000000000..7b3ebc0deeb --- /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 00000000000..353e56fd58f --- /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 00000000000..dc0d8e7c017 --- /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 +#include +#include +#include +#include + +#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; iobjects->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(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(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(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(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 00000000000..57c516c1d23 --- /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 00000000000..247d1433f4b --- /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 +#include +#include +#include +#include + +#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(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(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 00000000000..2feea9126cd --- /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 +#include + +#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("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("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 00000000000..63caeb7b6b1 --- /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 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 *modFileAliasStrings; // array of char*'s of -I module filename alias strings + Array *imppath; // array of char*'s of where to look for import modules + Array *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 *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 *debugids; // debug identifiers + + unsigned versionlevel; // version level + Array *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 *objfiles; + Array *linkswitches; + Array *libfiles; + Array *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 *path; // Array of char*'s which form the import lookup path + Array *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 00000000000..2c734b31822 --- /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 +#include +#include +#include + +#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 aop] < 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(""); + 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 00000000000..c4bafca6d36 --- /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 // 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 00000000000..1a4d810c30e --- /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 00000000000..5e0d9ae5a13 --- /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 00000000000..5e40746da7d --- /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 +#include +#include + +#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 00000000000..9352d286a75 --- /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 00000000000..d360ec850d8 --- /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 +#include +#include +#include + +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 00000000000..5b88e8e682e --- /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 +#include + +#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 00000000000..6d75603d80c --- /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 +#include +#include +#include +#include + +#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 00000000000..e0fa14d5888 --- /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 00000000000..e619cb4850a --- /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 +#include + +#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 00000000000..f4a150f83e4 --- /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 00000000000..bdaf2534a0c --- /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 00000000000..b4d54dbfeea --- /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 +#include + +#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 00000000000..69111586e8d --- /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 00000000000..4c49023b542 --- /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 +#include +#include + +#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 00000000000..7e4a51255b8 --- /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 00000000000..1fefe2b08de --- /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 +#include +#include +#include +#include +#include +#include +#include +#include // 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(×tamp[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(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(""); + 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(""); + 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(""); + 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(""); + 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(""); + 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 00000000000..988c06adec3 --- /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 00000000000..006f11842c4 --- /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 +#include +#include +#include + +#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 00000000000..72fc89a1860 --- /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 00000000000..9cc5bb86fee --- /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 +#include +#include + +#ifdef __DMC__ +#ifdef DEBUG +#undef assert +#define assert(e) (static_cast((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 00000000000..399b0085635 --- /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 00000000000..a4c38e8a1ee --- /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 +#include +#include +#include + +#if _MSC_VER +#include +#include +#elif __MINGW32__ +#include +#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(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(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(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(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(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 00000000000..c3b8a979bbe --- /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 00000000000..2b8255ee50e --- /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 00000000000..2bd6b969813 --- /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 +#include +#include + +#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 00000000000..8ca01ae8485 --- /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 00000000000..e12523d0a2e --- /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 00000000000..cc1f0981413 --- /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 00000000000..be6fd78886a --- /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 +#include +#include +#include +#include // 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(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 00000000000..12224fa5188 --- /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 +#include +#include +#include + +#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 00000000000..9ee2f0837b1 --- /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 +#include +#include // 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(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(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(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 00000000000..50381067917 --- /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 00000000000..a9a31af1b6e --- /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 00000000000..4c015bf0700 --- /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 +#include +#include +#include + +#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 00000000000..24c281a1503 --- /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 00000000000..ed128b93dd7 --- /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 +#include +#include +#include + +#include "object.h" +#include "rmem.h" + +template +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(x); + RootObject *oy = *(RootObject **)const_cast(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 00000000000..888ae5373fa --- /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 00000000000..3fc169c034e --- /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 +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 00000000000..f4fd51a0012 --- /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 +#endif + +#if _MSC_VER ||__MINGW32__ +#include +#include +#endif + +#if _WIN32 +#include +#include +#include +#endif + +#if POSIX +#include +#include +#include +#include +#include +#include +#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(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 00000000000..f6953ab34db --- /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 + +#include "array.h" + +typedef Array 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 00000000000..307e94f6584 --- /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 +#include + +#include "outbuffer.h" +#include "array.h" +#include "file.h" +#include "rmem.h" + +#if defined (__sun) +#include +#endif + +#if _MSC_VER ||__MINGW32__ +#include +#include +#endif + +#if _WIN32 +#include +#include +#include +#endif + +#if POSIX +#include +#include +#include +#include +#include +#include +#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(cpath)); + const char *p = mem.xstrdup(cname); + ::free(const_cast(cname)); + return p; + } +cont: + if (cpath) + ::free(const_cast(cpath)); + if (cname) + ::free(const_cast(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(p)); + return 0; + } +#endif + bool r = ensurePathExists(p); + mem.xfree(const_cast(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(str), 0xAB, strlen(str) + 1); // stomp + } + mem.xfree(const_cast(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 00000000000..0ef8c21328a --- /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 struct Array; +typedef Array 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 00000000000..1b05672ff9f --- /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 // uint{8|16|32}_t +#include + +// 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 00000000000..e9d770d5d3d --- /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 + +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 00000000000..7b6782defb1 --- /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 +#include +#include +#include +#include + +#if __sun +#include +#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 00000000000..6d3be107129 --- /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 +#include +#include +#include +#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 00000000000..3f3c46d9168 --- /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 // for alloca +#include + +#if _MSC_VER +#include +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 00000000000..92e79ca95ae --- /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 +#include +#include + +#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 00000000000..87d465f1da3 --- /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 // 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 00000000000..6c3df310479 --- /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 00000000000..cd239d6c3ca --- /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 + +#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 00000000000..52b4e4767f8 --- /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 +#include +#include +#include +#include + +#if __sun || _MSC_VER +#include +#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 00000000000..eaf3b2873eb --- /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 00000000000..158e2af6e23 --- /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 +#include // uint{8|16|32}_t +#include // memcpy() +#include + +#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 00000000000..2b4524b7631 --- /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 00000000000..138beb4b445 --- /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 00000000000..89209770234 --- /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 +#include + +#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 00000000000..f42a317f240 --- /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 00000000000..83e79738041 --- /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 +#include + +#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 00000000000..6e679074e0a --- /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 +#include +#include + +#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 00000000000..269d8ed77c6 --- /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 00000000000..7ee541c9d50 --- /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 +#include +#include + +#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 00000000000..476668f900b --- /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 +#include +#include + +#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 00000000000..0112f027024 --- /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 00000000000..7a0004f0b33 --- /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 00000000000..937900896b2 --- /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 + 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 FloatProperties; + typedef FPTypeProperties DoubleProperties; + typedef FPTypeProperties 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 00000000000..f5991030f39 --- /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 00000000000..6f68e478dee --- /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 +#include + +#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 00000000000..410af4e1b48 --- /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 00000000000..b869893d4f1 --- /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 +#include +#include +#include +#include + +#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(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(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 data; + data.setDim((size_t)cntdata); + data.zero(); + + class PointerBitmapVisitor : public Visitor + { + public: + PointerBitmapVisitor(Array* _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* 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(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(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(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(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("auto"))); + if (stc & STCreturn) + exps->push(new StringExp(e->loc, const_cast("return"))); + + if (stc & STCout) + exps->push(new StringExp(e->loc, const_cast("out"))); + else if (stc & STCref) + exps->push(new StringExp(e->loc, const_cast("ref"))); + else if (stc & STCin) + exps->push(new StringExp(e->loc, const_cast("in"))); + else if (stc & STClazy) + exps->push(new StringExp(e->loc, const_cast("lazy"))); + else if (stc & STCalias) + exps->push(new StringExp(e->loc, const_cast("alias"))); + + if (stc & STCconst) + exps->push(new StringExp(e->loc, const_cast("const"))); + if (stc & STCimmutable) + exps->push(new StringExp(e->loc, const_cast("immutable"))); + if (stc & STCwild) + exps->push(new StringExp(e->loc, const_cast("inout"))); + if (stc & STCshared) + exps->push(new StringExp(e->loc, const_cast("shared"))); + if (stc & STCscope && !(stc & STCscopeinferred)) + exps->push(new StringExp(e->loc, const_cast("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(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(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 00000000000..34e7da4e0d9 --- /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 00000000000..482782255d7 --- /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 + +#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 00000000000..f07340e95e0 --- /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 + +#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(c); + } + else if (c <= 0x07FF) + { + s[0] = static_cast(0xC0 | (c >> 6)); + s[1] = static_cast(0x80 | (c & 0x3F)); + } + else if (c <= 0xFFFF) + { + s[0] = static_cast(0xE0 | (c >> 12)); + s[1] = static_cast(0x80 | ((c >> 6) & 0x3F)); + s[2] = static_cast(0x80 | (c & 0x3F)); + } + else if (c <= 0x10FFFF) + { + s[0] = static_cast(0xF0 | (c >> 18)); + s[1] = static_cast(0x80 | ((c >> 12) & 0x3F)); + s[2] = static_cast(0x80 | ((c >> 6) & 0x3F)); + s[3] = static_cast(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(c); + } + else + { + s[0] = static_cast((((c - 0x010000) >> 10) & 0x03FF) + 0xD800); + s[1] = static_cast(((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 00000000000..154d39ad474 --- /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 + +/// 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 00000000000..e3ea8c19e50 --- /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 +#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 00000000000..6268822df19 --- /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 00000000000..ee0db983181 --- /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 + +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 00000000000..9a1aad42ddc --- /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 +. */ + +#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 *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 *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 % 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 % 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 *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 *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 *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 *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 *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 *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 *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 *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 00000000000..36d9c59b512 --- /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 00000000000..5a2f4eff6bb --- /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 +. */ + +#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 00000000000..e5546062274 --- /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 +. */ + +#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; */ + tree exp = build1 (VA_ARG_EXPR, type, ap); + + /* parmn = (T) VA_ARG_EXP; */ + 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 00000000000..c8ad81bd71a --- /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 +. */ + +/* 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 00000000000..479fccad4bf --- /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 +. */ + +/* 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 00000000000..892e65b24c1 --- /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 +; . + +; 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 Write D interface files to directory . + +Hf +D Joined Separate +-Hf Write D interface to . + +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 Write JSON output to the given . + +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= Compile in debug code, code <= , or code identified by . + +fdoc +D +Generate documentation. + +fdoc-dir= +D Joined RejectNegative +-fdoc-dir= Write documentation file to directory . + +fdoc-file= +D Joined RejectNegative +-fdoc-file= Write documentation to . + +fdoc-inc= +D Joined RejectNegative +-fdoc-inc= Include a Ddoc macro . + +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== use as source file for . + +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= Compile in version code >= or identified by . + +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 00000000000..89fc2b2df77 --- /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 +. */ + +#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 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 +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 00000000000..80573e1c2f2 --- /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 +. */ + +#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 *ctors; + vec *dtors; + vec *ctorgates; + + vec *sharedctors; + vec *shareddtors; + vec *sharedctorgates; + + vec *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 *static_ctor_list; +static GTY(()) vec *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 *functions, + vec *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 *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 *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 *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 *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 00000000000..7f1e9100a73 --- /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 +. */ + +#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 00000000000..e135bc3ec46 --- /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 +. */ + +/* 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 00000000000..0d78fa60aa5 --- /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 +. */ + +#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 (); + 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 (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 (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 (); + 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::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 (); + 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 *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 00000000000..0c2b695b09a --- /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 +. */ + +#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 *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 *elms = NULL; + + for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) + { + BaseClass *b = (*cd->vtblInterfaces)[i]; + ClassDeclaration *id = b->sym; + vec *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 *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 *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 *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 00000000000..d5eac2d7720 --- /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 +. */ + +#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 00000000000..0dd41eeaebe --- /dev/null +++ b/gcc/d/verstr.h @@ -0,0 +1 @@ +"2.076.1" diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi index a7af65b7549..7e772cf2300 100644 --- a/gcc/doc/contrib.texi +++ b/gcc/doc/contrib.texi @@ -138,6 +138,9 @@ Joerg Brunsmann for Java compiler hacking and help with the GCJ FAQ@. Joe Buck for his direction via the steering committee from its creation to 2013. +@item +Iain Buclaw for the D frontend. + @item Craig Burley for leadership of the G77 Fortran effort. diff --git a/gcc/doc/frontends.texi b/gcc/doc/frontends.texi index dbb83eed299..59654402aa1 100644 --- a/gcc/doc/frontends.texi +++ b/gcc/doc/frontends.texi @@ -9,6 +9,7 @@ @cindex GNU Compiler Collection @cindex GNU C Compiler @cindex Ada +@cindex D @cindex Fortran @cindex Go @cindex Objective-C @@ -16,7 +17,7 @@ GCC stands for ``GNU Compiler Collection''. GCC is an integrated distribution of compilers for several major programming languages. These languages currently include C, C++, Objective-C, Objective-C++, -Fortran, Ada, Go, and BRIG (HSAIL). +Fortran, Ada, D, Go, and BRIG (HSAIL). The abbreviation @dfn{GCC} has multiple meanings in common use. The current official meaning is ``GNU Compiler Collection'', which refers diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 069b71922d2..6c7dac99743 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -921,7 +921,7 @@ only for the listed packages. For other packages, only static libraries will be built. Package names currently recognized in the GCC tree are @samp{libgcc} (also known as @samp{gcc}), @samp{libstdc++} (not @samp{libstdc++-v3}), @samp{libffi}, @samp{zlib}, @samp{boehm-gc}, -@samp{ada}, @samp{libada}, @samp{libgo}, and @samp{libobjc}. +@samp{ada}, @samp{libada}, @samp{libgo}, @samp{libobjc}, and @samp{libphobos}. Note @samp{libiberty} does not support shared libraries at all. Use @option{--disable-shared} to build only static libraries. Note that @@ -1622,12 +1622,12 @@ their runtime libraries should be built. For a list of valid values for grep ^language= */config-lang.in @end smallexample Currently, you can use any of the following: -@code{all}, @code{default}, @code{ada}, @code{c}, @code{c++}, @code{fortran}, -@code{go}, @code{jit}, @code{lto}, @code{objc}, @code{obj-c++}. +@code{all}, @code{default}, @code{ada}, @code{c}, @code{c++}, @code{d}, +@code{fortran}, @code{go}, @code{jit}, @code{lto}, @code{objc}, @code{obj-c++}. Building the Ada compiler has special requirements, see below. If you do not pass this flag, or specify the option @code{default}, then the default languages available in the @file{gcc} sub-tree will be configured. -Ada, Go, Jit, and Objective-C++ are not default languages. LTO is not a +Ada, D, Go, Jit, and Objective-C++ are not default languages. LTO is not a default language, but is built by default because @option{--enable-lto} is enabled by default. The other languages are default languages. If @code{all} is specified, then all available languages are built. An @@ -2771,7 +2771,7 @@ on a simulator as described at @uref{http://gcc.gnu.org/simtest-howto.html}. In order to run sets of tests selectively, there are targets @samp{make check-gcc} and language specific @samp{make check-c}, -@samp{make check-c++}, @samp{make check-fortran}, +@samp{make check-c++}, @samp{make check-d} @samp{make check-fortran}, @samp{make check-ada}, @samp{make check-objc}, @samp{make check-obj-c++}, @samp{make check-lto} in the @file{gcc} subdirectory of the object directory. You can also diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 57491f1033c..055e8c4759c 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1439,6 +1439,15 @@ Go source code. @item @var{file}.brig BRIG files (binary representation of HSAIL). +@item @var{file}.d +D source code. + +@item @var{file}.di +D interface file. + +@item @var{file}.dd +D documentation code (Ddoc). + @item @var{file}.ads Ada source code file that contains a library unit declaration (a declaration of a package, subprogram, or generic, or a generic @@ -1482,6 +1491,7 @@ objective-c objective-c-header objective-c-cpp-output objective-c++ objective-c++-header objective-c++-cpp-output assembler assembler-with-cpp ada +d f77 f77-cpp-input f95 f95-cpp-input go brig diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 89157079ffb..748797762d2 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -106,6 +106,10 @@ The Objective-C and Objective-C++ runtime library. @item libquadmath The runtime support library for quad-precision math operations. +@item libphobos +The D standard and runtime library. The bulk of this library is mirrored +from the @uref{https://github.com/@/dlang, master D repositories}. + @item libssp The Stack protector runtime library. diff --git a/gcc/doc/standards.texi b/gcc/doc/standards.texi index 26350cc9265..4c1e2dad115 100644 --- a/gcc/doc/standards.texi +++ b/gcc/doc/standards.texi @@ -320,6 +320,12 @@ capability is typically utilized to implement the HSA runtime API's HSAIL finalization extension for a gcc supported processor. HSA standards are freely available at @uref{http://www.hsafoundation.com/standards/}. +@section D language + +GCC supports the D 2.0 programming language. The D language itself is +currently defined by its reference implementation and supporting language +specification, described at @uref{https://dlang.org/spec/spec.html}. + @section References for Other Languages @xref{Top, GNAT Reference Manual, About This Guide, gnat_rm, diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 0fcf8069b8c..f841527f971 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -52,6 +52,7 @@ through the macros defined in the @file{.h} file. * MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * PCH Target:: Validity checking for precompiled headers. * C++ ABI:: Controlling C++ ABI changes. +* D Language and ABI:: Controlling D ABI changes. * Named Address Spaces:: Adding support for named address spaces * Misc:: Everything else. @end menu @@ -106,6 +107,14 @@ documented as ``Common Target Hook''. This is declared in @code{target_has_targetm_common=yes} in @file{config.gcc}; otherwise a default definition is used. +Similarly, there is a @code{targetdm} variable for hooks that are +specific to the D language front end, documented as ``D Target Hook''. +This is declared in @file{d/d-target.h}, the initializer +@code{TARGETDM_INITIALIZER} in @file{d/d-target-def.h}. If targets +initialize @code{targetdm} themselves, they should set +@code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default +definition is used. + @node Driver @section Controlling the Compilation Driver, @file{gcc} @cindex driver @@ -10667,6 +10676,29 @@ unloaded. The default is to return false. Return target-specific mangling context of @var{decl} or @code{NULL_TREE}. @end deftypefn +@node D Language and ABI +@section D ABI parameters +@cindex parameters, d abi + +@deftypefn {D Target Hook} void TARGET_D_CPU_VERSIONS (void) +Declare all environmental version identifiers relating to the target CPU +using the function @code{builtin_version}, which takes a string representing +the name of the version. Version identifiers predefined by this hook apply +to all modules that are being compiled and imported. +@end deftypefn + +@deftypefn {D Target Hook} void TARGET_D_OS_VERSIONS (void) +Similarly to @code{TARGET_D_CPU_VERSIONS}, but is used for versions +relating to the target operating system. +@end deftypefn + +@deftypefn {D Target Hook} unsigned TARGET_D_CRITSEC_SIZE (void) +Returns the size of the data structure used by the target operating system +for critical sections and monitors. For example, on Microsoft Windows this +would return the @code{sizeof(CRITICAL_SECTION)}, while other platforms that +implement pthreads would return @code{sizeof(pthread_mutex_t)}. +@end deftypefn + @node Named Address Spaces @section Adding support for named address spaces @cindex named address spaces diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 63b0c0a98aa..967ef3ad22f 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -52,6 +52,7 @@ through the macros defined in the @file{.h} file. * MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * PCH Target:: Validity checking for precompiled headers. * C++ ABI:: Controlling C++ ABI changes. +* D Language and ABI:: Controlling D ABI changes. * Named Address Spaces:: Adding support for named address spaces * Misc:: Everything else. @end menu @@ -106,6 +107,14 @@ documented as ``Common Target Hook''. This is declared in @code{target_has_targetm_common=yes} in @file{config.gcc}; otherwise a default definition is used. +Similarly, there is a @code{targetdm} variable for hooks that are +specific to the D language front end, documented as ``D Target Hook''. +This is declared in @file{d/d-target.h}, the initializer +@code{TARGETDM_INITIALIZER} in @file{d/d-target-def.h}. If targets +initialize @code{targetdm} themselves, they should set +@code{target_has_targetdm=yes} in @file{config.gcc}; otherwise a default +definition is used. + @node Driver @section Controlling the Compilation Driver, @file{gcc} @cindex driver @@ -7310,6 +7319,16 @@ floating-point support; they are not included in this mechanism. @hook TARGET_CXX_DECL_MANGLING_CONTEXT +@node D Language and ABI +@section D ABI parameters +@cindex parameters, d abi + +@hook TARGET_D_CPU_VERSIONS + +@hook TARGET_D_OS_VERSIONS + +@hook TARGET_D_CRITSEC_SIZE + @node Named Address Spaces @section Adding support for named address spaces @cindex named address spaces diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 42eab9e0f66..30bbfee9052 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -5437,6 +5437,16 @@ is_ada (void) return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83; } +/* Return TRUE if the language is D. */ + +static inline bool +is_dlang (void) +{ + unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language); + + return lang == DW_LANG_D; +} + /* Remove the specified attribute if present. Return TRUE if removal was successful. */ @@ -24450,6 +24460,8 @@ gen_compile_unit_die (const char *filename) language = DW_LANG_ObjC; else if (strcmp (language_string, "GNU Objective-C++") == 0) language = DW_LANG_ObjC_plus_plus; + else if (strcmp (language_string, "GNU D") == 0) + language = DW_LANG_D; else if (dwarf_version >= 5 || !dwarf_strict) { if (strcmp (language_string, "GNU Go") == 0) @@ -26034,7 +26046,7 @@ declare_in_namespace (tree thing, dw_die_ref context_die) if (ns_context != context_die) { - if (is_fortran ()) + if (is_fortran () || is_dlang ()) return ns_context; if (DECL_P (thing)) gen_decl_die (thing, NULL, NULL, ns_context); @@ -26057,7 +26069,7 @@ gen_namespace_die (tree decl, dw_die_ref context_die) { /* Output a real namespace or module. */ context_die = setup_namespace_context (decl, comp_unit_die ()); - namespace_die = new_die (is_fortran () + namespace_die = new_die (is_fortran () || is_dlang () ? DW_TAG_module : DW_TAG_namespace, context_die, decl); /* For Fortran modules defined in different CU don't add src coords. */ @@ -26123,7 +26135,7 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx, break; case CONST_DECL: - if (!is_fortran () && !is_ada ()) + if (!is_fortran () && !is_ada () && !is_dlang ()) { /* The individual enumerators of an enum type get output when we output the Dwarf representation of the relevant enum type itself. */ @@ -26723,7 +26735,7 @@ dwarf2out_decl (tree decl) case CONST_DECL: if (debug_info_level <= DINFO_LEVEL_TERSE) return; - if (!is_fortran () && !is_ada ()) + if (!is_fortran () && !is_ada () && !is_dlang ()) return; if (TREE_STATIC (decl) && decl_function_context (decl)) context_die = lookup_decl_die (DECL_CONTEXT (decl)); @@ -29126,6 +29138,7 @@ prune_unused_types_walk_local_classes (dw_die_ref die) case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: + case DW_TAG_interface_type: break; case DW_TAG_subprogram: @@ -29159,6 +29172,7 @@ prune_unused_types_walk (dw_die_ref die) case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: + case DW_TAG_interface_type: if (die->die_perennial_p) break; @@ -29185,7 +29199,6 @@ prune_unused_types_walk (dw_die_ref die) case DW_TAG_volatile_type: case DW_TAG_typedef: case DW_TAG_array_type: - case DW_TAG_interface_type: case DW_TAG_friend: case DW_TAG_enumeration_type: case DW_TAG_subroutine_type: diff --git a/gcc/gcc.c b/gcc/gcc.c index 264204d7b37..c0d17eb4f1b 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -1305,6 +1305,7 @@ static const struct compiler default_compilers[] = {".f08", "#Fortran", 0, 0, 0}, {".F08", "#Fortran", 0, 0, 0}, {".r", "#Ratfor", 0, 0, 0}, {".go", "#Go", 0, 1, 0}, + {".d", "#D", 0, 1, 0}, {".dd", "#D", 0, 1, 0}, {".di", "#D", 0, 1, 0}, /* Next come the entries for C. */ {".c", "@c", 0, 0, 1}, {"@c", diff --git a/gcc/genhooks.c b/gcc/genhooks.c index 70f19a16b8a..9b6ab05507c 100644 --- a/gcc/genhooks.c +++ b/gcc/genhooks.c @@ -34,6 +34,7 @@ static struct hook_desc hook_array[] = { #include "target.def" #include "c-family/c-target.def" #include "common/common-target.def" +#include "d/d-target.def" #undef DEFHOOK }; diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog index c53054565cb..868b164da63 100644 --- a/gcc/po/ChangeLog +++ b/gcc/po/ChangeLog @@ -1,3 +1,7 @@ +2018-10-28 Iain Buclaw + + * EXCLUDES: Add sources from d/dmd. + 2018-10-17 Joseph Myers * es.po: Update. diff --git a/gcc/po/EXCLUDES b/gcc/po/EXCLUDES index 50274233cf0..dbcfb341bc5 100644 --- a/gcc/po/EXCLUDES +++ b/gcc/po/EXCLUDES @@ -53,3 +53,43 @@ genrecog.c gensupport.c gensupport.h read-md.c + +# These files are part of the front end to D, and have no i18n support. +d/dmd/arrayop.c +d/dmd/attrib.c +d/dmd/canthrow.c +d/dmd/cond.c +d/dmd/constfold.c +d/dmd/cppmangle.c +d/dmd/ctfeexpr.c +d/dmd/dcast.c +d/dmd/dclass.c +d/dmd/declaration.c +d/dmd/denum.c +d/dmd/dimport.c +d/dmd/dinterpret.c +d/dmd/dmangle.c +d/dmd/dmodule.c +d/dmd/doc.c +d/dmd/dscope.c +d/dmd/dstruct.c +d/dmd/dsymbol.c +d/dmd/dtemplate.c +d/dmd/dversion.c +d/dmd/expression.c +d/dmd/func.c +d/dmd/init.c +d/dmd/inline.c +d/dmd/lexer.c +d/dmd/mtype.c +d/dmd/nogc.c +d/dmd/nspace.c +d/dmd/objc.c +d/dmd/opover.c +d/dmd/optimize.c +d/dmd/parse.c +d/dmd/sideeffect.c +d/dmd/statement.c +d/dmd/statementsem.c +d/dmd/staticassert.c +d/dmd/traits.c diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5188d9bf62a..e49edfb2328 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,39 @@ +2018-10-28 Iain Buclaw + + * 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. + 2017-10-28 Thomas Koenig PR fortran/54613 diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp index 3219bed9121..f40cfabb41e 100644 --- a/gcc/testsuite/gcc.misc-tests/help.exp +++ b/gcc/testsuite/gcc.misc-tests/help.exp @@ -115,7 +115,7 @@ check_for_options c "--help=joined,undocumented" "" "" "" # subsystem. Do this one help class at a time to make it easier to # find the source a failure. -foreach cls { "ada" "c" "c++" "fortran" "go" \ +foreach cls { "ada" "c" "c++" "d" "fortran" "go" \ "optimizers" "param" "target" "warnings" } { check_for_options c "--help=$cls" "" "^ +-.*\[^:.\]$" "" diff --git a/gcc/testsuite/gdc.dg/asan/asan.exp b/gcc/testsuite/gdc.dg/asan/asan.exp new file mode 100644 index 00000000000..bc7c25c7076 --- /dev/null +++ b/gcc/testsuite/gdc.dg/asan/asan.exp @@ -0,0 +1,32 @@ +# 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Load support procs. +load_lib gdc-dg.exp +load_lib asan-dg.exp + +# Initialize `dg'. +dg-init +asan_init + +# Main loop. +if [check_effective_target_fsanitize_address] { + gdc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.d]] "" "" +} + +# All done. +asan_finish +dg-finish diff --git a/gcc/testsuite/gdc.dg/asan/gdc272.d b/gcc/testsuite/gdc.dg/asan/gdc272.d new file mode 100644 index 00000000000..bc511fefb14 --- /dev/null +++ b/gcc/testsuite/gdc.dg/asan/gdc272.d @@ -0,0 +1,15 @@ +/* { dg-options "-fsanitize=address" } */ +/* { dg-do compile } */ + +module asantests; + + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=272 + +extern(C) void my_memcmp(const(void) *s1, const(void) *s2); + +void bug(const(char)* p) +{ + my_memcmp(p, "__FILE__".ptr); +} diff --git a/gcc/testsuite/gdc.dg/compilable.d b/gcc/testsuite/gdc.dg/compilable.d new file mode 100644 index 00000000000..44fc5b5fdfb --- /dev/null +++ b/gcc/testsuite/gdc.dg/compilable.d @@ -0,0 +1,444 @@ +// { dg-options "-I $srcdir/gdc.dg -I $srcdir/gdc.dg/imports" } +// { dg-additional-sources "imports/gdc27.d imports/gdc231.d" } +// { dg-do compile } + +import core.simd; +import gcc.attribute; + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=27 + +import imports.gdc27; + +interface I_B : I_A +{ + void b(); +} + +abstract class C_B : C_A, I_B +{ + abstract void b(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=108 + +@attribute("forceinline") +void forceinline108() +{ +} + +@attribute("noinline") +void noinline108() +{ +} + +@attribute("flatten") +void flatten108() +{ +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=170 + +import imports.gdc170; + +void test170() +{ + foo!void.foo1!void(); + foo!void.foo2!void(); + foo!void.foo3(); + foo!void.foo3!void(); + foo!void.foo4(); + foo!void.foo4!void(); + foo!void.foo5!void(null); + foo!void.foo6!void(null); + foo!void.foo7(null); + foo!void.foo7!void(null); + foo!void.foo8(null); + foo!void.foo8!void(null); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=212 + +template hasElaborateAssign212(S) +{ + enum hasElaborateAssign212 = is(typeof(S.init.opAssign(rvalueOf212!S))) || + is(typeof(lvalueOf212!S)) ; +} + +T rvalueOf212(T)(); + +T lvalueOf212(T)(); + + +template TypeTuple212(TList...) +{ + alias TypeTuple212 = TList; +} + +template Tuple212() +{ + struct Tuple212 + { + void opAssign(R)(R) + { + if (hasElaborateAssign212!R) + { + } + } + } +} + +ref emplaceRef212() +{ + static if (!hasElaborateAssign212!(Tuple212!())) + chunk; +} + +class TaskPool212 +{ + void reduce() + { + Tuple212!() seed = void; + Tuple212!()[] results; + foreach(i; TypeTuple212!(0, 1)) + results[i] = seed; + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=213 + +struct S213 +{ + int4 vec; +} + +void test213() +{ + S213 s, b; + + assert(s == b); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=218 + +struct S218a +{ + this(int* pdata_) + { + pdata = pdata_; + } + + void opIndexAssign(int, size_t) { } + int* pdata; +}; + +struct S218 +{ + S218a getS218a() + { + return S218a(data.ptr); + } + + int[] data; + int[] tab2; +}; + +S218 f() +{ + S218 r; + + for(int i = 0; i < 1; ++i) + r.getS218a()[0] = 0; + + return r; +} + +S218 var; + +static this() +{ + var = f(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=223 + +struct S223 +{ + long[8] field; +} + +class C223 +{ + long[8] field; +} + +S223 test223_1(); +real test223_2(); +string[long[8]] test223_3(); +C223 test223_4(); +long test223_5(); +long[] test223_6(); +long[8] test223_7(); +C223[8] test223_8(); +void delegate() test223_9(); + +bool test223() +{ + return test223_1() == test223_1() && + test223_1() is test223_1() && + test223_2() == test223_2() && + test223_2() is test223_2() && + test223_3() == test223_3() && + test223_3() is test223_3() && + test223_4() == test223_4() && + test223_4() is test223_4() && + test223_5() == test223_5() && + test223_5() is test223_5() && + test223_6() == test223_6() && + test223_6() is test223_6() && + test223_7() == test223_7() && + test223_7() is test223_7() && + test223_8() == test223_8() && + test223_8() is test223_8() && + test223_9() == test223_9() && + test223_9() is test223_9(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=231 + +import imports.gdc231; + +class Range231 : Widget231 +{ + override void* getStruct() + { + return null; + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=239 + +import imports.gdc239; + +class C239 +{ + C239a *foo; +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=240 + +interface I204 +{ + void f(); +} + +class C204 : I204 +{ + void f(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=241 + +import imports.gdc241a; +import imports.gdc241b : S241, C241, E241, N241; + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=242 + +struct S242a +{ + enum M = S242a(); + void iter() { } +} + +void test242a() +{ + return S242a.M.iter; +} + +struct S242b +{ + enum M = S242b(); + void iter() { } +} + +void test242b() +{ + S242b.M.iter; +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=251 + +import imports.gdc251a; +import imports.gdc251b : C251; + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=253 + +import imports.gdc253; + +class C253 : C253a +{ + void test253() { } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=255 + +class C255 +{ + void f2() + { + class C1 + { + void f1() + { + void f0() + { + class C0 + { + void test255() + { + f2(); + } + } + } + } + } + } +} + +class C255a +{ + void f3() + { + class C1 + { + void f2() + { + void f1() + { + void f0() + { + class C0 + { + void test255a() + { + f3(); + } + } + } + } + } + } + } +} + +class C255b +{ + void f4() + { + class C2 + { + void f3() + { + void f2() + { + class C1 + { + void f1() + { + void f0() + { + class C0 + { + void test255b() + { + f4(); + } + } + } + } + } + } + } + } + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=256 + +import imports.gdcpkg256 : gdc256; + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=261 + +void test261() +{ + class C1 + { + void f1() + { + class C2 + { + void f2() + { + auto v = &f1; + } + } + } + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=280 + +struct RBNode280 +{ + RBNode280* _parent; + + @property left(RBNode280*) + { + _parent = &this; + } +} + +class RedBlackTree280 +{ + RBNode280* _end; + RBNode280* _begin; + + this(int[] elems...) + { + _end = new RBNode280; + + foreach (e; elems) + { + _end.left = _begin; + } + } +} + +__gshared s = new RedBlackTree280('h'); + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=284 + +alias v284 = __vector(int[2]); + +v284 test284(v284 a, ...) +{ + return a + a; +} diff --git a/gcc/testsuite/gdc.dg/dg.exp b/gcc/testsuite/gdc.dg/dg.exp new file mode 100644 index 00000000000..d05258e898a --- /dev/null +++ b/gcc/testsuite/gdc.dg/dg.exp @@ -0,0 +1,50 @@ +# 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gdc-dg.exp + +# The default option list can be overridden by +# TORTURE_OPTIONS="{ { list1 } ... { listN } }" + +if ![info exists TORTURE_OPTIONS] { + set TORTURE_OPTIONS [list \ + { -O0 } { -O1 } { -O2 } { -O3 } { -Os } \ + { -O0 -frelease } { -O0 -g } { -O0 -frelease -g } \ + { -O1 -frelease } { -O1 -g } { -O1 -frelease -g } \ + { -O2 -frelease } { -O2 -g } { -O2 -frelease -g } \ + { -O3 -frelease } { -O3 -g } { -O3 -frelease -g } \ + { -Os -frelease } { -Os -g } { -Os -frelease -g }] +} + +# Initialize `dg'. +dg-init + +# Initialize use of torture lists. +torture-init +set-torture-options $TORTURE_OPTIONS + +# Main loop. +gdc-dg-runtest [lsort \ + [glob -nocomplain $srcdir/$subdir/*.d ] ] "" "" + +# Finalize use of torture lists. +torture-finish + +# All done. +dg-finish diff --git a/gcc/testsuite/gdc.dg/gdc254.d b/gcc/testsuite/gdc.dg/gdc254.d new file mode 100644 index 00000000000..c0f6e560f50 --- /dev/null +++ b/gcc/testsuite/gdc.dg/gdc254.d @@ -0,0 +1,15 @@ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=254 +// { dg-options "-I $srcdir/gdc.dg" } +// { dg-shouldfail "interface function is not implemented" } +// { dg-do compile } + +import imports.gdc254a; + +interface A254 +{ + void F(); +} + +class C254 : B254, A254 // { dg-error "interface function '\[^\n\r]*' is not implemented" } +{ +} diff --git a/gcc/testsuite/gdc.dg/gdc260.d b/gcc/testsuite/gdc.dg/gdc260.d new file mode 100644 index 00000000000..4869796135a --- /dev/null +++ b/gcc/testsuite/gdc.dg/gdc260.d @@ -0,0 +1,10 @@ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=260 +// { dg-options "-Wall -Werror" } +// { dg-do compile } + +import gcc.builtins; + +char *bug260(char *buffer) +{ + return __builtin_strcat(&buffer[0], "Li"); +} diff --git a/gcc/testsuite/gdc.dg/gdc270a.d b/gcc/testsuite/gdc.dg/gdc270a.d new file mode 100644 index 00000000000..4df6f02f753 --- /dev/null +++ b/gcc/testsuite/gdc.dg/gdc270a.d @@ -0,0 +1,11 @@ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=270 +// { dg-do compile } + +module gdc270; + +void foo() +{ +} + +/* { dg-final { scan-assembler "_GLOBAL__D_6gdc270" } } */ +/* { dg-final { scan-assembler "_GLOBAL__I_6gdc270" } } */ diff --git a/gcc/testsuite/gdc.dg/gdc270b.d b/gcc/testsuite/gdc.dg/gdc270b.d new file mode 100644 index 00000000000..5a544c58693 --- /dev/null +++ b/gcc/testsuite/gdc.dg/gdc270b.d @@ -0,0 +1,7 @@ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=270 +// { dg-do compile } + +module gdc270; + +/* { dg-final { scan-assembler "_GLOBAL__D_6gdc270" } } */ +/* { dg-final { scan-assembler "_GLOBAL__I_6gdc270" } } */ diff --git a/gcc/testsuite/gdc.dg/gdc282.d b/gcc/testsuite/gdc.dg/gdc282.d new file mode 100644 index 00000000000..ce840501d64 --- /dev/null +++ b/gcc/testsuite/gdc.dg/gdc282.d @@ -0,0 +1,48 @@ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=282 +// { dg-shouldfail "conflicting methods in class" } +// { dg-do compile } + +class C282a +{ + void fun() + { + } + + void f282() + { + } + + void f282() // { dg-error "conflicts with gdc282.C282a.f282" } + { + } +} + +class C282b +{ + struct S282b + { + } + + void f282() + { + } + + void f282() // { dg-error "conflicts with gdc282.C282b.f282" } + { + } +} + +class C282c +{ + class C282c + { + } + + void f282() + { + } + + void f282() // { dg-error "conflicts with gdc282.C282c.f282" } + { + } +} diff --git a/gcc/testsuite/gdc.dg/gdc283.d b/gcc/testsuite/gdc.dg/gdc283.d new file mode 100644 index 00000000000..ca7ad3ff3f5 --- /dev/null +++ b/gcc/testsuite/gdc.dg/gdc283.d @@ -0,0 +1,102 @@ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=283 +// { dg-do run { target hw } } + +struct Impl +{ + size_t _count; +} + +struct RefCountedStore +{ + Impl* _store; + + void initialize() + { + import core.stdc.stdlib : malloc; + _store = cast(Impl*) malloc(Impl.sizeof); + _store._count = 1; + } + + bool isInitialized() + { + return _store !is null; + } + + void ensureInitialized() + { + if (!isInitialized) + initialize(); + } +} + +struct RefCounted14443 +{ + RefCountedStore _refCounted; + + this(int) + { + _refCounted.initialize(); + } + + this(this) + { + ++_refCounted._store._count; + } + + ~this() + { + if (--_refCounted._store._count) + return; + + import core.stdc.stdlib : free; + free(_refCounted._store); + _refCounted._store = null; + } + + int refCountedPayload() + { + _refCounted.ensureInitialized(); + return 1; + } +} + +struct PathRange14443 +{ + RefCounted14443 path; + + @property PathElement14443 front() + { + return PathElement14443(this, path.refCountedPayload()); + } +} + +struct PathElement14443 +{ + PathRange14443 range; + + this(PathRange14443 range, int) + { + this.range = range; + } +} + +void main() +{ + auto path = RefCounted14443(12); + if (path._refCounted._store._count != 1) + assert(0); + { + auto _r = PathRange14443(path); + if (path._refCounted._store._count != 2) + assert(0); + { + auto element = _r.front; + if (path._refCounted._store._count != 3) + assert(0); + } + if (path._refCounted._store._count != 2) + assert(0); + } + if (path._refCounted._store._count != 1) + assert(0); +} diff --git a/gcc/testsuite/gdc.dg/imports/gdc170.d b/gcc/testsuite/gdc.dg/imports/gdc170.d new file mode 100644 index 00000000000..f9fea1f483c --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc170.d @@ -0,0 +1,18 @@ +module imports.gdc170; + +class bar(T) +{ + void undefined_reference() {} +} + +template foo(T) +{ + bar!T foo1(T2)() if (true) body { return null; } + bar!T foo2(T2)() { return null; } + bar!T foo3(T2 = void)() if (true) body { return null; } + bar!T foo4(T2 = void)() { return null; } + void foo5(T2)(bar!T x) if (true) body {} + void foo6(T2)(bar!T x) {} + void foo7(T2 = void)(bar!T x) if (true) body {} + void foo8(T2 = void)(bar!T x) {} +} diff --git a/gcc/testsuite/gdc.dg/imports/gdc231.d b/gcc/testsuite/gdc.dg/imports/gdc231.d new file mode 100644 index 00000000000..b398e0fcd00 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc231.d @@ -0,0 +1,24 @@ +module imports.gdc231; + +interface ImplementorIF +{ + void* getImplementorStruct(); + void* getStruct(); +} + +template ImplementorT() +{ + void* getImplementorStruct() + { + return null; + } +} + +class Widget231 : ImplementorIF +{ + mixin ImplementorT; + void* getStruct() + { + return null; + } +} diff --git a/gcc/testsuite/gdc.dg/imports/gdc239.d b/gcc/testsuite/gdc.dg/imports/gdc239.d new file mode 100644 index 00000000000..3378d74bd9b --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc239.d @@ -0,0 +1,9 @@ +import std.path : buildNormalizedPath; + +class C239a +{ + auto bar() + { + auto path = buildNormalizedPath("/", "foo"); + } +} diff --git a/gcc/testsuite/gdc.dg/imports/gdc241a.d b/gcc/testsuite/gdc.dg/imports/gdc241a.d new file mode 100644 index 00000000000..28ba8ebe8ee --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc241a.d @@ -0,0 +1,6 @@ +import compilable; + +S241 *s241; // Use indirectly imported struct +C241 *c241; // Use indirectly imported class +E241 *e241; // Use indirectly imported enum +N241.T *n241; // Use indirectly imported namespace diff --git a/gcc/testsuite/gdc.dg/imports/gdc241b.d b/gcc/testsuite/gdc.dg/imports/gdc241b.d new file mode 100644 index 00000000000..3632575ba0d --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc241b.d @@ -0,0 +1,8 @@ + +class C241 { } + +enum E241 { a } + +struct S241 { } + +extern(C++, N241) { struct T { } } diff --git a/gcc/testsuite/gdc.dg/imports/gdc251a.d b/gcc/testsuite/gdc.dg/imports/gdc251a.d new file mode 100644 index 00000000000..5c2d4d58769 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc251a.d @@ -0,0 +1,6 @@ +module imports.gdc251a; + +import imports.gdc251b; +import compilable; + +C251 config; diff --git a/gcc/testsuite/gdc.dg/imports/gdc251b.d b/gcc/testsuite/gdc.dg/imports/gdc251b.d new file mode 100644 index 00000000000..e70823f1ed6 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc251b.d @@ -0,0 +1,3 @@ +module imports.gdc251b; + +class C251 { } diff --git a/gcc/testsuite/gdc.dg/imports/gdc253.d b/gcc/testsuite/gdc.dg/imports/gdc253.d new file mode 100644 index 00000000000..66492621210 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc253.d @@ -0,0 +1,23 @@ +module imports.gdc253; + +interface I253a +{ +} + +interface I253b +{ + size_t printf(...); + void flush(); +} + +class C253a : I253a , I253b +{ + size_t printf(...) + { + return 0; + } + + void flush() + { + } +} diff --git a/gcc/testsuite/gdc.dg/imports/gdc254a.d b/gcc/testsuite/gdc.dg/imports/gdc254a.d new file mode 100644 index 00000000000..2a2a50d2f06 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc254a.d @@ -0,0 +1,10 @@ +module imports.gdc254a; + +class B254 +{ + void F() + { + if (Error) return; + } + +} diff --git a/gcc/testsuite/gdc.dg/imports/gdc256.d b/gcc/testsuite/gdc.dg/imports/gdc256.d new file mode 100644 index 00000000000..1b405996b4b --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc256.d @@ -0,0 +1 @@ +module gdc256; diff --git a/gcc/testsuite/gdc.dg/imports/gdc27.d b/gcc/testsuite/gdc.dg/imports/gdc27.d new file mode 100644 index 00000000000..fcaa2ab3ca8 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdc27.d @@ -0,0 +1,14 @@ +module imports.gdc27; + +interface I_A +{ + bool a(); +} + +class C_A : I_A +{ + bool a() + { + return false; + } +} diff --git a/gcc/testsuite/gdc.dg/imports/gdcpkg256/package.d b/gcc/testsuite/gdc.dg/imports/gdcpkg256/package.d new file mode 100644 index 00000000000..edee28901db --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/gdcpkg256/package.d @@ -0,0 +1,3 @@ +module imports.gdcpkg256; + +public import gdc256; diff --git a/gcc/testsuite/gdc.dg/imports/runnable.d b/gcc/testsuite/gdc.dg/imports/runnable.d new file mode 100644 index 00000000000..f28ccdf5b65 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/runnable.d @@ -0,0 +1,23 @@ +module imports.runnable; + +private import runnable; + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=36 + +void test36d_1() +{ + auto parser = Parser!(char[])(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=253 + +class B253 : A253 +{ + void test253(int[int] a) + { + if (a.get(0, 1)) + return; + } +} diff --git a/gcc/testsuite/gdc.dg/link.d b/gcc/testsuite/gdc.dg/link.d new file mode 100644 index 00000000000..a8e1da15511 --- /dev/null +++ b/gcc/testsuite/gdc.dg/link.d @@ -0,0 +1,39 @@ +// { dg-do link { target arm*-*-* i?86-*-* x86_64-*-* } } + +/******************************************/ + +class C1() +{ + static struct S1 { A1 a; } +} + +enum E1 = is(C1!()); + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=300 + +struct S300(Range) +{ + double test(size_t remaining) + { + double r; + return r ^^ remaining; + } +} + +auto link300a(Range)(Range) +{ + return S300!(Range)(); +} + +void link300() +{ + struct I {} + static assert(is(typeof(link300a(I())) == struct)); + auto sample = link300a(I()); + sample.test(5); +} + +/******************************************/ + +void main() {} diff --git a/gcc/testsuite/gdc.dg/lto/lto.exp b/gcc/testsuite/gdc.dg/lto/lto.exp new file mode 100644 index 00000000000..1fed9cdd2ce --- /dev/null +++ b/gcc/testsuite/gdc.dg/lto/lto.exp @@ -0,0 +1,56 @@ +# 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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Test link-time optimization across multiple files. +# +# Programs are broken into multiple files. Each one is compiled +# separately with LTO information. The final executable is generated +# by collecting all the generated object files using regular LTO or WHOPR. + +if $tracelevel then { + strace $tracelevel +} + +# Load procedures from common libraries. +load_lib standard.exp +load_lib gdc-dg.exp + +# Load the language-independent compabibility support procedures. +load_lib lto.exp + +# If LTO has not been enabled, bail. +if { ![check_effective_target_lto] } { + return +} + +lto_init no-mathlib + +# Define an identifier for use with this suite to avoid name conflicts +# with other lto tests running at the same time. +set sid "d_lto" + +# Main loop. +foreach src [lsort [find $srcdir/$subdir *_0.d]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $src] then { + continue + } + + lto-execute $src $sid +} + +lto_finish + diff --git a/gcc/testsuite/gdc.dg/lto/ltotests_0.d b/gcc/testsuite/gdc.dg/lto/ltotests_0.d new file mode 100644 index 00000000000..bb18beaa9c8 --- /dev/null +++ b/gcc/testsuite/gdc.dg/lto/ltotests_0.d @@ -0,0 +1,90 @@ +// { dg-lto-do link } +module ltotests_0; + +import core.stdc.stdio; + + +/******************************************/ + +interface I284 +{ + void m284(); +} + +class C284 : I284 +{ + void m284() { } +} + +/******************************************/ + +class C304 +{ +} + +C304 c304; + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=61 + +struct S61a +{ + void a() { } + void b() { } +} + +struct S61b +{ + S61a other; + + void foo() + { + bar(); + } + + void bar() + { + try + other.a(); + catch + other.b(); + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=88 + +extern(C) int test88a(); + +void test88() +{ + test88a(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=252 + +class C252 +{ + struct S252 + { + int i; + ubyte u; + } + S252 s; +} + +void test252() +{ + C252 c = new C252(); +} + +/******************************************/ + +void main(string[]) +{ + test88(); + test252(); + + printf("Success!\n"); +} diff --git a/gcc/testsuite/gdc.dg/lto/ltotests_1.d b/gcc/testsuite/gdc.dg/lto/ltotests_1.d new file mode 100644 index 00000000000..3111f9add96 --- /dev/null +++ b/gcc/testsuite/gdc.dg/lto/ltotests_1.d @@ -0,0 +1,9 @@ +module ltotests_1; + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=88 + +extern(C) int test88a() +{ + return 0; +} diff --git a/gcc/testsuite/gdc.dg/runnable.d b/gcc/testsuite/gdc.dg/runnable.d new file mode 100644 index 00000000000..4f1ef76e4cb --- /dev/null +++ b/gcc/testsuite/gdc.dg/runnable.d @@ -0,0 +1,1575 @@ +// { dg-additional-sources "imports/runnable.d" } +// { dg-do run { target hw } } + +module runnable; + +import imports.runnable; +import core.stdc.stdio; +import gcc.attribute; + + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=2 + +struct S +{ + string toString() { return "foo"; } +} + +void test2() +{ + import std.string : format; + assert(format("%s", S()) == "foo"); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=4 + +void test4() +{ + string str = "allo"; + static assert(!__traits(compiles, str.reverse)); + static assert(!__traits(compiles, str.sort)); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=15 + +class B +{ + class A { } + A a; +} + +class C +{ + void visit(B b) + { + import std.algorithm : map; + auto as = [b.a]; + as.map!(d => d); + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=16 + +void test16() +{ + import std.parallelism : taskPool; + + taskPool.reduce!"a+b"([0, 1, 2, 3]); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=17 + +/** + * Parameters are not copied into a frame to be accessed from + * the method's __require function. + */ +void contractTest(string path) +{ + assert(path[0] == 't'); + assert(path.length == 9); + assert(path[8] == 'i'); +} + +interface ModuleSaver +{ + void save(string str) + in + { + contractTest(str); + } +} + +class ModuleWriter : ModuleSaver +{ + void save (string str) + in {} + body + { + } +} + +void test17() +{ + (new ModuleWriter()).save ("test.0.mci"); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=18 + +class C18 +{ + struct Link + { + int x; + int y; + } + + void sort_links() + { + import std.algorithm : sort; + import std.array : empty; + import std.exception : enforce; + + enforce(!_link.empty); + + bool lt(Link a, Link b) + { + if(a.x > b.x) + return false; + if(a.x < b.x) + return true; + if(a.y >= b.y) + return false; + else + return true; + } + sort!(lt)(_link); + } + + this() + { + _link ~= Link(8, 3); + _link ~= Link(4, 7); + _link ~= Link(4, 6); + _link ~= Link(3, 7); + _link ~= Link(2, 7); + _link ~= Link(2, 2); + _link ~= Link(4, 1); + } + + Link[] _link; +} + +void test18() +{ + C18 foo = new C18; + foo.sort_links(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=19 + +void test19() +{ + byte b; + --b = b; +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=24 + +void test24() +{ + struct S24 + { + char[1] b; + } + + S24 a; + + if (*a.b.ptr) + return; +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=29 + +void test29() +{ + import std.string : format; + import std.conv : text; + + string s; + for (auto i = 0; i < 100000; i++) + { + s = format("%d", i); + s = text(i); + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=31 + +class RedBlackTree(T, alias less) +{ + struct Range + { + @property empty() { } + } + + Range opSlice() + { + return Range(); + } +} + +auto redBlackTree(alias less, E)() +{ + return new RedBlackTree!(E, less); +} + +void test31() +{ + redBlackTree!((a){}, double)(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=35 + +/** + * Here the BinaryHeap instance uses an alias parameter and therefore + * the instance's functions (percolateDown) need to be generated in + * topNIndex->BinaryHeap scope and not in the declaration scope + * (module->BinaryHeap). + */ +void topNIndex()() +{ + bool indirectLess(int a, int b) + { + return a > b; + } + + auto a = BinaryHeap!(indirectLess)(); +} + +struct BinaryHeap(alias less) +{ + void percolateDown() + { + less(0, 1); + } +} + +void test35a() +{ + topNIndex(); +} + +/* + * Similar as test35a but with an additional indirection. + * The nested function chain for percolateDown should look like this: + * topNIndex2->BinaryHeap2->percolateDown. + */ +void topNIndex2()() +{ + bool indirectLess(int a, int b) + { + return a > b; + } + auto a = BinaryHeap2!(S35b!(indirectLess)())(); +} + +struct S35b(alias a) +{ + void foo() + { + a(0, 0); + } +} + +struct BinaryHeap2(alias less) +{ + void percolateDown() + { + less.foo(); + } +} + +void test35b() +{ + topNIndex2(); +} + +void test35() +{ + test35a(); + test35b(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=36 + +/** + * Here getChar is a function in a template where template.isnested == false + * but getChar still is a nested function and needs to get a static chain + * containing test36a. + */ +void test36a()(char val) +{ + void error() + { + } + + void getChar()() + { + error(); + } + + void parseString() + { + getChar(); + } +} + +/** + * Similar as test36a, but a little more complicated: + * Here getChar is nested in a struct template which is nested in a function. + * getChar's static chain still needs to contain test36b. + */ +void test36b()(char val) +{ + void error() + { + } + + struct S(T) + { + void getChar() + { + error(); + } + } + + + void parseString() + { + S!(int)().getChar(); + } +} + +/** + * If g had accessed a, the frontend would have generated a closure. + * + * As we do not access it, there's no closure. We have to be careful + * not to set a static chain for g containing test36c_1 though, + * as g can be called from outside (here from test1c). In the end + * we have to treat this as if everything in test36c_1 was declared + * at module scope. + */ +auto test36c_1() +{ + int a; + void c() {}; + class Result + { + int b; + void g() { c(); /*a = 42;*/ } + } + + return new Result(); +} + +void test36c() +{ + test36c_1().g(); +} + +/** + * empty is a (private) function which is nested in lightPostprocess. + * At the same time it's a template instance, so it has to be declared as + * weak or otherwise one-only. imports/runnable.d creates another instance + * of Regex!char to verify that. + */ +struct Parser(R) +{ + @property program() + { + return Regex!char(); + } +} + +struct Regex(Char) +{ + @trusted lightPostprocess() + { + struct FixedStack(T) + { + @property empty() { return false; } + } + auto counterRange = FixedStack!uint(); + } +} + +void test36d() +{ + auto parser = Parser!(char[])(); + imports.runnable.test36d_1; +} + +void test36() +{ + test36a('n'); + test36b('n'); + test36c(); + test36d(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=37 + +struct S37 +{ + int bar(const S37 s) + { + return 0; + } +} + +int test37() +{ + S37 s; + return s.bar(s); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=43 + +void test43() +{ + import core.vararg; + import core.stdc.stdio; + + void formatArray(ref va_list argptr) + { + auto a = va_arg!(const(float)[])(argptr); + foreach(f; a) + { + printf("%f\n", f); + } + } + + void doFormat(TypeInfo[] arguments, va_list argptr) + { + formatArray(argptr); + } + + void format(...) + { + doFormat(_arguments, _argptr); + } + + format([1.0f, 2.0f, 3.0f]); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=47 + +template Foo47() +{ + void test47() + { + asm { "nop"; } + } +} + +mixin Foo47!(); + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=51 + +struct S51 +{ + int x; + int pad; + + this(this) + { + ++x; + } +} + +void test51() +{ + S51 s; + auto sarr = new S51[1]; + auto sarr2 = sarr; + + // postblit all fields. + sarr2 ~= s; + + assert (sarr2[0].x == 1); + assert (sarr2[1].x == 1); + assert (sarr[0].x == 0); + assert (s.x == 0); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=52 + +class C52 +{ + C52 a; + + this() + { + printf("Construct: this=%p\n", cast(void*)this); + a = this; + } + + bool check() + { + printf("Check: this=%p a=%p\n", cast(void*)this, cast(void*)a); + return this is a; + } +} + +auto test52a() +{ + import std.conv, std.traits; + + struct Scoped + { + void[__traits (classInstanceSize, C52) ] Scoped_store = void; + + inout(C52) Scoped_payload() inout + { + void* alignedStore = cast(void*) Scoped_store.ptr; + return cast(inout (C52)) alignedStore; + } + alias Scoped_payload this; + } + + Scoped result; + emplace!(Unqual!C52)(result.Scoped_store); + assert(result.Scoped_payload().check); + return result; +} + +void test52() +{ + auto a1 = test52a(); + assert(a1.Scoped_payload().check); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=57 + +struct S57 +{ + int a; + long b; + // Doesn't happen for bigger structs +} + +S57 bar57() +{ + return S57(4, 42); +} + +void test57() +{ + S57 s = bar57(); + assert (s is S57(4, 42)); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=66 + +void test66() +{ + int pos = 0; + + foreach(x; 0 .. 64) + { + ++pos %= 4; + assert (pos != 4); + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=67 + +__vector(float[4]) d[2]; // ICE + + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=71 + +struct Leaf +{ + ubyte symbol; + ubyte codeLen; +} + +struct CanonicalHuffman +{ + Leaf[] table; + + void print() + { + import std.algorithm; + import std.range; + + auto list = zip(iota(table.length), table.dup).array + .sort!((a, b) => a[1].symbol < b[1].symbol) + .uniq!((a, b) => (a[0] & (1 << a[1].codeLen) - 1) == (b[0] & (1 << b[1].codeLen) - 1)); + } +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=77 + +void fun(ubyte[3] buf) +{ + import std.bitmanip : bigEndianToNative; + bigEndianToNative!ushort(buf[0..2]); +} + +void test77() +{ + fun([1,2,3]); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=108 + +@attribute("forceinline") +void test108() +{ + import std.stdio : writeln; + writeln("Here"); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=115 + +void test115() +{ + union U + { + float f; + uint i; + } + float a = 123.0; + const l = U(a); + + assert(l.i == U(a).i); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=121 + +immutable char C121 = void; // ICE + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=122 + +void test122() +{ + import std.algorithm : map; + import std.parallelism : taskPool; + import std.range : iota; + + immutable n = 10000; + enum delta = 1.0 / n; // XBUG: was 'immutable delta' https://issues.dlang.org/show_bug.cgi?id=17092 + immutable pi = 4.0 * delta * taskPool.reduce!"a + b"( + map!((int i) { immutable x = (i - 0.5) * delta; return 1.0 / (1.0 + x * x); })(iota(n))); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=127 + +int[0] test127a; // OK +int[1][0] test127b; // OK +int[0][1] test127c; // ICE + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=131 + +struct S131 +{ + this(string ) { } + string opAssign(string v) { return v; } +} + +void test131() +{ + S131[string] s; + s["foo"] = "bar"; +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=133 + +void delegate()[] D133; + +void test133a(void delegate() dg) +{ + D133 ~= dg; +} + +void test133() +{ + void nested() + {} + test133a(&nested); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=141 + +bool test141a(int a) +{ + return a > (a + 1); +} + +void test141() +{ + assert(test141a(int.min) == false); + assert(test141a(int.max) == true); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=142 + +@attribute("noinline") +int test142a()() +{ + return 142; +} + +void test142() +{ + enum E142 = test142a(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=171 + +void test171a() +{ + int count = 0; + short a = -1; + while (a != 0) + { + a >>>= 1; + count++; + assert(count <= 16); + } +} + +void test171b() +{ + uint[3] lhs = [99, 201, 300], + rhs = [-1, 0, 0]; + long t = 0; + + for (int i = 0; i < 3; i++) + { + t += lhs[i]; + t -= rhs[i]; + lhs[i] = cast(uint) t; + t >>= uint.sizeof * 8; + } + + assert(lhs == [100, 200, 300]); +} + +void test171() +{ + test171a(); + test171b(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=179 + +struct S179a +{ + @disable this(this); +} + +struct S179b +{ + S179a s1; + void connect() { printf("this=%p\n", &this); } +} + +class C179 +{ + private S179b s2; + ref S179b value() @property + { + printf("this=%p\n", &s2); + return s2; + } +} + +void test179() +{ + C179 a = new C179; + a.value.connect(); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=183 + +struct S183a +{ + union I183a + { + struct + { + double x, y, z; + } + struct + { + double a, b, c; + } + } + + I183a inner; + + this(double x, double y, double z) + { + this.inner.x = x; + this.inner.y = y; + this.inner.z = z; + } +} + +struct S183b +{ + @property get() + { + union Buf + { + void[0] result; + } + const Buf buf = { }; + return buf.result; + } +} + +struct S183c +{ + @property get() + { + union Buf + { + TypeInfo info; + void[0] result; + } + const Buf buf = { }; + return buf.result; + } +} + +void test183() +{ + auto v1 = S183a(0, 0, 0); + auto v2 = S183b().get; + auto v3 = S183c().get; +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=186 + +struct S186 +{ + union + { + struct + { + ubyte fieldA; + byte fieldB = -1; + byte fieldC = -1; + } + size_t _complete; + } + + this(size_t complete) + { + this._complete = complete; + } +} + +void check186(in S186 obj, byte fieldB) +{ + assert(obj.fieldA == 2); + assert(obj.fieldB == 0); + assert(obj.fieldC == 0); + assert(obj._complete == 2); + assert(fieldB == 0); +} + +void test186a(size_t val) +{ + S186 obj = S186(val); + check186(obj, obj.fieldB); + + assert(obj.fieldA == 2); + assert(obj.fieldB == 0); + assert(obj.fieldC == 0); + assert(obj._complete == 2); + + obj = S186(val); + check186(obj, obj.fieldB); + + assert(obj.fieldA == 2); + assert(obj.fieldB == 0); + assert(obj.fieldC == 0); + assert(obj._complete == 2); +} + +void test186() +{ + test186a(2); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=187 + +align(1) struct S187b +{ + align(1) + { + uint unpaddedA; + ushort unpaddedB; + } +} + +struct S187a +{ + S187b[3] unpaddedArray; + ubyte wontInitialize = ubyte.init; +} + +struct S187 +{ + S187a interesting; +} + + +void prepareStack() +{ + byte[255] stackGarbage; + foreach(i, ref b; stackGarbage) + { + b = cast(byte)(-i); + } +} + +void test187() +{ + prepareStack(); + auto a = S187(S187a()); + assert(a.interesting.wontInitialize == 0); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=191 + +class C191 +{ + int count = 0; + + void testA() + { + class Inner + { + void test() + { + void localFunction() + { + if (++count != 5) + testA(); + } + localFunction(); + } + } + scope ic = new Inner(); + ic.test(); + } + + void testB() + { + class Inner + { + void test() + { + void localFunction() + { + void anotherLocalFunction() + { + if (++count != 10) + testB(); + } + anotherLocalFunction(); + } + localFunction(); + } + } + scope ic = new Inner(); + ic.test(); + } + + void testC() + { + class Inner + { + int a = 1; + + void test() + { + void localFunction() + { + count += a; + if (count != 15) + testC(); + assert(a == 1); + } + localFunction(); + } + } + scope ic = new Inner(); + ic.test(); + } + + void testD() + { + class Inner + { + void test() + { + int a = 1; + + void localFunction() + { + count += a; + if (count != 20) + testD(); + assert(a == 1); + } + localFunction(); + } + } + scope ic = new Inner(); + ic.test(); + } + + void testE() + { + class Inner + { + int a = 1; + + void test() + { + void localFunction() + { + void anotherLocalFunction() + { + count += a; + if (count != 25) + testE(); + assert(a == 1); + } + + anotherLocalFunction(); + } + + localFunction(); + } + } + scope ic = new Inner(); + ic.test(); + } + + void testF() + { + class Inner + { + void test() + { + int a = 1; + + void localFunction() + { + void anotherLocalFunction() + { + count += a; + if (count != 30) + testF(); + assert(a == 1); + } + + anotherLocalFunction(); + } + + localFunction(); + } + } + scope ic = new Inner(); + ic.test(); + } + + void testG() + { + class Inner + { + void test() + { + void localFunction() + { + int a = 1; + + void anotherLocalFunction() + { + count += a; + if (count != 35) + testG(); + assert(a == 1); + } + + anotherLocalFunction(); + } + + localFunction(); + } + } + scope ic = new Inner(); + ic.test(); + } +} + +void test191() +{ + scope oc = new C191(); + oc.testA(); + assert(oc.count == 5); + + oc.testB(); + assert(oc.count == 10); + + oc.testC(); + assert(oc.count == 15); + + oc.testD(); + assert(oc.count == 20); + + oc.testE(); + assert(oc.count == 25); + + oc.testF(); + assert(oc.count == 30); + + oc.testG(); + assert(oc.count == 35); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=194 + +auto test194(ref bool overflow) +{ + import core.checkedint; + + return adds(1, 1, overflow); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=196 + +class C196 +{ + int a; +} + +struct S196 +{ + int a; +} + +void test196() +{ + __gshared c = new C196(); + __gshared s = new S196(0); + c.a = 1; + s.a = 1; +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=198 + +struct S198a +{ + union + { + float[3] v; + struct + { + float x; + float y; + float z; + } + } + + this(float x_, float y_, float z_) + { + x = x_; + y = y_; + z = z_; + } + + ref S198a opOpAssign(string op)(S198a operand) + if (op == "+") + { + x += operand.x; + y += operand.y; + z += operand.z; + return this; + } +} + +struct S198b +{ + @property get() + { + union Buf + { + void[0] result; + } + const Buf buf = { }; + return buf.result; + } +} + +struct S198c +{ + @property get() + { + union Buf + { + TypeInfo info; + void[0] result; + } + const Buf buf = { }; + return buf.result; + } +} + + +auto test198() +{ + S198a sum = S198a(0, 0, 0); + + foreach(size_t v; 0 .. 3) + sum += S198a(1, 2, 3); + + assert(sum.v == [3, 6, 9]); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=200 + +void test200a(double x, double y) +{ + const double y2 = x + 1.0; + assert(y == y2); +} + +void test200() +{ + const double x = .012; + const double y = x + 1.0; + test200a(x, y); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=210 + +struct S210 +{ + ubyte a; + uint b; +} + +union U210 +{ + S210 a; + uint b; +} + +S210 test210a() +{ + S210 s = S210(1, 2); + return s; +} + +S210[2] test210b() +{ + S210[2] s = [S210(1, 2), S210(3, 4)]; + return s; +} + +U210 test210c() +{ + U210 s = U210(S210(1, 2)); + return s; +} + +U210[2] test210d() +{ + U210[2] s = [U210(S210(1, 2)), U210(S210(3, 4))]; + return s; +} + +void test210() +{ + S210 a = S210(1, 2); + assert(a == S210(1, 2)); + assert(a == test210a()); + assert(a != S210(2, 1)); + + S210[2] b = [S210(1, 2), S210(3, 4)]; + assert(b == [S210(1, 2), S210(3, 4)]); + assert(b == test210b()); + assert(b != [S210(2, 1), S210(3, 4)]); + + U210 c = U210(S210(1, 2)); + assert(c == U210(S210(1, 2))); + assert(c == test210c()); + assert(c != U210(S210(2, 1))); + + U210[2] d = [U210(S210(1, 2)), U210(S210(3, 4))]; + assert(d == [U210(S210(1, 2)), U210(S210(3, 4))]); + assert(d == test210d()); + assert(d != [U210(S210(2, 1)), U210(S210(3, 4))]); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=240 + +void test240a(int a, int b) +{ + assert(a == 0); + assert(b == 0); +} + +void test240() +{ + int a = 0; + test240a(a, a++); + assert(a == 1); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=242 + +struct S242 +{ + enum M = S242(); + int a = 42; + + auto iter() + { + this.a = 24; + return this; + } +} + +S242 test242a() +{ + return S242.M.iter; +} + +void test242() +{ + assert(test242a() == S242(24)); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=248 + +class C248b +{ + bool isintegral() + { + return false; + } +} + +class C248a +{ + int count = 0; + + C248b getMemtype() + { + count++; + return new C248b(); + } +} + +class C248 +{ + C248a sym; + + this() + { + this.sym = new C248a(); + } + + bool isintegral() + { + return sym.getMemtype().isintegral(); + } +} + +void test248() +{ + C248 e = new C248(); + e.isintegral(); + assert(e.sym.count == 1); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=250 + +void test250() +{ + struct S + { + string data; + } + + auto a = S("hello"); + auto b = S("hello".dup); + + assert(a.data == b.data); + assert(a == b); + assert([a] == [b]); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=253 + +interface A253 +{ + void test253(int[int]); +} + +interface C253 : A253 +{ +} + +class D253 : B253, C253 +{ +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=273 + +class B273 +{ + B273[] members; +} + +class D273 : B273 +{ +} + +void test273() +{ + auto noPointers = ClassInfo.ClassFlags.noPointers; + assert((B273.classinfo.m_flags & noPointers) == 0); + assert((D273.classinfo.m_flags & noPointers) == 0); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=285 + +inout(char)[] test285a(inout(char)* s) @nogc @system pure nothrow +{ + import core.stdc.string : strlen; + return s ? s[0 .. strlen(s)] : null; +} + +void test285() +{ + assert(test285a(null) == null); + assert(test285a("foo") == "foo"); +} + +/******************************************/ +// https://bugzilla.gdcproject.org/show_bug.cgi?id=286 + +void test286() +{ + struct K286 + { + int count; + this(this) + { + count++; + } + } + + struct S286 + { + int data; + this(K286 key) + { + data = key.count; + } + } + + S286 getData(K286 key) + { + static S286[K286] getCache; + auto p = key in getCache; + if (p) + return *p; + return (getCache[key] = S286(key)); + } + + auto s = getData(K286()); + if (s.data == 0) + assert(0); +} + +/******************************************/ + +void main() +{ + test2(); + test4(); + test16(); + test17(); + test18(); + test35(); + test36(); + test43(); + test51(); + test52(); + test57(); + test66(); + test77(); + test108(); + test115(); + test131(); + test133(); + test141(); + test179(); + test186(); + test187(); + test191(); + test196(); + test198(); + test200(); + test210(); + test240(); + test242(); + test248(); + test250(); + test273(); + test285(); + test286(); + + printf("Success!\n"); +} diff --git a/gcc/testsuite/gdc.dg/simd.d b/gcc/testsuite/gdc.dg/simd.d new file mode 100644 index 00000000000..dd329254257 --- /dev/null +++ b/gcc/testsuite/gdc.dg/simd.d @@ -0,0 +1,1734 @@ +// { dg-do run { target hw } } +import core.simd; +import core.stdc.string; +import std.stdio; + +alias TypeTuple(T...) = T; + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=16087 + +static assert(void8.sizeof == 8); +static assert(float2.sizeof == 8); +static assert(byte8.sizeof == 8); +static assert(ubyte8.sizeof == 8); +static assert(short4.sizeof == 8); +static assert(ushort4.sizeof == 8); +static assert(int2.sizeof == 8); +static assert(uint2.sizeof == 8); + +static assert(void16.alignof == 16); +static assert(double2.alignof == 16); +static assert(float4.alignof == 16); +static assert(byte16.alignof == 16); +static assert(ubyte16.alignof == 16); +static assert(short8.alignof == 16); +static assert(ushort8.alignof == 16); +static assert(int4.alignof == 16); +static assert(uint4.alignof == 16); +static assert(long2.alignof == 16); +static assert(ulong2.alignof == 16); + +static assert(void16.sizeof == 16); +static assert(double2.sizeof == 16); +static assert(float4.sizeof == 16); +static assert(byte16.sizeof == 16); +static assert(ubyte16.sizeof == 16); +static assert(short8.sizeof == 16); +static assert(ushort8.sizeof == 16); +static assert(int4.sizeof == 16); +static assert(uint4.sizeof == 16); +static assert(long2.sizeof == 16); +static assert(ulong2.sizeof == 16); + +static assert(void32.alignof == 32); +static assert(double4.alignof == 32); +static assert(float8.alignof == 32); +static assert(byte32.alignof == 32); +static assert(ubyte32.alignof == 32); +static assert(short16.alignof == 32); +static assert(ushort16.alignof == 32); +static assert(int8.alignof == 32); +static assert(uint8.alignof == 32); +static assert(long4.alignof == 32); +static assert(ulong4.alignof == 32); + +static assert(void32.sizeof == 32); +static assert(double4.sizeof == 32); +static assert(float8.sizeof == 32); +static assert(byte32.sizeof == 32); +static assert(ubyte32.sizeof == 32); +static assert(short16.sizeof == 32); +static assert(ushort16.sizeof == 32); +static assert(int8.sizeof == 32); +static assert(uint8.sizeof == 32); +static assert(long4.sizeof == 32); +static assert(ulong4.sizeof == 32); + +/*****************************************/ + +void test1() +{ + void16 v1 = void,v2 = void; + byte16 b; + v2 = b; + v1 = v2; + static assert(!__traits(compiles, v1 + v2)); + static assert(!__traits(compiles, v1 - v2)); + static assert(!__traits(compiles, v1 * v2)); + static assert(!__traits(compiles, v1 / v2)); + static assert(!__traits(compiles, v1 % v2)); + static assert(!__traits(compiles, v1 & v2)); + static assert(!__traits(compiles, v1 | v2)); + static assert(!__traits(compiles, v1 ^ v2)); + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + static assert(!__traits(compiles, v1 << 1)); + static assert(!__traits(compiles, v1 >> 1)); + static assert(!__traits(compiles, v1 >>> 1)); + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + static assert(!__traits(compiles, ~v1)); + static assert(!__traits(compiles, -v1)); + static assert(!__traits(compiles, +v1)); + static assert(!__traits(compiles, !v1)); + + static assert(!__traits(compiles, v1 += v2)); + static assert(!__traits(compiles, v1 -= v2)); + static assert(!__traits(compiles, v1 *= v2)); + static assert(!__traits(compiles, v1 /= v2)); + static assert(!__traits(compiles, v1 %= v2)); + static assert(!__traits(compiles, v1 &= v2)); + static assert(!__traits(compiles, v1 |= v2)); + static assert(!__traits(compiles, v1 ^= v2)); + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + static assert(!__traits(compiles, v1 <<= 1)); + static assert(!__traits(compiles, v1 >>= 1)); + static assert(!__traits(compiles, v1 >>>= 1)); + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2() +{ + byte16 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2b() +{ + ubyte16 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2c() +{ + short8 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + v1 = v1 * 3; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2d() +{ + ushort8 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2e() +{ + int4 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2f() +{ + uint4 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2g() +{ + long2 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2h() +{ + ulong2 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + v1 = v2 % v3; + v1 = v2 & v3; + v1 = v2 | v3; + v1 = v2 ^ v3; + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + v1 = v2 << 1; + v1 = v2 >> 1; + v1 = v2 >>> 1; + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + v1 = ~v2; + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + v1 %= v2; + v1 &= v2; + v1 |= v2; + v1 ^= v2; + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + v1 <<= 1; + v1 >>= 1; + v1 >>>= 1; + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2i() +{ + float4 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + static assert(!__traits(compiles, v1 % v2)); + static assert(!__traits(compiles, v1 & v2)); + static assert(!__traits(compiles, v1 | v2)); + static assert(!__traits(compiles, v1 ^ v2)); + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + static assert(!__traits(compiles, v1 << 1)); + static assert(!__traits(compiles, v1 >> 1)); + static assert(!__traits(compiles, v1 >>> 1)); + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + static assert(!__traits(compiles, ~v1)); + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + static assert(!__traits(compiles, v1 %= v2)); + static assert(!__traits(compiles, v1 &= v2)); + static assert(!__traits(compiles, v1 |= v2)); + static assert(!__traits(compiles, v1 ^= v2)); + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + static assert(!__traits(compiles, v1 <<= 1)); + static assert(!__traits(compiles, v1 >>= 1)); + static assert(!__traits(compiles, v1 >>>= 1)); + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test2j() +{ + double2 v1, v2 = 1, v3 = 1; + v1 = v2; + v1 = v2 + v3; + v1 = v2 - v3; + v1 = v2 * v3; + v1 = v2 / v3; + static assert(!__traits(compiles, v1 % v2)); + static assert(!__traits(compiles, v1 & v2)); + static assert(!__traits(compiles, v1 | v2)); + static assert(!__traits(compiles, v1 ^ v2)); + static assert(!__traits(compiles, v1 ~ v2)); + static assert(!__traits(compiles, v1 ^^ v2)); + static assert(!__traits(compiles, v1 is v2)); + static assert(!__traits(compiles, v1 !is v2)); + static assert(!__traits(compiles, v1 == v2)); + static assert(!__traits(compiles, v1 != v2)); + static assert(!__traits(compiles, v1 < v2)); + static assert(!__traits(compiles, v1 > v2)); + static assert(!__traits(compiles, v1 <= v2)); + static assert(!__traits(compiles, v1 >= v2)); + static assert(!__traits(compiles, v1 <> v2)); + static assert(!__traits(compiles, v1 !< v2)); + static assert(!__traits(compiles, v1 !> v2)); + static assert(!__traits(compiles, v1 !<> v2)); + static assert(!__traits(compiles, v1 <>= v2)); + static assert(!__traits(compiles, v1 !<= v2)); + static assert(!__traits(compiles, v1 !>= v2)); + static assert(!__traits(compiles, v1 !<>= v2)); + static assert(!__traits(compiles, v1 << 1)); + static assert(!__traits(compiles, v1 >> 1)); + static assert(!__traits(compiles, v1 >>> 1)); + static assert(!__traits(compiles, v1 && v2)); + static assert(!__traits(compiles, v1 || v2)); + static assert(!__traits(compiles, ~v1)); + v1 = -v2; + v1 = +v2; + static assert(!__traits(compiles, !v1)); + + v1 += v2; + v1 -= v2; + v1 *= v2; + v1 /= v2; + static assert(!__traits(compiles, v1 %= v2)); + static assert(!__traits(compiles, v1 &= v2)); + static assert(!__traits(compiles, v1 |= v2)); + static assert(!__traits(compiles, v1 ^= v2)); + static assert(!__traits(compiles, v1 ~= v2)); + static assert(!__traits(compiles, v1 ^^= v2)); + static assert(!__traits(compiles, v1 <<= 1)); + static assert(!__traits(compiles, v1 >>= 1)); + static assert(!__traits(compiles, v1 >>>= 1)); + + // A cast from vector to non-vector is allowed only when the target is same size Tsarray. + static assert(!__traits(compiles, cast(byte)v1)); // 1byte + static assert(!__traits(compiles, cast(short)v1)); // 2byte + static assert(!__traits(compiles, cast(int)v1)); // 4byte + static assert(!__traits(compiles, cast(long)v1)); // 8byte + static assert(!__traits(compiles, cast(float)v1)); // 4byte + static assert(!__traits(compiles, cast(double)v1)); // 8byte + static assert(!__traits(compiles, cast(int[2])v1)); // 8byte Tsarray + static assert( __traits(compiles, cast(int[4])v1)); // 16byte Tsarray, OK + static assert( __traits(compiles, cast(long[2])v1)); // 16byte Tsarray, OK +} + +/*****************************************/ + +void test4() +{ + int4 c = 7; + (cast(int[4])c)[3] = 4; + (cast(int*)&c)[2] = 4; + c.array[1] = 4; + c.ptr[3] = 4; + assert(c.length == 4); +} + +/*****************************************/ + +void BaseTypeOfVector(T : __vector(T[N]), size_t N)(int i) +{ + assert(is(T == int)); + assert(N == 4); +} + + +void test7411() +{ + BaseTypeOfVector!(__vector(int[4]))(3); +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=7951 + +float[4] test7951() +{ + float4 v1; + float4 v2; + + return cast(float[4])(v1+v2); +} + +/*****************************************/ + +void test7951_2() +{ + float[4] v1 = [1,2,3,4]; + float[4] v2 = [1,2,3,4]; + float4 f1, f2, f3; + f1.array = v1; + f2.array = v2; + f3 = f1 + f2; +} + +/*****************************************/ + +immutable ulong2 gulong2 = 0x8000_0000_0000_0000; +immutable uint4 guint4 = 0x8000_0000; +immutable ushort8 gushort8 = 0x8000; +immutable ubyte16 gubyte16 = 0x80; + +immutable long2 glong2 = 0x7000_0000_0000_0000; +immutable int4 gint4 = 0x7000_0000; +immutable short8 gshort8 = 0x7000; +immutable byte16 gbyte16 = 0x70; + +immutable float4 gfloat4 = 4.0; +immutable double2 gdouble2 = 8.0; + +void test7414() +{ + immutable ulong2 lulong2 = 0x8000_0000_0000_0000; + assert(memcmp(&lulong2, &gulong2, gulong2.sizeof) == 0); + + immutable uint4 luint4 = 0x8000_0000; + assert(memcmp(&luint4, &guint4, guint4.sizeof) == 0); + + immutable ushort8 lushort8 = 0x8000; + assert(memcmp(&lushort8, &gushort8, gushort8.sizeof) == 0); + + immutable ubyte16 lubyte16 = 0x80; + assert(memcmp(&lubyte16, &gubyte16, gubyte16.sizeof) == 0); + + + immutable long2 llong2 = 0x7000_0000_0000_0000; + assert(memcmp(&llong2, &glong2, glong2.sizeof) == 0); + + immutable int4 lint4 = 0x7000_0000; + assert(memcmp(&lint4, &gint4, gint4.sizeof) == 0); + + immutable short8 lshort8 = 0x7000; + assert(memcmp(&lshort8, &gshort8, gshort8.sizeof) == 0); + + immutable byte16 lbyte16 = 0x70; + assert(memcmp(&lbyte16, &gbyte16, gbyte16.sizeof) == 0); + + + immutable float4 lfloat4 = 4.0; + assert(memcmp(&lfloat4, &gfloat4, gfloat4.sizeof) == 0); + + immutable double2 ldouble2 = 8.0; + assert(memcmp(&ldouble2, &gdouble2, gdouble2.sizeof) == 0); +} + +/*****************************************/ + +void test7413() +{ + byte16 b = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; + assert(b.array[0] == 1); + assert(b.array[1] == 2); + assert(b.array[2] == 3); + assert(b.array[3] == 4); + assert(b.array[4] == 5); + assert(b.array[5] == 6); + assert(b.array[6] == 7); + assert(b.array[7] == 8); + assert(b.array[8] == 9); + assert(b.array[9] == 10); + assert(b.array[10] == 11); + assert(b.array[11] == 12); + assert(b.array[12] == 13); + assert(b.array[13] == 14); + assert(b.array[14] == 15); + assert(b.array[15] == 16); + + ubyte16 ub = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; + assert(ub.array[0] == 1); + assert(ub.array[1] == 2); + assert(ub.array[2] == 3); + assert(ub.array[3] == 4); + assert(ub.array[4] == 5); + assert(ub.array[5] == 6); + assert(ub.array[6] == 7); + assert(ub.array[7] == 8); + assert(ub.array[8] == 9); + assert(ub.array[9] == 10); + assert(ub.array[10] == 11); + assert(ub.array[11] == 12); + assert(ub.array[12] == 13); + assert(ub.array[13] == 14); + assert(ub.array[14] == 15); + assert(ub.array[15] == 16); + + short8 s = [1,2,3,4,5,6,7,8]; + assert(s.array[0] == 1); + assert(s.array[1] == 2); + assert(s.array[2] == 3); + assert(s.array[3] == 4); + assert(s.array[4] == 5); + assert(s.array[5] == 6); + assert(s.array[6] == 7); + assert(s.array[7] == 8); + + ushort8 us = [1,2,3,4,5,6,7,8]; + assert(us.array[0] == 1); + assert(us.array[1] == 2); + assert(us.array[2] == 3); + assert(us.array[3] == 4); + assert(us.array[4] == 5); + assert(us.array[5] == 6); + assert(us.array[6] == 7); + assert(us.array[7] == 8); + + int4 i = [1,2,3,4]; + assert(i.array[0] == 1); + assert(i.array[1] == 2); + assert(i.array[2] == 3); + assert(i.array[3] == 4); + + uint4 ui = [1,2,3,4]; + assert(ui.array[0] == 1); + assert(ui.array[1] == 2); + assert(ui.array[2] == 3); + assert(ui.array[3] == 4); + + long2 l = [1,2]; + assert(l.array[0] == 1); + assert(l.array[1] == 2); + + ulong2 ul = [1,2]; + assert(ul.array[0] == 1); + assert(ul.array[1] == 2); + + float4 f = [1,2,3,4]; + assert(f.array[0] == 1); + assert(f.array[1] == 2); + assert(f.array[2] == 3); + assert(f.array[3] == 4); + + double2 d = [1,2]; + assert(d.array[0] == 1); + assert(d.array[1] == 2); +} + +/*****************************************/ + +byte16 b = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; +ubyte16 ub = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; +short8 s = [1,2,3,4,5,6,7,8]; +ushort8 us = [1,2,3,4,5,6,7,8]; +int4 i = [1,2,3,4]; +uint4 ui = [1,2,3,4]; +long2 l = [1,2]; +ulong2 ul = [1,2]; +float4 f = [1,2,3,4]; +double2 d = [1,2]; + +void test7413_2() +{ + assert(b.array[0] == 1); + assert(b.array[1] == 2); + assert(b.array[2] == 3); + assert(b.array[3] == 4); + assert(b.array[4] == 5); + assert(b.array[5] == 6); + assert(b.array[6] == 7); + assert(b.array[7] == 8); + assert(b.array[8] == 9); + assert(b.array[9] == 10); + assert(b.array[10] == 11); + assert(b.array[11] == 12); + assert(b.array[12] == 13); + assert(b.array[13] == 14); + assert(b.array[14] == 15); + assert(b.array[15] == 16); + + assert(ub.array[0] == 1); + assert(ub.array[1] == 2); + assert(ub.array[2] == 3); + assert(ub.array[3] == 4); + assert(ub.array[4] == 5); + assert(ub.array[5] == 6); + assert(ub.array[6] == 7); + assert(ub.array[7] == 8); + assert(ub.array[8] == 9); + assert(ub.array[9] == 10); + assert(ub.array[10] == 11); + assert(ub.array[11] == 12); + assert(ub.array[12] == 13); + assert(ub.array[13] == 14); + assert(ub.array[14] == 15); + assert(ub.array[15] == 16); + + assert(s.array[0] == 1); + assert(s.array[1] == 2); + assert(s.array[2] == 3); + assert(s.array[3] == 4); + assert(s.array[4] == 5); + assert(s.array[5] == 6); + assert(s.array[6] == 7); + assert(s.array[7] == 8); + + assert(us.array[0] == 1); + assert(us.array[1] == 2); + assert(us.array[2] == 3); + assert(us.array[3] == 4); + assert(us.array[4] == 5); + assert(us.array[5] == 6); + assert(us.array[6] == 7); + assert(us.array[7] == 8); + + assert(i.array[0] == 1); + assert(i.array[1] == 2); + assert(i.array[2] == 3); + assert(i.array[3] == 4); + + assert(ui.array[0] == 1); + assert(ui.array[1] == 2); + assert(ui.array[2] == 3); + assert(ui.array[3] == 4); + + assert(l.array[0] == 1); + assert(l.array[1] == 2); + + assert(ul.array[0] == 1); + assert(ul.array[1] == 2); + + assert(f.array[0] == 1); + assert(f.array[1] == 2); + assert(f.array[2] == 3); + assert(f.array[3] == 4); + + assert(d.array[0] == 1); + assert(d.array[1] == 2); +} + +/*****************************************/ + +float bug8060(float x) { + int i = *cast(int*)&x; + ++i; + return *cast(float*)&i; +} + +/*****************************************/ +/+ +// https://issues.dlang.org/show_bug.cgi?id=9200 + +void bar9200(double[2] a) +{ + assert(a[0] == 1); + assert(a[1] == 2); +} + +double2 * v9200(double2* a) +{ + return a; +} + +void test9200() +{ + double2 a = [1, 2]; + + *v9200(&a) = a; + + bar9200(a.array); +} ++/ + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=9304 +// https://issues.dlang.org/show_bug.cgi?id=9322 + +float4 foo9304(float4 a) +{ + return -a; +} + + +void test9304() +{ + auto a = foo9304([0, 1, 2, 3]); + //writeln(a.array); + assert(a.array == [0,-1,-2,-3]); +} + +/*****************************************/ + +void test9910() +{ + float4 f = [1, 1, 1, 1]; + auto works = f + 3; + auto bug = 3 + f; + + assert (works.array == [4,4,4,4]); + assert (bug.array == [4,4,4,4]); // no property 'array' for type 'int' +} + +/*****************************************/ + +bool normalize(double[] range, double sum = 1) +{ + double s = 0; + const length = range.length; + foreach (e; range) + { + s += e; + } + if (s == 0) + { + return false; + } + return true; +} + +void test12852() +{ + double[3] range = [0.0, 0.0, 0.0]; + assert(normalize(range[]) == false); + range[1] = 3.0; + assert(normalize(range[]) == true); +} + +/*****************************************/ + +void test9449() +{ + ubyte16[1] table; +} + +/*****************************************/ + +void test9449_2() +{ + float[4][2] m = [[2.0, 1, 3, 4], [5.0, 6, 7, 8]]; // segfault + + assert(m[0][0] == 2.0); + assert(m[0][1] == 1); + assert(m[0][2] == 3); + assert(m[0][3] == 4); + + assert(m[1][0] == 5.0); + assert(m[1][1] == 6); + assert(m[1][2] == 7); + assert(m[1][3] == 8); +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=13841 + +void test13841() +{ + alias Vector16s = TypeTuple!( + void16, byte16, short8, int4, long2, + ubyte16, ushort8, uint4, ulong2, float4, double2); + foreach (V1; Vector16s) + { + foreach (V2; Vector16s) + { + V1 v1 = void; + V2 v2 = void; + static if (is(V1 == V2)) + { + static assert( is(typeof(true ? v1 : v2) == V1)); + } + else + { + static assert(!is(typeof(true ? v1 : v2))); + } + } + } +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=12776 + +void test12776() +{ + alias Vector16s = TypeTuple!( + void16, byte16, short8, int4, long2, + ubyte16, ushort8, uint4, ulong2, float4, double2); + foreach (V; Vector16s) + { + static assert(is(typeof( V .init) == V )); + static assert(is(typeof( const(V).init) == const(V))); + static assert(is(typeof( inout( V).init) == inout( V))); + static assert(is(typeof( inout(const V).init) == inout(const V))); + static assert(is(typeof(shared( V).init) == shared( V))); + static assert(is(typeof(shared( const V).init) == shared( const V))); + static assert(is(typeof(shared(inout V).init) == shared(inout V))); + static assert(is(typeof(shared(inout const V).init) == shared(inout const V))); + static assert(is(typeof( immutable(V).init) == immutable(V))); + } +} + +/*****************************************/ + +void foo13988(double[] arr) +{ + static ulong repr(double d) { return *cast(ulong*)&d; } + foreach (x; arr) + assert(repr(arr[0]) == *cast(ulong*)&(arr[0])); +} + + +void test13988() +{ + double[] arr = [3.0]; + foo13988(arr); +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=15123 + +void test15123() +{ + alias Vector16s = TypeTuple!( + void16, byte16, short8, int4, long2, + ubyte16, ushort8, uint4, ulong2, float4, double2); + foreach (V; Vector16s) + { + auto x = V.init; + } +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=15144 + +void test15144() +{ + enum ubyte16 csXMM1 = ['a','b','c',0,0,0,0,0]; + __gshared ubyte16 csXMM2 = ['a','b','c',0,0,0,0,0]; + immutable ubyte16 csXMM3 = ['a','b','c',0,0,0,0,0]; +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=13927 + +void test13927(ulong2 a) +{ + ulong2 b = [long.min, long.min]; + auto tmp = a - b; +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=16488 + +void foo_byte16(byte t, byte s) +{ + byte16 f = s; + auto p = cast(byte*)&f; + foreach (i; 0 .. 16) + assert(p[i] == s); +} + +void foo_ubyte16(ubyte t, ubyte s) +{ + ubyte16 f = s; + auto p = cast(ubyte*)&f; + foreach (i; 0 .. 16) + assert(p[i] == s); +} + + +void foo_short8(short t, short s) +{ + short8 f = s; + auto p = cast(short*)&f; + foreach (i; 0 .. 8) + assert(p[i] == s); +} + +void foo_ushort8(ushort t, ushort s) +{ + ushort8 f = s; + auto p = cast(ushort*)&f; + foreach (i; 0 .. 8) + assert(p[i] == s); +} + + +void foo_int4(int t, int s) +{ + int4 f = s; + auto p = cast(int*)&f; + foreach (i; 0 .. 4) + assert(p[i] == s); +} + +void foo_uint4(uint t, uint s, uint u) +{ + uint4 f = s; + auto p = cast(uint*)&f; + foreach (i; 0 .. 4) + assert(p[i] == s); +} + + +void foo_long2(long t, long s, long u) +{ + long2 f = s; + auto p = cast(long*)&f; + foreach (i; 0 .. 2) + assert(p[i] == s); +} + +void foo_ulong2(ulong t, ulong s) +{ + ulong2 f = s; + auto p = cast(ulong*)&f; + foreach (i; 0 .. 2) + assert(p[i] == s); +} + +void foo_float4(float t, float s) +{ + float4 f = s; + auto p = cast(float*)&f; + foreach (i; 0 .. 4) + assert(p[i] == s); +} + +void foo_double2(double t, double s, double u) +{ + double2 f = s; + auto p = cast(double*)&f; + foreach (i; 0 .. 2) + assert(p[i] == s); +} + + +void test16448() +{ + foo_byte16(5, -10); + foo_ubyte16(5, 11); + + foo_short8(5, -6); + foo_short8(5, 7); + + foo_int4(5, -6); + foo_uint4(5, 0x12345678, 22); + + foo_long2(5, -6, 1); + foo_ulong2(5, 0x12345678_87654321L); + + foo_float4(5, -6); + foo_double2(5, -6, 2); +} + +/*****************************************/ + +void foo_byte32(byte t, byte s) +{ + byte32 f = s; + auto p = cast(byte*)&f; + foreach (i; 0 .. 32) + assert(p[i] == s); +} + +void foo_ubyte32(ubyte t, ubyte s) +{ + ubyte32 f = s; + auto p = cast(ubyte*)&f; + foreach (i; 0 .. 32) + assert(p[i] == s); +} + +void foo_short16(short t, short s) +{ + short16 f = s; + auto p = cast(short*)&f; + foreach (i; 0 .. 16) + assert(p[i] == s); +} + +void foo_ushort16(ushort t, ushort s) +{ + ushort16 f = s; + auto p = cast(ushort*)&f; + foreach (i; 0 .. 16) + assert(p[i] == s); +} + +void foo_int8(int t, int s) +{ + int8 f = s; + auto p = cast(int*)&f; + foreach (i; 0 .. 8) + assert(p[i] == s); +} + +void foo_uint8(uint t, uint s, uint u) +{ + uint8 f = s; + auto p = cast(uint*)&f; + foreach (i; 0 .. 8) + assert(p[i] == s); +} + +void foo_long4(long t, long s, long u) +{ + long4 f = s; + auto p = cast(long*)&f; + foreach (i; 0 .. 4) + assert(p[i] == s); +} + +void foo_ulong4(ulong t, ulong s) +{ + ulong4 f = s; + auto p = cast(ulong*)&f; + foreach (i; 0 .. 4) + assert(p[i] == s); +} + +void foo_float8(float t, float s) +{ + float8 f = s; + auto p = cast(float*)&f; + foreach (i; 0 .. 8) + assert(p[i] == s); +} + +void foo_double4(double t, double s, double u) +{ + double4 f = s; + auto p = cast(double*)&f; + foreach (i; 0 .. 4) + assert(p[i] == s); +} + +void test16448_32() +{ + import core.cpuid; + if (!core.cpuid.avx) + return; + + foo_byte32(5, -10); + foo_ubyte32(5, 11); + + foo_short16(5, -6); + foo_short16(5, 7); + + foo_int8(5, -6); + foo_uint8(5, 0x12345678, 22); + + foo_long4(5, -6, 1); + foo_ulong4(5, 0x12345678_87654321L); + + foo_float8(5, -6); + foo_double4(5, -6, 2); +} + + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=16703 + +float index(float4 f4, size_t i) +{ + return f4[i]; + //return (*cast(float[4]*)&f4)[2]; +} + +float[4] slice(float4 f4) +{ + return f4[]; +} + +float slice2(float4 f4, size_t lwr, size_t upr, size_t i) +{ + float[] fa = f4[lwr .. upr]; + return fa[i]; +} + +void test16703() +{ + float4 f4 = [1,2,3,4]; + assert(index(f4, 0) == 1); + assert(index(f4, 1) == 2); + assert(index(f4, 2) == 3); + assert(index(f4, 3) == 4); + + float[4] fsa = slice(f4); + assert(fsa == [1.0f,2,3,4]); + + assert(slice2(f4, 1, 3, 0) == 2); + assert(slice2(f4, 1, 3, 1) == 3); +} + +/*****************************************/ + +struct Sunsto +{ + align (1): // make sure f4 is misaligned + byte b; + union + { + float4 f4; + ubyte[16] a; + } +} + +ubyte[16] foounsto() +{ + float4 vf = 6; + Sunsto s; + s.f4 = vf * 2; + vf = s.f4; + + return s.a; +} + +void testOPvecunsto() +{ + auto a = foounsto(); + assert(a == [0, 0, 64, 65, 0, 0, 64, 65, 0, 0, 64, 65, 0, 0, 64, 65]); +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=10447 + +void test10447() +{ + immutable __vector(double[2]) a = [1.0, 2.0]; + __vector(double[2]) r; + r += a; + r = r * a; +} + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17237 + +struct S17237 +{ + bool a; + struct + { + bool b; + int8 c; + } +} + +static assert(S17237.a.offsetof == 0); +static assert(S17237.b.offsetof == 32); +static assert(S17237.c.offsetof == 64); + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=16697 + +static assert(!is(float == __vector)); +static assert(!is(float[1] == __vector)); +static assert(!is(float[4] == __vector)); +static assert( is(__vector(float[4]) == __vector)); +static assert(!is(__vector(float[3]) == __vector)); +static assert(!is(__vector(float[5]) == __vector)); +static assert( is(__vector(float[4]) X == __vector) && is(X == float[4])); +static assert( is(__vector(byte[16]) X == __vector) && is(X == byte[16])); + +/*****************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17720 + +void test17720() +{ + alias Vector16s = TypeTuple!( + void16, byte16, short8, int4, long2, + ubyte16, ushort8, uint4, ulong2, float4, double2); + alias Vector32s = TypeTuple!( + void32, byte32, short16, int8, long4, + ubyte32, ushort16, uint8, ulong4, float8, double4); + + // OK: __vector(T) -> __vector(void[]) of same size. + // NG: __vector(T) -> __vector(void[]) of different size. + // NG: explicit cast __vector(T) -> __vector(void[]) of different size. + foreach (V; Vector16s) + { + static assert( __traits(compiles, { void16 v = V.init; })); + static assert(!__traits(compiles, { void32 v = V.init; })); + static assert(!__traits(compiles, { void32 v = cast(void32)V.init; })); + } + foreach (V; Vector32s) + { + static assert( __traits(compiles, { void32 v = V.init; })); + static assert(!__traits(compiles, { void16 v = V.init; })); + static assert(!__traits(compiles, { void16 v = cast(void16)V.init; })); + } + + // NG: __vector(T) -> __vector(T) of same size. + // OK: explicit cast __vector(T) -> __vector(T) of same size. + // NG: __vector(T) -> __vector(T) of different size. + // NG: explicit cast __vector(T) -> __vector(T) of different size. + foreach (V; Vector16s) + { + static if (is(V == double2)) + { + static assert(!__traits(compiles, { long2 v = V.init; })); + static assert( __traits(compiles, { long2 v = cast(long2)V.init; })); + } + else + { + static assert(!__traits(compiles, { double2 v = V.init; })); + static assert( __traits(compiles, { double2 v = cast(double2)V.init; })); + } + static assert(!__traits(compiles, { double4 v = V.init; })); + static assert(!__traits(compiles, { double4 v = cast(double4)V.init; })); + } + foreach (V; Vector32s) + { + static if (is(V == double4)) + { + static assert(!__traits(compiles, { long4 v = V.init; })); + static assert( __traits(compiles, { long4 v = cast(long4)V.init; })); + } + else + { + static assert(!__traits(compiles, { double4 v = V.init; })); + static assert( __traits(compiles, { double4 v = cast(double4)V.init; })); + } + static assert(!__traits(compiles, { double2 v = V.init; })); + static assert(!__traits(compiles, { double2 v = cast(double2)V.init; })); + } +} + +/*****************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=17695 + +void test17695(__vector(ubyte[16]) a) +{ + auto b = -a; +} + +/*****************************************/ + +int main() +{ + test1(); + test2(); + test2b(); + test2c(); + test2d(); + test2e(); + test2f(); + test2g(); + test2h(); + test2i(); + test2j(); + + test4(); + test7411(); + + test7951(); + test7951_2(); + test7414(); + test7413(); + test7413_2(); +// test9200(); + test9304(); + test9910(); + test12852(); + test9449(); + test9449_2(); + test13988(); + test16448(); + test16448_32(); + test16703(); + testOPvecunsto(); + test10447(); + + return 0; +} diff --git a/gcc/testsuite/gdc.test/compilable/99bottles.d b/gcc/testsuite/gdc.test/compilable/99bottles.d new file mode 100644 index 00000000000..e7d2f77500e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/99bottles.d @@ -0,0 +1,52 @@ +// written by Don Clugston: +// http://www.digitalmars.com/d/archives/digitalmars/D/announce/4374.html +// http://www.99-bottles-of-beer.net/language-d-1212.html + +// Displays the "99 bottles of beer" song at compile time, +// using the template metaprograming facilities of D. +// No executable is generated. No libraries are used. +// Illustrates template default values, template string value parameters, +// compile-time concatenation of constant strings, static if. + +module bottles99; + +template decimaldigit(int n) { + const string decimaldigit = "0123456789"[n..n+1]; +} + +template itoa(ulong n) +{ + static if ( n < 10L ) + const string itoa = decimaldigit!(n); + else + const string itoa = itoa!( n / 10L ) ~ decimaldigit!( n % 10L ); +} + +template showHowMany(int n, string where, bool needcapital = false) +{ + static if ( n > 1 ) + const string showHowMany = itoa!(n) ~ " bottles of beer" ~ where ~ "\n"; + else static if ( n == 1 ) + const string showHowMany = "1 bottle of beer" ~ where ~ "\n"; + else static if ( needcapital ) + const string showHowMany = "No more bottles of beer" ~ where ~ "\n"; + else + const string showHowMany = "no more bottles of beer" ~ where ~ "\n"; +} + +template beer(int maxbeers, int n = maxbeers) +{ + static if ( n > 0 ) + const string beer = showHowMany!(n, " on the wall,", true) + ~ showHowMany!(n, ".") + ~ "Take one down and pass it around, " ~ "\n" + ~ showHowMany!( n - 1 , " on the wall.") + ~ "\n" ~ beer!(maxbeers, n - 1); // recurse for subsequent verses. + else + const string beer = showHowMany!(n, " on the wall,", true) + ~ showHowMany!(n, ".") + ~ "Go to the store and buy some more, " ~ "\n" + ~ showHowMany!( maxbeers, " on the wall."); +} + +pragma(msg, beer!(99)); diff --git a/gcc/testsuite/gdc.test/compilable/a3682.d b/gcc/testsuite/gdc.test/compilable/a3682.d new file mode 100644 index 00000000000..69191ec20a2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/a3682.d @@ -0,0 +1,20 @@ +// EXTRA_SOURCES: imports/b3682.d +// PERMUTE_ARGS: + +// 3682 + +struct Tuple(Types...) +{ + Tuple!(Types[0..1]) slice()() + { + Tuple!(Types[0..1]) x; + return x; + } + + void fail() + { + Tuple!(float, double, int) a; + auto s = a.slice(); + static assert(is(typeof(s) == Tuple!(float))); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/aggr_alignment.d b/gcc/testsuite/gdc.test/compilable/aggr_alignment.d new file mode 100644 index 00000000000..3a80a039e26 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/aggr_alignment.d @@ -0,0 +1,28 @@ +struct S1 // overall alignment: max(1, 1) = 1 +{ + byte[5] bytes; + struct // overall alignment: max(1, 1) = 1 + { + byte byte1; + align(1) int int1; + } +} + +static assert(S1.int1.offsetof == 6); +static assert(S1.alignof == 1); +static assert(S1.sizeof == 10); + +class C2 // overall alignment: max(vtbl.alignof, monitor.alignof, 1, 2) +{ + byte[5] bytes; + struct // overall alignment: max(1, 2) = 2 + { + byte byte1; + align(2) int int1; + } +} + +enum payloadOffset = C2.bytes.offsetof; +static assert(C2.int1.offsetof == payloadOffset + 8); +static assert(C2.alignof == size_t.sizeof); +static assert(__traits(classInstanceSize, C2) == payloadOffset + 12); diff --git a/gcc/testsuite/gdc.test/compilable/aliasdecl.d b/gcc/testsuite/gdc.test/compilable/aliasdecl.d new file mode 100644 index 00000000000..90e21effac3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/aliasdecl.d @@ -0,0 +1,40 @@ +template Test(T){ alias Type = T; } + +alias X1 = int; +static assert(is(X1 == int)); + +alias X2 = immutable(long)[], X3 = shared const double[int]; +static assert(is(X2 == immutable(long)[])); +static assert(is(X3 == shared const double[int])); + +alias X4 = void delegate() const, X5 = Test!int; +static assert(is(X4 == void delegate() const)); +static assert(is(X5.Type == int)); + +alias FP5 = extern(C) pure nothrow @safe @nogc void function(), + DG5 = extern(D) pure nothrow @safe @nogc void delegate(); +static assert(FP5.stringof == "extern (C) void function() pure nothrow " /* ~ "@safe " */ ~ "@nogc"); +static assert(DG5.stringof == "void delegate() pure nothrow " /* ~ "@safe " */ ~ "@nogc"); + +void main() +{ + alias Y1 = int; + static assert(is(Y1 == int)); + + alias Y2 = immutable(long)[], Y3 = shared const double[int]; + static assert(is(Y2 == immutable(long)[])); + static assert(is(Y3 == shared const double[int])); + + alias Y4 = void delegate() const, Y5 = Test!int; + static assert(is(Y4 == void delegate() const)); + static assert(is(Y5.Type == int)); + + /+ struct S + { + int value; + alias this = value; + } + auto s = S(10); + int n = s; + assert(n == 10); +/ +} diff --git a/gcc/testsuite/gdc.test/compilable/alignment.d b/gcc/testsuite/gdc.test/compilable/alignment.d new file mode 100644 index 00000000000..c5cc394866f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/alignment.d @@ -0,0 +1,12 @@ +/* Test alignment of stack variables. + * + * This test should be moved to "runnable" once DMD implements alignment of stack variables. + */ + +void main() +{ + byte dummy; + + align(32) int align32; + assert((cast(size_t)&align32 & cast(size_t)0b11111) == 0); +} diff --git a/gcc/testsuite/gdc.test/compilable/art4769.d b/gcc/testsuite/gdc.test/compilable/art4769.d new file mode 100644 index 00000000000..b9620588eaa --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/art4769.d @@ -0,0 +1,19 @@ +// http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.bugs&article_id=4769 + +// EXTRA_SOURCES: imports/art4769a.d imports/art4769b.d +// PERMUTE_ARGS: + +module art4769; + +private import imports.art4769a; + +struct Vector(T) +{ + DataStreamability!(T).footype f; + + static if (DataStreamability!(T).isStreamable) + void writeTo() + { + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/b11118.d b/gcc/testsuite/gdc.test/compilable/b11118.d new file mode 100644 index 00000000000..1c6c6a28b04 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b11118.d @@ -0,0 +1,12 @@ +struct X(size_t Z) +{ + void set(T)(T[Z] v...) + { + } +} + +void main() +{ + X!3 a; + a.set(1,2,3); +} diff --git a/gcc/testsuite/gdc.test/compilable/b1215.d b/gcc/testsuite/gdc.test/compilable/b1215.d new file mode 100644 index 00000000000..d3b0ccd2e4a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b1215.d @@ -0,0 +1,146 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -o- + +struct A(Args...) +{ + enum i = 1; + + // base use case. + Args[0].T mBase; + static assert(is(typeof(mBase) == B.T)); + // chained types + Args[0].T.TT mChain; + static assert(is(typeof(mChain) == B.T.TT)); + // chained packs + Args[1+1].FArgs[0] mChainPack; + static assert(is(typeof(mChainPack) == B)); + // expr + enum mExpr = Args[1].i; + static assert(mExpr == B.i); + // Nested + index eval + Args[Args[0].i2].T mNested; + static assert(is(typeof(mNested) == B.T)); + // index with constexpr + Args[i].T mCEIndex; + static assert(is(typeof(mCEIndex) == B.T)); + // Nested + index with constexpr + Args[Args[i].i2].T mNestedCE; + static assert(is(typeof(mNestedCE) == B.T)); + + // alias, base use case + alias UBase = Args[0].T; + static assert(is(UBase == B.T)); + // alias, chained types + alias UChain = Args[0].T.TT; + static assert(is(UChain == B.T.TT)); + // alias, chained packs + alias UChainPack = Args[1+1].FArgs[0]; + static assert(is(UChainPack == B)); + // alias, expr + alias uExpr = Args[1].i; + static assert(uExpr == B.i); + // alias, Nested + index eval + alias UNested = Args[Args[0].i2].T; + static assert(is(UNested == B.T)); + // alias, index with constexpr + alias UCEIndex = Args[i].T; + static assert(is(UCEIndex == B.T)); + // alias, Nested + index with constexpr + alias UNextedCE = Args[Args[i].i2].T; + static assert(is(UNextedCE == B.T)); +} + +struct B +{ + struct T + { + struct TT + { + } + } + enum i = 6; + enum i2 = 0; +} + +struct C(Args...) +{ + alias FArgs = Args; +} + +alias Z = A!(B,B,C!(B,B)); + +/***************************************************/ +// 14889 + +struct A14889(alias Exc) +{ + alias ExceptionType = Exc; +} +alias TT14889(Args...) = Args; + +alias X14889a = TT14889!(A14889!Throwable()); +alias Y14889a = X14889a[0].ExceptionType; + +alias X14889b = TT14889!(A14889!Throwable); +alias Y14889b = X14889b[0].ExceptionType; + +/***************************************************/ +// 14889 + +alias TypeTuple14900(T...) = T; + +struct S14900 +{ + alias T = int; + alias U = TypeTuple14900!(long,string); +} + +alias Types14900 = TypeTuple14900!(S14900, S14900); + +Types14900[0].T a14900; // Types[0] == S, then typeof(a) == S.T == int +Types14900[0].U[1] b14900; // Types[0].U == S.U, then typeof(b) == S.U[1] == string + +void test14900() +{ + Types14900[0].T a; // Types[0] == S, then typeof(a) == S.T == int + Types14900[0].U[1] b; // Types[0].U == S.U, then typeof(b) == S.U[1] == string +} + +/***************************************************/ +// 14911 + +void test14911() +{ + struct S {} + + int* buf1 = new int[2].ptr; // OK + S* buf2 = (new S[2]).ptr; // OK + S* buf3 = new S[2].ptr; // OK <- broken +} + +/***************************************************/ +// 14986 + +alias Id14986(alias a) = a; + +struct Foo14986 +{ + int tsize; +} +struct Bar14986 +{ + enum Foo14986[] arr = [Foo14986()]; +} + +Bar14986 test14986() +{ + Foo14986[] types; + auto a1 = new void[types[0].tsize]; // TypeIdentifier::toExpression + auto a2 = new void[Id14986!types[0].tsize]; // TypeInstance::toExpression + + Bar14986 bar; + auto a3 = Id14986!(typeof(bar).arr[0].tsize); // TypeTypeof::resolve + auto a4 = Id14986!(typeof(return).arr[0].tsize); // TypeReturn::resolve + + return Bar14986(); +} diff --git a/gcc/testsuite/gdc.test/compilable/b15428.d b/gcc/testsuite/gdc.test/compilable/b15428.d new file mode 100644 index 00000000000..f339a755b26 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b15428.d @@ -0,0 +1,13 @@ +class A +{ + this() {} +} + +class B : A +{ + this() + { + static if (__traits(compiles, super())) + super(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/b16244.d b/gcc/testsuite/gdc.test/compilable/b16244.d new file mode 100644 index 00000000000..7840095ca63 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16244.d @@ -0,0 +1,12 @@ +struct Foo +{ + void bar()(typeof(cast()this) x) + { + } +} + +void main() +{ + Foo x; + x.bar(x); +} diff --git a/gcc/testsuite/gdc.test/compilable/b16346.d b/gcc/testsuite/gdc.test/compilable/b16346.d new file mode 100644 index 00000000000..fb8742b5f55 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16346.d @@ -0,0 +1,3 @@ +enum A { B } +static assert(is(typeof(A.B) == A)); +static assert(is(typeof(A(A.B)) == A)); diff --git a/gcc/testsuite/gdc.test/compilable/b16355.d b/gcc/testsuite/gdc.test/compilable/b16355.d new file mode 100644 index 00000000000..429c9561440 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16355.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -c +struct S0 { this(this) {} } +struct S1 { S0[2] x; } +struct S2 { S0[0] x; } + +// S0 has an explicit and a compiler-generated postblit +static assert( __traits(hasMember, S0, "__postblit")); +static assert( __traits(hasMember, S0, "__xpostblit")); +// S1 has only the compiler-generated postblit +static assert(!__traits(hasMember, S1, "__postblit")); +static assert( __traits(hasMember, S1, "__xpostblit")); +// S2 has no postblit at all since the x array has zero length +static assert(!__traits(hasMember, S2, "__postblit")); +static assert(!__traits(hasMember, S2, "__xpostblit")); diff --git a/gcc/testsuite/gdc.test/compilable/b16382.d b/gcc/testsuite/gdc.test/compilable/b16382.d new file mode 100644 index 00000000000..08726cb8272 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16382.d @@ -0,0 +1,6 @@ +// REQUIRED_ARGS: -c +struct S0 { + void foo() { + pragma(msg, &this); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/b16483.d b/gcc/testsuite/gdc.test/compilable/b16483.d new file mode 100644 index 00000000000..2bfc2ef1cd1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16483.d @@ -0,0 +1,12 @@ +struct S +{ + enum a = is(typeof(false.bar!(x => x))); // The lambda compiles + enum b = is(typeof(false.bar!(x => y))); // The lambda doesn't compile +} +auto bar(alias foo)(bool var) +{ + return foo(var); +} +static assert(is(typeof(S.a) == bool)); +static assert(S.a == true); +static assert(S.b == false); diff --git a/gcc/testsuite/gdc.test/compilable/b16598.d b/gcc/testsuite/gdc.test/compilable/b16598.d new file mode 100644 index 00000000000..67cd7f5e8dd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16598.d @@ -0,0 +1,15 @@ +struct S +{ + this(int) {} + ~this() {} +} + +int g(S a, S b) +{ + return 1; +} + +void main() +{ + true ? g(S(), S(1)) : {}(); +} diff --git a/gcc/testsuite/gdc.test/compilable/b16697.d b/gcc/testsuite/gdc.test/compilable/b16697.d new file mode 100644 index 00000000000..78c9a2b1560 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16697.d @@ -0,0 +1,13 @@ +version(D_SIMD) +{ + static assert(!is( float == __vector)); + static assert(!is( float[1] == __vector)); + static assert(!is( float[4] == __vector)); + static assert( is(__vector(float[4]) == __vector)); + static assert(!is(__vector(float[3]) == __vector)); + static assert(!is(__vector(float[5]) == __vector)); + static assert( is(__vector(float[4]) X == __vector) && + is(X == float[4])); + static assert( is(__vector(byte[16]) X == __vector) && + is(X == byte[16])); +} diff --git a/gcc/testsuite/gdc.test/compilable/b16967.d b/gcc/testsuite/gdc.test/compilable/b16967.d new file mode 100644 index 00000000000..2b02fc3abb8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b16967.d @@ -0,0 +1,33 @@ +/* + * REQUIRED_ARGS: -c + * TEST_OUTPUT: +--- +compilable/b16967.d(16): Deprecation: switch case fallthrough - use 'goto default;' if intended +compilable/b16967.d(26): Deprecation: switch case fallthrough - use 'goto default;' if intended +--- +*/ +int foo(int x) +in +{ + switch (x) + { + case 1: + assert(x != 0); + default: + break; + } +} +out(v) +{ + switch(v) + { + case 42: + assert(x != 0); + default: + break; + } +} +body +{ + return 42; +} diff --git a/gcc/testsuite/gdc.test/compilable/b17111.d b/gcc/testsuite/gdc.test/compilable/b17111.d new file mode 100644 index 00000000000..54091249d60 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b17111.d @@ -0,0 +1,13 @@ +alias TestType = ubyte; + +void test() +{ + TestType a,b,c; + + switch(c) + { + case a: break; + case (cast(ushort)b): break; + default: assert(false); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/b33.d b/gcc/testsuite/gdc.test/compilable/b33.d new file mode 100644 index 00000000000..d422959d51e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b33.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: imports/b33a.d +// PERMUTE_ARGS: + +module b33; + +private import imports.b33a; + +size_t fn() +{ + return find( "123" ); +} + diff --git a/gcc/testsuite/gdc.test/compilable/b6227.d b/gcc/testsuite/gdc.test/compilable/b6227.d new file mode 100644 index 00000000000..6ec2dd0a3de --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b6227.d @@ -0,0 +1,18 @@ +/* TEST_OUTPUT: +--- +compilable/b6227.d(17): Deprecation: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` +compilable/b6227.d(18): Deprecation: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` +--- +*/ +enum X { + O, + R +} +enum Y { + U +} +static assert( (X.O == cast(const)X.O)); +static assert( (X.O == X.O)); +static assert( (X.O != X.R)); +static assert(!(X.O != Y.U)); +static assert( (X.O == Y.U)); diff --git a/gcc/testsuite/gdc.test/compilable/b6395.d b/gcc/testsuite/gdc.test/compilable/b6395.d new file mode 100644 index 00000000000..afbe3f19b9b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b6395.d @@ -0,0 +1,25 @@ +// REQUIRED_ARGS: -Icompilable/extra-files +// EXTRA_FILES: extra-files/c6395.d + +// 6395 + +import c6395; + +int regex(string pattern) +{ + return 0; +} + +bool match(string r) +{ + return true; +} + +void applyNoRemoveRegex() +{ + void scan(string[] noRemoveStr, string e) + { + auto a = find!((a){return match(e);})(map!regex(noRemoveStr)); + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/b6400.d b/gcc/testsuite/gdc.test/compilable/b6400.d new file mode 100644 index 00000000000..2c71107e913 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b6400.d @@ -0,0 +1,37 @@ +/* TEST_OUTPUT: +--- +Foo +Bar +--- +*/ +class Foo +{ + void opDispatch(string name)() { pragma(msg, "Foo"); } +} +class Bar +{ + void opDispatch(string name)() { pragma(msg, "Bar"); } +} +class Baz +{ +} + +void main() +{ + auto foo = new Foo; + auto bar = new Bar; + auto baz = new Baz; + + with (foo) + { + f0(); + with (bar) + { + f1(); + } + with (baz) + { + static assert(!__traits(compiles, f2())); + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/betterCarray.d b/gcc/testsuite/gdc.test/compilable/betterCarray.d new file mode 100644 index 00000000000..74c80be3b95 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/betterCarray.d @@ -0,0 +1,17 @@ +/* REQUIRED_ARGS: -betterC + PERMUTE_ARGS: +*/ + +import core.stdc.stdio; + +extern (C) int main(char** argv, int argc) { + printf("hello world\n"); + int[3] a; + foo(a[], 3); + return 0; +} + +int foo(int[] a, int i) +{ + return a[i]; +} diff --git a/gcc/testsuite/gdc.test/compilable/betterCswitch.d b/gcc/testsuite/gdc.test/compilable/betterCswitch.d new file mode 100644 index 00000000000..ab0fb0ab2ef --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/betterCswitch.d @@ -0,0 +1,16 @@ +import core.stdc.stdio; + +extern (C) int main(char** argv, int argc) { + printf("hello world\n"); + foo(3); + return 0; +} + +int foo(int i) +{ + final switch (i) + { + case 1: break; + } + return i; +} diff --git a/gcc/testsuite/gdc.test/compilable/bug11735.d b/gcc/testsuite/gdc.test/compilable/bug11735.d new file mode 100644 index 00000000000..b94cb6e77da --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/bug11735.d @@ -0,0 +1,36 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: + +/* +TEST_OUTPUT: +--- +print string +print wstring +print dstring +يطبع الترميز الموحد +يطبع الترميز الموحد +يطبع الترميز الموحد +foo_str +foo_wstr +foo_dstr +--- +*/ + +pragma(msg, "print string"); +pragma(msg, "print wstring"w); +pragma(msg, "print dstring"d); + +pragma(msg, "يطبع الترميز الموحد"); +pragma(msg, "يطبع الترميز الموحد"w); +pragma(msg, "يطبع الترميز الموحد"d); + +void main() +{ + enum a = "foo_str"; + enum b = "foo_wstr"w; + enum c = "foo_dstr"d; + + pragma(msg, a); + pragma(msg, b); + pragma(msg, c); +} diff --git a/gcc/testsuite/gdc.test/compilable/bug6963.d b/gcc/testsuite/gdc.test/compilable/bug6963.d new file mode 100644 index 00000000000..33d595cfedb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/bug6963.d @@ -0,0 +1,73 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: + +/* +TEST_OUTPUT: +--- +output foo: 1e: pure nothrow @nogc @safe void(int x) +output foo: 3e: pure nothrow @nogc @safe void(int x) +--- +*/ + +alias void function(int) pure nothrow @safe @nogc FuncPtrType; + +void foo1a(X)(X x) {} +void foo1b(X)(X x) {} +void foo1c(X)(X x) {} +void foo1d(X)(X x) {} +void foo1e(X)(X x) {} + +// module level declaration with type inference +auto fptr1 = &foo1a!int; +static assert(is(typeof(fptr1) == FuncPtrType)); + +// array initializer +auto fptrlist1 = [&foo1b!int]; +static assert(is(typeof(fptrlist1) == FuncPtrType[])); + +// static assert +static assert(is(typeof(&foo1c!int) == FuncPtrType)); + +// static if +static if(is(typeof(&foo1d!int) PF)) + static assert(is(PF == FuncPtrType)); +else + static assert(0); + +// pragma test +pragma(msg, "output foo: 1e: ", typeof(foo1e!int).stringof); + +void foo2a(X)(X x) {} +void foo2b(X)(X x) {} +void foo2c(X)(X x) {} + +FuncPtrType fptr3 = &foo2a!int; // most similar to original issue + +FuncPtrType[] fptrlist3 = [&foo2b!int]; + +struct S{ FuncPtrType fp; } +S s = { &foo2c!int }; + +void foo3a(X)(X x) {} +void foo3b(X)(X x) {} +void foo3c(X)(X x) {} +void foo3d(X)(X x) {} +void foo3e(X)(X x) {} + +void main() +{ + auto fptr2 = &foo3a!int; + static assert(is(typeof(fptr2) == FuncPtrType)); + + auto fptrlist2 = [&foo3b!int]; + static assert(is(typeof(fptrlist2) == FuncPtrType[])); + + static assert(is(typeof(&foo1c!int) == FuncPtrType)); + + static if(is(typeof(&foo1d!int) PF)) + static assert(is(PF == FuncPtrType)); + else + static assert(0); + + pragma(msg, "output foo: 3e: ", typeof(foo3e!int)); +} diff --git a/gcc/testsuite/gdc.test/compilable/callconv.d b/gcc/testsuite/gdc.test/compilable/callconv.d new file mode 100644 index 00000000000..fbb78ed7c39 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/callconv.d @@ -0,0 +1,75 @@ +// PERMUTE_ARGS: + +import core.stdc.stdarg; + +struct ABC +{ + int x[4]; +} + +ABC abc; + +int x,y,z; + +extern (Pascal): +ABC test1(int xx, int yy, int zz) +{ + x = xx; + y = yy; + z = zz; + return abc; +} + +extern (Pascal): +ABC test1v(int xx, int yy, int zz, ...) +{ + x = xx; + y = yy; + z = zz; + return abc; +} + +extern (C): +ABC test2v(int xx, int yy, int zz, ...) +{ + x = xx; + y = yy; + z = zz; + return abc; +} + +extern (C++): +ABC test3(int xx, int yy, int zz) +{ + x = xx; + y = yy; + z = zz; + return abc; +} + +ABC test3v(int xx, int yy, int zz, ...) +{ + x = xx; + y = yy; + z = zz; + return abc; +} + +extern (D): +ABC test4(int xx, int yy, int zz) +{ + x = xx; + y = yy; + z = zz; + return abc; +} + +ABC test4v(int xx, int yy, int zz, ...) +{ + x = xx; + y = yy; + z = zz; + return abc; +} + + diff --git a/gcc/testsuite/gdc.test/compilable/compile1.d b/gcc/testsuite/gdc.test/compilable/compile1.d new file mode 100644 index 00000000000..61669c2090c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/compile1.d @@ -0,0 +1,964 @@ +// PERMUTE_ARGS: + +/************************************************** + 1748 class template with stringof +**************************************************/ + +struct S1748(T) {} +static assert(S1748!int.stringof == "S1748!int"); + +class C1748(T) {} +static assert(C1748!int.stringof == "C1748!int"); + +/************************************************** + 2354 pragma + single semicolon DeclarationBlock +**************************************************/ + +version(all) + pragma(msg, "true"); +else + pragma(msg, "false"); + +/************************************************** + 2438 +**************************************************/ + +alias void delegate() Dg2438; + +alias typeof(Dg2438.ptr) CP2438a; +alias typeof(Dg2438.funcptr) FP2438a; +static assert(is(CP2438a == void*)); +static assert(is(FP2438a == void function())); + +alias typeof(Dg2438.init.ptr) CP2438b; +alias typeof(Dg2438.init.funcptr) FP2438b; +static assert(is(CP2438b == void*)); +static assert(is(FP2438b == void function())); + +/************************************************** + 4225 +**************************************************/ + +struct Foo4225 +{ + enum x = Foo4225(); + + static Foo4225 opCall() + { + return Foo4225.init; + } +} + +/************************************************** + 5996 ICE(expression.c) +**************************************************/ + +template T5996(T) +{ + auto bug5996() { + if (anyOldGarbage) {} + return 2; + } +} +static assert(!is(typeof(T5996!(int).bug5996()))); + +/************************************************** + 8532 segfault(mtype.c) - type inference + pure +**************************************************/ +auto segfault8532(Y, R ...)(R r, Y val) pure +{ return segfault8532(r, val); } + +static assert(!is(typeof( segfault8532(1,2,3)))); + +/************************************************** + 8982 ICE(ctfeexpr.c) __parameters with error in default value +**************************************************/ +template ice8982(T) +{ + void bug8982(ref const int v = 7){} + + static if (is(typeof(bug8982) P == __parameters)) { + pragma(msg, ((P[0..1] g) => g[0])()); + } +} + +static assert(!is(ice8982!(int))); + + +/************************************************** + 8801 ICE assigning to __ctfe +**************************************************/ +static assert(!is(typeof( { bool __ctfe= true; }))); +static assert(!is(typeof( { __ctfe |= true; }))); + +/************************************************** + 5932 ICE(s2ir.c) + 6675 ICE(glue.c) +**************************************************/ + +void bug3932(T)() { + static assert( 0 ); + func5932( 7 ); +} + +void func5932(T)( T val ) { + void onStandardMsg() { + foreach( t; T ) { } + } +} + +static assert(!is(typeof( + { + bug3932!(int)(); + }() +))); + +/************************************************** + 6650 ICE(glue.c) or wrong-code +**************************************************/ + +auto bug6650(X)(X y) +{ + X q; + q = "abc"; + return y; +} + +static assert(!is(typeof(bug6650!(int)(6)))); +static assert(!is(typeof(bug6650!(int)(18)))); + +/************************************************** + 14710 VC-built DMD crashes on templated variadic function IFTI +**************************************************/ + +void bug14710a(T)(T val, T[] arr...) +{ +} + +void bug14710b() +{ + bug14710a("", ""); +} + +/************************************************** + 6661 Templates instantiated only through is(typeof()) shouldn't cause errors +**************************************************/ + +template bug6661(Q) +{ + int qutz(Q y) + { + Q q = "abc"; + return 67; + } + static assert(qutz(13).sizeof!=299); + const Q blaz = 6; +} + +static assert(!is(typeof(bug6661!(int).blaz))); + +template bug6661x(Q) +{ + int qutz(Q y) + { + Q q = "abc"; + return 67; + } +} +// should pass, but doesn't in current +//static assert(!is(typeof(bug6661x!(int)))); + +/************************************************** + 6599 ICE(constfold.c) or segfault +**************************************************/ + +string bug6599extraTest(string x) { return x ~ "abc"; } + +template Bug6599(X) +{ + class Orbit + { + Repository repository = Repository(); + } + + struct Repository + { + string fileProtocol = "file://"; + string blah = bug6599extraTest("abc"); + string source = fileProtocol ~ "/usr/local/orbit/repository"; + } +} + +static assert(!is(typeof(Bug6599!int))); + +/************************************************** + 8422 TypeTuple of tuples can't be read at compile time +**************************************************/ + +template TypeTuple8422(TList...) +{ + alias TList TypeTuple8422; +} + +struct S8422 { int x; } + +void test8422() +{ + enum a = S8422(1); + enum b = S8422(2); + enum c = [1,2,3]; + foreach(t; TypeTuple8422!(b, a)) { + enum u = t; + } + foreach(t; TypeTuple8422!(c)) { + enum v = t; + } +} + +/************************************************** + 6096 ICE(el.c) with -O +**************************************************/ + +cdouble c6096; + +int bug6096() +{ + if (c6096) return 0; + return 1; +} + +/************************************************** + 7681 Segfault +**************************************************/ + +static assert( !is(typeof( (){ + undefined ~= delegate(){}; return 7; + }()))); + +/************************************************** + 8639 Buffer overflow +**************************************************/ + +void t8639(alias a)() {} +void bug8639() { + t8639!({auto r = -real.max;})(); +} + +/************************************************** + 7751 Segfault +**************************************************/ + +static assert( !is(typeof( (){ + bar[]r; r ~= []; + return 7; + }()))); + +/************************************************** + 7639 Segfault +**************************************************/ + +static assert( !is(typeof( (){ + enum foo = + [ + str : "functions", + ]; +}))); + +/************************************************** + 11991 +**************************************************/ + +void main() +{ + int Throwable; + int object; + try + { + } + catch + { + } +} + +/************************************************** + 11939 +**************************************************/ + +void test11939() +{ + scope(failure) + { + import object : Object; + } + throw new Exception(""); +} + +/************************************************** + 5796 +**************************************************/ + +template A(B) { + pragma(msg, "missing ;") + enum X = 0; +} + +static assert(!is(typeof(A!(int)))); + +/************************************************** + 6720 +**************************************************/ +void bug6720() { } + +static assert(!is(typeof( +cast(bool)bug6720() +))); + +/************************************************** + 1099 +**************************************************/ + +template Mix1099(int a) { + alias typeof(this) ThisType; + static assert (ThisType.init.tupleof.length == 2); +} + + +struct Foo1099 { + mixin Mix1099!(0); + int foo; + mixin Mix1099!(1); + int bar; + mixin Mix1099!(2); +} + +/************************************************** + 8788 - super() and return +**************************************************/ + +class B8788 { + this ( ) { } +} + +class C8788(int test) : B8788 +{ + this ( int y ) + { // TESTS WHICH SHOULD PASS + static if (test == 1) { + if (y == 3) { + super(); + return; + } + super(); + return; + } else static if (test == 2) { + if (y == 3) { + super(); + return; + } + super(); + } else static if (test == 3) { + if (y > 3) { + if (y == 7) { + super(); + return; + } + super(); + return; + } + super(); + } else static if (test == 4) { + if (y > 3) { + if (y == 7) { + super(); + return; + } + else if (y> 5) + super(); + else super(); + return; + } + super(); + } + // TESTS WHICH SHOULD FAIL + else static if (test == 5) { + if (y == 3) { + super(); + return; + } + return; // no super + } else static if (test == 6) { + if (y > 3) { + if (y == 7) { + super(); + return; + } + super(); + } + super(); // two calls + } else static if (test == 7) { + if (y == 3) { + return; // no super + } + super(); + } else static if (test == 8) { + if (y > 3) { + if (y == 7) { + return; // no super + } + super(); + return; + } + super(); + } else static if (test == 9) { + if (y > 3) { + if (y == 7) { + super(); + return; + } + else if (y> 5) + super(); + else return; // no super + return; + } + super(); + } + } +} + +static assert( is(typeof( { new C8788!(1)(0); } ))); +static assert( is(typeof( { new C8788!(2)(0); } ))); +static assert( is(typeof( { new C8788!(3)(0); } ))); +static assert( is(typeof( { new C8788!(4)(0); } ))); +static assert(!is(typeof( { new C8788!(5)(0); } ))); +static assert(!is(typeof( { new C8788!(6)(0); } ))); +static assert(!is(typeof( { new C8788!(7)(0); } ))); +static assert(!is(typeof( { new C8788!(8)(0); } ))); +static assert(!is(typeof( { new C8788!(9)(0); } ))); + +/************************************************** + 4967, 7058 +**************************************************/ + +enum Bug7058 bug7058 = { 1.5f, 2}; +static assert(bug7058.z == 99); + +struct Bug7058 +{ + float x = 0; + float y = 0; + float z = 99; +} + + +/***************************************************/ + +void test12094() +{ + auto n = null; + int *a; + int[int] b; + int[] c; + auto u = true ? null : a; + auto v = true ? null : b; + auto w = true ? null : c; + auto x = true ? n : a; + auto y = true ? n : b; + auto z = true ? n : c; + a = n; + b = n; + c = n; +} + +/***************************************************/ + +template test8163(T...) +{ + struct Point + { + T fields; + } + + enum N = 2; // N>=2 triggers the bug + extern Point[N] bar(); + + void foo() + { + Point[N] _ = bar(); + } +} + +alias test8163!(long) _l; +alias test8163!(double) _d; +alias test8163!(float, float) _ff; +alias test8163!(int, int) _ii; +alias test8163!(int, float) _if; +alias test8163!(ushort, ushort, ushort, ushort) _SSSS; +alias test8163!(ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte, ubyte) _BBBBBBBB; +alias test8163!(ubyte, ubyte, ushort, float) _BBSf; + + +/***************************************************/ +// 4757 + +auto foo4757(T)(T) +{ + static struct Bar(T) + { + void spam() + { + foo4757(1); + } + } + return Bar!T(); +} + +void test4757() +{ + foo4757(1); +} + +/***************************************************/ +// 9348 + +void test9348() +{ + @property Object F(int E)() { return null; } + + assert(F!0 !is null); + assert(F!0 !in [new Object():1]); +} + +/***************************************************/ +// 9690 + +@disable +{ + void dep9690() {} + void test9690() + { + dep9690(); // OK + void inner() + { + dep9690(); // OK <- NG + } + } +} + +/***************************************************/ +// 9987 + +static if (is(object.ModuleInfo == struct)) +{ + struct ModuleInfo {} + + static assert(!is(object.ModuleInfo == ModuleInfo)); + static assert(object.ModuleInfo.sizeof != ModuleInfo.sizeof); +} +static if (is(object.ModuleInfo == class)) +{ + class ModuleInfo {} + + static assert(!is(object.ModuleInfo == ModuleInfo)); + static assert(__traits(classInstanceSize, object.ModuleInfo) != + __traits(classInstanceSize, ModuleInfo)); +} + +/***************************************************/ +// 10158 + +class Outer10158 +{ + static struct Inner + { + int f; + } + + void test() + { + static assert( Inner.f .offsetof == 0); // OK <- NG + static assert((Inner.f).offsetof == 0); // OK + } +} + +void test10158() +{ + static assert(Outer10158.Inner.f.offsetof == 0); // OK +} + +/***************************************************/ +// 10326 + +class C10326 +{ + int val; + invariant { assert(val == 0); } + invariant() { assert(val == 0); } +} + +/***************************************************/ +// 11042 + +static if ((true || error) == true ) {} else { static assert(0); } +static if ((false && error) == false) {} else { static assert(0); } +static assert ((true || error) == true ); +static assert ((false && error) == false); +int f11042a1()() if ((true || error) == true ) { return 0; } enum x11042a1 = f11042a1(); +int f11042b1()() if ((false && error) == false) { return 0; } enum x11042b1 = f11042b1(); + +static if (is(typeof(true || error)) == false) {} else { static assert(0); } +static if (is(typeof(false && error)) == false) {} else { static assert(0); } +static assert (is(typeof(true || error)) == false); +static assert (is(typeof(false && error)) == false); +int f11042a2()() if (is(typeof(true || error)) == false) { return 0; } enum x11042a2 = f11042a2(); +int f11042b2()() if (is(typeof(false && error)) == false) { return 0; } enum x11042b2 = f11042b2(); + +static if (__traits(compiles, true || error) == false) {} else { static assert(0); } +static if (__traits(compiles, false && error) == false) {} else { static assert(0); } +static assert (__traits(compiles, true || error) == false); +static assert (__traits(compiles, false && error) == false); +int f11042a3()() if (__traits(compiles, true || error) == false) { return 0; } enum x11042a3 = f11042a3(); +int f11042b3()() if (__traits(compiles, false && error) == false) { return 0; } enum x11042b3 = f11042b3(); + +/***************************************************/ +// 11554 + +enum E11554; +static assert(is(E11554 == enum)); + +struct Bro11554(N...) {} +static assert(!is(E11554 unused : Bro11554!M, M...)); + +/***************************************************/ +// 12302 + +template isCallable12302(T...) + if (T.length == 1) +{ + static if (is(typeof(& T[0].opCall) == delegate)) + enum bool isCallable12302 = true; + else + static if (is(typeof(& T[0].opCall) V : V*) && is(V == function)) + enum bool isCallable12302 = true; + else + enum bool isCallable12302 = true; +} + +class A12302 +{ + struct X {} + X x; + auto opDispatch(string s, TArgs...)(TArgs args) + { + mixin("return x."~s~"(args);"); + } +} + +A12302 func12302() { return null; } +enum b12302 = isCallable12302!func12302; + +/***************************************************/ +// 12476 + +template A12476(T) { } + +struct S12476(T) +{ + alias B = A12476!T; +} + +class C12476(T) +{ + alias B = A12476!T; +} + +struct Bar12476(alias Foo) +{ + Foo!int baz; + alias baz this; +} + +alias Identity12476(alias A) = A; + +alias sb12476 = Identity12476!(Bar12476!S12476.B); +alias cb12476 = Identity12476!(Bar12476!C12476.B); + +static assert(__traits(isSame, sb12476, A12476!int)); +static assert(__traits(isSame, cb12476, A12476!int)); + +/***************************************************/ +// 12506 + +import imports.a12506; +private bool[9] r12506a = f12506!(i => true)(); // OK +private immutable bool[9] r12506b = f12506!(i => true)(); // OK <- error + +/***************************************************/ +// 12555 + +class A12555(T) +{ + Undef12555 error; +} + +static assert(!__traits(compiles, { + class C : A12555!C { } +})); + +/***************************************************/ +// 11622 + +class A11622(T) +{ + B11622!T foo() + { + return new B11622!T; + } +} + +class B11622(T) : T +{ +} + +static assert(!__traits(compiles, { + class C : A11622!C { } +})); + +/***************************************************/ +// 12688 + +void writeln12688(A...)(A) {} + +struct S12688 +{ + int foo() @property { return 1; } +} + +void test12688() +{ + S12688 s; + s.foo.writeln12688; // ok + (s.foo).writeln12688; // ok <- ng +} + +/***************************************************/ +// 12703 + +struct S12703 +{ + this(int) {} +} + +final class C12703 +{ + S12703 s = S12703(1); +} + +/***************************************************/ +// 12799 + +struct A12799 +{ + int a; + enum C = A12799.sizeof; + enum D = C; // OK <- Error +} + +/***************************************************/ +// 13236 + +pragma(msg, is(typeof({ struct S { S x; } }))); + +/***************************************************/ +// 13280 + +struct S13280 +{ + alias U = ubyte; + alias T1 = ubyte[this.sizeof]; // ok + alias T2 = const U[this.sizeof]; // ok + alias T3 = const ubyte[this.sizeof]; // ok <- error +} + +/***************************************************/ +// 13481 + +mixin template Mix13481(void function() callback) +{ + static this() + { + callback(); + } +} + +/***************************************************/ +// 13564 + +class E13564(T) +{ + int pos; +} + +class C13564(T) +{ + struct S + { + ~this() + { + C13564!int c; + c.element.pos = 0; + } + } + + E13564!T element; +} + +void test13564() +{ + auto c = new C13564!int(); +} + +/***************************************************/ +// 14166 + +struct Proxy14166(T) +{ + T* ptr; + ref deref() { return *ptr; } + alias deref this; +} +struct Test14166 +{ + auto opIndex() { return this; } + auto opIndex(int) { return 1; } +} +template Elem14166a(R) { alias Elem14166a = typeof(R.init[][0]); } +template Elem14166b(R) { alias Elem14166b = typeof(R.init[0]); } +void test14166() +{ + alias T = Proxy14166!Test14166; + static assert(is(Elem14166a!T == int)); // rejects-valid case + static assert(is(Elem14166b!T == int)); // regression case +} + +// other related cases +struct S14166 +{ + int x; + double y; + int[] a; + S14166 opUnary(string op : "++")() { return this; } +} +S14166 s14166; + +struct X14166 { this(int) { } X14166 opAssign(int) { return this; } } +X14166[int] aa14166; +X14166[int] makeAA14166() { return aa14166; } + +struct Tup14166(T...) { T field; alias field this; } +Tup14166!(int, int) tup14166; +Tup14166!(int, int) makeTup14166() { return tup14166; } + +pragma(msg, typeof((s14166.x += 1) = 2)); // ok <- error +pragma(msg, typeof(s14166.a.length += 2)); // ok <- error +pragma(msg, typeof(s14166++)); // ok <- error +pragma(msg, typeof(s14166.x ^^ 2)); // ok <- error +pragma(msg, typeof(s14166.y ^^= 2.5)); // ok <- error +pragma(msg, typeof(makeAA14166()[0] = 1)); // ok <- error +pragma(msg, typeof(tup14166.field = makeTup14166())); // ok <- error + +/***************************************************/ +// 14388 + +@property immutable(T)[] idup14388(T)(T[] a) +{ + alias U = immutable(T); + U[] res; + foreach (ref e; a) + res ~= e; + return res; +} + +struct Data14388(A14388 a) +{ + auto foo() + { + return Data14388!a.init; // [B] + } +} + +struct A14388 +{ + struct Item {} + + immutable(Item)[] items; + + this(int dummy) + { + items = [Item()].idup14388; + } +} + +void test14388() +{ + auto test = Data14388!(A14388(42)).init.foo(); // [A] + /* + * A(42) is interpreter to a struct literal A([immutable(Item)()]). + * The internal VarDeclaration with STCmanifest for the Data's template parameteter 'a' + * calls syntaxCopy() on its ((ExpInitializer *)init)->exp in VarDeclaration::semantic(), + * and 'immutable(Item)()'->syntaxCopy() had incorrectly removed the qualifier. + * Then, the arguments of two Data template instances at [A] and [B] had become unmatch, + * and the second instantiation had created the AST duplication. + */ +} + +/***************************************************/ +// 15163 + +void function() func15164(int[] arr) +{ + return () { }; +} + +void test15163() +{ + auto arr = [[0]]; + func15164(arr[0])(); +} + +/************************************************** + 3438 +**************************************************/ +import core.vararg; +struct S3438_1 { this(int x, int y = 1) { } } +struct S3438_2 { this(int x, ...) { } } +struct S3438_3 { this(int x, int[] arr...) { } } +struct S3438_4 { this(...) { } } +struct S3438_5 { this(int[] arr...) { } } + +/***************************************************/ +// 15362 + +void func15362() +{ + assert(true); + assert(true,); + assert(true, "So true"); + assert(true, "Very, very true",); + static assert(true); + static assert(true,); + static assert(true, "So true"); + static assert(true, "Very, very true",); +} + +/***************************************************/ +// 15799 + +interface I15799 +{ + void funA(); + + void funB(int n) + in { + assert(n); + }; // Semicolon is not a part of function declaration. It's an empty declaration. +} diff --git a/gcc/testsuite/gdc.test/compilable/const.d b/gcc/testsuite/gdc.test/compilable/const.d new file mode 100644 index 00000000000..9b97037baa0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/const.d @@ -0,0 +1,41 @@ + +static assert(2.0 * 3.0 == 6 ); +static assert(2.0 * 3.0i == 6i); +static assert(2.0i * 3.0 == 6i); +static assert(2.0i * 3.0i == -6 ); + +static assert(2.0 * (4.0 + 3.0i) == 8 + 6i); +static assert(2.0i * (4.0 + 3.0i) == 8i - 6 ); +static assert((4.0 + 3.0i) * 2.0 == 8 + 6i); +static assert((4.0 + 3.0i) * 2.0i == 8i - 6 ); +static assert((4.0 + 3.0i) * (5 + 7i) == -1 + 43i ); + +static assert((2.0).re == 2); +static assert((2.0i).re == 0); +static assert((3+2.0i).re == 3); + +static assert((4.0i).im == 4); +static assert((2.0i).im == 2); +static assert((3+2.0i).im == 2); + +static assert(6.0 / 2.0 == 3); +static assert(6i / 2i == 3); +static assert(6 / 2i == -3i); +static assert(6i / 2 == 3i); + +static assert((6 + 4i) / 2 == 3 + 2i); +static assert((6 + 4i) / 2i == -3i + 2); + +//static assert(2 / (6 + 4i) == -3i); +//static assert(2i / (6 + 4i) == 3i); +//static assert((1 + 2i) / (6 + 4i) == 3i); + +static assert(6.0 % 2.0 == 0); +static assert(6.0 % 3.0 == 0); +static assert(6.0 % 4.0 == 2); + +static assert(6.0i % 2.0i == 0); +static assert(6.0i % 3.0i == 0); +static assert(6.0i % 4.0i == 2i); + + diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle.d b/gcc/testsuite/gdc.test/compilable/cppmangle.d new file mode 100644 index 00000000000..0fd197d17c4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/cppmangle.d @@ -0,0 +1,353 @@ + +// Test C++ name mangling. +// See Bugs 4059, 5148, 7024, 10058 + + +import core.stdc.stdio; + +extern (C++) int foob(int i, int j, int k); + +class C +{ + extern (C++) int bar(int i, int j, int k) + { + printf("this = %p\n", this); + printf("i = %d\n", i); + printf("j = %d\n", j); + printf("k = %d\n", k); + return 1; + } +} + + +extern (C++) +int foo(int i, int j, int k) +{ + printf("i = %d\n", i); + printf("j = %d\n", j); + printf("k = %d\n", k); + assert(i == 1); + assert(j == 2); + assert(k == 3); + return 1; +} + +void test1() +{ + foo(1, 2, 3); + + auto i = foob(1, 2, 3); + assert(i == 7); + + C c = new C(); + c.bar(4, 5, 6); +} + +version (linux) +{ + static assert(foo.mangleof == "_Z3fooiii"); + static assert(foob.mangleof == "_Z4foobiii"); + static assert(C.bar.mangleof == "_ZN1C3barEiii"); +} +version (Win32) +{ + static assert(foo.mangleof == "?foo@@YAHHHH@Z"); + static assert(foob.mangleof == "?foob@@YAHHHH@Z"); + static assert(C.bar.mangleof == "?bar@C@@UAEHHHH@Z"); +} +version (Win64) +{ + static assert(foo.mangleof == "?foo@@YAHHHH@Z"); + static assert(foob.mangleof == "?foob@@YAHHHH@Z"); + static assert(C.bar.mangleof == "?bar@C@@UEAAHHHH@Z"); +} + +/****************************************/ + +extern (C++) +interface D +{ + int bar(int i, int j, int k); +} + +extern (C++) D getD(); + +void test2() +{ + D d = getD(); + int i = d.bar(9,10,11); + assert(i == 8); +} + +version (linux) +{ + static assert (getD.mangleof == "_Z4getDv"); + static assert (D.bar.mangleof == "_ZN1D3barEiii"); +} + +/****************************************/ + +extern (C++) int callE(E); + +extern (C++) +interface E +{ + int bar(int i, int j, int k); +} + +class F : E +{ + extern (C++) int bar(int i, int j, int k) + { + printf("F.bar: i = %d\n", i); + printf("F.bar: j = %d\n", j); + printf("F.bar: k = %d\n", k); + assert(i == 11); + assert(j == 12); + assert(k == 13); + return 8; + } +} + +void test3() +{ + F f = new F(); + int i = callE(f); + assert(i == 8); +} + +version (linux) +{ + static assert (callE.mangleof == "_Z5callEP1E"); + static assert (E.bar.mangleof == "_ZN1E3barEiii"); + static assert (F.bar.mangleof == "_ZN1F3barEiii"); +} + +/****************************************/ + +extern (C++) void foo4(char* p); + +void test4() +{ + foo4(null); +} + +version (linux) +{ + static assert(foo4.mangleof == "_Z4foo4Pc"); +} + +/****************************************/ + +extern(C++) +{ + struct foo5 { int i; int j; void* p; } + + interface bar5{ + foo5 getFoo(int i); + } + + bar5 newBar(); +} + +void test5() +{ + bar5 b = newBar(); + foo5 f = b.getFoo(4); + printf("f.p = %p, b = %p\n", f.p, cast(void*)b); + assert(f.p == cast(void*)b); +} + +version (linux) +{ + static assert(bar5.getFoo.mangleof == "_ZN4bar56getFooEi"); + static assert (newBar.mangleof == "_Z6newBarv"); +} + +/****************************************/ + +extern(C++) +{ + struct S6 + { + int i; + double d; + } + S6 foo6(); +} + +extern (C) int foosize6(); + +void test6() +{ + S6 f = foo6(); + printf("%d %d\n", foosize6(), S6.sizeof); + assert(foosize6() == S6.sizeof); + assert(f.i == 42); + printf("f.d = %g\n", f.d); + assert(f.d == 2.5); +} + +version (linux) +{ + static assert (foo6.mangleof == "_Z4foo6v"); +} + +/****************************************/ + +extern (C) int foo7(); + +struct S +{ + int i; + long l; +} + +void test7() +{ + printf("%d %d\n", foo7(), S.sizeof); + assert(foo7() == S.sizeof); +} + +/****************************************/ + +extern (C++) void foo8(const char *); + +void test8() +{ + char c; + foo8(&c); +} + +version (linux) +{ + static assert(foo8.mangleof == "_Z4foo8PKc"); +} + +/****************************************/ +// 4059 + +struct elem9 { } + +extern(C++) void foobar9(elem9*, elem9*); + +void test9() +{ + elem9 *a; + foobar9(a, a); +} + +version (linux) +{ + static assert(foobar9.mangleof == "_Z7foobar9P5elem9S0_"); +} + +/****************************************/ +// 5148 + +extern (C++) +{ + void foo10(const char*, const char*); + void foo10(const int, const int); + void foo10(const char, const char); + + struct MyStructType { } + void foo10(const MyStructType s, const MyStructType t); + + enum MyEnumType { onemember } + void foo10(const MyEnumType s, const MyEnumType t); +} + +void test10() +{ + char* p; + foo10(p, p); + foo10(1,2); + foo10('c','d'); + MyStructType s; + foo10(s,s); + MyEnumType e; + foo10(e,e); +} + +/**************************************/ +// 10058 + +extern (C++) +{ + void test10058a(void*) { } + void test10058b(void function(void*)) { } + void test10058c(void* function(void*)) { } + void test10058d(void function(void*), void*) { } + void test10058e(void* function(void*), void*) { } + void test10058f(void* function(void*), void* function(void*)) { } + void test10058g(void function(void*), void*, void*) { } + void test10058h(void* function(void*), void*, void*) { } + void test10058i(void* function(void*), void* function(void*), void*) { } + void test10058j(void* function(void*), void* function(void*), void* function(void*)) { } + void test10058k(void* function(void*), void* function(const (void)*)) { } + void test10058l(void* function(void*), void* function(const (void)*), const(void)* function(void*)) { } +} + +version (linux) +{ + static assert(test10058a.mangleof == "_Z10test10058aPv"); + static assert(test10058b.mangleof == "_Z10test10058bPFvPvE"); + static assert(test10058c.mangleof == "_Z10test10058cPFPvS_E"); + static assert(test10058d.mangleof == "_Z10test10058dPFvPvES_"); + static assert(test10058e.mangleof == "_Z10test10058ePFPvS_ES_"); + static assert(test10058f.mangleof == "_Z10test10058fPFPvS_ES1_"); + static assert(test10058g.mangleof == "_Z10test10058gPFvPvES_S_"); + static assert(test10058h.mangleof == "_Z10test10058hPFPvS_ES_S_"); + static assert(test10058i.mangleof == "_Z10test10058iPFPvS_ES1_S_"); + static assert(test10058j.mangleof == "_Z10test10058jPFPvS_ES1_S1_"); + static assert(test10058k.mangleof == "_Z10test10058kPFPvS_EPFS_PKvE"); + static assert(test10058l.mangleof == "_Z10test10058lPFPvS_EPFS_PKvEPFS3_S_E"); +} + +/**************************************/ +// 11696 + +class Expression; +struct Loc {} + +extern(C++) +class CallExp +{ + static void test11696a(Loc, Expression, Expression); + static void test11696b(Loc, Expression, Expression*); + static void test11696c(Loc, Expression*, Expression); + static void test11696d(Loc, Expression*, Expression*); +} + +version (linux) +{ + static assert(CallExp.test11696a.mangleof == "_ZN7CallExp10test11696aE3LocP10ExpressionS2_"); + static assert(CallExp.test11696b.mangleof == "_ZN7CallExp10test11696bE3LocP10ExpressionPS2_"); + static assert(CallExp.test11696c.mangleof == "_ZN7CallExp10test11696cE3LocPP10ExpressionS2_"); + static assert(CallExp.test11696d.mangleof == "_ZN7CallExp10test11696dE3LocPP10ExpressionS3_"); +} + +/**************************************/ +// 13337 + +extern(C++, N13337a.N13337b.N13337c) +{ + struct S13337{} + void foo13337(S13337 s); +} + +version (linux) +{ + static assert(foo13337.mangleof == "_ZN7N13337a7N13337b7N13337c8foo13337ENS1_6S13337E"); +} + +/**************************************/ +// 15789 + +extern (C++) void test15789a(T...)(T args); + +void test15789() +{ + test15789a(0); +} diff --git a/gcc/testsuite/gdc.test/compilable/ctfe_math.d b/gcc/testsuite/gdc.test/compilable/ctfe_math.d new file mode 100644 index 00000000000..78de869d090 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ctfe_math.d @@ -0,0 +1,25 @@ +// Test CTFE builtins for std.math functions. + +import std.math; + +void main() +{ + static assert(approxEqual(sin(2.0L), 0.9092974L)); + static assert(approxEqual(cos(2.0), -0.4161468)); + static assert(approxEqual(tan(2.0f), -2.185040f)); + static assert(approxEqual(sqrt(2.0L), 1.414214L)); + static assert(fabs(-2.0) == 2.0); + static assert(ldexp(2.5f, 3) == 20.0f); + + static assert(isNaN(real.init)); + static assert(isNaN(double.nan)); + static assert(!isNaN(float.infinity)); + + static assert(isInfinity(real.infinity)); + static assert(isInfinity(-double.infinity)); + static assert(!isInfinity(float.nan)); + + static assert(isFinite(1.0L)); + static assert(!isFinite(double.infinity)); + static assert(!isFinite(float.nan)); +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc1.d b/gcc/testsuite/gdc.test/compilable/ddoc1.d new file mode 100644 index 00000000000..fa5042a4780 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc1.d @@ -0,0 +1,69 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 1 +// REQUIRED_ARGS: -d + +/** This module is for ABC + * Copyright: Copyright © + */ + +module abc; + +string foos = "foo"; + +alias int myint; /// +alias int mytypedefint; + +/** windy + * city + * + * paragraph 2 about of F $$(NAME) + * ----- + * #include + * void main() + * { + * printf("hello\n"); + * } + * ----- + * Copyright: 1998 + */ +myint f; +enum E { e } /// comment1 +int g; /// comment2 +private int h; /// comment for H +static int i; +int j; +wchar LS = 0x2028; /// UTF line separator +wchar PS = 0x2029; /// UTF paragraph separator + +wchar _XX; /// ditto +wchar YY; /// ditto + +/** Function foo takes argument c and adds it to argulid. + * + * Then it munges argulid, u underline. + * Params: + * c = the character which adds c to argulid + * argulid = the argument + * u = the other argument + */ +int foo(char c, int argulid, char u); + +int barr() { return 3; } /// doc for barr() + +/++ The Class Bar +/ +class Bar +{ + int x; /// member X + int y; /// member Y + protected int z; /// member Z +} + +/++ The Enum Easy +/ + +enum Easy : int +{ + red, /// the Red + blue, /// the Blue + green, /// the Green +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10.d b/gcc/testsuite/gdc.test/compilable/ddoc10.d new file mode 100644 index 00000000000..90ab5a19ab2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10.d @@ -0,0 +1,210 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10 + +// 294 + +/// The foo +struct Foo(T) { } +/// ditto +struct Foo(T,U) { } + +/** This basic case doesn't work very well. The template signature is + * documented twice, but the function signature (argument names and return + * type) is not documented at all. This comment is also repeated twice. */ +int func1(T)(T x) {} + + + +/** This comment is also repeated twice, and the second function signature is + * not very well documented. */ +int func2(T,U)(T x, U y) {} + +/// ditto +int func2(T)(T x) {} + +/// Separate overload item. +int func2()() {} + + +/// +template func3(T,U) { + /** This used to work adequately and documented both func3 templates + * simultaneously. Now, it documents the first template twice and + * no longer documents the function argument and return types.*/ + int func3(T x, U y) {} +} + +/// ditto +deprecated template func3(T, U=int, V:long) { + private int func3(T x) {} +} + + + +/** + * blah + */ + +void map(char rs) +{ +} + +/// Ditto +void map(int rs) +{ +} + + + +/** + * blah + */ + +void map2()(char rs) +{ +} + +/// Ditto +void map2()(int rs) +{ +} + + + +/** + * blah http://www.map3.com map3 + */ + +void map3(char rs) +{ +} + + + + +/** + * blah http://www.map.com map + */ + +void map4(string s)(char rs) +{ +} + + + +/** + * blah http://www.map.com map + */ + +template map5(string s) +{ +} + + +/** blah */ +struct bar6 { + int blah; +} + + +/** template bodies */ +struct Foo7(T) { + + /**Attempt one: Doc outside static if.*/ + static if(is(T == uint)) { + /**Attempt two: Inside.*/ + void bar() {} + } + else { + /**Attempt two: else.*/ + void bar() {} + } + + /** the abc function should be static */ + static void abc() { } +} + + +/** show abstract */ +abstract class Foo8 { } + +/// a stray $(RPAREN) mustn't foul the macros +void bug4878(string a = ")") {} + +/**** + */ +struct S +{ + /**** + */ + this(long ticks) const pure nothrow { } + + /**** + */ + const pure nothrow this(this) { } + + /**** + */ + const pure nothrow ~this() { } + + /**** + */ + void foo(long ticks) const pure nothrow { } +} + + +/** Produces something in (a;b] */ +float f10(float a, float b) { return (a+b)/2.0; } +/** Produces something in [a;b) */ +float h10(float a, float b) { return (a+b)/2.0; } + + +/// +void bug6090(string f="$(B b)", char g=')')(string h="$(", string i="$)") {} + + +/**** + */ +struct T +{ + /**** + */ + this(A...)(A args) { } + + /// + this(int){} +} + + +// 14547 + +/// doc-comment +int x14547 = 1; + +/// ditto +enum int y14547 = 2; + +/// doc-comment +enum isInt14547(T) = is(T == int); + +/// ditto +enum bool isString14547(T) = is(T == string); + +/// ditto +static immutable typeName14547(T) = T.stringof; + +/// ditto +int storageFor14547(T) = 0; + +/// doc-comment +template foo14547(T) +{ + enum int foo14547 = T.stringof.length; +} + +/// ditto +template bar14547(T) if (is(T == int)) +{ + enum int bar14547 = T.stringof.length; +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10236.d b/gcc/testsuite/gdc.test/compilable/ddoc10236.d new file mode 100644 index 00000000000..25738ec34e3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10236.d @@ -0,0 +1,59 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -w -o- + +/* +TEST_OUTPUT: +--- +compilable/ddoc10236.d(33): Warning: Ddoc: parameter count mismatch +compilable/ddoc10236.d(45): Warning: Ddoc: function declaration has no parameter 'y' +compilable/ddoc10236.d(57): Warning: Ddoc: function declaration has no parameter 'y' +compilable/ddoc10236.d(57): Warning: Ddoc: parameter count mismatch +--- +*/ + +/*********************************** + * foo_good does this. + * Params: + * x = is for this + * and not for that + * y = is for that + */ + +void foo_good(int x, int y) +{ +} + +/*********************************** + * foo_count_mismatch does this. + * Params: + * x = is for this + * and not for that + */ + +void foo_count_mismatch(int x, int y) // Warning: Ddoc: parameter count mismatch +{ +} + +/*********************************** + * foo_no_param_y does this. + * Params: + * x = is for this + * and not for that + * y = is for that + */ + +void foo_no_param_y(int x, int z) // Warning: Ddoc: function declaration has no parameter 'y' +{ +} + +/*********************************** + * foo_count_mismatch_no_param_y does this. + * Params: + * x = is for this + * and not for that + * y = is for that + */ + +void foo_count_mismatch_no_param_y(int x) +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10236b.d b/gcc/testsuite/gdc.test/compilable/ddoc10236b.d new file mode 100644 index 00000000000..d814d375c06 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10236b.d @@ -0,0 +1,69 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -w -o- + +/* +TEST_OUTPUT: +--- +compilable/ddoc10236b.d(43): Warning: Ddoc: parameter count mismatch +compilable/ddoc10236b.d(55): Warning: Ddoc: function declaration has no parameter 'y' +compilable/ddoc10236b.d(67): Warning: Ddoc: function declaration has no parameter 'y' +compilable/ddoc10236b.d(67): Warning: Ddoc: parameter count mismatch +--- +*/ + +/*********************************** + * foo_good does this. + * Params: + * x = is for this + * and not for that + * y = is for that + */ + +void foo_good(int x)(int y) +{ +} + +/*********************************** + * foo_good2 does this. + * Params: + * y = is for that + */ + +void foo_good2(int x)(int y) +{ +} + +/*********************************** + * foo_count_mismatch does this. + * Params: + * x = is for this + * and not for that + */ + +void foo_count_mismatch(int x)(int y) // Warning: Ddoc: parameter count mismatch +{ +} + +/*********************************** + * foo_no_param_y does this. + * Params: + * x = is for this + * and not for that + * y = is for that + */ + +void foo_no_param_y(int x)(int z) // Warning: Ddoc: function declaration has no parameter 'y' +{ +} + +/*********************************** + * foo_count_mismatch_no_param_y does this. + * Params: + * x = is for this + * and not for that + * y = is for that + */ + +void foo_count_mismatch_no_param_y(int x)() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10325.d b/gcc/testsuite/gdc.test/compilable/ddoc10325.d new file mode 100644 index 00000000000..4f0068af58d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10325.d @@ -0,0 +1,17 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10325 + +module ddoc10325; + +/** */ +template templ(T...) + if (someConstraint!T) +{ +} + +/** */ +void foo(T)(T t) + if (someConstraint!T) +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10334.d b/gcc/testsuite/gdc.test/compilable/ddoc10334.d new file mode 100644 index 00000000000..3ff148da430 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10334.d @@ -0,0 +1,29 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10334 + +module ddoc10334; + +template Foo10334(T) if (Bar10334!()) {} /// +template Foo10334(T) if (Bar10334!100) {} /// +template Foo10334(T) if (Bar10334!3.14) {} /// +template Foo10334(T) if (Bar10334!"str") {} /// +template Foo10334(T) if (Bar10334!1.4i) {} /// +template Foo10334(T) if (Bar10334!null) {} /// +template Foo10334(T) if (Bar10334!true) {} /// +template Foo10334(T) if (Bar10334!false) {} /// +template Foo10334(T) if (Bar10334!'A') {} /// +template Foo10334(T) if (Bar10334!int) {} /// +template Foo10334(T) if (Bar10334!string) {} /// +template Foo10334(T) if (Bar10334!([1,2,3])) {} /// +template Foo10334(T) if (Bar10334!(Baz10334!())) {} /// +template Foo10334(T) if (Bar10334!(Baz10334!T)) {} /// +template Foo10334(T) if (Bar10334!(Baz10334!100)) {} /// +template Foo10334(T) if (Bar10334!(.foo)) {} /// +template Foo10334(T) if (Bar10334!(const int)) {} /// +template Foo10334(T) if (Bar10334!(shared T)) {} /// + +template Test10334(T...) {} /// +mixin Test10334!int a; /// +mixin Test10334!(int,long) b; /// +mixin Test10334!"str" c; /// diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10366.d b/gcc/testsuite/gdc.test/compilable/ddoc10366.d new file mode 100644 index 00000000000..5bc5f641f40 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10366.d @@ -0,0 +1,20 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10366 + +/// +struct S(T) +{ + /// + void method() {} + + public + { + /// + struct Nested + { + /// + void nestedMethod() {} + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10367.d b/gcc/testsuite/gdc.test/compilable/ddoc10367.d new file mode 100644 index 00000000000..836c7d0cc50 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10367.d @@ -0,0 +1,28 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10367 +// REQUIRED_ARGS: -m32 +// EXTRA_SOURCES: extra-files/ddoc10367.ddoc + +module ddoc10367; + +/// A +enum A +{ + a = 1, /// a + b = 2 /// b +} + +/// B +enum B : long +{ + a = 1, /// a + b = 2 /// b +} + +/// C +enum C : string +{ + a = "a", /// a + b = "b" /// b +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10869.d b/gcc/testsuite/gdc.test/compilable/ddoc10869.d new file mode 100644 index 00000000000..11b485453da --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10869.d @@ -0,0 +1,27 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10869 + +module ddoc10869; + +/// +class C +{ + const + { + /// + void c1Foo() const { } + + /// + void i1Foo() immutable { } + } + + immutable + { + /// + void c2Foo() const { } + + /// + void i2Foo() immutable { } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10870.d b/gcc/testsuite/gdc.test/compilable/ddoc10870.d new file mode 100644 index 00000000000..95a82ed9ffd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc10870.d @@ -0,0 +1,10 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10870 + +/// +interface I +{ + /// + void f(); +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11.d b/gcc/testsuite/gdc.test/compilable/ddoc11.d new file mode 100644 index 00000000000..cf6070edfef --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc11.d @@ -0,0 +1,69 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11 + +/// The various floating point exceptions +enum +{ + FE_INVALID = 1, /// + FE_DENORMAL = 2, /// + FE_DIVBYZERO = 4, /// + FE_OVERFLOW = 8, /// + FE_UNDERFLOW = 0x10, /// + FE_INEXACT = 0x20, /// + FE_ALL_EXCEPT = 0x3F, /// Mask of all the exceptions +} + +alias int myint; + +/// +myint bar; + +/// +myint foo(myint x = myint.max) +{ + return x; +} + + +/// +class Foo +{ + /// + this(string s) { } +} + + +extern (C): + +/// +struct div_t { int quot,rem; } +/// +struct ldiv_t { int quot,rem; } +/// +struct lldiv_t { long quot,rem; } + + div_t div(int,int); /// + ldiv_t ldiv(int,int); /// + lldiv_t lldiv(long, long); /// + + + + void *calloc(size_t, size_t); /// + void *malloc(size_t); /// dittx + +/** +Example: +--- +private: + int i = 0; +--- +*/ +void test1() +{ +} + + + + + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11479.d b/gcc/testsuite/gdc.test/compilable/ddoc11479.d new file mode 100644 index 00000000000..d2ddb1973e8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc11479.d @@ -0,0 +1,96 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11479 + +module ddoc11479; + +/// +struct S1(T) +{ + /// + int a; + + /// +private: + int x; + +private: + /// + int y; + + /// +public: + int b; + +public: + /// + int c; +} + + +/// +struct S2(T) +{ + /// + int a; + + /// + private int x; + + /// + int b; + + /// + public int c; + + public + /// + int d; +} + + +/// +struct S3(T) +{ + /// + int a; + + /// + private { int x; } + + /// + int b; + + /// + private + { + int y; + + public + { + int c; + } + } + + private + { + int z; + + /// + public + { + int d; + } + } + + private + { + int w; + + public + { + /// + int e; + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11511.d b/gcc/testsuite/gdc.test/compilable/ddoc11511.d new file mode 100644 index 00000000000..ba5829ec6d9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc11511.d @@ -0,0 +1,20 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -w -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11511 +module ddoc11511; + +/** +Params: +abcd = none1 +bcdef = none23 +... = doo +*/ +void foo(int abcd, int bcdef, ...); + +/** +Params: +abcd = none1 +bcdef = none23 +arr = doo +*/ +void foo(int abcd, int bcdef, int[] arr...); diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11823.d b/gcc/testsuite/gdc.test/compilable/ddoc11823.d new file mode 100644 index 00000000000..dfde4b68cc5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc11823.d @@ -0,0 +1,7 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11823 +module ddoc11823; + +/// file function name is _file, arg defaults to __FILE__ but not __something__ +void file(string arg) { } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12.d b/gcc/testsuite/gdc.test/compilable/ddoc12.d new file mode 100644 index 00000000000..4fdf9cff1ef --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc12.d @@ -0,0 +1,20 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 12 + +int ruhred; /// This documents correctly. +int rühred; /// This should too + +/** + * BUG: The parameters are not listed under Params in the generated output + * + * Params: + * ü = first + * ş = second + * ğ = third + * + */ +int foo(int ü, int ş, int ğ) +{ + return ğ; +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12706.d b/gcc/testsuite/gdc.test/compilable/ddoc12706.d new file mode 100644 index 00000000000..399583cf8b2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc12706.d @@ -0,0 +1,9 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 12706 + +/// +void test()(string[] args) if (args[$]) +{ +} + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12745.d b/gcc/testsuite/gdc.test/compilable/ddoc12745.d new file mode 100644 index 00000000000..2bfaee68e9b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc12745.d @@ -0,0 +1,25 @@ +// EXTRA_SOURCES: +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 12745 + +/** +i underlined $(BR) +_i not underlined $(BR) +__i force underscore $(BR) +$(BR) +_0 not underscored $(BR) +__0 force underscored + +1 underscore: +$(BR) +1_1 $(BR) +1_a $(BR) +a_1 $(BR) +a_a $(BR) +$(BR) +2 underscores: $(BR) +1__a $(BR) +2__b +*/ +int i; \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/ddoc13.d b/gcc/testsuite/gdc.test/compilable/ddoc13.d new file mode 100644 index 00000000000..eafc8b289be --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc13.d @@ -0,0 +1,26 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 13 + +/// struct doc +struct Bug4107(T) +{ + /// templated function doc + void foo(U)(U u) { } +} + +/// alpha +struct Bug4107b(T) { + /// beta + struct B(U) { + /// gamma + struct C(V) { + /// delta + struct D(W) { + /// epsilon + B!W e(X)(C!V c, X[] x...) {} + } + } + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc13270.d b/gcc/testsuite/gdc.test/compilable/ddoc13270.d new file mode 100644 index 00000000000..6b04922d45c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc13270.d @@ -0,0 +1,18 @@ +// PERMUTE_ARGS: -w +// REQUIRED_ARGS: -o- -D -Dd${RESULTS_DIR}/compilable +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 13270 + +module ddoc13270; + +/** + * My overloaded function. + * + * Params: + * task = String description of stuff to do. + * tasks = Array of descriptions of stuff to do. + * maxJobs = Max parallel jobs to run while doing stuff. + */ +void doStuff(string task) {} + +/// ditto +void doStuff(string[] tasks, int maxJobs) {} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc13502.d b/gcc/testsuite/gdc.test/compilable/ddoc13502.d new file mode 100644 index 00000000000..6ab2ca0614d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc13502.d @@ -0,0 +1,24 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -w -o- +/* +TEST_OUTPUT: +--- +compilable/ddoc13502.d(14): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. +compilable/ddoc13502.d(17): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. +compilable/ddoc13502.d(21): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. +compilable/ddoc13502.d(24): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. +--- +*/ + +/// ( +enum isSomeString(T) = true; + +/// ( +enum bool isArray(T) = true; + + +/// ( +extern(C) alias int T1; + +/// ( +extern(C) alias T2 = int; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc13645.d b/gcc/testsuite/gdc.test/compilable/ddoc13645.d new file mode 100644 index 00000000000..f12b3769ae4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc13645.d @@ -0,0 +1,9 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 13645 + +/** +Documentation comment on module +*/ +deprecated("msg") @(1) +module ddoc13645; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14.d b/gcc/testsuite/gdc.test/compilable/ddoc14.d new file mode 100644 index 00000000000..fe1fcc1cff2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc14.d @@ -0,0 +1,97 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14 + + +alias void V; +alias double* P; + +/// -1 +struct Structure { + public P variable; /// 0 + V mNone(lazy P p) {} /// 1 + pure nothrow V mPrefix(lazy P p) {} /// 2 + V mSuffix(lazy P p) pure nothrow {} /// 3 +// pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 + V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 + pure nothrow { + V mScoped(lazy P p) {} /// 6 + } + pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 +// pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 + auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 + pure nothrow: + V mColon(lazy P p) {} /// 10 +} + +/// -1 +class Class { + public P variable; /// 0 + V mNone(lazy P p) {} /// 1 + pure nothrow V mPrefix(lazy P p) {} /// 2 + V mSuffix(lazy P p) pure nothrow {} /// 3 +// pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 + V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 + pure nothrow { + V mScoped(lazy P p) {} /// 6 + } + pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 +// pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 + auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 + pure nothrow: + V mColon(lazy P p) {} /// 10 +} + +/+ +/// -1 +struct StructTemplate() { + public P variable; /// 0 + V mNone(lazy P p) {} /// 1 + pure nothrow V mPrefix(lazy P p) {} /// 2 + V mSuffix(lazy P p) pure nothrow {} /// 3 +// pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 + V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 + pure nothrow { + V mScoped(lazy P p) {} /// 6 + } + pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 +// pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 + auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 + pure nothrow: + V mColon(lazy P p) {} /// 10 +} + +/// -1 +interface Interface { + V mNone(lazy P p) ; /// 1 + pure nothrow V mPrefix(lazy P p) ; /// 2 + V mSuffix(lazy P p) pure nothrow ; /// 3 +// pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) ; /// 4 + V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow ; /// 5 + pure nothrow { + V mScoped(lazy P p) ; /// 6 + } +// pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 + auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 + pure nothrow: + V mColon(lazy P p) ; /// 10 +} ++/ + +public P variable; /// 0 +V mNone(lazy P p) {} /// 1 +pure nothrow V mPrefix(lazy P p) {} /// 2 +V mSuffix(lazy P p) pure nothrow {} /// 3 +// pure nothrow V mPrefixTemplate(T)(lazy P p, T[] t...) {} /// 4 +V mSuffixTemplate(T)(lazy P p, T[] t...) pure nothrow {} /// 5 +pure nothrow { + V mScoped(lazy P p) {} /// 6 +} +pure nothrow auto mAutoPrefix(ref P p) { return p; } /// 7 +// pure nothrow auto mAutoTemplatePrefix(alias T)(ref T t) { return p; } /// 8 +auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9 +pure nothrow: +V mColon(lazy P p) {} /// 10 + + + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14383.d b/gcc/testsuite/gdc.test/compilable/ddoc14383.d new file mode 100644 index 00000000000..273b058ad52 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc14383.d @@ -0,0 +1,14 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14383 + +/** + * Module docs. + */ +module ddoc14383; + +/// Ddoc'd unittest +unittest +{ + int iShouldAppearInTheDocs; +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14413.d b/gcc/testsuite/gdc.test/compilable/ddoc14413.d new file mode 100644 index 00000000000..dace15fa155 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc14413.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14413 + +module ddoc14413; + +/// This should +/// be one +/// paragraph. +/// +/// Paragraph 2 +void foo(){} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14633.d b/gcc/testsuite/gdc.test/compilable/ddoc14633.d new file mode 100644 index 00000000000..759287cfecf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc14633.d @@ -0,0 +1,23 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -w -o- + +/* +TEST_OUTPUT: +--- +--- +*/ + +/** Blah + Params: + T = some type + test = something + overnext = for testing overloaded functions +*/ +template case1(T) +{ + void case1(R)(R test) { } + void case1(R)(R test, string overnext) { } +} + +///ditto +alias case2 = case1!int; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14778.d b/gcc/testsuite/gdc.test/compilable/ddoc14778.d new file mode 100644 index 00000000000..6bb23534ff2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc14778.d @@ -0,0 +1,42 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14778 + +module ddoc14778; + +/// docs for Z +template Z14778(T) +{ + /// docs for E + enum E; + + /// docs for x + enum x = 1.0; + + /// docs for mv + auto mv = 1; + + /// docs for wv + inout wv = 3; + + /// doc for cv + const cv = "a"; + + /// docs for wcv + inout const wcv = "ab"; + + /// doc for sv + shared sv = 1.4142; + + /// doc for swv + shared inout swv = 3.14; + + /// doc for scv + shared const scv = new Object(); + + /// docs for swcv + shared inout const swcv = undefined; + + /// doc for iv + immutable iv = [1,2,3]; +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc15475.d b/gcc/testsuite/gdc.test/compilable/ddoc15475.d new file mode 100644 index 00000000000..f1923525104 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc15475.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 15475 + +/** +My module +---- + // Computes the interval [x,y) + auto interval = computeInterval(x, y); +---- +*/ +module ddoc15475; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc17697.d b/gcc/testsuite/gdc.test/compilable/ddoc17697.d new file mode 100644 index 00000000000..3d97c2c96f4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc17697.d @@ -0,0 +1,29 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 17697 + +/*** + * See: + * http://www.fooa.com/test1 + * http://www.fooa.com/_test1 + * https://www.foob.com/test1 + * $(LINK http://www.fooc.com/test1) + * $(LINK2 http://www.food.com/test1, test1) + */ + +/** +Also piggyback a few tests for https://github.com/dlang/dmd/pull/6989 + +not_a_tag_because_it_does_not_start_with_uppercase: + +not_a_tag_because_no_whitespace_after_colon:x + +TagGalore: yes this is a tag + +MoreTag: +yes the above is also a tag +*/ + +module test1; + +int a; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc198.d b/gcc/testsuite/gdc.test/compilable/ddoc198.d new file mode 100644 index 00000000000..16485b78b72 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc198.d @@ -0,0 +1,35 @@ +// EXTRA_SOURCES: extra-files/ddoc198.ddoc +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 198 + +module ddoc198; + +/// +interface I1 { } + +/// +class C1 { } + +/// +class Foo : C1, I1 { } + +/// +enum X { x = 1 } + +/// +enum Y : X { y = X.x } + +/// +struct S1 { } + +/// +enum enS : S1 { a = S1() } + +// disabled until class enums are possible +// enum enC : C1 { a = new C1() } + + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc2.d b/gcc/testsuite/gdc.test/compilable/ddoc2.d new file mode 100644 index 00000000000..54e492f1011 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc2.d @@ -0,0 +1,42 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 2 + +/** + * Summary + * + * Description1 + * + * Description2 + * + * Description3 + * + * Macros: + * WIKI = StdStream + * meemie + * See_Also: + * Things to see also. + * + * And more things. + */ + +/* + */ + +module std.test; + +/// A base class for stream exceptions. +class StreamException: Exception { + /** Construct a StreamException with given error message msg. + * Params: + * msg = the $(RED red) $(BLUE blue) $(GREEN green) $(YELLOW yellow). + * foo = next parameter which is a much longer + * message spanning multiple + * lines. + */ + this(string msg, int foo) { super(msg); } + + /********** stars ***************/ + int stars; +} + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc2273.d b/gcc/testsuite/gdc.test/compilable/ddoc2273.d new file mode 100644 index 00000000000..413ba71055e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc2273.d @@ -0,0 +1,37 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 2273 +// REQUIRED_ARGS: -m32 + +module ddoc2273; + +interface A { } + +interface C { } +interface D { } + +/// +interface B : C, D { } + +/// +class Foo : A, B { } + +/// +MinType!(T1, T2, T) min(T1, T2, T...)(T1 a, T2 b, T xs) { } + +/// +Templ!([1, 2, 3]) max(T...)() { } + +/// +template Base64Impl(char Map62th, char Map63th, char Padding) { } + +/// +int sqlite3_config(int,...); + +template staticIndexOf(T, TList...) { alias int staticIndexOf; } + +/// +alias staticIndexOf IndexOf; + +void main() { } + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc3.d b/gcc/testsuite/gdc.test/compilable/ddoc3.d new file mode 100644 index 00000000000..bc00b69e83e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc3.d @@ -0,0 +1,71 @@ +// EXTRA_SOURCES: extra-files/ddoc3.ddoc +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 3 + +/** + * Summary + * + * Description1 + * + * Description2 + * + * Description3 + * + * Macros: + * WIKI = StdStream + * meemie + * ARG0 = $0 + * ARG1 = $1 + * ARG2 = $2 + * ARG3 = $3 + * PLUS = $+ + * TROW = $(TR $(TCOL $1,$+)) + * TCOL = $(TD $1) $(TCOL $+) + * LPAREN = ( + * See_Also: + * Things to see also. + * + * And more things $(BR) + * 'arg1, arg2, arg3' : $(ARG0 arg1, arg2, arg3). $(BR) + * 'arg2, arg3' : $(PLUS arg1, arg2, arg3). $(BR) + * 'arg1' : $(ARG1 arg1, arg2, arg3). $(BR) + * 'arg2' : $(ARG2 arg1, arg2, arg3). $(BR) + * 'arg3' : $(ARG3 arg1, arg2, arg3). $(BR) + */ + +/** + * Things to see also $(HELLO). + * + * $(TABLE + * $(TROW 1, 2, 3) + * $(TROW 4, 5, 6) + * ) + * + * $(D_CODE + $(B pragma)( $(I name) ); + $(B pragma)( $(I name) , $(I option) [ $(I option) ] ); + $(U $(LPAREN)) + ) + */ + +/* + */ + +module std.test; + +/// A base class for stream exceptions. +class StreamException: Exception { + /** Construct a StreamException with given error message msg. + * Params: + * msg = the $(RED red) $(BLUE blue) $(GREEN green) $(YELLOW yellow). + * foo = next parameter which is a much longer + * message spanning multiple + * lines. + */ + this(string msg, int foo) { super(msg); } + + /********** stars ***************/ + int stars; +} + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc4.d b/gcc/testsuite/gdc.test/compilable/ddoc4.d new file mode 100644 index 00000000000..d0677363afb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc4.d @@ -0,0 +1,11 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 4 + +/** + a +*/ +enum +{ + ONE +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc4162.d b/gcc/testsuite/gdc.test/compilable/ddoc4162.d new file mode 100644 index 00000000000..3946eca85a6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc4162.d @@ -0,0 +1,17 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 4162 + +/// +interface A +{ + /// + static void staticHello() { } + + /// + final void hello() { } +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc4899.d b/gcc/testsuite/gdc.test/compilable/ddoc4899.d new file mode 100644 index 00000000000..1fbd6a9cbe8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc4899.d @@ -0,0 +1,23 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -w -o- + +/* +TEST_OUTPUT: +--- +compilable/ddoc4899.d(18): Warning: Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses. +compilable/ddoc4899.d(19): Warning: Ddoc: Stray ')'. This may cause incorrect Ddoc output. Use $(RPAREN) instead for unpaired right parentheses. +--- +*/ + +/++ + (See accompanying file LICENSE_1_0.txt or copy at + foo:) ++/ +module d; + +/** ( */ int a; +/** ) */ int b; + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5.d b/gcc/testsuite/gdc.test/compilable/ddoc5.d new file mode 100644 index 00000000000..4a8c396c66c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc5.d @@ -0,0 +1,31 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 5 + +/** + + Test module + +*/ +module test; + +/// class to test DDOC on members +class TestMembers(TemplateArg) +{ + public: + /** + + a static method + + Params: idx = index + + */ + static void PublicStaticMethod(int idx) + { + } +} + +void main() +{ +} + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446.d b/gcc/testsuite/gdc.test/compilable/ddoc5446.d new file mode 100644 index 00000000000..2e33617ede9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc5446.d @@ -0,0 +1,69 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 5446 +module ddoc5446; +import ddoc5446a; +private import ddoc5446b; + +/** */ +alias A_Foo This_Foo; + +/** */ +alias A_Foo_Alias This_Foo_Alias; + +/** */ +alias int This_Int; + +/** */ +alias A_Enum This_Enum; + +/** */ +deprecated alias ddoc5446b.A_Enum_New A_Enum_New; + +struct Nested +{ +} + +/** */ +struct Bar +{ + /** */ + alias A_Foo Bar_A_Foo; + + /** */ + alias A_Foo_Alias Bar_A_Foo_Alias; + + /** */ + alias A_Int Bar_A_Int; + + /** */ + alias This_Foo Bar_This_Foo; + + /** */ + alias This_Foo_Alias Bar_This_Foo_Alias; + + /** */ + alias This_Int Bar_This_Int; + + /** */ + alias Nested Nested_Alias; + + /** */ + alias .Nested Fake_Nested; + + /** */ + struct Nested + { + /** */ + alias Bar Bar_Nested_Bar_Alias; + + /** */ + alias .Bar Bar_Alias; + + /** */ + struct Bar + { + + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446a.d b/gcc/testsuite/gdc.test/compilable/ddoc5446a.d new file mode 100644 index 00000000000..2d69dab2e5a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc5446a.d @@ -0,0 +1,15 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +module ddoc5446a; + +/** */ +struct A_Foo { } + +/** */ +alias A_Foo A_Foo_Alias; + +/** */ +alias int A_Int; + +/** */ +enum A_Enum { x } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446b.d b/gcc/testsuite/gdc.test/compilable/ddoc5446b.d new file mode 100644 index 00000000000..f6e84d5f41b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc5446b.d @@ -0,0 +1,6 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +module ddoc5446b; + +/** */ +enum A_Enum_New { x } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc6.d b/gcc/testsuite/gdc.test/compilable/ddoc6.d new file mode 100644 index 00000000000..6d130901602 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc6.d @@ -0,0 +1,25 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 6 + +/** + * + */ +struct MyStruct(T) +{ + static if( true ) + { + void MyStruct() {} + } +} + +void main() +{ +} + +/+ +23 +C:\code\d\bugs>dmd -D -o- 148_1.d +148_1.d(6): Error: static if conditional cannot be at global scope ++/ + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc648.d b/gcc/testsuite/gdc.test/compilable/ddoc648.d new file mode 100644 index 00000000000..49c90973a85 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc648.d @@ -0,0 +1,90 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 648 + +module ddoc648; + +/// Mixin declaration +mixin template Mixin1() +{ + /// struct S + struct S { } +} + +/// class A +class A +{ + /// field x + int x; + + /// no docs for mixin statement (only for expanded members) + mixin Mixin1!(); +} + +/// class AB +class AB +{ + /// field x + int x; + + // no docs for mixin or its contents, must be a ddoc comment + mixin Mixin1!(); +} + +/// Mixin declaration2 +mixin template Mixin2() +{ + /// struct S2 + struct S2 { } +} + +/// Mixin declaration3 +mixin template Mixin3() +{ + /// another field + int f; + + /// no docs for mixin statement (only for expanded members) + mixin Mixin2!(); +} + +/// class B1 +class B1 +{ + /// no docs for mixin statement (only for expanded members) + mixin Mixin3!(); +} + + +/// Mixin declaration3 +mixin template Mixin4() +{ + /// another field + int f; + + // no docs at all for non-ddoc comment + mixin Mixin2!(); +} + +/// class B2 +class B2 +{ + /// no docs for mixin statement (only for expanded members) + mixin Mixin4!(); +} + +/// no docs for mixin statement (only for expanded members) +mixin Mixin3!(); + +/// +struct TS(T) +{ + mixin template MT() + { + } + + mixin MT; /// avoid calling semantic + + /// + int field; +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc6491.d b/gcc/testsuite/gdc.test/compilable/ddoc6491.d new file mode 100644 index 00000000000..028792accef --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc6491.d @@ -0,0 +1,14 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 6491 + +module ddoc6491; + +import core.cpuid; + +enum int c6491 = 4; + +/// test +void bug6491a(int a = ddoc6491.c6491, string b = core.cpuid.vendor); + + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7.d b/gcc/testsuite/gdc.test/compilable/ddoc7.d new file mode 100644 index 00000000000..81851832b8c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc7.d @@ -0,0 +1,59 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7 + +//----------------------------------------------- +/// my enum +enum E1 +{ + A, /// element a + B /// element b +} + +/// my enum +enum E2 +{ + /// element a + A, + /// element b + B +} + +/// my enum +enum E3 +{ + A /// element a + , B /// element b +} + +/// my enum +enum E4 +{ + A /// element a + , + B /// element b +} + +/// my enum +enum E5 +{ + /// element a + A + , + /// element b + B +} + +/// Some doc +void foo() {} + +/// More doc +alias foo bar; + +/// asdf +class C +{ + /// Some doc + abstract void foo(); +} + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7555.d b/gcc/testsuite/gdc.test/compilable/ddoc7555.d new file mode 100644 index 00000000000..efbb54785e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc7555.d @@ -0,0 +1,53 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7555 +module ddoc7555; + +/** +Dummy doc. + +$(X0 + DelimitedString + TokenString) + +$(X1 + DelimitedString + TokenString) + +$(X2 x,HexString) +$(X2 x, HexString) + +$(X3 x,x,HexString) +$(X3 x,x, HexString) + +$(X4 x,x,x,HexString) +$(X4 x,x,x, HexString) + +$(X5 x,x,x,x,HexString) +$(X5 x,x,x,x, HexString) + +$(X6 x,x,x,x,x,HexString) +$(X6 x,x,x,x,x, HexString) + +$(X7 x,x,x,x,x,x,HexString) +$(X7 x,x,x,x,x,x, HexString) + +$(X8 x,x,x,x,x,x,x,HexString) +$(X8 x,x,x,x,x,x,x, HexString) + +$(X9 x,x,x,x,x,x,x,x,HexString) +$(X9 x,x,x,x,x,x,x,x, HexString) + +Macros: + X0=$0 + X1=$1 + X2=$2 + X3=$3 + X4=$4 + X5=$5 + X6=$6 + X7=$7 + X8=$8 + X9=$9 +*/ +void dummy(); diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7656.d b/gcc/testsuite/gdc.test/compilable/ddoc7656.d new file mode 100644 index 00000000000..7a0ef0df3ce --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc7656.d @@ -0,0 +1,24 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7656 + +module ddoc7656; + +/** +-------- +int x; // This is a $ comment (and here is some +int y; // more information about that comment) +-------- +*/ +void main() { } + + +/** +(Regression check) + +Example: +---- +assert(add(1, 1) == 2); +---- +*/ +int add(int a, int b) { return a + b; } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7715.d b/gcc/testsuite/gdc.test/compilable/ddoc7715.d new file mode 100644 index 00000000000..ee33b28fe3a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc7715.d @@ -0,0 +1,16 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7715 + +module ddoc7656; + +/** +$1 $2 +--- +string s = "$1$2 $ $4"; +--- +*/ +void foo(){} + +/// +void test(string a = ")") {} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7795.d b/gcc/testsuite/gdc.test/compilable/ddoc7795.d new file mode 100644 index 00000000000..c100f5d70b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc7795.d @@ -0,0 +1,17 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7795 + +module ddoc7795; + +struct TimeValue { + this(int hour, int minute, int second = 0, int ms = 0) {} +} + +/// +struct DateTime { + /// + this(int x, TimeValue t = TimeValue(0, 0)) {} +} + +void main() { } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc8.d b/gcc/testsuite/gdc.test/compilable/ddoc8.d new file mode 100644 index 00000000000..6683b1bb90b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc8.d @@ -0,0 +1,9 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 8 + +/** foo */ + +class Foo(T) : Bar +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc8271.d b/gcc/testsuite/gdc.test/compilable/ddoc8271.d new file mode 100644 index 00000000000..45aca90c7c7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc8271.d @@ -0,0 +1,15 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 8271 + +module ddoc8271; + +/** + $(まくろ) +Macros: + まくろ = $(マクロ) + マクロ = Macro +*/ +void ddoc8271() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc8739.d b/gcc/testsuite/gdc.test/compilable/ddoc8739.d new file mode 100644 index 00000000000..cf7da98eda2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc8739.d @@ -0,0 +1,19 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 8739 + +module ddoc8739; + +/// +void delegate(int a) dg; + +/// +void delegate(int b) dg2; + +/// +void delegate(int c)[] dg3; + +/// +void delegate(int d)* dg4; + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9.d b/gcc/testsuite/gdc.test/compilable/ddoc9.d new file mode 100644 index 00000000000..21f312db44a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9.d @@ -0,0 +1,26 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9 + +// 273 + +/// Template Documentation (OK) +template Template(T) { } + +/// Function Documentation (Not included at all by DDoc) +void Function(T)(T x) { } + +/// Class Documentation (OK) +class Class(T) { } + +/// Struct Documentation +struct Struct(T) { } + +/// Union Documentation +union Union(T) { } + +/// Template documentation with anonymous enum +template TemplateWithAnonEnum(T) +{ + enum { TemplateWithAnonEnum = 1 } +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9037.d b/gcc/testsuite/gdc.test/compilable/ddoc9037.d new file mode 100644 index 00000000000..ac4ace249e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9037.d @@ -0,0 +1,18 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9037 + +module ddoc9037; + +/** +Example: +---- +D d = d; +---- +---- +D d = d; +---- +*/ +void test9037() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9155.d b/gcc/testsuite/gdc.test/compilable/ddoc9155.d new file mode 100644 index 00000000000..82b7f63ed9d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9155.d @@ -0,0 +1,81 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9155 + +module ddoc9155; + +/++ + + Note: + + test document note + + 2nd line + + Example: + + --- + + import std.stdio; //& + + writeln("Hello world!"); + + if (test) { + + writefln("D programming language"); + + } + + + + algorithm; + + + + xxx; //comment + + yyy; + + /* test + + * comment + + */ + + + + // Create MIME Base64 with CRLF, per line 76. + +File f = File("./text.txt", "r"); + +uint line = 0; + + // The ElementType of data is not aggregation type + +foreach (encoded; Base64.encoder(data)) + + --- + +/ + +/** + -------------------------------------------------------- + wstring ws; + transcode("hello world",ws); + // transcode from UTF-8 to UTF-16 + -------------------------------------------------------- + */ + +/** + * Example: + * --- + * import std.stdio; //& + * writeln("Hello world!"); + * if (test) { + * writefln("D programming language"); + * } + * + * algorithm; + * + * xxx; //comment + * yyy; + * /+ test + * + comment + * +/ + * --- + */ + +/** +---- +#!/usr/bin/env rdmd +// Computes average line length for standard input. +import std.stdio; +---- +*/ + +/** + --- + writefln(q"EOS + This + is a multi-line + heredoc string + EOS" + ); + --- +*/ + +void foo(){} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9305.d b/gcc/testsuite/gdc.test/compilable/ddoc9305.d new file mode 100644 index 00000000000..9c9b890657c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9305.d @@ -0,0 +1,38 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9305 + +module ddoc9305; + +/** +foo() +*/ +void foo(alias p = (a => a))() {} + +/* ret / prm / body */ +/* _ / _ / expr */ template X(alias pred = x => x) {} /// +/* _ / _ / stmt */ template X(alias pred = (x){ int y; return y; }) {} /// ditto +/* _ / x / expr */ template X(alias pred = (int x) => x) {} /// ditto +/* _ / x / stmt */ template X(alias pred = (int x){ int y; return y; }) {} /// ditto +/* x / _ / expr */ +/* x / _ / stmt */ +/* x / x / expr */ +/* x / x / stmt */ + +/* _ / _ / expr */ template X(alias pred = function (x) => x) {} /// +/* _ / _ / stmt */ template X(alias pred = function (x){ return x + 1; }) {} /// ditto +/* _ / x / expr */ template X(alias pred = function (int x) => x) {} /// ditto +/* _ / x / stmt */ template X(alias pred = function (int x){ return x + 1; }) {} /// ditto +/* x / _ / expr */ template X(alias pred = function int(x) => x) {} /// ditto +/* x / _ / stmt */ template X(alias pred = function int(x){ return x + 1; }) {} /// ditto +/* x / x / expr */ template X(alias pred = function int(int x) => x) {} /// ditto +/* x / x / stmt */ template X(alias pred = function int(int x){ return x + 1; }) {} /// ditto + +/* _ / _ / expr */ template X(alias pred = delegate (x) => x) {} /// +/* _ / _ / stmt */ template X(alias pred = delegate (x){ return x + 1; }) {} /// ditto +/* _ / x / expr */ template X(alias pred = delegate (int x) => x) {} /// ditto +/* _ / x / stmt */ template X(alias pred = delegate (int x){ return x + 1; }) {} /// ditto +/* x / _ / expr */ template X(alias pred = delegate int(x) => x) {} /// ditto +/* x / _ / stmt */ template X(alias pred = delegate int(x){ return x + 1; }) {} /// ditto +/* x / x / expr */ template X(alias pred = delegate int(int x) => x) {} /// ditto +/* x / x / stmt */ template X(alias pred = delegate int(int x){ return x + 1; }) {} /// ditto diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9369.d b/gcc/testsuite/gdc.test/compilable/ddoc9369.d new file mode 100644 index 00000000000..13bce824443 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9369.d @@ -0,0 +1,18 @@ +// PERMUTE_ARGS: +// EXTRA_SOURCES: extra-files/ddoc9369.ddoc +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9369 + +/** +Sample: +--- +a=1; +writeln(&a); +! +? +--- +*/ +void foo() { } + + + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9475.d b/gcc/testsuite/gdc.test/compilable/ddoc9475.d new file mode 100644 index 00000000000..460269ce676 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9475.d @@ -0,0 +1,29 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -w -o- -c -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9475 + +module ddoc9475; + +/// foo +void foo() { } + +/// +unittest +{ + // comment 1 + foreach (i; 0 .. 10) + { + // comment 2 + documentedFunction(); + } +} + +/// bar +void bar() { } + +/// +unittest +{ + // bar comment +} + diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497a.d b/gcc/testsuite/gdc.test/compilable/ddoc9497a.d new file mode 100644 index 00000000000..6617434b988 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9497a.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: extra-files/ddoc9497a.ddoc +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497a + +/** + foo function. + Args: $(XYZ arg1, arg2) +*/ +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497b.d b/gcc/testsuite/gdc.test/compilable/ddoc9497b.d new file mode 100644 index 00000000000..62ab44c8928 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9497b.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: extra-files/ddoc9497b.ddoc +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497b + +/** + foo function. + Args: $(XYZ arg1, arg2) +*/ +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497c.d b/gcc/testsuite/gdc.test/compilable/ddoc9497c.d new file mode 100644 index 00000000000..da9e3df11c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9497c.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: extra-files/ddoc9497c.ddoc +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497c + +/** + foo function. + Args: $(XYZ arg1, arg2) +*/ +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497d.d b/gcc/testsuite/gdc.test/compilable/ddoc9497d.d new file mode 100644 index 00000000000..c42f013e41c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9497d.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: extra-files/ddoc9497d.ddoc +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497d + +/** + foo function. + Args: $(XYZ arg1, arg2) +*/ +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9676a.d b/gcc/testsuite/gdc.test/compilable/ddoc9676a.d new file mode 100644 index 00000000000..fc12a6ec62d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9676a.d @@ -0,0 +1,9 @@ +// PERMUTE_ARGS: +// EXTRA_SOURCES: /extra-files/ddoc9676a.ddoc +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9676a + +module ddoc9676a; + +/// +deprecated void foo() {} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9676b.d b/gcc/testsuite/gdc.test/compilable/ddoc9676b.d new file mode 100644 index 00000000000..63145495ce8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9676b.d @@ -0,0 +1,8 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9676b + +module ddoc9676b; + +/// +deprecated void foo() {} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9727.d b/gcc/testsuite/gdc.test/compilable/ddoc9727.d new file mode 100644 index 00000000000..14e5fd2ab71 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9727.d @@ -0,0 +1,25 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9727 +module ddoc9727; + +/** The function foo. */ +void foo(int x); + +/** */ +unittest +{ + foo(1); +} + +/** foo can be used like this: */ +unittest +{ + foo(2); +} + +/** foo can also be used like this: */ +unittest +{ + foo(3); +} diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9789.d b/gcc/testsuite/gdc.test/compilable/ddoc9789.d new file mode 100644 index 00000000000..b220c7f8e76 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9789.d @@ -0,0 +1,11 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -w -o- -c -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9789 + +module ddoc9789; + +/// +struct S {} + +/// +alias A = S; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9903.d b/gcc/testsuite/gdc.test/compilable/ddoc9903.d new file mode 100644 index 00000000000..00b6a7982a2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddoc9903.d @@ -0,0 +1,35 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9903 + +/// sss +struct S9903X {} +/// Ditto +struct S9903Y {} + +/// ccc +class C9903X {} +/// Ditto +class C9903Y {} + +/// uuu +union U9903X {} +/// Ditto +union U9903Y {} + +/// iii +interface I9903X {} +/// Ditto +interface I9903Y {} + +/// eee +enum E9903X { a } +/// Ditto +enum E9903Y { a } + +/// +enum { + a9903, /// ea + b9903, /// Ditto + c9903, /// ec +} diff --git a/gcc/testsuite/gdc.test/compilable/ddocYear.d b/gcc/testsuite/gdc.test/compilable/ddocYear.d new file mode 100644 index 00000000000..ec8578f456b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddocYear.d @@ -0,0 +1,6 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocYear-postscript.sh + +/// $(YEAR) +int year; diff --git a/gcc/testsuite/gdc.test/compilable/ddocbackticks.d b/gcc/testsuite/gdc.test/compilable/ddocbackticks.d new file mode 100644 index 00000000000..8249c4b00d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddocbackticks.d @@ -0,0 +1,24 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh backticks + +/++ + Closely related to std.datetime is `core.time`, + and some of the time types used in std.datetime come from there - such as + $(CXREF time, Duration), $(CXREF time, TickDuration), and + $(CXREF time, FracSec). + core.time is publically imported into std.datetime, it isn't necessary + to import it separately. ++/ +module ddocbackticks; + +/// This should produce `inline code`. +void test() {} + +/// But `this should NOT be inline' +/// +/// However, restarting on a new line should be `inline again`. +void test2() {} + +/// This `int foo;` should show highlight on foo, but not int. +void foo() {} diff --git a/gcc/testsuite/gdc.test/compilable/ddocunittest.d b/gcc/testsuite/gdc.test/compilable/ddocunittest.d new file mode 100644 index 00000000000..940ef1caf34 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ddocunittest.d @@ -0,0 +1,496 @@ +// PERMUTE_ARGS: -unittest +// REQUIRED_ARGS: -D -w -o- -c -Dd${RESULTS_DIR}/compilable -o- +// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh unittest + +module ddocunittest; + +/* Insert test-cases for documented unittests feature here. */ + +/// foo function - 1 example +int foo(int a, int b) { return a + b; } + +/// +unittest +{ + assert(foo(1, 1) == 2); +} + +/// bar function - 1 example +bool bar() { return true; } + +/// +unittest +{ + // documented + assert(bar()); +} + +/// placeholder +unittest +{ +} + +/// doo function - no examples +void doo() { } + +/// +private unittest +{ + // undocumented + doo(); +} + +unittest +{ + // undocumented + doo(); +} + +/** +add function - 3 examples + +Examples: + +---- +assert(add(1, 1) == 2); +---- +*/ +int add(int a, int b) { return a + b; } + +/// +unittest +{ + // documented + assert(add(3, 3) == 6); + assert(add(4, 4) == 8); +} + +unittest +{ + // undocumented + assert(add(2, 2) + add(2, 2) == 8); +} + +/// +unittest +{ + // documented + assert(add(5, 5) == 10); + assert(add(6, 6) == 12); +} + +/// class Foo +immutable pure nothrow class Foo +{ + int x; + + /// + unittest + { + // another foo example + Foo foo = new Foo; + } +} + +/// +unittest +{ + Foo foo = new Foo; +} + +pure +{ + const + { + immutable + { + /// some class - 1 example + class SomeClass {} + } + } +} + +/// +unittest +{ + SomeClass sc = new SomeClass; +} + +/// Outer - 1 example +class Outer +{ + /// Inner + static class Inner + { + } + + /// + unittest + { + Inner inner = new Inner; + } +} + +/// +unittest +{ + Outer outer = new Outer; +} + +/** foobar - no examples */ +void foobar() +{ +} + +unittest +{ + foobar(); +} + +/** +func - 4 examples +Examples: +--- +foo(1); +--- + +Examples: +--- +foo(2); +--- +*/ +void foo(int x) { } + +/// +unittest +{ + foo(2); +} + +/// +unittest +{ + foo(4); +} + +// ------------------------------------ +// insert import declaration between documented function and unittests + +/// +void fooImport() {} +import core.stdc.stdio; +/// test +unittest { fooImport(); } + +/// +void fooStaticImport() {} +static import core.stdc.stdlib; +/// test +unittest { fooStaticImport(); } + +/// +void fooPublicImport() {} +public import core.stdc.string; +/// test +unittest { fooPublicImport(); } + +/// +void fooSelectiveImport() {} +import core.stdc.ctype : isalpha; +/// test +unittest { fooSelectiveImport(); } + +/// +void fooRenamedImport() {} +import io = core.stdc.stdio; +/// test +unittest { fooRenamedImport(); } + +// ------------------------------------ +// documented unittest after conditional declarations + +static if (true) + void fooConditionalDecl1a() {} /** */ +unittest { int x1a; } /// + +static if (true) +{ void fooConditionalDecl1b() {} /** */ } +unittest { int x1b; } /// + +static if (false) + void fooConditionalDecl2a() {} /** */ +unittest { int x2a; } /// + +static if (false) +{ void fooConditionalDecl2b() {} /** */ } +unittest { int x2b; } /// + +static if (true) +{ void fooConditionalDecl3a() {} /** */ } +else +{ void barConditionalDecl3a() {} /** */ } +unittest { int x3a; } /// + +static if (true) +{ void fooConditionalDecl3b() {} /** */ } +else +{ void barConditionalDecl3b() {} /** */ } +unittest { int x3b; } /// + +static if (false) + void fooConditionalDecl4a() {} /** */ +else + void barConditionalDecl4a() {} /** */ +unittest { int x4a; } /// + +static if (false) +{ void fooConditionalDecl4b() {} /** */ } +else +{ void barConditionalDecl4b() {} /** */ } +unittest { int x4b; } /// + +static if (true) +{} +else + void barConditionalDecl5a() {} /** */ +unittest { int x5a; } /// + +static if (true) +{} +else +{ void barConditionalDecl5b() {} /** */ } +unittest { int x5b; } /// + +static if (false) +{} +else + void barConditionalDecl6a() {} /** */ +/// +unittest { int x6a; } + +static if (false) +{} +else +{ void barConditionalDecl6b() {} /** */ } +/// +unittest { int x6b; } + +// ------------------------------------ +// 9474 + +/// +void foo9474() { } + +version(none) +unittest { } + +/// Example +unittest { foo9474(); } + +/// doc +void bar9474() { } + +version(none) +unittest { } + +/// Example +unittest { bar9474(); } + +/// +struct S9474 +{ +} +/// +unittest { S9474 s; } + +/// +auto autovar9474 = 1; +/// +unittest { int v = autovar9474; } + +/// +auto autofun9474() { return 1; } +/// + unittest { int n = autofun9474(); } + +/// +template Template9474() +{ + /// Shouldn't link following unittest to here + void foo() {} +} +/// +unittest { alias Template9474!() T; } + +// ------------------------------------ +// 9713 + +/// +void fooNoDescription() {} +/// +unittest { fooNoDescription(); } +/// +unittest { if (true) {fooNoDescription(); } /* comment */ } + +// ------------------------------------ + +/// test for bugzilla 9757 +void foo9757() {} +/// ditto +void bar9757() {} +/// ditto +void baz9757() {} +/// +unittest { foo9757(); bar9757(); } +/// +unittest { bar9757(); foo9757(); } + +/// with template functions +auto redBlackTree(E)(E[] elems...) +{ + return 1; +} +/// ditto +auto redBlackTree(bool allowDuplicates, E)(E[] elems...) +{ + return 2; +} +/// ditto +auto redBlackTree(alias less, E)(E[] elems...) +{ + return 3; +} +/// +unittest +{ + auto rbt1 = redBlackTree(0, 1, 5, 7); + auto rbt2 = redBlackTree!string("hello", "world"); + auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5); + auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7); +} + +// ------------------------------------ +// Issue 9758 + +/// test +void foo(){} + +/// +unittest { } + +// ------------------------------------ +// Issue 10519 + +/// +bool balancedParens10519(string, char, char) { return true; } +/// +unittest +{ + auto s = "1 + (2 * (3 + 1 / 2)"; + assert(!balancedParens10519(s, '(', ')')); +} + +// ------------------------------------ +// Issue 12097 + +/// declaration +struct S12097 +{ + /// method + void foo() {} +} + +/// ditto +void f12097() {} + +/// ddoc code 1 +unittest +{ + int a = 1; +} + +/// ditto +struct T12097(T) {} + +/// ddoc code 2 +unittest +{ + int[] arr; +} + +// ------------------------------------ +// 14594 + +/******************* + * testA + */ +void fun14594a()() {} +/// +unittest { fun14594a(); } + +/******************* + * testB + */ +void fun14594b()() {} +/// ditto +void fun14594b(T)(T) {} +/// +unittest { fun14594b(); fun14594b(1); } + +/******************* + * testC + */ +void fun14594c()() {} +/// +unittest { fun14594c(); fun14594c(1); } +/// ditto +void fun14594c(T)(T) {} + +/******************* + * testD + */ +void fun14594d()() {} +/// +unittest { fun14594d(); } +/// ditto +void fun14594d(T)(T) {} +/// +unittest { fun14594d(1); } + +/******************* + * testE + */ +template fun14594e() +{ + /// concatenated doc-comment fun14594e + void fun14594e() {} + /// ignored-unittest fun14594e + unittest { fun14594e(); } +} +/// doc-unittest fun14594e +unittest { fun14594e(); } + +/******************* + * testF + */ +template fun14594f() +{ + /// concatenated doc-comment fun14594f + void fun14594f() {} + /// ignored-unittest fun14594f + unittest { fun14594f(); } +} +/// ditto +template fun14594f(T) +{ + /// ignored doc-comment fun14594f + void fun14594f(T) {} + /// ignored-unittest fun14594f + unittest { fun14594f(1); } +} +/// doc-unittest fun14594f +unittest { fun14594f(); } + +// ------------------------------------ + +void main() { } diff --git a/gcc/testsuite/gdc.test/compilable/debuginfo.d b/gcc/testsuite/gdc.test/compilable/debuginfo.d new file mode 100644 index 00000000000..320019515c5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/debuginfo.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -g + +struct Bug7127a { + const(Bug7127a)* self; +} + +struct Bug7127b { + void function(const(Bug7127b) self) foo; +} + +void main() { + Bug7127a a; + Bug7127b b; +} + +// https://issues.dlang.org/show_bug.cgi?id=13975 +static immutable int a = 8; +enum Bar { aa = a } + +void foo(Bar bar) {} diff --git a/gcc/testsuite/gdc.test/compilable/defa.d b/gcc/testsuite/gdc.test/compilable/defa.d new file mode 100644 index 00000000000..4fb700bed44 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/defa.d @@ -0,0 +1,19 @@ +// PERMUTE_ARGS: + +module defa; + +private import imports.defaa; + +public abstract class A +{ + Display d; + int style; + + this() {} + + public this(A parent, int style) + { + this.style = style; + d = parent.d; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/depmsg.d b/gcc/testsuite/gdc.test/compilable/depmsg.d new file mode 100644 index 00000000000..c841916a5ff --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/depmsg.d @@ -0,0 +1,33 @@ +// REQUIRED_ARGS: -d +// PERMUTE_ARGS: -dw + +void main() +{ + class Inner + { + deprecated("With message!") + { + struct A { } + class B { } + interface C { } + union D { } + enum E { e }; + //typedef int F; + alias int G; + static int H; + template I() { class I {} } + } + } + with(Inner) + { + A a; + B b; + C c; + D d; + E e; + //F f; + G g; + auto h = H; + I!() i; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/deprecate12979a.d b/gcc/testsuite/gdc.test/compilable/deprecate12979a.d new file mode 100644 index 00000000000..afe919af13d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/deprecate12979a.d @@ -0,0 +1,27 @@ +// REQUIRED_ARGS: -dw +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +compilable/deprecate12979a.d(13): Deprecation: asm statement is assumed to throw - mark it with `nothrow` if it does not +--- +*/ + +void foo() nothrow +{ + version(GNU) + { + asm + { + ""; + } + } + else + { + asm + { + ret; + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/deprecate14283.d b/gcc/testsuite/gdc.test/compilable/deprecate14283.d new file mode 100644 index 00000000000..9c82add1776 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/deprecate14283.d @@ -0,0 +1,18 @@ +// REQUIRED_ARGS: -dw +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +--- +*/ + +class C +{ + void bug() + { + autoref(this); // 'auto ref' becomes non-ref parameter + autoref(super); // 'auto ref' becomes non-ref parameter + } +} + +void autoref(T)(auto ref T t) { static assert(__traits(isRef, t) == false); } diff --git a/gcc/testsuite/gdc.test/compilable/depsOutput9948.d b/gcc/testsuite/gdc.test/compilable/depsOutput9948.d new file mode 100644 index 00000000000..5ba4897a1f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/depsOutput9948.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -deps=${RESULTS_DIR}/compilable/depsOutput9948.deps +// POST_SCRIPT: compilable/extra-files/depsOutput.sh +// EXTRA_SOURCES: /extra-files/depsOutput9948a.d + +module depsOutput9948; +import depsOutput9948a; + +void main() +{ + templateFunc!("import std.string;")(); +} diff --git a/gcc/testsuite/gdc.test/compilable/derivedarray.d b/gcc/testsuite/gdc.test/compilable/derivedarray.d new file mode 100644 index 00000000000..7a7f3c8c44b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/derivedarray.d @@ -0,0 +1,130 @@ +// PERMUTE_ARGS: + +class C {} +class D : C {} + +void dynamicarrays() +{ + C[] a; + D[] b; + const(C)[] c; + const(D)[] d; + immutable(C)[] e; + immutable(D)[] f; + + static assert( __traits(compiles, a = a)); + static assert(!__traits(compiles, a = b)); + static assert(!__traits(compiles, a = c)); + static assert(!__traits(compiles, a = d)); + static assert(!__traits(compiles, a = e)); + static assert(!__traits(compiles, a = f)); + + static assert(!__traits(compiles, b = a)); + static assert( __traits(compiles, b = b)); + static assert(!__traits(compiles, b = c)); + static assert(!__traits(compiles, b = d)); + static assert(!__traits(compiles, b = e)); + static assert(!__traits(compiles, b = f)); + + static assert( __traits(compiles, c = a)); + static assert( __traits(compiles, c = b)); + static assert( __traits(compiles, c = c)); + static assert( __traits(compiles, c = d)); + static assert( __traits(compiles, c = e)); + static assert( __traits(compiles, c = f)); + + static assert(!__traits(compiles, d = a)); + static assert( __traits(compiles, d = b)); + static assert(!__traits(compiles, d = c)); + static assert( __traits(compiles, d = d)); + static assert(!__traits(compiles, d = e)); + static assert( __traits(compiles, d = f)); + + static assert(!__traits(compiles, e = a)); + static assert(!__traits(compiles, e = b)); + static assert(!__traits(compiles, e = c)); + static assert(!__traits(compiles, e = d)); + static assert( __traits(compiles, e = e)); + static assert( __traits(compiles, e = f)); + + static assert(!__traits(compiles, f = a)); + static assert(!__traits(compiles, f = b)); + static assert(!__traits(compiles, f = c)); + static assert(!__traits(compiles, f = d)); + static assert(!__traits(compiles, f = e)); + static assert( __traits(compiles, f = f)); +} + + +void statictodynamicarrays() +{ + C[] a; + D[] b; + const(C)[] c; + const(D)[] d; + immutable(C)[] e; + immutable(D)[] f; + + C[1] sa; + D[1] sb; + const(C)[1] sc = void; + const(D)[1] sd = void; + immutable(C)[1] se = void; + immutable(D)[1] sf = void; + + static assert( __traits(compiles, a = sa)); + static assert(!__traits(compiles, a = sb)); + static assert(!__traits(compiles, a = sc)); + static assert(!__traits(compiles, a = sd)); + static assert(!__traits(compiles, a = se)); + static assert(!__traits(compiles, a = sf)); + + static assert(!__traits(compiles, b = sa)); + static assert( __traits(compiles, b = sb)); + static assert(!__traits(compiles, b = sc)); + static assert(!__traits(compiles, b = sd)); + static assert(!__traits(compiles, b = se)); + static assert(!__traits(compiles, b = sf)); + + static assert( __traits(compiles, c = sa)); + static assert( __traits(compiles, c = sb)); + static assert( __traits(compiles, c = sc)); + static assert( __traits(compiles, c = sd)); + static assert( __traits(compiles, c = se)); + static assert( __traits(compiles, c = sf)); + + static assert(!__traits(compiles, d = sa)); + static assert( __traits(compiles, d = sb)); + static assert(!__traits(compiles, d = sc)); + static assert( __traits(compiles, d = sd)); + static assert(!__traits(compiles, d = se)); + static assert( __traits(compiles, d = sf)); + + static assert(!__traits(compiles, e = sa)); + static assert(!__traits(compiles, e = sb)); + static assert(!__traits(compiles, e = sc)); + static assert(!__traits(compiles, e = sd)); + static assert( __traits(compiles, e = se)); + static assert( __traits(compiles, e = sf)); + + static assert(!__traits(compiles, f = sa)); + static assert(!__traits(compiles, f = sb)); + static assert(!__traits(compiles, f = sc)); + static assert(!__traits(compiles, f = sd)); + static assert(!__traits(compiles, f = se)); + static assert( __traits(compiles, f = sf)); +} + +void staticarrays() +{ + C[1] sa; + D[1] sb; + + const(C)[1] sc = sa; + const(D)[1] sd = sb; + + sa = sb; + static assert(!__traits(compiles, sb = sa)); +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/diag11066.d b/gcc/testsuite/gdc.test/compilable/diag11066.d new file mode 100644 index 00000000000..3d9383189a5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/diag11066.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w -profile +/* +TEST_OUTPUT: +--- +--- +*/ + +void main() +{ + string s; + foreach (dchar c; s) // affected by dchar + return; +} diff --git a/gcc/testsuite/gdc.test/compilable/diag3243.d b/gcc/testsuite/gdc.test/compilable/diag3243.d new file mode 100644 index 00000000000..b25d0bb3819 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/diag3243.d @@ -0,0 +1,19 @@ +// REQUIRED_ARGS: -vtls +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +--- +*/ + +template T() +{ + static this() {} +} + +class C +{ + alias ti = T!(); +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/dip22.d b/gcc/testsuite/gdc.test/compilable/dip22.d new file mode 100644 index 00000000000..5c0201a070f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/dip22.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -de +import imports.dip22; + +class Foo : Base1, Base2 +{ + void test() + { + static assert(typeof(bar()).sizeof == 2); + static assert(baz == 2); + static assert(T.sizeof == 2); + } +} + +void test() +{ + bar(12); + baz(12); + 12.bar(); + 12.baz(); +} diff --git a/gcc/testsuite/gdc.test/compilable/empty_file.d b/gcc/testsuite/gdc.test/compilable/empty_file.d new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gcc/testsuite/gdc.test/compilable/exception.d b/gcc/testsuite/gdc.test/compilable/exception.d new file mode 100644 index 00000000000..0b85762fe7d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/exception.d @@ -0,0 +1,18 @@ +class E2 : Exception { this() { super(null); } } +class E3 : Exception { this() { super(null); } } + +void main() +{ + try + { + } + catch (E3) + { + } + catch (E2) + { + } + catch (Exception) + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/c6395.d b/gcc/testsuite/gdc.test/compilable/extra-files/c6395.d new file mode 100644 index 00000000000..47e9c9c3523 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/c6395.d @@ -0,0 +1,20 @@ +// 6395 + +template map(alias fun) { + auto map(Range)(Range r) { + struct Result + { + @property auto ref front() + { + return fun("a"); + } + } + return Result(); + } +} + +Range find(alias pred, Range)(Range haystack) { + pred(haystack.front); + return haystack; +} + diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc10367.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc10367.ddoc new file mode 100644 index 00000000000..2b1dcee52ab --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc10367.ddoc @@ -0,0 +1 @@ +DDOC_ENUM_BASETYPE = $(RED $0) diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc198.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc198.ddoc new file mode 100644 index 00000000000..4b69e8f6bf3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc198.ddoc @@ -0,0 +1,2 @@ +DDOC_PSYMBOL = $0 +DDOC_PSUPER_SYMBOL = $0 diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc3.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc3.ddoc new file mode 100644 index 00000000000..ff8fcae04a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc3.ddoc @@ -0,0 +1,3 @@ +HELLO = world + +UNUSED=unused \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9369.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9369.ddoc new file mode 100644 index 00000000000..04fb07b446d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9369.ddoc @@ -0,0 +1,3 @@ +ESCAPES = /&/AddressOf!/ + /!/Exclamation/ + /?/QuestionMark/ diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497a.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497a.ddoc new file mode 100644 index 00000000000..b543e1f95e9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497a.ddoc @@ -0,0 +1 @@ +DDOC_UNDEFINED_MACRO= \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497b.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497b.ddoc new file mode 100644 index 00000000000..d1cdd903733 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497b.ddoc @@ -0,0 +1 @@ +DDOC_UNDEFINED_MACRO=$(DOLLAR)($1 $+) diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497c.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497c.ddoc new file mode 100644 index 00000000000..5d71cdf87d5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497c.ddoc @@ -0,0 +1 @@ +DDOC_UNDEFINED_MACRO=$+ diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497d.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497d.ddoc new file mode 100644 index 00000000000..619fb9e2987 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9497d.ddoc @@ -0,0 +1 @@ +DDOC_UNDEFINED_MACRO=ERROR_UNDEFINED_MACRO: "$1" diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9676a.ddoc b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9676a.ddoc new file mode 100644 index 00000000000..63be0be03f7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/ddoc9676a.ddoc @@ -0,0 +1 @@ +DEPRECATED = $0 diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d b/gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d new file mode 100644 index 00000000000..3f4e3a3d3b6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d @@ -0,0 +1,6 @@ +module depsOutput9948a; + +void templateFunc(string myImport)() +{ + mixin(myImport); +} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/e6815.d b/gcc/testsuite/gdc.test/compilable/extra-files/e6815.d new file mode 100644 index 00000000000..96c5d92e222 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/e6815.d @@ -0,0 +1,7 @@ +bool e(T)(T) +{ + f(true); + return true; +} + +void f(lazy bool) {} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/example7190/controllers/HomeController.d b/gcc/testsuite/gdc.test/compilable/extra-files/example7190/controllers/HomeController.d new file mode 100644 index 00000000000..e83653a9b32 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/example7190/controllers/HomeController.d @@ -0,0 +1,7 @@ +module example7190.controllers.HomeController; + +import serenity7190.core.Controller; + +class HomeController : Controller { + mixin register!(HomeController); +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/example7190/models/HomeModel.d b/gcc/testsuite/gdc.test/compilable/extra-files/example7190/models/HomeModel.d new file mode 100644 index 00000000000..17709481874 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/example7190/models/HomeModel.d @@ -0,0 +1,11 @@ +module example7190.models.HomeModel; + +import serenity7190.core.Model; + +struct Article { + ulong id; +} + +class HomeModel : Model { + private SqlitePersister!Article mArticles; +} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d new file mode 100644 index 00000000000..a746a2aac06 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d @@ -0,0 +1,521 @@ +module foo.bar; + +import core.vararg; +import std.stdio; + +pragma(lib, "test"); +pragma(msg, "Hello World"); + +static assert(true, "message"); + +alias double mydbl; + +int testmain() +in +{ + assert(1+(2+3) == -(1 - 2*3)); +} +out (result) +{ + assert(result == 0); +} +body +{ + float f = float.infinity; + int i = cast(int) f; + writeln((i,1),2); + writeln(cast(int)float.max); + assert(i == cast(int)float.max); + assert(i == 0x80000000); + return 0; +} + +struct S { int m, n; } + +template Foo(T, int V) +{ + void foo(...) + { + static if (is(Object _ : X!TL, alias X, TL...)) {} // Bugzilla 10044 + + auto x = __traits(hasMember, Object, "noMember"); + auto y = is(Object : X!TL, alias X, TL...); + assert(!x && !y, "message"); + + S s = { 1,2 }; + auto a = [1, 2, 3]; + auto aa = [1:1, 2:2, 3:3]; + + int n,m; + } + + int bar(double d, int x) + { + if (d) + { d++; + } + else + d--; + + asm + { naked ; + mov EAX, 3; + } + + for (;;) + { + d = d + 1; + } + + for (int i = 0; i < 10; i++) + { + d = i ? d + 1 : 5; + } + + char[] s; + foreach (char c; s) + { + d *= 2; + if (d) + break; + else + continue; + } + + switch (V) + { + case 1: + case 2: break; + case 3: goto case 1; + case 4: goto default; + default: + d /= 8; + break; + } + + enum Label { A, B, C } + void fswitch(Label l) + { + final switch (l) + { + case A: break; + case B: break; + case C: break; + } + } + + loop: + while (x) + { + x--; + if (x) + break loop; + else + continue loop; + } + + do + { + x++; + } while (x < 10); + + try + { + bar(1, 2); + } + catch (Object o) + { + x++; + } + finally + { + x--; + } + + try + bar(1, 2); + catch(Object o) + x++; + finally + x--; + + Object o; + synchronized (o) + { + x = ~x; + } + + synchronized + { + x = x < 3; + } + + with (o) + { + toString(); + } + } +} + +static this() +{ +} + +static ~this() +{ +} + +pure nothrow @safe @nogc static this() {} +pure nothrow @safe @nogc static ~this() {} +static this() pure nothrow @safe @nogc {} +static ~this() pure nothrow @safe @nogc {} + +pure nothrow @safe @nogc shared static this() {} +pure nothrow @safe @nogc shared static ~this() {} +shared static this() pure nothrow @safe @nogc {} +shared static ~this() pure nothrow @safe @nogc {} + +interface iFoo{} +class xFoo: iFoo{} + +interface iFoo2{} +class xFoo2: iFoo, iFoo2{} + +class Foo3 +{ + this(int a, ...){} + this(int* a){} +} + +alias int myint; + +static notquit = 1; + +class Test +{ + void a() {} + void b() {} + void c() {} + void d() {} + void e() {} + void f() {} + void g() {} + void h() {} + void i() {} + void j() {} + void k() {} + void l() {} + void m() {} + void n() {} + void o() {} + void p() {} + void q() {} + void r() {} + void s() {} + void t() {} + void u() {} + void v() {} + void w() {} + void x() {} + void y() {} + void z() {} + + void aa() {} + void bb() {} + void cc() {} + void dd() {} + void ee() {} // Try adding or removing some functions here to see the effect. + + template A(T) { } + + alias A!(uint) getHUint; + alias A!(int) getHInt; + alias A!(float) getHFloat; + alias A!(ulong) getHUlong; + alias A!(long) getHLong; + alias A!(double) getHDouble; + alias A!(byte) getHByte; + alias A!(ubyte) getHUbyte; + alias A!(short) getHShort; + alias A!(ushort) getHUShort; + alias A!(real) getHReal; + + alias void F(); + + pure nothrow @safe @nogc unittest {} + pure nothrow @safe @nogc invariant {} + + pure nothrow @safe @nogc new (size_t sz) { return null; } + pure nothrow @safe @nogc delete (void* p) { } +} + +template templ( T ) +{ + void templ( T val ) + { + pragma( msg, "Invalid destination type." ); + } +} + +static char[] charArray = [ '\"', '\'' ]; + +class Point +{ + auto x = 10; + uint y = 20; +} + +template Foo2(bool bar) +{ + void test() + { + static if(bar) + { + int i; + } + else + { + } + static if(!bar) + { + } + else + { + } + } +} + + +template Foo4() +{ + void bar() + { + } +} + +template Foo4x( T... ) {} + +class Baz4 +{ + mixin Foo4 foo; + mixin Foo4x!(int, "str") foox; + + alias foo.bar baz; +} + +int test(T)(T t) +{ + if (auto o = cast(Object)t) return 1; + return 0; +} + +enum x6 = 1; + +bool foo6(int a, int b, int c, int d) +{ + return (a < b) != (c < d); +} + +auto foo7(int x) +{ + return 5; +} + +class D8{} +void func8() +{ + scope a= new D8(); +} + +T func9(T)() if (true) +{ + T i; + scope(exit) i= 1; + scope(success) i = 2; + scope(failure) i = 3; + return i; +} + +template V10(T) +{ + void func() + { + for(int i,j=4; i<3;i++) + { + } + } +} + +int foo11(int function() fn) +{ + return fn(); +} + +int bar11(T)() +{ + return foo11(function int (){ return 0; }); +} + + +struct S6360 +{ + @property long weeks1() const pure nothrow { return 0; } + + @property const pure nothrow long weeks2() { return 0; } +} + + +struct S12 +{ + /// postfix storage class and constructor + this(int n) nothrow{} + + /// prefix storage class (==StorageClassDeclaration) and constructor + nothrow this(string s){} +} + +/// dummy +struct T12 +{ + /// postfix storage class and template constructor + this()(int args) immutable { } + + /// prefix storage class (==StorageClassDeclaration) and template constructor + immutable this(A...)(A args){ } +} + + +// 6591 +import std.stdio : writeln, F = File; + +void foo6591()() +{ + import std.stdio : writeln, F = File; +} + + +// 8081 +version(unittest) { + pure nothrow unittest {} + pure nothrow unittest {} + + public unittest {} + extern(C) unittest {} + align unittest {} +} + + +// 10334 + +template Foo10334(T) if (Bar10334!()) {} /// +template Foo10334(T) if (Bar10334!100) {} /// +template Foo10334(T) if (Bar10334!3.14) {} /// +template Foo10334(T) if (Bar10334!"str") {} /// +template Foo10334(T) if (Bar10334!1.4i) {} /// +template Foo10334(T) if (Bar10334!null) {} /// +template Foo10334(T) if (Bar10334!true) {} /// +template Foo10334(T) if (Bar10334!false) {} /// +template Foo10334(T) if (Bar10334!'A') {} /// +template Foo10334(T) if (Bar10334!int) {} /// +template Foo10334(T) if (Bar10334!string) {} /// +template Foo10334(T) if (Bar10334!wstring) {} /// +template Foo10334(T) if (Bar10334!dstring) {} /// +template Foo10334(T) if (Bar10334!this) {} /// +template Foo10334(T) if (Bar10334!([1,2,3])) {} /// +template Foo10334(T) if (Bar10334!(Baz10334!())) {} /// +template Foo10334(T) if (Bar10334!(Baz10334!T)) {} /// +template Foo10334(T) if (Bar10334!(Baz10334!100)) {} /// +template Foo10334(T) if (Bar10334!(.foo)) {} /// +template Foo10334(T) if (Bar10334!(const int)) {} /// +template Foo10334(T) if (Bar10334!(shared T)) {} /// + +template Test10334(T...) {} /// +mixin Test10334!int a; /// +mixin Test10334!(int,long) b; /// +mixin Test10334!"str" c; /// + +// 12266 +auto clamp12266a(T1, T2, T3)(T1 x, T2 min_val, T3 max_val) +{ + return 0; +} +pure clamp12266b(T1, T2, T3)(T1 x, T2 min_val, T3 max_val) +{ + return 0; +} +@disable pure clamp12266c(T1, T2, T3)(T1 x, T2 min_val, T3 max_val) +{ + return 0; +} + +// 13832 +alias Dg13832 = ref int delegate(); + +// 16590 +class TestClass { + int aa; + int b1, b2; + this(int b1, int b2) + { + this.b1 = b1; + this.b2 = b2; + } + + ref foo() { + return aa; + } + + ref retFunc() return { + return aa; + } + + ~this() @trusted @disable @nogc { + } +} + +class FooA { + protected void method42() { + + } + + ~this() @safe { + } + +} + + +class Bar : FooA { + override void method42() { + + } +} + +double foo() @trusted { + int a = 5; + return a; +} + +struct Foo1(size_t Size = 42 / magic()) { + +} + + +size_t magic() { + return 42; +} + +class Foo2A { + + immutable(FooA) Dummy = new immutable(FooA); + private immutable pure nothrow @nogc @safe this() { + + } + +} + +// bugzilla 15676 +struct Foo3A(T) +{ + @disable this(this); + @disable this(); +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header2.d b/gcc/testsuite/gdc.test/compilable/extra-files/header2.d new file mode 100644 index 00000000000..f8c52ff1541 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/header2.d @@ -0,0 +1,152 @@ +// for D 2.0 only + +class C { } + +void foo(const C c, const(char)[] s, const int* q, const (int*) p) +{ +} + +void bar(in void *p) +{ +} + +void f(void function() f2); + +class C2; +void foo2(const C2 c); + +struct Foo3 +{ + int k; + ~this() @trusted @disable @nogc { k = 1; } + this(this) { k = 2; } +} + + +class C3 { @property int get() { return 0; } } + +T foo3(T)() {} + +struct S4A(T) +{ + T x; + ~this() @safe {} +} + +struct S4B(T) if (1) +{ + T x; +} + +union U4A(T) +{ + T x; +} + +union U4B(T) if (2*4 == 8) +{ + T x; +} + +class C4A(T) +{ + T x; +} + +class C4B(T) if (true) { T x; } + +class C4C(T) : C4A!int if (!false) +{ + T x; +} + +class C4D(T) if (!false) : C4B!long, C4C!(int[]) +{ + T x; +} + +interface I4(T) if ((int[1]).length == 1) { T x; } + +// eponymous template case +template MyClass4(T) + if (is(typeof(T.subtype))) +{ + alias HelperSymbol = T.subtype; + class MyClass4 {} +} + +enum isInt(T) = is(T == int); +enum bool isString(T) = is(T == string); +static immutable typeName(T) = T.stringof; +int storageFor(T) = 0; + +template templateVariableFoo(T) +{ + enum int templateVariableFoo = T.stringof.length; +} +template templateVariableBar(T) if (is(T == int)) +{ + enum int templateVariableBar = T.stringof.length; +} + +auto flit = 3 / 2.0; + +// 11217 +void foo11217()( const int[] arr) {} +void foo11217()(immutable int[] arr) {} +void foo11217()( ref int[] arr) {} +void foo11217()( lazy int[] arr) {} +void foo11217()( auto ref int[] arr) {} +void foo11217()( scope int[] arr) {} +void foo11217()( in int[] arr) {} +void foo11217()( inout int[] arr) {} + +// 13275 +void test13275() +{ + if ( auto n = 1) {} + if ( const n = 1) {} + if ( immutable n = 1) {} + if (shared n = 1) {} + if (shared const n = 1) {} + + if ( int n = 1) {} + + if ( const int n = 1) {} + if ( immutable int n = 1) {} + if (shared int n = 1) {} + if (shared const int n = 1) {} + + if ( const(int) n = 1) {} + if ( immutable(int) n = 1) {} + if (shared (int) n = 1) {} + if (shared const(int) n = 1) {} + + foreach ( e; [1,2]) {} + foreach ( const e; [1,2]) {} + foreach ( immutable e; [1,2]) {} + foreach (shared e; [1,2]) {} + foreach (shared const e; [1,2]) {} + + foreach ( int e; [1,2]) {} + foreach ( const int e; [1,2]) {} + foreach ( immutable int e; [1,2]) {} + foreach (shared int e; [1,2]) {} + foreach (shared const int e; [1,2]) {} + + foreach ( int e; [1,2]) {} + foreach ( const(int) e; [1,2]) {} + foreach ( immutable(int) e; [1,2]) {} + foreach (shared (int) e; [1,2]) {} + foreach (shared const(int) e; [1,2]) {} +} + +// 9766 +align (1) struct S9766 +{ +align (true ? 2 : 3): + int var1; + +align: + int var2; +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header3.d b/gcc/testsuite/gdc.test/compilable/extra-files/header3.d new file mode 100644 index 00000000000..57680a6d99f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/header3.d @@ -0,0 +1,14 @@ +auto elseifchain() +{ + bool a,b,c; + + if (a) + { + } + else if (b) + { + } + else if (c) + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/imp12624.d b/gcc/testsuite/gdc.test/compilable/extra-files/imp12624.d new file mode 100644 index 00000000000..bb572ddae3d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/imp12624.d @@ -0,0 +1,27 @@ +// typecons.d +template RebindableCommon(T, U, This) +{ + union { U stripped; } + + void opAssign(T another) + { + stripped = cast() another; + } + + this(T initializer) + { + opAssign(initializer); + } +} + + +template Rebindable(T) +{ + static if (is(T == immutable U, U)) + struct Rebindable + { + mixin RebindableCommon!(T, U, Rebindable); + } +} + + diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d b/gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d new file mode 100644 index 00000000000..54598dd7769 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d @@ -0,0 +1,5 @@ +struct BugInt +{ + uint[] data = ZEROX; +} +enum uint [] ZEROX = [0]; diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/imp9057_2.d b/gcc/testsuite/gdc.test/compilable/extra-files/imp9057_2.d new file mode 100644 index 00000000000..07061b32c97 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/imp9057_2.d @@ -0,0 +1,5 @@ +struct BugInt +{ + uint[] data = [0]; +} + diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/common.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/common.d new file mode 100644 index 00000000000..5a402abe482 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/common.d @@ -0,0 +1,3 @@ +module pkgDIP37.datetime.common; + +void def(); diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/package.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/package.d new file mode 100644 index 00000000000..93b007b69fc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/datetime/package.d @@ -0,0 +1,3 @@ +module pkgDIP37.datetime; +public import pkgDIP37.datetime.common; +//alias std.datetime.common.def def; diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/common.di b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/common.di new file mode 100644 index 00000000000..9cd182f6a07 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/common.di @@ -0,0 +1,3 @@ +module pkgDIP37.test17629.common; + +void foo17629(); diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/package.di b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/package.di new file mode 100644 index 00000000000..ea99ce12366 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37/test17629/package.di @@ -0,0 +1,2 @@ +module pkgDIP37.test17629; +public import pkgDIP37.test17629.common; diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/liba.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/liba.d new file mode 100644 index 00000000000..221aaff854e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/liba.d @@ -0,0 +1,2 @@ +module pkgDIP37_10302.liba; +void foo() {} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/libb.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/libb.d new file mode 100644 index 00000000000..f4ef4dee48b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/libb.d @@ -0,0 +1,11 @@ +module pkgDIP37_10302.libb; +import pkgDIP37_10302.liba; +void bar() +{ + foo(); + + // should be error, but unfortunately this works by bug 314 now. + //lib.foo(); + + pkgDIP37_10302.liba.foo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/package.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/package.d new file mode 100644 index 00000000000..820dc377dfb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10302/package.d @@ -0,0 +1,2 @@ +module pkgDIP37_10302; +public import pkgDIP37_10302.liba; diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mbar.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mbar.d new file mode 100644 index 00000000000..8fced25afba --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mbar.d @@ -0,0 +1,2 @@ +module pkgDIP37_10354.mbar; +void bar(T)() {} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mfoo.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mfoo.d new file mode 100644 index 00000000000..7cd7c8bc250 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/mfoo.d @@ -0,0 +1,2 @@ +module pkgDIP37_10354.mfoo; +void foo(T)() {} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/package.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/package.d new file mode 100644 index 00000000000..9852eddba31 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10354/package.d @@ -0,0 +1,3 @@ +module pkgDIP37_10354; +public import pkgDIP37_10354.mfoo; +public import pkgDIP37_10354.mbar; diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/mod.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/mod.d new file mode 100644 index 00000000000..b149e8833e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/mod.d @@ -0,0 +1,8 @@ +module pkgDIP37_10421.algo.mod; +import pkgDIP37_10421.algo; // foo +import pkgDIP37_10421.except; // baz +void test() +{ + foo(); // should be accessible + baz(); // should be accessible +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/package.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/package.d new file mode 100644 index 00000000000..3f51a64ce00 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/algo/package.d @@ -0,0 +1,7 @@ +module pkgDIP37_10421.algo; +public import pkgDIP37_10421.algo.mod; +package +{ + void foo() {} + void bar() { foo(); } // should be accessible +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/except.d b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/except.d new file mode 100644 index 00000000000..e69a2239e5d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/pkgDIP37_10421/except.d @@ -0,0 +1,3 @@ +module pkgDIP37_10421.except; + +package void baz() {} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Controller.d b/gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Controller.d new file mode 100644 index 00000000000..9ade3170ee2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Controller.d @@ -0,0 +1,8 @@ +class Controller { + mixin template register(T : Controller) { + enum _s_pkg = __traits(parent, __traits(parent, __traits(parent, T))).stringof["package ".length .. $]; + + enum _s_model = T.stringof[0 .. $-`Controller`.length] ~ `Model`; + mixin(q{enum _ = is(} ~ _s_pkg ~ q{.models.} ~ _s_model ~ q{.} ~ _s_model ~ q{ : serenity7190.core.Model.Model);}); + } +} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Model.d b/gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Model.d new file mode 100644 index 00000000000..c75f9edd59a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/serenity7190/core/Model.d @@ -0,0 +1,5 @@ +class SqlitePersister(T) { + static assert(T.tupleof.length > 0, T.stringof ~ `(` ~ (T.tupleof.length + '0') ~ `): ` ~ T.tupleof.stringof); +} + +class Model {} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/test16080b.d b/gcc/testsuite/gdc.test/compilable/extra-files/test16080b.d new file mode 100644 index 00000000000..9cd9fc8d5c7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/test16080b.d @@ -0,0 +1,6 @@ +import imp16080; + +void test2() { + A!() v = A!().a; +} + diff --git a/gcc/testsuite/gdc.test/compilable/fail260.d b/gcc/testsuite/gdc.test/compilable/fail260.d new file mode 100644 index 00000000000..96f4d1bdfa8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/fail260.d @@ -0,0 +1,37 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -d + +struct Static(uint width2, uint height2) +{ + immutable width = width2; + immutable height = height2; + + static Static opCall() + { + Static ret; + return ret; + } + + alias float E; + + template MultReturn(alias M1, alias M2) + { + alias Static!(M2.width, M1.height) MultReturn; + } + + void opMultVectors(M2)(M2 b) + { + alias MultReturn!(Static, M2) ret_matrix; + } +} + +void test() +{ + alias Static!(4, 1) matrix_stat; + static matrix_stat m4 = matrix_stat(); + + alias Static!(1, 4) matrix_stat2; + static m6 = matrix_stat2(); + + m6.opMultVectors(m4); +} diff --git a/gcc/testsuite/gdc.test/compilable/fix17123.d b/gcc/testsuite/gdc.test/compilable/fix17123.d new file mode 100644 index 00000000000..f6a38bca64c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/fix17123.d @@ -0,0 +1,14 @@ +/* +PERMUTE_ARGS: + +https://issues.dlang.org/show_bug.cgi?id=17123 + */ + +void test() +{ + char[256] buffer; + + char[] delegate() read = () { + return buffer[]; + }; +} diff --git a/gcc/testsuite/gdc.test/compilable/fix17335.d b/gcc/testsuite/gdc.test/compilable/fix17335.d new file mode 100644 index 00000000000..0e76bb53b72 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/fix17335.d @@ -0,0 +1,28 @@ +/* + * PERMUTE_ARGS: + */ + +// https://issues.dlang.org/show_bug.cgi?id=17335 + +bool alwaysFalse() { return false; } +void main() +{ + static if (false && a == 1) + { + } + static if ("a" == "b" && b == 1) + { + } + static if (alwaysFalse() && c == 1) + { + } + static if (!alwaysFalse() || d == 1) + { + } + static if (alwaysFalse() ? e == 1 : 1) + { + } + static if (!alwaysFalse() ? 1 : f == 1) + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/fix17349.d b/gcc/testsuite/gdc.test/compilable/fix17349.d new file mode 100644 index 00000000000..2222c355927 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/fix17349.d @@ -0,0 +1,40 @@ +/* REQUIRED_ARGS: -dw + * PERMUTE_ARGS: + * TEST_OUTPUT: +--- +compilable/fix17349.d(37): Deprecation: cannot implicitly override base class method `fix17349.E.foo` with `fix17349.F.foo`; add `override` attribute +--- + */ + +// https://issues.dlang.org/show_bug.cgi?id=17349 + +struct S { } + +class C { + void bar(); + void foo(void* p); + void abc(Object); + void def(S); +} + +class D : C { + override void bar() const; + override void foo(const void*); + override void abc(const Object); + override void def(const S); +} + +alias fp_t = void function(int*); +@safe void abc(const int*); +fp_t fp = &abc; + + +class E { + void foo(void*); +} + +class F : E { + void foo(const void*); +} + + diff --git a/gcc/testsuite/gdc.test/compilable/fix17686.d b/gcc/testsuite/gdc.test/compilable/fix17686.d new file mode 100644 index 00000000000..db82252ff4a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/fix17686.d @@ -0,0 +1,45 @@ +/* REQUIRED_ARGS: + * PERMUTE_ARGS: + */ + +// https://issues.dlang.org/show_bug.cgi?id=17686 + +interface INode +{ + @property INode parentNode(); + @property IDocument ownerDocument(); +} +interface IDocument: INode {} +interface IEntityReference: INode {} + +class DOMImplementation(T) +{ + abstract class Node: INode + { + override + { + @property Node parentNode() { return null; } + @property Document ownerDocument() { return null; } + } + + @property bool readonly() { return true; } + } + abstract class NodeWithChildren: Node {} + + class Document: NodeWithChildren, IDocument {} + + class EntityReference: NodeWithChildren, IEntityReference + { + override + { + @property bool readonly() { return true; } + } + } + +} + +void main() +{ + alias aaa = DOMImplementation!string; +} + diff --git a/gcc/testsuite/gdc.test/compilable/forward1.d b/gcc/testsuite/gdc.test/compilable/forward1.d new file mode 100644 index 00000000000..7417b037bed --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/forward1.d @@ -0,0 +1,7 @@ +// REQUIRED_ARGS: -g + +// 104. fails only with -g + +Foofunc f; +alias int Foo; +alias int function(Foo) Foofunc; diff --git a/gcc/testsuite/gdc.test/compilable/future.d b/gcc/testsuite/gdc.test/compilable/future.d new file mode 100644 index 00000000000..89a13965d1b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/future.d @@ -0,0 +1,47 @@ +/* PERMUTE_ARGS: + * TEST_OUTPUT: +--- +compilable/future.d(15): Deprecation: @future base class method future.A.msg is being overridden by future.B.msg; rename the latter +--- + */ + +class A +{ + @__future char msg() { return 'a'; } +} + +class B : A +{ + char msg() { return 'b'; } +} + +class C : B +{ + override char msg() { return 'c'; } +} + +class D : A +{ + override char msg() { return 'd'; } +} + +int main() +{ + auto a = new A(); + assert(a.msg() == 'a'); + auto b = new B(); + assert(b.msg() == 'b'); + auto c = new C(); + assert(c.msg() == 'c'); + auto d = new D(); + assert(d.msg() == 'd'); + + assert(b.A.msg() == 'a'); + + auto ba = cast(A)b; + assert(ba.msg() == 'a'); + + auto da = cast(A)d; + assert(da.msg() == 'd'); + return 0; +} diff --git a/gcc/testsuite/gdc.test/compilable/futurexf.d b/gcc/testsuite/gdc.test/compilable/futurexf.d new file mode 100644 index 00000000000..c550b68d30f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/futurexf.d @@ -0,0 +1,12 @@ +/* PERMUTE_ARGS: + REQUIRED_ARGS: -Xffuture.json + */ + +class A +{ + @__future char msg(); +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/iasm_labeloperand.d b/gcc/testsuite/gdc.test/compilable/iasm_labeloperand.d new file mode 100644 index 00000000000..f88fd16511a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/iasm_labeloperand.d @@ -0,0 +1,48 @@ + +version (D_InlineAsm_X86) + version = TestInlineAsm; +else version (D_InlineAsm_X86_64) + version = TestInlineAsm; +else version (GNU) + version = TestInlineAsm; +else + pragma(msg, "Inline asm not supported, not testing."); + +version (TestInlineAsm) +{ + void testInlineAsm() + { + version (GNU) + { + L1: + asm { ""; } + asm { "" : : : : L1, L2; } + L2: + asm { ""; } + } + else + { + asm + { + L1: + nop; + nop; + nop; + nop; + + mov EAX, dword ptr L1; // Check back references + mov EAX, dword ptr L2; // Check forward references + mov EAX, dword ptr DS:L1; // Not really useful in standard use, but who knows. + mov EAX, dword ptr FS:L2; // Once again, not really useful, but it is valid. + mov EAX, dword ptr CS:L1; // This is what the first test case should implicitly be. + + L2: + nop; + nop; + nop; + nop; + + } + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice10040.d b/gcc/testsuite/gdc.test/compilable/ice10040.d new file mode 100644 index 00000000000..e93ea08360f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice10040.d @@ -0,0 +1,15 @@ +struct MsgProc1 { mixin MsgMixin; } +struct MsgProc2 { mixin MsgMixin; } + +struct MsgHeader {} + +template MsgMixin() +{ + mixin(mixinMembers!(MsgHeader.init)); +} + +string mixinMembers(T ...)() +{ + struct Op {} + return null; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice10431a.d b/gcc/testsuite/gdc.test/compilable/ice10431a.d new file mode 100644 index 00000000000..593287ca74b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice10431a.d @@ -0,0 +1,19 @@ +mixin ADT!(); + +struct Tuple(TL...) { TL expand; } + +template Seq(T...) { alias T Seq; } + +template ADT() +{ + mixin(q{ + struct ListI + { + private + { + size_t tag; + union { Seq!(Tuple!()*, Tuple!(int,ListI,)*,) data; } + } + } + }); +} diff --git a/gcc/testsuite/gdc.test/compilable/ice10431b.d b/gcc/testsuite/gdc.test/compilable/ice10431b.d new file mode 100644 index 00000000000..8dfdddc0a56 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice10431b.d @@ -0,0 +1,11 @@ +struct X(alias Y) +{ +} + +struct A +{ + int[] data; +} + +alias X!(A([])) X1; +alias X!(A([])) X2; diff --git a/gcc/testsuite/gdc.test/compilable/ice10486.d b/gcc/testsuite/gdc.test/compilable/ice10486.d new file mode 100644 index 00000000000..962a1304f05 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice10486.d @@ -0,0 +1,5 @@ +void main() +{ + typeof(null) null_; + int[1] sarr = null_; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice10598.d b/gcc/testsuite/gdc.test/compilable/ice10598.d new file mode 100644 index 00000000000..58a7c3be5f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice10598.d @@ -0,0 +1,3 @@ +// EXTRA_SOURCES: imports/ice10598a.d imports/ice10598b.d + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/ice11054.d b/gcc/testsuite/gdc.test/compilable/ice11054.d new file mode 100644 index 00000000000..1b8c63bdc1a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice11054.d @@ -0,0 +1,8 @@ +import imports.ice11054a; + +static assert(!__traits(compiles, tuple())); + +E[] appender(A : E, E)() +{ + return E; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice11300.d b/gcc/testsuite/gdc.test/compilable/ice11300.d new file mode 100644 index 00000000000..473a1c2cba3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice11300.d @@ -0,0 +1,5 @@ +// PERMUTE_ARGS: + +module ice11300; +import imports.ice11300a; +enum value = 42; diff --git a/gcc/testsuite/gdc.test/compilable/ice11596.d b/gcc/testsuite/gdc.test/compilable/ice11596.d new file mode 100644 index 00000000000..2b1600d2728 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice11596.d @@ -0,0 +1,17 @@ +// PERMUTE_ARGS: -inline -release -g -O -version=X + +version(X) + alias M = real; +else + alias M = int[2]; /* or other T[n] with n != 1 */ + +struct S { M m; } + +S f() { assert(false); } + +class C +{ + S[1] ss; /* Here, size doesn't matter. */ + + this() { ss[] = f(); } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice11610.d b/gcc/testsuite/gdc.test/compilable/ice11610.d new file mode 100644 index 00000000000..fb22cdb82c2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice11610.d @@ -0,0 +1,79 @@ + +struct Token +{ + TokenType type; +} + +enum TokenType : ushort +{ + invalid +} + +class Parser +{ + bool peekIsOneOf(TokenType[] types...) + { + canFind(types, tokens[1].type); + return true; + } + + Token[] tokens; +} + +/*************************************************/ +// std.algorithm + +R find(alias pred = "a == b", R, E)(R haystack, E needle) +{ + enum isIntegralNeedle = isSomeChar!E/* || isIntegral!E || isBoolean!E*/; + + return haystack; +} + +bool canFind(alias pred = "a == b", R, E)(R haystack, E needle) +if (is(typeof(find!pred(haystack, needle)))) // 1st instantiate of find template with error gagging +{ + return find!pred(haystack, needle).length != 0; // 2nd instantiate of find template without gagging +} + +/*************************************************/ +// std.traits + +template CharTypeOf(T) +{ + inout( char) idx( inout( char) ); + inout(wchar) idx( inout(wchar) ); + inout(dchar) idx( inout(dchar) ); + shared(inout char) idx( shared(inout char) ); + shared(inout wchar) idx( shared(inout wchar) ); + shared(inout dchar) idx( shared(inout dchar) ); + + static if (is(T == enum)) + { + /* This line instantiates CharTypeOf!short and will make error. + * But, when CharTypeOf!short is re-instantiated without gagging, + * that's for correct error report, its 'members' does not re-created. + * so, members' semantic will call FuncDeclaration::overloadInsert of + * 'idx' functions, and will make circular linked list of + * FuncDeclaration::overnext. Finally, iterating it will cause + * infinite recursion and compiler segfault. + */ + alias .CharTypeOf!(OriginalType!T) CharTypeOf; + } + else static if (is(typeof(idx(T.init)) X)) + { + alias X CharTypeOf; + } + else + static assert(0, T.stringof~" is not a character type"); +} + +template isSomeChar(T) +{ + enum isSomeChar = is(CharTypeOf!T); +} + +template OriginalType(T) +{ + alias OriginalType = ushort; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice11777.d b/gcc/testsuite/gdc.test/compilable/ice11777.d new file mode 100644 index 00000000000..704f35c9b94 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice11777.d @@ -0,0 +1,14 @@ +void f(void delegate(int)) {} + +class C +{ + int i; + this() + { + f((a){}); + /* (a){} is a template lambda, so FuncExp::semantic -> TemplateDeclaration::semantic + * will save the scope in TemplateDeclaration::scope with fieldinit. Later push/pop + * of the scope for template lambda body semantics will violate the assertion in Scope::pop(). + */ + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice11906.d b/gcc/testsuite/gdc.test/compilable/ice11906.d new file mode 100644 index 00000000000..f568701b463 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice11906.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +nothrow /*extern(Windows) */export int GetModuleHandleA(const char* lpModuleName); + +void main() +{ + /*extern(Windows) */int function(const char*) f; + assert(f != &GetModuleHandleA); +} diff --git a/gcc/testsuite/gdc.test/compilable/ice11925.d b/gcc/testsuite/gdc.test/compilable/ice11925.d new file mode 100644 index 00000000000..630af429a47 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice11925.d @@ -0,0 +1,38 @@ +void test11925a() +{ + try + { + try + { + L1: {} + } + finally + { + } + } + finally + { + } + goto L1; +} + +void test11925b() +{ + switch (1) + { + case 1: + goto L1; + break; + + default: + break; + } + + try + { + L1: { } + } + finally + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice12002.d b/gcc/testsuite/gdc.test/compilable/ice12002.d new file mode 100644 index 00000000000..c80c9abdf8b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice12002.d @@ -0,0 +1,24 @@ +// REQUIRED_ARGS: -inline +// PERMUTE_ARGS: + +void doFormat(void delegate(dchar) putc, TypeInfo[] arguments) +{ + void formatArg(char fc) + { + const(char)* prefix = ""; + + void putstr(const char[] s) + { + //if (flags & FL0pad) + { + while (*prefix) + putc(*prefix++); + } + + foreach (dchar c; s) + putc(c); + } + + putstr(null); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice12554.d b/gcc/testsuite/gdc.test/compilable/ice12554.d new file mode 100644 index 00000000000..76452f462dc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice12554.d @@ -0,0 +1,46 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +void main() pure +{ + int[] foo; + + // if indirectly instantiated aggregate is struct (== MapResultS) + foo.map!(MapResultS, x => foo.map!(MapResultS, y => x).array); + + // if indirectly instantiated aggregate is class (== MapResultC) + foo.map!(MapResultC, x => foo.map!(MapResultC, y => x).array); +} + +T array(T)(T a) +{ + static int g; g = 1; // impure operation + return a; +} + +template map(alias MapResult, fun...) +{ + auto map(Range)(Range r) + { + alias AppliedReturnType(alias f) = typeof(f(r[0])); + static assert(!is(AppliedReturnType!fun == void)); + + return MapResult!(fun).init; + } +} + +struct MapResultS(alias fun) +{ + @property front() + { + return fun(1); + } +} + +class MapResultC(alias fun) +{ + @property front() + { + return fun(1); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice12956.d b/gcc/testsuite/gdc.test/compilable/ice12956.d new file mode 100644 index 00000000000..69d182e4fa5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice12956.d @@ -0,0 +1,30 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +template isCallable(T...) +{ + static if (is(typeof(& T[0].opCall) == delegate)) + { + enum bool isCallable = true; + } + else static if (is(typeof(& T[0].opCall) V : V*) && is(V == function)) + { + enum bool isCallable = true; + } + else + enum bool isCallable = false; +} + +@property auto injectChain(Injectors...)() +{ + return &ChainTemplates!(Injectors); +} + +template ChainTemplates(Templates...) +{ + alias Head = Templates[0]; + alias Tail = Templates[1..$]; + alias Head!(Tail) ChainTemplates; +} + +static assert(!isCallable!(injectChain)); diff --git a/gcc/testsuite/gdc.test/compilable/ice13071.d b/gcc/testsuite/gdc.test/compilable/ice13071.d new file mode 100644 index 00000000000..b180c1756fc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13071.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +T foo(T)() +{ + __gshared int[] bar = []; + return T.init; +} + +void main() +{ + foo!char(); +} diff --git a/gcc/testsuite/gdc.test/compilable/ice13088.d b/gcc/testsuite/gdc.test/compilable/ice13088.d new file mode 100644 index 00000000000..326796feded --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13088.d @@ -0,0 +1,19 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +struct X +{ + void mfoo(this T)() {} +} +void test() +{ + shared const X scx; + + scx.mfoo(); +} + +struct Vec +{ + int x; + void sc() shared const {} +} diff --git a/gcc/testsuite/gdc.test/compilable/ice13245.d b/gcc/testsuite/gdc.test/compilable/ice13245.d new file mode 100644 index 00000000000..83ac0fa9eb7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13245.d @@ -0,0 +1,5 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +template T(alias f) {} +static assert(!is(T!( (int x){ return invalid; } ))); diff --git a/gcc/testsuite/gdc.test/compilable/ice13323.d b/gcc/testsuite/gdc.test/compilable/ice13323.d new file mode 100644 index 00000000000..d5d471f659b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13323.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +struct UDA {} + +struct S +{ + @UDA: + import object; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice13403.d b/gcc/testsuite/gdc.test/compilable/ice13403.d new file mode 100644 index 00000000000..bb7c4e5955e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13403.d @@ -0,0 +1,5 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -o- +import imports.ice13403a; + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/ice13792.d b/gcc/testsuite/gdc.test/compilable/ice13792.d new file mode 100644 index 00000000000..2dab1e7982c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13792.d @@ -0,0 +1,6 @@ +enum E; + +void main() +{ + E* p; // ICE in glue layer +} diff --git a/gcc/testsuite/gdc.test/compilable/ice13874.d b/gcc/testsuite/gdc.test/compilable/ice13874.d new file mode 100644 index 00000000000..9c13328982a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13874.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +template FunctionTypeOf(func...) + if (func.length == 1) +{ + static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate)) + { + alias Fsym FunctionTypeOf; + } + else static if (is(typeof(& func[0].opCall) Fobj == delegate)) + { + alias Fobj FunctionTypeOf; + } + else + static assert(0); +} + +enum DummyEnum; +static assert(!is(FunctionTypeOf!DummyEnum)); diff --git a/gcc/testsuite/gdc.test/compilable/ice13886.d b/gcc/testsuite/gdc.test/compilable/ice13886.d new file mode 100644 index 00000000000..05eebc4adc4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13886.d @@ -0,0 +1,14 @@ +// REQUIRED__ARGS: +// PERMUTE_ARGS: + +struct Y() +{ + this() {} + ~this() { this = null; } + ref opAssign(S)(S) { } +} + +void main() +{ + static if (is(typeof({ Y!(); }))) {} +} diff --git a/gcc/testsuite/gdc.test/compilable/ice13920.d b/gcc/testsuite/gdc.test/compilable/ice13920.d new file mode 100644 index 00000000000..466b2e0449f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13920.d @@ -0,0 +1,25 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +class Foo +{ + void foo() + { + foreach (f; __traits(getOverloads, typeof(this), "bar")) + { + auto dg = &f; + } + + foreach (f; __traits(getVirtualMethods, typeof(this), "bar")) + { + auto dg = &f; + } + + foreach (f; __traits(getVirtualFunctions, typeof(this), "bar")) + { + auto dg = &f; + } + } + + uint bar() { return 0; } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice13968.d b/gcc/testsuite/gdc.test/compilable/ice13968.d new file mode 100644 index 00000000000..92f19c217fb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice13968.d @@ -0,0 +1,18 @@ +// REQUIRED_ARGS: +// PERMUTE_ARGS: + +union U +{ + bool a; + long b; +} + +U test1() +{ + return U(); +} + +U* test2() +{ + return new U(); +} diff --git a/gcc/testsuite/gdc.test/compilable/ice14075.d b/gcc/testsuite/gdc.test/compilable/ice14075.d new file mode 100644 index 00000000000..5dcfea4fe11 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice14075.d @@ -0,0 +1,15 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +struct Foo +{ + auto opAssign(this X)(ref typeof(this)); + auto opAssign(this X, V)(ref V) if (!is(V == typeof(this))); +} + +void test() +{ + Foo src; + const(Foo) target; + static if (is(typeof(target = src))) {} +} diff --git a/gcc/testsuite/gdc.test/compilable/ice1524.d b/gcc/testsuite/gdc.test/compilable/ice1524.d new file mode 100644 index 00000000000..ffcf81bcbc3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice1524.d @@ -0,0 +1,22 @@ +// Issue 1524 - ICE(constfold.c) on using "is" with strings in CTFE + +/* 1524 PATCH Assertion failure: '0' on line 863 in file 'constfold.c' +constfold.c +@@ -845,9 +845,9 @@ + Loc loc = e1->loc; + int cmp; + +- if (e1->op == TOKnull && e2->op == TOKnull) ++ if (e1->op == TOKnull || e2->op == TOKnull) + { +- cmp = 1; ++ cmp = (e1->op == TOKnull && e2->op == TOKnull) ? 1 : 0; + } + else if (e1->op == TOKsymoff && e2->op == TOKsymoff) + { +*/ +bool isNull(string str) +{ + return str is null; +} +const bool test = isNull("hello!"); diff --git a/gcc/testsuite/gdc.test/compilable/ice15333.d b/gcc/testsuite/gdc.test/compilable/ice15333.d new file mode 100644 index 00000000000..4923dfa5b9b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice15333.d @@ -0,0 +1,14 @@ +// EXTRA_SOURCES: imports/a15333.d + +module ice15333; + +void map(alias fun)() {} + +struct IdentifierResolver(alias handler) +{ + void resolve() + { + map!((a) {}); + handler(true); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/ice15760.d b/gcc/testsuite/gdc.test/compilable/ice15760.d new file mode 100644 index 00000000000..aa7b9c3ae27 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice15760.d @@ -0,0 +1,11 @@ +// PERMUTE_ARGS: +// EXTRA_SOURCES: imports/a15760.d + +module ice15760; + +import imports.a15760 : Foo; + +struct Bar +{ + __gshared Foo foo; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice15789.d b/gcc/testsuite/gdc.test/compilable/ice15789.d new file mode 100644 index 00000000000..7829ca02b32 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice15789.d @@ -0,0 +1,30 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +struct InputRange {} + +auto md5OfA(T...)(T ) {} +auto md5OfB(T...)(T ) {} + +template fqnSymA(alias T : X!A, alias X, A...) +{ + template fqnTuple(B) { enum fqnTuple = 1; } + enum fqnSymA = fqnTuple!A; +} +template fqnSymB(alias T : X!A, alias X, A...) +{ + template fqnTuple(B) { enum fqnTuple = 1; } + enum fqnSymB = fqnTuple!A; +} + +void test1() // OK <- NG +{ + md5OfA(InputRange()); + auto n = fqnSymA!(md5OfA!InputRange); +} + +void test2() // OK +{ + auto n = fqnSymB!(md5OfB!InputRange); + md5OfB(InputRange()); +} diff --git a/gcc/testsuite/gdc.test/compilable/ice15992.d b/gcc/testsuite/gdc.test/compilable/ice15992.d new file mode 100644 index 00000000000..07bc6c9af38 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice15992.d @@ -0,0 +1,34 @@ +// PERMUTE_ARGS: + +struct Appender() +{ + bool canExtend = false; +} + +struct CustomFloat() +{ + union ToBinary + { + CustomFloat!() get; + } + + void opAssign(F)(F input) + if (__traits(compiles, cast(real)input)) + { + } + + real get()() + { + Appender!() app; + assert(false); + } + + T opCast(T)() { return get!(); } + + alias g = get!(); +} + +void f() +{ + alias FPTypes = CustomFloat!(); +} diff --git a/gcc/testsuite/gdc.test/compilable/ice6538.d b/gcc/testsuite/gdc.test/compilable/ice6538.d new file mode 100644 index 00000000000..12d1ed0fa91 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice6538.d @@ -0,0 +1,43 @@ + + +/**************************************/ +// 6538 + +template allSatisfy(alias F, T...) { enum bool allSatisfy = true; } +template isIntegral(T) { enum bool isIntegral = true; } + +void foo(I...)(I sizes) +if (allSatisfy!(isIntegral, sizes)) {} + +void test6538a() +{ + foo(42, 86); +} + +void bar(T1, T2)(T1 t1, T2 t2) +if (allSatisfy!(isIntegral, t1, t2)) {} + +void test6538b() +{ + bar(42, 86); +} + +/**************************************/ +// 9361 + +template Sym(alias A) +{ + enum Sym = true; +} + +struct S +{ + void foo()() if (Sym!(this)) {} + void bar()() { static assert(Sym!(this)); } // OK +} +void test9361a() +{ + S s; + s.foo(); // fail + s.bar(); // OK +} diff --git a/gcc/testsuite/gdc.test/compilable/ice8392.d b/gcc/testsuite/gdc.test/compilable/ice8392.d new file mode 100644 index 00000000000..5a374139ea2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice8392.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: imports/a8392.d + +module ice8392; + +struct A +{ +} + +auto fooa(alias handler)(A a) +{ + return handler(null); +} diff --git a/gcc/testsuite/gdc.test/compilable/ice854.d b/gcc/testsuite/gdc.test/compilable/ice854.d new file mode 100644 index 00000000000..3ede52eeb59 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice854.d @@ -0,0 +1,43 @@ +// Issue 854 - TypeTuple in anonymous delegate causes ice in glue.c + +/* 854 VOTE PATCH (=2863, =2251?) Assertion failure: '0' on line 935 in file 'glue.c' +I haven't checked this patch myself. +--- dmd/func.c 2009-03-05 01:56:46.000000000 +0100 ++++ dmd-fixed/func.c 2009-03-30 00:39:41.000000000 +0200 +@@ -756,6 +756,27 @@ + } + } + ++ if (f->parameters) ++ { ++ for (size_t i = 0; i < Argument::dim(f->parameters); i++) ++ { ++ Argument *arg = (Argument *)Argument::getNth(f->parameters, i); ++ Type* nw = arg->type->semantic(0, sc); ++ if (arg->type != nw) { ++ arg->type = nw; ++ // Examine this index again. ++ // This is important if it turned into a tuple. ++ // In particular, the empty tuple should be handled or the ++ // next parameter will be skipped. ++ // FIXME: Maybe we only need to do this for tuples, ++ // and can add tuple.length after decrement? ++ i--; ++ } ++ } ++ // update nparams to include expanded tuples ++ nparams = Argument::dim(f->parameters); ++ } ++ + // Propagate storage class from tuple parameters to their element-parameters. + if (f->parameters) + { +*/ +template Foo(T...) +{ + alias T Foo; +} +void main() +{ + auto y = (Foo!(int) x){ return 0; }; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice9663.d b/gcc/testsuite/gdc.test/compilable/ice9663.d new file mode 100644 index 00000000000..8ea26d7f9ca --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/ice9663.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -wi + +void main() +{ + int[1] a; + int[] b = [1]; + + a = 1; + + b[] = a; + + b = a; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a12506.d b/gcc/testsuite/gdc.test/compilable/imports/a12506.d new file mode 100644 index 00000000000..b4307c3c3c7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a12506.d @@ -0,0 +1,3 @@ +module imports.a12506; + +auto f12506(alias fun)() { return fun(1); } diff --git a/gcc/testsuite/gdc.test/compilable/imports/a12567.d b/gcc/testsuite/gdc.test/compilable/imports/a12567.d new file mode 100644 index 00000000000..053e3d8d7c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a12567.d @@ -0,0 +1,4 @@ +deprecated("This module will be removed in future release.") +module imports.a12567; + +void foo() {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a13226.d b/gcc/testsuite/gdc.test/compilable/imports/a13226.d new file mode 100644 index 00000000000..bbe3e68fcd0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a13226.d @@ -0,0 +1,18 @@ +module imports.a13226; + +enum isFunction(alias f) = is(typeof(f) == function); +enum isIntField(alias f) = is(typeof(f) == int); + +string t(alias cls, string method)() +{ + static if (isFunction!(mixin("cls."~method))) + {} + return ""; +} + +string u(alias cls, string member)() +{ + static if (isIntField!(mixin("cls."~member))) + {} + return ""; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a14528.d b/gcc/testsuite/gdc.test/compilable/imports/a14528.d new file mode 100644 index 00000000000..73386a35f83 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a14528.d @@ -0,0 +1,6 @@ +module imports.a14528; + +void foo(alias f)() +{ + f(); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a15333.d b/gcc/testsuite/gdc.test/compilable/imports/a15333.d new file mode 100644 index 00000000000..6e899a32223 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a15333.d @@ -0,0 +1,12 @@ +module imports.a15333; + +import ice15333; + +struct StatementVisitor +{ + void visit() + { + int location; + alias IR = IdentifierResolver!((e){ location = 0; }); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a15760.d b/gcc/testsuite/gdc.test/compilable/imports/a15760.d new file mode 100644 index 00000000000..16eeddb1295 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a15760.d @@ -0,0 +1,8 @@ +module imports.a15760; + +import ice15760; + +struct Foo +{ + Bar a; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a15856.d b/gcc/testsuite/gdc.test/compilable/imports/a15856.d new file mode 100644 index 00000000000..ca252138159 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a15856.d @@ -0,0 +1,3 @@ +module imports.a15856; + +alias int c_long; diff --git a/gcc/testsuite/gdc.test/compilable/imports/a313.d b/gcc/testsuite/gdc.test/compilable/imports/a313.d new file mode 100644 index 00000000000..8519059d73e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a313.d @@ -0,0 +1,8 @@ +module imports.a313; + +// adds private package imports +private import imports.b313; +// adds private package core +private import core.stdc.stdio; +// adds public alias cstdio +public alias cstdio = core.stdc.stdio; diff --git a/gcc/testsuite/gdc.test/compilable/imports/a313templatemixin1.d b/gcc/testsuite/gdc.test/compilable/imports/a313templatemixin1.d new file mode 100644 index 00000000000..29c24bd8f0d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a313templatemixin1.d @@ -0,0 +1,3 @@ +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a313templatemixin2.d b/gcc/testsuite/gdc.test/compilable/imports/a313templatemixin2.d new file mode 100644 index 00000000000..29c24bd8f0d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a313templatemixin2.d @@ -0,0 +1,3 @@ +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/a314.d b/gcc/testsuite/gdc.test/compilable/imports/a314.d new file mode 100644 index 00000000000..7c33ccc2285 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a314.d @@ -0,0 +1,5 @@ +module imports.pkg.a314; // sub package + +package(imports) static import imports.c314; +package(imports) import renamed = imports.c314; +package(imports) import imports.c314 : bug; diff --git a/gcc/testsuite/gdc.test/compilable/imports/a8392.d b/gcc/testsuite/gdc.test/compilable/imports/a8392.d new file mode 100644 index 00000000000..4677b50bbf2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/a8392.d @@ -0,0 +1,15 @@ +module imports.a8392; + +import ice8392; + +class B +{ + this(B); +} + +void foob(A a, B b) +{ + a.fooa!((arg){ + return new B(b); + }); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/art4769a.d b/gcc/testsuite/gdc.test/compilable/imports/art4769a.d new file mode 100644 index 00000000000..7c994e6f0eb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/art4769a.d @@ -0,0 +1,15 @@ +module imports.art4769a; + +import core.stdc.stdio; + +template DataStreamability(T) +{ + const int isStreamable = true; + alias T footype; + + void write() + { + printf("hallo\n"); + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/art4769b.d b/gcc/testsuite/gdc.test/compilable/imports/art4769b.d new file mode 100644 index 00000000000..e43b2f201e0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/art4769b.d @@ -0,0 +1,9 @@ +private import imports.art4769a; +private import art4769; + +int main(char [][] args) +{ + Vector!(wchar) str; + return 0; +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/b313.d b/gcc/testsuite/gdc.test/compilable/imports/b313.d new file mode 100644 index 00000000000..f5775a4b487 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/b313.d @@ -0,0 +1,7 @@ +module imports.b313; + +void bug() +{ + // scope has access to it's own module + imports.b313.bug(); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/b33a.d b/gcc/testsuite/gdc.test/compilable/imports/b33a.d new file mode 100644 index 00000000000..5d52c66ceec --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/b33a.d @@ -0,0 +1,28 @@ +module imports.b33a; + +struct IsEqual( T ) +{ + bool opCall( char p1, char p2 ) + { + return p1 == p2; + } +} + +template find_( Elem, Pred = IsEqual!(Elem) ) +{ + size_t fn( char[] buf, Pred pred = Pred.init ) + { + return 3; + } +} + +template find() +{ + size_t find( char[3] buf ) + { + return find_!(char).fn( buf ); + } +} + + + diff --git a/gcc/testsuite/gdc.test/compilable/imports/b3682.d b/gcc/testsuite/gdc.test/compilable/imports/b3682.d new file mode 100644 index 00000000000..f554e12ee7e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/b3682.d @@ -0,0 +1,5 @@ +module imports.b3682; + +import a3682; +alias Tuple!(int) tint; + diff --git a/gcc/testsuite/gdc.test/compilable/imports/bug8922.d b/gcc/testsuite/gdc.test/compilable/imports/bug8922.d new file mode 100644 index 00000000000..a3567ba042c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/bug8922.d @@ -0,0 +1 @@ +module imports.bug8922; diff --git a/gcc/testsuite/gdc.test/compilable/imports/c314.d b/gcc/testsuite/gdc.test/compilable/imports/c314.d new file mode 100644 index 00000000000..5c43c8608e4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/c314.d @@ -0,0 +1,4 @@ +module imports.c314; + +void bug(string s) +{} diff --git a/gcc/testsuite/gdc.test/compilable/imports/defaa.d b/gcc/testsuite/gdc.test/compilable/imports/defaa.d new file mode 100644 index 00000000000..c35167c9870 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/defaa.d @@ -0,0 +1,15 @@ + +module imports.defaa; + +class Display +{ + + private import imports.defab; + + B lastHittestB; + + this() { } +} + + + diff --git a/gcc/testsuite/gdc.test/compilable/imports/defab.d b/gcc/testsuite/gdc.test/compilable/imports/defab.d new file mode 100644 index 00000000000..84b92096ffc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/defab.d @@ -0,0 +1,15 @@ + +module imports.defab; + +private import defa; + +public class B : A +{ + + private import imports.defad; + + D parent; + + this() {} +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/defac.d b/gcc/testsuite/gdc.test/compilable/imports/defac.d new file mode 100644 index 00000000000..a8d953630a6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/defac.d @@ -0,0 +1,13 @@ + +module imports.defac; + +private import imports.defab; + +public abstract class C : B +{ + private import imports.defad; + + this() {} + + this(D parent, int style) {} +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/defad.d b/gcc/testsuite/gdc.test/compilable/imports/defad.d new file mode 100644 index 00000000000..498406d302b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/defad.d @@ -0,0 +1,14 @@ + +module imports.defad; + +private import imports.defac; +private import imports.defab; + +public class D : C +{ + B [] tabList; + + this() {} + + this(D parent, int style){ } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/dip22.d b/gcc/testsuite/gdc.test/compilable/imports/dip22.d new file mode 100644 index 00000000000..381d424d9ef --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/dip22.d @@ -0,0 +1,21 @@ +module imports.dip22; + +interface Base1 +{ + private ubyte bar() { return 1; } + private enum baz = 1; + private alias T = byte; +} + +interface Base2 +{ + final short bar() { return 2; } + enum baz = 2; + alias T = short; +} + +private void bar() {} +void bar(int) {} + +void baz(int) {} +private void baz() {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/f313.d b/gcc/testsuite/gdc.test/compilable/imports/f313.d new file mode 100644 index 00000000000..570cd091251 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/f313.d @@ -0,0 +1,6 @@ + // different module declaration not used for access check +module foo.bar; + +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/fwdref12201a.d b/gcc/testsuite/gdc.test/compilable/imports/fwdref12201a.d new file mode 100644 index 00000000000..c5b8817885c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/fwdref12201a.d @@ -0,0 +1 @@ +alias int FILE; diff --git a/gcc/testsuite/gdc.test/compilable/imports/fwdref2_test17548.d b/gcc/testsuite/gdc.test/compilable/imports/fwdref2_test17548.d new file mode 100644 index 00000000000..91391bbd521 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/fwdref2_test17548.d @@ -0,0 +1,9 @@ +module fwdref2_test17548; + +import test17548; + +struct S2 { + void bar(int arg = .test17548.cnst) {} + S1 s; + import fwdref2_test17548; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/fwdref9514.d b/gcc/testsuite/gdc.test/compilable/imports/fwdref9514.d new file mode 100644 index 00000000000..fe1298fbfab --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/fwdref9514.d @@ -0,0 +1,4 @@ +bool find9514(alias pred, R)(R range) +{ + return true; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/g313.d b/gcc/testsuite/gdc.test/compilable/imports/g313.d new file mode 100644 index 00000000000..92e703a10a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/g313.d @@ -0,0 +1,24 @@ +module imports.g313; + +// adds public package imports (see Bugzilla 15900) +public import imports.g313public; +// same w/ deferred semantics +static if (true) + public import imports.g313staticif; +mixin("public import imports.g313stringmixin;"); + +template impD() +{ + public import imports.g313templatemixin; +} + +mixin impD!(); + +void test15900() +{ + // publically imported modules should obviously be available in here as well + imports.g313public.bug(); + imports.g313staticif.bug(); + imports.g313stringmixin.bug(); + imports.g313templatemixin.bug(); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/g313public.d b/gcc/testsuite/gdc.test/compilable/imports/g313public.d new file mode 100644 index 00000000000..29c24bd8f0d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/g313public.d @@ -0,0 +1,3 @@ +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/g313staticif.d b/gcc/testsuite/gdc.test/compilable/imports/g313staticif.d new file mode 100644 index 00000000000..29c24bd8f0d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/g313staticif.d @@ -0,0 +1,3 @@ +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/g313stringmixin.d b/gcc/testsuite/gdc.test/compilable/imports/g313stringmixin.d new file mode 100644 index 00000000000..29c24bd8f0d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/g313stringmixin.d @@ -0,0 +1,3 @@ +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/g313templatemixin.d b/gcc/testsuite/gdc.test/compilable/imports/g313templatemixin.d new file mode 100644 index 00000000000..29c24bd8f0d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/g313templatemixin.d @@ -0,0 +1,3 @@ +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/ice10598a.d b/gcc/testsuite/gdc.test/compilable/imports/ice10598a.d new file mode 100644 index 00000000000..b0e9c3b99a3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/ice10598a.d @@ -0,0 +1,5 @@ +module imports.ice10598a; + +template TypeTuple(TL...) { alias TL TypeTuple; } + +alias TypeTuple!(__traits(getMember, imports.ice10598b, (__traits(allMembers, imports.ice10598b)[1])))[0] notImportedType; diff --git a/gcc/testsuite/gdc.test/compilable/imports/ice10598b.d b/gcc/testsuite/gdc.test/compilable/imports/ice10598b.d new file mode 100644 index 00000000000..de5078709fc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/ice10598b.d @@ -0,0 +1,3 @@ +module imports.ice10598b; + +struct LocalType {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/ice11054a.d b/gcc/testsuite/gdc.test/compilable/imports/ice11054a.d new file mode 100644 index 00000000000..a81d3d77801 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/ice11054a.d @@ -0,0 +1,21 @@ +template Tuple() +{ + string injectNamedFields() + { + formatNthX(); + return ""; + } +} +Tuple!T tuple(T...)() +{ +} + +void formatNthX(A...)(A) +{ + static gencode(size_t count)() + { + result ~= ""; // comment out this line will remove the ICE + return ""; + } + mixin(gencode!(A.length)()); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/ice11300a.d b/gcc/testsuite/gdc.test/compilable/imports/ice11300a.d new file mode 100644 index 00000000000..0b31623655e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/ice11300a.d @@ -0,0 +1,3 @@ +module imports.ice11300a; +static import ice11300; +enum value = ice11300.value; diff --git a/gcc/testsuite/gdc.test/compilable/imports/ice13403a.d b/gcc/testsuite/gdc.test/compilable/imports/ice13403a.d new file mode 100644 index 00000000000..d30901c0e7c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/ice13403a.d @@ -0,0 +1,7 @@ +module imports.ice13403a; + +package(imports): + +template BacktrackingMatcher() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp12242a.d b/gcc/testsuite/gdc.test/compilable/imports/imp12242a.d new file mode 100644 index 00000000000..5e5259dc762 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp12242a.d @@ -0,0 +1,17 @@ +module imports.imp12242a; + +public: +import imports.imp12242a1; // std.string +import imports.imp12242a2; // std.algorithm + + +private mixin template MixTmp(T, int x) +{ + template foo(U) if (is(U == T)) + { + enum foo = x; + } +} + +mixin MixTmp!(int, 1); +mixin MixTmp!(long, 2); diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp12242a1.d b/gcc/testsuite/gdc.test/compilable/imports/imp12242a1.d new file mode 100644 index 00000000000..5c5e5233068 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp12242a1.d @@ -0,0 +1,8 @@ +module imports.imp12242a1; + +// std.string.strip +int stripA(C)(C[] str) @safe pure + if (is(immutable C == immutable char)) +{ + return 1; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp12242a2.d b/gcc/testsuite/gdc.test/compilable/imports/imp12242a2.d new file mode 100644 index 00000000000..c0d789031a5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp12242a2.d @@ -0,0 +1,11 @@ +module imports.imp12242a2; + +// std.algorithm.strip +auto stripA(R, E)(R range, E element) +{ + return 2; +} +auto stripA(alias pred, R)(R range) +{ + return 3; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp12242b.d b/gcc/testsuite/gdc.test/compilable/imports/imp12242b.d new file mode 100644 index 00000000000..886104f54c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp12242b.d @@ -0,0 +1,17 @@ +module imports.imp12242b; + +public: +import imports.imp12242b1; // std.string +import imports.imp12242b2; // std.algorithm + + +private mixin template MixTmp(T, int x) +{ + template foo(U) if (is(U == T)) + { + enum foo = x; + } +} + +mixin MixTmp!(float, 3); +mixin MixTmp!(real, 4); diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp12242b1.d b/gcc/testsuite/gdc.test/compilable/imports/imp12242b1.d new file mode 100644 index 00000000000..e23fdc8da2e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp12242b1.d @@ -0,0 +1,8 @@ +module imports.imp12242b1; + +// std.string.strip +int stripB(C)(C[] str) @safe pure + if (is(immutable C == immutable char)) +{ + return 1; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp12242b2.d b/gcc/testsuite/gdc.test/compilable/imports/imp12242b2.d new file mode 100644 index 00000000000..0f559988722 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp12242b2.d @@ -0,0 +1,11 @@ +module imports.imp12242b2; + +// std.algorithm.strip +auto stripB(R, E)(R range, E element) +{ + return 2; +} +auto stripB(alias pred, R)(R range) +{ + return 3; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp15490a.d b/gcc/testsuite/gdc.test/compilable/imports/imp15490a.d new file mode 100644 index 00000000000..edb3b45e600 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp15490a.d @@ -0,0 +1,8 @@ +module imports.imp15490a; + +import imports.imp15490b; + +void listenTCP() +{ + enum r = regex(); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp15490b.d b/gcc/testsuite/gdc.test/compilable/imports/imp15490b.d new file mode 100644 index 00000000000..3a2490c9f6c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp15490b.d @@ -0,0 +1,12 @@ +module imports.imp15490b; + +int regex() +{ + return regexImpl(); +} + +auto regexImpl() +{ + int r = 0; + return r; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp15907.d b/gcc/testsuite/gdc.test/compilable/imports/imp15907.d new file mode 100644 index 00000000000..2ffce94db1d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp15907.d @@ -0,0 +1,23 @@ +module imports.imp15907; + +void process(T)(T t) +{ + foreach (member; __traits(allMembers, T)) + { + static if (__traits(getProtection, __traits(getMember, t, member)) != "private") + { + } + } +} + +enum allMembers(T) = [__traits(allMembers, T)]; + +struct PublicStruct +{ + private struct S {} +} + +private: + +struct PrivateStruct {} +int privateVar; diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp15925.d b/gcc/testsuite/gdc.test/compilable/imports/imp15925.d new file mode 100644 index 00000000000..c9d537aa769 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp15925.d @@ -0,0 +1 @@ +enum X = 1; diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp16080.d b/gcc/testsuite/gdc.test/compilable/imports/imp16080.d new file mode 100644 index 00000000000..1afd9b565c0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp16080.d @@ -0,0 +1,4 @@ +struct A() { + static immutable A a; +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp16085.d b/gcc/testsuite/gdc.test/compilable/imports/imp16085.d new file mode 100644 index 00000000000..6b250ba5930 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp16085.d @@ -0,0 +1,29 @@ +struct Pass +{ +} + +struct S +{ + import imports.imp16085b : functionAndFunction, staticFunctionAndFunction, + functionAndTemplate, templateAndTemplate; //<- private + // public + Pass functionAndFunction() + { + return Pass(); + } + + static Pass staticFunctionAndFunction() + { + return Pass(); + } + + Pass functionAndTemplate() + { + return Pass(); + } + + Pass templateAndTemplate()() + { + return Pass(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp16085b.d b/gcc/testsuite/gdc.test/compilable/imports/imp16085b.d new file mode 100644 index 00000000000..4f22740dee5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp16085b.d @@ -0,0 +1,25 @@ +import imp16085 : S; + +struct Fail +{ +} + +Fail functionAndFunction(ref S) +{ + return Fail(); +} + +Fail staticFunctionAndFunction(int) +{ + return Fail(); +} + +Fail functionAndTemplate(T)(T) +{ + return Fail(); +} + +Fail templateAndTemplate(T)(T) +{ + return Fail(); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp16460.d b/gcc/testsuite/gdc.test/compilable/imports/imp16460.d new file mode 100644 index 00000000000..f729004e9c0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp16460.d @@ -0,0 +1,3 @@ +module imports.imp16460; + +package enum val = 0; diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp16798.d b/gcc/testsuite/gdc.test/compilable/imports/imp16798.d new file mode 100644 index 00000000000..8ddc9985b19 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp16798.d @@ -0,0 +1,4 @@ + +module its.a.dessert.topping; + +pragma(msg, "it's a dessert topping"); diff --git a/gcc/testsuite/gdc.test/compilable/imports/jsonimport1.d b/gcc/testsuite/gdc.test/compilable/imports/jsonimport1.d new file mode 100644 index 00000000000..e989e6af030 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/jsonimport1.d @@ -0,0 +1,3 @@ +module imports.jsonimport1; + +int target1, target2; diff --git a/gcc/testsuite/gdc.test/compilable/imports/jsonimport2.d b/gcc/testsuite/gdc.test/compilable/imports/jsonimport2.d new file mode 100644 index 00000000000..f6e89a2945a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/jsonimport2.d @@ -0,0 +1,3 @@ +module imports.jsonimport2; + +int target1, target2; diff --git a/gcc/testsuite/gdc.test/compilable/imports/jsonimport3.d b/gcc/testsuite/gdc.test/compilable/imports/jsonimport3.d new file mode 100644 index 00000000000..8c8bc675dc4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/jsonimport3.d @@ -0,0 +1,3 @@ +module imports.jsonimport3; + +int target1, target2, target3; diff --git a/gcc/testsuite/gdc.test/compilable/imports/jsonimport4.d b/gcc/testsuite/gdc.test/compilable/imports/jsonimport4.d new file mode 100644 index 00000000000..531931faf01 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/jsonimport4.d @@ -0,0 +1 @@ +module imports.jsonimport4; diff --git a/gcc/testsuite/gdc.test/compilable/imports/pkg313/c313.d b/gcc/testsuite/gdc.test/compilable/imports/pkg313/c313.d new file mode 100644 index 00000000000..bd2a7ae97e8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/pkg313/c313.d @@ -0,0 +1,5 @@ +module imports.pkg313.c313; + +void bug() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/pkgmod313/mod.d b/gcc/testsuite/gdc.test/compilable/imports/pkgmod313/mod.d new file mode 100644 index 00000000000..2612892ffae --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/pkgmod313/mod.d @@ -0,0 +1,3 @@ +module imports.pkgmod313.mod; + +void bar() {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/pkgmod313/package.d b/gcc/testsuite/gdc.test/compilable/imports/pkgmod313/package.d new file mode 100644 index 00000000000..41022629978 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/pkgmod313/package.d @@ -0,0 +1,5 @@ +module imports.pkgmod313; + +public import imports.pkgmod313.mod; + +void foo() {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/protectionimp.d b/gcc/testsuite/gdc.test/compilable/imports/protectionimp.d new file mode 100644 index 00000000000..6c99cf325d9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/protectionimp.d @@ -0,0 +1,30 @@ +private +{ + void privF() {} + class privC {} + struct privS {} + union privU {} + interface privI {} + enum privE { foo } + mixin template privMT() {} + + void privTF(T)() {} + class privTC(T) {} + struct privTS(T) {} + union privTU(T) {} + interface privTI(T) {} +} + +void publF(T)() {} +void publFA(alias A)() {} +private alias privC privA; + +public mixin template publMT() {} + +/***************************************************/ +// 14169 + +template GetName14169(TemplateParam) +{ + enum GetName14169 = TemplateParam.Name; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/stdio4003.d b/gcc/testsuite/gdc.test/compilable/imports/stdio4003.d new file mode 100644 index 00000000000..f37b70e4d78 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/stdio4003.d @@ -0,0 +1,3 @@ +module imports.stdio4003; + +import imports.typecons4003; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test10375a.d b/gcc/testsuite/gdc.test/compilable/imports/test10375a.d new file mode 100644 index 00000000000..36d84c05013 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test10375a.d @@ -0,0 +1,6 @@ +module imports.test10375a; + +private template Pack(T...) +{ + alias T tuple; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test10752.d b/gcc/testsuite/gdc.test/compilable/imports/test10752.d new file mode 100644 index 00000000000..42bff3aae68 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test10752.d @@ -0,0 +1,2 @@ +module imports.test10752; +private int priv; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test11225b.d b/gcc/testsuite/gdc.test/compilable/imports/test11225b.d new file mode 100644 index 00000000000..8d5d1e23eaa --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test11225b.d @@ -0,0 +1,13 @@ +module imports.test11225b; +import test11225a; + +interface J : I {} // remove this line to make it work + +static assert(is(typeof({ import imports.test11225c; }))); // OK +pragma(msg, B!().result); // just instantiates the template + +template B() +{ + static assert(is(typeof({ import imports.test11225c; }))); // FAILS + enum result = "WORKS"; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test11225c.d b/gcc/testsuite/gdc.test/compilable/imports/test11225c.d new file mode 100644 index 00000000000..22e814b9bbf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test11225c.d @@ -0,0 +1,2 @@ +module imports.test11225c; +// empty diff --git a/gcc/testsuite/gdc.test/compilable/imports/test11563core_bitop.d b/gcc/testsuite/gdc.test/compilable/imports/test11563core_bitop.d new file mode 100644 index 00000000000..c808d164b2e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test11563core_bitop.d @@ -0,0 +1 @@ +module test11563core_bitop; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test11563std_array.d b/gcc/testsuite/gdc.test/compilable/imports/test11563std_array.d new file mode 100644 index 00000000000..6dc0af69701 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test11563std_array.d @@ -0,0 +1,6 @@ +module imports.test11563std_array; + +void popFront(S)(ref S str)// @trusted pure nothrow +{ + import imports.test11563core_bitop; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test11563std_range.d b/gcc/testsuite/gdc.test/compilable/imports/test11563std_range.d new file mode 100644 index 00000000000..f71289a7be0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test11563std_range.d @@ -0,0 +1,12 @@ +module imports.test11563std_range; + +public import imports.test11563std_array; + +template isInputRange(R) +{ + enum bool isInputRange = is(typeof( + { + R r = void; + r.popFront(); + })); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d b/gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d new file mode 100644 index 00000000000..983fd11be4f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d @@ -0,0 +1,22 @@ +module imports.test11563std_traits; + +import imports.test11563std_range; + +bool startsWith(R1, R2)(R1 doesThisStart, R2 withThis) +if (isInputRange!R1) +{ + return true; +} + +template moduleName(alias T) +{ + static if (T.stringof.startsWith("module ")) + { + enum moduleName = "b"; + } + else + { + pragma(msg, "--error--"); + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test1238a.d b/gcc/testsuite/gdc.test/compilable/imports/test1238a.d new file mode 100644 index 00000000000..58bfd2d590c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test1238a.d @@ -0,0 +1,3 @@ +module imports.test1238a; + +private int zuiop; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test1238b.d b/gcc/testsuite/gdc.test/compilable/imports/test1238b.d new file mode 100644 index 00000000000..30f1a2faa4e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test1238b.d @@ -0,0 +1,3 @@ +module imports.test1238b; + +public int zuiop; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test13242a.d b/gcc/testsuite/gdc.test/compilable/imports/test13242a.d new file mode 100644 index 00000000000..941c9941b1b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test13242a.d @@ -0,0 +1,19 @@ +module imports.test13242a; + +template expensiveArgs(alias v) +{ + pragma(msg, "a.expensiveArgs: ", v); +} + +template expensiveTemplate(Args...) +{ + pragma(msg, "a.expensiveTemplate: ", Args[0]); +} + +alias apiSym1 = expensiveTemplate!(1, expensiveArgs!(1)); + +alias apiSym2 = expensiveTemplate!(2, expensiveArgs!(2)); + +public import imports.test13242b : apiSym3; + +void cheapFunc() {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test13242b.d b/gcc/testsuite/gdc.test/compilable/imports/test13242b.d new file mode 100644 index 00000000000..fab8d686726 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test13242b.d @@ -0,0 +1,13 @@ +module imports.test13242b; + +template expensiveArgs(alias v) +{ + pragma(msg, "b.expensiveArgs: ", v); +} + +template expensiveTemplate(Args...) +{ + pragma(msg, "b.expensiveTemplate: ", Args[0]); +} + +alias apiSym3 = expensiveTemplate!(3, expensiveArgs!(3)); diff --git a/gcc/testsuite/gdc.test/compilable/imports/test14666a.d b/gcc/testsuite/gdc.test/compilable/imports/test14666a.d new file mode 100644 index 00000000000..ee6c4248b71 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test14666a.d @@ -0,0 +1,9 @@ +module imports.test14666a; + +auto getNames() +{ + import imports.test14666b; + return ""; +} + +enum Names = getNames; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test14666b.d b/gcc/testsuite/gdc.test/compilable/imports/test14666b.d new file mode 100644 index 00000000000..edfa970c74b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test14666b.d @@ -0,0 +1,8 @@ +module imports.test14666b; + +import test14666; + +struct Token +{ + Location location; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test15117a.d b/gcc/testsuite/gdc.test/compilable/imports/test15117a.d new file mode 100644 index 00000000000..9daf6f187d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test15117a.d @@ -0,0 +1,9 @@ +module imports.test15117a; + +struct AssertResult {} + +auto test_usr_1() +{ + // 2. generate TyepInfoStructDeclaration + auto x = typeid(AssertResult); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test15150a.d b/gcc/testsuite/gdc.test/compilable/imports/test15150a.d new file mode 100644 index 00000000000..fe3b8ab06be --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test15150a.d @@ -0,0 +1,6 @@ +module imports.test15150a; + +enum +{ + x +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test15150b.d b/gcc/testsuite/gdc.test/compilable/imports/test15150b.d new file mode 100644 index 00000000000..24b0928cc79 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test15150b.d @@ -0,0 +1,3 @@ +module imports.test15150b; + +import imports.test15150a : x; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test15785.d b/gcc/testsuite/gdc.test/compilable/imports/test15785.d new file mode 100644 index 00000000000..b596f9b5382 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test15785.d @@ -0,0 +1,13 @@ +module imports.test15785; + +interface IBase2 +{ + final protected void faz() {} +} + +class Base +{ + protected void foo() {} + protected void bar() {} + protected alias T = int; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test15857a.d b/gcc/testsuite/gdc.test/compilable/imports/test15857a.d new file mode 100644 index 00000000000..9362e06143e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test15857a.d @@ -0,0 +1,2 @@ +public import imports.test15857b; +public import imports.test15857c; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test15857b.d b/gcc/testsuite/gdc.test/compilable/imports/test15857b.d new file mode 100644 index 00000000000..511ef9f9a77 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test15857b.d @@ -0,0 +1 @@ +void bar15857(int) {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test15857c.d b/gcc/testsuite/gdc.test/compilable/imports/test15857c.d new file mode 100644 index 00000000000..8652d8ea26d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test15857c.d @@ -0,0 +1 @@ +void bar15857(string) {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test16348.d b/gcc/testsuite/gdc.test/compilable/imports/test16348.d new file mode 100644 index 00000000000..c9f871cc43a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test16348.d @@ -0,0 +1,6 @@ +module mypackage.bar; + +package bool bar() +{ + return false; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test1754a.d b/gcc/testsuite/gdc.test/compilable/imports/test1754a.d new file mode 100644 index 00000000000..08fc0dd158c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test1754a.d @@ -0,0 +1,5 @@ +module imports.test1754a; + +private void bar() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test1754b.d b/gcc/testsuite/gdc.test/compilable/imports/test1754b.d new file mode 100644 index 00000000000..e8e8f3c55b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test1754b.d @@ -0,0 +1,5 @@ +module imports.test1754b; + +void bar() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test1imp.d b/gcc/testsuite/gdc.test/compilable/imports/test1imp.d new file mode 100644 index 00000000000..35d2253b143 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test1imp.d @@ -0,0 +1,2 @@ + + alias uint DWORD; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test25a.d b/gcc/testsuite/gdc.test/compilable/imports/test25a.d new file mode 100644 index 00000000000..1de08f9d0e4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test25a.d @@ -0,0 +1,12 @@ +module imports.test25a; + +import imports.test25b; +import core.stdc.stdio; + +class Afoo +{ + static this() + { + printf("Afoo()\n"); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test25b.d b/gcc/testsuite/gdc.test/compilable/imports/test25b.d new file mode 100644 index 00000000000..089f69bfb68 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test25b.d @@ -0,0 +1,9 @@ +module imports.test25b; + +import imports.test25a; + +import core.stdc.stdio; + +class Bfoo +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test2991.d b/gcc/testsuite/gdc.test/compilable/imports/test2991.d new file mode 100644 index 00000000000..52fae39ebd8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test2991.d @@ -0,0 +1,5 @@ +module imports.test2991; + +private void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test4003a.d b/gcc/testsuite/gdc.test/compilable/imports/test4003a.d new file mode 100644 index 00000000000..a05a16d5b90 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test4003a.d @@ -0,0 +1,6 @@ +module imports.test4003a; + +import imports.typecons4003; + +Tuple!(string) t; + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test50a.d b/gcc/testsuite/gdc.test/compilable/imports/test50a.d new file mode 100644 index 00000000000..da5bf3684de --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test50a.d @@ -0,0 +1,6 @@ +module imports.test50a; + +class Foo { + protected int a; +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test55a.d b/gcc/testsuite/gdc.test/compilable/imports/test55a.d new file mode 100644 index 00000000000..e6fa224d057 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test55a.d @@ -0,0 +1,14 @@ +module imports.test55a; + +import test55; + +class Arm { + alias int ListHead; + MessageQueue.ListHead mqueue; +} + +class Arm2 { + alias int ListHead; + Queue2.ListHead mqueue; +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test59a.d b/gcc/testsuite/gdc.test/compilable/imports/test59a.d new file mode 100644 index 00000000000..5078d67105c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test59a.d @@ -0,0 +1,5 @@ +module imports.test59a; + +import test59; + +HRESULT h; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test59b.d b/gcc/testsuite/gdc.test/compilable/imports/test59b.d new file mode 100644 index 00000000000..bf12c6f6f50 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test59b.d @@ -0,0 +1,3 @@ +module imports.test59b; + +alias int HRESULT; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test6013.d b/gcc/testsuite/gdc.test/compilable/imports/test6013.d new file mode 100644 index 00000000000..30bcc57eb0f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test6013.d @@ -0,0 +1,11 @@ +module imports.test6013; + +int value; +int func() { return 0; }; + +public alias value public_alias_value; +private alias value private_alias_value; +public alias func public_alias_func; +private alias func private_alias_func; +public alias int public_alias_type; +private alias int private_alias_type; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test61a.d b/gcc/testsuite/gdc.test/compilable/imports/test61a.d new file mode 100644 index 00000000000..b08f637c87f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test61a.d @@ -0,0 +1,4 @@ +module imports.test61a; + +enum FooA { fooA }; +void bar(FooA x) {} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test62a.d b/gcc/testsuite/gdc.test/compilable/imports/test62a.d new file mode 100644 index 00000000000..7179f3a906f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test62a.d @@ -0,0 +1,15 @@ +module imports.test62a; + +import test62; + +struct T() +{ + struct Nested + { + S member; + } +} + +alias T!() instance; + + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test63a.d b/gcc/testsuite/gdc.test/compilable/imports/test63a.d new file mode 100644 index 00000000000..a8edbd8ae0f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test63a.d @@ -0,0 +1,10 @@ +module imports.test63a; + +private import test63; + +struct s { + + char a[ SIZE ]; + +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test66a.d b/gcc/testsuite/gdc.test/compilable/imports/test66a.d new file mode 100644 index 00000000000..7e605331644 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test66a.d @@ -0,0 +1,7 @@ +module imports.test66a; + +import test66; + +class A : Lexer +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test67a.d b/gcc/testsuite/gdc.test/compilable/imports/test67a.d new file mode 100644 index 00000000000..796ab800137 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test67a.d @@ -0,0 +1,19 @@ +module imports.test67a; + +import test67; + +class Base +{ + I create() { + return null; + } +} + +class Derived : Base +{ + override SubI create() { + return null; + } +} + + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test68a.d b/gcc/testsuite/gdc.test/compilable/imports/test68a.d new file mode 100644 index 00000000000..7e44f3e0f2e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test68a.d @@ -0,0 +1,9 @@ +module imports.test68a; + +class OtherModuleClass +{ + protected void foo() + { + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test70.d b/gcc/testsuite/gdc.test/compilable/imports/test70.d new file mode 100644 index 00000000000..6015ce99864 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test70.d @@ -0,0 +1,5 @@ +module imports.test70; + +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test71.d b/gcc/testsuite/gdc.test/compilable/imports/test71.d new file mode 100644 index 00000000000..1e91b3fcb12 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test71.d @@ -0,0 +1,6 @@ +module imports_test71; +import imports = object; + +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test72a.d b/gcc/testsuite/gdc.test/compilable/imports/test72a.d new file mode 100644 index 00000000000..c695bae1c1f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test72a.d @@ -0,0 +1,2 @@ +module imports.test72a; +public import imports.test72b; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test72b.d b/gcc/testsuite/gdc.test/compilable/imports/test72b.d new file mode 100644 index 00000000000..96da53c040d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test72b.d @@ -0,0 +1,2 @@ +module imports.test72b; +private import imports.test72c : foo; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test72c.d b/gcc/testsuite/gdc.test/compilable/imports/test72c.d new file mode 100644 index 00000000000..49b13152bf4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test72c.d @@ -0,0 +1,5 @@ +module imports.test72c; + +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test7491a.d b/gcc/testsuite/gdc.test/compilable/imports/test7491a.d new file mode 100644 index 00000000000..6a2bb01f36d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test7491a.d @@ -0,0 +1 @@ +module imports.test7491a; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test7491b.d b/gcc/testsuite/gdc.test/compilable/imports/test7491b.d new file mode 100644 index 00000000000..2e8a0025e92 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test7491b.d @@ -0,0 +1 @@ +module imports.test7491b; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276decl.d b/gcc/testsuite/gdc.test/compilable/imports/test9276decl.d new file mode 100644 index 00000000000..0f507bc2ce6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276decl.d @@ -0,0 +1,14 @@ +module imports.test9276decl; + +import imports.test9276sem, imports.test9276visitors, imports.test9276util; + +class Declaration +{ + mixin DownCastMethods!TemplateDecl; +} + +class TemplateDecl : OverloadableDecl +{ + mixin Visitors; +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276expr.d b/gcc/testsuite/gdc.test/compilable/imports/test9276expr.d new file mode 100644 index 00000000000..376d6a4eb3b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276expr.d @@ -0,0 +1,15 @@ +module imports.test9276expr; + +import imports.test9276parser; +import imports.test9276util; + +class Node +{ + mixin DownCastMethods!Declaration; + +} + +class Expression : Node +{ +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276hash.d b/gcc/testsuite/gdc.test/compilable/imports/test9276hash.d new file mode 100644 index 00000000000..de714dccf2a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276hash.d @@ -0,0 +1 @@ +module imports.test9276hash; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276parser.d b/gcc/testsuite/gdc.test/compilable/imports/test9276parser.d new file mode 100644 index 00000000000..5e307eec37a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276parser.d @@ -0,0 +1,4 @@ +module imports.test9276parser; + +public import imports.test9276expr, imports.test9276decl; + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276sem.d b/gcc/testsuite/gdc.test/compilable/imports/test9276sem.d new file mode 100644 index 00000000000..3b660f420dc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276sem.d @@ -0,0 +1,25 @@ +module imports.test9276sem; + +class Declaration +{ + mixin Visitors; +} + +template Semantic(T) +{ +private: + struct + { + import imports.test9276hash; + } + +} + + + +import imports.test9276visitors; + +class OverloadableDecl : Declaration +{ +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276type.d b/gcc/testsuite/gdc.test/compilable/imports/test9276type.d new file mode 100644 index 00000000000..8a2cb3c98a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276type.d @@ -0,0 +1,12 @@ +module imports.test9276type; + +import imports.test9276parser; + +class Type : Expression // <- note to Walter. +{ +} + +class BasicType : Type +{ +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276util.d b/gcc/testsuite/gdc.test/compilable/imports/test9276util.d new file mode 100644 index 00000000000..f3a95d9fc90 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276util.d @@ -0,0 +1,13 @@ +module imports.test9276util; + +string _dgliteral(T...)() +{ + foreach (t; T) + return t.stringof; + assert(0); +} +template DownCastMethods(T...) +{ + enum x = _dgliteral!T; +} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9276visitors.d b/gcc/testsuite/gdc.test/compilable/imports/test9276visitors.d new file mode 100644 index 00000000000..e2d507c639c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9276visitors.d @@ -0,0 +1,16 @@ +module imports.test9276visitors; + +template Visitors() +{ + mixin Semantic!(typeof(this)); + mixin DeepDup!(typeof(this)); +} + +import imports.test9276type; + +template DeepDup(T) if (is(T : BasicType)) +{} + +template DeepDup(T) +{} + diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9399a.d b/gcc/testsuite/gdc.test/compilable/imports/test9399a.d new file mode 100644 index 00000000000..dbc80310dbb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9399a.d @@ -0,0 +1,5 @@ +module imports.test9399a; + +void call(alias n)() { + n(); +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9436aggr.d b/gcc/testsuite/gdc.test/compilable/imports/test9436aggr.d new file mode 100644 index 00000000000..a80d372a3bb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9436aggr.d @@ -0,0 +1,11 @@ +module imports.test9436aggr; + +import imports.test9436type; + +class Aggregate : Type +{ +} + +class Class +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9436interp.d b/gcc/testsuite/gdc.test/compilable/imports/test9436interp.d new file mode 100644 index 00000000000..57405119b49 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9436interp.d @@ -0,0 +1,16 @@ +module imports.test9436interp; + +import imports.test9436type; +import imports.test9436aggr; + +class ReferenceValueT(T) +{ + void doCast() + { + auto x = Type.ConversionFlags.kAllowBaseClass; + } +} + +class ClassValue : ReferenceValueT!Class +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9436node.d b/gcc/testsuite/gdc.test/compilable/imports/test9436node.d new file mode 100644 index 00000000000..8ec09586137 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9436node.d @@ -0,0 +1,7 @@ +module imports.test9436node; + +import imports.test9436aggr; + +template ForwardCtor() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9436type.d b/gcc/testsuite/gdc.test/compilable/imports/test9436type.d new file mode 100644 index 00000000000..d1f14e73f90 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9436type.d @@ -0,0 +1,13 @@ +module imports.test9436type; + +import imports.test9436node; + +class Type +{ + mixin ForwardCtor!(); + + enum ConversionFlags + { + kAllowBaseClass = 0 + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9672a.d b/gcc/testsuite/gdc.test/compilable/imports/test9672a.d new file mode 100644 index 00000000000..3ca7552ab7a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9672a.d @@ -0,0 +1,32 @@ +module imports.test9672a; // interpret + +import test9672; // node + +class Type +{ + mixin ForwardCtor!(); +} + +//BasicType only created for standard types associated with tokens +class BasicType : Type +{ + static Type createType() + { + return null; + } +} + +class ValueT(T) +{ + Type getType() + { + return BasicType.createType(); + } +} +class CharValue : ValueT!char +{ + string toStr() + { + return null; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9692b.d b/gcc/testsuite/gdc.test/compilable/imports/test9692b.d new file mode 100644 index 00000000000..25be84b3413 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9692b.d @@ -0,0 +1,2 @@ +module imports.test9692b; +int j; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9919a.d b/gcc/testsuite/gdc.test/compilable/imports/test9919a.d new file mode 100644 index 00000000000..8bf3faf6eda --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9919a.d @@ -0,0 +1,3 @@ +module imports.test9919a; + +import imports.test9919c; diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9919b.d b/gcc/testsuite/gdc.test/compilable/imports/test9919b.d new file mode 100644 index 00000000000..0b9f1fd48cf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9919b.d @@ -0,0 +1,19 @@ +module imports.test9919b; + +class Event +{ + mixin genToString; // @BUG@ +} + +class MouseEvent : Event +{ + enum Action { A, B } +} + +mixin template genToString() +{ + override string toString() + { + return ""; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/test9919c.d b/gcc/testsuite/gdc.test/compilable/imports/test9919c.d new file mode 100644 index 00000000000..ed50b1e0453 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/test9919c.d @@ -0,0 +1,5 @@ +module imports.test9919c; + +import test9919; + +MouseEvent.Action action; diff --git a/gcc/testsuite/gdc.test/compilable/imports/testcontracts.d b/gcc/testsuite/gdc.test/compilable/imports/testcontracts.d new file mode 100644 index 00000000000..f7414cefbee --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/testcontracts.d @@ -0,0 +1,32 @@ +module imports.testcontracts; + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=3602 + +class Base3602 +{ + void method(int x, int y) + in + { + assert(x > 0); + assert(y > 0); + } + body + { + } +} + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=5230 + +class Base5230 +{ + int method() + out (res) + { + } + body + { + return 42; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/typecons4003.d b/gcc/testsuite/gdc.test/compilable/imports/typecons4003.d new file mode 100644 index 00000000000..d1d2eff80ad --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/typecons4003.d @@ -0,0 +1,22 @@ +module imports.typecons4003; + +struct Tuple(T...) +{ + alias T Types; + Types field; + + ref Tuple!(Types[from .. to]) slice(uint from, uint to)() + { + return *cast(typeof(return) *) &(field[from]); + } + + void test() //unittest + { + .Tuple!(int, string, float, double) a; + a.field[1] = "abc"; + a.field[2] = 4.5; + auto s = a.slice!(1, 3); + static assert(is(typeof(s) == Tuple!(string, float))); + //assert(s.field[0] == "abc" && s.field[1] == 4.5); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/udamodule1.d b/gcc/testsuite/gdc.test/compilable/imports/udamodule1.d new file mode 100644 index 00000000000..b51b7d75dbb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/udamodule1.d @@ -0,0 +1,5 @@ +@(1) deprecated("This module will be removed.") @(2) module imports.udamodule1; + +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/udamodule2.d b/gcc/testsuite/gdc.test/compilable/imports/udamodule2.d new file mode 100644 index 00000000000..131b4b2aa83 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/udamodule2.d @@ -0,0 +1,7 @@ +@UDA(1) @UDA(2) module imports.udamodule2; + +import imports.udamodule2a; + +void foo() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/udamodule2a.d b/gcc/testsuite/gdc.test/compilable/imports/udamodule2a.d new file mode 100644 index 00000000000..bd6ebd98af9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/udamodule2a.d @@ -0,0 +1,6 @@ +module imports.udamodule2a; + +struct UDA +{ + int a; +} diff --git a/gcc/testsuite/gdc.test/compilable/imports/wax16798.d b/gcc/testsuite/gdc.test/compilable/imports/wax16798.d new file mode 100644 index 00000000000..af98706b696 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/wax16798.d @@ -0,0 +1,4 @@ +module its.a.floorwax.wax16798; + +pragma(msg, "it's a floor wax"); + diff --git a/gcc/testsuite/gdc.test/compilable/interpret3.d b/gcc/testsuite/gdc.test/compilable/interpret3.d new file mode 100644 index 00000000000..8e7025c7f59 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/interpret3.d @@ -0,0 +1,7733 @@ +// PERMUTE_ARGS: -inline + +template compiles(int T) +{ + bool compiles = true; +} + +alias TypeTuple(T...) = T; + +/************************************************** + 3901 Arbitrary struct assignment, ref return +**************************************************/ + +struct ArrayRet +{ + int x; +} + +int arrayRetTest(int z) +{ + ArrayRet[6] w; + int q = (w[3].x = z); + return q; +} +static assert(arrayRetTest(51) == 51); + +// Bugzilla 3842 -- must not segfault +int ice3842(int z) +{ + ArrayRet w; + return arrayRetTest((*(&w)).x); +} +static assert(true || is(typeof(compiles!(ice3842(51))))); + +int arrayret2() +{ + int[5] a; + int[3] b; + b[] = a[1 .. $-1] = 5; + return b[1]; +} +static assert(arrayret2() == 5); + +struct DotVarTest +{ + ArrayRet z; +} + +struct DotVarTest2 +{ + ArrayRet z; + DotVarTest p; +} + +int dotvar1() +{ + DotVarTest w; + w.z.x = 3; + return w.z.x; +} +static assert(dotvar1() == 3); + +int dotvar2() +{ + DotVarTest2[4] m; + m[2].z.x = 3; + m[1].p.z.x = 5; + return m[2].z.x + 7; +} +static assert(dotvar2() == 10); + + +struct RetRefStruct +{ + int x; + char c; +} + +// Return value reference tests, for D2 only. + +ref RetRefStruct reffunc1(ref RetRefStruct a) +{ + int y = a.x; + return a; +} + +ref RetRefStruct reffunc2(ref RetRefStruct a) +{ + RetRefStruct z = a; + return reffunc1(a); +} + +ref int reffunc7(ref RetRefStruct aa) +{ + return reffunc1(aa).x; +} + +ref int reffunc3(ref int a) +{ + return a; +} + +struct RefTestStruct +{ + RetRefStruct r; + + ref RefTestStruct reffunc4(ref RetRefStruct[3] a) + { + return this; + } + + ref int reffunc6() + { + return this.r.x; + } +} + +ref RetRefStruct reffunc5(ref RetRefStruct[3] a) +{ + int t = 1; + for (int i = 0; i < 10; ++i) + { + if (i == 7) + ++t; + } + return a[reffunc3(t)]; +} + +int retRefTest1() +{ + RetRefStruct b = RetRefStruct(0, 'a'); + reffunc1(b).x = 3; + return b.x - 1; +} + +int retRefTest2() +{ + RetRefStruct b = RetRefStruct(0, 'a'); + reffunc2(b).x = 3; + RetRefStruct[3] z; + RefTestStruct w; + w.reffunc4(z).reffunc4(z).r.x = 4; + assert(w.r.x == 4); + w.reffunc6() = 218; + assert(w.r.x == 218); + z[2].x = 3; + int q = 4; + int u = reffunc5(z).x + reffunc3(q); + assert(u == 7); + reffunc5(z).x += 7; + assert(z[2].x == 10); + RetRefStruct m = RetRefStruct(7, 'c'); + m.x = 6; + reffunc7(m) += 3; + assert(m.x == 9); + return b.x - 1; +} + +int retRefTest3() +{ + RetRefStruct b = RetRefStruct(0, 'a'); + auto deleg = function (RetRefStruct a){ return a; }; + typeof(deleg)[3] z; + z[] = deleg; + auto y = deleg(b).x + 27; + b.x = 5; + assert(y == 27); + y = z[1](b).x + 22; + return y - 1; +} + +int retRefTest4() +{ + RetRefStruct b = RetRefStruct(0, 'a'); + reffunc3(b.x) = 218; + assert(b.x == 218); + return b.x; +} + +static assert(retRefTest1() == 2); +static assert(retRefTest2() == 2); +static assert(retRefTest3() == 26); +static assert(retRefTest4() == 218); + +/************************************************** + Bug 7887 assign to returned reference +**************************************************/ + +bool test7887() +{ + ref int f(ref int x) { return x; } + int a; + f(a) = 42; + return (a == 42); +} +static assert(test7887()); + +/************************************************** + Bug 7473 struct non-ref +**************************************************/ + +struct S7473 +{ + int i; +} + +static assert({ + S7473 s = S7473(1); + assert(s.i == 1); + bug7473(s); + assert(s.i == 1); + return true; +}()); + +void bug7473(S7473 s) +{ + s.i = 2; +} + +struct S7473b +{ + S7473 m; +} + +static assert({ + S7473b s = S7473b(S7473(7)); + assert(s.m.i == 7); + bug7473b(s); + assert(s.m.i == 7); + return true; +}()); + +void bug7473b(S7473b s) +{ + s.m.i = 2; +} + +/************************************************** + Bug 4389 +**************************************************/ + +int bug4389() +{ + string s; + dchar c = '\u2348'; + s ~= c; + assert(s.length == 3); + dchar d = 'D'; + s ~= d; + assert(s.length == 4); + s = ""; + s ~= c; + assert(s.length == 3); + s ~= d; + assert(s.length == 4); + string z; + wchar w = '\u0300'; + z ~= w; + assert(z.length == 2); + z = ""; + z ~= w; + assert(z.length == 2); + return 1; +} + +static assert(bug4389()); + +// ICE(constfold.c) +int ice4389() +{ + string s; + dchar c = '\u2348'; + s ~= c; + s = s ~ "xxx"; + return 1; +} + +static assert(ice4389()); + +// ICE(expression.c) +string ice4390() +{ + string s; + dchar c = '`'; + s ~= c; + s ~= c; + return s; +} + +static assert(mixin(ice4390()) == ``); + +// bug 5248 (D1 + D2) +struct Leaf5248 +{ + string Compile_not_ovloaded() + { + return "expression"; + } +} +struct Matrix5248 +{ + Leaf5248 Right; + + string Compile() + { + return Right.Compile_not_ovloaded(); + } +}; + +static assert(Matrix5248().Compile()); + +/************************************************** + 4837 >>>= +**************************************************/ + +bool bug4837() +{ + ushort x = 0x89AB; + x >>>= 4; + assert(x == 0x89A); + byte y = 0x7C; + y >>>= 2; + assert(y == 0x1F); + return true; +} + +static assert(bug4837()); + +/************************************************** + 10252 shift out of range +**************************************************/ + +int lshr10252(int shift) +{ + int a = 5; + return a << shift; +} + +int rshr10252(int shift) +{ + int a = 5; + return a >> shift; +} + +int ushr10252(int shift) +{ + int a = 5; + return a >>> shift; +} + +static assert( is(typeof(compiles!(lshr10252( 4))))); +static assert(!is(typeof(compiles!(lshr10252(60))))); +static assert( is(typeof(compiles!(rshr10252( 4))))); +static assert(!is(typeof(compiles!(rshr10252(80))))); +static assert( is(typeof(compiles!(ushr10252( 2))))); +static assert(!is(typeof(compiles!(ushr10252(60))))); + +/************************************************** + 1982 CTFE null problems +**************************************************/ + +enum a1982 = [1, 2, 3]; +static assert(a1982 !is null); + +string foo1982() { return null; } +static assert(foo1982() is null); +static assert(!foo1982().length); + +static assert(null is null); + +/************************************************** + 7988 CTFE return values should be allowed in compile-time expressions +**************************************************/ + +class X7988 { int y; this() { y = 2; } } +static assert((new X7988).y == 2); + +/************************************************** + 8253 ICE: calling of member function of non-CTFE class variable +**************************************************/ + +class Bug8253 +{ + bool j() + { + return true; + } +} +Bug8253 m8253; +static assert(!is(typeof(compiles!(m8253.j())))); + +/************************************************** + 8285 Issue with slice returned from CTFE function +**************************************************/ + +string foo8285() +{ + string s = "ab"; + return s[0 .. $]; +} + +template T8285b(string s) { } + +template T8285a() +{ + enum s = foo8285(); + alias T8285b!(s) t2; +} + +int bar8285() +{ + alias T8285a!() t1; + return 0; +} + +int baz8285(int x) +{ + return 0; +} + +static assert(baz8285(bar8285()) == 0); + +// test case 2 + +string xbar8285() +{ + string s = "ab"; + return s[0 .. $]; +} + +template xT8285a() +{ + enum xT8285a = xbar8285()[0 .. $]; +} + +string xbaz8285() +{ + return xT8285a!(); +} + +string xfoo8285(string s) +{ + return s; +} + +static assert(xfoo8285(xbaz8285()) == "ab"); + +/************************************************** + 'this' parameter bug revealed during refactoring +**************************************************/ + +int thisbug1(int x) { return x; } + +struct ThisBug1 +{ + int m = 1; + int wut() + { + return thisbug1(m); + } +} + +int thisbug2() +{ + ThisBug1 spec; + return spec.wut(); +} + +static assert(thisbug2()); + +/************************************************** + 6972 ICE with cast()cast()assign +**************************************************/ + +int bug6972() +{ + ubyte n = 6; + n /= 2u; + return n; +} +static assert(bug6972() == 3); + +/************************************************** + Bug 6164 +**************************************************/ + +size_t bug6164() +{ + int[] ctfe2(int n) + { + int[] r = []; + if (n != 0) + r ~= [1] ~ ctfe2(n - 1); + return r; + } + return ctfe2(2).length; +} +static assert(bug6164() == 2); + +/************************************************** + Interpreter code coverage tests +**************************************************/ + +int cov1(int a) +{ + a %= 15382; + a /= 5; + a = ~ a; + bool c = (a == 0); + bool b = true && c; + assert(b == 0); + b = false && c; + assert(b == 0); + b = false || c; + assert(b == 0); + a ^= 0x45349; + a = ~ a; + a &= 0xFF3F; + a >>>= 1; + a = a ^ 0x7393; + a = a >> 1; + a = a >>> 1; + a = a | 0x010101; + return a; +} +static assert(cov1(534564) == 71589); + +int cov2() +{ + int i = 0; + do + { + goto DOLABEL; + DOLABEL: + if (i != 0) + { + goto IFLABEL; + IFLABEL: + switch(i) + { + case 3: + break; + case 6: + goto SWITCHLABEL; + SWITCHLABEL: + i = 27; + goto case 3; + default: + assert(0); + } + return i; + } + i = 6; + } while(true); + return 88; // unreachable +} +static assert(cov2() == 27); + +template CovTuple(T...) +{ + alias T CovTuple; +} + +alias CovTuple!(int, long) TCov3; + +int cov3(TCov3 t) +{ + TCov3 s; + s = t; + assert(s[0] == 1); + assert(s[1] == 2); + return 7; +} +static assert(cov3(1, 2) == 7); + +int badassert1(int z) +{ + assert(z == 5, "xyz"); + return 1; +} + +size_t badslice1(int[] z) +{ + return z[0 .. 3].length; +} + +size_t badslice2(int[] z) +{ + return z[0 .. badassert1(1)].length; +} + +size_t badslice3(int[] z) +{ + return z[badassert1(1) .. 2].length; +} + +static assert(!is(typeof(compiles!(badassert1(67))))); +static assert( is(typeof(compiles!(badassert1(5))))); +static assert(!is(typeof(compiles!(badslice1([1,2]))))); +static assert(!is(typeof(compiles!(badslice2([1,2]))))); +static assert(!is(typeof(compiles!(badslice3([1,2,3]))))); + +/*******************************************/ + +int bug7894() +{ + for (int k = 0; k < 2; ++k) + { + goto Lagain; +Lagain: + ; + } + int m = 1; + do + { + ++m; + goto Ldo; +Ldo: ; + } while (m < 3); + assert(m == 3); + + return 1; +} +static assert(bug7894()); + +/*******************************************/ + +size_t bug5524(int x, int[] more...) +{ + int[0] zz; + assert(zz.length == 0); + return 7 + more.length + x; +} +static assert(bug5524(3) == 10); + + +// 5722 + +static assert(("" ~ "\©"[0]).length == 1); +const char[] null5722 = null; +static assert((null5722 ~ "\©"[0]).length == 1); +static assert(("\©"[0] ~ null5722).length == 1); + +/******************************************* + * Tests for CTFE Array support. + * Including bugs 1330, 3801, 3835, 4050, + * 4051, 5147, and major functionality + *******************************************/ + +char[] bug1330StringIndex() +{ + char[] blah = "foo".dup; + assert(blah == "foo"); + char[] s = blah[0 .. 2]; + blah[0] = 'h'; + assert(s == "ho"); + s[0] = 'm'; + return blah; +} +static assert(bug1330StringIndex() == "moo"); +static assert(bug1330StringIndex() == "moo"); // check we haven't clobbered any string literals + +int[] bug1330ArrayIndex() +{ + int[] blah = [1,2,3]; + int[] s = blah; + s = blah[0 .. 2]; + int z = blah[0] = 6; + assert(z == 6); + assert(blah[0] == 6); + assert(s[0] == 6); + assert(s == [6, 2]); + s[1] = 4; + assert(z == 6); + return blah; +} +static assert(bug1330ArrayIndex() == [6, 4, 3]); +static assert(bug1330ArrayIndex() == [6, 4, 3]); // check we haven't clobbered any literals + +char[] bug1330StringSliceAssign() +{ + char[] blah = "food".dup; + assert(blah == "food"); + char[] s = blah[1 .. 4]; + blah[0 .. 2] = "hc"; + assert(s == "cod"); + s[0 .. 2] = ['a', 'b']; // Mix string + array literal + assert(blah == "habd"); + s[0 .. 2] = "mq"; + return blah; +} +static assert(bug1330StringSliceAssign() == "hmqd"); +static assert(bug1330StringSliceAssign() == "hmqd"); + +int[] bug1330ArraySliceAssign() +{ + int[] blah = [1, 2, 3, 4]; + int[] s = blah[1 .. 4]; + blah[0 .. 2] = [7, 9]; + assert(s == [9, 3, 4]); + s[0 .. 2] = [8, 15]; + return blah; +} +static assert(bug1330ArraySliceAssign() == [7, 8, 15, 4]); + +int[] bug1330ArrayBlockAssign() +{ + int[] blah = [1, 2, 3, 4, 5]; + int[] s = blah[1 .. 4]; + blah[0 .. 2] = 17; + assert(s == [17, 3, 4]); + s[0 .. 2] = 9; + return blah; +} +static assert(bug1330ArrayBlockAssign() == [17, 9, 9, 4, 5]); + +char[] bug1330StringBlockAssign() +{ + char[] blah = "abcde".dup; + char[] s = blah[1 .. 4]; + blah[0 .. 2] = 'x'; + assert(s == "xcd"); + s[0 .. 2] = 'y'; + return blah; +} +static assert(bug1330StringBlockAssign() == "xyyde"); + +int assignAA(int x) +{ + int[int] aa; + int[int] cc = aa; + assert(cc.values.length == 0); + assert(cc.keys.length == 0); + aa[1] = 2; + aa[x] = 6; + int[int] bb = aa; + assert(bb.keys.length == 2); + assert(cc.keys.length == 0); // cc is not affected to aa, because it is null + aa[500] = 65; + assert(bb.keys.length == 3); // but bb is affected by changes to aa + return aa[1] + aa[x]; +} +static assert(assignAA(12) == 8); + +template Compileable(int z) { bool OK; } + +int arraybounds(int j, int k) +{ + int[] xxx = [1, 2, 3, 4, 5]; + int[] s = xxx[1 .. $]; + s = s[j .. k]; // slice of slice + return s[$ - 1]; +} +static assert(!is(typeof(Compileable!(arraybounds(1, 14))))); +static assert(!is(typeof(Compileable!(arraybounds(15, 3))))); +static assert(arraybounds(2, 4) == 5); + +int arraybounds2(int j, int k) +{ + int[] xxx = [1, 2, 3, 4, 5]; + int[] s = xxx[j .. k]; // direct slice + return 1; +} +static assert(!is(typeof(Compileable!(arraybounds2(1, 14))))); +static assert(!is(typeof(Compileable!(arraybounds2(15, 3))))); +static assert(arraybounds2(2, 4) == 1); + +int bug5147a() +{ + int[1][2] a = 37; + return a[0][0]; +} +static assert(bug5147a() == 37); + +int bug5147b() +{ + int[4][2][3][17] a = 37; + return a[0][0][0][0]; +} +static assert(bug5147b() == 37); + +int setlen() +{ + int[][] zzz; + zzz.length = 2; + zzz[0].length = 10; + assert(zzz.length == 2); + assert(zzz[0].length == 10); + assert(zzz[1].length == 0); + return 2; +} +static assert(setlen() == 2); + +int[1][1] bug5147() +{ + int[1][1] a = 1; + return a; +} +static assert(bug5147() == [[1]]); + +enum int[1][1] enum5147 = bug5147(); +static assert(enum5147 == [[1]]); + +immutable int[1][1] bug5147imm = bug5147(); + +// Index referencing +int[2][2] indexref1() +{ + int[2][2] a = 2; + a[0] = 7; + + int[][] b = [null, null]; + b[0 .. $] = a[0][0 .. 2]; + assert(b[0][0] == 7); + assert(b[0][1] == 7); + int[] w; + w = a[0]; + assert(w[0] == 7); + w[0 .. $] = 5; + assert(a[0] != [7, 7]); + assert(a[0] == [5, 5]); + assert(b[0] == [5, 5]); + return a; +} +int[2][2] indexref2() +{ + int[2][2] a = 2; + a[0] = 7; + + int[][2] b = null; + b[0 .. $] = a[0]; + assert(b[0][0] == 7); + assert(b[0][1] == 7); + assert(b == [[7, 7], [7, 7]]); + int[] w; + w = a[0]; + assert(w[0] == 7); + w[0 .. $] = 5; + assert(a[0] != [7, 7]); + assert(a[0] == [5, 5]); + assert(b[0] == [5, 5]); + return a; +} +int[2][2] indexref3() +{ + int[2][2] a = 2; + a[0]=7; + + int[][2] b = [null, null]; + b[0 .. $] = a[0]; + assert(b[0][0] == 7); + assert(b[0][1] == 7); + int[] w; + w = a[0]; + assert(w[0] == 7); + w[0 .. $] = 5; + assert(a[0] != [7, 7]); + assert(a[0] == [5, 5]); + assert(b[0] == [5, 5]); + return a; +} +int[2][2] indexref4() +{ + int[2][2] a = 2; + a[0] = 7; + + int[][2] b =[[1, 2, 3], [1, 2, 3]]; // wrong code + b[0] = a[0]; + assert(b[0][0] == 7); + assert(b[0][1] == 7); + int[] w; + w = a[0]; //[0 .. $]; + assert(w[0] == 7); + w[0 .. $] = 5; + assert(a[0] != [7, 7]); + assert(a[0] == [5, 5]); + assert(b[0] == [5, 5]); + return a; +} +static assert(indexref1() == [[5, 5], [2, 2]]); +static assert(indexref2() == [[5, 5], [2, 2]]); +static assert(indexref3() == [[5, 5], [2, 2]]); +static assert(indexref4() == [[5, 5], [2, 2]]); + +int staticdynamic() +{ + int[2][1] a = 2; + assert(a == [[2, 2]]); + + int[][1] b = a[0][0 .. 1]; + assert(b[0] == [2]); + auto k = b[0]; + auto m = a[0][0 .. 1]; + assert(k == [2]); + assert(m == k); + return 0; +} +static assert(staticdynamic() == 0); + +int chainassign() +{ + int[4] x = 6; + int[] y = new int[4]; + auto k = (y[] = (x[] = 2)); + return k[0]; +} +static assert(chainassign() == 2); + +// index assignment +struct S3801 +{ + char c; + int[3] arr; + + this(int x, int y) + { + c = 'x'; + arr[0] = x; + arr[1] = y; + } +} + +int bug3801() +{ + S3801 xxx = S3801(17, 67); + int[] w = xxx.arr; + xxx.arr[1] = 89; + assert(xxx.arr[0] == 17); + assert(w[1] == 89); + assert(w == [17, 89, 0]); + return xxx.arr[1]; +} + +enum : S3801 { bug3801e = S3801(17, 18) } +static assert(bug3801e.arr == [17, 18, 0]); + +immutable S3801 bug3801u = S3801(17, 18); +static assert(bug3801u.arr == [17, 18, 0]); +static assert(bug3801() == 89); + +int bug3835() +{ + int[4] arr; + arr[] = 19; + arr[0] = 4; + int kk; + foreach (ref el; arr) + { + el += 10; + kk = el; + } + assert(arr[2] == 29); + arr[0] += 3; + return arr[0]; +} +static assert(bug3835() == 17); + +auto bug5852(const(string) s) +{ + string[] r; + r ~= s; + assert(r.length == 1); + return r[0].length; +} +static assert(bug5852("abc") == 3); + +// 7217 + +struct S7217 { int[] arr; } + +bool f7217() +{ + auto s = S7217(); + auto t = s.arr; + return true; +} +static assert(f7217()); + +/******************************************* + Set array length +*******************************************/ + +static assert( +{ + struct W { int[] z; } + W w; + w.z.length = 2; + assert(w.z.length == 2); + w.z.length = 6; + assert(w.z.length == 6); + return true; +}()); + +// 7185 char[].length = n + +bool bug7185() +{ + auto arr = new char[2]; + auto arr2 = new char[2]; + arr2[] = "ab"; + arr.length = 1; + arr2.length = 7; + assert(arr.length == 1); + assert(arr2.length == 7); + assert(arr2[0 .. 2] == "ab"); + return true; +} +static assert(bug7185()); + +bool bug9908() +{ + static const int[3] sa = 1; + return sa == [1, 1, 1]; +} +static assert(bug9908()); + +/******************************************* + 6934 +*******************************************/ + +struct Struct6934 +{ + int[] x = [1, 2]; +} + +void bar6934(ref int[] p) +{ + p[0] = 12; + assert(p[0] == 12); + p[0 .. 1] = 17; + assert(p[0] == 17); + p = p[1 .. $]; +} + +int bug6934() +{ + Struct6934 q; + bar6934(q.x); + int[][] y = [[2, 5], [3, 6, 8]]; + bar6934(y[0]); + return 1; +} +static assert(bug6934()); + +/******************************************* + Bug 5671 +*******************************************/ + +static assert(['a', 'b'] ~ "c" == "abc"); + +/******************************************* + 8624 +*******************************************/ + +int evil8624() +{ + long m = 0x1_0000_0000L; + assert(m != 0); + long[] a = [0x1_0000_0000L]; + long[] b = [0x4_0000_0000L]; + assert(a[] != b[]); + return 1; +} +static assert(evil8624()); + +/******************************************* + 8644 array literal >,< +*******************************************/ + +int bug8644() +{ + auto m = "a"; + auto z = ['b']; + auto c = "b7"; + auto d = ['b', '6']; + assert(m < z); + assert(z > m); + assert(z <= c); + assert(c > z); + assert(c > d); + assert(d >= d); + return true; +} +static assert(bug8644()); + +/******************************************* + Bug 6159 +*******************************************/ + +struct A6159 {} + +static assert({ return A6159.init is A6159.init; }()); +static assert({ return [1] is [1]; }()); + +/******************************************* + Bug 5685 +*******************************************/ + +string bug5685() +{ + return "xxx"; +} +struct Bug5865 +{ + void test1() + { + enum file2 = (bug5685())[0 .. $]; + } +} + +/******************************************* + 6235 - Regression ICE on $ in template +*******************************************/ + +struct Bug6235(R) +{ + enum XXX = is(typeof(R.init[0 .. $]) : const ubyte[]); +} + +Bug6235!(ubyte[]) bug6235; + +/******************************************* + 8673 ICE +*******************************************/ + +enum dollar8673 = [0][(() => $ - 1)()]; + +/******************************************* + Bug 5840 +*******************************************/ + +struct Bug5840 +{ + string g; + int w; +} + +int bug5840(int u) +{ + // check for clobbering + Bug5840 x = void; + x.w = 4; + x.g = "3gs"; + if (u == 1) + bug5840(2); + if (u == 2) + { + x.g = "abc"; + x.w = 3465; + } + else + { + assert(x.g == "3gs"); + assert(x.w == 4); + } + return 56; +} +static assert(bug5840(1) == 56); + +/******************************************* + 7810 +*******************************************/ + +int bug7810() +{ + int[1][3] x = void; + x[0] = [2]; + x[1] = [7]; + assert(x[0][0] == 2); + + char[1][3] y = void; + y[0] = "a"; + y[1] = "b"; + assert(y[0][0] == 'a'); + + return 1; +} +static assert(bug7810()); + +struct Bug7810 +{ + int w; +} +int bug7810b(T)(T[] items...) +{ + assert(items[0] == Bug7810(20)); + return 42; +} +static assert(bug7810b(Bug7810(20), Bug7810(10)) == 42); + +/******************************************* + std.datetime ICE (30 April 2011) +*******************************************/ + +struct TimeOfDayZ +{ +public: + this(int hour) { } + invariant() { } +} +const testTODsThrownZ = TimeOfDayZ(0); + +/******************************************* + Bug 5954 +*******************************************/ + +struct Bug5954 +{ + int x; + this(int xx) + { + this.x = xx; + } +} +void bug5954() +{ + enum f = Bug5954(10); + static assert(f.x == 10); +} + +/******************************************* + Bug 5972 +*******************************************/ + +int bug5972() +{ + char[] z = "abc".dup; + char[][] a = [null, null]; + a[0] = z[0 .. 2]; + char[] b = a[0]; + assert(b == "ab"); + a[0][1] = 'q'; + assert(a[0] == "aq"); + assert(b == "aq"); + assert(b[1] == 'q'); + //a[0][0 .. $ - 1][0 .. $] = a[0][0 .. $ - 1][0 .. $]; // overlap + return 56; +} +static assert(bug5972() == 56); + +/******************************************* + 2.053beta [CTFE]ICE 'global errors' +*******************************************/ + +int wconcat(wstring replace) +{ + wstring value; + value = "A"w; + value = value ~ replace; + return 1; +} +static assert(wconcat("X"w)); + +/******************************************* + 10397 string concat +*******************************************/ + +static assert(!is(typeof(compiles!("abc" ~ undefined)))); +static assert(!is(typeof(compiles!(otherundefined ~ "abc")))); + +/******************************************* + 9634 struct concat +*******************************************/ + +struct Bug9634 +{ + int raw; +} + +bool bug9634() +{ + Bug9634[] jr = [Bug9634(42)]; + + Bug9634[] ir = null ~ jr; + Bug9634[] kr = jr ~ null; + Bug9634[] mr = jr ~ jr; + + jr[0].raw = 6; + assert(ir[0].raw == 42); + assert(kr[0].raw == 42); + assert(jr[0].raw == 6); + assert(&mr[0] != &mr[1]); + return true; +} + +static assert(bug9634()); + +/******************************************* + Bug 4001: A Space Oddity +*******************************************/ + +int space() { return 4001; } + +void oddity4001(int q) +{ + const int bowie = space(); + static assert(space() == 4001); + static assert(bowie == 4001); +} + +/******************************************* + Bug 3779 +*******************************************/ + +static const bug3779 = ["123"][0][$ - 1]; + +/******************************************* + Bug 8893 ICE with bad struct literal +*******************************************/ + +struct Foo8893 +{ + char[3] data; +} +int bar8893(Foo8893 f) +{ + return f.data[0]; +} +static assert(!is(typeof(compiles!(bar8893(Foo8893(['a','b'])))))); + +/******************************************* + non-Cow struct literals +*******************************************/ + +struct Zadok +{ + int[3] z; + char[4] s = void; + ref int[] fog(ref int[] q) { return q; } + int bfg() + { + z[0] = 56; + auto zs = z[]; + fog(zs) = [56, 6, 8]; + + assert(z[0] == 56); + assert(z[1] == 61); + assert(z[2] == 61); + + assert(zs[0] == 56); + assert(zs[1] == 6); + return zs[2]; + } +} + +struct Vug +{ + Zadok p; + int[] other; +} + +int quop() +{ + int[] heap = new int[5]; + heap[] = 738; + Zadok pong; + pong.z = 3; + int[] w = pong.z; + assert(w[0] == 3); + Zadok phong; + phong.z = 61; + pong = phong; + assert(w[0] == 61); + Vug b = Vug(Zadok(17, "abcd")); + b = Vug(Zadok(17, "abcd"), heap); + b.other[2] = 78; + assert(heap[2] == 78); + char[] y = b.p.s; + assert(y[2] == 'c'); + phong.s = ['z','x','f', 'g']; + w = b.p.z; + assert(y[2] == 'c'); + assert(w[0] == 17); + b.p = phong; + assert(y[2] == 'f'); + + Zadok wok = Zadok(6, "xyzw"); + b.p = wok; + assert(y[2] == 'z'); + b.p = phong; + assert(w[0] == 61); + Vug q; + q.p = pong; + return pong.bfg(); +} + +static assert(quop() == 8); +static assert(quop() == 8); // check for clobbering + +/************************************************** + Bug 5676 tuple assign of struct that has void opAssign +**************************************************/ + +struct S5676 +{ + int x; + void opAssign(S5676 rhs) { x = rhs.x; } +} + +struct Tup5676(E...) +{ + E g; + void foo(E values) { g = values; } +} + +bool ice5676() +{ + Tup5676!(S5676) q; + q.foo(S5676(3)); + assert(q.g[0].x == 3); + return true; +} + +static assert(ice5676()); + +/************************************************** + Bug 5682 Wrong CTFE with operator overloading +**************************************************/ + +struct A +{ + int n; + auto opBinary(string op : "*")(A rhs) + { + return A(n * rhs.n); + } +} + +A foo(A[] lhs, A[] rhs) +{ + A current; + for (size_t k = 0; k < rhs.length; ++k) + { + current = lhs[k] * rhs[k]; + } + return current; +} + +auto test() +{ + return foo([A(1), A(2)], [A(3), A(4)]); +} + +static assert(test().n == 8); + +/************************************************** + Attempt to modify a read-only string literal +**************************************************/ +struct Xarg +{ + char[] s; +} + +int zfs(int n) +{ + char[] m = "exy".dup; + if (n == 1) + { + // it's OK to cast to const, then cast back + string ss = cast(string)m; + m = cast(char[])ss; + m[2]='q'; + return 56; + } + auto q = Xarg(cast(char[])"abc"); + assert(q.s[1] == 'b'); + if (n == 2) + q.s[1] = 'p'; + else if (n == 3) + q.s[0 .. $] = 'p'; + char* w = &q.s[2]; + if (n == 4) + *w = 'z'; + return 76; +} + +static assert(!is(typeof(compiles!(zfs(2))))); +static assert(!is(typeof(compiles!(zfs(3))))); +static assert(!is(typeof(compiles!(zfs(4))))); +static assert( is(typeof(compiles!(zfs(1))))); +static assert( is(typeof(compiles!(zfs(5))))); + +/************************************************** + .dup must protect string literals +**************************************************/ + +string mutateTheImmutable(immutable string _s) +{ + char[] s = _s.dup; + foreach (ref c; s) + c = 'x'; + return s.idup; +} + +string doharm(immutable string _name) +{ + return mutateTheImmutable(_name[2 .. $].idup); +} + +enum victimLiteral = "CL_INVALID_CONTEXT"; + +enum thug = doharm(victimLiteral); +static assert(victimLiteral == "CL_INVALID_CONTEXT"); + +/************************************************** + Use $ in a slice of a dotvar slice +**************************************************/ + +int sliceDollar() +{ + Xarg z; + z.s = new char[20]; + z.s[] = 'b'; + z.s = z.s[2 .. $ - 2]; + z.s[$ - 2] = 'c'; + return z.s[$ - 2]; +} +static assert(sliceDollar() == 'c'); + +/************************************************** + Variation of 5972 which caused segfault +**************************************************/ + +int bug5972crash() +{ + char[] z = "abc".dup; + char[][] a = [null, null]; + a[0] = z[0 .. 2]; + a[0][1] = 'q'; + return 56; +} +static assert(bug5972crash() == 56); + +/************************************************** + String slice assignment through ref parameter +**************************************************/ + +void popft(A)(ref A a) +{ + a = a[1 .. $]; +} + +int sdfgasf() +{ + auto scp = "abc".dup; + popft(scp); + return 1; +} +static assert(sdfgasf() == 1); + +/************************************************** + 8830 slice of slice.ptr +**************************************************/ + +string bug8830(string s) +{ + auto ss = s[1 .. $]; + return ss.ptr[0 .. 2]; +} +static assert(bug8830("hello") == "el"); + +/************************************************** + 8608 ICE +**************************************************/ + +void bug8608(ref int m) {} +void test8608() +{ + int z; + int foo(bool b) + { + if (b) + bug8608(z); + return 1; + } + static assert( is(typeof(compiles!(foo(false))))); + static assert(!is(typeof(compiles!(foo(true) )))); +} + +/************************************************** + Bug 7770 +**************************************************/ + +immutable char[] foo7770 = "abcde"; + +int bug7770a(string a) +{ + return 1; +} + +bool bug7770b(char c) +{ + return true; +} + +static assert(bug7770a(foo7770[0 .. $])); +static assert(bug7770b(foo7770[$ - 2])); + +void baz7770() +{ + static assert(bug7770a(foo7770[0 .. $])); + static assert(bug7770b(foo7770[$ - 2])); +} + +/************************************************** + 8601 ICE +**************************************************/ + +dchar bug8601(dstring s) +{ + dstring w = s[1 .. $]; + return w[0]; +} + +enum dstring e8601 = [cast(dchar)'o', 'n']; +static assert(bug8601(e8601) == 'n'); + +/************************************************** + Bug 6015 +**************************************************/ + +struct Foo6015 +{ + string field; +} + +bool func6015(string input) +{ + Foo6015 foo; + foo.field = input[0 .. $]; + assert(foo.field == "test"); + foo.field = "test2"; + assert(foo.field != "test"); + assert(foo.field == "test2"); + return true; +} + +static assert(func6015("test")); + +/************************************************** + Bug 6001 +**************************************************/ + +void bug6001e(ref int[] s) +{ + int[] r = s; + s ~= 0; +} +bool bug6001f() +{ + int[] s; + bug6001e(s); + return true; +} +static assert(bug6001f()); + +// Assignment to AAs + +void blah(int[char] as) +{ + auto k = [6: as]; + as = k[6]; +} +int blaz() +{ + int[char] q; + blah(q); + return 67; +} +static assert(blaz() == 67); + +void bug6001g(ref int[] w) +{ + w = [88]; + bug6001e(w); + w[0] = 23; +} + +bool bug6001h() +{ + int[] s; + bug6001g(s); + assert(s.length == 2); + assert(s[1] == 0); + assert(s[0] == 23); + return true; +} +static assert(bug6001h()); + +/************************************************** + 10243 wrong code *&arr as ref parameter + 10551 wrong code (&arr)[0] as ref parameter +**************************************************/ + +void bug10243(ref int n) +{ + n = 3; +} + +void bug10551(int* p) +{ + bug10243(p[0]); +} + +bool test10243() +{ + int[1] arr; + bug10243(*arr.ptr); + assert(arr[0] == 3); + int[1] arr2; + bug10551(arr2.ptr); + assert(arr2[0] == 3); + int v; + bug10551(&v); + assert(v == 3); + return true; +} + +static assert(test10243()); + +/************************************************** + Bug 4910 +**************************************************/ + +int bug4910(int a) +{ + return a; +} + +static int var4910; +static assert(!is(typeof(Compiles!(bug4910(var4910))))); + +static assert(bug4910(123)); + +/************************************************** + Bug 5845 - Regression(2.041) +**************************************************/ + +void test5845(ulong cols) {} + +uint solve(bool niv, ref ulong cols) +{ + if (niv) + solve(false, cols); + else + test5845(cols); + return 65; +} + +ulong nqueen(int n) +{ + ulong cols = 0; + return solve(true, cols); +} + +static assert(nqueen(2) == 65); + +/************************************************** + Bug 5258 +**************************************************/ + +struct Foo5258 { int x; } +void bar5258(int n, ref Foo5258 fong) +{ + if (n) + bar5258(n - 1, fong); + else + fong.x++; +} +int bug5258() +{ + Foo5258 foo5258 = Foo5258(); + bar5258(1, foo5258); + return 45; +} +static assert(bug5258() == 45); + +struct Foo5258b { int[2] r; } +void baqopY(int n, ref int[2] fongo) +{ + if (n) + baqopY(n - 1, fongo); + else + fongo[0]++; +} +int bug5258b() +{ + Foo5258b qq; + baqopY(1, qq.r); + return 618; +} +static assert(bug5258b() == 618); + +// Notice that this case involving reassigning the dynamic array +struct Foo5258c { int[] r; } +void baqop(int n, ref int[] fongo) +{ + if (n) + baqop(n - 1, fongo); + else + { + fongo = new int[20]; + fongo[0]++; + } +} +size_t bug5258c() +{ + Foo5258c qq; + qq.r = new int[30]; + baqop(1, qq.r); + return qq.r.length; +} +static assert(bug5258c() == 20); + +/************************************************** + Bug 6049 +**************************************************/ + +struct Bug6049 +{ + int m; + this(int x) { m = x; } + invariant() { } +} + +const Bug6049[] foo6049 = [Bug6049(6), Bug6049(17)]; + +static assert(foo6049[0].m == 6); + +/************************************************** + Bug 6052 +**************************************************/ + +struct Bug6052 +{ + int a; +} + +bool bug6052() +{ + Bug6052[2] arr; + for (int i = 0; i < 2; ++ i) + { + Bug6052 el = {i}; + Bug6052 ek = el; + arr[i] = el; + el.a = i + 2; + assert(ek.a == i); // ok + assert(arr[i].a == i); // fail + } + assert(arr[1].a == 1); // ok + assert(arr[0].a == 0); // fail + return true; +} + +static assert(bug6052()); + +bool bug6052b() +{ + int[][1] arr; + int[1] z = [7]; + arr[0] = z; + assert(arr[0][0] == 7); + arr[0] = z; + z[0] = 3; + assert(arr[0][0] == 3); + return true; +} + +static assert(bug6052b()); + +struct Bug6052c +{ + int x; + this(int a) { x = a; } +} + +int bug6052c() +{ + Bug6052c[] pieces = []; + for (int c = 0; c < 2; ++ c) + pieces ~= Bug6052c(c); + assert(pieces[1].x == 1); + assert(pieces[0].x == 0); + return 1; +} +static assert(bug6052c() == 1); +static assert(bug6052c() == 1); + + +static assert({ + Bug6052c[] pieces = []; + pieces.length = 2; + int c = 0; + pieces[0] = Bug6052c(c); + ++c; + pieces[1] = Bug6052c(c); + assert(pieces[0].x == 0); + return true; +}()); + +static assert({ + int[1][] pieces = []; + pieces.length = 2; + for (int c = 0; c < 2; ++ c) + pieces[c][0] = c; + assert(pieces[1][0] == 1); + assert(pieces[0][0] == 0); + return true; +}()); + +static assert({ + Bug6052c[] pieces = []; + for (int c = 0; c < 2; ++ c) + pieces ~= Bug6052c(c); + assert(pieces[1].x == 1); + assert(pieces[0].x == 0); + return true; +}()); + +static assert({ + int[1] z = 7; + int[1][] pieces = [z,z]; + pieces[1][0]=3; + assert(pieces[0][0] == 7); + pieces = pieces ~ [z,z]; + pieces[3][0] = 16; + assert(pieces[2][0] == 7); + pieces = [z,z] ~ pieces; + pieces[5][0] = 16; + assert(pieces[4][0] == 7); + return true; +}()); + +/************************************************** + Bug 6749 +**************************************************/ + +struct CtState +{ + string code; +} + +CtState bug6749() +{ + CtState[] pieces; + CtState r = CtState("correct"); + pieces ~= r; + r = CtState("clobbered"); + return pieces[0]; +} +static assert(bug6749().code == "correct"); + +/************************************************** + Index + slice assign to function returns +**************************************************/ + +int[] funcRetArr(int[] a) +{ + return a; +} + +int testFuncRetAssign() +{ + int[] x = new int[20]; + funcRetArr(x)[2] = 4; + assert(x[2] == 4); + funcRetArr(x)[] = 27; + assert(x[15] == 27); + return 5; +} +static assert(testFuncRetAssign() == 5); + +int keyAssign() +{ + int[int] pieces; + pieces[3] = 1; + pieces.keys[0] = 4; + pieces.values[0] = 27; + assert(pieces[3] == 1); + return 5; +} +static assert(keyAssign() == 5); + +/************************************************** + Bug 6054 -- AA literals +**************************************************/ + +enum x6054 = { + auto p = { + int[string] pieces; + pieces[['a'].idup] = 1; + return pieces; + }(); + return p; +}(); + +/************************************************** + Bug 6077 +**************************************************/ + +enum bug6077 = { + string s; + string t; + return s ~ t; +}(); + +/************************************************** + Bug 6078 -- Pass null array by ref +**************************************************/ + +struct Foo6078 +{ + int[] bar; +} + +static assert({ + Foo6078 f; + int i; + foreach (ref e; f.bar) + { + i += e; + } + return i; +}() == 0); + +int bug6078(ref int[] z) +{ + int[] q = z; + return 2; +} + +static assert({ + Foo6078 f; + return bug6078(f.bar); +}() == 2); + +/************************************************** + Bug 6079 -- Array bounds checking +**************************************************/ + +static assert(!is(typeof(compiles!({ + int[] x = [1, 2, 3, 4]; + x[4] = 1; + return true; +}() +)))); + +/************************************************** + Bug 6100 +**************************************************/ + +struct S6100 +{ + int a; +} + +S6100 init6100(int x) +{ + S6100 s = S6100(x); + return s; +} + +static const S6100[2] s6100a = [init6100(1), init6100(2)]; +static assert(s6100a[0].a == 1); + +/************************************************** + Bug 4825 -- failed with -inline +**************************************************/ + +int a4825() +{ + int r; + return r; +} + +int b4825() +{ + return a4825(); +} + +void c4825() +{ + void d() + { + auto e = b4825(); + } + static const int f = b4825(); +} + +/************************************************** + Bug 5708 -- failed with -inline +**************************************************/ + +string b5708(string s) { return s; } +string a5708(string s) { return b5708(s); } + +void bug5708() +{ + void m() { a5708("lit"); } + static assert(a5708("foo") == "foo"); + static assert(a5708("bar") == "bar"); +} + +/************************************************** + Bug 6120 -- failed with -inline +**************************************************/ + +struct Bug6120(T) +{ + this(int x) { } +} +static assert({ + auto s = Bug6120!int(0); + return true; +}()); + +/************************************************** + Bug 6123 -- failed with -inline +**************************************************/ + +struct Bug6123(T) +{ + void f() {} + // can also trigger if the struct is normal but f is template +} +static assert({ + auto piece = Bug6123!int(); + piece.f(); + return true; +}()); + +/************************************************** + Bug 6053 -- ICE involving pointers +**************************************************/ + +static assert({ + int* a = null; + assert(a is null); + assert(a == null); + return true; +}()); + +static assert({ + int b; + int* a = &b; + assert(a !is null); + *a = 7; + assert(b == 7); + assert(*a == 7); + return true; +}()); + +int dontbreak6053() +{ + auto q = &dontbreak6053; + void caz() {} + auto tr = &caz; + return 5; +} +static assert(dontbreak6053()); + +static assert({ + int a; + *(&a) = 15; + assert(a == 15); + assert(*(&a) == 15); + return true; +}()); + +static assert({ + int a = 5, b = 6, c = 2; + assert(*(c ? &a : &b) == 5); + assert(*(!c ? &a : &b) == 6); + return true; +}()); + +static assert({ + int a, b, c; + (c ? a : b) = 1; + return true; +}()); + +static assert({ + int a, b, c = 1; + int* p = &a; + (c ? *p : b) = 51; + assert(a == 51); + return true; +}()); + +/************************************************** + Pointer arithmetic, dereference, and comparison +**************************************************/ + +// dereference null pointer +static assert(!is(typeof(compiles!({ + int a, b, c = 1; + int* p; + (c ? *p : b) = 51; + return 6; +}() +)))); +static assert(!is(typeof(compiles!({ + int* a = null; + assert(*a != 6); + return 72; +}() +)))); + +// cannot <, > compare pointers to different arrays +static assert(!is(typeof(compiles!({ + int[5] a, b; + bool c = (&a[0] > &b[0]); + return 72; +}() +)))); + +// can ==, is, !is, != compare pointers for different arrays +static assert({ + int[5] a; + int[5] b; + assert(!(&a[0] == &b[0])); + assert(&a[0] != &b[0]); + assert(!(&a[0] is &b[0])); + assert(&a[0] !is &b[0]); + return 72; +}()); + +static assert({ + int[5] a; + a[0] = 25; + a[1] = 5; + int* b = &a[1]; + assert(*b == 5); + *b = 34; + int c = *b; + *b += 6; + assert(b == &a[1]); + assert(b != &a[0]); + assert(&a[0] < &a[1]); + assert(&a[0] <= &a[1]); + assert(!(&a[0] >= &a[1])); + assert(&a[4] > &a[0]); + assert(c == 34); + assert(*b == 40); + assert(a[1] == 40); + return true; +}()); + +static assert({ + int[12] x; + int* p = &x[10]; + int* q = &x[4]; + return p - q; +}() == 6); + +static assert({ + int[12] x; + int* p = &x[10]; + int* q = &x[4]; + q = p; + assert(p == q); + q = &x[4]; + assert(p != q); + q = q + 6; + assert(q is p); + return 6; +}() == 6); + +static assert({ + int[12] x; + int[] y = x[2 .. 8]; + int* p = &y[4]; + int* q = &x[6]; + assert(p == q); + p = &y[5]; + assert(p > q); + p = p + 5; // OK, as long as we don't dereference + assert(p > q); + return 6; +}() == 6); + +static assert({ + char[12] x; + const(char)* p = "abcdef"; + const (char)* q = p; + q = q + 2; + assert(*q == 'c'); + assert(q > p); + assert(q - p == 2); + assert(p - q == -2); + q = &x[7]; + p = &x[1]; + assert(q>p); + return 6; +}() == 6); + +// Relations involving null pointers +bool nullptrcmp() +{ + // null tests + void* null1 = null, null2 = null; + int x = 2; + void* p = &x; + assert(null1 == null2); + assert(null1 is null2); + assert(null1 <= null2); + assert(null1 >= null2); + assert(!(null1 > null2)); + assert(!(null2 > null1)); + assert(null1 != p); + assert(null1 !is p); + assert(p != null1); + assert(p !is null1); + assert(null1 <= p); + assert(p >= null2); + assert(p > null1); + assert(!(null1 > p)); + return true; +} +static assert(nullptrcmp()); + +/************************************************** + 10840 null pointer in dotvar +**************************************************/ + +struct Data10840 +{ + bool xxx; +} + +struct Bug10840 +{ + Data10840* _data; +} + +bool bug10840(int n) +{ + Bug10840 stack; + if (n == 1) + { + // detect deref through null pointer + return stack._data.xxx; + } + // Wrong-code for ?: + return stack._data ? false : true; +} + +static assert(bug10840(0)); +static assert(!is(typeof(Compileable!(bug10840(1))))); + +/************************************************** + 8216 ptr inside a pointer range +**************************************************/ + +// Four-pointer relations. Return true if [p1 .. p2] points inside [q1 .. q2] +// (where the end points don't coincide). +bool ptr4cmp(void* p1, void* p2, void* q1, void* q2) +{ +// Each compare can be written with <, <=, >, or >=. +// Either && or || can be used, giving 32 permutations. +// Additionally each compare can be negated with !, yielding 128 in total. + bool b1 = (p1 > q1 && p2 <= q2); + bool b2 = (p1 > q1 && p2 < q2); + bool b3 = (p1 >= q1 && p2 <= q2); + bool b4 = (p1 >= q1 && p2 < q2); + + bool b5 = (q1 <= p1 && q2 > p2); + bool b6 = (q1 <= p1 && q2 >= p2); + bool b7 = (p2 <= q2 && p1 > q1); + bool b8 = (!(p1 <= q1) && p2 <= q2); + bool b9 = (!(p1 <= q1) && !(p2 > q2)); + bool b10 = (!!!(p1 <= q1) && !(p2 > q2)); + + assert(b1 == b2 && b1 == b3 && b1 == b4 && b1 == b5 && b1 == b6); + assert(b1 == b7 && b1 == b8 && b1 == b9 && b1 == b10); + + bool c1 = (p1 <= q1 || p2 > q2); + assert(c1 == !b1); + bool c2 = (p1 < q1 || p2 >= q2); + bool c3 = (!(q1 <= p1) || !(q2 >= p2)); + assert(c1 == c2 && c1 == c3); + return b1; +} + +bool bug8216() +{ + int[4] a; + int[13] b; + int v; + int* p = &v; + assert(!ptr4cmp(&a[0], &a[3], p, p)); + assert(!ptr4cmp(&b[2], &b[9], &a[1], &a[2])); + assert(!ptr4cmp(&b[1], &b[9], &b[2], &b[8])); + assert( ptr4cmp(&b[2], &b[8], &b[1], &b[9])); + return 1; +} +static assert(bug8216()); + +/************************************************** + 6517 ptr++, ptr-- +**************************************************/ + +int bug6517() +{ + int[] arr = [1, 2, 3]; + auto startp = arr.ptr; + auto endp = arr.ptr + arr.length; + + for (; startp < endp; startp++) {} + startp = arr.ptr; + assert(startp++ == arr.ptr); + assert(startp != arr.ptr); + assert(startp-- != arr.ptr); + assert(startp == arr.ptr); + + return 84; +} +static assert(bug6517() == 84); + +/************************************************** + Out-of-bounds pointer assignment and deference +**************************************************/ + +int ptrDeref(int ofs, bool wantDeref) +{ + int[5] a; + int* b = &a[0]; + b = b + ofs; // OK + if (wantDeref) + return *b; // out of bounds + return 72; +} + +static assert(!is(typeof(compiles!(ptrDeref(-1, true))))); +static assert( is(typeof(compiles!(ptrDeref(4, true))))); +static assert( is(typeof(compiles!(ptrDeref(5, false))))); +static assert(!is(typeof(compiles!(ptrDeref(5, true))))); +static assert(!is(typeof(compiles!(ptrDeref(6, false))))); +static assert(!is(typeof(compiles!(ptrDeref(6, true))))); + +/************************************************** + Pointer += +**************************************************/ +static assert({ + int[12] x; + int zzz; + assert(&zzz); + int* p = &x[10]; + int* q = &x[4]; + q = p; + assert(p == q); + q = &x[4]; + assert(p != q); + q += 4; + assert(q == &x[8]); + q = q - 2; + q = q + 4; + assert(q is p); + return 6; +}() == 6); + +/************************************************** + Reduced version of bug 5615 +**************************************************/ + +const(char)[] passthrough(const(char)[] x) +{ + return x; +} + +sizediff_t checkPass(Char1)(const(Char1)[] s) +{ + const(Char1)[] balance = s[1 .. $]; + return passthrough(balance).ptr - s.ptr; +} +static assert(checkPass("foobar") == 1); + +/************************************************** + Pointers must not escape from CTFE +**************************************************/ + +struct Toq +{ + const(char)* m; +} + +Toq ptrRet(bool b) +{ + string x = "abc"; + return Toq(b ? x[0 .. 1].ptr : null); +} + +static assert(is(typeof(compiles!({ + enum Toq boz = ptrRet(false); // OK - ptr is null + Toq z = ptrRet(true); // OK -- ptr doesn't escape + return 4; +}() +)))); + +static assert(!is(typeof(compiles!({ + enum Toq boz = ptrRet(true); // fail - ptr escapes + return 4; +}() +)))); + +/************************************************** + Pointers to struct members +**************************************************/ + +struct Qoz +{ + int w; + int[3] yof; +} + +static assert({ + int[3] gaz; + gaz[2] = 3156; + Toq z = ptrRet(true); + auto p = z.m; + assert(*z.m == 'a'); + assert(*p == 'a'); + auto q = &z.m; + assert(*q == p); + assert(**q == 'a'); + Qoz g = Qoz(2, [5, 6, 7]); + auto r = &g.w; + assert(*r == 2); + r = &g.yof[1]; + assert(*r == 6); + g.yof[0] = 15; + ++r; + assert(*r == 7); + r -= 2; + assert(*r == 15); + r = &gaz[0]; + r += 2; + assert(*r == 3156); + return *p; +}() == 'a'); + +struct AList +{ + AList* next; + int value; + static AList* newList() + { + AList[] z = new AList[1]; + return &z[0]; + } + static AList* make(int i, int j) + { + auto r = newList(); + r.next = (new AList[1]).ptr; + r.value = 1; + AList* z = r.next; + (*z).value = 2; + r.next.value = j; + assert(r.value == 1); + assert(r.next.value == 2); + r.next.next = &(new AList[1])[0]; + assert(r.next.next != null); + assert(r.next.next); + r.next.next.value = 3; + assert(r.next.next.value == 3); + r.next.next = newList(); + r.next.next.value = 9; + return r; + } + static int checkList() + { + auto r = make(1,2); + assert(r.value == 1); + assert(r.next.value == 2); + assert(r.next.next.value == 9); + return 2; + } +} + +static assert(AList.checkList() == 2); + +/************************************************** + 7194 pointers as struct members +**************************************************/ + +struct S7194 { int* p, p2; } + +int f7194() +{ + assert(S7194().p == null); + assert(!S7194().p); + assert(S7194().p == S7194().p2); + S7194 s = S7194(); + assert(!s.p); + assert(s.p == null); + assert(s.p == s.p2); + int x; + s.p = &x; + s.p2 = s.p; + assert(s.p == &x); + return 0; +} + +int g7194() +{ + auto s = S7194(); + assert(s.p); // should fail + return 0; +} + +static assert(f7194() == 0); +static assert(!is(typeof(compiles!(g7194())))); + +/************************************************** + 7248 recursive struct pointers in array +**************************************************/ + +struct S7248 { S7248* ptr; } + +bool bug7248() +{ + S7248[2] sarr; + sarr[0].ptr = &sarr[1]; + sarr[0].ptr = null; + S7248* t = sarr[0].ptr; + return true; +} +static assert(bug7248()); + +/************************************************** + 7216 calling a struct pointer member +**************************************************/ + +struct S7216 +{ + S7216* p; + int t; + + void f() { } + void g() { ++t; } +} + +bool bug7216() +{ + S7216 s0, s1; + s1.t = 6; + s0.p = &s1; + s0.p.f(); + s0.p.g(); + assert(s1.t == 7); + return true; +} + +static assert(bug7216()); + +/************************************************** + 10858 Wrong code with array of pointers +**************************************************/ + +bool bug10858() +{ + int*[4] x; + x[0] = null; + assert(x[0] == null); + return true; +} +static assert(bug10858()); + +/************************************************** + 12528 - painting inout type for value type literals +**************************************************/ + +inout(T)[] dup12528(T)(inout(T)[] a) +{ + inout(T)[] res; + foreach (ref e; a) + res ~= e; + return res; +} + +enum arr12528V1 = dup12528([0]); +enum arr12528V2 = dup12528([0, 1]); +static assert(arr12528V1 == [0]); +static assert(arr12528V2 == [0, 1]); + +/************************************************** + 9745 Allow pointers to static variables +**************************************************/ + +shared int x9745; +shared int[5] y9745; + +shared(int)* bug9745(int m) +{ + auto k = &x9745; + auto j = &x9745; + auto p = &y9745[0]; + auto q = &y9745[3]; + assert(j - k == 0); + assert(j == k); + assert(q - p == 3); + --q; + int a = 0; + assert(p + 2 == q); + if (m == 7) + { + auto z1 = y9745[0 .. 2]; // slice global pointer + } + if (m == 8) + p[1] = 7; // modify through a pointer + if (m == 9) + a = p[1]; // read from a pointer + if (m == 0) + return &x9745; + return &y9745[1]; +} + +int test9745(int m) +{ + bug9745(m); + // type painting + shared int* w = bug9745(0); + return 1; +} + +shared int* w9745a = bug9745(0); +shared int* w9745b = bug9745(1); +static assert( is(typeof(compiles!(test9745(6))))); +static assert(!is(typeof(compiles!(test9745(7))))); +static assert(!is(typeof(compiles!(test9745(8))))); +static assert(!is(typeof(compiles!(test9745(9))))); + +// pointers cast from an absolute address +// (mostly applies to fake pointers, eg Windows HANDLES) +bool test9745b() +{ + void* b6 = cast(void*)0xFEFEFEFE; + void* b7 = cast(void*)0xFEFEFEFF; + assert(b6 is b6); + assert(b7 != b6); + return true; +} +static assert(test9745b()); + +/************************************************** + 9364 ICE with pointer to local struct +**************************************************/ + +struct S9364 +{ + int i; +} + +bool bug9364() +{ + S9364 s; + auto k = (&s).i; + return 1; +} + +static assert(bug9364()); + +/************************************************** + 10251 Pointers to const globals +**************************************************/ + +static const int glob10251 = 7; + +const(int)* bug10251() +{ + return &glob10251; +} + +static a10251 = &glob10251; // OK +static b10251 = bug10251(); + +/************************************************** + 4065 [CTFE] AA "in" operator doesn't work +**************************************************/ + +bool bug4065(string s) +{ + enum int[string] aa = ["aa":14, "bb":2]; + int* p = s in aa; + if (s == "aa") + assert(*p == 14); + else if (s == "bb") + assert(*p == 2); + else + assert(!p); + int[string] zz; + assert(!("xx" in zz)); + bool c = !p; + return cast(bool)(s in aa); +} + +static assert(!bug4065("xx")); +static assert( bug4065("aa")); +static assert( bug4065("bb")); + +/************************************************** + 12689 - assigning via pointer from 'in' expression +**************************************************/ + +int g12689() +{ + int[int] aa; + aa[1] = 13; + assert(*(1 in aa) == 13); + *(1 in aa) = 42; + return aa[1]; +} +static assert(g12689() == 42); + +/************************************************** + Pointers in ? : +**************************************************/ + +static assert({ + int[2] x; + int* p = &x[1]; + return p ? true: false; +}()); + +/************************************************** + Pointer slicing +**************************************************/ + +int ptrSlice() +{ + auto arr = new int[5]; + int* x = &arr[0]; + int[] y = x[0 .. 5]; + x[1 .. 3] = 6; + ++x; + x[1 .. 3] = 14; + assert(arr[1] == 6); + assert(arr[2] == 14); + //x[-1 .. 4] = 5; // problematic because negative lower boundary will throw RangeError in runtime + (x - 1)[0 .. 3] = 5; + int[] z = arr[1 .. 2]; + z.length = 4; + z[$ - 1] = 17; + assert(arr.length == 5); + return 2; +} +static assert(ptrSlice() == 2); + +/************************************************** + 6344 - create empty slice from null pointer +**************************************************/ + +static assert({ + char* c = null; + auto m = c[0 .. 0]; + return true; +}()); + +/************************************************** + 8365 - block assignment of enum arrays +**************************************************/ + +enum E8365 { first = 7, second, third, fourth } +static assert({ E8365[2] x; return x[0]; }() == E8365.first); +static assert({ E8365[2][2] x; return x[0][0]; }() == E8365.first); +static assert({ E8365[2][2][2] x; return x[0][0][0]; }() == E8365.first); + +/************************************************** + 4448 - labelled break + continue +**************************************************/ + +int bug4448() +{ + int n = 2; +L1: + do + { + switch(n) + { + case 5: + return 7; + default: + n = 5; + break L1; + } + int w = 7; + } while (0); + return 3; +} +static assert(bug4448() == 3); + +int bug4448b() +{ + int n = 2; +L1: + for (n = 2; n < 5; ++n) + { + for (int m = 1; m < 6; ++m) + { + if (n < 3) + { + assert(m == 1); + continue L1; + } + } + break; + } + return 3; +} +static assert(bug4448b() == 3); + +/************************************************** + 6985 - non-constant case +**************************************************/ + +int bug6985(int z) +{ + int q = z * 2 - 6; + switch(z) + { + case q: + q = 87; + break; + default: + } + return q; +} +static assert(bug6985(6) == 87); + +/************************************************** + 6281 - [CTFE] A null pointer '!is null' returns 'true' +**************************************************/ + +static assert(!{ + auto p = null; + return p !is null; +}()); + +static assert(!{ + auto p = null; + return p != null; +}()); + +/************************************************** + 6331 - evaluate SliceExp on if condition +**************************************************/ + +bool bug6331(string s) +{ + if (s[0 .. 1]) + return true; + return false; +} +static assert(bug6331("str")); + +/************************************************** + 6283 - assign to AA with slice as index +**************************************************/ + +static assert({ + immutable p = "pp"; + int[string] pieces = [p: 0]; + pieces["qq"] = 1; + return true; +}()); + +static assert({ + immutable renames = [0: "pp"]; + int[string] pieces; + pieces[true ? renames[0] : "qq"] = 1; + pieces["anything"] = 1; + return true; +}()); + +static assert({ + immutable qq = "qq"; + string q = qq; + int[string] pieces = ["a":1]; + pieces[q] = 0; + string w = "ab"; + int z = pieces[w[0 .. 1]]; + assert(z == 1); + return true; +}()); + +/************************************************** + 6282 - dereference 'in' of an AA +**************************************************/ + +static assert({ + int[] w = new int[4]; + w[2] = 6; + auto c = [5: w]; + auto kk = (*(5 in c))[2]; + (*(5 in c))[2] = 8; + (*(5 in c))[1 .. $ - 2] = 4; + auto a = [4:"1"]; + auto n = *(4 in a); + return n; +}() == "1"); + +/************************************************** + 6337 - member function call on struct literal +**************************************************/ + +struct Bug6337 +{ + int k; + void six() + { + k = 6; + } + int ctfe() + { + six(); + return k; + } +} +static assert(Bug6337().ctfe() == 6); + +/************************************************** + 6603 call manifest function pointer +**************************************************/ + +int f6603(int a) { return a + 5; } +enum bug6603 = &f6603; +static assert(bug6603(6) == 11); + +/************************************************** + 6375 +**************************************************/ + +struct D6375 +{ + int[] arr; +} +A6375 a6375(int[] array) +{ + return A6375(array); +} +struct A6375 +{ + D6375* _data; + this(int[] arr) + { + _data = new D6375; + _data.arr = arr; + } + int[] data() + { + return _data.arr; + } +} +static assert({ + int[] a = [1, 2]; + auto app2 = a6375(a); + auto data = app2.data(); + return true; +}()); + +/************************************************** + 6280 Converting pointers to bool +**************************************************/ + +static assert({ + if ((0 in [0:0])) {} + if ((0 in [0:0]) && (0 in [0:0])) {} + return true; +}()); + +/************************************************** + 6276 ~= +**************************************************/ + +struct Bug6276 +{ + int[] i; +} +static assert({ + Bug6276 foo; + foo.i ~= 1; + foo.i ~= 2; + return true; +}()); + +/************************************************** + 6374 ptr[n] = x, x = ptr[n] +**************************************************/ + +static assert({ + int[] arr = [1]; + arr.ptr[0] = 2; + auto k = arr.ptr[0]; + assert(k == 2); + return arr[0]; +}() == 2); + +/************************************************** + 6306 recursion and local variables +**************************************************/ + +void recurse6306() +{ + bug6306(false); +} + +bool bug6306(bool b) +{ + int x = 0; + if (b) + recurse6306(); + assert(x == 0); + x = 1; + return true; +} +static assert(bug6306(true)); + +/************************************************** + 6386 ICE on unsafe pointer cast +**************************************************/ + +static assert(!is(typeof(compiles!({ + int x = 123; + int* p = &x; + float z; + float* q = cast(float*)p; + return true; +}() +)))); + +static assert({ + int[] x = [123, 456]; + int* p = &x[0]; + auto m = cast(const(int)*)p; + auto q = p; + return *q; +}()); + +/************************************************** + 6420 ICE on dereference of invalid pointer +**************************************************/ + +static assert({ + // Should compile, but pointer can't be dereferenced + int x = 123; + int* p = cast(int*)x; + auto q = cast(char*)x; + auto r = cast(char*)323; + // Valid const-changing cast + const float *m = cast(immutable float*)[1.2f,2.4f,3f]; + return true; +}() +); + +static assert(!is(typeof(compiles!({ + int x = 123; + int* p = cast(int*)x; + int a = *p; + return true; +}() +)))); + +static assert(!is(typeof(compiles!({ + int* p = cast(int*)123; + int a = *p; + return true; +}() +)))); + +static assert(!is(typeof(compiles!({ + auto k = cast(int*)45; + *k = 1; + return true; +}() +)))); + +static assert(!is(typeof(compiles!({ + *cast(float*)"a" = 4.0; + return true; +}() +)))); + +static assert(!is(typeof(compiles!({ + float f = 2.8; + long *p = &f; + return true; +}() +)))); + +static assert(!is(typeof(compiles!({ + long *p = cast(long*)[1.2f, 2.4f, 3f]; + return true; +}() +)))); + +/************************************************** + 6250 deref pointers to array +**************************************************/ + +int[]* simple6250(int[]* x) { return x; } + +void swap6250(int[]* lhs, int[]* rhs) +{ + int[] kk = *lhs; + assert(simple6250(lhs) == lhs); + lhs = simple6250(lhs); + assert(kk[0] == 18); + assert((*lhs)[0] == 18); + assert((*rhs)[0] == 19); + *lhs = *rhs; + assert((*lhs)[0] == 19); + *rhs = kk; + assert(*rhs == kk); + assert(kk[0] == 18); + assert((*rhs)[0] == 18); +} + +int ctfeSort6250() +{ + int[][2] x; + int[3] a = [17, 18, 19]; + x[0] = a[1 .. 2]; + x[1] = a[2 .. $]; + assert(x[0][0] == 18); + assert(x[0][1] == 19); + swap6250(&x[0], &x[1]); + assert(x[0][0] == 19); + assert(x[1][0] == 18); + a[1] = 57; + assert(x[0][0] == 19); + return x[1][0]; +} + +static assert(ctfeSort6250() == 57); + +/************************************************** + 6672 circular references in array +**************************************************/ + +void bug6672(ref string lhs, ref string rhs) +{ + auto tmp = lhs; + lhs = rhs; + rhs = tmp; +} + +static assert({ + auto kw = ["a"]; + bug6672(kw[0], kw[0]); + return true; +}()); + +void slice6672(ref string[2] agg, ref string lhs) +{ + agg[0 .. $] = lhs; +} + +static assert({ + string[2] kw = ["a", "b"]; + slice6672(kw, kw[0]); + assert(kw[0] == "a"); + assert(kw[1] == "a"); + return true; +}()); + +// an unrelated rejects-valid bug +static assert({ + string[2] kw = ["a", "b"]; + kw[0 .. 2] = "x"; + return true; +}()); + +void bug6672b(ref string lhs, ref string rhs) +{ + auto tmp = lhs; + assert(tmp == "a"); + lhs = rhs; + assert(tmp == "a"); + rhs = tmp; +} + +static assert({ + auto kw=["a", "b"]; + bug6672b(kw[0], kw[1]); + assert(kw[0] == "b"); + assert(kw[1] == "a"); + return true; +}()); + +/************************************************** + 6399 (*p).length = n +**************************************************/ + +struct A6399 +{ + int[] arr; + int subLen() + { + arr = [1, 2, 3, 4, 5]; + arr.length -= 1; + return cast(int)arr.length; + } +} + +static assert({ + A6399 a; + return a.subLen(); +}() == 4); + +/************************************************** + 7789 (*p).length++ where *p is null +**************************************************/ + +struct S7789 +{ + size_t foo() + { + _ary.length += 1; + return _ary.length; + } + + int[] _ary; +} + +static assert(S7789().foo()); + +/************************************************** + 6418 member named 'length' +**************************************************/ + +struct Bug6418 +{ + size_t length() { return 189; } +} +static assert(Bug6418.init.length == 189); + +/************************************************** + 4021 rehash +**************************************************/ + +bool bug4021() +{ + int[int] aa = [1: 1]; + aa.rehash; + return true; +} +static assert(bug4021()); + +/************************************************** + 11629 crash on AA.rehash +**************************************************/ + +struct Base11629 +{ + alias T = ubyte, Char = char; + alias String = immutable(Char)[]; + + const Char[T] toChar; + + this(int _dummy) + { + Char[T] toCharTmp = [0:'A']; + + toChar = toCharTmp.rehash; + } +} +enum ct11629 = Base11629(4); + +/************************************************** + 3512 foreach (dchar; string) + 6558 foreach (int, dchar; string) +**************************************************/ + +bool test3512() +{ + string s = "öhai"; + int q = 0; + + foreach (wchar c; s) + { + if (q == 2) + assert(c == 'a'); + ++q; + } + assert(q == 4); + + // _aApplycd1 + foreach (dchar c; s) + { + ++q; + if (c == 'h') + break; + } + assert(q == 6); + + // _aApplycw2 + foreach (int i, wchar c; s) + { + assert(i >= 0 && i < s.length); + } + + // _aApplycd2 + foreach (int i, dchar c; s) + { + assert(i >= 0 && i < s.length); + } + + wstring w = "xüm"; + + // _aApplywc1 + foreach (char c; w) + { + ++q; + } + assert(q == 10); + + // _aApplywd1 + foreach (dchar c; w) + { + ++q; + } + assert(q == 13); + + // _aApplywc2 + foreach (int i, char c; w) + { + assert(i >= 0 && i < w.length); + } + + // _aApplywd2 + foreach (int i, dchar c; w) + { + assert(i >= 0 && i < w.length); + } + + dstring d = "yäq"; + + // _aApplydc1 + q = 0; + foreach (char c; d) + { + ++q; + } + assert(q == 4); + + // _aApplydw1 + q = 0; + foreach (wchar c; d) + { + ++q; + } + assert(q == 3); + + // _aApplydc2 + foreach (int i, char c; d) + { + assert(i >= 0 && i < d.length); + } + // _aApplydw2 + foreach (int i, wchar c; d) + { + assert(i >= 0 && i < d.length); + } + + dchar[] dr = "squop"d.dup; + + foreach (int n, char c; dr) + { + if (n == 2) + break; + assert(c != 'o'); + } + + // _aApplyRdc1 + foreach_reverse (char c; dr) + {} + + // _aApplyRdw1 + foreach_reverse (wchar c; dr) + {} + + // _aApplyRdc2 + foreach_reverse (int n, char c; dr) + { + if (n == 4) + break; + assert(c != 'o'); + } + + // _aApplyRdw2 + foreach_reverse (int i, wchar c; dr) + { + assert(i >= 0 && i < dr.length); + } + + q = 0; + wstring w2 = ['x', 'ü', 'm']; // foreach over array literals + foreach_reverse (int n, char c; w2) + { + ++q; + if (c == 'm') assert(n == 2 && q == 1); + if (c == 'x') assert(n == 0 && q == 4); + } + return true; +} +static assert(test3512()); + +/************************************************** + 6510 ICE only with -inline +**************************************************/ + +struct Stack6510 +{ + struct Proxy + { + void shrink() {} + } + Proxy stack; + void pop() + { + stack.shrink(); + } +} + +int bug6510() +{ + static int used() + { + Stack6510 junk; + junk.pop(); + return 3; + } + return used(); +} + +void test6510() +{ + static assert(bug6510() == 3); +} + +/************************************************** + 6511 arr[] shouldn't make a copy +**************************************************/ + +T bug6511(T)() +{ + T[1] a = [1]; + a[] += a[]; + return a[0]; +} +static assert(bug6511!ulong() == 2); +static assert(bug6511!long() == 2); + +/************************************************** + 6512 new T[][] +**************************************************/ + +bool bug6512(int m) +{ + auto x = new int[2][][](m, 5); + assert(x.length == m); + assert(x[0].length == 5); + assert(x[0][0].length == 2); + foreach (i; 0.. m) + foreach (j; 0 .. 5) + foreach (k; 0 .. 2) + x[i][j][k] = k + j*10 + i*100; + foreach (i; 0.. m) + foreach (j; 0 .. 5) + foreach (k; 0 .. 2) + assert(x[i][j][k] == k + j*10 + i*100); + return true; +} +static assert(bug6512(3)); + +/************************************************** + 6516 ICE(constfold.c) +**************************************************/ + +dstring bug6516() +{ + return cast(dstring)new dchar[](0); +} + +static assert(bug6516() == ""d); + +/************************************************** + 6727 ICE(interpret.c) +**************************************************/ + +const(char)* ice6727(const(char)* z) { return z; } +static assert({ + auto q = ice6727("a".dup.ptr); + return true; +}()); + +/************************************************** + 6721 Cannot get pointer to start of char[] +**************************************************/ + +static assert({ + char[] c1 = "".dup; + auto p = c1.ptr; + string c2 = ""; + auto p2 = c2.ptr; + return 6; +}() == 6); + +/************************************************** + 6693 Assign to null AA +**************************************************/ + +struct S6693 +{ + int[int] m; +} + +static assert({ + int[int][int] aaa; + aaa[3][1] = 4; + int[int][3] aab; + aab[2][1] = 4; + S6693 s; + s.m[2] = 4; + return 6693; +}() == 6693); + +/************************************************** + 7602 Segfault AA.keys on null AA +**************************************************/ + +string[] test7602() +{ + int[string] array; + return array.keys; +} + +enum bug7602 = test7602(); + +/************************************************** + 6739 Nested AA assignment +**************************************************/ + +static assert({ + int[int][int][int] aaa; + aaa[3][1][6] = 14; + return aaa[3][1][6]; +}() == 14); + +static assert({ + int[int][int] aaa; + aaa[3][1] = 4; + aaa[3][3] = 3; + aaa[1][5] = 9; + auto kk = aaa[1][5]; + return kk; +}() == 9); + +/************************************************** + 6751 ref AA assignment +**************************************************/ + +void bug6751(ref int[int] aa) +{ + aa[1] = 2; +} + +static assert({ + int[int] aa; + bug6751(aa); + assert(aa[1] == 2); + return true; +}()); + +void bug6751b(ref int[int][int] aa) +{ + aa[1][17] = 2; +} + +struct S6751 +{ + int[int][int] aa; + int[int] bb; +} + +static assert({ + S6751 s; + bug6751b(s.aa); + assert(s.aa[1][17] == 2); + return true; +}()); + +static assert({ + S6751 s; + s.aa[7][56] = 57; + bug6751b(s.aa); + assert(s.aa[1][17] == 2); + assert(s.aa[7][56] == 57); + bug6751c(s.aa); + assert(s.aa.keys.length == 1); + assert(s.aa.values.length == 1); + return true; +}()); + +static assert({ + S6751 s; + s.bb[19] = 97; + bug6751(s.bb); + assert(s.bb[1] == 2); + assert(s.bb[19] == 97); + return true; +}()); + +void bug6751c(ref int[int][int] aa) +{ + aa = [38: [56 : 77]]; +} + +/************************************************** + 7790 AA foreach ref +**************************************************/ + +struct S7790 +{ + size_t id; +} + +size_t bug7790(S7790[string] tree) +{ + foreach (k, ref v; tree) + v.id = 1; + return tree["a"].id; +} + +static assert(bug7790(["a":S7790(0)]) == 1); + +/************************************************** + 6765 null AA.length +**************************************************/ + +static assert({ + int[int] w; + return w.length; +}() == 0); + +/************************************************** + 6769 AA.keys, AA.values with -inline +**************************************************/ + +static assert({ + double[char[3]] w = ["abc" : 2.3]; + double[] z = w.values; + return w.keys.length; +}() == 1); + +/************************************************** + 4022 AA.get +**************************************************/ + +static assert({ + int[int] aa = [58: 13]; + int r = aa.get(58, 1000); + assert(r == 13); + r = aa.get(59, 1000); + return r; +}() == 1000); + +/************************************************** + 6775 AA.opApply +**************************************************/ + +static assert({ + int[int] aa = [58: 17, 45:6]; + int valsum = 0; + int keysum = 0; + foreach (m; aa) // aaApply + { + valsum += m; + } + assert(valsum == 17 + 6); + valsum = 0; + foreach (n, m; aa) // aaApply2 + { + valsum += m; + keysum += n; + } + assert(valsum == 17 + 6); + assert(keysum == 58 + 45); + // Check empty AA + valsum = 0; + int[int] bb; + foreach (m; bb) + { + ++valsum; + } + assert(valsum == 0); + return true; +}()); + +/************************************************** + 7890 segfault struct with AA field +**************************************************/ + +struct S7890 +{ + int[int] tab; +} + +S7890 bug7890() +{ + S7890 foo; + foo.tab[0] = 0; + return foo; +} + +enum e7890 = bug7890(); + +/************************************************** + AA.remove +**************************************************/ + +static assert({ + int[int] aa = [58: 17, 45:6]; + aa.remove(45); + assert(aa.length == 1); + aa.remove(7); + assert(aa.length == 1); + aa.remove(58); + assert(aa.length == 0); + return true; +}()); + +/************************************************** + try, finally +**************************************************/ + +static assert({ + int n = 0; + + try + { + n = 1; + } + catch (Exception e) + {} + assert(n == 1); + + try + { + n = 2; + } + catch (Exception e) + {} + finally + { + assert(n == 2); + n = 3; + } + assert(n == 3); + return true; +}()); + +/************************************************** + 6800 bad pointer casts +**************************************************/ + +bool badpointer(int k) +{ + int m = 6; + int* w = &m; + assert(*w == 6); + int[3] a = [17, 2, 21]; + int* w2 = &a[2]; + assert(*w2 == 21); + + // cast int* to uint* is OK + uint* u1 = cast(uint*)w; + assert(*u1 == 6); + uint* u2 = cast(uint*)w2; + assert(*u2 == 21); + uint* u3 = cast(uint*)&m; + assert(*u3 == 6); + // cast int* to void* is OK + void* v1 = cast(void*)w; + void* v3 = &m; + void* v4 = &a[0]; + // cast from void* back to int* is OK + int* t3 = cast(int*)v3; + assert(*t3 == 6); + int* t4 = cast(int*)v4; + assert(*t4 == 17); + // cast from void* to uint* is OK + uint* t1 = cast(uint*)v1; + assert(*t1 == 6); + // and check that they're real pointers + m = 18; + assert(*t1 == 18); + assert(*u3 == 18); + + int** p = &w; + + if (k == 1) // bad reinterpret + double *d1 = cast(double*)w; + if (k == 3) // bad reinterpret + char* d3 = cast(char*)w2; + if (k == 4) { + void* q1 = cast(void*)p; // OK-void is int* + void* *q = cast(void**)p; // OK-void is int + } + if (k == 5) + void*** q = cast(void***)p; // bad: too many * + if (k == 6) // bad reinterpret through void* + double* d1 = cast(double*)v1; + if (k == 7) + double* d7 = cast(double*)v4; + if (k == 8) + ++v4; // can't do pointer arithmetic on void* + return true; +} +static assert(badpointer(4)); +static assert(!is(typeof(compiles!(badpointer(1))))); +static assert( is(typeof(compiles!(badpointer(2))))); +static assert(!is(typeof(compiles!(badpointer(3))))); +static assert( is(typeof(compiles!(badpointer(4))))); +static assert(!is(typeof(compiles!(badpointer(5))))); +static assert(!is(typeof(compiles!(badpointer(6))))); +static assert(!is(typeof(compiles!(badpointer(7))))); +static assert(!is(typeof(compiles!(badpointer(8))))); + +/************************************************** + 10211 Allow casts S**->D**, when S*->D* is OK +**************************************************/ + +int bug10211() +{ + int m = 7; + int* x = &m; + int** y = &x; + assert(**y == 7); + uint* p = cast(uint*)x; + uint** q = cast(uint**)y; + return 1; +} + +static assert(bug10211()); + +/************************************************** + 10568 CTFE rejects function pointer safety casts +**************************************************/ + +@safe void safetyDance() {} + +int isItSafeToDance() +{ + void function() @trusted yourfriends = &safetyDance; + void function() @safe nofriendsOfMine = yourfriends; + return 1; +} + +static assert(isItSafeToDance()); + +/************************************************** + 12296 CTFE rejects const compatible AA pointer cast +**************************************************/ + +int test12296() +{ + immutable x = [5 : 4]; + auto aa = &x; + const(int[int])* y = aa; + return 1; +} +static assert(test12296()); + +/************************************************** + 9170 Allow reinterpret casts float<->int +**************************************************/ + +int f9170(float x) +{ + return *(cast(int*)&x); +} + +float i9170(int x) +{ + return *(cast(float*)&x); +} + +float u9170(uint x) +{ + return *(cast(float*)&x); +} + +int f9170arr(float[] x) +{ + return *(cast(int*)&(x[1])); +} + +long d9170(double x) +{ + return *(cast(long*)&x); +} + +int fref9170(ref float x) +{ + return *(cast(int*)&x); +} + +long dref9170(ref double x) +{ + return *(cast(long*)&x); +} + +bool bug9170() +{ + float f = 1.25; + double d = 1.25; + assert(f9170(f) == 0x3FA0_0000); + assert(fref9170(f) == 0x3FA0_0000); + assert(d9170(d) == 0x3FF4_0000_0000_0000L); + assert(dref9170(d) == 0x3FF4_0000_0000_0000L); + float [3] farr = [0, 1.25, 0]; + assert(f9170arr(farr) == 0x3FA0_0000); + int i = 0x3FA0_0000; + assert(i9170(i) == 1.25); + uint u = 0x3FA0_0000; + assert(u9170(u) == 1.25); + return true; +} + +static assert(bug9170()); + +/************************************************** + 6792 ICE with pointer cast of indexed array +**************************************************/ + +struct S6792 +{ + int i; +} + +static assert({ + { + void* p; + p = [S6792(1)].ptr; + S6792 s = *(cast(S6792*)p); + assert(s.i == 1); + } + { + void*[] ary; + ary ~= [S6792(2)].ptr; + S6792 s = *(cast(S6792*)ary[0]); + assert(s.i == 2); + } + { + void*[7] ary; + ary[6]= [S6792(2)].ptr; + S6792 s = *(cast(S6792*)ary[6]); + assert(s.i == 2); + } + { + void* p; + p = [S6792(1)].ptr; + void*[7] ary; + ary[5]= p; + S6792 s = *(cast(S6792*)ary[5]); + assert(s.i == 1); + } + { + S6792*[string] aa; + aa["key"] = [S6792(3)].ptr; + const(S6792) s = *(cast(const(S6792)*)aa["key"]); + assert(s.i == 3); + } + { + S6792[string] blah; + blah["abc"] = S6792(6); + S6792*[string] aa; + aa["kuy"] = &blah["abc"]; + const(S6792) s = *(cast(const(S6792)*)aa["kuy"]); + assert(s.i == 6); + + void*[7] ary; + ary[5]= &blah["abc"]; + S6792 t = *(cast(S6792*)ary[5]); + assert(t.i == 6); + + int q = 6; + ary[3]= &q; + int gg = *(cast(int*)(ary[3])); + } + return true; +}()); + +/************************************************** + 7780 array cast +**************************************************/ + +int bug7780(int testnum) +{ + int[] y = new int[2]; + y[0] = 2000000; + if (testnum == 1) + { + void[] x = y; + return (cast(byte[])x)[1]; + } + if (testnum == 2) + { + int[] x = y[0 .. 1]; + return (cast(byte[])x)[1]; + } + return 1; +} + +static assert( is(typeof(compiles!(bug7780(0))))); +static assert(!is(typeof(compiles!(bug7780(1))))); +static assert(!is(typeof(compiles!(bug7780(2))))); + +/************************************************** + 14028 - static array pointer that refers existing array elements. +**************************************************/ + +int test14028a(size_t ofs)(bool ct) +{ + int[4] a; + int[2]* p; + int num = ofs; + + if (ct) + p = cast(int[2]*)&a[ofs]; // SymOffExp + else + p = cast(int[2]*)&a[num]; // CastExp + AddrExp + + // pointers comparison + assert(cast(void*)a.ptr <= cast(void*)p); + assert(cast(void*)a.ptr <= cast(void*)&(*p)[0]); + assert(cast(void*)&a[0] <= cast(void*)p); + + return 1; +} +static assert(test14028a!0(true)); +static assert(test14028a!0(false)); +static assert(test14028a!3(true)); +static assert(test14028a!3(false)); +static assert(!is(typeof(compiles!(test14028a!4(true))))); +static assert(!is(typeof(compiles!(test14028a!4(false))))); + +int test14028b(int num) +{ + int[4] a; + int[2]* p; + + if (num == 1) + { + p = cast(int[2]*)&a[0]; // &a[0..2]; + (*p)[0] = 1; // a[0] = 1 + (*p)[1] = 2; // a[1] = 2 + assert(a == [1,2,0,0]); + p = p + 1; // &a[0] -> &a[2] + (*p)[0] = 3; // a[2] = 3 + (*p)[1] = 4; // a[3] = 4 + assert(a == [1,2,3,4]); + } + if (num == 2) + { + p = cast(int[2]*)&a[1]; // &a[1..3]; + (*p)[0] = 1; // a[1] = 1 + p = p + 1; // &a[1..3] -> &a[3..5] + (*p)[0] = 2; // a[3] = 2 + assert(a == [0,1,0,2]); + } + if (num == 3) + { + p = cast(int[2]*)&a[1]; // &a[1..3]; + (*p)[0] = 1; // a[1] = 1 + p = p + 1; // &a[1..3] -> &a[3..5] + (*p)[0] = 2; // a[3] = 2 + (*p)[1] = 3; // a[4] = 3 (CTFE error) + } + if (num == 4) + { + p = cast(int[2]*)&a[0]; // &a[0..2]; + p = p + 1; // &a[0..2] -> &a[2..4] + p = p + 1; // &a[2..4] -> &a[4..6] (ok) + } + if (num == 5) + { + p = cast(int[2]*)&a[1]; // &a[1..3]; + p = p + 2; // &a[1..3] -> &a[5..7] (CTFE error) + } + return 1; +} +static assert(test14028b(1)); +static assert(test14028b(2)); +static assert(!is(typeof(compiles!(test14028b(3))))); +static assert(test14028b(4)); +static assert(!is(typeof(compiles!(test14028b(5))))); + +/************************************************** + 10275 cast struct literals to immutable +**************************************************/ + +struct Bug10275 +{ + uint[] ivals; +} + +Bug10275 bug10275() +{ + return Bug10275([1, 2, 3]); +} + +int test10275() +{ + immutable(Bug10275) xxx = cast(immutable(Bug10275))bug10275(); + return 1; +} + +static assert(test10275()); + +/************************************************** + 6851 passing pointer by argument +**************************************************/ + +void set6851(int* pn) +{ + *pn = 20; +} +void bug6851() +{ + int n = 0; + auto pn = &n; + *pn = 10; + assert(n == 10); + set6851(&n); +} +static assert({ bug6851(); return true; }()); + +/************************************************** + 7876 +**************************************************/ + +int* bug7876(int n) @system +{ + int x; + auto ptr = &x; + if (n == 2) + ptr = null; + return ptr; +} + +struct S7876 +{ + int* p; +} + +S7876 bug7876b(int n) @system +{ + int x; + S7876 s; + s.p = &x; + if (n == 11) + s.p = null; + return s; +} + +int test7876(int n) +{ + if (n >= 10) + { + S7876 m = bug7876b(n); + return 1; + } + int* p = bug7876(n); + return 1; +} + +static assert( is(typeof(compiles!(test7876(2))))); +static assert(!is(typeof(compiles!(test7876(0))))); +static assert( is(typeof(compiles!(test7876(11))))); +static assert(!is(typeof(compiles!(test7876(10))))); + +/************************************************** + 11824 +**************************************************/ + +int f11824(T)() +{ + T[] arr = new T[](1); + T* getAddr(ref T a) + { + return &a; + } + getAddr(arr[0]); + return 1; +} +static assert(f11824!int()); // OK +static assert(f11824!(int[])()); // OK <- NG + +/************************************************** + 6817 if converted to &&, only with -inline +**************************************************/ + +static assert({ + void toggle() + { + bool b; + if (b) + b = false; + } + toggle(); + return true; +}()); + +/************************************************** + cast to void +**************************************************/ + +static assert({ + cast(void)(71); + return true; +}()); + +/************************************************** + 6816 nested function can't access this +**************************************************/ + +struct S6816 +{ + size_t foo() + { + return (){ return value +1 ; }(); + } + size_t value; +} + +enum s6816 = S6816().foo(); + +/************************************************** + 7277 ICE nestedstruct.init.tupleof +**************************************************/ + +struct Foo7277 +{ + int a; + int func() + { + int b; + void nested() + { + b = 7; + a = 10; + } + nested(); + return a+b; + } +} + +static assert(Foo7277().func() == 17); + +/************************************************** + 10217 ICE. CTFE version of 9315 +**************************************************/ + +bool bug10217() +{ + struct S + { + int i; + void bar() {} + } + auto yyy = S.init.tupleof[$ - 1]; + assert(!yyy); + return 1; +} + +static assert(bug10217()); + +/************************************************** + 8276 ICE +**************************************************/ + +void bug8676(int n) +{ + const int X1 = 4 + n; + const int X2 = 4; + int X3 = 4; + int bar1() { return X1; } + int bar2() { return X2; } + int bar3() { return X3; } + static assert(!is(typeof(compiles!(bar1())))); + static assert( is(typeof(compiles!(bar2())))); + static assert(!is(typeof(compiles!(bar3())))); +} + +/************************************************** + classes and interfaces +**************************************************/ + +interface SomeInterface +{ + int daz(); + float bar(char); + int baz(); +} + +interface SomeOtherInterface +{ + int xxx(); +} + +class TheBase : SomeInterface, SomeOtherInterface +{ + int q = 88; + int rad = 61; + int a = 14; + int somebaseclassfunc() { return 28; } + int daz() { return 0; } + int baz() { return 0; } + int xxx() { return 762; } + int foo() { return q; } + float bar(char c) { return 3.6; } +} + +class SomeClass : TheBase, SomeInterface +{ + int gab = 9; + int fab; + int a = 17; + int b = 23; + override int foo() { return gab + a; } + override float bar(char c) { return 2.6; } + int something() { return 0; } + override int daz() { return 0; } + override int baz() { return 0; } +} + +class Unrelated : TheBase +{ + this(int x) { a = x; } +} + +auto classtest1(int n) +{ + SomeClass c = new SomeClass; + assert(c.a == 17); + assert(c.q == 88); + TheBase d = c; + assert(d.a == 14); + assert(d.q == 88); + if (n == 7) + { + // bad cast -- should fail + Unrelated u = cast(Unrelated)d; + assert(u is null); + } + SomeClass e = cast(SomeClass)d; + d.q = 35; + assert(c.q == 35); + assert(c.foo() == 9 + 17); + ++c.a; + assert(c.foo() == 9 + 18); + assert(d.foo() == 9 + 18); + d = new TheBase; + SomeInterface fc = c; + SomeOtherInterface ot = c; + assert(fc.bar('x') == 2.6); + assert(ot.xxx() == 762); + fc = d; + ot = d; + assert(fc.bar('x') == 3.6); + assert(ot.xxx() == 762); + + Unrelated u2 = new Unrelated(7); + assert(u2.a == 7); + return 6; +} +static assert(classtest1(1)); +static assert(classtest1(2)); +static assert(classtest1(7)); // bug 7154 + +// can't initialize enum with not null class +SomeClass classtest2(int n) +{ + return n == 5 ? (new SomeClass) : null; +} +static assert( is(typeof((){ enum const(SomeClass) xx = classtest2(2);}()))); +static assert(!is(typeof((){ enum const(SomeClass) xx = classtest2(5);}()))); + +class RecursiveClass +{ + int x; + this(int n) { x = n; } + RecursiveClass b; + void doit() { b = new RecursiveClass(7); b.x = 2;} +} + +int classtest3() +{ + RecursiveClass x = new RecursiveClass(17); + x.doit(); + RecursiveClass y = x.b; + assert(y.x == 2); + assert(x.x == 17); + return 1; +} + +static assert(classtest3()); + +/************************************************** + 12016 class cast and qualifier reinterpret +**************************************************/ + +class B12016 { } + +class C12016 : B12016 { } + +bool f12016(immutable B12016 b) +{ + assert(b); + return true; +} + +static assert(f12016(new immutable C12016)); + +/************************************************** + 10610 ice immutable implicit conversion +**************************************************/ + +class Bug10610(T) +{ + int baz() immutable + { + return 1; + } + static immutable(Bug10610!T) min = new Bug10610!T(); +} + +void ice10610() +{ + alias T10610 = Bug10610!(int); + static assert (T10610.min.baz()); +} + +/************************************************** + 13141 regression fix caused by 10610 +**************************************************/ + +struct MapResult13141(alias pred) +{ + int[] range; + @property empty() { return range.length == 0; } + @property front() { return pred(range[0]); } + void popFront() { range = range[1 .. $]; } +} + +string[] array13141(R)(R r) +{ + typeof(return) result; + foreach (e; r) + result ~= e; + return result; +} + +//immutable string[] splitterNames = [4].map!(e => "4").array(); +immutable string[] splitterNames13141 = MapResult13141!(e => "4")([4]).array13141(); + +/************************************************** + 11587 AA compare +**************************************************/ + +static assert([1:2, 3:4] == [3:4, 1:2]); + +/************************************************** + 14325 more AA comparisons +**************************************************/ + +static assert([1:1] != [1:2, 2:1]); // OK +static assert([1:1] != [1:2]); // OK +static assert([1:1] != [2:1]); // OK <- Error +static assert([1:1, 2:2] != [3:3, 4:4]); // OK <- Error + +/************************************************** + 7147 typeid() +**************************************************/ + +static assert({ + TypeInfo xxx = typeid(Object); + TypeInfo yyy = typeid(new Error("xxx")); + return true; +}()); + +int bug7147(int n) +{ + Error err = n ? new Error("xxx") : null; + TypeInfo qqq = typeid(err); + return 1; +} + +// Must not segfault if class is null +static assert(!is(typeof(compiles!(bug7147(0))))); +static assert( is(typeof(compiles!(bug7147(1))))); + + +/************************************************** + 14123 - identity TypeInfo objects +**************************************************/ + +static assert({ + bool eq(TypeInfo t1, TypeInfo t2) + { + return t1 is t2; + } + + class C {} + struct S {} + + assert( eq(typeid(C), typeid(C))); + assert(!eq(typeid(C), typeid(Object))); + assert( eq(typeid(S), typeid(S))); + assert(!eq(typeid(S), typeid(int))); + assert( eq(typeid(int), typeid(int))); + assert(!eq(typeid(int), typeid(long))); + + Object o = new Object; + Object c = new C; + assert( eq(typeid(o), typeid(o))); + assert(!eq(typeid(c), typeid(o))); + assert(!eq(typeid(o), typeid(S))); + + return 1; +}()); + +/************************************************** + 6885 wrong code with new array +**************************************************/ + +struct S6885 +{ + int p; +} + +int bug6885() +{ + auto array = new double[1][2]; + array[1][0] = 6; + array[0][0] = 1; + assert(array[1][0] == 6); + + auto barray = new S6885[2]; + barray[1].p = 5; + barray[0].p = 2; + assert(barray[1].p == 5); + return 1; +} + +static assert(bug6885()); + +/************************************************** + 6886 ICE with new array of dynamic arrays +**************************************************/ + +int bug6886() +{ + auto carray = new int[][2]; + carray[1] = [6]; + carray[0] = [4]; + assert(carray[1][0] == 6); + return 1; +} + +static assert(bug6886()); + +/************************************************** + 10198 Multidimensional struct block initializer +**************************************************/ + +struct Block10198 +{ + int val[3][4]; +} + +int bug10198() +{ + Block10198 pp = Block10198(67); + assert(pp.val[2][3] == 67); + assert(pp.val[1][3] == 67); + return 1; +} +static assert(bug10198()); + +/************************************************** + 14440 Multidimensional block initialization should create distinct arrays for each elements +**************************************************/ + +struct Matrix14440(E, size_t row, size_t col) +{ + E[col][row] array2D; + + @safe pure nothrow + this(E[row * col] numbers...) + { + foreach (r; 0 .. row) + { + foreach (c; 0 .. col) + { + array2D[r][c] = numbers[r * col + c]; + } + } + } +} + +void test14440() +{ + // Replace 'enum' with 'auto' here and it will work fine. + enum matrix = Matrix14440!(int, 3, 3)( + 1, 2, 3, + 4, 5, 6, + 7, 8, 9 + ); + + static assert(matrix.array2D[0][0] == 1); + static assert(matrix.array2D[0][1] == 2); + static assert(matrix.array2D[0][2] == 3); + static assert(matrix.array2D[1][0] == 4); + static assert(matrix.array2D[1][1] == 5); + static assert(matrix.array2D[1][2] == 6); + static assert(matrix.array2D[2][0] == 7); + static assert(matrix.array2D[2][1] == 8); + static assert(matrix.array2D[2][2] == 9); +} + +/**************************************************** + * Exception chaining tests from xtest46.d + ****************************************************/ + +class A75 +{ + pure static void raise(string s) + { + throw new Exception(s); + } +} + +int test75() +{ + int x = 0; + try + { + A75.raise("a"); + } + catch (Exception e) + { + x = 1; + } + assert(x == 1); + return 1; +} +static assert(test75()); + +/**************************************************** + * Exception chaining tests from test4.d + ****************************************************/ + +int test4_test54() +{ + int status = 0; + + try + { + try + { + status++; + assert(status == 1); + throw new Exception("first"); + } + finally + { + status++; + assert(status == 2); + status++; + throw new Exception("second"); + } + } + catch (Exception e) + { + assert(e.msg == "first"); + assert(e.next.msg == "second"); + } + return true; +} + +static assert(test4_test54()); + +void foo55() +{ + try + { + Exception x = new Exception("second"); + throw x; + } + catch (Exception e) + { + assert(e.msg == "second"); + } +} + +int test4_test55() +{ + int status = 0; + try + { + try + { + status++; + assert(status == 1); + Exception x = new Exception("first"); + throw x; + } + finally + { + status++; + assert(status == 2); + status++; + foo55(); + } + } + catch (Exception e) + { + assert(e.msg == "first"); + assert(status == 3); + } + return 1; +} + +static assert(test4_test55()); + +/**************************************************** + * Exception chaining tests from eh.d + ****************************************************/ + +void bug1513outer() +{ + int result1513; + + void bug1513a() + { + throw new Exception("d"); + } + + void bug1513b() + { + try + { + try + { + bug1513a(); + } + finally + { + result1513 |= 4; + throw new Exception("f"); + } + } + catch (Exception e) + { + assert(e.msg == "d"); + assert(e.next.msg == "f"); + assert(!e.next.next); + } + } + + void bug1513c() + { + try + { + try + { + throw new Exception("a"); + } + finally + { + result1513 |= 1; + throw new Exception("b"); + } + } + finally + { + bug1513b(); + result1513 |= 2; + throw new Exception("c"); + } + } + + void bug1513() + { + result1513 = 0; + try + { + bug1513c(); + } + catch (Exception e) + { + assert(result1513 == 7); + assert(e.msg == "a"); + assert(e.next.msg == "b"); + assert(e.next.next.msg == "c"); + } + } + + bug1513(); +} + +void collideone() +{ + try + { + throw new Exception("x"); + } + finally + { + throw new Exception("y"); + } +} + +void doublecollide() +{ + try + { + try + { + try + { + throw new Exception("p"); + } + finally + { + throw new Exception("q"); + } + } + finally + { + collideone(); + } + } + catch (Exception e) + { + assert(e.msg == "p"); + assert(e.next.msg == "q"); + assert(e.next.next.msg == "x"); + assert(e.next.next.next.msg == "y"); + assert(!e.next.next.next.next); + } +} + +void collidetwo() +{ + try + { + try + { + throw new Exception("p2"); + } + finally + { + throw new Exception("q2"); + } + } + finally + { + collideone(); + } +} + +void collideMixed() +{ + int works = 6; + try + { + try + { + try + { + throw new Exception("e"); + } + finally + { + throw new Error("t"); + } + } + catch (Exception f) + { + // Doesn't catch, because Error is chained to it. + works += 2; + } + } + catch (Error z) + { + works += 4; + assert(z.msg == "t"); // Error comes first + assert(z.next is null); + assert(z.bypassedException.msg == "e"); + } + assert(works == 10); +} + +class AnotherException : Exception +{ + this(string s) + { + super(s); + } +} + +void multicollide() +{ + try + { + try + { + try + { + try + { + throw new Exception("m2"); + } + finally + { + throw new AnotherException("n2"); + } + } + catch (AnotherException s) + { + // Not caught -- we needed to catch the root cause "m2", not + // just the collateral "n2" (which would leave m2 uncaught). + assert(0); + } + } + finally + { + collidetwo(); + } + } + catch (Exception f) + { + assert(f.msg == "m2"); + assert(f.next.msg == "n2"); + Throwable e = f.next.next; + assert(e.msg == "p2"); + assert(e.next.msg == "q2"); + assert(e.next.next.msg == "x"); + assert(e.next.next.next.msg == "y"); + assert(!e.next.next.next.next); + } +} + +int testsFromEH() +{ + bug1513outer(); + doublecollide(); + collideMixed(); + multicollide(); + return 1; +} +static assert(testsFromEH()); + +/************************************************** + With + synchronized statements + bug 6901 +**************************************************/ + +struct With1 +{ + int a; + int b; +} + +class Foo6 +{ +} + +class Foo32 +{ + struct Bar + { + int x; + } +} + +class Base56 +{ + private string myfoo; + private string mybar; + + // Get/set properties that will be overridden. + void foo(string s) { myfoo = s; } + string foo() { return myfoo; } + + // Get/set properties that will not be overridden. + void bar(string s) { mybar = s; } + string bar() { return mybar; } +} + +class Derived56 : Base56 +{ + alias Base56.foo foo; // Bring in Base56's foo getter. + override void foo(string s) { super.foo = s; } // Override foo setter. +} + +int testwith() +{ + With1 x = With1(7); + with (x) + { + a = 2; + } + assert(x.a == 2); + + // from test11.d + Foo6 foo6 = new Foo6(); + + with (foo6) + { + int xx; + xx = 4; + } + with (new Foo32) + { + Bar z; + z.x = 5; + } + Derived56 d = new Derived56; + with (d) + { + foo = "hi"; + d.foo = "hi"; + bar = "hi"; + assert(foo == "hi"); + assert(d.foo == "hi"); + assert(bar == "hi"); + } + int w = 7; + synchronized + { + ++w; + } + assert(w == 8); + return 1; +} + +static assert(testwith()); + +/************************************************** + 9236 ICE switch with(EnumType) +**************************************************/ + +enum Command9236 +{ + Char, + Any, +}; + +bool bug9236(Command9236 cmd) +{ + int n = 0; + with (Command9236) switch (cmd) + { + case Any: + n = 1; + break; + default: + n = 2; + } + assert(n == 1); + + switch (cmd) with (Command9236) + { + case Any: + return true; + default: + return false; + } +} + +static assert(bug9236(Command9236.Any)); + +/************************************************** + 6416 static struct declaration +**************************************************/ + +static assert({ + static struct S { int y = 7; } + S a; + a.y += 6; + assert(a.y == 13); + return true; +}()); + +/************************************************** + 10499 static template struct declaration +**************************************************/ + +static assert({ + static struct Result() {} + return true; +}()); + +/************************************************** + 13757 extern(C) alias declaration +**************************************************/ + +static assert({ + alias FP1 = extern(C) int function(); + alias extern(C) int function() FP2; + return true; +}()); + +/************************************************** + 6522 opAssign + foreach ref +**************************************************/ + +struct Foo6522 +{ + bool b = false; + void opAssign(int x) + { + this.b = true; + } +} + +bool foo6522() +{ + Foo6522[1] array; + foreach (ref item; array) + item = 1; + return true; +} + +static assert(foo6522()); + +/************************************************** + 7245 pointers + foreach ref +**************************************************/ + +int bug7245(int testnum) +{ + int[3] arr; + arr[0] = 4; + arr[1] = 6; + arr[2] = 8; + int* ptr; + + foreach (i, ref p; arr) + { + if (i == 1) + ptr = &p; + if (testnum == 1) + p = 5; + } + + return *ptr; +} + +static assert(bug7245(0) == 6); +static assert(bug7245(1) == 5); + +/************************************************** + 8498 modifying foreach + 7658 foreach ref + 8539 nested funcs, ref param, -inline +**************************************************/ + +int bug8498() +{ + foreach (ref i; 0 .. 5) + { + assert(i == 0); + i = 100; + } + return 1; +} +static assert(bug8498()); + +string bug7658() +{ + string[] children = ["0"]; + foreach (ref child; children) + child = "1"; + return children[0]; +} + +static assert(bug7658() == "1"); + +int bug8539() +{ + static void one(ref int x) + { + x = 1; + } + static void go() + { + int y; + one(y); + assert(y == 1); // fails with -inline + } + go(); + return 1; +} + +static assert(bug8539()); + +/************************************************** + 7874, 13297, 13740 - better lvalue handling +**************************************************/ + +int bug7874(int x){ return ++x = 1; } +static assert(bug7874(0) == 1); + +// ---- + +struct S13297 +{ + int* p; +} +void f13297(ref int* p) +{ + p = cast(int*) 1; + assert(p); // passes +} +static assert( +{ + S13297 s; + f13297(s.p); + return s.p != null; // false +}()); + +// ---- + +class R13740 +{ + int e; + bool empty = false; + @property ref front() { return e; } + void popFront() { empty = true; } +} +static assert({ + auto r = new R13740(); + foreach (ref e; r) + e = 42; + assert(r.e == 42); /* fails in CTFE */ + + return true; +}()); + +/************************************************** + 6919 +**************************************************/ + +void bug6919(int* val) +{ + *val = 1; +} +void test6919() +{ + int n; + bug6919(&n); + assert(n == 1); +} +static assert({ test6919(); return true; }()); + +void bug6919b(string* val) +{ + *val = "1"; +} + +void test6919b() +{ + string val; + bug6919b(&val); + assert(val == "1"); +} +static assert({ test6919b(); return true; }()); + +/************************************************** + 6995 +**************************************************/ + +struct Foo6995 +{ + static size_t index(size_t v)() + { + return v; + } +} + +static assert(Foo6995.index!(27)() == 27); + +/************************************************** + 7043 ref with -inline +**************************************************/ + +int bug7043(S)(ref int x) +{ + return x; +} + +static assert({ + int i = 416; + return bug7043!(char)(i); +}() == 416); + +/************************************************** + 6037 recursive ref +**************************************************/ + +void bug6037(ref int x, bool b) +{ + int w = 3; + if (b) + { + bug6037(w, false); + assert(w == 6); + } + else + { + x = 6; + assert(w == 3); // fails + } +} + +int bug6037outer() +{ + int q; + bug6037(q, true); + return 401; +} + +static assert(bug6037outer() == 401); + +/************************************************** + 14299 - [REG2.067a], more than one depth of recursive call with ref +**************************************************/ + +string gen14299(int max, int idx, ref string name) +{ + string ret; + name = [cast(char)(idx + '0')]; + ret ~= name; + if (idx < max) + { + string subname; + ret ~= gen14299(max, idx + 1, subname); + } + ret ~= name; + return ret; +} +string test14299(int max) +{ + string n; + return gen14299(max, 0, n); +} +static assert(test14299(1) == "0110"); // OK <- fail +static assert(test14299(2) == "012210"); // OK <- ICE +static assert(test14299(3) == "01233210"); +static assert(test14299(4) == "0123443210"); +static assert(test14299(5) == "012345543210"); + +/************************************************** + 7940 wrong code for complicated assign +**************************************************/ + +struct Bug7940 +{ + int m; +} + +struct App7940 +{ + Bug7940[] x; +} + +int bug7940() +{ + Bug7940[2] y; + App7940 app; + app.x = y[0 .. 1]; + app.x[0].m = 12; + assert(y[0].m == 12); + assert(app.x[0].m == 12); + return 1; +} + +static assert(bug7940()); + +/************************************************** + 10298 wrong code for struct array literal init +**************************************************/ + +struct Bug10298 +{ + int m; +} + +int bug10298() +{ + Bug10298[1] y = [Bug10298(78)]; + y[0].m = 6; + assert(y[0].m == 6); + + // Root cause + Bug10298[1] x; + x[] = [cast(const Bug10298)(Bug10298(78))]; + assert(x[0].m == 78); + return 1; +} + +static assert(bug10298()); + +/************************************************** + 7266 dotvar ref parameters +**************************************************/ + +struct S7266 { int a; } + +bool bug7266() +{ + S7266 s; + s.a = 4; + bar7266(s.a); + assert(s.a == 5); + out7266(s.a); + assert(s.a == 7); + return true; +} + +void bar7266(ref int b) +{ + b = 5; + assert(b == 5); +} + +void out7266(out int b) +{ + b = 7; + assert(b == 7); +} + +static assert(bug7266()); + +/************************************************** + 9982 dotvar assign through pointer +**************************************************/ + +struct Bug9982 +{ + int a; +} + +int test9982() +{ + Bug9982 x; + int*q = &x.a; + *q = 99; + assert(x.a == 99); + return 1; +} + +static assert(test9982()); + +// 9982, rejects-valid case + +struct SS9982 +{ + Bug9982 s2; + this(Bug9982 s1) + { + s2.a = 6; + emplace9982(&s2, s1); + assert(s2.a == 3); + } +} + +void emplace9982(Bug9982* chunk, Bug9982 arg) +{ + *chunk = arg; +} + +enum s9982 = Bug9982(3); +enum p9982 = SS9982(s9982); + +/************************************************** + 11618 dotvar assign through casted pointer +**************************************************/ + +struct Tuple11618(T...) +{ + T field; + alias field this; +} + +static assert({ + Tuple11618!(immutable dchar) result = void; + auto addr = cast(dchar*)&result[0]; + *addr = dchar.init; + return (result[0] == dchar.init); +}()); + +/************************************************** + 7143 'is' for classes +**************************************************/ + +class C7143 +{ + int x; +} + +int bug7143(int test) +{ + C7143 c = new C7143; + C7143 d = new C7143; + if (test == 1) + { + if (c) + return c.x + 8; + return -1; + } + if (test == 2) + { + if (c is null) + return -1; + return c.x + 45; + } + if (test == 3) + { + if (c is c) + return 58; + } + if (test == 4) + { + if (c !is c) + return -1; + else + return 48; + } + if (test == 6) + d = c; + if (test == 5 || test == 6) + { + if (c is d) + return 188; + else + return 48; + } + return -1; +} + +static assert(bug7143(1) == 8); +static assert(bug7143(2) == 45); +static assert(bug7143(3) == 58); +static assert(bug7143(4) == 48); +static assert(bug7143(5) == 48); +static assert(bug7143(6) == 188); + +/************************************************** + 7147 virtual function calls from base class +**************************************************/ + +class A7147 +{ + int foo() { return 0; } + + int callfoo() + { + return foo(); + } +} + +class B7147 : A7147 +{ + override int foo() { return 1; } +} + +int test7147() +{ + A7147 a = new B7147; + return a.callfoo(); +} + +static assert(test7147() == 1); + +/************************************************** + 7158 +**************************************************/ + +class C7158 +{ + bool b() { return true; } +} +struct S7158 +{ + C7158 c; +} + +bool test7158() +{ + S7158 s = S7158(new C7158); + return s.c.b; +} +static assert(test7158()); + +/************************************************** + 8484 +**************************************************/ + +class C8484 +{ + int n; + int b() { return n + 3; } +} + +struct S +{ + C8484 c; +} + +int t8484(ref C8484 c) +{ + return c.b(); +} + +int test8484() +{ + auto s = S(new C8484); + s.c.n = 4; + return t8484(s.c); +} +static assert(test8484() == 7); + +/************************************************** + 7419 +**************************************************/ + +struct X7419 +{ + double x; + this(double x) + { + this.x = x; + } +} + +void bug7419() +{ + enum x = { + auto p = X7419(3); + return p.x; + }(); + static assert(x == 3); +} + +/************************************************** + 9445 ice +**************************************************/ + +template c9445(T...) { } + +void ice9445(void delegate() expr, void function() f2) +{ + static assert(!is(typeof(c9445!(f2())))); + static assert(!is(typeof(c9445!(expr())))); +} + +/************************************************** + 10452 delegate == +**************************************************/ + +struct S10452 +{ + bool func() { return true; } +} + +struct Outer10452 +{ + S10452 inner; +} + +class C10452 +{ + bool func() { return true; } +} + +bool delegate() ref10452(ref S10452 s) +{ + return &s.func; +} + +bool test10452() +{ + bool delegate() bar = () { return true; }; + + assert(bar !is null); + assert(bar is bar); + + S10452 bag; + S10452[6] bad; + Outer10452 outer; + C10452 tag = new C10452; + + auto rat = &outer.inner.func; + assert(rat == rat); + auto tat = &tag.func; + assert(tat == tat); + + auto bat = &outer.inner.func; + auto mat = &bad[2].func; + assert(mat is mat); + assert(rat == bat); + + auto zat = &bag.func; + auto cat = &bag.func; + assert(zat == zat); + assert(zat == cat); + + auto drat = ref10452(bag); + assert(cat == drat); + assert(drat == drat); + drat = ref10452(bad[2]); + assert( drat == mat); + assert(tat != rat); + assert(zat != rat); + assert(rat != cat); + assert(zat != bar); + assert(tat != cat); + cat = bar; + assert(cat == bar); + return true; +} +static assert(test10452()); + +/************************************************** + 7162 and 4711 +**************************************************/ + +void f7162() { } + +bool ice7162() +{ + false && f7162(); + false || f7162(); + false && f7162(); // bug 4711 + true && f7162(); + return true; +} + +static assert(ice7162()); + +/************************************************** + 8857, only with -inline (creates an &&) +**************************************************/ + +struct Result8857 { char[] next; } + +void bug8857()() +{ + Result8857 r; + r.next = null; + if (true) + { + auto next = r.next; + } +} +static assert({ + bug8857(); + return true; +}()); + +/************************************************** + 7527 +**************************************************/ + +struct Bug7527 +{ + char[] data; +} + +int bug7527() +{ + auto app = Bug7527(); + + app.data.ptr[0 .. 1] = "x"; + return 1; +} + +static assert(!is(typeof(compiles!(bug7527())))); + +/************************************************** + 7527 +**************************************************/ + +int bug7380; + +static assert(!is(typeof( compiles!( + (){ + return &bug7380; + }() +)))); + +/************************************************** + 7165 +**************************************************/ + +struct S7165 +{ + int* ptr; + bool f() const { return !!ptr; } +} + +static assert(!S7165().f()); + +/************************************************** + 7187 +**************************************************/ + +int[] f7187() { return [0]; } +int[] f7187b(int n) { return [0]; } + +int g7187(int[] r) +{ + auto t = r[0 .. 0]; + return 1; +} + +static assert(g7187(f7187())); +static assert(g7187(f7187b(7))); + +struct S7187 { const(int)[] field; } + +const(int)[] f7187c() +{ + auto s = S7187([0]); + return s.field; +} + +bool g7187c(const(int)[] r) +{ + auto t = r[0 .. 0]; + return true; +} + +static assert(g7187c(f7187c())); + + +/************************************************** + 6933 struct destructors +**************************************************/ + +struct Bug6933 +{ + int x = 3; + ~this() { } +} + +int test6933() +{ + Bug6933 q; + assert(q.x == 3); + return 3; +} + +static assert(test6933()); + +/************************************************** + 7197 +**************************************************/ + +int foo7197(int[] x...) +{ + return 1; +} +template bar7197(y...) +{ + enum int bar7197 = foo7197(y); +} +enum int bug7197 = 7; +static assert(bar7197!(bug7197)); + +/************************************************** + Enum string compare +**************************************************/ + +enum EScmp : string { a = "aaa" } + +bool testEScmp() +{ + EScmp x = EScmp.a; + assert(x < "abc"); + return true; +} + +static assert(testEScmp()); + +/************************************************** + 7667 +**************************************************/ + +bool baz7667(int[] vars...) +{ + return true; +} + +struct S7667 +{ + static void his(int n) + { + static assert(baz7667(2)); + } +} + +bool bug7667() +{ + S7667 unused; + unused.his(7); + return true; +} +enum e7667 = bug7667(); + +/************************************************** + 7536 +**************************************************/ + +bool bug7536(string expr) +{ + return true; +} + +void vop() +{ + const string x7536 = "x"; + static assert(bug7536(x7536)); +} + +/************************************************** + 6681 unions +**************************************************/ + +struct S6681 +{ + this(int a, int b) { this.a = b; this.b = a; } + union + { + ulong g; + struct { int a, b; }; + } +} + +static immutable S6681 s6681 = S6681(0, 1); + +bool bug6681(int test) +{ + S6681 x = S6681(0, 1); + x.g = 5; + auto u = &x.g; + auto v = &x.a; + long w = *u; + int z; + assert(w == 5); + if (test == 4) + z = *v; // error + x.a = 2; // invalidate g, and hence u. + if (test == 1) + w = *u; // error + z = *v; + assert(z == 2); + x.g = 6; + w = *u; + assert(w == 6); + if (test == 3) + z = *v; + return true; +} +static assert(bug6681(2)); +static assert(!is(typeof(compiles!(bug6681(1))))); +static assert(!is(typeof(compiles!(bug6681(3))))); +static assert(!is(typeof(compiles!(bug6681(4))))); + +/************************************************** + 9113 ICE with struct in union +**************************************************/ + +union U9113 +{ + struct M + { + int y; + } + int xx; +} + +int bug9113(T)() +{ + U9113 x; + x.M.y = 10; // error, need 'this' + return 1; +} + +static assert(!is(typeof(compiles!(bug9113!(int)())))); + +/************************************************** + Creation of unions +**************************************************/ + +union UnionTest1 +{ + int x; + float y; +} + +int uniontest1() +{ + UnionTest1 u = UnionTest1(1); + return 1; +} + +static assert(uniontest1()); + +/************************************************** + 6438 void +**************************************************/ + +struct S6438 +{ + int a; + int b = void; +} + +void fill6438(int[] arr, int testnum) +{ + if (testnum == 2) + { + auto u = arr[0]; + } + foreach (ref x; arr) + x = 7; + auto r = arr[0]; + S6438[2] s; + auto p = &s[0].b; + if (testnum == 3) + { + auto v = *p; + } +} + +bool bug6438(int testnum) +{ + int[4] stackSpace = void; + fill6438(stackSpace[], testnum); + assert(stackSpace == [7, 7, 7, 7]); + return true; +} + +static assert( is(typeof(compiles!(bug6438(1))))); +static assert(!is(typeof(compiles!(bug6438(2))))); +static assert(!is(typeof(compiles!(bug6438(3))))); + +/************************************************** + 10994 void static array members +**************************************************/ + +struct Bug10994 +{ + ubyte[2] buf = void; +} + +static bug10994 = Bug10994.init; + +/************************************************** + 10937 struct inside union +**************************************************/ + +struct S10937 +{ + union + { + ubyte[1] a; + struct + { + ubyte b; + } + } + + this(ubyte B) + { + if (B > 6) + this.b = B; + else + this.a[0] = B; + } +} + +enum test10937 = S10937(7); +enum west10937 = S10937(2); + +/************************************************** + 13831 +**************************************************/ + +struct Vector13831() +{ +} + +struct Coord13831 +{ + union + { + struct { short x; } + Vector13831!() vector; + } +} + +struct Chunk13831 +{ + this(Coord13831) + { + coord = coord; + } + + Coord13831 coord; + + static const Chunk13831* unknownChunk = new Chunk13831(Coord13831()); +} + +/************************************************** + 7732 +**************************************************/ + +struct AssociativeArray +{ + int* impl; + int f() + { + if (impl !is null) + auto x = *impl; + return 1; + } +} + +int test7732() +{ + AssociativeArray aa; + return aa.f; +} + +static assert(test7732()); + +/************************************************** + 7784 +**************************************************/ +struct Foo7784 +{ + void bug() + { + tab["A"] = Bar7784(&this); + auto pbar = "A" in tab; + auto bar = *pbar; + } + + Bar7784[string] tab; +} + +struct Bar7784 +{ + Foo7784* foo; + int val; +} + +bool ctfe7784() +{ + auto foo = Foo7784(); + foo.bug(); + return true; +} + +static assert(ctfe7784()); + +/************************************************** + 7781 +**************************************************/ + +static assert(({ return; }(), true)); + +/************************************************** + 7785 +**************************************************/ + +bool bug7785(int n) +{ + int val = 7; + auto p = &val; + if (n == 2) + { + auto ary = p[0 .. 1]; + } + auto x = p[0]; + val = 6; + assert(x == 7); + if (n == 3) + p[0 .. 1] = 1; + return true; +} + +static assert(bug7785(1)); +static assert(!is(typeof(compiles!(bug7785(2))))); +static assert(!is(typeof(compiles!(bug7785(3))))); + +/************************************************** + 7987 +**************************************************/ + +class C7987 +{ + int m; +} + +struct S7987 +{ + int* p; + C7987 c; +} + +bool bug7987() +{ + int[7] q; + int[][2] b = q[0 .. 5]; + assert(b == b); + assert(b is b); + C7987 c1 = new C7987; + C7987 c2 = new C7987; + S7987 s, t; + s.p = &q[0]; + t.p = &q[1]; + assert(s != t); + s.p = &q[1]; + /*assert(s == t);*/ assert(s.p == t.p); + s.c = c1; + t.c = c2; + /*assert(s != t);*/ assert(s.c !is t.c); + assert(s !is t); + s.c = c2; + /*assert(s == t);*/ assert(s.p == t.p && s.c is t.c); + assert(s is t); + return true; +} + +static assert(bug7987()); + +/************************************************** + 10579 typeinfo.func() must not segfault +**************************************************/ + +static assert(!is(typeof(compiles!(typeid(int).toString.length)))); + +class Bug10579 +{ + int foo() { return 1; } +} +Bug10579 uninitialized10579; + +static assert(!is(typeof(compiles!(uninitialized10579.foo())))); + +/************************************************** + 10804 mixin ArrayLiteralExp typed string +**************************************************/ + +void test10804() +{ + String identity(String)(String a) { return a; } + + string cfun() + { + char[] s; + s.length = 8 + 2 + (2) + 1 + 2; + s[] = "identity(`Ω`c)"c[]; + return cast(string)s; // Return ArrayLiteralExp as the CTFE result + } + { + enum a1 = "identity(`Ω`c)"c; + enum a2 = cfun(); + static assert(cast(ubyte[])mixin(a1) == [0xCE, 0xA9]); + static assert(cast(ubyte[])mixin(a2) == [0xCE, 0xA9]); // should pass + } + + wstring wfun() + { + wchar[] s; + s.length = 8 + 2 + (2) + 1 + 2; + s[] = "identity(`\U0002083A`w)"w[]; + return cast(wstring)s; // Return ArrayLiteralExp as the CTFE result + } + { + enum a1 = "identity(`\U0002083A`w)"w; + enum a2 = wfun(); + static assert(cast(ushort[])mixin(a1) == [0xD842, 0xDC3A]); + static assert(cast(ushort[])mixin(a2) == [0xD842, 0xDC3A]); + } + + dstring dfun() + { + dchar[] s; + s.length = 8 + 2 + (1) + 1 + 2; + s[] = "identity(`\U00101000`d)"d[]; + return cast(dstring)s; // Return ArrayLiteralExp as the CTFE result + } + { + enum a1 = "identity(`\U00101000`d)"d; + enum a2 = dfun(); + static assert(cast(uint[])mixin(a1) == [0x00101000]); + static assert(cast(uint[])mixin(a2) == [0x00101000]); + } +} + +/******************************************************/ + +struct B73 {} +struct C73 { B73 b; } +C73 func73() { C73 b = void; b.b = B73(); return b; } +C73 test73 = func73(); + +/******************************************************/ + +struct S74 +{ + int n[1]; + static S74 test(){ S74 ret = void; ret.n[0] = 0; return ret; } +} + +enum Test74 = S74.test(); + +/******************************************************/ + +static bool bug8865() +in +{ + int x = 0; +label: + foreach (i; (++x) .. 3) + { + if (i == 1) + continue label; // doesn't work. + else + break label; // doesn't work. + } +} +out +{ + int x = 0; +label: + foreach (i; (++x) .. 3) + { + if (i == 1) + continue label; // doesn't work. + else + break label; // doesn't work. + } +} +body +{ + int x = 0; +label: + foreach (i; (++x) .. 3) + { + if (i == 1) + continue label; // works. + else + break label; // works. + } + + return true; +} +static assert(bug8865()); + +/******************************************************/ +// 15450 labeled foreach + continue/break + +static assert({ + L1: + foreach (l; [0]) + continue L1; + + L2: + foreach (l; [0]) + break L2; + + return true; +}()); + +struct Test75 +{ + this(int) pure {} +} + +/******************************************************/ + +static assert( __traits(compiles, { static shared(Test75*) t75 = new shared(Test75)(0); return t75; })); +static assert( __traits(compiles, { static shared(Test75)* t75 = new shared(Test75)(0); return t75; })); +static assert( __traits(compiles, { static __gshared Test75* t75 = new Test75(0); return t75; })); +static assert( __traits(compiles, { static const(Test75*) t75 = new const(Test75)(0); return t75; })); +static assert( __traits(compiles, { static immutable Test75* t75 = new immutable(Test75)(0); return t75; })); +static assert(!__traits(compiles, { static Test75* t75 = new Test75(0); return t75; })); +/+ +static assert(!__traits(compiles, { enum t75 = new shared(Test75)(0); return t75; })); +static assert(!__traits(compiles, { enum t75 = new Test75(0); return t75; })); +static assert(!__traits(compiles, { enum shared(Test75)* t75 = new shared(Test75)(0); return t75; })); +static assert(!__traits(compiles, { enum Test75* t75 = new Test75(0); return t75; })); + +static assert( __traits(compiles, { enum t75 = new const(Test75)(0); return t75;})); +static assert( __traits(compiles, { enum t75 = new immutable(Test75)(0); return t75;})); +static assert( __traits(compiles, { enum const(Test75)* t75 = new const(Test75)(0); return t75;})); +static assert( __traits(compiles, { enum immutable(Test75)* t75 = new immutable(Test75)(0); return t75;})); ++/ +/******************************************************/ + +class Test76 +{ + this(int) pure {} +} +/+ +static assert(!__traits(compiles, { enum t76 = new shared(Test76)(0); return t76;})); +static assert(!__traits(compiles, { enum t76 = new Test76(0); return t76;})); +static assert(!__traits(compiles, { enum shared(Test76) t76 = new shared(Test76)(0); return t76;})); +static assert(!__traits(compiles, { enum Test76 t76 = new Test76(0); return t76;})); + +static assert( __traits(compiles, { enum t76 = new const(Test76)(0); return t76;})); +static assert( __traits(compiles, { enum t76 = new immutable(Test76)(0); return t76;})); +static assert( __traits(compiles, { enum const(Test76) t76 = new const(Test76)(0); return t76;})); +static assert( __traits(compiles, { enum immutable(Test76) t76 = new immutable(Test76)(0); return t76;})); ++/ +/******************************************************/ + +static assert( __traits(compiles, { static shared Test76 t76 = new shared(Test76)(0); return t76; })); +static assert( __traits(compiles, { static shared(Test76) t76 = new shared(Test76)(0); return t76; })); +static assert( __traits(compiles, { static __gshared Test76 t76 = new Test76(0); return t76; })); +static assert( __traits(compiles, { static const Test76 t76 = new const(Test76)(0); return t76; })); +static assert( __traits(compiles, { static immutable Test76 t76 = new immutable Test76(0); return t76; })); +static assert(!__traits(compiles, { static Test76 t76 = new Test76(0); return t76; })); + +/***** Bug 5678 *********************************/ + +struct Bug5678 +{ + this(int) {} +} + +static assert(!__traits(compiles, { enum const(Bug5678)* b5678 = new const(Bug5678)(0); return b5678; })); + +/************************************************** + 10782 run semantic2 for class field +**************************************************/ + +enum e10782 = 0; +class C10782 { int x = e10782; } +string f10782() +{ + auto c = new C10782(); + return ""; +} +mixin(f10782()); + +/************************************************** + 10929 NRVO support in CTFE +**************************************************/ + +struct S10929 +{ + this(this) + { + postblitCount++; + } + ~this() + { + dtorCount++; + } + int payload; + int dtorCount; + int postblitCount; +} + +auto makeS10929() +{ + auto s = S10929(42, 0, 0); + return s; +} + +bool test10929() +{ + auto s = makeS10929(); + assert(s.postblitCount == 0); + assert(s.dtorCount == 0); + return true; +}; +static assert(test10929()); + +/************************************************** + 9245 - support postblit call on array assignments +**************************************************/ + +bool test9245() +{ + int postblits = 0; + struct S + { + this(this) + { + ++postblits; + } + } + + S s; + S[2] a; + assert(postblits == 0); + + { + S[2] arr = s; + assert(postblits == 2); + arr[] = s; + assert(postblits == 4); + postblits = 0; + + S[2] arr2 = arr; + assert(postblits == 2); + arr2 = arr; + assert(postblits == 4); + postblits = 0; + + const S[2] constArr = s; + assert(postblits == 2); + postblits = 0; + + const S[2] constArr2 = arr; + assert(postblits == 2); + postblits = 0; + } + { + S[2][2] arr = s; + assert(postblits == 4); + arr[] = a; + assert(postblits == 8); + postblits = 0; + + S[2][2] arr2 = arr; + assert(postblits == 4); + arr2 = arr; + assert(postblits == 8); + postblits = 0; + + const S[2][2] constArr = s; + assert(postblits == 4); + postblits = 0; + + const S[2][2] constArr2 = arr; + assert(postblits == 4); + postblits = 0; + } + + return true; +} +static assert(test9245()); + +/************************************************** + 12906 don't call postblit on blit initializing +**************************************************/ + +struct S12906 { this(this) { assert(0); } } + +static assert({ + S12906[1] arr; + return true; +}()); + +/************************************************** + 11510 support overlapped field access in CTFE +**************************************************/ + +struct S11510 +{ + union + { + size_t x; + int* y; // pointer field + } +} +bool test11510() +{ + S11510 s; + + s.y = [1,2,3].ptr; // writing overlapped pointer field is OK + assert(s.y[0 .. 3] == [1,2,3]); // reading valid field is OK + + s.x = 10; + assert(s.x == 10); + + // There's no reinterpretation between S.x and S.y + return true; +} +static assert(test11510()); + +/************************************************** + 11534 - subtitude inout +**************************************************/ + +struct MultiArray11534 +{ + void set(size_t[] sizes...) + { + storage = new size_t[5]; + } + + @property auto raw_ptr() inout + { + return storage.ptr + 1; + } + size_t[] storage; +} + +enum test11534 = () { + auto m = MultiArray11534(); + m.set(3,2,1); + auto start = m.raw_ptr; //this trigger the bug + //auto start = m.storage.ptr + 1; //this obviously works + return 0; +}(); + +/************************************************** + 11941 - Regression of 11534 fix +**************************************************/ + +void takeConst11941(const string[]) {} +string[] identity11941(string[] x) { return x; } + +bool test11941a() +{ + struct S { string[] a; } + S s; + + takeConst11941(identity11941(s.a)); + s.a ~= []; + + return true; +} +static assert(test11941a()); + +bool test11941b() +{ + struct S { string[] a; } + S s; + + takeConst11941(identity11941(s.a)); + s.a ~= "foo"; /* Error refers to this line (15), */ + string[] b = s.a[]; /* but only when this is here. */ + + return true; +} +static assert(test11941b()); + +/************************************************** + 11535 - element-wise assignment from string to ubyte array literal +**************************************************/ + +struct Hash11535 +{ + ubyte[6] _buffer; + + void put(scope const(ubyte)[] data...) + { + uint i = 0, index = 0; + auto inputLen = data.length; + + (&_buffer[index])[0 .. inputLen - i] = (&data[i])[0 .. inputLen - i]; + } +} + +auto md5_digest11535(T...)(scope const T data) +{ + Hash11535 hash; + hash.put(cast(const(ubyte[]))data[0]); + return hash._buffer; +} + +static assert(md5_digest11535(`TEST`) == [84, 69, 83, 84, 0, 0]); + +/************************************************** + 11540 - goto label + try-catch-finally / with statement +**************************************************/ + +static assert(() +{ + // enter to TryCatchStatement.body + { + bool c = false; + try + { + if (c) // need to bypass front-end optimization + throw new Exception(""); + else + { + goto Lx; + L1: + c = true; + } + } + catch (Exception e) {} + + Lx: + if (!c) + goto L1; + } + + // jump inside TryCatchStatement.body + { + bool c = false; + try + { + if (c) // need to bypass front-end optimization + throw new Exception(""); + else + goto L2; + L2: + ; + } + catch (Exception e) {} + } + + // exit from TryCatchStatement.body + { + bool c = false; + try + { + if (c) // need to bypass front-end optimization + throw new Exception(""); + else + goto L3; + } + catch (Exception e) {} + + c = true; + L3: + assert(!c); + } + + return 1; +}()); + +static assert(() +{ + // enter to TryCatchStatement.catches which has no exception variable + { + bool c = false; + goto L1; + try + { + c = true; + } + catch (Exception/* e*/) + { + L1: + ; + } + assert(c == false); + } + + // jump inside TryCatchStatement.catches + { + bool c = false; + try + { + throw new Exception(""); + } + catch (Exception e) + { + goto L2; + c = true; + L2: + ; + } + assert(c == false); + } + + // exit from TryCatchStatement.catches + { + bool c = false; + try + { + throw new Exception(""); + } + catch (Exception e) + { + goto L3; + c = true; + } + L3: + assert(c == false); + } + + return 1; +}()); + +static assert(() +{ + // enter forward to TryFinallyStatement.body + { + bool c = false; + goto L0; + c = true; + try + { + L0: + ; + } + finally {} + assert(!c); + } + + // enter back to TryFinallyStatement.body + { + bool c = false; + try + { + goto Lx; + L1: + c = true; + } + finally { + } + + Lx: + if (!c) + goto L1; + } + + // jump inside TryFinallyStatement.body + { + try + { + goto L2; + L2: ; + } + finally {} + } + + // exit from TryFinallyStatement.body + { + bool c = false; + try + { + goto L3; + } + finally {} + + c = true; + L3: + assert(!c); + } + + // enter in / exit out from finally block is rejected in semantic analysis + + // jump inside TryFinallyStatement.finalbody + { + bool c = false; + try + { + } + finally + { + goto L4; + c = true; + L4: + assert(c == false); + } + } + + return 1; +}()); + +static assert(() +{ + { + bool c = false; + with (Object.init) + { + goto L2; + c = true; + L2: + ; + } + assert(c == false); + } + + { + bool c = false; + with (Object.init) + { + goto L3; + c = true; + } + L3: + assert(c == false); + } + + return 1; +}()); + +/************************************************** + 11627 - cast dchar to char at compile time on AA assignment +**************************************************/ + +bool test11627() +{ + char[ubyte] toCharTmp; + dchar letter = 'A'; + + //char c = cast(char)letter; // OK + toCharTmp[0] = cast(char)letter; // NG + + return true; +} +static assert(test11627()); + +/************************************************** + 11664 - ignore function local static variables +**************************************************/ + +bool test11664() +{ + static int x; + static int y = 1; + return true; +} +static assert(test11664()); + +/************************************************** + 12110 - operand of dereferencing does not need to be an lvalue +**************************************************/ + +struct SliceOverIndexed12110 +{ + Uint24Array12110* arr; + + @property front(uint val) + { + arr.dupThisReference(); + } +} + +struct Uint24Array12110 +{ + ubyte[] data; + + this(ubyte[] range) + { + data = range; + SliceOverIndexed12110(&this).front = 0; + assert(data.length == range.length * 2); + } + + void dupThisReference() + { + auto new_data = new ubyte[data.length * 2]; + data = new_data; + } +} + +static m12110 = Uint24Array12110([0x80]); + +/************************************************** + 12310 - heap allocation for built-in sclar types +**************************************************/ + +bool test12310() +{ + auto p1 = new int, p2 = p1; + assert(*p1 == 0); + assert(*p2 == 0); + *p1 = 10; + assert(*p1 == 10); + assert(*p2 == 10); + + auto q1 = new int(3), q2 = q1; + assert(*q1 == 3); + assert(*q2 == 3); + *q1 = 20; + assert(*q1 == 20); + assert(*q2 == 20); + + return true; +} +static assert(test12310()); + +/************************************************** + 12499 - initialize TupleDeclaraion in CTFE +**************************************************/ + +auto f12499() +{ + //Initialize 3 ints to 5. + TypeTuple!(int, int, int) a = 5; + return a[0]; //Error: variable _a_field_0 cannot be read at compile time +} +static assert(f12499() == 5); + +/************************************************** + 12602 - slice in struct literal members +**************************************************/ + +struct Result12602 +{ + uint[] source; +} + +auto wrap12602a(uint[] r) +{ + return Result12602(r); +} + +auto wrap12602b(uint[] r) +{ + Result12602 x; + x.source = r; + return x; +} + +auto testWrap12602a() +{ + uint[] dest = [1, 2, 3, 4]; + + auto ra = wrap12602a(dest[0 .. 2]); + auto rb = wrap12602a(dest[2 .. 4]); + + foreach (i; 0 .. 2) + rb.source[i] = ra.source[i]; + + assert(ra.source == [1,2]); + assert(rb.source == [1,2]); + assert(&ra.source[0] == &dest[0]); + assert(&rb.source[0] == &dest[2]); + assert(dest == [1,2,1,2]); + return dest; +} + +auto testWrap12602b() +{ + uint[] dest = [1, 2, 3, 4]; + + auto ra = wrap12602b(dest[0 .. 2]); + auto rb = wrap12602b(dest[2 .. 4]); + + foreach (i; 0 .. 2) + rb.source[i] = ra.source[i]; + + assert(ra.source == [1,2]); + assert(rb.source == [1,2]); + assert(&ra.source[0] == &dest[0]); + assert(&rb.source[0] == &dest[2]); + assert(dest == [1,2,1,2]); + return dest; +} + +auto testWrap12602c() +{ + uint[] dest = [1, 2, 3, 4]; + + auto ra = Result12602(dest[0 .. 2]); + auto rb = Result12602(dest[2 .. 4]); + + foreach (i; 0 .. 2) + rb.source[i] = ra.source[i]; + + assert(ra.source == [1,2]); + assert(rb.source == [1,2]); + assert(&ra.source[0] == &dest[0]); + assert(&rb.source[0] == &dest[2]); + assert(dest == [1,2,1,2]); + return dest; +} + +auto testWrap12602d() +{ + uint[] dest = [1, 2, 3, 4]; + + Result12602 ra; ra.source = dest[0 .. 2]; + Result12602 rb; rb.source = dest[2 .. 4]; + + foreach (i; 0 .. 2) + rb.source[i] = ra.source[i]; + + assert(ra.source == [1,2]); + assert(rb.source == [1,2]); + assert(&ra.source[0] == &dest[0]); + assert(&rb.source[0] == &dest[2]); + assert(dest == [1,2,1,2]); + return dest; +} + +static assert(testWrap12602a() == [1,2,1,2]); +static assert(testWrap12602b() == [1,2,1,2]); +static assert(testWrap12602c() == [1,2,1,2]); +static assert(testWrap12602d() == [1,2,1,2]); + +/************************************************** + 12677 - class type initializing from DotVarExp +**************************************************/ + +final class C12677 +{ + TypeTuple!(Object, int[]) _test; + this() + { + auto t0 = _test[0]; // + auto t1 = _test[1]; // + assert(t0 is null); + assert(t1 is null); + } +} + +struct S12677 +{ + auto f = new C12677(); +} + +/************************************************** + 12851 - interpret function local const static array +**************************************************/ + +void test12851() +{ + const int[5] arr; + alias staticZip = TypeTuple!(arr[0]); +} + +/************************************************** + 13630 - indexing and setting array element via pointer +**************************************************/ + +struct S13630(T) +{ + T[3] arr; + + this(A...)(auto ref in A args) + { + auto p = arr.ptr; + + foreach (ref v; args) + { + *p = 0; + } + } +} + +enum s13630 = S13630!float(1); + +/************************************************** + 13827 +**************************************************/ + +struct Matrix13827(T, uint N) +{ + private static defaultMatrix() + { + T arr[N]; + return arr; + } + + union + { + T[N] A = defaultMatrix; + T[N] flat; + } + + this(A...)(auto ref in A args) + { + uint k; + + foreach (ref v; args) + flat[k++] = cast(T)v; + } +} +enum m13827 = Matrix13827!(int, 3)(1, 2, 3); + +/************************************************** + 13847 - support DotTypeExp +**************************************************/ + +class B13847 +{ + int foo() { return 1; } +} + +class C13847 : B13847 +{ + override int foo() { return 2; } + + final void test(int n) + { + assert(foo() == n); + assert(B13847.foo() == 1); + assert(C13847.foo() == 2); + assert(this.B13847.foo() == 1); + assert(this.C13847.foo() == 2); + } +} + +class D13847 : C13847 +{ + override int foo() { return 3; } +} + +static assert({ + C13847 c = new C13847(); + c.test(2); + assert(c.B13847.foo() == 1); + assert(c.C13847.foo() == 2); + + D13847 d = new D13847(); + d.test(3); + assert(d.B13847.foo() == 1); + assert(d.C13847.foo() == 2); + assert(d.D13847.foo() == 3); + + c = d; + c.test(3); + assert(c.B13847.foo() == 1); + assert(c.C13847.foo() == 2); + return true; +}()); + +/************************************************** + 12495 - cast from string to immutable(ubyte)[] +**************************************************/ + +string getStr12495() +{ + char[1] buf = void; // dummy starting point. + string s = cast(string)buf[0..0]; // empty slice, .ptr points mutable. + assert(buf.ptr == s.ptr); + s ~= 'a'; // this should allocate. + assert(buf.ptr != s.ptr); + return s.idup; // this should allocate again, and + // definitely point immutable memory. +} +auto indexOf12495(string s) +{ + auto p1 = s.ptr; + auto p2 = (cast(immutable(ubyte)[])s).ptr; + assert(cast(void*)p1 == cast(void*)p2); // OK <- fails + return cast(void*)p2 - cast(void*)p1; // OK <- "cannot subtract pointers ..." +} +static assert(indexOf12495(getStr12495()) == 0); + +/************************************************** + 13992 - Repainting pointer arithmetic result +**************************************************/ + +enum hash13992 = hashOf13992("abcd".ptr); + +@trusted hashOf13992(const void* buf) +{ + auto data = cast(const(ubyte)*) buf; + size_t hash; + data += 2; // problematic pointer arithmetic + hash += *data; // CTFE internal issue was shown by the dereference + return hash; +} + +/************************************************** + 13739 - Precise copy for ArrayLiteralExp elements +**************************************************/ + +static assert( +{ + int[] a1 = [13]; + int[][] a2 = [a1]; + assert(a2[0] is a1); // OK + assert(a2[0].ptr is a1.ptr); // OK <- NG + + a1[0] = 1; + assert(a2[0][0] == 1); // OK <- NG + + a2[0][0] = 2; + assert(a1[0] == 2); // OK <- NG + + return 1; +}()); + +/************************************************** + 14463 - ICE on slice assignment without postblit +**************************************************/ + +struct Boo14463 +{ + private int[1] c; + this(int[] x) + { + c = x; + } +} +immutable Boo14463 a14463 = Boo14463([1]); + +/************************************************** + 13295 - Don't copy struct literal in VarExp::interpret() +**************************************************/ + +struct S13295 +{ + int n; +} + +void f13295(ref const S13295 s) +{ + *cast(int*) &s.n = 1; + assert(s.n == 1); // OK <- fail +} + +static assert( +{ + S13295 s; + f13295(s); + return s.n == 1; // true <- false +}()); + +int foo14061(int[] a) +{ + foreach (immutable x; a) + { + auto b = a ~ x; + return b == [1, 1]; + } + return 0; +} +static assert(foo14061([1])); + +/************************************************** + 14024 - CTFE version +**************************************************/ + +bool test14024() +{ + string op; + + struct S + { + char x = 'x'; + this(this) { op ~= x-0x20; } // upper case + ~this() { op ~= x; } // lower case + } + + S[4] mem; + ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; } + + op = null; + mem[0].x = 'a'; + mem[1].x = 'b'; + mem[2].x = 'x'; + mem[3].x = 'y'; + slice(0, 2) = slice(2, 4); // [ab] = [xy] + assert(op == "XaYb", op); + + op = null; + mem[0].x = 'x'; + mem[1].x = 'y'; + mem[2].x = 'a'; + mem[3].x = 'b'; + slice(2, 4) = slice(0, 2); // [ab] = [xy] + assert(op == "XaYb", op); + + op = null; + mem[0].x = 'a'; + mem[1].x = 'b'; + mem[2].x = 'c'; + slice(0, 2) = slice(1, 3); // [ab] = [bc] + assert(op == "BaCb", op); + + op = null; + mem[0].x = 'x'; + mem[1].x = 'y'; + mem[2].x = 'z'; + slice(1, 3) = slice(0, 2); // [yz] = [xy] + assert(op == "YzXy", op); + + return true; +} +static assert(test14024()); + +/************************************************** + 14304 - cache of static immutable value +**************************************************/ + +immutable struct Bug14304 +{ + string s_name; + alias s_name this; + + string fun()() + { + return "fun"; + } +} +class Buggy14304 +{ + static string fun(string str)() + { + return str; + } + static immutable val = immutable Bug14304("val"); +} +void test14304() +{ + enum kt = Buggy14304.fun!(Buggy14304.val); + static assert(kt == "val"); + enum bt = Buggy14304.val.fun(); + static assert(bt == "fun"); +} + +/************************************************** + 14371 - evaluate BinAssignExp as lvalue +**************************************************/ + +int test14371() +{ + int x; + ++(x += 1); + return x; +} +static assert(test14371() == 2); + +/************************************************** + 7151 - [CTFE] cannot compare classes with == +**************************************************/ + +bool test7151() +{ + auto a = new Object; + return a == a && a != new Object; +} +static assert(test7151()); + + +/************************************************** + 12603 - [CTFE] goto does not correctly call dtors +**************************************************/ + +struct S12603 +{ + this(uint* dtorCalled) + { + *dtorCalled = 0; + this.dtorCalled = dtorCalled; + } + + @disable this(); + + ~this() + { + ++*dtorCalled; + } + + uint* dtorCalled; +} + + +auto numDtorCallsByGotoWithinScope() +{ + uint dtorCalled; + { + S12603 s = S12603(&dtorCalled); + assert(dtorCalled == 0); + goto L_abc; + L_abc: + assert(dtorCalled == 0); + } + assert(dtorCalled == 1); + return dtorCalled; +} +static assert(numDtorCallsByGotoWithinScope() == 1); + + +auto numDtorCallsByGotoOutOfScope() +{ + uint dtorCalled; + { + S12603 s = S12603(&dtorCalled); + assert(dtorCalled == 0); + goto L_abc; + } + L_abc: + assert(dtorCalled == 1); + return dtorCalled; +} +static assert(numDtorCallsByGotoOutOfScope() == 1); + + +uint numDtorCallsByGotoDifferentScopeAfter() +{ + uint dtorCalled; + { + S12603 s = S12603(&dtorCalled); + assert(dtorCalled == 0); + } + assert(dtorCalled == 1); + goto L_abc; + L_abc: + assert(dtorCalled == 1); + return dtorCalled; +} +static assert(numDtorCallsByGotoDifferentScopeAfter() == 1); + + +auto numDtorCallsByGotoDifferentScopeBefore() +{ + uint dtorCalled; + assert(dtorCalled == 0); + goto L_abc; + L_abc: + assert(dtorCalled == 0); + { + S12603 s = S12603(&dtorCalled); + assert(dtorCalled == 0); + } + assert(dtorCalled == 1); + return dtorCalled; +} +static assert(numDtorCallsByGotoDifferentScopeBefore() == 1); + + +struct S12603_2 +{ + ~this() + { + dtorCalled = true; + } + + bool dtorCalled = false; +} + +auto structInCaseScope() +{ + auto charsets = S12603_2(); + switch(1) + { + case 0: + auto set = charsets; + break; + default: + break; + } + return charsets.dtorCalled; +} + +static assert(!structInCaseScope()); + +/************************************************** + 15233 - ICE in TupleExp, Copy On Write bug +**************************************************/ + +alias TT15233(stuff ...) = stuff; + +struct Tok15233 {} +enum tup15233 = TT15233!(Tok15233(), "foo"); +static assert(tup15233[0] == Tok15233()); +static assert(tup15233[1] == "foo"); + +/************************************************** + 15251 - void cast in ForStatement.increment +**************************************************/ + +int test15251() +{ + for (ubyte lwr = 19; + lwr != 20; + cast(void)++lwr) // have to to be evaluated with ctfeNeedNothing + {} + return 1; +} +static assert(test15251()); + +/************************************************** + 15998 - Sagfault caused by memory corruption +**************************************************/ + +immutable string[2] foo15998 = ["",""]; +immutable string[2][] bar15998a = foo15998 ~ baz15998; +immutable string[2][] bar15998b = baz15998 ~ foo15998; + +auto baz15998() +{ + immutable(string[2])[] r; + return r; +} + +static assert(bar15998a == [["", ""]]); +static assert(bar15998b == [["", ""]]); + +/************************************************** + 16094 - Non-overlapped slice assignment on an aggregate +**************************************************/ + +char[] f16094a() +{ + char[] x = new char[](6); + x[3..6] = x[0..3]; + return x; +} + +int[] f16094b() +{ + int[] x = new int[](6); + x[3..6] = x[0..3]; + return x; +} + +enum copy16094a = f16094a(); +enum copy16094b = f16094b(); + +/**************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17407 + +bool foo17407() +{ + void delegate ( ) longest_convert; + return __traits(compiles, longest_convert = &doesNotExists); +} + +static assert(!foo17407); + diff --git a/gcc/testsuite/gdc.test/compilable/json.d b/gcc/testsuite/gdc.test/compilable/json.d new file mode 100644 index 00000000000..b5a560dcb2b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/json.d @@ -0,0 +1,113 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -o- -X -Xf${RESULTS_DIR}/compilable/json.out +// POST_SCRIPT: compilable/extra-files/json-postscript.sh +// EXTRA_FILES: imports/jsonimport1.d imports/jsonimport2.d imports/jsonimport3.d imports/jsonimport4.d + +module json; + + +static this() {} + +static ~this() {} + + +alias int myInt; +myInt x; // bug 3404 + +struct Foo(T) { T t; } +class Bar(int T) { int t = T; } +interface Baz(T...) { T[0] t() const; } // bug 3466 + +template P(alias T) {} + +class Bar2 : Bar!1, Baz!(int, 2, null) { + this() {} + ~this() {} // bug 4178 + + static foo() {} + protected abstract Foo!int baz(); + override int t() const { return 0; } +} + +class Bar3 : Bar2 { + private int val; + this(int i) { val = i; } + + protected override Foo!int baz() { return Foo!int(val); } +} + +struct Foo2 { + Bar2 bar2; + union U { + struct { + short s; + int i; + } + Object o; + } +} + +/++ + + Documentation test + +/ +@trusted myInt bar(ref uint blah, Bar2 foo = new Bar3(7)) // bug 4477 +{ + return -1; +} + +@property int outer() nothrow +in { + assert(true); +} +out(result) { + assert(result == 18); +} +body { + int x = 8; + int inner(void* v) nothrow + { + int y = 2; + assert(true); + return x + y; + } + int z = inner(null); + return x + z; +} + +/** Issue 9484 - selective and renamed imports */ +import imports.jsonimport1 : target1, target2; +import imports.jsonimport2 : alias1 = target1, alias2 = target2; +import imports.jsonimport3 : alias3 = target1, alias4 = target2, target3; +import imports.jsonimport4; + +struct S +{ + /** Issue 9480 - Template name should be stripped of parameters */ + this(T)(T t) { } +} + +/** Issue 9755 - Protection not emitted properly for Templates. */ +private struct S1_9755(T) { } +package struct S2_9755(T) { } + +class C_9755 +{ + protected static class CI_9755(T) { } +} + +/** Issue 10011 - init property is wrong for object initializer. */ +const Object c_10011 = new Object(); + +/// +enum Numbers +{ + unspecified1, + one = 2, + two = 3, + FILE_NOT_FOUND = 101, + unspecified3, + unspecified4, + four = 4, +} + +template IncludeConstraint(T) if (T == string) {} diff --git a/gcc/testsuite/gdc.test/compilable/line.d b/gcc/testsuite/gdc.test/compilable/line.d new file mode 100644 index 00000000000..5122ed3cbf8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/line.d @@ -0,0 +1,30 @@ +module line; + +static assert(__LINE__ == 3); + +int #line 10 +x; + +static assert(__LINE__ == 12); +version(Windows) { + static assert(__FILE__ == "compilable\\line.d"); + static assert(__FILE_FULL_PATH__[1..3] == ":\\"); +} else { + static assert(__FILE__ == "compilable/line.d"); + static assert(__FILE_FULL_PATH__[0] == '/'); +} +static assert(__FILE_FULL_PATH__[$-__FILE__.length..$] == __FILE__); + +#line 100 "newfile.d" + +static assert(__LINE__ == 101); +static assert(__FILE__ == "newfile.d"); +static assert(__FILE_FULL_PATH__ == "newfile.d"); + +# line 200 + +static assert(__LINE__ == 201); +static assert(__FILE__ == "newfile.d"); +static assert(__FILE_FULL_PATH__ == "newfile.d"); + + diff --git a/gcc/testsuite/gdc.test/compilable/noderef.d b/gcc/testsuite/gdc.test/compilable/noderef.d new file mode 100644 index 00000000000..eed7b358efb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/noderef.d @@ -0,0 +1,53 @@ +// PERMUTE_ARGS: +// https://github.com/dlang/dmd/pull/5860 + +int[] bar() @safe; + +void foo(int[] a) @safe +{ + static int[] as; + + bool b; + + b = a.ptr == null; + b = null == (*&as).ptr; + b = bar().ptr == null; + + b = a.ptr != null; + b = null != (*&as).ptr; + b = bar().ptr != null; + + b = a.ptr is null; + b = null is (*&as).ptr; + b = bar().ptr is null; + + b = a.ptr !is null; + b = null !is (*&as).ptr; + b = bar().ptr !is null; + + b = !a.ptr; + b = !(*&as).ptr; + b = !bar().ptr; + + b = cast(bool)a.ptr; + b = cast(bool)(*&as).ptr; + b = cast(bool)bar().ptr; + + b = a.ptr ? false : true; + + b = a.ptr < null; + b = null < a.ptr; + + b = a.ptr && null || a.ptr; + + if (a.ptr) + b = true; + + while (a.ptr) + b = true; + + for (; a.ptr;) + b = true; + +// ptrdiff_t d = a.ptr - a.ptr; +} diff --git a/gcc/testsuite/gdc.test/compilable/nogc.d b/gcc/testsuite/gdc.test/compilable/nogc.d new file mode 100644 index 00000000000..c2581da9c26 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/nogc.d @@ -0,0 +1,111 @@ +// REQUIRED_ARGS: -o- + +/***************** Covariance ******************/ + +class C1 +{ + void foo() @nogc; + void bar(); +} + +class D1 : C1 +{ + override void foo(); // no error + override void bar() @nogc; // no error +} + +/******************************************/ +// __traits(compiles) + +static assert(__traits(compiles, new Object())); + +void foo_compiles() {} + +@nogc void test_compiles() +{ + auto fp = &foo_compiles; + static assert(!__traits(compiles, foo_compiles())); + static assert(!__traits(compiles, fp())); + static assert(!__traits(compiles, (*fp)())); + + static assert(!__traits(compiles, [1,2,3])); + static assert(!__traits(compiles, [1:1, 2:2])); + + struct Struct {} + static assert(!__traits(compiles, new int)); + static assert(!__traits(compiles, new Struct())); + static assert(!__traits(compiles, new Object())); + + int* p; + static assert(!__traits(compiles, delete p)); + + int[int] aa; + static assert(!__traits(compiles, aa[0])); + + int[] a; + static assert(!__traits(compiles, a.length = 1)); + static assert(!__traits(compiles, a.length += 1)); + static assert(!__traits(compiles, a.length -= 1)); + + static assert(!__traits(compiles, a ~= 1)); + static assert(!__traits(compiles, a ~ a)); +} + +/******************************************/ +// 12630 + +void test12630() @nogc +{ + // All of these declarations should cause no errors. + + static const ex1 = new Exception("invalid"); + //enum ex2 = new Exception("invalid"); + + static const arr1 = [[1,2], [3, 4]]; + enum arr2 = [[1,2], [3, 4]]; + + //static const aa1 = [1:1, 2:2]; + enum aa2 = [1:1, 2:2]; + + //static const v1 = aa1[1]; + enum v2 = aa2[1]; + + Object o; + //static const del1 = (delete o).sizeof; + //enum del2 = (delete o).sizeof; + + int[] a; + static const len1 = (a.length = 1).sizeof; + enum len2 = (a.length = 1).sizeof; + + static const cata1 = (a ~= 1).sizeof; + enum cata2 = (a ~= 1).sizeof; + + static const cat1 = (a ~ a).sizeof; + enum cat2 = (a ~ a).sizeof; +} + +/******************************************/ +// 12642 + +static if (is(__vector(ulong[2]))) +{ + import core.simd; + + ulong2 test12642() @nogc + { + return [0, 0]; + } +} + +/******************************************/ +// 13550 + +auto foo13550() @nogc +{ + static int[] bar() + { + return new int[2]; + } + return &bar; +} diff --git a/gcc/testsuite/gdc.test/compilable/protattr.d b/gcc/testsuite/gdc.test/compilable/protattr.d new file mode 100644 index 00000000000..ca53a5e7ec4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protattr.d @@ -0,0 +1,5 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: +import protection.basic.tests; +import protection.subpkg.tests; +import protection.subpkg2.tests; diff --git a/gcc/testsuite/gdc.test/compilable/protection.d b/gcc/testsuite/gdc.test/compilable/protection.d new file mode 100644 index 00000000000..3d6198d757c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection.d @@ -0,0 +1,96 @@ +// REQUIRED_ARGS: -de +import imports.protectionimp; + +alias TypeTuple(T...) = T; + +private +{ + void localF() {} + class localC {} + struct localS {} + union localU {} + interface localI {} + enum localE { foo } + mixin template localMT() {} + + class localTC(T) {} + struct localTS(T) {} + union localTU(T) {} + interface localTI(T) {} + void localTF(T)() {} +} + +void main() +{ + // Private non-template declarations + static assert(!__traits(compiles, privF())); + static assert(!__traits(compiles, privC)); + static assert(!__traits(compiles, privS)); + static assert(!__traits(compiles, privU)); + static assert(!__traits(compiles, privI)); + static assert(!__traits(compiles, privE)); + static assert(!__traits(compiles, privMT)); + + // Private local non-template declarations. + static assert( __traits(compiles, localF())); + static assert( __traits(compiles, localC)); + static assert( __traits(compiles, localS)); + static assert( __traits(compiles, localU)); + static assert( __traits(compiles, localI)); + static assert( __traits(compiles, localE)); + static assert( __traits(compiles, localMT)); + + // Private template declarations. + static assert(!__traits(compiles, privTF!int())); + static assert(!__traits(compiles, privTC!int)); + static assert(!__traits(compiles, privTS!int)); + static assert(!__traits(compiles, privTU!int)); + static assert(!__traits(compiles, privTI!int)); + + // Private local template declarations. + static assert( __traits(compiles, localTF!int())); + static assert( __traits(compiles, localTC!int)); + static assert( __traits(compiles, localTS!int)); + static assert( __traits(compiles, localTU!int)); + static assert( __traits(compiles, localTI!int)); + + // Public template function with private type parameters. + static assert(!__traits(compiles, publF!privC())); + static assert(!__traits(compiles, publF!privS())); + static assert(!__traits(compiles, publF!privU())); + static assert(!__traits(compiles, publF!privI())); + static assert(!__traits(compiles, publF!privE())); + + // Public template function with private alias parameters. + static assert(!__traits(compiles, publFA!privC())); + static assert(!__traits(compiles, publFA!privS())); + static assert(!__traits(compiles, publFA!privU())); + static assert(!__traits(compiles, publFA!privI())); + static assert(!__traits(compiles, publFA!privE())); + + // Private alias. + static assert(!__traits(compiles, privA)); + + // Public template mixin. + static assert( __traits(compiles, publMT)); +} + +/***************************************************/ +// 14169 + +template staticMap14169(alias fun, T...) +{ + static if (T.length > 0) + alias staticMap14169 = TypeTuple!(fun!(T[0]), staticMap14169!(fun, T[1..$])); + else + alias staticMap14169 = TypeTuple!(); +} + +class C14169 +{ + private struct InnerStruct(string NameS) + { + alias Name = NameS; + } + alias DimensionNames = staticMap14169!(GetName14169, InnerStruct!"A"); +} diff --git a/gcc/testsuite/gdc.test/compilable/protection/aggregate/mod14275.d b/gcc/testsuite/gdc.test/compilable/protection/aggregate/mod14275.d new file mode 100644 index 00000000000..a6bcb415c62 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection/aggregate/mod14275.d @@ -0,0 +1,11 @@ +module protection.aggregate.mod14275; + +public struct Foo +{ + package(protection) void foo() {} + package void foo2() {} +} + +package(protection) void bar() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/protection/basic/mod1.d b/gcc/testsuite/gdc.test/compilable/protection/basic/mod1.d new file mode 100644 index 00000000000..76527bd5ca7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection/basic/mod1.d @@ -0,0 +1,13 @@ +module protection.basic.mod1; + +public void publicFoo() {} +package void packageFoo() {} +private void privateFoo() {} + +class Test +{ + public void publicFoo(); + protected void protectedFoo(); + package void packageFoo(); + private void privateFoo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/protection/basic/tests.d b/gcc/testsuite/gdc.test/compilable/protection/basic/tests.d new file mode 100644 index 00000000000..6d3ee5aa25d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection/basic/tests.d @@ -0,0 +1,23 @@ +module protection.basic.tests; + +import protection.basic.mod1; + +static assert ( is(typeof(publicFoo()))); +static assert ( is(typeof(packageFoo()))); +static assert (!is(typeof(privateFoo()))); + +static assert ( is(typeof(Test.init.publicFoo()))); +static assert (!is(typeof(Test.init.protectedFoo()))); +static assert ( is(typeof(Test.init.packageFoo()))); +static assert (!is(typeof(Test.init.privateFoo()))); + +class Deriv : Test +{ + void stub() + { + static assert ( is(typeof(this.publicFoo()))); + static assert ( is(typeof(this.protectedFoo()))); + static assert ( is(typeof(this.packageFoo()))); + static assert (!is(typeof(this.privateFoo()))); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/protection/bug/bug14275.d b/gcc/testsuite/gdc.test/compilable/protection/bug/bug14275.d new file mode 100644 index 00000000000..90b7ea7a03a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection/bug/bug14275.d @@ -0,0 +1,12 @@ +module protection.bug.bug14275; + +import protection.aggregate.mod14275; + +// https://issues.dlang.org/show_bug.cgi?id=14275 + +void main() { + Foo f; + f.foo(); + static assert (!is(typeof(f.foo2()))); + bar(); +} diff --git a/gcc/testsuite/gdc.test/compilable/protection/subpkg/explicit.d b/gcc/testsuite/gdc.test/compilable/protection/subpkg/explicit.d new file mode 100644 index 00000000000..306ec9f2866 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection/subpkg/explicit.d @@ -0,0 +1,4 @@ +module protection.subpkg.explicit; + +package(protection) void commonAncestorFoo(); +package(protection.subpkg) void samePkgFoo(); diff --git a/gcc/testsuite/gdc.test/compilable/protection/subpkg/tests.d b/gcc/testsuite/gdc.test/compilable/protection/subpkg/tests.d new file mode 100644 index 00000000000..0e8c716d3cf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection/subpkg/tests.d @@ -0,0 +1,12 @@ +module protection.subpkg.tests; + +import crosspkg = protection.basic.mod1; + +static assert ( is(typeof(crosspkg.publicFoo()))); +static assert (!is(typeof(crosspkg.packageFoo()))); +static assert (!is(typeof(crosspkg.privateFoo()))); + +import samepkg = protection.subpkg.explicit; + +static assert ( is(typeof(samepkg.commonAncestorFoo()))); +static assert ( is(typeof(samepkg.samePkgFoo()))); diff --git a/gcc/testsuite/gdc.test/compilable/protection/subpkg2/tests.d b/gcc/testsuite/gdc.test/compilable/protection/subpkg2/tests.d new file mode 100644 index 00000000000..9458a8e6b96 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/protection/subpkg2/tests.d @@ -0,0 +1,5 @@ +module protection.subpkg2.tests; + +import pkg = protection.subpkg.explicit; + +static assert (is(typeof(pkg.commonAncestorFoo()))); diff --git a/gcc/testsuite/gdc.test/compilable/pull6815.d b/gcc/testsuite/gdc.test/compilable/pull6815.d new file mode 100644 index 00000000000..0debf07de42 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/pull6815.d @@ -0,0 +1,9 @@ +/* REQUIRED_ARGS: -inline -Icompilable/extra-files + EXTRA_FILES: extra-files/e6815.d + */ + +void b() +{ + import e6815 : e; + e(""); +} diff --git a/gcc/testsuite/gdc.test/compilable/riia_ctor.d b/gcc/testsuite/gdc.test/compilable/riia_ctor.d new file mode 100644 index 00000000000..1c8e142b796 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/riia_ctor.d @@ -0,0 +1,44 @@ +// https://issues.dlang.org/show_bug.cgi?id=17494 +struct S +{ + ~this() {} +} + +class C +{ + S s; + + this() nothrow {} +} + +// https://issues.dlang.org/show_bug.cgi?id=17505 +struct Array +{ + int[] _payload; + ~this() + { + import core.stdc.stdlib : free; + free(_payload.ptr); + } +} + +class Scanner +{ + Array arr; + this() @safe {} +} + +// https://issues.dlang.org/show_bug.cgi?id=17506 +struct TreeMap +{ + this() @disable; + this(TTree tree) { this.tree = tree; } + TTree tree; +} + +struct TTree +{ + this() @disable; + this(int foo) {} + ~this() {} +} diff --git a/gcc/testsuite/gdc.test/compilable/scope.d b/gcc/testsuite/gdc.test/compilable/scope.d new file mode 100644 index 00000000000..4f53730df1f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/scope.d @@ -0,0 +1,14 @@ +/* + currently fails with extra safety checks + PERMUTE_FIXME_ARGS: -dip1000 +*/ + +struct Cache +{ + ubyte[1] v; + + ubyte[] set(ubyte[1] v) + { + return this.v[] = v[]; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/shared_destructor.d b/gcc/testsuite/gdc.test/compilable/shared_destructor.d new file mode 100644 index 00000000000..534bb4c7b7d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/shared_destructor.d @@ -0,0 +1,21 @@ +struct MaybeShared +{ + this(this T)() + { + + } + + ~this() + { + + } +} + +void main() { + { + auto aboutToDie = MaybeShared(); + } + { + auto aboutToDie = shared MaybeShared(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/sw_transition_complex.d b/gcc/testsuite/gdc.test/compilable/sw_transition_complex.d new file mode 100644 index 00000000000..f034c69e99e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/sw_transition_complex.d @@ -0,0 +1,136 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -c -transition=complex + +/* +TEST_OUTPUT: +--- +compilable/sw_transition_complex.d(15): use of complex type 'creal' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(16): use of complex type 'cdouble' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead +compilable/sw_transition_complex.d(17): use of complex type 'cfloat' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead +compilable/sw_transition_complex.d(19): use of imaginary type 'ireal' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(20): use of imaginary type 'idouble' is scheduled for deprecation, use 'double' instead +compilable/sw_transition_complex.d(21): use of imaginary type 'ifloat' is scheduled for deprecation, use 'float' instead +--- +*/ +creal c80value; +cdouble c64value; +cfloat c32value; + +ireal i80value; +idouble i64value; +ifloat i32value; + +/* +TEST_OUTPUT: +--- +compilable/sw_transition_complex.d(34): use of complex type 'creal*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(35): use of complex type 'cdouble*' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead +compilable/sw_transition_complex.d(36): use of complex type 'cfloat*' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead +compilable/sw_transition_complex.d(38): use of imaginary type 'ireal*' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(39): use of imaginary type 'idouble*' is scheduled for deprecation, use 'double' instead +compilable/sw_transition_complex.d(40): use of imaginary type 'ifloat*' is scheduled for deprecation, use 'float' instead +--- +*/ +creal* c80pointer; +cdouble* c64pointer; +cfloat* c32pointer; + +ireal* i80pointer; +idouble* i64pointer; +ifloat* i32pointer; + +/* +TEST_OUTPUT: +--- +compilable/sw_transition_complex.d(53): use of complex type 'creal[]*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(54): use of complex type 'cdouble[]*' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead +compilable/sw_transition_complex.d(55): use of complex type 'cfloat[]*' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead +compilable/sw_transition_complex.d(57): use of imaginary type 'ireal[]*' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(58): use of imaginary type 'idouble[]*' is scheduled for deprecation, use 'double' instead +compilable/sw_transition_complex.d(59): use of imaginary type 'ifloat[]*' is scheduled for deprecation, use 'float' instead +--- +*/ +creal[]* c80arrayp; +cdouble[]* d64arrayp; +cfloat[]* c32arrayp; + +ireal[]* i80arrayp; +idouble[]* i64arrayp; +ifloat[]* i32arrayp; + +/* +TEST_OUTPUT: +--- +compilable/sw_transition_complex.d(72): use of complex type 'creal[4][]*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(73): use of complex type 'cdouble[4][]*' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead +compilable/sw_transition_complex.d(74): use of complex type 'cfloat[4][]*' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead +compilable/sw_transition_complex.d(76): use of imaginary type 'ireal[4][]*' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(77): use of imaginary type 'idouble[4][]*' is scheduled for deprecation, use 'double' instead +compilable/sw_transition_complex.d(78): use of imaginary type 'ifloat[4][]*' is scheduled for deprecation, use 'float' instead +--- +*/ +creal[4][]* c80sarrayp; +cdouble[4][]* c64sarrayp; +cfloat[4][]* c32sarrayp; + +ireal[4][]* i80sarrayp; +idouble[4][]* i64sarrayp; +ifloat[4][]* i32sarrayp; + +/* +TEST_OUTPUT: +--- +compilable/sw_transition_complex.d(96): use of complex type 'creal' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(97): use of complex type 'creal*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(98): use of complex type 'creal[]' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(99): use of complex type 'creal[4]' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(101): use of imaginary type 'ireal' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(102): use of imaginary type 'ireal*' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(103): use of imaginary type 'ireal[]' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(104): use of imaginary type 'ireal[4]' is scheduled for deprecation, use 'real' instead +--- +*/ +alias C14488 = creal; +alias I14488 = ireal; + +C14488 calias1; +C14488* calias2; +C14488[] calias3; +C14488[4] calias4; + +I14488 ialias1; +I14488* ialias2; +I14488[] ialias3; +I14488[4] ialias4; + +/* +TEST_OUTPUT: +--- +compilable/sw_transition_complex.d(115): use of complex type 'cdouble' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead +compilable/sw_transition_complex.d(116): use of imaginary type 'idouble' is scheduled for deprecation, use 'double' instead +compilable/sw_transition_complex.d(117): use of complex type 'cdouble' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead +compilable/sw_transition_complex.d(118): use of complex type 'cdouble[]' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead +--- +*/ +auto cauto = 1 + 0i; +auto iauto = 1i; +size_t c64sizeof = (cdouble).sizeof; +TypeInfo c64ti = typeid(cdouble[]); + +/* +TEST_OUTPUT: +--- +compilable/sw_transition_complex.d(128): use of complex type 'creal*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +compilable/sw_transition_complex.d(128): use of imaginary type 'ireal' is scheduled for deprecation, use 'real' instead +compilable/sw_transition_complex.d(132): use of complex type 'creal' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead +--- +*/ +void test14488a(creal *p, real r, ireal i) +{ +} + +creal test14488b() +{ + return 1 + 0i; +} + diff --git a/gcc/testsuite/gdc.test/compilable/sw_transition_field.d b/gcc/testsuite/gdc.test/compilable/sw_transition_field.d new file mode 100644 index 00000000000..83dd2617459 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/sw_transition_field.d @@ -0,0 +1,25 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -c -transition=field +/* +TEST_OUTPUT: +--- +compilable/sw_transition_field.d(15): sw_transition_field.S1.ix is immutable field +compilable/sw_transition_field.d(16): sw_transition_field.S1.cx is const field +compilable/sw_transition_field.d(21): sw_transition_field.S2!(immutable(int)).S2.f is immutable field +compilable/sw_transition_field.d(21): sw_transition_field.S2!(const(int)).S2.f is const field +--- +*/ + +struct S1 +{ + immutable int ix = 1; + const int cx = 2; +} + +struct S2(F) +{ + F f = F.init; +} + +alias S2!(immutable int) S2I; +alias S2!( const int) S2C; diff --git a/gcc/testsuite/gdc.test/compilable/sw_transition_tls.d b/gcc/testsuite/gdc.test/compilable/sw_transition_tls.d new file mode 100644 index 00000000000..1085e80c401 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/sw_transition_tls.d @@ -0,0 +1,16 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -c -transition=tls +/* +TEST_OUTPUT: +--- +compilable/sw_transition_tls.d(11): x is thread local +compilable/sw_transition_tls.d(15): y is thread local +--- +*/ + +int x; + +struct S +{ + static int y; +} diff --git a/gcc/testsuite/gdc.test/compilable/test1.d b/gcc/testsuite/gdc.test/compilable/test1.d new file mode 100644 index 00000000000..80c382b5e71 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test1.d @@ -0,0 +1,13 @@ +// PERMUTE_ARGS: + +class File +{ + import imports.test1imp; + + static char[] read(char[] name) + { + DWORD size; // DWORD is defined in test1imp + return null; + } + +} diff --git a/gcc/testsuite/gdc.test/compilable/test10056.d b/gcc/testsuite/gdc.test/compilable/test10056.d new file mode 100644 index 00000000000..ec076d5d24d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10056.d @@ -0,0 +1,66 @@ +void main() +{ + alias Zoo = Foo10056!(false, false, 1); +} + +struct Foo10056(bool S, bool L, size_t N) +{ + string bar() + { + Appender10056!(string) w; + char[] buf; put10056(w, buf); + return ""; + } + + public bool opEquals(T)(T other) //const + //If you add const, also fails to compile with 2.062. + { + alias Foo10056!(typeof(this), T, "CMP") P; + return false; + } +} + +template Foo10056(T, U, string OP) +{ + static if (T.ISEMPTY && U.ISEMPTY) + enum bool S = false; + else + enum bool S = false; + + alias Foo10056 = Foo10056!(false, false, 0); +} + +/**********************************************/ + +void put10056(R, E)(ref R r, E e) +{ + static if (is(typeof(r.put(e)))) + { + r.put(e); + } + else + { + static assert(false, "Cannot put a "~E.stringof~" into a "~R.stringof); + } +} + +struct Appender10056(A : T[], T) +{ + private template canPutItem(U) + { + enum bool canPutItem = is(U : T); + } + private template canPutRange(R) + { + enum bool canPutRange = is(typeof(Appender10056.init.put(R.init[0]))); + } + + void put(U)(U item) if (canPutItem!U) + { + char[T.sizeof == 1 ? 4 : 2] encoded; + put(encoded[]); + } + void put(R)(R items) if (canPutRange!R) + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test10066.d b/gcc/testsuite/gdc.test/compilable/test10066.d new file mode 100644 index 00000000000..fc3ffe2cb3c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10066.d @@ -0,0 +1,66 @@ +void main() +{ + alias Zoo = Foo!(1); +} + +struct Foo(size_t N) +{ + string bar() + { + Appender!(string) w; + char[] buf; put(w, buf); + return ""; + } + + public bool opEquals(T)(T other) const + // Add const, different from bug 10056 + { + alias Foo!(typeof(this), T, "CMP") P; + return false; + } +} + +template Foo(T, U, string OP) +{ + static if (T.ISEMPTY && U.ISEMPTY) + enum bool S = false; + else + enum bool S = false; + + alias Foo = Foo!(0); +} + +/**********************************************/ + +void put(R, E)(ref R r, E e) +{ + static if (is(typeof(r.put(e)))) + { + r.put(e); + } + else + { + static assert(false, "Cannot put a "~E.stringof~" into a "~R.stringof); + } +} + +struct Appender(A : T[], T) +{ + private template canPutItem(U) + { + enum bool canPutItem = is(U : T); + } + private template canPutRange(R) + { + enum bool canPutRange = is(typeof(Appender.init.put(R.init[0]))); + } + + void put(U)(U item) if (canPutItem!U) + { + char[T.sizeof == 1 ? 4 : 2] encoded; + put(encoded[]); + } + void put(R)(R items) if (canPutRange!R) + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test10073.d b/gcc/testsuite/gdc.test/compilable/test10073.d new file mode 100644 index 00000000000..1faf6bf18e4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10073.d @@ -0,0 +1,24 @@ +struct Arr(T) +{ + T[] dArr; + alias dArr this; + bool opEquals(Arr!T d) + { + foreach (idx, it; d) + { + if (this[idx] != it) + { + return false; + } + } + return true; + } +} + +class Bar +{ + Arr!Foo fooQ; +} + +class Foo {} // NG + diff --git a/gcc/testsuite/gdc.test/compilable/test10186.d b/gcc/testsuite/gdc.test/compilable/test10186.d new file mode 100644 index 00000000000..d7eccbc7e38 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10186.d @@ -0,0 +1,27 @@ +struct S { + @disable this(); + + this(int i) { + } +} + +class C { + this() { + s = S(1); + } + + S s; +} + +class CR +{ + S s; + + this() { + s = S(1); + } +} + +void main() { + auto c = new C; +} diff --git a/gcc/testsuite/gdc.test/compilable/test10312.d b/gcc/testsuite/gdc.test/compilable/test10312.d new file mode 100644 index 00000000000..db56bc2b5e2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10312.d @@ -0,0 +1,11 @@ + +version(D_SIMD) +{ + const __vector(float[4]) si = [1f, 1f, 1f, 1f]; + + void main() + { + auto arr = si; + return; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test10375.d b/gcc/testsuite/gdc.test/compilable/test10375.d new file mode 100644 index 00000000000..b9704f6a244 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10375.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -o- + +import imports.test10375a; + +void packIt(Pack)(Pack p){ } //3 + +void main() +{ + alias p = packIt!(int); + p(2); // OK <- NG + packIt(2); // OK <- NG + packIt!(int)(2); // OK <- NG +} diff --git a/gcc/testsuite/gdc.test/compilable/test10520.d b/gcc/testsuite/gdc.test/compilable/test10520.d new file mode 100644 index 00000000000..9a24d840527 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10520.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -debug -profile + +// Issue 10520 [profile+nothrow] Building with profiler results in "is not nothrow" error on some contracts + +void f() { } + +void g()() +in { f(); } // OK <- Error: 'main.f' is not nothrow +body { } + +alias gi = g!(); diff --git a/gcc/testsuite/gdc.test/compilable/test10695.d b/gcc/testsuite/gdc.test/compilable/test10695.d new file mode 100644 index 00000000000..c4894cd0a8b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10695.d @@ -0,0 +1,9 @@ +// PERMUTE_ARGS: +module a; + +void main() +{ + mixin("string mod1 = __MODULE__;"); + mixin("enum mod2 = __MODULE__;"); + static assert(mod2 == "a"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test10726.d b/gcc/testsuite/gdc.test/compilable/test10726.d new file mode 100644 index 00000000000..3db2f807ab2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10726.d @@ -0,0 +1,53 @@ +// PERMUTE_ARGS: + +public struct CirBuff(T) +{ + private T[] data; + private size_t head = 0; + private size_t size = 0; + public size_t length() const { return size; } + + public bool opEquals(CirBuff!T d) @trusted + { + if (length != d.length) + return false; + for (size_t i=0; i!=size; ++i) + { + if (this.data[(this.head+i) % this.data.length] != + d.data[(d.head + i) % d.data.length]) + { + return false; + } + } + return true; + } +} + +class Once +{ + Foo!Bar _bar; +} + +class Bar +{ + static Once _once; + mixin(sync!(Once, "_once")); +} + +class Foo(T = int) +{ + CirBuff!T _buff; +} + +template sync(T, string U = "this", size_t ITER = 0) +{ + static if (ITER == __traits(derivedMembers, T).length) + enum sync = ""; + else + { + enum string mem = __traits(derivedMembers, T)[ITER]; + enum string sync = + "static if(! __traits(isVirtualMethod, " ~ U ~ "." ~ mem ~ ")) { }" + ~ sync!(T, U, ITER+1); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test10752.d b/gcc/testsuite/gdc.test/compilable/test10752.d new file mode 100644 index 00000000000..449377e3f06 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10752.d @@ -0,0 +1,6 @@ +import imports.test10752; +void main() +{ + static assert(!__traits(compiles, priv)); + static assert(!__traits(compiles, priv)); +} diff --git a/gcc/testsuite/gdc.test/compilable/test10981.d b/gcc/testsuite/gdc.test/compilable/test10981.d new file mode 100644 index 00000000000..f0a6820fa7e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10981.d @@ -0,0 +1,24 @@ +void foo(int i) +in +{ + class X1 + { + void in_nested() pure + in { assert(i); } // OK <- NG + out { assert(i); } // OK <- NG + body {} + } +} +out +{ + class X2 + { + void out_nested() pure + in { assert(i); } // OK <- NG + out { assert(i); } // OK <- NG + body {} + } +} +body +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/test10992.d b/gcc/testsuite/gdc.test/compilable/test10992.d new file mode 100644 index 00000000000..8462939ed79 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10992.d @@ -0,0 +1,11 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -unittest + +unittest { } +unittest { } +unittest { } + +void main() +{ + static assert(__traits(getUnitTests, mixin(__MODULE__)).length == 3); +} diff --git a/gcc/testsuite/gdc.test/compilable/test10992b.d b/gcc/testsuite/gdc.test/compilable/test10992b.d new file mode 100644 index 00000000000..67c7d41d71c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10992b.d @@ -0,0 +1,16 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -unittest + +version(none) +{} +else +{ + unittest { } + unittest { } + unittest { } +} + +void main() +{ + static assert(__traits(getUnitTests, mixin(__MODULE__)).length == 3); +} diff --git a/gcc/testsuite/gdc.test/compilable/test10993.d b/gcc/testsuite/gdc.test/compilable/test10993.d new file mode 100644 index 00000000000..e5a1b847976 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10993.d @@ -0,0 +1,33 @@ +module test10993; + +auto foo(T)(T a) +{ + static immutable typeof(a) q; +// pragma(msg, "foo: " ~ typeof(q).mangleof); + return q; +} + +struct test(alias fn) +{ + bool ini = true; + void* p; +} + +auto fun() +{ + auto x = foo!()(test!(a=>a)()); +// pragma(msg, "fun: " ~ typeof(x).mangleof); + + return x; +} + +void main() +{ + const x = fun(); + enum mangle_x = typeof(x).mangleof; +// pragma(msg, "x : " ~ mangle_x); + auto y = cast()x; + enum mangle_y = typeof(y).mangleof; +// pragma(msg, "y : " ~ mangle_y); + static assert (mangle_y == mangle_x[1..$]); +} diff --git a/gcc/testsuite/gdc.test/compilable/test11169.d b/gcc/testsuite/gdc.test/compilable/test11169.d new file mode 100644 index 00000000000..10a3df2c7a6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11169.d @@ -0,0 +1,45 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +1: false +2: true +3: true +--- +*/ + +class A +{ + abstract void foo(); +} + +template MixinAbstractBar() { abstract void bar(); } + +class B1 : A +{ + // Use pragma instead of static assert, in order to evaluate + // __traits during ClassDeclaration.semantic(). + pragma(msg, "1: ", __traits(isAbstractClass, typeof(this))); + override void foo() {} +} + +class B2 : A +{ + pragma(msg, "2: ", __traits(isAbstractClass, typeof(this))); + override void foo() {} + abstract void bar(); +} + +class B3 : A +{ + pragma(msg, "3: ", __traits(isAbstractClass, typeof(this))); + override void foo() {} + mixin MixinAbstractBar!(); +} + +void main() +{ + static assert( __traits(compiles, { auto b = new B1(); })); + static assert(!__traits(compiles, { auto b = new B2(); })); + static assert(!__traits(compiles, { auto b = new B3(); })); +} diff --git a/gcc/testsuite/gdc.test/compilable/test11225a.d b/gcc/testsuite/gdc.test/compilable/test11225a.d new file mode 100644 index 00000000000..58df82793e3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11225a.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +WORKS +--- +*/ + +import imports.test11225b; +interface I {} diff --git a/gcc/testsuite/gdc.test/compilable/test11237.d b/gcc/testsuite/gdc.test/compilable/test11237.d new file mode 100644 index 00000000000..1700af426f7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11237.d @@ -0,0 +1,4 @@ +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/test11237.sh + +struct Buffer { ubyte[64 * 1024] buffer; } diff --git a/gcc/testsuite/gdc.test/compilable/test11371.d b/gcc/testsuite/gdc.test/compilable/test11371.d new file mode 100644 index 00000000000..c5229292a62 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11371.d @@ -0,0 +1,11 @@ + +version(D_SIMD) +{ + __vector(long[2]) f() + { + __vector(long[2]) q; + return q; + } + + enum __vector(long[2]) v = f(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test11471.d b/gcc/testsuite/gdc.test/compilable/test11471.d new file mode 100644 index 00000000000..1df7e80f20a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11471.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -profile + +void main() nothrow +{ + // Error: asm statements are assumed to throw + version(GNU) + asm { ""; } + else + asm { nop; } +} diff --git a/gcc/testsuite/gdc.test/compilable/test11559upgradeoptlink.d b/gcc/testsuite/gdc.test/compilable/test11559upgradeoptlink.d new file mode 100644 index 00000000000..b61ffc81d27 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11559upgradeoptlink.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -g + +// If this is failing, you need optlink 8.00.14 or higher + +string gen() +{ + string m; + foreach(i; 0..4096) + m ~= "mixin(\"assert(0);\n\n\n\n\");\n"; + return m; +} + +void main() +{ + mixin(gen()); +} diff --git a/gcc/testsuite/gdc.test/compilable/test11563.d b/gcc/testsuite/gdc.test/compilable/test11563.d new file mode 100644 index 00000000000..b208215bdb6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11563.d @@ -0,0 +1,9 @@ +import imports.test11563std_traits; + +interface J : I {} // comment out to let compilation succeed + +struct A { } +pragma(msg, moduleName!A); + + +interface I {} diff --git a/gcc/testsuite/gdc.test/compilable/test11656.d b/gcc/testsuite/gdc.test/compilable/test11656.d new file mode 100644 index 00000000000..4de3065088d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11656.d @@ -0,0 +1,10 @@ + +version(D_SIMD) +{ + struct Foo + { + __vector(float[4]) x; + } + static assert(Foo.x.offsetof == 0); + static assert(Foo.x.stringof == "x"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test11824.d b/gcc/testsuite/gdc.test/compilable/test11824.d new file mode 100644 index 00000000000..0ec0dd63e48 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11824.d @@ -0,0 +1,72 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +struct Take(R) +{ + public R source; + private size_t _maxAvailable; + + alias R Source; + + @property bool empty() + { + return _maxAvailable == 0 || source.empty; + } + + @property auto ref front() + { + return source.front; + } + + void popFront() + { + source.popFront(); + --_maxAvailable; + } + + @property size_t length() const + { + return _maxAvailable; + } +} + +struct Repeat(T) +{ + private T _value; + + enum bool empty = false; + @property inout(T) front() inout { return _value; } + void popFront() {} +} + +Take!(Repeat!T) repeat(T)(T value, size_t n) +{ + return typeof(return)(Repeat!T(value), n); +} + +auto array(Range)(Range r) +{ + alias E = typeof(r.front); + //static if (hasLength!Range) + { + if (r.length == 0) + return null; + + auto result = new E[](r.length); + + size_t i; + static auto trustedGetAddr(T)(ref T t) @trusted nothrow pure + { + return &t; + } + foreach (e; r) + { + *trustedGetAddr(result[i]) = e; + ++i; + } + return cast(E[])result; + } +} + +enum r = [1].repeat(1).array; +static assert(r == [[1]]); diff --git a/gcc/testsuite/gdc.test/compilable/test11914.d b/gcc/testsuite/gdc.test/compilable/test11914.d new file mode 100644 index 00000000000..f3195f1abe1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11914.d @@ -0,0 +1,118 @@ +// std.array +@property bool empty(T)(in T[] a) { return !a.length; } +@property ref T front(T)(T[] a) { return a[0]; } +void popFront(T)(ref T[] a) { a = a[1 .. $]; } + +// std.typecons +struct Tuple(T...) +{ + T field; + alias field this; +} +Tuple!T tuple(T...)(T args) { return typeof(return)(args); } + +// std.range +template ElementType(R) +{ + static if (is(typeof(R.init.front.init) T)) + alias T ElementType; + else + alias void ElementType; +} + +struct Repeat(T) +{ + private T _value; + + enum bool empty = false; + @property inout(T) front() inout { return _value; } + void popFront() {} +} +Repeat!T repeat(T)(T value) { return Repeat!T(value); } + +struct Zip(R...) +{ + //alias Tuple!(staticMap!(.ElementType, R)) ElementType; + static if (R.length == 3) + alias Tuple!(int, int, int) ElementType; + static if (R.length == 2) + alias Tuple!(int, int) ElementType; + + R ranges; + + this(R rs) + { + foreach (i, Unused; R) + { + ranges[i] = rs[i]; + } + } + + @property bool empty() + { + foreach (i, Unused; R) + { + if (ranges[i].empty) + return true; + } + return false; + } + @property ElementType front() + { + ElementType result; + return result; + } + void popFront() + { + foreach (i, Unused; R) + { + ranges[i].popFront(); + } + } + + ElementType opIndex(size_t n) + { + ElementType result; + return result; + } +} +auto zip(Rs...)(Rs ranges) { return Zip!Rs(ranges); } + +// std.algorithm +template map(fun...) +{ + auto map(Range)(Range r) + { + return MapResult!(fun, Range)(r); + } +} +private struct MapResult(alias fun, R) +{ + R _input; + + this(R input) + { + _input = input; + } + + @property bool empty() { return _input.empty; } + @property auto ref front() { return fun(_input.front); } + void popFront() { _input.popFront(); } +} + +auto cartesianProduct(R1, R2)(R1 range1, R2 range2) +{ + return range2.map!((ElementType!R2 a) => zip(range1, repeat(a))); +} +auto cartesianProduct(R1, R2, RR...)(R1 range1, R2 range2, RR otherRanges) +{ + return map!(a => tuple(a[0], a[1][0], a[1][1]))( + cartesianProduct(range1, cartesianProduct(range2, otherRanges)) + ); +} + +// test +void main() +{ + foreach (i, j, k; cartesianProduct([1], [1], [1])) {} +} diff --git a/gcc/testsuite/gdc.test/compilable/test11980.d b/gcc/testsuite/gdc.test/compilable/test11980.d new file mode 100644 index 00000000000..27974e42451 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test11980.d @@ -0,0 +1,2 @@ +void start() {} +pragma(startaddress, start); diff --git a/gcc/testsuite/gdc.test/compilable/test12009.d b/gcc/testsuite/gdc.test/compilable/test12009.d new file mode 100644 index 00000000000..be6049bf757 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12009.d @@ -0,0 +1,36 @@ +struct RefCounted(T) +{ + struct RefCountedStore + { + private struct Impl + { + T _payload; + } + + private Impl* _store; + } + RefCountedStore _refCounted; + + ~this() + { + import core.stdc.stdlib : free; + } +} + +struct GroupBy(R) +{ + struct SharedInput + { + Group unused; + } + + struct Group + { + private RefCounted!SharedInput _allGroups; + } +} + +void main() +{ + GroupBy!(int[]) g1; +} diff --git a/gcc/testsuite/gdc.test/compilable/test1238.d b/gcc/testsuite/gdc.test/compilable/test1238.d new file mode 100644 index 00000000000..fa19d619b04 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test1238.d @@ -0,0 +1,10 @@ +module test1238; + +import imports.test1238a; +import imports.test1238b; + +void foo() +{ + int qwert = zuiop; +} + diff --git a/gcc/testsuite/gdc.test/compilable/test12523.d b/gcc/testsuite/gdc.test/compilable/test12523.d new file mode 100644 index 00000000000..8a8eae15097 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12523.d @@ -0,0 +1,15 @@ +void test12523(inout(int)) +{ + void check(T)() + { + T[] a; + foreach (ref e; a) + static assert(is(typeof(e) == T)); + } + + check!(int)(); + check!(inout(int))(); + check!(inout(const(int)))(); + check!(const(int))(); + check!(immutable(int))(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test12527.d b/gcc/testsuite/gdc.test/compilable/test12527.d new file mode 100644 index 00000000000..b075b9ede03 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12527.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=12527 + +@system: + alias Fun = void function() @safe; + pragma (msg, Fun.stringof); + static assert(Fun.stringof == "void function() @safe"); + alias Del = void delegate() @safe; + pragma (msg, Del.stringof); + static assert(Del.stringof == "void delegate() @safe"); + diff --git a/gcc/testsuite/gdc.test/compilable/test12558.d b/gcc/testsuite/gdc.test/compilable/test12558.d new file mode 100644 index 00000000000..580cf60cb42 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12558.d @@ -0,0 +1,39 @@ +// REQUIRED_ARGS: +/* +TEST_OUTPUT: +--- +compilable/test12558.d(16): Deprecation: catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior +compilable/test12558.d(21): Deprecation: catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior +--- +*/ + +void main() +{ + auto handler = () { }; + + try { + assert(0); + } catch + handler(); + + try { + assert(0); + } catch { + handler(); + } + + // ensure diagnostics are not emitted for verioned-out blocks + version (none) + { + try { + assert(0); + } catch // should not emit diagnostics + handler(); + + try { + assert(0); + } catch { // ditto + handler(); + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test12567a.d b/gcc/testsuite/gdc.test/compilable/test12567a.d new file mode 100644 index 00000000000..53cc377e632 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12567a.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +--- +*/ +deprecated +module test12567a; + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/test12567b.d b/gcc/testsuite/gdc.test/compilable/test12567b.d new file mode 100644 index 00000000000..2e37d31c786 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12567b.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +--- +*/ +deprecated("message") +module test12567b; + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/test12567c.d b/gcc/testsuite/gdc.test/compilable/test12567c.d new file mode 100644 index 00000000000..cadc375bf0b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12567c.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +compilable/test12567c.d(9): Deprecation: module imports.a12567 is deprecated - This module will be removed in future release. +--- +*/ +import imports.a12567; + +void main() { foo(); } diff --git a/gcc/testsuite/gdc.test/compilable/test12567d.d b/gcc/testsuite/gdc.test/compilable/test12567d.d new file mode 100644 index 00000000000..512f0b76e23 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12567d.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -d +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +--- +*/ +import imports.a12567; + +void main() { foo(); } diff --git a/gcc/testsuite/gdc.test/compilable/test12593.d b/gcc/testsuite/gdc.test/compilable/test12593.d new file mode 100644 index 00000000000..1b2dcacc0d2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12593.d @@ -0,0 +1,12 @@ +int[R] aa; // Place before the declaration of key struct + +struct R +{ + int opCmp(ref const R) const { return 0; } + + //bool opEquals(ref const R) const { return true; } + //size_t toHash() const nothrow @safe { return 0; } +} + +void main() +{} diff --git a/gcc/testsuite/gdc.test/compilable/test12624.d b/gcc/testsuite/gdc.test/compilable/test12624.d new file mode 100644 index 00000000000..f262a59abad --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12624.d @@ -0,0 +1,31 @@ +// REQUIRED_ARGS: -lib -Icompilable/extra-files +// EXTRA_FILES: extra-files/imp12624.d +// https://issues.dlang.org/show_bug.cgi?id=12624 + +struct SysTime +{ + import imp12624; + + Rebindable!(immutable TimeZone) _timezone = UTC(); +} + + +class TimeZone +{ + this(string , string , string ) immutable {} +} + + +class UTC : TimeZone +{ + static immutable(UTC) opCall() + { + return _utc; + } + + this() immutable { + super("UTC", "UTC", "UTC"); + } + + static _utc = new immutable(UTC); +} diff --git a/gcc/testsuite/gdc.test/compilable/test12967.d b/gcc/testsuite/gdc.test/compilable/test12967.d new file mode 100644 index 00000000000..dd238386866 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12967.d @@ -0,0 +1,64 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +void foo() {} +alias F = typeof(foo); + +const { void block_c() {} } +immutable { void block_i() {} } +inout { void block_w() {} } +shared { void block_s() {} } +shared const { void block_sc() {} } +shared inout { void block_sw() {} } + +static assert(is(typeof(block_c) == F)); +static assert(is(typeof(block_i) == F)); +static assert(is(typeof(block_w) == F)); +static assert(is(typeof(block_s) == F)); +static assert(is(typeof(block_sc) == F)); +static assert(is(typeof(block_sw) == F)); + +version (all) { const: void label_c() {} } +version (all) { immutable: void label_i() {} } +version (all) { inout: void label_w() {} } +version (all) { shared: void label_s() {} } +version (all) { shared const: void label_sc() {} } +version (all) { shared inout: void label_sw() {} } + +static assert(is(typeof(label_c) == F)); +static assert(is(typeof(label_i) == F)); +static assert(is(typeof(label_w) == F)); +static assert(is(typeof(label_s) == F)); +static assert(is(typeof(label_sc) == F)); +static assert(is(typeof(label_sw) == F)); + +class C +{ + const { static void block_c() {} } + immutable { static void block_i() {} } + inout { static void block_w() {} } + shared { static void block_s() {} } + shared const { static void block_sc() {} } + shared inout { static void block_sw() {} } + + static assert(is(typeof(block_c) == F)); + static assert(is(typeof(block_i) == F)); + static assert(is(typeof(block_w) == F)); + static assert(is(typeof(block_s) == F)); + static assert(is(typeof(block_sc) == F)); + static assert(is(typeof(block_sw) == F)); + + version (all) { const: static void label_c() {} } + version (all) { immutable: static void label_i() {} } + version (all) { inout: static void label_w() {} } + version (all) { shared: static void label_s() {} } + version (all) { shared const: static void label_sc() {} } + version (all) { shared inout: static void label_sw() {} } + + static assert(is(typeof(label_c) == F)); + static assert(is(typeof(label_i) == F)); + static assert(is(typeof(label_w) == F)); + static assert(is(typeof(label_s) == F)); + static assert(is(typeof(label_sc) == F)); + static assert(is(typeof(label_sw) == F)); +} diff --git a/gcc/testsuite/gdc.test/compilable/test12979a.d b/gcc/testsuite/gdc.test/compilable/test12979a.d new file mode 100644 index 00000000000..14ca6efc0ee --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12979a.d @@ -0,0 +1,5 @@ +void parse() +{ + asm pure nothrow @nogc @trusted {} + asm @safe {} +} diff --git a/gcc/testsuite/gdc.test/compilable/test12979b.d b/gcc/testsuite/gdc.test/compilable/test12979b.d new file mode 100644 index 00000000000..41c76a251e8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test12979b.d @@ -0,0 +1,64 @@ +// REQUIRED_ARGS: -w -de + +void foo() pure nothrow @nogc @safe +{ + version(GNU) + { + asm pure nothrow @nogc @trusted + { + ""; + } + } + else + { + asm pure nothrow @nogc @trusted + { + ret; + } + } +} + +void bar()() +{ + version(GNU) + { + asm pure nothrow @nogc @trusted + { + ""; + } + } + else + { + asm pure nothrow @nogc @trusted + { + ret; + } + } +} + +static assert(__traits(compiles, () pure nothrow @nogc @safe => bar())); + +void baz()() +{ + version(GNU) + { + asm + { + ""; + } + } + else + { + asm + { + ret; + } + } +} + +// wait for deprecation of asm pure inference +// static assert(!__traits(compiles, () pure => baz())); +static assert(!__traits(compiles, () nothrow => baz())); +// wait for deprecation of asm @nogc inference +// static assert(!__traits(compiles, () @nogc => baz())); +static assert(!__traits(compiles, () @safe => baz())); diff --git a/gcc/testsuite/gdc.test/compilable/test13008.d b/gcc/testsuite/gdc.test/compilable/test13008.d new file mode 100644 index 00000000000..fd1f41db9cd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13008.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: -d -de -dw +/* +TEST_OUTPUT* +--- +--- +*/ +deprecated class Dep { } +deprecated Dep depFunc1(); // error +deprecated void depFunc2(Dep); // error diff --git a/gcc/testsuite/gdc.test/compilable/test13053.d b/gcc/testsuite/gdc.test/compilable/test13053.d new file mode 100644 index 00000000000..3f8b4219c96 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13053.d @@ -0,0 +1,13 @@ +// PERMUTE_ARGS: -w -wi +/* +TEST_OUTPUT: +--- +--- +*/ + +@system: + +struct S +{ + int[] a; +} diff --git a/gcc/testsuite/gdc.test/compilable/test13193.d b/gcc/testsuite/gdc.test/compilable/test13193.d new file mode 100644 index 00000000000..58cb617c497 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13193.d @@ -0,0 +1,126 @@ +// REQUIRED_ARGS: -O -inline -c + + +final class SharedLib { + void getSymbol() {return getSymbolImpl();} + void getSymbolImpl() {return getSymbol_();} + /* add more intermediate functions to go slower */ + void getSymbol_() {} +} + + +void test13193() +{ +SharedLib ssllib; +void bindFunc() {ssllib.getSymbol();} + bindFunc(); /* add more of these to go slower */ + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 10 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 20 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 30 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 40 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 50 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 60 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 70 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 80 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 90 */ + + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); + bindFunc(); /* 100 */ +} + diff --git a/gcc/testsuite/gdc.test/compilable/test13194.d b/gcc/testsuite/gdc.test/compilable/test13194.d new file mode 100644 index 00000000000..cefa7ba0fed --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13194.d @@ -0,0 +1,17 @@ +module test13194; + +class C13194 +{ + static Object o = void; +} + +struct S13194 +{ + static Object o = void; +} + +union U13194 +{ + static Object o = void; +} + diff --git a/gcc/testsuite/gdc.test/compilable/test13226.d b/gcc/testsuite/gdc.test/compilable/test13226.d new file mode 100644 index 00000000000..65bf3356630 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13226.d @@ -0,0 +1,32 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: -version=bug + +import imports.a13226; + +class C +{ + // class C member m is not accessible + version(bug) mixin(t!(typeof(this), "f")); else {} + version(bug) mixin(u!(typeof(this), "v")); else {} + + void f() {} + int v; + + // here is ok + version(bug) {} else mixin(t!(typeof(this), "f")); + version(bug) {} else mixin(u!(typeof(this), "v")); +} + +struct S +{ + // struct S member m is not accessible + version(bug) mixin(t!(typeof(this), "f")); else {} + version(bug) mixin(u!(typeof(this), "v")); else {} + + void f() {} + int v; + + // here is ok + version(bug) {} else mixin(t!(typeof(this), "f")); + version(bug) {} else mixin(u!(typeof(this), "v")); +} diff --git a/gcc/testsuite/gdc.test/compilable/test13242.d b/gcc/testsuite/gdc.test/compilable/test13242.d new file mode 100644 index 00000000000..0d6ef276aa0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13242.d @@ -0,0 +1,34 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +main ++alias apiSym1 +a.expensiveArgs: 1 +a.expensiveTemplate: 1 +-alias apiSym1 ++alias apiSym3 +b.expensiveArgs: 3 +b.expensiveTemplate: 3 +-alias apiSym3 +--- +*/ + +import imports.test13242a; + +void main() +{ + pragma(msg, "main"); + + cheapFunc(); + + pragma(msg, "+alias apiSym1"); + alias apiSym1 = .apiSym1; + pragma(msg, "-alias apiSym1"); + + // imports.test13242a.apiSym2 is not analyzed. + + pragma(msg, "+alias apiSym3"); + alias apiSym3 = .apiSym3; + pragma(msg, "-alias apiSym3"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test13281.d b/gcc/testsuite/gdc.test/compilable/test13281.d new file mode 100644 index 00000000000..0d747faf3fd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13281.d @@ -0,0 +1,47 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +123 +123u +123L +123LU +123.5 +123.5F +123.5L +123.5i +123.5Fi +123.5Li +(123.5+5.5i) +(123.5F+5.5Fi) +(123.5L+5.5Li) +--- +*/ +pragma(msg, 123); +pragma(msg, 123u); +pragma(msg, 123L); +pragma(msg, 123uL); +pragma(msg, 123.5); +pragma(msg, 123.5f); +pragma(msg, 123.5L); +pragma(msg, 123.5i); +pragma(msg, 123.5fi); +pragma(msg, 123.5Li); +pragma(msg, 123.5 +5.5i); +pragma(msg, 123.5f+5.5fi); +pragma(msg, 123.5L+5.5Li); + +static assert((123 ).stringof == "123"); +static assert((123u ).stringof == "123u"); +static assert((123L ).stringof == "123L"); +static assert((123uL).stringof == "123LU"); +static assert((123.5 ).stringof == "1.235e+2"); +static assert((123.5f ).stringof == "1.235e+2F"); +static assert((123.5L ).stringof == "1.235e+2L"); +static assert((123.5i ).stringof == "1.235e+2i"); +static assert((123.5fi).stringof == "1.235e+2Fi"); +static assert((123.5Li).stringof == "1.235e+2Li"); +static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); +static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); +static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); diff --git a/gcc/testsuite/gdc.test/compilable/test13512.d b/gcc/testsuite/gdc.test/compilable/test13512.d new file mode 100644 index 00000000000..bc78bd4dff3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13512.d @@ -0,0 +1,8 @@ +#!/opt/dmd/ÐÒÏÂÙ/rdmd + +import std.stdio; + + +void main () { + writeln("we are here!"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test1353.d b/gcc/testsuite/gdc.test/compilable/test1353.d new file mode 100644 index 00000000000..b724aa818b1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test1353.d @@ -0,0 +1,14 @@ + +class A {} +interface B {} +interface C {} +interface D(X) {} + +void fun() +{ + class T : typeof(new A), .B, const(C), D!int {} + version(none) + { + class U : int, float, __vector(int[3]) {} + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test13600.d b/gcc/testsuite/gdc.test/compilable/test13600.d new file mode 100644 index 00000000000..a16b39c197f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13600.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -g + +class Retry +{ + alias bool delegate ( lazy void ) SuccessDecider; + + SuccessDecider success_decide; + + void on_retry ( ) + { + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/test13668.d b/gcc/testsuite/gdc.test/compilable/test13668.d new file mode 100644 index 00000000000..d69c764b91c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13668.d @@ -0,0 +1,38 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +tuple("id", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory") +genProps +--- +*/ + +class User : Entity!User +{ + int id; +} + +class Entity(T) +{ + pragma(msg, generateProperties!T); + /* Compiler runs pragma(msg) in semantic() phase, but it does not insert any members + * in this class. Therefore getting __traits(allMembers, User) while evaluating + * generateProperties!User should work. + */ +} + +template generateProperties(alias To) +{ + string getProperties(alias Ta)() + { + string toRet = "genProps"; + + // This line is bad + pragma(msg, __traits(allMembers, Ta)); + + return toRet; + } + + enum generateProperties = getProperties!(To); +} diff --git a/gcc/testsuite/gdc.test/compilable/test13858.d b/gcc/testsuite/gdc.test/compilable/test13858.d new file mode 100644 index 00000000000..5a0432c59ce --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13858.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -w +// 13858 + +void foo() { assert(0); } + +void main() +{ + int x = 0; + + LSwitch: switch (x) + { + case 0: + break LSwitch; + + default: return; + } + + foo(); +} + diff --git a/gcc/testsuite/gdc.test/compilable/test13902.d b/gcc/testsuite/gdc.test/compilable/test13902.d new file mode 100644 index 00000000000..af4c90470a4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test13902.d @@ -0,0 +1,8 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +void foo() +{ + int a; + int* bar() { return &a; } +} diff --git a/gcc/testsuite/gdc.test/compilable/test14275.d b/gcc/testsuite/gdc.test/compilable/test14275.d new file mode 100644 index 00000000000..66f899c11a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14275.d @@ -0,0 +1,4 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +import protection.bug.bug14275; diff --git a/gcc/testsuite/gdc.test/compilable/test14317.d b/gcc/testsuite/gdc.test/compilable/test14317.d new file mode 100644 index 00000000000..ff97e731402 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14317.d @@ -0,0 +1,15 @@ + +// REQUIRED_ARGS: -O -profile -inline + +struct Range { + private string s; + char charAt(int unused1) { return s[0]; } +} + +bool count(Range* r, int* unused2) +{ + *unused2 = 0; + int unused3; + char c = r.charAt(0); + return true; +} diff --git a/gcc/testsuite/gdc.test/compilable/test14375.d b/gcc/testsuite/gdc.test/compilable/test14375.d new file mode 100644 index 00000000000..30206d844cd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14375.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +--- + */ +interface IKeysAPI(string greetings) { + static assert(greetings == "Hello world", greetings); +} + +void main() { + foreach (method; __traits(allMembers, IKeysAPI!("Hello world"))) { + static assert (method.length, "Empty string from the compiler ??"); + pragma(msg, method); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test14528.d b/gcc/testsuite/gdc.test/compilable/test14528.d new file mode 100644 index 00000000000..badab92006f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14528.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -o- +// PERMTE_ARGS: + +import imports.a14528; + +class C +{ + protected static void func() {} + + void test() + { + foo!func(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test14666.d b/gcc/testsuite/gdc.test/compilable/test14666.d new file mode 100644 index 00000000000..6162dd9ea6b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14666.d @@ -0,0 +1,8 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: +module test14666; + +struct Location +{ + import imports.test14666a; +} diff --git a/gcc/testsuite/gdc.test/compilable/test14747.d b/gcc/testsuite/gdc.test/compilable/test14747.d new file mode 100644 index 00000000000..eb0b418933d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14747.d @@ -0,0 +1,31 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: -w + +int foo(Args...)() +{ + int x; + + foreach (arg; Args) + { + static if(is(arg == int)) + { + return 0; + } + static if(is(arg == long)) + { + // fallthrough + ++x; // this statement might be unreachable, but + // UnrollStatement does not warn that. + } + } + // no return +} + +void main() +{ + auto r1 = foo!(int)(); // return + auto r2 = foo!(int, long)(); // return -> fallthrough (it's unreachable) + auto r3 = foo!(long, int)(); // fallthough -> return + static assert(!__traits(compiles, foo!(long)())); // fallthough + static assert(!__traits(compiles, foo!(long, long)())); // fallthough -> fallthough +} diff --git a/gcc/testsuite/gdc.test/compilable/test14781.d b/gcc/testsuite/gdc.test/compilable/test14781.d new file mode 100644 index 00000000000..3ccf5d0b798 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14781.d @@ -0,0 +1,38 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +void impure() {} // impure + +auto fb1(T)() pure +{ + int x; + struct A(S) + { + void fc(T2)() + { + x = 1; // accessing pure function context is just ok + impure(); // impure function call makes fc as impure + } + this(S a) {} + } + return A!int(); +} +auto fb2(T)() pure +{ + int x; + struct A(S) + { + void fc(T2)() + { + impure(); // impure function call makes fc as impure + x = 1; // accessing pure function context is just ok + } + this(S a) {} + } + return A!int(); +} +void test1() +{ + fb1!int().fc!int(); + fb2!int().fc!int(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test14838.d b/gcc/testsuite/gdc.test/compilable/test14838.d new file mode 100644 index 00000000000..766406898e6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14838.d @@ -0,0 +1,91 @@ +// PERMUTE_ARGS: + +struct A(T) { ~this() {} } +class C { A!int[1] array; } + +void test14838() pure nothrow @nogc @safe +{ + C c; + c.__xdtor(); // C.~this() will also be inferred to + // pure nothrow @nogc @safe + + A!int[1] array; + // scope destructor call does not cause attribute violation. +} + +// ---- + +/* + * This is a reduced test case comes from std.container.Array template, + * to fix the semantic analysis order issue for correct destructor attribute inference. + * + * Before the bugfix: + * 1. StructDeclaration('Array!int').semantic() instantiates + * RangeT!(Array!int) at the `alias Range = ...;`, but + * StructDeclaration('RangeT!(Array!int)').semantic() exits + * with sizeok == SIZEOKfwd, because the size of _outer_ field is not yet determined. + * 2. StructDeclaration('Array!int').semantic() succeeds to determine the size + * (sizeok = SIZEOKdone). + * 3. StructDeclaration('Array!int').buildOpAssign() will generate opAssign because + * Array!int._data field has identity opAssign member function. + * 4. The semantic3 will get called for the generated opAssign, then + * 6-1. Array!int.~this() semantic3, and + * 6-2. RefCounted!(Array!int.Payload).~this() semantic3 + * will also get called to infer their attributes. + * 5. In RefCounted!(Array!int.Payload).~this(), destroy(t) will be instantiated. + * At that, TemplateInstance.expandMembers() will invoke runDeferredSemantic() + * and it will re-run StructDeclaration('RangeT!(Array!int)').semantic(). + * 6. StructDeclaration('RangeT!(Array!int)').semantic() determines the size + * (sizeok = SIZEOKdone). Then, it will generate identity opAssign and run its semantic3. + * It will need to infer RangeT!(Array!int).~this() attribute, then it requires the + * correct attribute of Array!int.~this(). + * + * However, the Array!int.~this() attribute is not yet determined! [bug] + * -> it's wongly handled as impure/system/throwable/gc-able. + * + * -> then, the attribute inference results for + * RangeT!(Array!int).~this() and Array!int.~this() will be incorrect. + * + * After the bugfix: + * In 6, StructDeclaration('RangeT!(Array!int)').semantic() will check that: + * all base struct types of the instance fields have completed addition of + * special functions (dtor, opAssign, etc). + * If not, it will defer the completion of its semantic pass. + */ + +void destroy14838(S)(ref S s) if (is(S == struct)) +{ + s.__xdtor(); +} + +struct RefCounted14838(T) +{ + ~this() + { + T t; + .destroy14838(t); + } + + void opAssign(typeof(this) rhs) {} +} + +struct RangeT14838(A) +{ + A[1] _outer_; +} + +struct Array14838(T) +{ + struct Payload + { + ~this() {} + } + RefCounted14838!Payload _data; + + alias Range = RangeT14838!Array14838; +} + +class Test14838 +{ + Array14838!int[1] field; +} diff --git a/gcc/testsuite/gdc.test/compilable/test14962.d b/gcc/testsuite/gdc.test/compilable/test14962.d new file mode 100644 index 00000000000..69c0d89eb43 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14962.d @@ -0,0 +1,41 @@ +template map(fun...) +{ + auto map(R)(R r) + { + return MapResult!(fun, R)(r); + } +} + +struct MapResult(alias fun, R) +{ + R _input; + + @property bool empty() { return _input.length == 0; } + @property auto front() { return fun(_input[0]); } + void popFront() { _input = _input[1..$]; } +} + +struct Foo +{ + int baz(int v) + { + static int id; + return v + id++; + } + void bar() + { + auto arr1 = [1, 2, 3]; + auto arr2 = [4, 5, 6]; + arr1.map!( + // lambda1 + i => + arr2.map!( + // lambda2 + j => + baz(i + j) + ) + ); + } +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/test14973.d b/gcc/testsuite/gdc.test/compilable/test14973.d new file mode 100644 index 00000000000..b76c89dbd27 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test14973.d @@ -0,0 +1,104 @@ +template map(fun...) +{ + auto map(R)(R r) + { + return MapResult!(fun, R)(r); + } +} + +struct MapResult(alias fun, R) +{ + R _input; + + @property bool empty() { return _input.length == 0; } + @property auto front() { return fun(_input[0]); } + void popFront() { _input = _input[1..$]; } +} + +class Foo +{ + int baz() { return 1; } + void bar() + { + auto s = [1].map!(i => baz()); // compiles + auto r = [1].map!( // returns MapResult-1 + // lambda1 + i => + [1].map!( // returns MapResult-2 + // lambda2 + j => + baz() + ) + ); // compiles <- error + + // When lambda1 is called in MapResult-1.front(), it was changed to + // TOKfunction in functionResolve. But in that time, MapResult-2 semantic3 + // was not yet finished, then the lambda2 call in MapResult-2.front() + // could not access to enclosing scope frame to call baz(). + // To fix the issue, MapResult-2 semantic3 should be finished during the + // lambda1 body analysis. + } +} + +class Bar +{ + int baz; + void bar() + { + auto s = [1].map!(i => baz); // compiles + auto r = [1].map!( + // lambda1 + i => + [1].map!( + // lambda2 + j => + baz + ) + ); // compiles <- error + } +} + +/*******************************************/ + +struct ChunkByImpl(alias eq) +{ + struct Group + { + int[] start; + int[] current; + + void popFront() + { + // In here: + // SortedRange.pred == (a, b) => a @ test14978b() + // ChunkByImpl.eq == (a, b) => pred(a, b) @ SortedRange.groupBy() + // + // The context deduction should be: + // First pred is deduced to function pointer, + // and then, eq is also deduced to function pointer because pred is function pointer. + // + // Therefore, when ChunkByImpl is instantiated in groupBy(), its semantic3 + // needs to be invoked to analyze ??? + eq(start, current); + } + } +} + +struct SortedRange(alias pred) +{ + int[] input; + + auto groupBy() + { + ChunkByImpl!( + (a, b) => pred(a, b) + ) r; + } +} + +void test14973b() +{ + SortedRange!( + (a, b) => a + ) r; +} diff --git a/gcc/testsuite/gdc.test/compilable/test15019.d b/gcc/testsuite/gdc.test/compilable/test15019.d new file mode 100644 index 00000000000..c2948759a14 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15019.d @@ -0,0 +1,74 @@ +// https://issues.dlang.org/show_bug.cgi?id=15019 +// dmd -m32 -c all.d + +import std.string; + +struct Color() +{ + static fromHex(char[] s) + { + import std.conv; + s.to!ubyte; + } +} + +Color!() RGB ; + +struct Matrix(T, int R, int C) +{ + Vector!(T, C) row_t; + T[C] v; // all elements + + /// Covnerts to pretty string. + string toString() const + { + try + return format("%s", v); + catch + assert(false); // should not happen since format is right + } +} + +// GLSL is a big inspiration here +// we defines types with more or less the same names +template mat2x2(T) { Matrix!(T, 2, 2) mat2x2; } +template mat3x3(T) { Matrix!(T, 3, 3) mat3x3; } +template mat4x4(T) { Matrix!(T, 4, 4) mat4x4; } + +alias mat2x2 mat2; +alias mat3x3 mat3; // shorter names for most common matrices +alias mat4x4 mat4; + +string definePostfixAliases(string type) +{ + return "alias " ~ type ~ "!byte " ~ type ~ "b;\n" +"alias " ~ type ~ "!ubyte " ~ type ~ "ub;\n" +"alias " ~ type ~ "!short " ~ type ~ "s;\n" +"alias " ~ type ~ "!ushort " ~ type ~ "us;\n" +"alias " ~ type ~ "!int " ~ type ~ "i;\n" +"alias " ~ type ~ "!uint " ~ type ~ "ui;\n" +"alias " ~ type ~ "!long " ~ type ~ "l;\n" +"alias " ~ type ~ "!ulong " ~ type ~ "ul;\n" +"alias " ~ type ~ "!float " ~ type ~ "f;\n" +"alias " ~ type ~ "!double " ~ type ~ "d;\n"; +} + +// define a lot of type names +mixin(definePostfixAliases("mat2")); +mixin(definePostfixAliases("mat3")); +mixin(definePostfixAliases("mat4")); +import std.string; + +struct Vector(T, int N) +{ + T[N] v; + + string toString() + { + try + return format("%s", v); + catch + assert(false); + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/test15056.d b/gcc/testsuite/gdc.test/compilable/test15056.d new file mode 100644 index 00000000000..5beccba6bd3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15056.d @@ -0,0 +1,28 @@ +nothrow: + +version (Windows) +{ + version (LP_64) + import core.stdc.stdlib; + else + // doesn't currently work b/c SEH remains present even in nothrow code + void* alloca(size_t) { return null; } +} +else + import core.stdc.stdlib; + +struct S +{ + ~this() nothrow {} +} + +S foo(void* p = alloca(1234)) +{ + return S(); +} + +int main() +{ + foo(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/compilable/test15150.d b/gcc/testsuite/gdc.test/compilable/test15150.d new file mode 100644 index 00000000000..3a00b80348b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15150.d @@ -0,0 +1,8 @@ +// PERMUTE_ARGS: + +module test15150; + +import imports.test15150a; +import imports.test15150b; + +enum y = x; diff --git a/gcc/testsuite/gdc.test/compilable/test15177.d b/gcc/testsuite/gdc.test/compilable/test15177.d new file mode 100644 index 00000000000..0bb2d0498c6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15177.d @@ -0,0 +1,23 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: +// EXTRA_SOURCES: imports/test15117a.d + +import users = imports.test15117a; + +void RunApiTest(T...)() +{ + foreach (name; __traits(allMembers, users)) + { + // 3. list the name of TyepInfoStructDeclaration, + // but it's just internal symbol and invisible. + mixin("alias func = users . " ~ name ~ ";"); + } +} + +void main() +{ + // 1. run semantic3 of users.test_usr_1 + users.test_usr_1(); + + RunApiTest!(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test15326.d b/gcc/testsuite/gdc.test/compilable/test15326.d new file mode 100644 index 00000000000..05c942b2432 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15326.d @@ -0,0 +1,23 @@ +// REQUIRED_ARGS: -w -c -unittest + +version (unittest) +private struct _NestedSym_ +{ + static if ((void*).sizeof == 8) + { + pragma(msg, "64"); + } + else + { + pragma(msg, "32"); + } + + version (X86_64) + { + pragma(msg, "X86_64"); + } + else + { + pragma(msg, "Not 64"); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test1537.d b/gcc/testsuite/gdc.test/compilable/test1537.d new file mode 100644 index 00000000000..a1717abfc00 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test1537.d @@ -0,0 +1,106 @@ +// 1537 + +void foo(char[] s) +{ + int x = -1; + + while (s.length) + { + char c = s[0]; + + if (c == '}') + break; + + assert (c >= '0' && c <= '9', s[0..$]); + + if (x == -1) + x = 0; + } +} + +/**************************************/ + +enum bug4732 = 42; +static assert( __traits(identifier, bug4732) == "bug4732"); + +/**************************************/ + +template Compileable(int z) { bool OK=true;} + +int bug5245a(U)() +{ + { enum T { a = 5 } T v; } + { enum T { a = 6 } T w; } + return 91; +} + +int bug5245b(U)() +{ + { struct T { int a = 2; } T v; } + { union T { int a = 3; } T w; } + return 91; +} + +int bug5245c(U)() +{ + { struct T { int a = 2; } T v; } + { class T { int a = 3; } T w; } + return 91; +} + +int bug5245d(U)() +{ + { enum T { a = 3 } T w; } + { struct T { int a = 2; } T v; } + return 91; +} + + +static assert(!is(typeof(Compileable!(bug5245a!(int)()).OK))); +static assert(!is(typeof(Compileable!(bug5245b!(int)()).OK))); +static assert(!is(typeof(Compileable!(bug5245c!(int)()).OK))); +static assert(!is(typeof(Compileable!(bug5245d!(int)()).OK))); + +/**************************************/ + +class Bug5349(T) // segfault D2.051 +{ + int x; + static int g() + { + class B + { + int inner() + { + return x; // should not compile + } + } + return (new B).inner(); + } + int y = g(); +} + +static assert(!is(typeof(Bug5349!(int)))); + +/**************************************/ + +class Bug4033 {} + +class Template4033(T) { + static assert(is(T : Bug4033)); +} + +alias Template4033!(Z4033) Bla; + +class Z4033 : Bug4033 { } + +/**************************************/ + +struct Bug4322 { + int[1] a = void; +} + +void bug4322() { + Bug4322 f = Bug4322(); + Bug4322 g = Bug4322.init; +} diff --git a/gcc/testsuite/gdc.test/compilable/test15389_x.d b/gcc/testsuite/gdc.test/compilable/test15389_x.d new file mode 100644 index 00000000000..896f81a2a42 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15389_x.d @@ -0,0 +1,7 @@ +import test15389_y; + +//struct ns +extern (C++, ns) +{ + class X { test15389_y.ns.Y a; } +} diff --git a/gcc/testsuite/gdc.test/compilable/test15389_y.d b/gcc/testsuite/gdc.test/compilable/test15389_y.d new file mode 100644 index 00000000000..35e6a2511fa --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15389_y.d @@ -0,0 +1,8 @@ +import test15389_x; + +//struct ns +extern (C++, ns) +{ + class Y { test15389_x.ns.X b; } +} + diff --git a/gcc/testsuite/gdc.test/compilable/test15402.d b/gcc/testsuite/gdc.test/compilable/test15402.d new file mode 100644 index 00000000000..ddd7b9200d0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15402.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -de + +struct S +{ + package int field; +} + +void test() +{ + S s; + s.field = 1; +} diff --git a/gcc/testsuite/gdc.test/compilable/test15464.d b/gcc/testsuite/gdc.test/compilable/test15464.d new file mode 100644 index 00000000000..b8c3e9bb2d5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15464.d @@ -0,0 +1,22 @@ +class C15464 +{ + static immutable field = 0; +} + +struct S15464 +{ + this(int i) + { + } +} + +void issue15464(T)() @S15464(T.field) +{ +} + +void main() +{ + issue15464!C15464(); +} + + diff --git a/gcc/testsuite/gdc.test/compilable/test15490.d b/gcc/testsuite/gdc.test/compilable/test15490.d new file mode 100644 index 00000000000..eab5c61a74c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15490.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -o- -inline +// PERMUTE_ARGS: +module test15490; + +import imports.imp15490a; +import imports.imp15490b; + +void main() +{ + regex(); + listenTCP(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test15519_x.d b/gcc/testsuite/gdc.test/compilable/test15519_x.d new file mode 100644 index 00000000000..53cfe920a7a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15519_x.d @@ -0,0 +1,7 @@ + +import test15519_y; + +extern(C++, ns) +{ + class X { test15519_y.ns.Y v; } +} diff --git a/gcc/testsuite/gdc.test/compilable/test15519_y.d b/gcc/testsuite/gdc.test/compilable/test15519_y.d new file mode 100644 index 00000000000..58db30b2141 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15519_y.d @@ -0,0 +1,8 @@ + +import test15519_x: NS = ns; // fails +//import test15519_x; alias test15519_x.ns NS; // works + +extern(C++, ns) +{ + class Y { NS.X v; } +} diff --git a/gcc/testsuite/gdc.test/compilable/test15550.d b/gcc/testsuite/gdc.test/compilable/test15550.d new file mode 100644 index 00000000000..7a016fa4814 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15550.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +struct Vector(T, int N) +{ + void opDispatch(string, U)(U) + { + } + + void baz(string, U)(U) + { + } +} + +static assert(!is(typeof(Vector!(int, 2)._isMatrix))); +static assert(!is(typeof(Vector!(int, 2).baz!"_isMatrix"))); diff --git a/gcc/testsuite/gdc.test/compilable/test15565.d b/gcc/testsuite/gdc.test/compilable/test15565.d new file mode 100644 index 00000000000..4beb900d977 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15565.d @@ -0,0 +1,3 @@ +alias X2 = X; +extern (C++, ns) struct X {} + diff --git a/gcc/testsuite/gdc.test/compilable/test15578.d b/gcc/testsuite/gdc.test/compilable/test15578.d new file mode 100644 index 00000000000..81dd76a6e8f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15578.d @@ -0,0 +1,10 @@ +__gshared private: + int j; + extern(C++, ns) int k; + +void f() +{ + j = 0; // works as expected + k = 0; // Error: variable foo.ns.k is private +} + diff --git a/gcc/testsuite/gdc.test/compilable/test15618.d b/gcc/testsuite/gdc.test/compilable/test15618.d new file mode 100644 index 00000000000..f99c4417f37 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15618.d @@ -0,0 +1,19 @@ +class Base +{ + ~this() {} + size_t x = 4; +} + +interface Interface +{ + int Method(); +} + +class Derived : Base, Interface +{ + size_t y = 5; + int Method() { return 3; } +} + +static assert(Derived.x.offsetof == (void*).sizeof * 2); +static assert(Derived.y.offsetof == (void*).sizeof * 4); diff --git a/gcc/testsuite/gdc.test/compilable/test15668.d b/gcc/testsuite/gdc.test/compilable/test15668.d new file mode 100644 index 00000000000..72352162200 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15668.d @@ -0,0 +1,9 @@ +void foo ( int line = __LINE__ ) ( string msg = "" ) +{ + static assert (line == 8); +} + +void main() +{ + foo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test15762.d b/gcc/testsuite/gdc.test/compilable/test15762.d new file mode 100644 index 00000000000..0fb0293e5a8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15762.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=15762 + +enum Windows1252Char : ubyte { init } + +void main() @safe { + ubyte[] a = [1, 2, 3, 4]; + auto aw = cast(Windows1252Char[]) a; + auto caw = cast(const(Windows1252Char)[]) a; + const(ubyte)[] c = [1, 2, 3, 4]; + auto d = cast(const(ubyte)[]) c; + auto e = cast(const(Windows1252Char)[]) c; +} + diff --git a/gcc/testsuite/gdc.test/compilable/test15780.d b/gcc/testsuite/gdc.test/compilable/test15780.d new file mode 100644 index 00000000000..25c64cde333 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15780.d @@ -0,0 +1,17 @@ +// PERMUTE_ARGS: +// https://issues.dlang.org/show_bug.cgi?id=15780 + +import std.typecons; +//import std.stdio; + +void foo(alias fields)() { + foreach(i, field; fields) { + enum string a = fields[i]; // OK + enum string b = field; // not OK with 2.069.2 ??? + //writeln(field); + } +} + +void main() { + foo!(tuple("H", "I"))(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test15784.d b/gcc/testsuite/gdc.test/compilable/test15784.d new file mode 100644 index 00000000000..33b1bf3c919 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15784.d @@ -0,0 +1,47 @@ +// PERMUTE_ARGS: + +template AddField(T) +{ + T b; + this(Args...)(T b, auto ref Args args) + { + this.b = b; + this(args); + } +} + +template construcotrs() +{ + int a; + this(int a) + { + this.a = a; + } +} + +class B +{ + mixin construcotrs; + mixin AddField!(string); +} + +class C : B +{ + this(A...)(A args) + { + // The called super ctor is an overload set. + super(args); + } +} + +struct S +{ + mixin construcotrs; + mixin AddField!(string); +} + +void main() +{ + auto s = S("bar", 15); + auto c = new C("bar", 15); +} diff --git a/gcc/testsuite/gdc.test/compilable/test15785.d b/gcc/testsuite/gdc.test/compilable/test15785.d new file mode 100644 index 00000000000..c8ad24096e8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15785.d @@ -0,0 +1,22 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +--- +*/ +import imports.test15785; + +class Derived : Base, IBase2 +{ + override void foo() + { + super.foo(); + bar(); + // Base.bar(); // doesn't work yet due to a bug in checkAccess + faz(); + // IBase2.faz(); // doesn't work yet due to a bug in checkAccess + } + + super.T t; +} diff --git a/gcc/testsuite/gdc.test/compilable/test15802.d b/gcc/testsuite/gdc.test/compilable/test15802.d new file mode 100644 index 00000000000..9566eab6d9b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15802.d @@ -0,0 +1,10 @@ +extern(C++) { + template Foo(T) { + static int boo(); + } +} + +void main() +{ + string s = Foo!(int).boo.mangleof; +} diff --git a/gcc/testsuite/gdc.test/compilable/test15856.d b/gcc/testsuite/gdc.test/compilable/test15856.d new file mode 100644 index 00000000000..b61d1c4a812 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15856.d @@ -0,0 +1,17 @@ +// REQUIRED_ARGS: -transition=checkimports -de +// PERMUTE_ARGS: +/* +TEST_PUTPUT: +--- +--- +*/ + +class Foo +{ + import imports.a15856; + + struct Bar + { + c_long a; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test15898.d b/gcc/testsuite/gdc.test/compilable/test15898.d new file mode 100644 index 00000000000..01c325e9982 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15898.d @@ -0,0 +1,27 @@ +// REQUIRED_ARGS: -O +// https://issues.dlang.org/show_bug.cgi?id=15898 + +int addAssignSimple(int[] , const(int)[] ) +{ + uint c; + return c; +} + +void mulKaratsuba(int[] result, const(int)[] x, const(int)[] y, int[] ) +{ + const(int)[] y1 = y; + int[] newscratchbuff; + int[] resultHigh = result; + + bool ysmaller2 = x.length >= y1.length; + newscratchbuff[0..y1.length] = resultHigh; + mulKaratsuba( + resultHigh[1..$], + ysmaller2 ? x[1..$] : y1, + ysmaller2 ? y1 : x, + newscratchbuff[y1.length..$] + ); + + addAssignSimple(resultHigh[1..$], newscratchbuff[0..y1.length]); +} + diff --git a/gcc/testsuite/gdc.test/compilable/test15907.d b/gcc/testsuite/gdc.test/compilable/test15907.d new file mode 100644 index 00000000000..c362e04dbc4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15907.d @@ -0,0 +1,18 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: +import imports.imp15907; + +struct S +{ + private int a; +} + +void test() +{ + process(S()); +} + +static assert(allMembers!S == ["a"]); +enum sz = __traits(getMember, imports.imp15907, "PrivateStruct").sizeof; +static assert(__traits(hasMember, imports.imp15907, "privateVar")); +typeof(__traits(getMember, PublicStruct, "S").init) s; diff --git a/gcc/testsuite/gdc.test/compilable/test15925.d b/gcc/testsuite/gdc.test/compilable/test15925.d new file mode 100644 index 00000000000..871af4e55ed --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test15925.d @@ -0,0 +1,18 @@ +/* REQUIRED_ARGS: -transition=import -transition=checkimports +PERMUTE_ARGS: +TEST_OUTPUT: +--- +compilable/test15925.d(17): Deprecation: local import search method found variable imp15925.X instead of nothing +--- +*/ + +mixin template Import() +{ + import imports.imp15925; +} + +class Foo +{ + mixin Import!(); + static assert(X == 1); +} diff --git a/gcc/testsuite/gdc.test/compilable/test16031.d b/gcc/testsuite/gdc.test/compilable/test16031.d new file mode 100644 index 00000000000..7239522e107 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16031.d @@ -0,0 +1,33 @@ +// REQUIRED_ARGS: -fPIC -lib +// PERMUTE_ARGS: +// DISABLED: win32 win64 +extern void throwing(); + +void foo() +{ + // create plenty of symbols, so that the catch references get a high symbol index + static int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, + b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, + c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, + d0, d1, d2, d3, d4, d5, d6, d7, d8, d9; + try + { + throwing(); + } + catch (Exception) + { + } +} + +void bar() +{ + try + { + throwing(); + } + // symbol index for DW.ref._D9Exception7__ClassZ + // gets reused for another object and is out of bounds + catch (Exception) + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test16080.d b/gcc/testsuite/gdc.test/compilable/test16080.d new file mode 100644 index 00000000000..e9c60663ea5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16080.d @@ -0,0 +1,7 @@ +// REQUIRED_ARGS: -lib -Icompilable/imports +// COMPILED_IMPORTS: extra-files/test16080b.d +// EXTRA_FILES: imports/imp16080.d +// https://issues.dlang.org/show_bug.cgi?id=16080 + +import imp16080; + diff --git a/gcc/testsuite/gdc.test/compilable/test16083.d b/gcc/testsuite/gdc.test/compilable/test16083.d new file mode 100644 index 00000000000..f12b4523999 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16083.d @@ -0,0 +1,15 @@ +template Alias(Stuff...) +{ + alias Alias = Stuff; +} + +enum A { a = 0 } +enum B { b = 0 } + +enum C { c = "abc" } +enum D { d = "abc" } + +static assert(is(typeof(Alias!(A.a)[0]) == A)); +static assert(is(typeof(Alias!(B.b)[0]) == B)); +static assert(is(typeof(Alias!(C.c)[0]) == C)); +static assert(is(typeof(Alias!(D.d)[0]) == D)); diff --git a/gcc/testsuite/gdc.test/compilable/test16085.d b/gcc/testsuite/gdc.test/compilable/test16085.d new file mode 100644 index 00000000000..936a1fbdaca --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16085.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: +import imports.imp16085; + +void test() +{ + S s; + assert(s.functionAndFunction() == Pass()); + assert(s.staticFunctionAndFunction() == Pass()); + // assert(S.staticFunctionAndFunction() == Pass()); // erroneous not accessible error + assert(s.functionAndTemplate() == Pass()); + assert(s.templateAndTemplate() == Pass()); +} diff --git a/gcc/testsuite/gdc.test/compilable/test16225.d b/gcc/testsuite/gdc.test/compilable/test16225.d new file mode 100644 index 00000000000..6600842b769 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16225.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -O -m64 +// PERMUTE_ARGS: + +// https://issues.dlang.org/show_bug.cgi?id=16225 + +struct C +{ + hash_t foo( ) + { + int y; + return ((cast(ubyte*)&y)[1]); + } +} + diff --git a/gcc/testsuite/gdc.test/compilable/test16292.d b/gcc/testsuite/gdc.test/compilable/test16292.d new file mode 100644 index 00000000000..f513ddb1fe2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16292.d @@ -0,0 +1,19 @@ +/* PERMUTE_ARGS: + */ +// https://issues.dlang.org/show_bug.cgi?id=16292 + +void main() +{ + goto label; + if (makeS()[0]) + { + label: + } +} + +S makeS() { return S(); } + +struct S +{ + int opIndex(size_t i) { return 0; } +} diff --git a/gcc/testsuite/gdc.test/compilable/test16303.d b/gcc/testsuite/gdc.test/compilable/test16303.d new file mode 100644 index 00000000000..38589750755 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16303.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=16303 + +void yayf(void function(int*) fp); +void yayd(void delegate(int*) dg); + +void bar() +{ + void function(const(int)* p) fp; + yayf(fp); // should be good but produces error + + void delegate(const(int)* p) dg; + yayd(dg); // should be good but produces error +} diff --git a/gcc/testsuite/gdc.test/compilable/test16340.d b/gcc/testsuite/gdc.test/compilable/test16340.d new file mode 100644 index 00000000000..37124a8aa72 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16340.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -w + +version(unittest) template symsToStrs(fields...) +{ + static if (fields.length == 0) + enum symsToStrs = ["hello"]; + else + enum symsToStrs = ["world"]; +} diff --git a/gcc/testsuite/gdc.test/compilable/test16348.d b/gcc/testsuite/gdc.test/compilable/test16348.d new file mode 100644 index 00000000000..4efe24f1190 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16348.d @@ -0,0 +1,13 @@ +// EXTRA_SOURCES: imports/test16348.d +module mypackage.foo; + +void bug() +{ + // removing the if-else also removes the segfault + if (true) {} + else + { + import mypackage.bar; + auto b = bar(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test16460.d b/gcc/testsuite/gdc.test/compilable/test16460.d new file mode 100644 index 00000000000..868e7ecec4a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16460.d @@ -0,0 +1,13 @@ +module imports.test16460; + +void bug() +{ + auto d1 = (){ + import imports.imp16460; + return val; + }; + enum d2 = (){ + import imports.imp16460; + return val; + }; +} diff --git a/gcc/testsuite/gdc.test/compilable/test16525.d b/gcc/testsuite/gdc.test/compilable/test16525.d new file mode 100644 index 00000000000..6c85e0cad5f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16525.d @@ -0,0 +1,19 @@ +static immutable templ(alias var) = 1234; + +struct D +{ + int memvar; +} + +extern(C++) struct CPP +{ + int memvar; +} + +void test() +{ + pragma(msg, templ!(D.memvar)); + pragma(msg, templ!(CPP.memvar)); + // root cause, C++ member variables have no mangling + pragma(msg, CPP.memvar.mangleof); +} diff --git a/gcc/testsuite/gdc.test/compilable/test16540.d b/gcc/testsuite/gdc.test/compilable/test16540.d new file mode 100644 index 00000000000..ed7e47b6870 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16540.d @@ -0,0 +1,14 @@ +/* REQUIRED_ARGS: + PERMUTE_ARGS: + */ + +// https://issues.dlang.org/show_bug.cgi?id=16540 + +@safe: + +void foo(scope lazy int* f) @nogc { +} + +void bar1() @nogc { + foo(new int(5)); // It does not understand that the new here is wrapped in an invisible delegate +} diff --git a/gcc/testsuite/gdc.test/compilable/test16563.d b/gcc/testsuite/gdc.test/compilable/test16563.d new file mode 100644 index 00000000000..a215176e49a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16563.d @@ -0,0 +1,10 @@ +void test16563() +{ + align(1) + struct S + { + uint i; + ubyte b; + static assert(S.sizeof == 5); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test16570.d b/gcc/testsuite/gdc.test/compilable/test16570.d new file mode 100644 index 00000000000..20b84857605 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16570.d @@ -0,0 +1,8 @@ +static immutable int _a = 0; + +enum Regression +{ + a = _a, +} + +static assert(is(typeof(Regression.a) == Regression)); diff --git a/gcc/testsuite/gdc.test/compilable/test16572.d b/gcc/testsuite/gdc.test/compilable/test16572.d new file mode 100644 index 00000000000..480870e406f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16572.d @@ -0,0 +1,15 @@ +class K +{ + inout(int) f() inout + { + return var; + } + + void bug() + { + auto d = &f; + d(); + } + + int var; +} diff --git a/gcc/testsuite/gdc.test/compilable/test16574.d b/gcc/testsuite/gdc.test/compilable/test16574.d new file mode 100644 index 00000000000..ad19994cdf2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16574.d @@ -0,0 +1,34 @@ +// https://issues.dlang.org/show_bug.cgi?id=16574 +template Recursive(T) if (is(T == class)) +{ + // fails because T is still forward referenced + // speculative determineSize must not set type to error + static assert (!__traits(compiles, { new T; })); + // known size of class + static assert (is(typeof(T.init) == T)); + + alias Recursive = T; +} + +// must be resolvable +class C +{ + Recursive!C r; +} + +template Recursive(T) if (is(T == struct)) +{ + // fails because T is still forward referenced + // speculative determineSize must not set type to error + static assert (!__traits(compiles, { T t; })); + // no size yet for struct + static assert (!is(typeof(T.init))); + + alias Recursive = T*; +} + +// must be resolvable +struct S +{ + Recursive!S r; +} diff --git a/gcc/testsuite/gdc.test/compilable/test16607.d b/gcc/testsuite/gdc.test/compilable/test16607.d new file mode 100644 index 00000000000..7009d9aea3a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16607.d @@ -0,0 +1,15 @@ +struct A(T) +{ + T t; // causes A to be SIZEOKfwd b/c B (passed as T) isn't yet done + + // On the 2nd semantic pass through A, _scope of C got set again, + // even though the struct was already done. + struct C + { + } +} + +struct B +{ + A!B* a; // causes instantiation of A!B, but can finish semantic with A!B still being fwdref +} diff --git a/gcc/testsuite/gdc.test/compilable/test16627.d b/gcc/testsuite/gdc.test/compilable/test16627.d new file mode 100644 index 00000000000..176f1257f4a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16627.d @@ -0,0 +1,18 @@ +void test() +{ + int a; + + struct Field + { + this(this) { ++a; } + ~this() { --a; } + } + + struct S + { + Field field; // generates __fieldPostblit, __fieldDtor, and opAssign + } + + static assert(__traits(isNested, Field)); + static assert(!__traits(isNested, S)); +} diff --git a/gcc/testsuite/gdc.test/compilable/test1673.d b/gcc/testsuite/gdc.test/compilable/test1673.d new file mode 100644 index 00000000000..bd91468c3ad --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test1673.d @@ -0,0 +1,52 @@ +module test1673; + +template Foo(T...) { } + +template Bar(T...) +{ + template Doo(T...) + { + } +} + +template Tuple(T...) { alias Tuple = T; } + +void main() +{ + static assert( __traits(isTemplate, Foo)); + static assert(!__traits(isTemplate, Foo!int)); + static assert(!__traits(isTemplate, main)); + + static assert( __traits(isTemplate, Bar)); + static assert(!__traits(isTemplate, Bar!int)); + static assert( __traits(isTemplate, Bar!(int).Doo)); + static assert(!__traits(isTemplate, Bar!(int).Doo!int)); + + alias Tup = Tuple!(Foo, Foo!int, Bar, Bar!int, Bar!(int).Doo, Bar!(int).Doo!int); + + static assert( __traits(isTemplate, Tup[0])); + static assert(!__traits(isTemplate, Tup[1])); + static assert( __traits(isTemplate, Tup[2])); + static assert(!__traits(isTemplate, Tup[3])); + static assert( __traits(isTemplate, Tup[4])); + static assert(!__traits(isTemplate, Tup[5])); +} + +/// test overloads +void foo_over() { } +void foo_over(T : int)(T) { } +void foo_over(T : float)(T) { } +static assert(__traits(isTemplate, foo_over)); + +/// ditto +void bar_over() { } +void bar_over(int) { } +static assert(!__traits(isTemplate, bar_over)); + +/// alias to overloads +alias a_foo_over = foo_over; +static assert(__traits(isTemplate, a_foo_over)); + +/// ditto +alias a_bar_over = bar_over; +static assert(!__traits(isTemplate, a_bar_over)); diff --git a/gcc/testsuite/gdc.test/compilable/test16747.d b/gcc/testsuite/gdc.test/compilable/test16747.d new file mode 100644 index 00000000000..a0badc2bba7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16747.d @@ -0,0 +1,13 @@ +/* +PERMUTE_ARGS: +*/ + +class C { @safe ~this() { } } +class D : C { } + +void fwd() @safe +{ + scope o = new Object(); + scope c = new C(); + scope d = new D(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test16798.d b/gcc/testsuite/gdc.test/compilable/test16798.d new file mode 100644 index 00000000000..41e09e0134a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test16798.d @@ -0,0 +1,13 @@ +/* +REQUIRED_ARGS: -mv=its.a.dessert.topping=imports/imp16798.d -mv=its.a.floorwax=imports/ +PERMUTE_ARGS: +TEST_OUTPUT: +--- +it's a floor wax +it's a dessert topping +--- +*/ + +import its.a.floorwax.wax16798; +import its.a.dessert.topping; + diff --git a/gcc/testsuite/gdc.test/compilable/test17057.d b/gcc/testsuite/gdc.test/compilable/test17057.d new file mode 100644 index 00000000000..c90e35f99f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17057.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: + +class LeClass { + import std.stdio; +} + +void main() +{ + static assert([__traits(allMembers, LeClass)] == ["toString", "toHash", "opCmp", "opEquals", "Monitor", "factory"]); +} + diff --git a/gcc/testsuite/gdc.test/compilable/test17059.d b/gcc/testsuite/gdc.test/compilable/test17059.d new file mode 100644 index 00000000000..b7eb26af86a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17059.d @@ -0,0 +1,11 @@ +mixin template impl() +{ + alias T = typeof(this); + enum doImplement = is(T : I); + + static if (doImplement) + {} +} + +interface I {} +class A : I {mixin impl;} diff --git a/gcc/testsuite/gdc.test/compilable/test17130.d b/gcc/testsuite/gdc.test/compilable/test17130.d new file mode 100644 index 00000000000..f3f5c3b45b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17130.d @@ -0,0 +1,38 @@ +class Base +{ + this() shared + {} + + this() + {} +} + +class Derived1 : Base +{ + this() + { + // implicit super(); + } +} + +class Derived2 : Base +{ + // implicit this() +} + +class Base2 +{ + this() shared + {} +} + +class Derived3 : Base2 +{ + // implicit this() shared +} + +void test() +{ + auto d2 = new Derived2; + auto d3 = new shared(Derived3); +} diff --git a/gcc/testsuite/gdc.test/compilable/test17143.d b/gcc/testsuite/gdc.test/compilable/test17143.d new file mode 100644 index 00000000000..403c9aa456c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17143.d @@ -0,0 +1,4 @@ +import std.typecons : tuple; +enum foo = tuple(1, 2).expand; +pragma(msg, typeof(foo).stringof); +pragma(msg, foo.stringof); diff --git a/gcc/testsuite/gdc.test/compilable/test17168.d b/gcc/testsuite/gdc.test/compilable/test17168.d new file mode 100644 index 00000000000..1cfbfbbc51b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17168.d @@ -0,0 +1,4 @@ +// REQUIRED_ARGS: -O +// PERMUTE_ARGS: + +void fn(uint x){uint a = 0 << x;} diff --git a/gcc/testsuite/gdc.test/compilable/test17215.d b/gcc/testsuite/gdc.test/compilable/test17215.d new file mode 100644 index 00000000000..047039e7681 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17215.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -O +version (X86_64): +alias vec = __vector(int[4]); + +vec binop(vec a) +{ + vec b = a; + return b; +} diff --git a/gcc/testsuite/gdc.test/compilable/test17339.d b/gcc/testsuite/gdc.test/compilable/test17339.d new file mode 100644 index 00000000000..c908af9c724 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17339.d @@ -0,0 +1,19 @@ +void foo(alias param)() +{ +} + +const CONST1 = 1; +const CONST2 = 1; +static assert(&foo!CONST1 !is &foo!CONST2); +static assert(foo!CONST1.mangleof != foo!CONST2.mangleof); + +immutable IMM1 = 1; +immutable IMM2 = 1; +static assert(&foo!IMM1 !is &foo!IMM2); +static assert(foo!IMM1.mangleof != foo!IMM2.mangleof); + +// Behaves different for manifest constants! +enum ENUM1 = 1; +enum ENUM2 = 1; +static assert(&foo!ENUM1 is &foo!ENUM2); +static assert(foo!ENUM1.mangleof == foo!ENUM2.mangleof); diff --git a/gcc/testsuite/gdc.test/compilable/test17349.d b/gcc/testsuite/gdc.test/compilable/test17349.d new file mode 100644 index 00000000000..06070e6d751 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17349.d @@ -0,0 +1,30 @@ + +/* REQUIRED_ARGS: + PERMUTE_ARGS: + */ + +// https://issues.dlang.org/show_bug.cgi?id=16538 + +const(int) retConst1(); +int retConst2(); +auto retConst = [&retConst1, &retConst2]; + +const(int*) retConstPtr1(); +const(int)* retConstPtr2(); +auto retConstPtr = [&retConstPtr1, &retConstPtr2]; + +void constArray1(const(int)[1]); +void constArray2(const(int[1])); +auto constArray = [&constArray1, &constArray2]; + +const(int)[] retConstSlice1(); +const(int[]) retConstSlice2(); +auto retConstSlice = [&retConstSlice1, &retConstSlice2]; + +void constSlice1(const(int)[]); +void constSlice2(const(int[])); +auto constSlice = [&constSlice1, &constSlice2]; + +void ptrToConst1(const(int)*); +void ptrToConst2(const(int*)); +auto ptrToConst = [&ptrToConst1, &ptrToConst2]; diff --git a/gcc/testsuite/gdc.test/compilable/test17352.d b/gcc/testsuite/gdc.test/compilable/test17352.d new file mode 100644 index 00000000000..9f9355dcd20 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17352.d @@ -0,0 +1,18 @@ +// https://issues.dlang.org/show_bug.cgi?id=17352 +void bug(Args...)() +{ +} + +void test(bool coin) +{ + if (coin) + { + string foobar; + bug!foobar(); + } + else + { + string foobar; + bug!foobar(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test17399.d b/gcc/testsuite/gdc.test/compilable/test17399.d new file mode 100644 index 00000000000..98d22ef17b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17399.d @@ -0,0 +1,18 @@ +/* REQUIRED_ARGS: -inline + */ + +// https://issues.dlang.org/show_bug.cgi?id=17399 + +pragma(inline, true) +uint addu(uint x, uint y, ref bool overflow) { + uint r = x + y; + if (r < x || r < y) + overflow = true; + return r; +} + +void foo() { + uint a, b; + bool over; + addu(a, b, over); +} diff --git a/gcc/testsuite/gdc.test/compilable/test17419.d b/gcc/testsuite/gdc.test/compilable/test17419.d new file mode 100644 index 00000000000..219ed4f712e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17419.d @@ -0,0 +1,37 @@ +// https://issues.dlang.org/show_bug.cgi?id=17419 + + +extern (C) int fooc(); +alias aliasc = fooc; + +static assert(__traits(getLinkage, fooc) == "C"); +static assert(__traits(getLinkage, aliasc) == "C"); + +extern (D) int food(); +extern (C++) int foocpp(); +extern (Windows) int foow(); +extern (Pascal) int foop(); +extern (Objective-C) int fooobjc(); +extern (System) int foos(); + +static assert(__traits(getLinkage, food) == "D"); +static assert(__traits(getLinkage, foocpp) == "C++"); +static assert(__traits(getLinkage, foow) == "Windows"); +static assert(__traits(getLinkage, foop) == "Pascal"); +static assert(__traits(getLinkage, fooobjc) == "Objective-C"); +version (Windows) + static assert(__traits(getLinkage, foos) == "Windows"); +else + static assert(__traits(getLinkage, foos) == "C"); + +extern (C) int global; +static assert(__traits(getLinkage, global) == "C"); + +static assert(__traits(getLinkage, typeof(fooc)) == "C"); +static assert(__traits(getLinkage, typeof(&fooc)) == "C"); + +void bar() +{ + void nested() { } + static assert(__traits(getLinkage, typeof(&nested)) == "D"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test17421.d b/gcc/testsuite/gdc.test/compilable/test17421.d new file mode 100644 index 00000000000..e5075fb460e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17421.d @@ -0,0 +1,19 @@ +// https://issues.dlang.org/show_bug.cgi?id=17421 + +import core.stdc.stdarg; + +void novar() {} +extern(C) void cstyle(int, ...) {} +extern(C++) void cppstyle(int, ...) {} +void dstyle(...) {} +void typesafe(int[]...) {} + +static assert(__traits(getFunctionVariadicStyle, novar) == "none"); +static assert(__traits(getFunctionVariadicStyle, cstyle) == "stdarg"); +static assert(__traits(getFunctionVariadicStyle, cppstyle) == "stdarg"); +static assert(__traits(getFunctionVariadicStyle, dstyle) == "argptr"); +static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe"); + +static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe"); +static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg"); + diff --git a/gcc/testsuite/gdc.test/compilable/test17468.d b/gcc/testsuite/gdc.test/compilable/test17468.d new file mode 100644 index 00000000000..840de219ae9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17468.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: +struct S +{ + const char* path; + @disable this(); + this(const(char)* path) + { + this.path = path; + } +} +const S CONST_S = S("/tmp".ptr); + diff --git a/gcc/testsuite/gdc.test/compilable/test1754.d b/gcc/testsuite/gdc.test/compilable/test1754.d new file mode 100644 index 00000000000..3193477d309 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test1754.d @@ -0,0 +1,9 @@ +module test1754; + +import imports.test1754a; +import imports.test1754b; + +void foo() +{ + bar(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test17545.d b/gcc/testsuite/gdc.test/compilable/test17545.d new file mode 100644 index 00000000000..bb0c2ae9ace --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17545.d @@ -0,0 +1,16 @@ +/* TEST_OUTPUT: +--- +tuple((Attrib)) +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17545 + +module example; + +struct Attrib {} + +@Attrib enum TEST = 123; + +pragma(msg, __traits(getAttributes, + __traits(getMember, example, "TEST"))); diff --git a/gcc/testsuite/gdc.test/compilable/test17548.d b/gcc/testsuite/gdc.test/compilable/test17548.d new file mode 100644 index 00000000000..67b32d7a3ad --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17548.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -c + +module test17548; + +struct S1 { + void foo(scope S2 arg) {} + int myField; +} + +enum cnst = 4321; + +import imports.fwdref2_test17548; diff --git a/gcc/testsuite/gdc.test/compilable/test17590.d b/gcc/testsuite/gdc.test/compilable/test17590.d new file mode 100644 index 00000000000..6eec76f7423 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17590.d @@ -0,0 +1,40 @@ +// REQUIRED_ARGS: -o- + +void lazyfun(scope lazy int a) @nogc; + +// Test that returning a local _static_ struct does not lead to allocation of a closure. +auto foo_static(int a, bool b) @nogc { + static struct SInside {} + + SInside res; + + lazyfun(a); + + return res; +} + +// Test that returning a local _non-static_ struct that does not reference any local variable does not lead to allocation of a closure. +auto foo_nonstatic(int a, bool b) @nogc { + struct SInside {} + + SInside res; + + lazyfun(a); + + return res; +} + +// Test that returning a local non-static struct that references a local variable does lead to allocation of a closure. +static assert(!__traits(compiles, () @nogc => goo(1))); +static assert(__traits(compiles, () => goo(1))); +auto goo(T)(T a) { + struct SInside { + T foo() { return a; } + } + + SInside res; + + lazyfun(a); + + return res; +} diff --git a/gcc/testsuite/gdc.test/compilable/test1878a.d b/gcc/testsuite/gdc.test/compilable/test1878a.d new file mode 100644 index 00000000000..6c8fb6b628c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test1878a.d @@ -0,0 +1,16 @@ +void main() +{ + ubyte from, to; + foreach(i; from..to) + { + static assert(is(typeof(i) == ubyte)); + } + foreach(i; 'a'..'l') + { + static assert(is(typeof(i) == char)); + } + foreach(i; 'א' .. 'ת') + { + static assert(is(typeof(i) == wchar)); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test25.d b/gcc/testsuite/gdc.test/compilable/test25.d new file mode 100644 index 00000000000..42fc8141b47 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test25.d @@ -0,0 +1,10 @@ +// PERMUTE_ARGS: + +import imports.test25a, imports.test25b; + +import std.stdio; + +void main() +{ + std.stdio.writefln("hello"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test2991.d b/gcc/testsuite/gdc.test/compilable/test2991.d new file mode 100644 index 00000000000..61281b83444 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test2991.d @@ -0,0 +1,12 @@ +module test2991; + +void foo() +{ +} + +class C +{ + import imports.test2991; + + void bar() { foo(); } +} diff --git a/gcc/testsuite/gdc.test/compilable/test313a.d b/gcc/testsuite/gdc.test/compilable/test313a.d new file mode 100644 index 00000000000..daa6afb3a0e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test313a.d @@ -0,0 +1,36 @@ +/* +REQUIRED_ARGS: -de +*/ +module test313; + +import imports.a313; + +void test1() +{ + import imports.b313; + imports.b313.bug(); +} + +void test2() +{ + cstdio.printf(""); +} + +import imports.pkg313.c313; +void test3() +{ + imports.pkg313.c313.bug(); +} + +template imp() +{ + static import imports.a313templatemixin1; + import imports.a313templatemixin2; +} + +mixin imp!(); +void test4() +{ + imports.a313templatemixin1.bug(); + imports.a313templatemixin2.bug(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test313b.d b/gcc/testsuite/gdc.test/compilable/test313b.d new file mode 100644 index 00000000000..7ef27c5e0d0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test313b.d @@ -0,0 +1,6 @@ +// REQUIRED_ARGS: -de +void test1() +{ + import core.stdc.stdio; + core.stdc.stdio.printf(""); +} diff --git a/gcc/testsuite/gdc.test/compilable/test313c.d b/gcc/testsuite/gdc.test/compilable/test313c.d new file mode 100644 index 00000000000..3b075bd6ebf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test313c.d @@ -0,0 +1,8 @@ +// REQUIRED_ARGS: -de +import imports.pkgmod313; + +void test() +{ + imports.pkgmod313.foo(); + imports.pkgmod313.bar(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test313d.d b/gcc/testsuite/gdc.test/compilable/test313d.d new file mode 100644 index 00000000000..7545d8012d9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test313d.d @@ -0,0 +1,9 @@ +// first imported as package +// EXTRA_SOURCES: imports/pkgmod313/mod.d +// REQUIRED_ARGS: -de +import imports.pkgmod313; // then as package module + +void test() +{ + imports.pkgmod313.foo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test313e.d b/gcc/testsuite/gdc.test/compilable/test313e.d new file mode 100644 index 00000000000..b24f24ef6af --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test313e.d @@ -0,0 +1,9 @@ +// first resolved as package, then created as module (with name package) +// EXTRA_SOURCES: imports/pkgmod313/mod.d imports/pkgmod313/package.d +// REQUIRED_ARGS: -de +import imports.pkgmod313; // then imported as package module + +void test() +{ + imports.pkgmod313.foo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test313f.d b/gcc/testsuite/gdc.test/compilable/test313f.d new file mode 100644 index 00000000000..e758e37c9db --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test313f.d @@ -0,0 +1,7 @@ +// REQUIRED_ARGS: -de +import imports.f313; + +void test() +{ + imports.f313.bug(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test313g.d b/gcc/testsuite/gdc.test/compilable/test313g.d new file mode 100644 index 00000000000..f2052147d1a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test313g.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -de +// EXTRA_SOURCES: imports/g313.d +import imports.g313; + +void test15900() +{ + // publically imported modules from g313 should be available here + imports.g313public.bug(); + imports.g313staticif.bug(); + imports.g313stringmixin.bug(); + imports.g313templatemixin.bug(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test314.d b/gcc/testsuite/gdc.test/compilable/test314.d new file mode 100644 index 00000000000..b7c15e39ca5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test314.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -de +module imports.test314; // package imports + +import imports.a314; + +void main() +{ + imports.a314.bug("This should work.\n"); + renamed.bug("This should work.\n"); + bug("This should work.\n"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test3673.d b/gcc/testsuite/gdc.test/compilable/test3673.d new file mode 100644 index 00000000000..3d118be8da3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test3673.d @@ -0,0 +1,48 @@ +class Base {} + +class Foo(T) + if (is(T == int)) : Base { } + +class Bar(T) : Base + if (is(T == bool)) +{ } + +interface OutputRange(T...) + if (T.length == 1) +{ + void put(T[0] value); +} + +interface OutputRange(T...) : OutputRange!(T[0]), OutputRange!(T[1 .. $]) + if (T.length > 1) +{ +} + +alias OutputRange!(int, float) OR; + +class COR : OR +{ + void put(int) { } + void put(float) { } +} + +class A {}; +class B(T) : A if (true) {} +class C(T) if (false) : A {} + +alias Foo!int FooInt; +alias Bar!bool BarBool; + +static assert(!__traits(compiles, Foo!bool)); +static assert(!__traits(compiles, Bar!int)); + +void main() +{ + auto fi = new FooInt; + auto bb = new BarBool; + auto cor = new COR; + + auto a = new A(); + auto b = new B!int(); + static assert(!__traits(compiles, new C!int())); +} diff --git a/gcc/testsuite/gdc.test/compilable/test3775.d b/gcc/testsuite/gdc.test/compilable/test3775.d new file mode 100644 index 00000000000..47b9b88660c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test3775.d @@ -0,0 +1,9 @@ +// 3775 + +struct Bug3775 { + static int byLine()() { return 1; } +} + +static assert(cast(int)Bug3775.byLine == 1); + + diff --git a/gcc/testsuite/gdc.test/compilable/test4003.d b/gcc/testsuite/gdc.test/compilable/test4003.d new file mode 100644 index 00000000000..8a401f219bd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test4003.d @@ -0,0 +1,6 @@ +// EXTRA_SOURCES: imports/test4003a.d +// PERMUTE_ARGS: + +import imports.stdio4003; +void main(){} + diff --git a/gcc/testsuite/gdc.test/compilable/test4090.d b/gcc/testsuite/gdc.test/compilable/test4090.d new file mode 100644 index 00000000000..8f8f7c9f26d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test4090.d @@ -0,0 +1,235 @@ +void test4090a() +{ + // for the mutable elements + { + int[] arr = [1,2,3]; + + // inference + qualifier + foreach ( x; arr) static assert(is(typeof(x) == int)); + foreach ( const x; arr) static assert(is(typeof(x) == const int)); + foreach (immutable x; arr) static assert(is(typeof(x) == immutable int)); + + // inference + qualifier + ref + foreach ( ref x; arr) static assert(is(typeof(x) == int)); + foreach ( const ref x; arr) static assert(is(typeof(x) == const int)); + static assert(!__traits(compiles, { + foreach (immutable ref x; arr) {} + })); + + // with exact type + qualifier + foreach ( int x; arr) static assert(is(typeof(x) == int)); + foreach ( const int x; arr) static assert(is(typeof(x) == const int)); + foreach (immutable int x; arr) static assert(is(typeof(x) == immutable int)); + + // with exact type + qualifier + ref + foreach ( ref int x; arr) static assert(is(typeof(x) == int)); + foreach ( const ref int x; arr) static assert(is(typeof(x) == const int)); + static assert(!__traits(compiles, { + foreach (immutable ref int x; arr) {} + })); + + // convertible type + qualifier + foreach ( double x; arr) static assert(is(typeof(x) == double)); + foreach ( const double x; arr) static assert(is(typeof(x) == const double)); + foreach (immutable double x; arr) static assert(is(typeof(x) == immutable double)); + + // convertible type + qualifier + ref + static assert(!__traits(compiles, { + foreach ( ref double x; arr) {} + })); + static assert(!__traits(compiles, { + foreach ( const ref double x; arr) {} + })); + static assert(!__traits(compiles, { + foreach (immutable ref double x; arr) {} + })); + } + // for the immutable elements + { + immutable(int)[] iarr = [1,2,3]; + + // inference + qualifier + foreach ( x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach ( const x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach (immutable x; iarr) static assert(is(typeof(x) == immutable int)); + + // inference + qualifier + ref + foreach ( ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach ( const ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach (immutable ref x; iarr) static assert(is(typeof(x) == immutable int)); + + // with exact type + qualifier + foreach ( int x; iarr) static assert(is(typeof(x) == int)); + foreach ( const int x; iarr) static assert(is(typeof(x) == const int)); + foreach (immutable int x; iarr) static assert(is(typeof(x) == immutable int)); + + // with exact type + qualifier + ref + static assert(!__traits(compiles, { + foreach ( ref int x; iarr) {} + })); + foreach ( const ref int x; iarr) static assert(is(typeof(x) == const int)); + foreach (immutable ref int x; iarr) static assert(is(typeof(x) == immutable int)); + + // convertible type + qualifier + foreach ( double x; iarr) static assert(is(typeof(x) == double)); + foreach ( const double x; iarr) static assert(is(typeof(x) == const double)); + foreach (immutable double x; iarr) static assert(is(typeof(x) == immutable double)); + + // convertible type + qualifier + ref + static assert(!__traits(compiles, { + foreach (ref double x; iarr) {} + })); + static assert(!__traits(compiles, { + foreach (const ref double x; iarr) {} + })); + static assert(!__traits(compiles, { + foreach (immutable ref double x; iarr) {} + })); + } +} + +void test4090b() +{ + // for the key + { + int[] arr = [1,2,3]; + + // inference + qualifier + foreach ( i, x; arr) static assert(is(typeof(i) == size_t)); + foreach ( const i, x; arr) static assert(is(typeof(i) == const size_t)); + foreach (immutable i, x; arr) static assert(is(typeof(i) == immutable size_t)); + + // inference + qualifier + ref + foreach ( ref i, x; arr) static assert(is(typeof(i) == size_t)); + foreach ( const ref i, x; arr) static assert(is(typeof(i) == const size_t)); + static assert(!__traits(compiles, { + foreach (immutable ref i, x; arr) {} + })); + + // with exact type + qualifier + foreach ( size_t i, x; arr) static assert(is(typeof(i) == size_t)); + foreach ( const size_t i, x; arr) static assert(is(typeof(i) == const size_t)); + foreach (immutable size_t i, x; arr) static assert(is(typeof(i) == immutable size_t)); + + // with exact type + qualifier + ref + foreach ( ref size_t i, x; arr) static assert(is(typeof(i) == size_t)); + foreach ( const ref size_t i, x; arr) static assert(is(typeof(i) == const size_t)); + static assert(!__traits(compiles, { + foreach (immutable ref size_t i, x; arr) {} + })); + } + + // for the mutable elements + { + int[] arr = [1,2,3]; + + // inference + qualifier + foreach (i, x; arr) static assert(is(typeof(x) == int)); + foreach (i, const x; arr) static assert(is(typeof(x) == const int)); + foreach (i, immutable x; arr) static assert(is(typeof(x) == immutable int)); + + // inference + qualifier + ref + foreach (i, ref x; arr) static assert(is(typeof(x) == int)); + foreach (i, const ref x; arr) static assert(is(typeof(x) == const int)); + static assert(!__traits(compiles, { + foreach (i, immutable ref x; arr) {} + })); + + // with exact type + qualifier + foreach (i, int x; arr) static assert(is(typeof(x) == int)); + foreach (i, const int x; arr) static assert(is(typeof(x) == const int)); + foreach (i, immutable int x; arr) static assert(is(typeof(x) == immutable int)); + + // with exact type + qualifier + ref + foreach (i, ref int x; arr) static assert(is(typeof(x) == int)); + foreach (i, const ref int x; arr) static assert(is(typeof(x) == const int)); + static assert(!__traits(compiles, { + foreach (i, immutable ref int x; arr) {} + })); + + // convertible type + qualifier + foreach (i, double x; arr) static assert(is(typeof(x) == double)); + foreach (i, const double x; arr) static assert(is(typeof(x) == const double)); + foreach (i, immutable double x; arr) static assert(is(typeof(x) == immutable double)); + + // convertible type + qualifier + ref + static assert(!__traits(compiles, { + foreach (i, ref double x; arr) {} + })); + static assert(!__traits(compiles, { + foreach (i, const ref double x; arr) {} + })); + static assert(!__traits(compiles, { + foreach (i, immutable ref double x; arr) {} + })); + } + // for the immutable elements + { + immutable(int)[] iarr = [1,2,3]; + + // inference + qualifier + foreach (i, x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach (i, const x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach (i, immutable x; iarr) static assert(is(typeof(x) == immutable int)); + + // inference + qualifier + ref + foreach (i, ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach (i, const ref x; iarr) static assert(is(typeof(x) == immutable int)); // same as variable declaration + foreach (i, immutable ref x; iarr) static assert(is(typeof(x) == immutable int)); + + // with exact type + qualifier + foreach (i, int x; iarr) static assert(is(typeof(x) == int)); + foreach (i, const int x; iarr) static assert(is(typeof(x) == const int)); + foreach (i, immutable int x; iarr) static assert(is(typeof(x) == immutable int)); + + // with exact type + qualifier + ref + static assert(!__traits(compiles, { + foreach (i, ref int x; iarr) {} + })); + foreach (i, const ref int x; iarr) static assert(is(typeof(x) == const int)); + foreach (i, immutable ref int x; iarr) static assert(is(typeof(x) == immutable int)); + + // convertible type + qualifier + foreach (i , double x; iarr) static assert(is(typeof(x) == double)); + foreach (i, const double x; iarr) static assert(is(typeof(x) == const double)); + foreach (i, immutable double x; iarr) static assert(is(typeof(x) == immutable double)); + + // convertible type + qualifier + ref + static assert(!__traits(compiles, { + foreach (i, ref double x; iarr) {} + })); + static assert(!__traits(compiles, { + foreach (i, const ref double x; iarr) {} + })); + static assert(!__traits(compiles, { + foreach (i, immutable ref double x; iarr) {} + })); + } +} + +void test4090c() +{ + foreach ( x; 1..11) static assert(is(typeof(x) == int)); + foreach ( const x; 1..11) static assert(is(typeof(x) == const int)); + foreach (immutable x; 1..11) static assert(is(typeof(x) == immutable int)); + + foreach ( int x; 1..11) static assert(is(typeof(x) == int)); + foreach ( const int x; 1..11) static assert(is(typeof(x) == const int)); + foreach (immutable int x; 1..11) static assert(is(typeof(x) == immutable int)); + + foreach ( ref x; 1..11) static assert(is(typeof(x) == int)); + foreach ( const ref x; 1..11) static assert(is(typeof(x) == const int)); + static assert(!__traits(compiles, { + foreach (immutable ref x; 1..11) {} + })); + + foreach ( double x; 1..11) static assert(is(typeof(x) == double)); + foreach ( const double x; 1..11) static assert(is(typeof(x) == const double)); + foreach (immutable double x; 1..11) static assert(is(typeof(x) == immutable double)); + + foreach ( ref double x; 1..11) static assert(is(typeof(x) == double)); + foreach ( const ref double x; 1..11) static assert(is(typeof(x) == const double)); + static assert(!__traits(compiles, { + foreach (immutable ref double x; 1..11) {} + })); +} diff --git a/gcc/testsuite/gdc.test/compilable/test4364.d b/gcc/testsuite/gdc.test/compilable/test4364.d new file mode 100644 index 00000000000..fb4e913b123 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test4364.d @@ -0,0 +1,8 @@ +struct Object{} +class Game {} + +void main() +{ + static assert(is(Object == struct)); + static assert(is(object.Object == class)); +} diff --git a/gcc/testsuite/gdc.test/compilable/test4375.d b/gcc/testsuite/gdc.test/compilable/test4375.d new file mode 100644 index 00000000000..234895e24ce --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test4375.d @@ -0,0 +1,473 @@ +// REQUIRED_ARGS: -unittest +// 4375: disallow dangling else + +void main() { + + if (true) { + if (false) { + assert(1); + } else { + assert(2); + } + } + + + if (true) { + if (false) + assert(7); + } else + assert(8); + + + if (true) { + if (false) + assert(9); + else + assert(10); + } + + + { + if (true) + assert(11); + else + assert(12); + } + + + { +label1: + if (true) + assert(13); + else + assert(14); + } + + + if (true) + foreach (i; 0 .. 5) { + if (true) + assert(17); + else + assert(18); + } + + + if (true) { + foreach (i; 0 .. 5) + if (true) + assert(18.1); + } else + assert(18.2); + + + if (true) + assert(19); + else + assert(20); + + + if (true) + assert(21); + else if (false) + assert(22); + else + assert(23); + + + version (A) { + if (true) + assert(26); + } else + assert(27); + + + version (A) { + if (true) + assert(28); + else + assert(29); + } + + + version (A) + assert(30); + else version (B) + assert(31); + else + assert(32); + + + static if (true) { + static if (true) + assert(35); + } else + assert(36); + + + static if (true) { + static if (true) + assert(37); + else + assert(38); + } + + + static if (true) + assert(39); + else static if (true) + assert(40); + else + assert(41); + + switch (4) { + case 0: + if (true) + assert(42); + else + assert(43); + break; + case 1: .. case 5: + if (true) + assert(44); + else + assert(45); + break; + default: + if (true) + assert(46); + else + assert(47); + break; + } + + // (o_O) + switch (1) + default: + if (true) + assert(113); + else + assert(114); + + // (o_O) + final switch (1) + case 1: + if (true) + assert(117); + else + assert(118); + + mixin(q{ + if (true) + assert(56); + else + assert(57); + }); + + + + while (false) + if (true) + assert(66); + else + assert(67); + + + if (true) + while (false) + assert(68); + else + assert(69); + + + do + if (true) + assert(72); + else + assert(73); + while (false); + + + if (true) + do + if (true) + assert(74); + else + assert(75); + while (false); + + for ( + if (true) // (o_O) + assert(78); + else + assert(79); + false; false + ) + if (true) + assert(80); + else + assert(81); + + if (true) + for (if (true) assert(84); else assert(85); false;) + assert(86); + + + if (true) + if (true) + if (true) + if (true) + if (true) + assert(87); + + auto x = new C; + + + if (true) + while (false) + for (;;) + scope (exit) + synchronized (x) + assert(88); + else + assert(89); + + + if (true) + while (false) + for (;;) { + scope (exit) + synchronized (x) + if (true) + assert(90); + else + assert(89); + } + + + if (true) + while (false) + for (;;) + scope (exit) + synchronized (x) + if (true) + assert(90); + else + assert(89); + else + assert(12); + + + with (x) + if (false) + assert(92); + else + assert(93); + + + try + if (true) + assert(94); + else + assert(95); + catch (Exception e) + if (true) + assert(96); + else + assert(97); + finally + if (true) + assert(98); + else + assert(99); + + + if (true) + try + if (true) + assert(100); + else + assert(101); + finally + assert(102); + + if (true) + try + assert(109); + catch(Exception e) + if (true) + assert(110); + else + assert(112); + finally + assert(111); + + static struct F { + static if (true) + int x; + else + int y; + + static if (true) { + static if (false) + int z; + } else + int w; + + static if (true) + int t; + else static if (false) + int u; + else + int v; + } + + if (true) + if (true) + assert(113); + else + assert(114); + else + assert(115); + + static if (true) + static if (true) + assert(116); + else + assert(117); + else + assert(118); + +} + +unittest { + if (true) + assert(50); + else + assert(51); +} + +class C { + invariant() { + if (true) + assert(58); + else + assert(59); + } + + int f() + in { + if (true) + assert(60); + else + assert(61); + } + out(res) { + if (true) + assert(62); + else + assert(63); + } + body { + if (true) + assert(64); + else + assert(65); + return 0; + } +} + +enum q = q{ + if(true) + if(true) + assert(54.1); + else + assert(55.2); +}; + +static if (true) + struct F0 {} +else static if (true) + struct F1 {} +else + struct F2 {} + +static if (true) { + static if (false) + struct F3 {} +} else + struct F4 {} + +version(A) { + version(B) + struct F5 {} +} else + struct F6 {} + +version(A) { + version(B) + struct F5a {} + else + struct F5b {} +} + +version (C) + struct F5c {} +else + struct F5d {} + +struct F7 { + static if (true) + int x; + else + float x; + +private: + static if (true) + int y; + else + float y; +} + +template F8() { + static if (true) + int x; + else + float x; +} + +static if (true) + align(1) + static if (false) + struct F9 {} + +static if (true) + align(1) { + extern(C) + pure + static if (false) + void F10(){} + else + void F11(){} + } + + +void f() { + int[] x; + static if (5 > 0) + version (Y) + scope (failure) + foreach (i, e; x) + while (i > 20) + with (e) + if (e < 0) + synchronized(e) + assert(1); + else + assert(2); + else + x = null; + else + x = null; +} + diff --git a/gcc/testsuite/gdc.test/compilable/test50.d b/gcc/testsuite/gdc.test/compilable/test50.d new file mode 100644 index 00000000000..f05c3e4bc06 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test50.d @@ -0,0 +1,10 @@ +// EXTRA_SOURCES: imports/test50a.d +// PERMUTE_ARGS: + +import imports.test50a; + +class Bar : Foo { + alias typeof(Foo.tupleof) Bleh; +} + + diff --git a/gcc/testsuite/gdc.test/compilable/test5227.d b/gcc/testsuite/gdc.test/compilable/test5227.d new file mode 100644 index 00000000000..c270b79245b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test5227.d @@ -0,0 +1,124 @@ +/* +REQUIRED_ARGS: +PERMUTE_ARGS: +TEST_OUTPUT: +--- +log() +1.70475L +log2() +2.45943L +log10() +0.740363L +round() +6.00000L +floor() +5.00000F +5.00000 +5.00000L +ceil() +6.00000F +6.00000 +6.00000L +trunc() +5.00000L +expm1() +243.692L +exp2() +45.2548L +fmin() +-3.2L +fmax() +5.2L +copysign() +-2.5F +-2.5 +-2.5L +pow() +9.88212F +9.88212 +9.88212L +9.88212 +fma() +-12.84L +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=5227 + +import std.math; + +pragma(msg, "log()"); +enum logf = log(5.5f); //pragma(msg, logf); +enum logd = log(5.5 ); //pragma(msg, logd); +enum logr = log(5.5L); pragma(msg, logr); + +pragma(msg, "log2()"); +enum log2f = log2(5.5f); //pragma(msg, log2f); +enum log2d = log2(5.5 ); //pragma(msg, log2d); +enum log2r = log2(5.5L); pragma(msg, log2r); + +pragma(msg, "log10()"); +enum log10f = log10(5.5f); //pragma(msg, log10f); +enum log10d = log10(5.5 ); //pragma(msg, log10d); +enum log10r = log10(5.5L); pragma(msg, log10r); + +pragma(msg, "round()"); +enum roundf = round(5.5f); //pragma(msg, roundf); +enum roundd = round(5.5 ); //pragma(msg, roundd); +enum roundr = round(5.5L); pragma(msg, roundr); + +pragma(msg, "floor()"); +enum floorf = floor(5.5f); pragma(msg, floorf); +enum floord = floor(5.5 ); pragma(msg, floord); +enum floorr = floor(5.5L); pragma(msg, floorr); + +pragma(msg, "ceil()"); +enum ceilf = ceil(5.5f); pragma(msg, ceilf); +enum ceild = ceil(5.5 ); pragma(msg, ceild); +enum ceilr = ceil(5.5L); pragma(msg, ceilr); + +pragma(msg, "trunc()"); +enum truncf = trunc(5.5f); //pragma(msg, truncf); +enum truncd = trunc(5.5 ); //pragma(msg, truncd); +enum truncr = trunc(5.5L); pragma(msg, truncr); + +pragma(msg, "expm1()"); +enum expm1f = expm1(5.5f); //pragma(msg, expm1f); +enum expm1d = expm1(5.5 ); //pragma(msg, expm1d); +enum expm1r = expm1(5.5L); pragma(msg, expm1r); + +pragma(msg, "exp2()"); +enum exp2f = exp2(5.5f); //pragma(msg, exp2f); +enum exp2d = exp2(5.5 ); //pragma(msg, exp2d); +enum exp2r = exp2(5.5L); pragma(msg, exp2r); + + + +pragma(msg, "fmin()"); +enum fminf = fmin(-3.2f, 5.2f); //pragma(msg, fminf); +enum fmind = fmin(-3.2 , 5.2 ); //pragma(msg, fmind); +enum fminr = fmin(-3.2L, 5.2L); pragma(msg, fminr); + +pragma(msg, "fmax()"); +enum fmaxf = fmax(-3.2f, 5.2f); //pragma(msg, fmaxf); +enum fmaxd = fmax(-3.2 , 5.2 ); //pragma(msg, fmaxd); +enum fmaxr = fmax(-3.2L, 5.2L); pragma(msg, fmaxr); + +pragma(msg, "copysign()"); +enum csf = copysign(2.5f, -3.0f); pragma(msg, csf); static assert(csf == -2.5); +enum csd = copysign(2.5 , -3.0 ); pragma(msg, csd); static assert(csd == -2.5); +enum csr = copysign(2.5L, -3.0L); pragma(msg, csr); static assert(csr == -2.5); + +pragma(msg, "pow()"); +enum powf = pow(2.5f, 2.5f); pragma(msg, powf); +enum powd = pow(2.5 , 2.5 ); pragma(msg, powd); +enum powr = pow(2.5L, 2.5L); pragma(msg, powr); +enum powctfe = 2.5 ^^ 2.5; pragma(msg, powctfe); + + +pragma(msg, "fma()"); +enum fmaf = fma(-3.2f, 5.2f, 3.8f); //pragma(msg, fmaf); +enum fmad = fma(-3.2 , 5.2 , 3.8 ); //pragma(msg, fmad); +enum fmar = fma(-3.2L, 5.2L, 3.8L); pragma(msg, fmar); + + diff --git a/gcc/testsuite/gdc.test/compilable/test55.d b/gcc/testsuite/gdc.test/compilable/test55.d new file mode 100644 index 00000000000..0dd7b7b4136 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test55.d @@ -0,0 +1,20 @@ +// COMPILE_SEPARATELY +// EXTRA_SOURCES: imports/test55a.d +// PERMUTE_ARGS: -dw +// REQUIRED_ARGS: -d + +public import imports.test55a; + +class Queue { + alias int ListHead; + Arm a; +} + +class MessageQueue : Queue { +} + +class Queue2 { + alias int ListHead; + Arm2 a; +} + diff --git a/gcc/testsuite/gdc.test/compilable/test59.d b/gcc/testsuite/gdc.test/compilable/test59.d new file mode 100644 index 00000000000..c9f4edfba18 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test59.d @@ -0,0 +1,4 @@ +// PERMUTE_ARGS: + +public import imports.test59a; +public import imports.test59b; diff --git a/gcc/testsuite/gdc.test/compilable/test6013.d b/gcc/testsuite/gdc.test/compilable/test6013.d new file mode 100644 index 00000000000..5824c9155b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6013.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -de +import imports.test6013; + +static assert(__traits(compiles, public_alias_value)); +static assert(!__traits(compiles, private_alias_value)); +static assert(__traits(compiles, public_alias_func())); +static assert(!__traits(compiles, private_alias_func())); +static assert(__traits(compiles, () { public_alias_type val; })); +static assert(!__traits(compiles, () { private_alias_type val; })); diff --git a/gcc/testsuite/gdc.test/compilable/test602.d b/gcc/testsuite/gdc.test/compilable/test602.d new file mode 100644 index 00000000000..979af91e5ef --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test602.d @@ -0,0 +1,412 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +// Disallow skipping variable decl +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + int x; + label: {} + assert(!x); +})); + +// Disallow skipping variable in block backwards +static assert(!__traits(compiles, (bool b) +{ + { + int x; + label: {} + assert(!x); + } + if (b) goto label; +})); + +// Disallow skipping backwards int block +static assert(!__traits(compiles, (bool b) +{ + { + int x; + label: {} + assert(!x); + } + if (b) goto label; +})); + +// Variable inside try block +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + try + { + int x; + label: {} + assert(!x); + } + catch + { + } +})); + +// Variable inside catch block +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + try + { + } + catch + { + int x; + label: {} + assert(!x); + } +})); + +// Goto into catch block with unnamed exception +static assert(__traits(compiles, (bool b) +{ + if (b) goto label; + try + { + } + catch(Exception) + { + label: {} + } +})); + +// Goto into catch block with named exception +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + try + { + } + catch(Exception e) + { + label: {} + assert(e); + } +})); + +// Goto into finally block +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + try + { + } + finally + { + label: {} + } +})); + +// Goto into variable with block +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + struct S + { + int x; + } + with (S()) + { + label: {} + assert(!x); + } +})); + +// Goto backwards into variable with block +static assert(!__traits(compiles, (bool b) +{ + struct S + { + int x; + } + with (S()) + { + label: {} + assert(!x); + } + if (b) goto label; +})); + +// Goto into symbolic with block +static assert(__traits(compiles, (bool b) +{ + if (b) goto label; + struct S + { + int x; + } + with (S) + { + label: {} + } +})); + +// Goto backwards into symbolic with block +static assert(__traits(compiles, (bool b) +{ + struct S + { + int x; + } + with (S) + { + label: {} + } + if (b) goto label; +})); + +// Goto into for loop +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + for (int i = 0; i < 8; ++i) + { + label: {} + assert(i); + } +})); + +// Goto into for loop backwards +static assert(!__traits(compiles, (bool b) +{ + for (int i = 0; i < 8; ++i) + { + label: {} + assert(i); + } + if (b) goto label; +})); + +// Goto into foreach loop +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + foreach(i; 0..8) + { + label: {} + assert(i); + } +})); + +// Goto into foreach loop backwards +static assert(!__traits(compiles, (bool b) +{ + foreach(i; 0..8) + { + label: {} + assert(i); + } + if (b) goto label; +})); + +// Goto into if block with variable +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + if (auto x = b) + { + label: {} + assert(x); + } +})); + +// Goto backwards into if block with variable +static assert(!__traits(compiles, (bool b) +{ + if (auto x = b) + { + label: {} + assert(x); + } + if (b) goto label; +})); + +// Goto into if block without variable +static assert(__traits(compiles, (bool b) +{ + if (b) goto label; + if (b) + { + label: {} + } +})); + +// Goto into else block +static assert(__traits(compiles, (bool b) +{ + if (b) goto label; + if (auto x = b) + { + } + else + { + label: {} + } +})); + +// Goto backwards into else with variable +static assert(!__traits(compiles, (bool b) +{ + if (auto x = b) + { + } + else + { + int y; + label: {} + } + if (b) goto label; +})); + +// Goto into while block +static assert(__traits(compiles, (bool b) +{ + if (b) goto label; + while (b) + { + label: {} + } +})); + +// Goto into while block with internal variable +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + while (b) + { + int x; + label: {} + assert(!x); + } +})); + +// Goto into do block +static assert(__traits(compiles, (bool b) +{ + if (b) goto label; + do + { + label: {} + } + while (b); +})); + +// Goto over switch variable +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + switch(0) + { + default: + break; + int x; + label: {} + } +})); + +// Goto over switch variable +static assert(!__traits(compiles, (bool b) +{ + if (b) goto label; + switch(0) + { + default: + break; + case 0: + int x; + label: {} + } +})); + +// Goto into synchronized statement +static assert(!__traits(compiles, (bool b) +{ + if (b) + goto label; + synchronized + { + label: {} + } +})); + +// Goto into scope(success) with variable +static assert(!__traits(compiles, (bool b) +{ + scope(success) { int x; label: {} assert(!x); } + if (b) + goto label; +})); + +// Goto into scope(failure) +static assert(!__traits(compiles, (bool b) +{ + if (b) + goto label; + scope(failure) { label: {} } +})); + +// Goto into scope(failure) with variable +static assert(!__traits(compiles, (bool b) +{ + scope(failure) { int x; label: {} assert(!x); } + if (b) + goto label; +})); + +// Goto into scope(exit) +static assert(!__traits(compiles, (bool b) +{ + if (b) + goto label; + scope(exit) { label: {} } +})); + +// Goto into scope(exit) +static assert(!__traits(compiles, (bool b) +{ + scope(exit) { label: {} } + if (b) + goto label; +})); + +// Goto into scope(exit) with variable +static assert(!__traits(compiles, (bool b) +{ + scope(exit) { int x; label: {} assert(!x); } + if (b) + goto label; +})); + +/***************************************************/ +// 11659 + +int test11659() +{ + goto LABEL; + enum expr = "0"; + LABEL: + return mixin(expr); +} + +/***************************************************/ +// 13321 + +void test13321(bool b) +{ + static struct Foo + { + this(int) {} + } + + Foo x; + if (b) + goto EXIT; + x = Foo(1); + EXIT: +} + diff --git a/gcc/testsuite/gdc.test/compilable/test6056a.d b/gcc/testsuite/gdc.test/compilable/test6056a.d new file mode 100644 index 00000000000..fb4f1897870 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6056a.d @@ -0,0 +1,3 @@ +alias const(typeof('c')*) A; +alias const(typeof(0)*) B; +static assert(is(B == const(int*))); diff --git a/gcc/testsuite/gdc.test/compilable/test6056b.d b/gcc/testsuite/gdc.test/compilable/test6056b.d new file mode 100644 index 00000000000..ff0d6bb1bfe --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6056b.d @@ -0,0 +1,5 @@ +template X(T) { alias T X; } + +alias const(X!char*) A; +alias const(X!int*) B; +static assert(is(B == const(int*))); diff --git a/gcc/testsuite/gdc.test/compilable/test6056c.d b/gcc/testsuite/gdc.test/compilable/test6056c.d new file mode 100644 index 00000000000..c17b3339dd9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6056c.d @@ -0,0 +1,3 @@ +alias int T; +static assert( is( T** : const(T**) )); +static assert( is( T* : const(T* ) )); diff --git a/gcc/testsuite/gdc.test/compilable/test6089.d b/gcc/testsuite/gdc.test/compilable/test6089.d new file mode 100644 index 00000000000..b1fa2cf4b8f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6089.d @@ -0,0 +1,6 @@ +// PERMUTE_ARGS: +void main() +{ + extern int[1][1] foo; +} + diff --git a/gcc/testsuite/gdc.test/compilable/test61.d b/gcc/testsuite/gdc.test/compilable/test61.d new file mode 100644 index 00000000000..e4d3d659367 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test61.d @@ -0,0 +1,15 @@ +// PERMUTE_ARGS: + +import imports.test61a; +alias imports.test61a.bar bar; + +mixin(` +enum FooB { fooB }; +void bar(FooB x) {} +`); + +void test() +{ + bar(FooA.fooA); + bar(FooB.fooB); +} diff --git a/gcc/testsuite/gdc.test/compilable/test62.d b/gcc/testsuite/gdc.test/compilable/test62.d new file mode 100644 index 00000000000..c723a96b788 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test62.d @@ -0,0 +1,7 @@ +// PERMUTE_ARGS: + +import imports.test62a; + +struct S { } + +void main() { } diff --git a/gcc/testsuite/gdc.test/compilable/test63.d b/gcc/testsuite/gdc.test/compilable/test63.d new file mode 100644 index 00000000000..70d49646f77 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test63.d @@ -0,0 +1,7 @@ +// EXTRA_SOURCES: imports/test63a.d +// PERMUTE_ARGS: + +private import imports.test63a; + +const int SIZE = 7; + diff --git a/gcc/testsuite/gdc.test/compilable/test6319.d b/gcc/testsuite/gdc.test/compilable/test6319.d new file mode 100644 index 00000000000..fb036d744d9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6319.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -debug + +int x; + +void main() pure +{ + debug + { + { + x = 0; + } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test6395.d b/gcc/testsuite/gdc.test/compilable/test6395.d new file mode 100644 index 00000000000..95f1a7eae6e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6395.d @@ -0,0 +1,7 @@ +// REQUIRED_ARGS: -c -Icompilable/extra-files +// EXTRA_SOURCES: b6395.d + +// 6395 + +import c6395; + diff --git a/gcc/testsuite/gdc.test/compilable/test6534.d b/gcc/testsuite/gdc.test/compilable/test6534.d new file mode 100644 index 00000000000..513655d3b70 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6534.d @@ -0,0 +1,39 @@ +void main() +{ + class MC{ int x; } + const class CC{ int x; } static assert(is(typeof( CC.x) == const)); + immutable class IC{ int x; } static assert(is(typeof( IC.x) == immutable)); + shared class SC{ int x; } static assert(is(typeof( SC.x) == shared)); + shared const class SCC{ int x; } static assert(is(typeof(SCC.x) == shared) && is(typeof(SCC.x) == const)); + + struct MS{ int x; } + const struct CS{ int x; } static assert(is(typeof( CS.x) == const)); + immutable struct IS{ int x; } static assert(is(typeof( IS.x) == immutable)); + shared struct SS{ int x; } static assert(is(typeof( SS.x) == shared)); + shared const struct SCS{ int x; } static assert(is(typeof(SCS.x) == shared) && is(typeof(SCS.x) == const)); + + union MU{ int x; } + const union CU{ int x; } static assert(is(typeof( CU.x) == const)); + immutable union IU{ int x; } static assert(is(typeof( IU.x) == immutable)); + shared union SU{ int x; } static assert(is(typeof( SU.x) == shared)); + shared const union SCU{ int x; } static assert(is(typeof(SCU.x) == shared) && is(typeof(SCU.x) == const)); + + + static class S_MC{ int x; } + const static class S_CC{ int x; } static assert(is(typeof( S_CC.x) == const)); + immutable static class S_IC{ int x; } static assert(is(typeof( S_IC.x) == immutable)); + shared static class S_SC{ int x; } static assert(is(typeof( S_SC.x) == shared)); + shared const static class S_SCC{ int x; } static assert(is(typeof(S_SCC.x) == shared) && is(typeof(S_SCC.x) == const)); + + static struct S_MS{ int x; } + const static struct S_CS{ int x; } static assert(is(typeof( S_CS.x) == const)); + immutable static struct S_IS{ int x; } static assert(is(typeof( S_IS.x) == immutable)); + shared static struct S_SS{ int x; } static assert(is(typeof( S_SS.x) == shared)); + shared const static struct S_SCS{ int x; } static assert(is(typeof(S_SCS.x) == shared) && is(typeof(S_SCS.x) == const)); + + static union S_MU{ int x; } + const static union S_CU{ int x; } static assert(is(typeof( S_CU.x) == const)); + immutable static union S_IU{ int x; } static assert(is(typeof( S_IU.x) == immutable)); + shared static union S_SU{ int x; } static assert(is(typeof( S_SU.x) == shared)); + shared const static union S_SCU{ int x; } static assert(is(typeof(S_SCU.x) == shared) && is(typeof(S_SCU.x) == const)); +} diff --git a/gcc/testsuite/gdc.test/compilable/test6552.d b/gcc/testsuite/gdc.test/compilable/test6552.d new file mode 100644 index 00000000000..4a06f5cb68e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6552.d @@ -0,0 +1,26 @@ +// REQUIRED_ARGS: -w + +void main() +{ + int i; + switch (i) + { + case 1, 2: + case 3, 4: break; + default: break; + } + + char ch; + switch (ch) + { + case 'U', 'u': + case 'L', 'l': + default: + } + + switch (i) + { + default: case 1: + case 3,4: + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test66.d b/gcc/testsuite/gdc.test/compilable/test66.d new file mode 100644 index 00000000000..1213884f72f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test66.d @@ -0,0 +1,21 @@ +// PERMUTE_ARGS: + +import imports.test66a; + +alias int TOK; + +enum +{ + TOKmax +}; + +struct Token +{ + static char[] tochars[TOKmax]; +} + +class Lexer +{ + Token token; +} + diff --git a/gcc/testsuite/gdc.test/compilable/test67.d b/gcc/testsuite/gdc.test/compilable/test67.d new file mode 100644 index 00000000000..bcd48b20ddf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test67.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: + +import imports.test67a; + +interface I +{ +} + +interface SubI : I +{ +} + diff --git a/gcc/testsuite/gdc.test/compilable/test68.d b/gcc/testsuite/gdc.test/compilable/test68.d new file mode 100644 index 00000000000..bfac489342d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test68.d @@ -0,0 +1,19 @@ +// PERMUTE_ARGS: + +// Bugzilla 4278 + +import imports.test68a; + +class Foo : OtherModuleClass +{ + override void foo() + { + super.foo(); + } +} + +void main() +{ + new Foo(); +} + diff --git a/gcc/testsuite/gdc.test/compilable/test69.d b/gcc/testsuite/gdc.test/compilable/test69.d new file mode 100644 index 00000000000..fb8e1ba30c8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test69.d @@ -0,0 +1,54 @@ +// PERMUTE_ARGS: + +// ICE(expression.c) DMD 0.110 +// http://www.digitalmars.com/d/archives/digitalmars/D/bugs/2966.html + +string str255() { return "\255"; } +void fromFail49() +{ + switch("abc") + { + case "": + case str255(): + break; + default: + break; + } +} + +// Bugzilla 5735 + +struct A {} +void b() {} + +void foo(bool cond) {} + +void main() +{ + A a; + int i; + + static assert(!__traits(compiles, assert(a))); + static assert(!__traits(compiles, assert(i || a))); + static assert(!__traits(compiles, assert(0 || a))); + static assert(!__traits(compiles, assert(i && a))); + static assert(!__traits(compiles, assert(1 && a))); + + static assert(!__traits(compiles, foo(a))); + static assert(!__traits(compiles, foo(i || a))); + static assert(!__traits(compiles, foo(0 || a))); + static assert(!__traits(compiles, foo(i && a))); + static assert(!__traits(compiles, foo(1 && a))); + + static assert(!__traits(compiles, assert(b))); + static assert(!__traits(compiles, assert(i || b))); + static assert(!__traits(compiles, assert(0 || b))); + static assert(!__traits(compiles, assert(i && b))); + static assert(!__traits(compiles, assert(1 && b))); + + static assert(!__traits(compiles, foo(b))); + static assert(!__traits(compiles, foo(i || b))); + static assert(!__traits(compiles, foo(0 || b))); + static assert(!__traits(compiles, foo(i && b))); + static assert(!__traits(compiles, foo(1 && b))); +} diff --git a/gcc/testsuite/gdc.test/compilable/test6999.d b/gcc/testsuite/gdc.test/compilable/test6999.d new file mode 100644 index 00000000000..c4e916f75cf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test6999.d @@ -0,0 +1,29 @@ +// 6999: inout in front of return type + +struct A +{ +inout: + inout(int) foo() + { + return 0; + } +} + +struct B +{ + inout + { + inout(int) foo() + { + return 0; + } + } +} + +struct C +{ + inout inout(int) foo() + { + return 0; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test70.d b/gcc/testsuite/gdc.test/compilable/test70.d new file mode 100644 index 00000000000..9a821b23202 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test70.d @@ -0,0 +1,10 @@ +import imports.test70 : foo; + +void foo(int) // overloads with selective import +{ +} + +void bar() +{ + foo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test7065.d b/gcc/testsuite/gdc.test/compilable/test7065.d new file mode 100644 index 00000000000..e078debc7cd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7065.d @@ -0,0 +1,38 @@ +void main() +{ + align(1) + struct X1 { ubyte b; int n; } + static assert(X1.sizeof == 8); + static assert(X1.b.offsetof == 0); + static assert(X1.n.offsetof == 4); + //X1 x1; + //assert(cast(void*)&x1.b == cast(void*)&x1 + 0); + //assert(cast(void*)&x1.n == cast(void*)&x1 + 1); + + struct Y1 { ubyte b; int n; } + static assert(Y1.sizeof == 8); + static assert(Y1.b.offsetof == 0); + static assert(Y1.n.offsetof == 4); + //Y1 y1; + //assert(cast(void*)&y1.b == cast(void*)&y1 + 0); + //assert(cast(void*)&y1.n == cast(void*)&y1 + 4); + + int local; + + align(1) + struct X2 { ubyte b; int n; int f(){ return local; } } + static assert(X2.sizeof == 8 + (void*).sizeof); + static assert(X2.b.offsetof == 0); + static assert(X2.n.offsetof == 4); + //X2 x2; + //assert(cast(void*)&x2.b == cast(void*)&x2 + 0); + //assert(cast(void*)&x2.n == cast(void*)&x2 + 1); + + struct Y2 { ubyte b; int n; int f(){ return local; } } + static assert(Y2.sizeof == 8 + (void*).sizeof); + static assert(Y2.b.offsetof == 0); + static assert(Y2.n.offsetof == 4); + //Y2 y2; + //assert(cast(void*)&y2.b == cast(void*)&y2 + 0); + //assert(cast(void*)&y2.n == cast(void*)&y2 + 4); +} diff --git a/gcc/testsuite/gdc.test/compilable/test71.d b/gcc/testsuite/gdc.test/compilable/test71.d new file mode 100644 index 00000000000..83b24a01b32 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test71.d @@ -0,0 +1,6 @@ +import imports.test71; + +void bar() +{ + imports.test71.foo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test7172.d b/gcc/testsuite/gdc.test/compilable/test7172.d new file mode 100644 index 00000000000..a4cf663066e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7172.d @@ -0,0 +1,23 @@ +void main() +{ + abstract class AbstractC{} + static assert(!__traits(compiles, { new AbstractC(); })); + + final class FinalC{} + static assert(!__traits(compiles, { class D : FinalC{} })); + + scope class ScopeC{} + static assert(!__traits(compiles, { auto sc = new ScopeC(); })); + static assert( __traits(compiles, { scope sc = new ScopeC(); })); + + synchronized class SyncC{ void f(){} } + static assert(SyncC.f.mangleof[$-13..$] == "5SyncC1fMOFZv"); + + @safe class SCx{ void f(){} } + @trusted class SCy{ void f(){} } + @system class SCz{ void f(){} } + + static assert(SCx.f.mangleof[$-12..$] == "3SCx1fMFNfZv"); // Nf: FuncAttrSafe + static assert(SCy.f.mangleof[$-12..$] == "3SCy1fMFNeZv"); // Ne: FuncAttrTrusted + static assert(SCz.f.mangleof[$-10..$] == "3SCz1fMFZv"); // (none) +} diff --git a/gcc/testsuite/gdc.test/compilable/test7190.d b/gcc/testsuite/gdc.test/compilable/test7190.d new file mode 100644 index 00000000000..5143f55e772 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7190.d @@ -0,0 +1,8 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -Icompilable/extra-files +// EXTRA_FILES: extra-files/example7190/controllers/HomeController.d extra-files/example7190/models/HomeModel.d extra-files/serenity7190/core/Controller.d extra-files/serenity7190/core/Model.d + +import example7190.controllers.HomeController; +import example7190.models.HomeModel; + +void main(){} diff --git a/gcc/testsuite/gdc.test/compilable/test72.d b/gcc/testsuite/gdc.test/compilable/test72.d new file mode 100644 index 00000000000..5de9d42a72d --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test72.d @@ -0,0 +1,8 @@ +module test72; + +import imports.test72a, imports.test72c; + +void bar() +{ + foo(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test7252.d b/gcc/testsuite/gdc.test/compilable/test7252.d new file mode 100644 index 00000000000..9cef2abe081 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7252.d @@ -0,0 +1,10 @@ +alias char* function() Func; + +alias const char* function() CFunc; + +void to(S)(S) { } + +void foo(CFunc cFunc) +{ + to(cFunc()); +} diff --git a/gcc/testsuite/gdc.test/compilable/test7399.d b/gcc/testsuite/gdc.test/compilable/test7399.d new file mode 100644 index 00000000000..76ac9202c68 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7399.d @@ -0,0 +1,6 @@ +// 7399 +static assert(!__traits(compiles, { import non.existing.file; })); + +// 7400 +static assert(!is(typeof({import non_existing_file;}))); + diff --git a/gcc/testsuite/gdc.test/compilable/test7491.d b/gcc/testsuite/gdc.test/compilable/test7491.d new file mode 100644 index 00000000000..eb742e23598 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7491.d @@ -0,0 +1,53 @@ +struct Struct +{ + import object; + import imports.test7491a; + import renamed=imports.test7491b; +} + +struct AliasThis +{ + Struct _struct; + alias _struct this; +} + +class Base +{ + import object; + import imports.test7491a; + import renamed=imports.test7491b; +} + +class Derived : Base +{ +} + +interface Interface +{ + import object; + import imports.test7491a; + import renamed=imports.test7491b; +} + +class Impl : Interface +{ +} + +static assert(__traits(compiles, Struct.object)); +static assert(__traits(compiles, Struct.imports)); +static assert(__traits(compiles, Struct.renamed)); +static assert(__traits(compiles, AliasThis.object)); +static assert(__traits(compiles, AliasThis.imports)); +static assert(__traits(compiles, AliasThis.renamed)); +static assert(__traits(compiles, Base.object)); +static assert(__traits(compiles, Base.imports)); +static assert(__traits(compiles, Base.renamed)); +static assert(__traits(compiles, Derived.object)); +static assert(__traits(compiles, Derived.imports)); +static assert(__traits(compiles, Derived.renamed)); +static assert(__traits(compiles, Interface.object)); +static assert(__traits(compiles, Interface.imports)); +static assert(__traits(compiles, Interface.renamed)); +static assert(__traits(compiles, Impl.object)); +static assert(__traits(compiles, Impl.imports)); +static assert(__traits(compiles, Impl.renamed)); diff --git a/gcc/testsuite/gdc.test/compilable/test7524.d b/gcc/testsuite/gdc.test/compilable/test7524.d new file mode 100644 index 00000000000..6ff491a7159 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7524.d @@ -0,0 +1,3 @@ +// 7524 + +#line __LINE__ "y.d" diff --git a/gcc/testsuite/gdc.test/compilable/test7569.d b/gcc/testsuite/gdc.test/compilable/test7569.d new file mode 100644 index 00000000000..59d73aa4f74 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7569.d @@ -0,0 +1,9 @@ +template Tuple(T...) +{ + alias T Tuple; +} + +void main() +{ + Tuple!(int, int) tup1 = void; +} diff --git a/gcc/testsuite/gdc.test/compilable/test7754.d b/gcc/testsuite/gdc.test/compilable/test7754.d new file mode 100644 index 00000000000..1ce9b448995 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test7754.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -H -Hd${RESULTS_DIR}/compilable +// POST_SCRIPT: compilable/extra-files/test7754-postscript.sh +// PERMUTE_ARGS: -d -dw + +struct Foo(T) +{ + shared static this() + { + } + + static this() + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test8038.d b/gcc/testsuite/gdc.test/compilable/test8038.d new file mode 100644 index 00000000000..436d7072a42 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8038.d @@ -0,0 +1,13 @@ +template t(T){alias T t;} + +t!(#line 10 + t!( + int, + ) +) i; + +t!( + t!(#line 10 + int, + ) +) j; diff --git a/gcc/testsuite/gdc.test/compilable/test8041.d b/gcc/testsuite/gdc.test/compilable/test8041.d new file mode 100644 index 00000000000..ee47120e0ca --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8041.d @@ -0,0 +1,10 @@ +// PERMUTE_ARGS: + +struct Foo { } + +void main() +{ + static Foo sf; // ok + __gshared Foo gf; // was: Error: non-constant expression gf = 0 + __gshared int[1][1] arr; // dup: Issue 6089 +} diff --git a/gcc/testsuite/gdc.test/compilable/test8296.d b/gcc/testsuite/gdc.test/compilable/test8296.d new file mode 100644 index 00000000000..d27ba15f3e0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8296.d @@ -0,0 +1,33 @@ +struct bar2 +{ + int i; + @disable this(); + this(int i) + { + this.i = i; + } +} + +class InnerBar { + bar2 b; + + this() + { + b = bar2(0); + } +} + +struct bar1 +{ + InnerBar b; +} + +class Foo +{ + bar1 m_bar1; +} + +void main(string[] args) +{ + auto foo = new Foo(); +} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/compilable/test8509.d b/gcc/testsuite/gdc.test/compilable/test8509.d new file mode 100644 index 00000000000..a9072231fe8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8509.d @@ -0,0 +1,11 @@ +module test8509; +enum E : string { a = "hello", b = "world" } +struct S { E opCat(S s) { return E.a; } E opCat(string s) { return E.a; } } + +void main() +{ + E e3 = S() ~ S(); + E e4 = S() ~ "a"; + assert(e3 == E.a); + assert(e4 == E.a); +} diff --git a/gcc/testsuite/gdc.test/compilable/test8513.d b/gcc/testsuite/gdc.test/compilable/test8513.d new file mode 100644 index 00000000000..bcdc657be93 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8513.d @@ -0,0 +1,32 @@ +interface I_Foo { void i_outer(); } +class C_Foo { void c_outer() { } } + +class Bar +{ + interface I_Foo { void i_inner(); } + class C_Foo { void c_inner() { } } + + class Impl1 : C_Foo, I_Foo + { + override void i_inner() { } + override void c_inner() { } + } + + class Impl2 : C_Foo, .I_Foo + { + override void i_outer() { } + override void c_inner() { } + } + + class Impl3 : .C_Foo, I_Foo + { + override void i_inner() { } + override void c_outer() { } + } + + class Impl4 : .C_Foo, .I_Foo + { + override void i_outer() { } + override void c_outer() { } + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test8543.d b/gcc/testsuite/gdc.test/compilable/test8543.d new file mode 100644 index 00000000000..4b29542647e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8543.d @@ -0,0 +1,32 @@ + +version (D_SIMD) +{ + struct vfloat + { + public: + __vector(float[4]) f32; + + this(float X) nothrow + { + f32.ptr[0] = X; + f32.ptr[1] = X; + f32.ptr[2] = X; + f32.ptr[3] = X; + } + this(float X, float Y, float Z, float W) nothrow + { + f32.array[0] = X; + f32.array[1] = Y; + f32.array[2] = Z; + f32.array[3] = W; + } + this(float[4] values) nothrow + { + f32.array = values; + } + } + + immutable GvfGlobal_ThreeA = vfloat(3.0f); + immutable GvfGlobal_ThreeB = vfloat(3.0f, 3.0f, 3.0f, 3.0f); + immutable GvfGlobal_ThreeC = vfloat([3.0f, 3.0f, 3.0f, 3.0f]); +} diff --git a/gcc/testsuite/gdc.test/compilable/test8631.d b/gcc/testsuite/gdc.test/compilable/test8631.d new file mode 100644 index 00000000000..662729f2535 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8631.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -de + +class B { + int foo() immutable { return 2; } + int foo() const { return 2; } +} +class D : B { + override int foo() immutable { return 2; } + int foo() const shared { return 2; } + override int foo() const { return 2; } +} diff --git a/gcc/testsuite/gdc.test/compilable/test8675.d b/gcc/testsuite/gdc.test/compilable/test8675.d new file mode 100644 index 00000000000..ecabfdd6567 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8675.d @@ -0,0 +1,17 @@ +class MyError : Error +{ + this(string msg) + { + super(msg); + } +} + +void foo() nothrow +{ + throw new Error("Some error"); +} + +void bar() nothrow +{ + throw new MyError("Some error"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test8696.d b/gcc/testsuite/gdc.test/compilable/test8696.d new file mode 100644 index 00000000000..755d52996a3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8696.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -w + +// 8696: incorrect dangling else with version(): +version (all): + +version (linux) +{ +} +else version (OSX) +{ +} +else +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/test8717.d b/gcc/testsuite/gdc.test/compilable/test8717.d new file mode 100644 index 00000000000..26a2866c682 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8717.d @@ -0,0 +1,63 @@ +module test8717; + +struct SPR +{ +private: + enum e = 1; + immutable int ii = 1; + immutable static int sii = 1; + static int sf() { return 1; } + int f() const { return 1; } +} + +static assert(SPR.e == 1); +//static assert(SPR.ii == 1); +static assert(SPR.sii == 1); +static assert(SPR.sf() == 1); +static assert(SPR.init.e == 1); +static assert(SPR.init.ii == 1); +static assert(SPR.init.sii == 1); +static assert(SPR.sf() == 1); +static assert(SPR.init.f() == 1); + +static if(SPR.e != 1) { static assert(0); } +//static if(SPR.ii != 1) { static assert(0); } +static if(SPR.sii != 1) { static assert(0); } +static if(SPR.sf() != 1) { static assert(0); } +static if(SPR.init.e != 1) { static assert(0); } +static if(SPR.init.ii != 1) { static assert(0); } +static if(SPR.init.sii != 1) { static assert(0); } +static if(SPR.sf() != 1) { static assert(0); } +static if(SPR.init.f() != 1) { static assert(0); } + +struct SPT +{ +protected: + enum e = 1; + immutable int ii = 1; + immutable static int sii = 1; + static int sf() { return 1; } + int f() const { return 1; } +} + +static assert(SPT.e == 1); +//static assert(SPT.ii == 1); +static assert(SPT.sii == 1); +static assert(SPT.sf() == 1); +static assert(SPT.init.e == 1); +static assert(SPT.init.ii == 1); +static assert(SPT.init.sii == 1); +static assert(SPT.sf() == 1); +static assert(SPT.init.f() == 1); + +static if(SPT.e != 1) { static assert(0); } +//static if(SPT.ii != 1) { static assert(0); } +static if(SPT.sii != 1) { static assert(0); } +static if(SPT.sf() != 1) { static assert(0); } +static if(SPT.init.e != 1) { static assert(0); } +static if(SPT.init.ii != 1) { static assert(0); } +static if(SPT.init.sii != 1) { static assert(0); } +static if(SPT.sf() != 1) { static assert(0); } +static if(SPT.init.f() != 1) { static assert(0); } + +void main() { } diff --git a/gcc/testsuite/gdc.test/compilable/test8802.d b/gcc/testsuite/gdc.test/compilable/test8802.d new file mode 100644 index 00000000000..7365e91fe77 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8802.d @@ -0,0 +1,39 @@ +// PERMUTE_ARGS: +enum A : typeof(null)* +{ + a = null +} + +enum B : typeof(null)** +{ + a = null +} + +enum C : void* +{ + a = null +} + +enum D : void** +{ + a = null +} + +enum NullEn : void* +{ + z = null +} + +enum E : NullEn +{ + a = null +} + +void main() +{ + auto a = A.a; + auto b = B.a; + auto c = C.a; + auto d = D.a; + auto e = E.a; +} diff --git a/gcc/testsuite/gdc.test/compilable/test8898.d b/gcc/testsuite/gdc.test/compilable/test8898.d new file mode 100644 index 00000000000..9433a77ff58 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8898.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -w +// PERMUTE_ARGS: + +static if (true): + +version (Foo) +{ +} +else +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/test8922a.d b/gcc/testsuite/gdc.test/compilable/test8922a.d new file mode 100644 index 00000000000..e2f3d5c2c67 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8922a.d @@ -0,0 +1,9 @@ +// PERMUTE_ARGS: +import imports.bug8922; + +void test() +{ + static assert(!__traits(compiles, __traits(parent, imports))); + enum x = __traits(parent, imports.bug8922).stringof; + static assert(x == "package imports"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test8922b.d b/gcc/testsuite/gdc.test/compilable/test8922b.d new file mode 100644 index 00000000000..a91601b3219 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8922b.d @@ -0,0 +1,9 @@ +// PERMUTE_ARGS: +void test() +{ + import imports.bug8922; + static assert(!__traits(compiles, __traits(parent, imports))); + enum x = __traits(parent, imports.bug8922).stringof; + static assert(x == "package imports"); +} + diff --git a/gcc/testsuite/gdc.test/compilable/test8922c.d b/gcc/testsuite/gdc.test/compilable/test8922c.d new file mode 100644 index 00000000000..da5ad3a6267 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8922c.d @@ -0,0 +1,10 @@ +// PERMUTE_ARGS: +static import imports.bug8922; + +void test() +{ + static assert(!__traits(compiles, __traits(parent, imports))); + static assert(!__traits(compiles, __traits(parent, bug8922))); + enum x = __traits(parent, imports.bug8922).stringof; + static assert(x == "package imports"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test8922d.d b/gcc/testsuite/gdc.test/compilable/test8922d.d new file mode 100644 index 00000000000..4a56dd7f190 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8922d.d @@ -0,0 +1,10 @@ +// PERMUTE_ARGS: +void test() +{ + static import imports.bug8922; + static assert(!__traits(compiles, __traits(parent, imports))); + static assert(!__traits(compiles, __traits(parent, bug8922))); + enum x = __traits(parent, imports.bug8922).stringof; + static assert(x == "package imports"); +} + diff --git a/gcc/testsuite/gdc.test/compilable/test8922e.d b/gcc/testsuite/gdc.test/compilable/test8922e.d new file mode 100644 index 00000000000..3c52d006b49 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8922e.d @@ -0,0 +1,11 @@ +// PERMUTE_ARGS: +import renamed = imports.bug8922; + +void test() +{ + enum x = __traits(parent, renamed).stringof; + static assert(x == "package imports"); + static assert(!__traits(compiles, __traits(parent, imports))); + static assert(!__traits(compiles, __traits(parent, bug8922))); + static assert(!__traits(compiles, __traits(parent, imports.bug8922))); +} diff --git a/gcc/testsuite/gdc.test/compilable/test8922f.d b/gcc/testsuite/gdc.test/compilable/test8922f.d new file mode 100644 index 00000000000..2b2eb0fb9c7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8922f.d @@ -0,0 +1,10 @@ +// PERMUTE_ARGS: +void test() +{ + import renamed = imports.bug8922; + enum x = __traits(parent, renamed).stringof; + static assert(x == "package imports"); + static assert(!__traits(compiles, __traits(parent, imports))); + static assert(!__traits(compiles, __traits(parent, bug8922))); + static assert(!__traits(compiles, __traits(parent, imports.bug8922))); +} diff --git a/gcc/testsuite/gdc.test/compilable/test8937.d b/gcc/testsuite/gdc.test/compilable/test8937.d new file mode 100644 index 00000000000..c6f59bc1c56 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8937.d @@ -0,0 +1,60 @@ + +mixin template X8937() +{ + int value; +} + +debug = test; + +void main() +{ + // (static) import statement + { + static assert(!__traits(compiles, cos(0))); + if (true) + { + static assert(!__traits(compiles, cos(0))); + import core.stdc.math; + static assert( __traits(compiles, cos(0))); + } + static assert(!__traits(compiles, cos(0))); + + if (true) + import core.stdc.math; + static assert(!__traits(compiles, cos(0))); // fails + + if (true) + static import core.stdc.math; + static assert(!__traits(compiles, core.stdc.math.cos(0))); // fails + } + static assert(!__traits(compiles, cos(0))); + + // mixin statement + { + if (true) + mixin X8937!(); + static assert(!__traits(compiles, value)); // fails + } + + // enum declaration + { + if (true) + enum E { x = 10 } + static assert(!__traits(compiles, E)); // fails + } + + // conditional declarations + { + if (true) + static if (true) struct S1 {} + static assert(!__traits(compiles, S1)); // fails + + if (true) + version (all) struct S2 {} + static assert(!__traits(compiles, S2)); // fails + + if (true) + debug (test) struct S3 {} + static assert(!__traits(compiles, S3)); // fails + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test8959.d b/gcc/testsuite/gdc.test/compilable/test8959.d new file mode 100644 index 00000000000..b7805bbf131 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test8959.d @@ -0,0 +1,55 @@ +/* +TEST_OUTPUT: +--- +U1 = int +U2 = int +V1 = long, K1 = string +V2 = long, K2 = string +TL1 = (int, string) +TL2 = (int, string) +U3 = int +U4 = int +V3 = long, K3 = string +V4 = long, K4 = string +TL3 = (int, string) +TL4 = (int, string) +--- +*/ + +static if (is(int* == U1*, U1)) { pragma(msg, "U1 = ", U1); } +static if (is(int* : U2*, U2)) { pragma(msg, "U2 = ", U2); } +static assert(is(int* == U*, U)); +static assert(is(int* : U*, U)); + +alias AA = long[string]; +static if (is(AA == V1[K1], V1, K1)) { pragma(msg, "V1 = ", V1, ", K1 = ", K1); } +static if (is(AA : V2[K2], V2, K2)) { pragma(msg, "V2 = ", V2, ", K2 = ", K2); } +static assert(is(AA == V[K], V, K)); +static assert(is(AA : V[K], V, K)); + +class B(TL...) {} +class C(TL...) : B!TL {} +alias X = C!(int, string); + +static if (is(X == C!TL1, TL1...)) { pragma(msg, "TL1 = ", TL1); } +static if (is(X : B!TL2, TL2...)) { pragma(msg, "TL2 = ", TL2); } +static assert(is(X == C!TL, TL...)); +static assert(is(X : B!TL, TL...)); + +void test8959() +{ + static if (is(int* == U3*, U3)) { pragma(msg, "U3 = ", U3); } + static if (is(int* : U4*, U4)) { pragma(msg, "U4 = ", U4); } + static assert(is(int* == U*, U)); + static assert(is(int* : U*, U)); + + static if (is(AA == V3[K3], V3, K3)) { pragma(msg, "V3 = ", V3, ", K3 = ", K3); } + static if (is(AA : V4[K4], V4, K4)) { pragma(msg, "V4 = ", V4, ", K4 = ", K4); } + static assert(is(AA == V[K], V, K)); + static assert(is(AA : V[K], V, K)); + + static if (is(X == C!TL3, TL3...)) { pragma(msg, "TL3 = ", TL3); } + static if (is(X : B!TL4, TL4...)) { pragma(msg, "TL4 = ", TL4); } + static assert(is(X == C!TL, TL...)); + static assert(is(X : B!TL, TL...)); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9057.d b/gcc/testsuite/gdc.test/compilable/test9057.d new file mode 100644 index 00000000000..3594a043dfb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9057.d @@ -0,0 +1,20 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -Icompilable/extra-files +// EXTRA_FILES: extra-files/imp9057.d extra-files/imp9057_2.d + +struct Bug9057(T) +{ + T x; +} + +void test9507() { + import imp9057; + Bug9057!(BugInt) xxx; +} + +void test9507_2() { + import imp9057_2; + Bug9057!(BugInt) xxx; +} + + diff --git a/gcc/testsuite/gdc.test/compilable/test9209.d b/gcc/testsuite/gdc.test/compilable/test9209.d new file mode 100644 index 00000000000..03c2b79904a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9209.d @@ -0,0 +1,16 @@ +// PERMUTE_ARGS: + +// 9209 + +auto array(T)(T t){ return t; } + +auto bar()(in int* x) +{ + if (true) return 0; + return array(bar(x)); +} + +void main () +{ + bar(null); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9276.d b/gcc/testsuite/gdc.test/compilable/test9276.d new file mode 100644 index 00000000000..f6cefa5b48c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9276.d @@ -0,0 +1,6 @@ +// EXTRA_SOURCES: imports/test9276parser.d + + +// This is a dummy module for compilable test +void main() +{} diff --git a/gcc/testsuite/gdc.test/compilable/test9278a.d b/gcc/testsuite/gdc.test/compilable/test9278a.d new file mode 100644 index 00000000000..932411fc656 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9278a.d @@ -0,0 +1,16 @@ +// PREMUTE_ARGS: + +// Works fine here +struct datum { float num = 0.0; } + +datum emitOne() +{ + datum t; + return t; +} +const dataArr = [emitOne()]; + +// A very bad day +//struct datum { float num = 0.0; } + +void main(){} diff --git a/gcc/testsuite/gdc.test/compilable/test9278b.d b/gcc/testsuite/gdc.test/compilable/test9278b.d new file mode 100644 index 00000000000..0b4fee2f491 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9278b.d @@ -0,0 +1,16 @@ +// PREMUTE_ARGS: + +// Works fine here +//struct datum { float num = 0.0; } + +datum emitOne() +{ + datum t; + return t; +} +const dataArr = [emitOne()]; + +// A very bad day +struct datum { float num = 0.0; } + +void main(){} diff --git a/gcc/testsuite/gdc.test/compilable/test9399.d b/gcc/testsuite/gdc.test/compilable/test9399.d new file mode 100644 index 00000000000..47879e78fe2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9399.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -c -inline -Icompilable/imports +// EXTRA_SOURCES: imports/test9399a.d + +import imports.test9399a; +void fun(int a) { + void nested() { + a = 42; + } + call!nested(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9434.d b/gcc/testsuite/gdc.test/compilable/test9434.d new file mode 100644 index 00000000000..26c711731bf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9434.d @@ -0,0 +1,19 @@ +import test9435;//semantic; + +template Visitors() +{ + mixin Semantic!(typeof(this)); +} + +class Node +{ + mixin Visitors; +} + +class Expression : Node +{ +} + +class BinaryExp(TokenType op) : Expression +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/test9435.d b/gcc/testsuite/gdc.test/compilable/test9435.d new file mode 100644 index 00000000000..7046fdd8a15 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9435.d @@ -0,0 +1,17 @@ +import test9434;//expression; + +enum TokenType { Dot } + +template Tok(string type) +{ + enum Tok = TokenType.Dot; +} + +template Semantic(T) +{ + invariant(){} +} + +template Semantic(T) if (is(T == BinaryExp!(Tok!"."))) +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/test9436.d b/gcc/testsuite/gdc.test/compilable/test9436.d new file mode 100644 index 00000000000..c80bdc59e82 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9436.d @@ -0,0 +1,5 @@ +// REQUIRED_ARGS: -c +// EXTRA_SOURCES: imports/test9436interp.d + +// this is a dummy module for test 9436. + diff --git a/gcc/testsuite/gdc.test/compilable/test9526.d b/gcc/testsuite/gdc.test/compilable/test9526.d new file mode 100644 index 00000000000..2a18539f95a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9526.d @@ -0,0 +1,21 @@ +template forward(args...) +{ + @property fwd()() { return args[0]; } + static assert(__traits(compiles, { auto ex = fwd; })); + alias fwd forward; +} + +void initializeClassInstance(C, Args...)(C chunk, auto ref Args args) +{ + chunk.__ctor(forward!args); +} + +void main() +{ + static int si = 0; + static class C { this(int) { ++si; } } + void[__traits(classInstanceSize, C)] buff = void; + auto c = cast(C) buff.ptr; + initializeClassInstance(c, 0); + assert(si); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9554.d b/gcc/testsuite/gdc.test/compilable/test9554.d new file mode 100644 index 00000000000..c2270f94771 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9554.d @@ -0,0 +1,22 @@ +// REQUIRED_ARGS: -o- + +module pkg.test9554; +alias mod = pkg.test9554; + +template Test(alias name) { enum Test = name; } +void fun() {} + +static assert(fun.stringof == Test!(fun.stringof)); +static assert(fun.stringof == "fun()"); +static assert(fun.mangleof == Test!(fun.mangleof)); +static assert(fun.mangleof == "_D3pkg8test95543funFZv"); + +static assert(mod.stringof == Test!(mod.stringof)); +static assert(mod.stringof == "module test9554"); +static assert(mod.mangleof == Test!(mod.mangleof)); +static assert(mod.mangleof == "3pkg8test9554"); + +static assert(pkg.stringof == Test!(pkg.stringof)); +static assert(pkg.stringof == "package pkg"); +static assert(pkg.mangleof == Test!(pkg.mangleof)); +static assert(pkg.mangleof == "3pkg"); diff --git a/gcc/testsuite/gdc.test/compilable/test9565.d b/gcc/testsuite/gdc.test/compilable/test9565.d new file mode 100644 index 00000000000..9e3ee6a8170 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9565.d @@ -0,0 +1,86 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +template TypeTuple(T...) { alias TypeTuple = T; } + +bool startsWith(string s, string m) { return s[0 .. m.length] == m; } + +void main() +{ + enum string castPrefix = "cast(" ~ size_t.stringof ~ ")"; + + // TypeSArray + static assert((int[10]).stringof == "int[10]", T.stringof); + + int[] arr; + + // IndexExp + { + // index == IntegerExp + static assert((arr[ 4 ]).stringof == "arr[4]"); + static assert((arr[ 4U ]).stringof == "arr[4]"); + static assert((arr[ 4L ]).stringof == "arr[4]"); + static assert((arr[ 4LU]).stringof == "arr[4]"); + + // index == UAddExp + static assert((arr[+4 ]).stringof == "arr[4]"); + static assert((arr[+4U ]).stringof == "arr[4]"); + static assert((arr[+4L ]).stringof == "arr[4]"); + static assert((arr[+4LU]).stringof == "arr[4]"); + + // index == NegExp + static assert((arr[-4 ]).stringof == "arr[" ~ castPrefix ~ "-4]"); + static assert((arr[-4U ]).stringof == "arr[4294967292]"); + static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]"); + static if (is(size_t == ulong)) + { + static assert((arr[-4L ]).stringof == "arr[" ~ castPrefix ~ "-4L]"); + static assert((arr[-4LU]).stringof == "arr[-4LU]"); + + // IntegerLiteral needs suffix if the value is greater than long.max + static assert((arr[long.max + 0]).stringof == "arr[9223372036854775807]"); + static assert((arr[long.max + 1]).stringof == "arr[" ~ castPrefix ~ "(9223372036854775807L + 1L)]"); + } + + foreach (Int; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong)) + { + enum Int p4 = +4; + enum string result1 = (arr[p4]).stringof; + static assert(result1 == "arr[4]"); + + enum string result2 = (arr[cast(Int)+4]).stringof; + static assert(result2 == "arr[4]"); + } + foreach (Int; TypeTuple!(byte, short, int, long)) + { + // keep "cast(Type)" in the string representation + + enum Int m4 = -4; + static if (is(typeof({ size_t x = m4; }))) + { + enum string result1 = (arr[m4]).stringof; + static assert(result1.startsWith("arr[" ~ castPrefix)); + } + else + static assert(!__traits(compiles, arr[m4])); + + enum string result2 = (arr[cast(Int)-4]).stringof; + static assert(result2.startsWith("arr[" ~ castPrefix)); + } + } + + // SliceExp + { + // lwr,upr == IntegerExp + static assert((arr[4 .. 8 ]).stringof == "arr[4..8]"); + static assert((arr[4U .. 8U ]).stringof == "arr[4..8]"); + static assert((arr[4L .. 8L ]).stringof == "arr[4..8]"); + static assert((arr[4LU .. 8LU]).stringof == "arr[4..8]"); + + // lwr,upr == UAddExp + static assert((arr[+4 .. +8 ]).stringof == "arr[4..8]"); + static assert((arr[+4U .. +8U ]).stringof == "arr[4..8]"); + static assert((arr[+4L .. +8L ]).stringof == "arr[4..8]"); + static assert((arr[+4LU .. +8LU]).stringof == "arr[4..8]"); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test9570.d b/gcc/testsuite/gdc.test/compilable/test9570.d new file mode 100644 index 00000000000..c9df59cf320 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9570.d @@ -0,0 +1,59 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +void main() +{ + ubyte[256] data; + + foreach (immutable i; 0..256) data[i] = i; + foreach ( const i; 0..256) data[i] = i; + foreach ( i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + foreach (immutable int i; 0..256) data[i] = i; + foreach ( const int i; 0..256) data[i] = i; + foreach ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + foreach (immutable(int) i; 0..256) data[i] = i; + foreach ( const(int) i; 0..256) data[i] = i; + foreach ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + foreach (immutable(ulong) i; 0..256) data[i] = i; + foreach ( const(ulong) i; 0..256) data[i] = i; + foreach ( ulong i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + + foreach (immutable i, x; data) data[i] = i; + foreach ( const i, x; data) data[i] = i; + foreach ( i, x; data) static assert(!__traits(compiles, (data[i] = i))); + foreach (immutable int i, x; data) data[i] = i; + foreach ( const int i, x; data) data[i] = i; + foreach ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); + foreach (immutable(int) i, x; data) data[i] = i; + foreach ( const(int) i, x; data) data[i] = i; + foreach ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); + foreach (immutable(ulong) i, x; data) data[i] = i; + foreach ( const(ulong) i, x; data) data[i] = i; + foreach ( ulong i, x; data) static assert(!__traits(compiles, (data[i] = i))); + + foreach_reverse (immutable i; 0..256) data[i] = i; + foreach_reverse ( const i; 0..256) data[i] = i; + foreach_reverse ( i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + foreach_reverse (immutable int i; 0..256) data[i] = i; + foreach_reverse ( const int i; 0..256) data[i] = i; + foreach_reverse ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + foreach_reverse (immutable(int) i; 0..256) data[i] = i; + foreach_reverse ( const(int) i; 0..256) data[i] = i; + foreach_reverse ( int i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + foreach_reverse (immutable(ulong) i; 0..256) data[i] = i; + foreach_reverse ( const(ulong) i; 0..256) data[i] = i; + foreach_reverse ( ulong i; 0..256) static assert(!__traits(compiles, (data[i] = i))); + + foreach_reverse (immutable i, x; data) data[i] = i; + foreach_reverse ( const i, x; data) data[i] = i; + foreach_reverse ( i, x; data) static assert(!__traits(compiles, (data[i] = i))); + //foreach_reverse (immutable int i, x; data) data[i] = i; + //foreach_reverse ( const int i, x; data) data[i] = i; + //foreach_reverse ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); + //foreach_reverse (immutable(int) i, x; data) data[i] = i; + //foreach_reverse ( const(int) i, x; data) data[i] = i; + //foreach_reverse ( int i, x; data) static assert(!__traits(compiles, (data[i] = i))); + foreach_reverse (immutable(ulong) i, x; data) data[i] = i; + foreach_reverse ( const(ulong) i, x; data) data[i] = i; + foreach_reverse ( ulong i, x; data) static assert(!__traits(compiles, (data[i] = i))); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9613.d b/gcc/testsuite/gdc.test/compilable/test9613.d new file mode 100644 index 00000000000..c49c293282f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9613.d @@ -0,0 +1,32 @@ +// PREMUTE_ARGS: +struct S9613 +{ + int f( + const(byte) a = const(byte).init, + immutable(byte) b = immutable(byte).init, + shared(byte) c = shared(byte).init, + inout(byte) d = inout(byte).init, + ) inout + { + assert(a == byte.init); + assert(b == byte.init); + assert(c == byte.init); + assert(d == byte.init); + static assert(const(byte).init == byte.init); + static assert(immutable(byte).init == byte.init); + static assert(shared(byte).init == byte.init); + static assert(inout(byte).init == byte.init); + return 0; + } +} + +void main() +{ + static assert(const(byte).init == byte.init); + static assert(immutable(byte).init == byte.init); + static assert(shared(byte).init == byte.init); + static assert(const(byte).init.sizeof == byte.sizeof); + static assert(const(byte[2]).init[0] == byte.init); + enum s = S9613(); + enum v = s.f(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9639.d b/gcc/testsuite/gdc.test/compilable/test9639.d new file mode 100644 index 00000000000..e79db9ecb81 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9639.d @@ -0,0 +1,19 @@ +class A { this(A) {} } +class B {} +class C {} + +// two sibling nested functions in main +typeof(null) foo(alias fn)(A a) { fn(a); return foo!fn(B.init); } +typeof(null) foo(alias fn)(B b) { return foo!fn(A.init); } + +// three sibling nested functions in main +typeof(null) bar(alias fn)(A a) { fn(a); return bar!fn(B.init); } +typeof(null) bar(alias fn)(B b) { return bar!fn(C.init); } +typeof(null) bar(alias fn)(C c) { return bar!fn(A.init); } + +void main() +{ + A a; + foo!((stuff){ new A(a); })(a); + bar!((stuff){ new A(a); })(a); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9672.d b/gcc/testsuite/gdc.test/compilable/test9672.d new file mode 100644 index 00000000000..bb10e3a33f4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9672.d @@ -0,0 +1,7 @@ +module test9672; // node + +import imports.test9672a; // interpret + +mixin template ForwardCtor() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/test9692.d b/gcc/testsuite/gdc.test/compilable/test9692.d new file mode 100644 index 00000000000..765b657c1de --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9692.d @@ -0,0 +1,7 @@ +module test9692; + +import test9692a; +import imports.test9692b; + +enum x = [__traits(allMembers, imports.test9692b)]; // ok +enum y = [__traits(allMembers, test9692a)]; // ng: should work diff --git a/gcc/testsuite/gdc.test/compilable/test9692a.d b/gcc/testsuite/gdc.test/compilable/test9692a.d new file mode 100644 index 00000000000..6fd304b2d1a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9692a.d @@ -0,0 +1,2 @@ +module test9692a; +int j; diff --git a/gcc/testsuite/gdc.test/compilable/test9766.d b/gcc/testsuite/gdc.test/compilable/test9766.d new file mode 100644 index 00000000000..3cfc22f0464 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9766.d @@ -0,0 +1,77 @@ +// PERMUTE_ARGS: + +size_t getAlign9766(size_t n) { return n; } + +struct S9766 +{ +align(getAlign9766(1)): + ubyte[5] pad1; + ubyte var1; + +align(getAlign9766(2)): + ubyte[5] pad2; + ubyte var2; + +align(getAlign9766(4)): + ubyte[5] pad3; + ubyte var3; + +align(getAlign9766(8)): + ubyte[5] pad4; + ubyte var4; +} + +static assert(S9766.pad1.offsetof == 0); +static assert(S9766.var1.offsetof == 5); + +static assert(S9766.pad2.offsetof == 6); +static assert(S9766.var2.offsetof == 12); + +static assert(S9766.pad3.offsetof == 16); +static assert(S9766.var3.offsetof == 24); + +static assert(S9766.pad4.offsetof == 32); +static assert(S9766.var4.offsetof == 40); + +union U9766 +{ + struct + { + align(getAlign9766(1)): + ubyte[5] pad1; + ubyte var1; + + align(getAlign9766(2)): + ubyte[5] pad2; + ubyte var2; + + align(getAlign9766(4)): + ubyte[5] pad3; + ubyte var3; + + align(getAlign9766(8)): + ubyte[5] pad4; + ubyte var4; + } +} + +static assert(U9766.pad1.offsetof == 0); +static assert(U9766.var1.offsetof == 5); + +static assert(U9766.pad2.offsetof == 6); +static assert(U9766.var2.offsetof == 12); + +static assert(U9766.pad3.offsetof == 16); +static assert(U9766.var3.offsetof == 24); + +static assert(U9766.pad4.offsetof == 32); +static assert(U9766.var4.offsetof == 40); + +struct TestMaxAlign +{ +align(1u << 31): + ubyte a; + ubyte b; +} + +static assert(TestMaxAlign.b.offsetof == 2147483648u); diff --git a/gcc/testsuite/gdc.test/compilable/test9818.d b/gcc/testsuite/gdc.test/compilable/test9818.d new file mode 100644 index 00000000000..779b1cf0fe6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9818.d @@ -0,0 +1,76 @@ +/************************************/ +// 9818 + +/* +TEST_OUTPUT: +--- +sa1: [1, 1, 1] +ea1: [1, 1, 1] +sa2: [1, 1, 1] +ea2: [1, 1, 1] +eas: [1, 1, 1] +eac: [1, 1, 1] +sa3: [1, 1, 1] +ea3: [1, 1, 1] +sa4: [1, 1, 1] +ea4: [1, 1, 1] +--- +*/ + +static const int[3] sa1 = 1; +pragma(msg, "sa1: ", sa1); // doesn't work +static assert(sa1 == [1, 1, 1]); // doesn't work + +enum int[3] ea1 = 1; +pragma(msg, "ea1: ", ea1); // prints "1" - bad +static assert(ea1 == [1, 1, 1]); // doesn't work + +struct X +{ + static const int[3] sa2 = 1; + pragma(msg, "sa2: ", sa1); // doesn't work + static assert(sa2 == [1, 1, 1]); // doesn't work + + enum int[3] ea2 = 1; + pragma(msg, "ea2: ", ea2); // prints "1" - bad + static assert(ea2 == [1, 1, 1]); // doesn't work +} + +struct S +{ + enum int[3] eas = 1; +} +pragma(msg, "eas: ", S.eas); +static assert(S.eas == [1, 1, 1]); +class C +{ + enum int[3] eac = 1; +} +pragma(msg, "eac: ", C.eac); +static assert(C.eac == [1, 1, 1]); + +void test() +{ + static const int[3] sa3 = 1; + pragma(msg, "sa3: ", sa3); // doesn't work + static assert(sa3 == [1, 1, 1]); // doesn't work + + enum int[3] ea3 = 1; + pragma(msg, "ea3: ", ea3); // prints "1" - bad + static assert(ea3 == [1, 1, 1]); // doesn't work + + struct Y + { + static const int[3] sa4 = 1; + pragma(msg, "sa4: ", sa4); // doesn't work + static assert(sa4 == [1, 1, 1]); // doesn't work + + enum int[3] ea4 = 1; + pragma(msg, "ea4: ", ea4); // prints "1" - bad + static assert(ea4 == [1, 1, 1]); // doesn't work + } +} + +/************************************/ + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/test9919.d b/gcc/testsuite/gdc.test/compilable/test9919.d new file mode 100644 index 00000000000..5cf8bc99cce --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9919.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -o- + +module test9919; + +public +{ + import imports.test9919a; + import imports.test9919b; +} diff --git a/gcc/testsuite/gdc.test/compilable/testDIP37.d b/gcc/testsuite/gdc.test/compilable/testDIP37.d new file mode 100644 index 00000000000..a612365eaf4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testDIP37.d @@ -0,0 +1,42 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -Icompilable/extra-files +// EXTRA_FILES: extra-files/pkgDIP37/datetime/package.d extra-files/pkgDIP37/datetime/common.d extra-files/pkgDIP37/test17629/package.di extra-files/pkgDIP37/test17629/common.di + +void test1() +{ + import pkgDIP37.datetime; + def(); + pkgDIP37.datetime.def(); + pkgDIP37.datetime.common.def(); +} + +void test3() +{ + import pkgDIP37.datetime.common; + def(); + pkgDIP37.datetime.def(); + pkgDIP37.datetime.common.def(); +} + +void test4() +{ + import pkgDIP37.datetime : def; + def(); + static assert(!__traits(compiles, pkgDIP37.datetime.def())); + static assert(!__traits(compiles, pkgDIP37.datetime.common.def())); +} + +void test7() +{ + static import pkgDIP37.datetime; + static assert(!__traits(compiles, def())); + pkgDIP37.datetime.def(); + pkgDIP37.datetime.common.def(); +} + +// https://issues.dlang.org/show_bug.cgi?id=17629 +void test17629() +{ + import pkgDIP37.test17629; + foo17629(); +} diff --git a/gcc/testsuite/gdc.test/compilable/testDIP37_10302.d b/gcc/testsuite/gdc.test/compilable/testDIP37_10302.d new file mode 100644 index 00000000000..7e76595f06f --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testDIP37_10302.d @@ -0,0 +1,8 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -c -Icompilable/extra-files +// EXTRA_SOURCES: extra-files/pkgDIP37_10302/liba.d extra-files/pkgDIP37_10302/libb.d +// EXTRA_FILES: extra-files/pkgDIP37_10302/package.d + +module test; +import pkgDIP37_10302; +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testDIP37_10354.d b/gcc/testsuite/gdc.test/compilable/testDIP37_10354.d new file mode 100644 index 00000000000..2993fa94d39 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testDIP37_10354.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -o- -Icompilable/extra-files +// EXTRA_FILES: extra-files/pkgDIP37_10354/mbar.d extra-files/pkgDIP37_10354/mfoo.d extra-files/pkgDIP37_10354/package.d + +module testDIP37_10354; +import pkgDIP37_10354.mfoo; +void main() +{ + import pkgDIP37_10354; + foo!string(); // OK + bar!string(); // OK <- ICE +} diff --git a/gcc/testsuite/gdc.test/compilable/testDIP37_10421.d b/gcc/testsuite/gdc.test/compilable/testDIP37_10421.d new file mode 100644 index 00000000000..859347331b1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testDIP37_10421.d @@ -0,0 +1,7 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -Icompilable/extra-files +// COMPILED_IMPORTS: extra-files/pkgDIP37_10421/algo/package.d extra-files/pkgDIP37_10421/algo/mod.d extra-files/pkgDIP37_10421/except.d + +module testDIP37_10421; +import pkgDIP37_10421.algo; +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testDIP37a.d b/gcc/testsuite/gdc.test/compilable/testDIP37a.d new file mode 100644 index 00000000000..8bd8b2d3397 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testDIP37a.d @@ -0,0 +1,8 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -c -Icompilable/extra-files +// EXTRA_SOURCES: extra-files/pkgDIP37/datetime/package.d +// EXTRA_SOURCES: extra-files/pkgDIP37/datetime/common.d + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/testDIP42.d b/gcc/testsuite/gdc.test/compilable/testDIP42.d new file mode 100644 index 00000000000..7bb154619eb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testDIP42.d @@ -0,0 +1,97 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +// enum ident(tpl) = Initializer; + +enum isIntegral(T) = is(T == int) || is(T == long); +static assert( isIntegral!int); +static assert( isIntegral!long); +static assert(!isIntegral!double); +static assert(!isIntegral!(int[])); + +version(none) +{ +enum + allSatisfy(alias pred, TL...) = + TL.length == 0 || (pred!(TL[0]) && allSatisfy!(pred, TL[1..$])), + anySatisfy(alias pred, TL...) = + TL.length != 0 && (pred!(TL[0]) || anySatisfy!(pred, TL[1..$])) || false; +static assert( allSatisfy!(isIntegral, int, long)); +static assert(!allSatisfy!(isIntegral, int, double)); +static assert( anySatisfy!(isIntegral, int, double)); +static assert(!anySatisfy!(isIntegral, int[], double)); +} + +void test1() +{ + // statement + enum isIntegral2(T) = is(T == int) || is(T == long); + static assert(isIntegral2!int); +} + +/******************************************/ +// alias ident(tpl) = Type; + +alias TypeTuple(TL...) = TL; +static assert(is(TypeTuple!(int, long)[0] == int)); +static assert(is(TypeTuple!(int, long)[1] == long)); + +alias Id(T) = T, Id(alias A) = A; +static assert(is(Id!int == int)); +static assert(__traits(isSame, Id!TypeTuple, TypeTuple)); + +void test2() +{ + // statement + alias TypeTuple2(TL...) = TL; + static assert(is(TypeTuple2!(int, long)[0] == int)); + static assert(is(TypeTuple2!(int, long)[1] == long)); + + alias IdT(T) = T, IdA(alias A) = A; + static assert(is(IdT!int == int)); + static assert(__traits(isSame, IdA!TypeTuple, TypeTuple)); +} + +/******************************************/ +// template auto declaration + +auto tynameLen(T) = T.stringof.length; + +void test3() +{ + assert(tynameLen!int == 3); + assert(tynameLen!long == 4); + tynameLen!int = 4; + tynameLen!long = 5; + assert(tynameLen!int == 4); + assert(tynameLen!long == 5); + + // statement + auto tynameLen2(T) = T.stringof.length; + + assert(tynameLen2!int == 3); + assert(tynameLen2!long == 4); + tynameLen2!int = 4; + tynameLen2!long = 5; + assert(tynameLen2!int == 4); + assert(tynameLen2!long == 5); +} + +/******************************************/ +// template variable declaration + +static T math_pi(T) = cast(T)3.1415; + +enum bool isFloatingPoint(T) = is(T == float) || is(T == double); +static assert( isFloatingPoint!double); +static assert(!isFloatingPoint!string); + +void main() +{ + assert(math_pi!int == 3); + assert(math_pi!double == 3.1415); + + enum bool isFloatingPoint2(T) = is(T == float) || is(T == double); + static assert( isFloatingPoint2!double); + static assert(!isFloatingPoint2!string); +} diff --git a/gcc/testsuite/gdc.test/compilable/testInference.d b/gcc/testsuite/gdc.test/compilable/testInference.d new file mode 100644 index 00000000000..95f4fcba259 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testInference.d @@ -0,0 +1,817 @@ + +/***************************************************/ +// 6265. + +pure nothrow @safe int h6265() { + return 1; +} +int f6265a(alias g)() { + return g(); +} +pure nothrow @safe int i6265a() { + return f6265a!h6265(); +} + +int f6265b()() { + return h6265(); +} +pure nothrow @safe int i6265b() { + return f6265b(); +} + +pure nothrow @safe int i6265c() { + return { + return h6265(); + }(); +} + +/***************************************************/ +// Make sure a function is not infered as pure if it isn't. + +int fNPa() { + return 1; +} +int gNPa()() { + return fNPa(); +} +static assert( __traits(compiles, function int () { return gNPa(); })); +static assert(!__traits(compiles, function int () pure { return gNPa(); })); +static assert(!__traits(compiles, function int () nothrow { return gNPa(); })); +static assert(!__traits(compiles, function int () @safe { return gNPa(); })); + +/***************************************************/ +// Need to ensure the comment in Expression::checkPurity is not violated. + +void fECPa() { + void g()() { + void h() { + } + h(); + } + static assert( is(typeof(&g!()) == void delegate() pure nothrow @nogc @safe)); + static assert(!is(typeof(&g!()) == void delegate())); +} + +void fECPb() { + void g()() { + void h() { + } + fECPb(); + } + static assert(!is(typeof(&g!()) == void delegate() pure)); + static assert( is(typeof(&g!()) == void delegate())); +} + +/***************************************************/ +// 5635 + +pure bool foo5635(R = int)(string x) +{ + bool result = false; + foreach (dchar d; x) + result = true; + return result; +} + +void test5635() +{ + foo5635("hi"); +} + +/***************************************************/ +// 5936 + +auto bug5936c(R)(R i) @safe pure nothrow { + return true; +} +static assert( bug5936c(0) ); + +/***************************************************/ +// 6351 + +void bug6351(alias dg)() +{ + dg(); +} + +void test6351() +{ + void delegate(int[] a...) deleg6351 = (int[] a...){}; + alias bug6351!(deleg6351) baz6531; +} + +/***************************************************/ +// 6359 + +void impure6359() nothrow @safe @nogc {} +void throwable6359() pure @safe @nogc {} +void system6359() pure nothrow @nogc {} +void gcable6359() pure nothrow @safe {} + +int global6359; + +void f6359() pure nothrow @safe @nogc +{ + static assert(!__traits(compiles, impure6359())); + static assert(!__traits(compiles, throwable6359())); + static assert(!__traits(compiles, system6359())); + static assert(!__traits(compiles, gcable6359())); + static assert(!__traits(compiles, global6359++)); + + static assert(!__traits(compiles, { impure6359(); }())); + static assert(!__traits(compiles, { throwable6359(); }())); + static assert(!__traits(compiles, { system6359(); }())); + static assert(!__traits(compiles, { gcable6359(); }())); + static assert(!__traits(compiles, { global6359++; }())); +} + +void g6359()() pure nothrow @safe @nogc +{ + static assert(!__traits(compiles, impure6359())); + static assert(!__traits(compiles, throwable6359())); + static assert(!__traits(compiles, system6359())); + static assert(!__traits(compiles, gcable6359())); + static assert(!__traits(compiles, global6359++)); + + static assert(!__traits(compiles, { impure6359(); }())); + static assert(!__traits(compiles, { throwable6359(); }())); + static assert(!__traits(compiles, { system6359(); }())); + static assert(!__traits(compiles, { gcable6359(); }())); + static assert(!__traits(compiles, { global6359++; }())); +} + +// attribute inference is not affected by the expressions inside __traits(compiles) +void h6359()() +{ + static assert( __traits(compiles, impure6359())); + static assert( __traits(compiles, throwable6359())); + static assert( __traits(compiles, system6359())); + static assert( __traits(compiles, gcable6359())); + static assert( __traits(compiles, global6359++)); + + static assert( __traits(compiles, { impure6359(); }())); + static assert( __traits(compiles, { throwable6359(); }())); + static assert( __traits(compiles, { system6359(); }())); + static assert( __traits(compiles, { gcable6359(); }())); + static assert( __traits(compiles, { global6359++; }())); +} + +void test6359() pure nothrow @safe @nogc +{ + f6359(); + g6359(); + h6359(); +} + +/***************************************************/ +// 7017 + +template map7017(fun...) if (fun.length >= 1) +{ + auto map7017() + { + struct Result { + this(int dummy){} // impure member function -> inferred to pure by fixing issue 10329 + } + return Result(0); // impure call -> inferred to pure by fixing issue 10329 + } +} + +int foo7017(immutable int x) pure nothrow { return 1; } + +void test7017a() pure +{ + int bar7017(immutable int x) pure nothrow { return 1; } + + static assert(__traits(compiles, map7017!((){})())); + static assert(__traits(compiles, map7017!q{ 1 }())); + static assert(__traits(compiles, map7017!foo7017())); + static assert(__traits(compiles, map7017!bar7017())); +} + +/***************************************************/ +// 7017 (little simpler cases) + +auto map7017a(alias fun)() { return fun(); } // depends on purity of fun +auto map7017b(alias fun)() { return; } // always pure +auto map7017c(alias fun)() { return yyy7017(); } // always impure + +int xxx7017() pure { return 1; } +int yyy7017() { return 1; } + +void test7017b() pure +{ + static assert( __traits(compiles, map7017a!xxx7017() )); + static assert(!__traits(compiles, map7017a!yyy7017() )); + + static assert( __traits(compiles, map7017b!xxx7017() )); + static assert( __traits(compiles, map7017b!yyy7017() )); + + static assert(!__traits(compiles, map7017c!xxx7017() )); + static assert(!__traits(compiles, map7017c!yyy7017() )); +} + +/***************************************************/ +// Test case from std.process + +auto escapeArgumentImpl(alias allocator)() +{ + return allocator(); +} + +auto escapeShellArgument(alias allocator)() +{ + return escapeArgumentImpl!allocator(); +} + +pure string escapeShellArguments() +{ + char[] allocator() + { + return new char[1]; + } + + /* Both escape!allocator and escapeImpl!allocator are impure, + * but they are nested template function that instantiated here. + * Then calling them from here doesn't break purity. + */ + return escapeShellArgument!allocator(); +} + +/***************************************************/ +// 8234 + +void test8234() +{ + immutable int x = 0; + + alias FP = typeof({ enum e = x; return e; }); + static assert(is(FP : int function())); + + auto fp = { enum e = x; return e; }; + static assert(is(typeof(fp) : int function())); + + alias DG = typeof({ auto e = x; return e; }); + static assert(is(DG : int delegate())); + + auto dg = { auto e = x; return e; }; + static assert(is(typeof(dg) : int delegate())); +} + +/***************************************************/ +// 8504 + +void foo8504()() +{ + static assert(typeof(foo8504!()).stringof == "void()"); + static assert(typeof(foo8504!()).mangleof == "FZv"); + static assert(foo8504!().mangleof == "_D13testInference12__T7foo8504Z7foo8504FZv"); +} + +auto toDelegate8504a(F)(auto ref F fp) { return fp; } + F toDelegate8504b(F)(auto ref F fp) { return fp; } + +extern(C) void testC8504() {} + +void test8504() +{ + static assert(typeof(foo8504!()).stringof == "pure nothrow @nogc @safe void()"); + static assert(typeof(foo8504!()).mangleof == "FNaNbNiNfZv"); + static assert(foo8504!().mangleof == "_D13testInference12__T7foo8504Z7foo8504FNaNbNiNfZv"); + + auto fp1 = toDelegate8504a(&testC8504); + auto fp2 = toDelegate8504b(&testC8504); + static assert(is(typeof(fp1) == typeof(fp2))); + static assert(typeof(fp1).stringof == "extern (C) void function()"); + static assert(typeof(fp2).stringof == "extern (C) void function()"); + static assert(typeof(fp1).mangleof == "PUZv"); + static assert(typeof(fp2).mangleof == "PUZv"); +} + +/***************************************************/ +// 8751 + +alias bool delegate(in int) pure Bar8751; +Bar8751 foo8751a(immutable int x) pure +{ + return y => x > y; // OK +} +Bar8751 foo8751b(const int x) pure +{ + return y => x > y; // error -> OK +} + +/***************************************************/ +// 8793 + +alias bool delegate(in int) pure Dg8793; +alias bool function(in int) pure Fp8793; + +Dg8793 foo8793fp1(immutable Fp8793 f) pure { return x => (*f)(x); } // OK +Dg8793 foo8793fp2( const Fp8793 f) pure { return x => (*f)(x); } // OK + +Dg8793 foo8793dg1(immutable Dg8793 f) pure { return x => f(x); } // OK +Dg8793 foo8793dg2( const Dg8793 f) pure { return x => f(x); } // OK <- error + +Dg8793 foo8793pfp1(immutable Fp8793* f) pure { return x => (*f)(x); } // OK +Dg8793 foo8793pdg1(immutable Dg8793* f) pure { return x => (*f)(x); } // OK + +Dg8793 foo8793pfp2(const Fp8793* f) pure { return x => (*f)(x); } // OK <- error +Dg8793 foo8793pdg2(const Dg8793* f) pure { return x => (*f)(x); } // OK <- error + +// general case for the hasPointer type +Dg8793 foo8793ptr1(immutable int* p) pure { return x => *p == x; } // OK + +Dg8793 foo8793ptr2(const int* p) pure { return x => *p == x; } // OK <- error + +/***************************************************/ +// 9072 + +struct A9072(T) +{ + this(U)(U x) {} + ~this() {} +} +void test9072() +{ + A9072!int a = A9072!short(); +} + +/***************************************************/ +// 5933 + Issue 8504 - Template attribute inferrence doesn't work + +int foo5933()(int a) { return a*a; } +struct S5933 +{ + double foo()(double a) { return a * a; } +} +// outside function +static assert(typeof(foo5933!()).stringof == "pure nothrow @nogc @safe int(int a)"); +static assert(typeof(S5933.init.foo!()).stringof == "pure nothrow @nogc @safe double(double a)"); + +void test5933() +{ + // inside function + static assert(typeof(foo5933!()).stringof == "pure nothrow @nogc @safe int(int a)"); + static assert(typeof(S5933.init.foo!()).stringof == "pure nothrow @nogc @safe double(double a)"); +} + +/***************************************************/ +// 9148 + +void test9148a() pure +{ + static int g; + int x; + + void foo1() /+pure+/ + { + static assert(!__traits(compiles, g++)); + x++; + } + void foo2() pure + { + static assert(!__traits(compiles, g++)); + x++; + } + foo1(); + static assert(is(typeof(&foo1) == void delegate() pure nothrow @nogc @safe)); + foo2(); + static assert(is(typeof(&foo2) == void delegate() pure nothrow @nogc @safe)); + + void bar1() immutable /+pure+/ + { + static assert(!__traits(compiles, g++)); + static assert(!__traits(compiles, x++)); + } + void bar2() immutable pure + { + static assert(!__traits(compiles, g++)); + static assert(!__traits(compiles, x++)); + } + bar1(); + static assert(is(typeof(&bar1) == void delegate() pure immutable nothrow @nogc @safe)); + bar2(); + static assert(is(typeof(&bar2) == void delegate() pure immutable nothrow @nogc @safe)); + + struct S + { + void foo1() /+pure+/ + { + static assert(!__traits(compiles, g++)); + x++; + } + void foo2() pure + { + static assert(!__traits(compiles, g++)); + x++; + } + void bar1() immutable /+pure+/ + { + static assert(!__traits(compiles, g++)); + static assert(!__traits(compiles, x++)); + } + void bar2() immutable pure + { + static assert(!__traits(compiles, g++)); + static assert(!__traits(compiles, x++)); + } + } + + S sm; + sm.foo1(); + static assert(is(typeof(&sm.foo1) == void delegate() pure)); + sm.foo2(); + static assert(is(typeof(&sm.foo2) == void delegate() pure)); + + immutable S si; + si.bar1(); + static assert(is(typeof(&si.bar1) == void delegate() pure immutable)); + si.bar2(); + static assert(is(typeof(&si.bar2) == void delegate() pure immutable)); +} + +// ---- +// inheritance of pure and @safe + +void test9148b() pure nothrow @nogc @safe +{ + void nf() {} + static assert(is(typeof(&nf) == void delegate() pure nothrow @nogc @safe)); + + struct NS + { + void mf() {} + static void sf() {} + } + NS ns; + static assert(is(typeof(&ns.mf) == void delegate() pure nothrow @nogc @safe)); + static assert(is(typeof(&NS.sf) == void function() pure nothrow @nogc @safe)); + + static void sf() {} + static assert(is(typeof(&sf) == void function() pure nothrow @nogc @safe)); + + static struct SS + { + void mf() {} + static void sf() {} + } + SS ss; + static assert(is(typeof(&ss.mf) == void delegate() pure nothrow @nogc @safe)); + static assert(is(typeof(&SS.sf) == void function() pure nothrow @nogc @safe)); +} + +void impureSystem9148b() {} +void func9148b()() +{ + void bar() // do not inherit PUREfwdref + { + static assert(is(typeof(&bar) == void delegate())); + impureSystem9148b(); + } + static assert(is(typeof(&bar) == void delegate())); +} +static assert(is(typeof(&func9148b!()) == void function() pure nothrow @nogc @safe)); + +// ---- +// from fail_compilation/fail283.d + +pure int double_sqr9148c(int x) +{ + int y = x; + void do_sqr() pure { y *= y; } + do_sqr(); + return y; +} + +void test9148c() +{ + assert(double_sqr9148c(10) == 100); +} + +// ---- +// from fail_compilation/fail348.d + +void test9148d() pure +{ + void g() // implicitly marked as 'pure' + { + void h() pure + { + // i() and j() are implicitly marked as 'pure' + void i() { } + void j() { i(); g(); } // can call i() and g() + } + } +} + +void test9148e() +{ + int x; + static assert(is(typeof((int a){ return a + x; }) == int delegate(int) pure nothrow @nogc @safe)); + + auto dg = (int a){ return a + x; }; + static assert(is(typeof(dg) == int delegate(int) pure nothrow @nogc @safe)); +} + +/***************************************************/ +// 12912 + +struct S12912(alias fun) +{ + void f() { fun(); } +} + +class C12912 +{ + int n; + + void f() pure + { + S12912!(() => n) s; + // Here lambda should be inferred to weak purity. + + s.f(); + // And this call will be a pure member function call. + } +} + +/***************************************************/ +// 10002 + +void impure10002() {} +void remove10002(alias pred, bool impure = false, Range)(Range range) +{ + pred(range[0]); + static if (impure) impure10002(); +} +class Node10002 +{ + Node10002 parent; + Node10002[] children; + + void foo() pure + { + parent.children.remove10002!(n => n is parent)(); + remove10002!(n => n is parent)(parent.children); + static assert(!__traits(compiles, parent.children.remove10002x!(n => n is parent, true)())); + static assert(!__traits(compiles, remove10002x!(n => n is parent, true)(parent.children))); + + Node10002 p; + p.children.remove10002!(n => n is p)(); + remove10002!(n => n is p)(p.children); + static assert(!__traits(compiles, p.children.remove10002x!(n => n is p, true)())); + static assert(!__traits(compiles, remove10002x!(n => n is p, true)(p.children))); + } +} + +/***************************************************/ +// 10148 + +void fa10148() {} // fa is @system + +auto fb10148(T)() +{ + struct A(S) + { + // [4] Parent function fb is already inferred to @safe, then + // fc is forcely marked @safe on default until 2.052. + // But fc should keep attribute inference ability + // by overriding the inherited @safe-ty from its parent. + void fc(T2)() + { + // [5] During semantic3 process, fc is not @safe on default. + static assert(is(typeof(&fc) == void delegate())); + fa10148(); + } + // [1] this is now inferred to @safe by implementing issue 7511 + this(S a) {} + } + + // [2] A!int(0) is now calling @safe function, then fb!T also be inferred to @safe + return A!int(0); +} + +void test10148() +{ + fb10148!int.fc!int; // [0] instantiate fb + // [3] instantiate fc + + // [6] After semantic3 done, fc!int is deduced to @system. + static assert(is(typeof(&fb10148!int.fc!int) == void delegate() @system)); +} + +/***************************************************/ +// 10289 + +void test10289() +{ + void foo(E)() + { + throw new E(""); + } + void bar(E1, E2)() + { + throw new E1(""); + throw new E2(""); + } + void baz(E1, E2)(bool cond) + { + if (cond) + throw new E1(""); + else + throw new E2(""); + } + + import core.exception; + static class MyException : Exception + { + this(string) @safe pure nothrow { super(""); } + } + + static assert( __traits(compiles, () nothrow { foo!Error(); })); + static assert( __traits(compiles, () nothrow { foo!AssertError(); })); + + static assert(!__traits(compiles, () nothrow { foo!Exception(); })); + static assert(!__traits(compiles, () nothrow { foo!MyException(); })); + + static assert( __traits(compiles, () nothrow { bar!(Error, Exception)(); })); + static assert(!__traits(compiles, () nothrow { bar!(Exception, Error)(); })); + + static assert(!__traits(compiles, () nothrow { baz!(Error, Exception)(); })); + static assert(!__traits(compiles, () nothrow { baz!(Exception, Error)(); })); +} + +/***************************************************/ +// 10296 + +void foo10296()() +{ + int[3] a; + + void bar()() { a[1] = 2; } + bar(); + pragma(msg, typeof(bar!())); // nothrow @safe void() +} +pure void test10296() +{ + foo10296(); +} + +/***************************************************/ +// 12025 + +struct Foo12025 +{ + int[5] bar; +} + +void test12025a() pure +{ + enum n1 = typeof(Foo12025.bar).length; // OK + enum n2 = Foo12025.bar .length; // OK <- error + + auto x1 = typeof(Foo12025.bar).length; // OK + auto x2 = Foo12025.bar .length; // OK <- error +} + +void test12025b() pure +{ + static int[5] bar; + + enum n1 = typeof(bar).length; // OK + enum n2 = bar .length; // OK <- error + + auto x1 = typeof(bar).length; // OK + auto x2 = bar .length; // OK <- error +} + +/***************************************************/ +// 12542 + +int logOf12542(T)(T n) +{ + if (n) + return 1 + logOf12542(n/2); + return 0; +} + +void test12542() @safe nothrow pure +{ + int log = logOf12542(9); +} + +/***************************************************/ +// 12704 + +void foo12704() @system; +alias FP12704 = typeof(function() { foo12704(); }); +static assert(is(FP12704 == void function() @system)); + +/***************************************************/ +// 12970 + +@system { @safe void f12970a() {} } +@system { void f12970b() @safe {} } +static assert(is(typeof(&f12970a) == void function() @safe)); +static assert(is(typeof(&f12970b) == void function() @safe)); + +@system { @trusted void f12970c() {} } +@system { void f12970d() @trusted {} } +static assert(is(typeof(&f12970c) == void function() @trusted)); +static assert(is(typeof(&f12970d) == void function() @trusted)); + +@safe { @system void f12970e() {} } +@safe { void f12970f() @system {} } +static assert(is(typeof(&f12970e) == void function() @system)); +static assert(is(typeof(&f12970f) == void function() @system)); + +@safe { @trusted void f12970g() {} } +@safe { void f12970h() @trusted {} } +static assert(is(typeof(&f12970g) == void function() @trusted)); +static assert(is(typeof(&f12970h) == void function() @trusted)); + +@trusted { @safe void f12970i() {} } +@trusted { void f12970j() @safe {} } +static assert(is(typeof(&f12970i) == void function() @safe)); +static assert(is(typeof(&f12970j) == void function() @safe)); + +@trusted { @system void f12970k() {} } +@trusted { void f12970l() @system {} } +static assert(is(typeof(&f12970k) == void function() @system)); +static assert(is(typeof(&f12970l) == void function() @system)); + +/***************************************************/ +// Parsing prefix STC_FUNCATTR for variable declaration + +__gshared immutable pure nothrow @property @nogc @safe void function() prefix_qualified_fp1; +__gshared{immutable{pure{nothrow{@property{@nogc{@safe{void function() prefix_qualified_fp2;}}}}}}} +static assert(typeof(prefix_qualified_fp1).stringof == typeof(prefix_qualified_fp2).stringof); +static assert(typeof(prefix_qualified_fp1).stringof + == "immutable(void function() pure nothrow @nogc @property @safe)"); + +const pure nothrow @property @nogc @safe void function()[] prefix_qualified_fp_array1; +const{pure{nothrow{@property{@nogc{@safe{void function()[] prefix_qualified_fp_array2;}}}}}} +static assert(typeof(prefix_qualified_fp_array1).stringof == typeof(prefix_qualified_fp_array2).stringof); +static assert(typeof(prefix_qualified_fp_array1).stringof + == "const(void function() pure nothrow @nogc @property @safe[])"); + +/***************************************************/ +// Parsing prefix, intermediate, or postfix @safe for alias declaration + +@safe alias void function() AliasDecl_FP1; +alias @safe void function() AliasDecl_FP2; // is not @safe +alias void function() @safe AliasDecl_FP3; +static assert(AliasDecl_FP1.stringof == "void function() @safe"); +static assert(AliasDecl_FP2.stringof == "void function()"); +static assert(AliasDecl_FP3.stringof == "void function() @safe"); + +/***************************************************/ +// 13217 + +void writeln13217(string) {} + +nothrow void a13217(T)(T x) +{ + try + { + () { writeln13217("a"); } (); + } + catch (Exception e) {} +} + +void test13217() +{ + a13217(1); +} + +/***************************************************/ +// 13840 + +struct Foo13840 +{ + int opApply(int delegate(int)) + { + return 0; + } +} + +void func13840() +{ +} + +void test13840() nothrow +{ + try + { + foreach (i; Foo13840()) // generated delegate is throwable + { + func13840(); // throwable function call + } + } + catch + {} +} + +// Add more tests regarding inferences later. + diff --git a/gcc/testsuite/gdc.test/compilable/testVRP.d b/gcc/testsuite/gdc.test/compilable/testVRP.d new file mode 100644 index 00000000000..96a499fa4ac --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testVRP.d @@ -0,0 +1,331 @@ +// PERMUTE_ARGS: -O -inline + +// Test value-range propagation. +// See Bug 3147, Bug 6000, Bug 5225. + +void add() { + byte x, y; + short a = x + y; +} + +void leftShift() { + byte x, y; + short z = x << 1; +} + +void leftShiftFail() { + ubyte x, y; + ushort z; + static assert(!__traits(compiles, z = x << y)); + // 1 << 31 surely overflows the range of 'ushort'. +} + +void rightShiftFail() { + short x; + byte y, z; + static assert(!__traits(compiles, z = x >> y)); + // [this passes in 2.053.] +} + +void rightShift() { + ushort x; + ubyte y = x >> 16; +} + +void unsignedRightShiftFail() { + int x; + ubyte y; + static assert(!__traits(compiles, y = x >>> 2)); + // [this passes in 2.053.] +} + +void subtract() { + ubyte x, y; + short z = x - y; +} + +void multiply() { + byte x, y; + short z = x * y; +} + +void subMulFail() { + ubyte x, y; + ubyte z; + static assert(!__traits(compiles, z = x - y)); + static assert(!__traits(compiles, z = x * y)); + // [these pass in 2.053.] +} + +void multiplyNeg1() { + byte b; + b = -1 + (b * -1); + static assert(!__traits(compiles, b = -1 + b * ulong.max)); +} + +void divide() { + short w; + byte y = w / 300; +} + +void divideFail() { + short w; + byte y; + static assert(!__traits(compiles, y = w / -1)); +} + +void plus1Fail() { + byte u, v; + static assert(!__traits(compiles, v = u + 1)); + // [these pass in 2.053.] +} + +void modulus() { + int x; + byte u = x % 128; +} + +void modulus_bug6000a() { + ulong t; + uint u = t % 16; +} + +void modulus_bug6000b() { + long n = 10520; + ubyte b; + static assert(!__traits(compiles, b = n % 10)); +} + +void modulus2() { + short s; + byte b = byte.max; + byte c = s % b; +} + +void modulus3() { + int i; + short s = short.max; + short t = i % s; +} + +void modulus4() { + uint i; + ushort s; + short t; + static assert(!__traits(compiles, t = i % s)); +} + +void modulusFail() { + int i; + short s; + byte b; + static assert(!__traits(compiles, b = i % s)); + static assert(!__traits(compiles, b = i % 257)); + // [these pass in 2.053.] +} + +void bitwise() { + ubyte a, b, c; + uint d; + c = a & b; + c = a | b; + c = a ^ b; + c = d & 0xff; + // [these pass in 2.053.] +} + +void bitAnd() { + byte c; + int d; + c = (0x3ff_ffffU << (0&c)) & (0x4000_0000U << (0&c)); + // the result of the above is always 0 :). +} + +void bitOrFail() { + ubyte c; + static assert(!__traits(compiles, c = c | 0x100)); + // [this passes in 2.053.] +} + +void bitAndOr() { + ubyte c; + c = (c | 0x1000) & ~0x1000; +} + +void bitAndFail() { + int d; + short s; + byte c; + static assert(!__traits(compiles, c = d & s)); + static assert(!__traits(compiles, c = d & 256)); + // [these pass in 2.053.] +} + +void bitXor() { + ushort s; + ubyte c; + c = (0xffff << (s&0)) ^ 0xff00; +} + +void bitComplement() { + int i; + ubyte b = ~(i | ~0xff); +} + +void bitComplementFail() { + ubyte b; + static assert(!__traits(compiles, b = ~(b | 1))); + // [this passes in 2.053.] +} + +void negation() { + int x; + byte b = -(x & 0x7); +} + +void negationFail() { + int x; + byte b; + static assert(!__traits(compiles, b = -(x & 255))); + // [this passes in 2.053.] +} + +short bug5225(short a) { + return a>>1; +} + +short bug1977_comment5(byte i) { + byte t = 1; + short o = t - i; + return o; +} + +void testDchar() { + dchar d; + uint i; + /+ + static assert(!__traits(compiles, d = i)); + static assert(!__traits(compiles, d = i & 0x1fffff)); + +/ + d = i % 0x110000; +} + +void bug1977_comment11() { + uint a; + byte b = a & 1; + // [this passes in 2.053.] +} + +void bug1977_comment20() { + long a; + int b = a % 1000; +} + +/******************************************/ +// 9617 + +void test9617() +{ + void f1(int) {} + void f2(short) {} + void f3(byte) {} + + // Why these calls are accepted? + static assert(!__traits(compiles, f1(ulong.max))); + static assert(!__traits(compiles, f2(ulong.max))); + static assert(!__traits(compiles, f3(ulong.max))); + + // But, if argument is not constant value, compilation fails. + ulong x; + static assert(!__traits(compiles, f1(x))); // is not callable using argument types (ulong) + static assert(!__traits(compiles, f2(x))); // is not callable using argument types (ulong) + static assert(!__traits(compiles, f3(x))); // is not callable using argument types (ulong) + + void f4(uint) {} + void f5(ushort) {} + void f6(ubyte) {} + + // If parameter type is unsigned, it is collectly rejected + static assert(!__traits(compiles, f4(ulong.max))); // is not callable using argument types (ulong) + static assert(!__traits(compiles, f5(ulong.max))); // is not callable using argument types (ulong) + static assert(!__traits(compiles, f6(ulong.max))); // is not callable using argument types (ulong) +} + +//import std.typetuple; +template TypeTuple(T...) { alias TypeTuple = T; } +template staticIota(size_t end) +{ + static if (0 < end) + alias staticIota = TypeTuple!(staticIota!(end - 1), end - 1); + else + alias staticIota = TypeTuple!(); +} +void test9617a() +{ + alias Repr = TypeTuple!( + byte, "127", // T and literal representation of T.max + ubyte, "255", + short, "32767", + ushort, "65535", + int, "2147483647", + uint, "4294967295", + long, "9223372036854775807", + ulong, "18446744073709551615" // "" or "L" -> "signed integral overflow" + ); + alias Indices = staticIota!(Repr.length / 2); + + foreach (t; Indices) + { + alias T = Repr[t * 2]; + void func(T)(T) {} + alias func!T f; + + foreach (r; Indices) + { + alias S = Repr[r * 2]; + S src = S.max; + + enum x = Repr[r * 2 + 1]; + foreach (repr; TypeTuple!(S.stringof~".max", x~"", x~"U", x~"L", x~"LU")) + { + static if (S.sizeof != T.sizeof) + static if (is(typeof(mixin(repr)) R)) + { + // "Compilable" test should be equal, even if + // the given argument is either constant or runtime variable. + enum ct = __traits(compiles, f( mixin(repr) )); + enum rt = __traits(compiles, f( src )); + + static assert(ct == rt); + //import std.string; + //enum msg = format("%6s.max to %-6s variable/constant = %d/%d, constant_repr = (%s) %s", + // S.stringof, T.stringof, rt, ct, R.stringof, repr); + //static if (ct != rt) pragma(msg, msg); + } + } + } + } +} + +void test10018(ubyte value) +{ + const int c = value; + ubyte b = c; + static assert(!__traits(compiles, b = c - 1)); + static assert(!__traits(compiles, b = c + 1)); + immutable int i = value; + b = i; + static assert(!__traits(compiles, b = i - 1)); + static assert(!__traits(compiles, b = i + 1)); +} + +void test13001(bool unknown) +{ + foreach (const i; 0..unknown?2:3) + { + ubyte b = i; + static assert(!__traits(compiles, b = i - 1)); + b = i + 253; + static assert(!__traits(compiles, b = i + 254)); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/testcheckimports.d b/gcc/testsuite/gdc.test/compilable/testcheckimports.d new file mode 100644 index 00000000000..328b8a9825b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testcheckimports.d @@ -0,0 +1,33 @@ +// REQUIRED_ARGS: -transition=checkimports -de +/* +TEST_OUTPUT: +--- +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=15825 + +template anySatisfy15825(T...) +{ + alias anySatisfy15825 = T[$ - 1]; +} + +alias T15825 = anySatisfy15825!(int); + +// https://issues.dlang.org/show_bug.cgi?id=15857 + +template Mix15857(T) +{ + void foo15857(T) {} +} +mixin Mix15857!int; +mixin Mix15857!string; + +// will find an overloadset on 2nd lookup w/ SearchImportsOnly set +import imports.test15857a; + +void test15857() +{ + foo15857(1); + bar15857(1); +} diff --git a/gcc/testsuite/gdc.test/compilable/testcontracts.d b/gcc/testsuite/gdc.test/compilable/testcontracts.d new file mode 100644 index 00000000000..21c0e4b35cc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testcontracts.d @@ -0,0 +1,174 @@ +// EXTRA_SOURCES: imports/testcontracts.d + +import imports.testcontracts; + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=3602 + +class Derived3602 : Base3602 +{ + override void method(int x, int y) + in + { + assert(x > 0); + assert(y > 0); + } + body + { + } +} + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=5230 + +class Derived5230 : Base5230 +{ + override int method() + { + return 69; + } +} + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17502 +class Foo17502 +{ + auto foo() + out {} + body {} + + auto bar() + out { assert (__result > 5); } + body { return 6; } + + auto bar_2() + out (res) { assert (res > 5); } + body { return 6; } + + int concrete() + out { assert(__result > 5); } + body { return 6; } + + int concrete_2() + out(res) { assert (res > 5); } + body { return 6; } + + void void_foo() + out {} + body {} + + auto void_auto() + out {} + body {} +} + +/***************************************************/ +// Order of declaration: (A), (C : B), (B : A) + +class A17502 +{ + int method(int p) + in + { + assert(p > 5); + } + out(res) + { + assert(res > 5); + } + body + { + return p; + } +} + +class C17502 : B17502 +{ + override int method(int p) + in + { + assert(p > 3); + } + body + { + return p * 2; + } +} + +class B17502 : A17502 +{ + override int method(int p) + in + { + assert(p > 2); + } + body + { + return p * 3; + } +} + +/***************************************************/ +// Order of declaration: (X : Y), (Y : Z), (Z) + +class X17502 : Y17502 +{ + override int method(int p) + in + { + assert(p > 3); + } + body + { + return p * 2; + } +} + +class Y17502 : Z17502 +{ + override int method(int p) + in + { + assert(p > 2); + } + body + { + return p * 3; + } +} + +class Z17502 +{ + int method(int p) + in + { + assert(p > 5); + } + out(res) + { + assert(res > 5); + } + body + { + return p; + } +} + +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17893 + +final class Foo17893(T) +{ + extern(C) void maythrow(); + + void bar() + in + { + maythrow(); + } + body + { + } +} + +Foo17893!int foo17893; diff --git a/gcc/testsuite/gdc.test/compilable/testexpression.d b/gcc/testsuite/gdc.test/compilable/testexpression.d new file mode 100644 index 00000000000..b581df7bdca --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testexpression.d @@ -0,0 +1,121 @@ + +template TT(T...) { alias T TT; } + +void TestOpAssign(Tx, Ux, ops)() +{ + foreach(T; Tx.x) + foreach(U; Ux.x) + foreach(op; ops.x) + { + T a = cast(T)1; + mixin("a " ~ op ~ " cast(U)1;"); + } +} + +void TestOpAssignAssign(Tx, Ux, ops)() +{ + foreach(T; Tx.x) + foreach(U; Ux.x) + foreach(op; ops.x) + { + T a = cast(T)1; + U b = cast(U)1; + T r; + mixin("r = a " ~ op ~ " cast(U)1;"); + } +} + +void TestOpAssignAuto(Tx, Ux, ops)() +{ + foreach(T; Tx.x) + foreach(U; Ux.x) + static if (U.sizeof <= T.sizeof) + foreach(op; ops.x) + { + T a = cast(T)1; + U b = cast(U)1; + mixin("auto r = a " ~ op ~ " cast(U)1;"); + } +} + +void TestOpAndAssign(Tx, Ux, ops)() +{ + foreach(T; Tx.x) + foreach(U; Ux.x) + static if (U.sizeof <= T.sizeof && T.sizeof >= 4) + foreach(op; ops.x) + { + T a = cast(T)1; + U b = cast(U)1; + mixin("a = a " ~ op[0..$-1] ~ " cast(U)1;"); + } +} + +struct boolean { alias TT!(bool) x; } +struct integral { alias TT!(byte, ubyte, short, ushort, int, uint, long, ulong) x; } +struct floating { alias TT!(float, double, real) x; } +struct imaginary { alias TT!(ifloat, idouble, ireal) x; } +struct complex { alias TT!(cfloat, cdouble, creal) x; } + +struct all { alias TT!("+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", ">>>=") x; } +struct arith { alias TT!("+=", "-=", "*=", "/=", "%=") x; } +struct bitwise { alias TT!("&=", "|=", "^=") x; } +struct shift { alias TT!("<<=", ">>=", ">>>=") x; } +struct addsub { alias TT!("+=", "-=") x; } +struct muldivmod { alias TT!("*=", "/=", "%=") x; } +struct nomod { alias TT!("+=", "-=", "*=", "/=") x; } + +void OpAssignCases(alias X)() +{ + X!(boolean, boolean, bitwise)(); + + X!(integral, boolean, all)(); + X!(integral, integral, all)(); + X!(integral, floating, arith)(); + + X!(floating, boolean, arith)(); + X!(floating, integral, arith)(); + X!(floating, floating, arith)(); + + X!(imaginary, boolean, muldivmod)(); + X!(imaginary, integral, muldivmod)(); + X!(imaginary, floating, muldivmod)(); + X!(imaginary, imaginary, addsub)(); + + X!(complex, boolean, arith)(); + X!(complex, integral, arith)(); + X!(complex, floating, arith)(); + X!(complex, imaginary, arith)(); + X!(complex, complex, nomod)(); +} + +void OpReAssignCases(alias X)() +{ + X!(boolean, boolean, bitwise)(); + + X!(integral, boolean, all)(); + X!(integral, integral, all)(); + + X!(floating, boolean, arith)(); + X!(floating, integral, arith)(); + X!(floating, floating, arith)(); + + X!(imaginary, boolean, muldivmod)(); + X!(imaginary, integral, muldivmod)(); + X!(imaginary, floating, muldivmod)(); + X!(imaginary, imaginary, addsub)(); + + X!(complex, boolean, arith)(); + X!(complex, integral, arith)(); + X!(complex, floating, arith)(); + X!(complex, imaginary, arith)(); + X!(complex, complex, nomod)(); +} + +void main() +{ + OpAssignCases!TestOpAssign(); + OpAssignCases!TestOpAssignAssign(); // was once disabled due to bug 7436 + OpAssignCases!TestOpAssignAuto(); // 5181 + OpReAssignCases!TestOpAndAssign(); +} diff --git a/gcc/testsuite/gdc.test/compilable/testfptr.d b/gcc/testsuite/gdc.test/compilable/testfptr.d new file mode 100644 index 00000000000..e6a0dd670df --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testfptr.d @@ -0,0 +1,423 @@ +// PERMUTE_ARGS: + +ref int frvv(); +class A {} +class B : A {} + +B restrictedfunc(in const(int)) @safe pure nothrow; +A relaxedfunc(in int); + +void bug3797() +{ + // Cannot convert if the return type or parameters are different + + void function() vv; + void function(int) vi; + int function() iv; + const(int) function() cv; + immutable(int) function() xv; + + static assert( is(typeof( vv = vv ))); + static assert(!is(typeof( vv = vi ))); + static assert(!is(typeof( vv = iv ))); + static assert(!is(typeof( vv = cv ))); + static assert(!is(typeof( vv = xv ))); + + static assert(!is(typeof( vi = vv ))); + static assert( is(typeof( vi = vi ))); + static assert(!is(typeof( vi = iv ))); + static assert(!is(typeof( vi = cv ))); + static assert(!is(typeof( vi = cx ))); + + static assert(!is(typeof( iv = vv ))); + static assert(!is(typeof( iv = vi ))); + static assert( is(typeof( iv = iv ))); + static assert( is(typeof( iv = cv ))); + static assert( is(typeof( iv = xv ))); + + static assert(!is(typeof( cv = vv ))); + static assert( is(typeof( cv = iv ))); + static assert(!is(typeof( cv = vi ))); + static assert( is(typeof( cv = cv ))); + static assert( is(typeof( cv = xv ))); + + static assert(!is(typeof( xv = vv ))); + static assert( is(typeof( xv = iv ))); + static assert(!is(typeof( xv = vi ))); + static assert( is(typeof( xv = cv ))); + static assert( is(typeof( xv = xv ))); + + int* function() ipfunc; + const(int*) function() cipfunc; + + static assert( is(typeof( cipfunc = ipfunc )) ); + static assert(!is(typeof( ipfunc = cipfunc )) ); + + // functions with different linkages can't convert + + extern(C) void function() cfunc; + extern(D) void function() dfunc; + + static assert(!is(typeof( cfunc = dfunc ))); + static assert(!is(typeof( dfunc = cfunc ))); + + // ref return can't convert to non-ref return + + typeof(&frvv) rvv; + + static assert(!is(typeof( rvv = iv ))); + static assert(!is(typeof( rvv = cv ))); + + static assert(!is(typeof( iv = rvv ))); + static assert(!is(typeof( cv = rvv ))); + + // variadic functions don't mix + + void function(...) vf; + + static assert(!is(typeof( vf = vv ))); + static assert(!is(typeof( vv = vf ))); + + // non-nothrow -> nothrow + + void function() nothrow ntf; + + static assert(!is(typeof( ntf = vv ))); + static assert( is(typeof( vv = ntf ))); + + // @safe <-> @trusted -> @system + + void function() @system systemfunc; + void function() @trusted trustedfunc; + void function() @safe safefunc; + + static assert( is(typeof( trustedfunc = safefunc ))); + static assert( is(typeof( systemfunc = trustedfunc ))); + static assert( is(typeof( systemfunc = safefunc ))); + static assert( is(typeof( safefunc = trustedfunc ))); + + static assert(!is(typeof( trustedfunc = systemfunc ))); + static assert(!is(typeof( safefunc = systemfunc ))); + + // pure -> non-pure + + void function() nonpurefunc; + void function() pure purefunc; + + static assert(!is(typeof( purefunc = nonpurefunc ))); + static assert( is(typeof( nonpurefunc = purefunc ))); + + // Cannot convert parameter storage classes (except const to in and in to const) + + void function(const(int)) constfunc; + void function(in int) infunc; + void function(out int) outfunc; + void function(ref int) reffunc; + void function(lazy int) lazyfunc; + + static assert(is(typeof( infunc = constfunc ))); + static assert(is(typeof( constfunc = infunc ))); + + static assert(!is(typeof( infunc = outfunc ))); + static assert(!is(typeof( infunc = reffunc ))); + static assert(!is(typeof( infunc = lazyfunc ))); + + static assert(!is(typeof( outfunc = infunc ))); + static assert(!is(typeof( outfunc = reffunc ))); + static assert(!is(typeof( outfunc = lazyfunc ))); + + static assert(!is(typeof( reffunc = infunc ))); + static assert(!is(typeof( reffunc = outfunc ))); + static assert(!is(typeof( reffunc = lazyfunc ))); + + static assert(!is(typeof( lazyfunc = infunc ))); + static assert(!is(typeof( lazyfunc = outfunc ))); + static assert(!is(typeof( lazyfunc = reffunc ))); + + // Test class covariance + + A function() afunc; + B function() bfunc; + + static assert( is(typeof( afunc = bfunc ))); + static assert(!is(typeof( bfunc = afunc ))); + + // Test all the conversions at once + typeof(&restrictedfunc) prestrictedfunc; + typeof(&relaxedfunc) prelaxedfunc = prestrictedfunc; +} + +void bug3797dg() +{ + ref int frvv() { return *(new int); } + B restrictedfunc(in const(int)) @safe pure nothrow { return null; } + A relaxedfunc(in int) { return null; } + // Cannot convert if the return type or parameters are different + + void delegate() vv; + void delegate(int) vi; + int delegate() iv; + const(int) delegate() cv; + immutable(int) delegate() xv; + + static assert( is(typeof( vv = vv ))); + static assert(!is(typeof( vv = vi ))); + static assert(!is(typeof( vv = iv ))); + static assert(!is(typeof( vv = cv ))); + static assert(!is(typeof( vv = xv ))); + + static assert(!is(typeof( vi = vv ))); + static assert( is(typeof( vi = vi ))); + static assert(!is(typeof( vi = iv ))); + static assert(!is(typeof( vi = cv ))); + static assert(!is(typeof( vi = cx ))); + + static assert(!is(typeof( iv = vv ))); + static assert(!is(typeof( iv = vi ))); + static assert( is(typeof( iv = iv ))); + static assert( is(typeof( iv = cv ))); + static assert( is(typeof( iv = xv ))); + + static assert(!is(typeof( cv = vv ))); + static assert( is(typeof( cv = iv ))); + static assert(!is(typeof( cv = vi ))); + static assert( is(typeof( cv = cv ))); + static assert( is(typeof( cv = xv ))); + + static assert(!is(typeof( xv = vv ))); + static assert( is(typeof( xv = iv ))); + static assert(!is(typeof( xv = vi ))); + static assert( is(typeof( xv = cv ))); + static assert( is(typeof( xv = xv ))); + + int* delegate() ipfunc; + const(int*) delegate() cipfunc; + + static assert( is(typeof( cipfunc = ipfunc )) ); + static assert(!is(typeof( ipfunc = cipfunc )) ); + + // delegates with different linkages can't convert + + extern(C) void delegate() cfunc; + extern(D) void delegate() dfunc; + + static assert(!is(typeof( cfunc = dfunc ))); + static assert(!is(typeof( dfunc = cfunc ))); + + // ref return can't convert to non-ref return + + typeof(&frvv) rvv; + + static assert(!is(typeof( rvv = iv ))); + static assert(!is(typeof( rvv = cv ))); + + static assert(!is(typeof( iv = rvv ))); + static assert(!is(typeof( cv = rvv ))); + + // variadic delegates don't mix + + void delegate(...) vf; + + static assert(!is(typeof( vf = vv ))); + static assert(!is(typeof( vv = vf ))); + + // non-nothrow -> nothrow + + void delegate() nothrow ntf; + + static assert(!is(typeof( ntf = vv ))); + static assert( is(typeof( vv = ntf ))); + + // @safe <-> @trusted -> @system + + void delegate() @system systemfunc; + void delegate() @trusted trustedfunc; + void delegate() @safe safefunc; + + static assert( is(typeof( trustedfunc = safefunc ))); + static assert( is(typeof( systemfunc = trustedfunc ))); + static assert( is(typeof( systemfunc = safefunc ))); + static assert( is(typeof( safefunc = trustedfunc ))); + + static assert(!is(typeof( trustedfunc = systemfunc ))); + static assert(!is(typeof( safefunc = systemfunc ))); + + // pure -> non-pure + + void delegate() nonpurefunc; + void delegate() pure purefunc; + + static assert(!is(typeof( purefunc = nonpurefunc ))); + static assert( is(typeof( nonpurefunc = purefunc ))); + + // Cannot convert parameter storage classes (except const to in and in to const) + + void delegate(const(int)) constfunc; + void delegate(in int) infunc; + void delegate(out int) outfunc; + void delegate(ref int) reffunc; + void delegate(lazy int) lazyfunc; + + static assert(is(typeof( infunc = constfunc ))); + static assert(is(typeof( constfunc = infunc ))); + + static assert(!is(typeof( infunc = outfunc ))); + static assert(!is(typeof( infunc = reffunc ))); + static assert(!is(typeof( infunc = lazyfunc ))); + + static assert(!is(typeof( outfunc = infunc ))); + static assert(!is(typeof( outfunc = reffunc ))); + static assert(!is(typeof( outfunc = lazyfunc ))); + + static assert(!is(typeof( reffunc = infunc ))); + static assert(!is(typeof( reffunc = outfunc ))); + static assert(!is(typeof( reffunc = lazyfunc ))); + + static assert(!is(typeof( lazyfunc = infunc ))); + static assert(!is(typeof( lazyfunc = outfunc ))); + static assert(!is(typeof( lazyfunc = reffunc ))); + + // Test class covariance + + A delegate() afunc; + B delegate() bfunc; + + static assert( is(typeof( afunc = bfunc ))); + static assert(!is(typeof( bfunc = afunc ))); + + // Test all the conversions at once + typeof(&restrictedfunc) prestrictedfunc; + typeof(&relaxedfunc) prelaxedfunc = prestrictedfunc; +} + +void bug3268() +{ + auto a = &bug3268; + const b = a; + assert(a == a); + assert(a == b); + assert(b == b); + immutable c = cast(immutable)a; + assert(a == c); + assert(b == c); + assert(c == c); + + static assert(is(typeof(*a) == typeof(*b))); + static assert(is(typeof(*a) == typeof(*c))); +} + +void bug3268dg() +{ + void bug3268x() {} + auto a = &bug3268x; + const b = a; + assert(a == a); + assert(a == b); + assert(b == b); + immutable c = cast(immutable)a; + assert(a == c); + assert(b == c); + assert(c == c); +} + +void bug3833() +{ + bool b; + + void function() func; + void function() pure purefunc; + void function() nothrow nothrowfunc; + void function() @safe safefunc; + void function() @trusted trustedfunc; + + static assert( is(typeof( b ? func : purefunc ) == typeof( func ))); + static assert( is(typeof( b ? func : nothrowfunc ) == typeof( func ))); + static assert( is(typeof( b ? func : safefunc ) == typeof( func ))); + static assert( is(typeof( b ? func : trustedfunc ) == typeof( func ))); + + static assert( is(typeof( b ? purefunc : nothrowfunc ) == typeof( func ))); + static assert( is(typeof( b ? purefunc : safefunc ) == typeof( func ))); + static assert( is(typeof( b ? purefunc : trustedfunc ) == typeof( func ))); + + static assert( is(typeof( b ? nothrowfunc : safefunc ) == typeof( func ))); + static assert( is(typeof( b ? nothrowfunc : trustedfunc ) == typeof( func ))); + + static assert( is(typeof( b ? safefunc : trustedfunc ) == typeof( trustedfunc ))); + + auto arr = [func, purefunc, nothrowfunc, safefunc, trustedfunc]; + + static assert( is(typeof( arr ) == typeof(func)[]) ); +} + +void bug3833dg() +{ + bool b; + + void delegate() func; + void delegate() pure purefunc; + void delegate() nothrow nothrowfunc; + void delegate() @safe safefunc; + void delegate() @trusted trustedfunc; + + static assert( is(typeof( b ? func : purefunc ) == typeof( func ))); + static assert( is(typeof( b ? func : nothrowfunc ) == typeof( func ))); + static assert( is(typeof( b ? func : safefunc ) == typeof( func ))); + static assert( is(typeof( b ? func : trustedfunc ) == typeof( func ))); + + static assert( is(typeof( b ? purefunc : nothrowfunc ) == typeof( func ))); + static assert( is(typeof( b ? purefunc : safefunc ) == typeof( func ))); + static assert( is(typeof( b ? purefunc : trustedfunc ) == typeof( func ))); + + static assert( is(typeof( b ? nothrowfunc : safefunc ) == typeof( func ))); + static assert( is(typeof( b ? nothrowfunc : trustedfunc ) == typeof( func ))); + + static assert( is(typeof( b ? safefunc : trustedfunc ) == typeof( trustedfunc ))); + + auto arr = [func, purefunc, nothrowfunc, safefunc, trustedfunc]; + + static assert( is(typeof( arr ) == typeof(func)[]) ); +} + +void bug4838() +{ + void delegate() const dgc; + static assert(typeof(dgc).stringof == "void delegate() const"); + + void delegate() immutable dgi; + static assert(typeof(dgi).stringof == "void delegate() immutable"); + + void delegate() shared dgs; + static assert(typeof(dgs).stringof == "void delegate() shared"); + + void delegate() shared const dgsc; + static assert(typeof(dgsc).stringof == "void delegate() shared const"); + + void delegate() inout dgw; + static assert(typeof(dgw).stringof == "void delegate() inout"); + + void delegate() shared inout dgsw; + static assert(typeof(dgsw).stringof == "void delegate() shared inout"); +} + +void test8822() +{ + struct S { void foo() const {} } + S s; + void delegate() const dg = &s.foo; // OK + + void foo(void delegate() const dg){} // OK + + struct Foo(T) {} + alias Foo!(void delegate() const) X; // NG -> OK +} + +void main() +{ + static assert(is(typeof(&main) P : U*, U)); + auto x = cast(void*)&main; + + const void * p = &main; + + __gshared void function() gp = null; + __gshared void delegate() gp2 = null; +} diff --git a/gcc/testsuite/gdc.test/compilable/testfwdref.d b/gcc/testsuite/gdc.test/compilable/testfwdref.d new file mode 100644 index 00000000000..12b5cc85279 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testfwdref.d @@ -0,0 +1,716 @@ +// PERMUTE_ARGS: + +/***************************************************/ +// 6766 + +class Foo6766 +{ + this(int x) { } + void test(Foo6766 foo = new Foo6766(1)) { } +} + +struct Bar6766 +{ + this(int x) { } + void test(Bar6766 bar = Bar6766(1)) { } +} + +/***************************************************/ +// 8609 + +struct Tuple8609(T) +{ + T arg; +} + +// ---- + +struct Foo8609a +{ + Bar8609a b; +} +struct Bar8609a +{ + int x; + Tuple8609!(Foo8609a) spam() { return Tuple8609!(Foo8609a)(); } +} + +// ---- + +struct Foo8609b +{ + Bar8609b b; +} +struct Bar8609b +{ + int x; + Tuple8609!(Foo8609b[1]) spam() { return Tuple8609!(Foo8609b[1])(); } +} + +/***************************************************/ +// 8698 + +interface IRoot8698a {} +interface IClass8698a : IRoot8698a { } +struct Struct8698a { } +class Class8698a : IClass8698a { alias Struct8698a Value; } +void test8698a(Class8698a.Value) { } +//interface IRoot8698a {} + +// ---- + +//interface IRoot8698b {} +interface IClass8698b : IRoot8698b { } +struct Struct8698b { } +class Class8698b : IClass8698b { alias Struct8698b Value; } +void test8698b(Class8698b.Value) { } +interface IRoot8698b {} + +/***************************************************/ +// 9514 + +template TStructHelpers9514a() +{ + void opEquals(Foo9514a) + { + auto n = FieldNames9514a!(); + } +} + +struct Foo9514a +{ + mixin TStructHelpers9514a!(); +} + +import imports.fwdref9514 : find9514; // selective import without aliasing + +template FieldNames9514a() +{ + static if (find9514!`true`([1])) enum int FieldNames9514a = 1; +} + +// ---- + +template TStructHelpers9514b() +{ + void opEquals(Foo9514b) + { + auto n = FieldNames9514b!(); + } +} + +struct Foo9514b +{ + mixin TStructHelpers9514b!(); +} + +import imports.fwdref9514 : foo9514 = find9514; // selective import with aliasing + +template FieldNames9514b() +{ + static if (foo9514!`true`([1])) enum int FieldNames9514b = 1; +} + +/***************************************************/ +// 10015 + +struct S10015(T) { alias X = int; } + +alias Y10015 = s10015.X; +S10015!int s10015; + +/***************************************************/ +// 10101 + +int front10101(int); + +mixin template reflectRange10101() +{ + static if (is(typeof(this.front10101))) + { + int x; + } +} + +struct S10101(R) +{ + R r_; + + typeof(r_.front10101) front10101() @property { return r_.front10101; } + + mixin reflectRange10101; +} + +void test10101() +{ + S10101!(int) s; +} + +/***************************************************/ +// 11019 + +class A11019 +{ + A11019 View() { return null; } +} + +class B11019 : A11019 +{ + override D11019 View() { return null; } +} + +class D11019 : B11019 {} + +/***************************************************/ +// 11166 + +template Tup11166(T...) { alias Tup11166 = T; } + +struct S11166a +{ + enum S11166a a = S11166a(0); + enum S11166a b = S11166a(1); + + this(long value) { } + + long value; + + // only triggered when private and a template instance. + private alias types = Tup11166!(a, b); +} + +struct S11166b +{ + enum S11166b a = S11166b(0); + enum S11166b b = S11166b(1); + + // not at the last of members + alias types = Tup11166!(a, b); + + this(long value) { } + + long value; +} + +/***************************************************/ +// 12152 + +class A12152 +{ + alias Y = B12152.X; +} + +class B12152 : A12152 +{ + alias int X; +} + +static assert(is(A12152.Y == int)); + +/***************************************************/ +// 12201 + +template T12201() +{ + alias imports.fwdref12201a.FILE* FP; +} + +struct S12201a +{ + mixin T12201; + import imports.fwdref12201a; +} + +union U12201 +{ + mixin T12201; + import imports.fwdref12201a; +} + +class C12201 +{ + mixin T12201; + import imports.fwdref12201a; +} + +interface I12201 +{ + mixin T12201; + import imports.fwdref12201a; +} + + +template TI12201() +{ + mixin T12201; + import imports.fwdref12201a; +} +mixin template TM12201() +{ + mixin T12201; + import imports.fwdref12201a; +} +struct S12201b +{ + alias ti = TI12201!(); + + mixin TM12201; +} + +/***************************************************/ +// 12531 + +struct Node12531(T) +{ + T _val; +} + +void test12531() +{ + static struct Foo + { + Node12531!Foo* node; + } +} + +/***************************************************/ +// 12543 + +class C12543; +static assert(C12543.sizeof == (void*).sizeof); +static assert(C12543.alignof == (void*).sizeof); +static assert(C12543.mangleof == "C10testfwdref6C12543"); + +/***************************************************/ +// 14010 + +enum E14010; +static assert(E14010.mangleof == "E10testfwdref6E14010"); + +struct S14010; +static assert(S14010.mangleof == "S10testfwdref6S14010"); + +/***************************************************/ +// 12983 + +alias I12983 = int; +class B12983(T) { alias MyC = C12983!string; } + +class C12983(T) : B12983!float +{ + void m() { f12983(0); } +} + +alias MyB12983 = B12983!float; + +void f12983(); +void f12983(I12983); + +/***************************************************/ +// 12984 + +class B12984a { alias MyD = D12984a!int; } +class C12984a : B12984a { } + +class D12984a(T) { alias MyE = E12984a!float; } +class E12984a(T) : D12984a!int +{ + void m() + { + auto c = new C12984a(); + } +} + +static assert(__traits(classInstanceSize, B12984a) == (void*).sizeof * 2); +static assert(__traits(classInstanceSize, C12984a) == (void*).sizeof * 2); + +// ---- + +class B12984b { int b; alias MyD = D12984b!int; } +class C12984b : B12984b { int c; } + +class D12984b(T) { int d; alias MyE = E12984b!float; } +class E12984b(T) : D12984b!int +{ + int e; + void m() + { + auto c = new C12984b(); + } +} + +static assert(__traits(classInstanceSize, B12984b) == (void*).sizeof * 2 + int.sizeof); +static assert(__traits(classInstanceSize, C12984b) == (void*).sizeof * 2 + int.sizeof * 2); + +/***************************************************/ +// 14390 + +class B14390a { alias MyD = D14390a!int; } +class C14390a : B14390a { void f(int) {} } +class D14390a(T) { alias MyE = E14390a!float; } +class E14390a(T) : D14390a!int { void m() { auto c = new C14390a(); } } + +class B14390b { alias MyD = D14390b!int; } +class C14390b : B14390b { static struct S {} } +class D14390b(T) { alias MyE = E14390b!float; } +class E14390b(T) : D14390b!int { void m() { auto c = new C14390b(); } } + +/***************************************************/ +// 13860 + +/* +TEST_OUTPUT: +--- +pure nothrow @nogc @safe void() +pure nothrow @nogc @safe void() +--- +*/ + +struct Foo13860(Bar...) +{ + Bar bars; + auto baz(size_t d)() {} + pragma(msg, typeof(baz!0)); +} + +auto bar13860(S, R)(S s, R r) +{ + pragma(msg, typeof(Foo13860!().baz!0)); +} + +void test13860() +{ + int[] x; + int[] y; + x.bar13860(y); +} + +/***************************************************/ +// 14083 + +class NBase14083 +{ + int foo(NA14083 a) { return 1; } + int foo(NB14083 a) { return 2; } +} +class NA14083 : NBase14083 +{ + int v; + this(int v) { this.v = v; } +} +class NB14083 : NBase14083 +{ + override int foo(NA14083 a) { return a.v; } +} + +class TBase14083(T) +{ + int foo(TA14083!T a) { return 1; } + int foo(TB14083!T a) { return 2; } +} +class TA14083(T) : TBase14083!T +{ + T v; + this(T v) { this.v = v; } +} +class TB14083(T) : TBase14083!T +{ + override int foo(TA14083!T a) { return a.v; } +} + +static assert( +{ + NA14083 na = new NA14083(10); + NB14083 nb = new NB14083(); + assert(na.foo(na) == 1); + assert(na.foo(nb) == 2); + assert(nb.foo(na) == 10); + + TA14083!int ta = new TA14083!int(10); + TB14083!int tb = new TB14083!int(); + assert(ta.foo(ta) == 1); + assert(ta.foo(tb) == 2); + assert(tb.foo(ta) == 10); + + return true; +}()); + +/***************************************************/ +// 14549 + +string foo14549(T)() +{ + static if (T.tupleof.length >= 0) + return ""; +} + +class Frop14549 +{ + mixin(foo14549!(typeof(this))); + + static if (__traits(compiles, undefined)) + { + } + else + { + int bar = 0; + } + + static if (!__traits(isVirtualMethod, this.bar)) {} +} + +// ---- +// regression case + +template Mix14549() +{ + mixin(code14549!(typeof(this))); +} + +template code14549(T) +{ + enum string code14549 = + q{ static if (!__traits(isVirtualMethod, "boo")) {} }; +} + +class Bar14549 +{ + mixin Mix14549; + int boo; +} + +// ---- +// 14609 - regression case + +interface Foo14609(T) +{ + static if (is(T == int)) + public int bar(); +} +class Frop14609 : Foo14609!int +{ + public int bar() { return 0; } +} + +/***************************************************/ +// test case 1, comes from Phobos +/* +TEST_OUTPUT: +--- ++alias Alias12540 ++anySatisfy, T.length == 1 ++isStaticArray ++T.stringof in StaticArrayTypeOf +-T.stringof in StaticArrayTypeOf +-isStaticArray ++hasElaborateCpCtor S == struct or else +-hasElaborateCpCtor S == struct or else +-anySatisfy, T.length == 1 +-alias Alias12540 +--- +*/ + +template anySatisfy15726x(alias F, T...) +{ + //static if (T.length == 1) + //{ + pragma(msg, "+anySatisfy, T.length == 1"); + enum anySatisfy15726x = F!(T[0]); + pragma(msg, "-anySatisfy, T.length == 1"); + //} +} + +template StaticArrayTypeOf15726x(T) +{ + alias X = T; + + static if (is(X : E[n], E, size_t n)) + { + //alias StaticArrayTypeOf15726x = X; + } + else + { + pragma(msg, "+T.stringof in StaticArrayTypeOf"); + // Fixed: T.stringof (T == Class12540) should not invoke + // T.size() in ClassDeclaration.search(). + static assert(0, T.stringof~" is not a static array type"); + pragma(msg, "-T.stringof in StaticArrayTypeOf"); + } +} + +//enum bool isStaticArray(T) = is(StaticArrayTypeOf15726x!T); +template isStaticArray15726x(T) +{ + pragma(msg, "+isStaticArray"); + enum bool isStaticArray15726x = is(StaticArrayTypeOf15726x!T); + pragma(msg, "-isStaticArray"); +} + +template hasElaborateCpCtor15726x(S) +{ + static if (isStaticArray15726x!S && S.length) + { + //pragma(msg, "X+"); + enum bool hasElaborateCpCtor15726x = + hasElaborateCpCtor15726x!(typeof(S.init[0])); + //pragma(msg, "X-"); + } + else + { + pragma(msg, "+hasElaborateCpCtor S == struct or else"); + static if (is(S == struct)) + { + enum bool hasElaborateCpCtor15726x = true; + //enum hasElaborateCpCtor15726x = hasMember!(S, "__postblit") + // || anySatisfy15726x!(.hasElaborateCpCtor15726x, FieldTypeTuple!S); + } + else + { + enum bool hasElaborateCpCtor15726x = false; + } + pragma(msg, "-hasElaborateCpCtor S == struct or else"); + } +} + +struct VariantN15726x(AllowedTypesParam...) +{ + alias AllowedTypes = AllowedTypesParam; + + static if (!AllowedTypes.length || + anySatisfy15726x!(hasElaborateCpCtor15726x, AllowedTypes)) + { + } +} + +template Algebraic15726x(T) +{ + alias Algebraic15726x = VariantN15726x!(T); +} + +void test15726x() +{ + static struct DummyScope + { + pragma(msg, "+alias Alias12540"); + alias Alias12540 = Algebraic15726x!Class12540; + pragma(msg, "-alias Alias12540"); + static class Class12540 + { + Alias12540 entity; + } + } +} + +/***************************************************/ +// test case 2, comes from Phobos + +struct RefCounted15726y(T) +{ + struct RefCountedStore + { + struct Impl + { + T _payload; + } + Impl* _store; + } + RefCountedStore _refCounted; + + this(this) {} + + ~this() + { + _refCounted._store._payload.__xdtor(); + } +} + +struct RangeT15726y(A) +{ + A[1] _outer_; + alias RC = RangeT15726y!(const(A)); +} + +struct Array15726y(T) +{ + struct Payload + { + ~this(); + } + + alias Data = RefCounted15726y!(Payload); + Data _data; + + alias Range = RangeT15726y!Array15726y; +} + +void test15726y() +{ + alias Range = RangeT15726y!(Array15726y!int); + Range r; + r = r; // opAssign +} + +/***************************************************/ +// 15726 + +struct RC15726(T) +{ + struct Impl + { + T _payload; + } + + Impl* _store; + + ~this() + { + destroy15726a(_store._payload); + } +} + +// ---- + +struct Con15726a(T) +{ + alias Stmt15726a = .Stmt15726a!T; +} + +struct Stmt15726a(T) +{ + alias Con15726a = .Con15726a!T; + + RC15726!Payload data; + + struct Payload + { + Con15726a con; + } +} + +Con15726a!int x15726a; + +void destroy15726a(T)(ref T obj) @trusted +{ + auto buf = (cast(ubyte*)&obj)[0 .. T.sizeof]; +} + +// ---- + +struct Util15726b(C, S) {} + +struct Con15726b(T) +{ + alias Util15726b = .Util15726b!(Con15726b!T, Stmt15726b!T); +} + +struct Stmt15726b(T) +{ + struct Payload + { + Con15726b!T con; + } + + RC15726!Payload data; +} + +Con15726b!int x15726b; diff --git a/gcc/testsuite/gdc.test/compilable/testheader1.d b/gcc/testsuite/gdc.test/compilable/testheader1.d new file mode 100644 index 00000000000..c46728d64c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheader1.d @@ -0,0 +1,6 @@ +// EXTRA_SOURCES: extra-files/header1.d +// REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/header1.di +// PERMUTE_ARGS: -d -dw +// POST_SCRIPT: compilable/extra-files/header-postscript.sh header1 + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testheader12567a.d b/gcc/testsuite/gdc.test/compilable/testheader12567a.d new file mode 100644 index 00000000000..27c14756880 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheader12567a.d @@ -0,0 +1,7 @@ +// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header12567a.di +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/header-postscript.sh header12567a + +deprecated module header12567a; + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testheader12567b.d b/gcc/testsuite/gdc.test/compilable/testheader12567b.d new file mode 100644 index 00000000000..93393c50928 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheader12567b.d @@ -0,0 +1,7 @@ +// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header12567b.di +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/header-postscript.sh header12567b + +deprecated("message") module header12567b; + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testheader1i.d b/gcc/testsuite/gdc.test/compilable/testheader1i.d new file mode 100644 index 00000000000..98599925965 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheader1i.d @@ -0,0 +1,6 @@ +// EXTRA_SOURCES: extra-files/header1.d +// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header1i.di -inline +// PERMUTE_ARGS: -d -dw +// POST_SCRIPT: compilable/extra-files/header-postscript.sh header1i + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testheader2.d b/gcc/testsuite/gdc.test/compilable/testheader2.d new file mode 100644 index 00000000000..003d56467a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheader2.d @@ -0,0 +1,6 @@ +// EXTRA_SOURCES: extra-files/header2.d +// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header2.di +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/header-postscript.sh header2 + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testheader2i.d b/gcc/testsuite/gdc.test/compilable/testheader2i.d new file mode 100644 index 00000000000..79662edd184 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheader2i.d @@ -0,0 +1,6 @@ +// EXTRA_SOURCES: extra-files/header2.d +// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header2i.di -inline +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/header-postscript.sh header2i + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testheader3.d b/gcc/testsuite/gdc.test/compilable/testheader3.d new file mode 100644 index 00000000000..f5fdbc1d43e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheader3.d @@ -0,0 +1,8 @@ +// EXTRA_SOURCES: extra-files/header3.d +// REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/header3.di +// PERMUTE_ARGS: -d -dw +// POST_SCRIPT: compilable/extra-files/header-postscript.sh header3 + +void main() {} + + diff --git a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d new file mode 100644 index 00000000000..1a7d6506669 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheaderudamodule.di +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/header-postscript.sh testheaderudamodule + +@(1, UDA(2)) +module testheaderudamodule; + +struct UDA +{ + int a; +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/compilable/testimport12242.d b/gcc/testsuite/gdc.test/compilable/testimport12242.d new file mode 100644 index 00000000000..1d1cccd0100 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testimport12242.d @@ -0,0 +1,26 @@ +// PERMUTE_ARGS: + +module testimport12242; + +import imports.imp12242a; // test // stripA == OverloadSet +import imports.imp12242a1; // std.string // stripA == template + +import imports.imp12242b1; // std.string // stripB == template +import imports.imp12242b; // test // stripB == OverloadSet + +void main() +{ + static assert(stripA(" af ") == 1); + static assert(" af ".stripA() == 1); // UFCS (1) + static assert(" af ".stripA == 1); // UFCS (2) + + static assert(stripB(" af ") == 1); + static assert(" af ".stripB() == 1); // UFCS (1) + static assert(" af ".stripB == 1); // UFCS (2) + + + static assert(foo!int == 1); + static assert(foo!long == 2); + static assert(foo!float == 3); + static assert(foo!real == 4); +} diff --git a/gcc/testsuite/gdc.test/compilable/testparse.d b/gcc/testsuite/gdc.test/compilable/testparse.d new file mode 100644 index 00000000000..d6713ad40c2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testparse.d @@ -0,0 +1,168 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -o- + +/***************************************************/ +// 6719 + +pragma(msg, __traits(compiles, mixin("(const(A))[0..0]"))); + +/***************************************************/ +// 9232 + +struct Foo9232 +{ + void bar(T)() {} + void baz() {} +} + +void test9232() +{ + Foo9232 foo; + (foo).bar!int(); // OK <- Error: found '!' when expecting ';' following statement + ((foo)).bar!int(); // OK + foo.bar!int(); // OK + (foo).baz(); // OK +} + +/***************************************************/ +// 9401 + +struct S9401a +{ + ~this() nothrow pure @safe { } +} + +struct S9401b +{ + @safe ~this() pure nothrow { } +} + +void test9401() nothrow pure @safe +{ + S9401a s1; + S9401b s2; +} + +/***************************************************/ +// 9649 + +class Outer9649 +{ + class Inner + { + } +} + +void test9649() +{ + Outer9649 outer9649; + (outer9649).new Inner(); +} + +/***************************************************/ +// 9679 + +void test9679(inout int = 0) +{ + if ( auto n = 1) { static assert(is(typeof(n) == int)); } + if ( const n = 1) { static assert(is(typeof(n) == const int)); } + if ( immutable n = 1) { static assert(is(typeof(n) == immutable int)); } + if (shared n = 1) { static assert(is(typeof(n) == shared int)); } + if (shared const n = 1) { static assert(is(typeof(n) == shared const int)); } + if ( inout n = 1) { static assert(is(typeof(n) == inout int)); } + if (shared inout n = 1) { static assert(is(typeof(n) == shared inout int)); } + + if ( const int n = 1) { static assert(is(typeof(n) == const int)); } + if ( immutable int n = 1) { static assert(is(typeof(n) == immutable int)); } + if (shared int n = 1) { static assert(is(typeof(n) == shared int)); } + if (shared const int n = 1) { static assert(is(typeof(n) == shared const int)); } + if ( inout int n = 1) { static assert(is(typeof(n) == inout int)); } + if (shared inout int n = 1) { static assert(is(typeof(n) == shared inout int)); } + + if ( const(int) n = 1) { static assert(is(typeof(n) == const int)); } + if ( immutable(int) n = 1) { static assert(is(typeof(n) == immutable int)); } + if (shared (int) n = 1) { static assert(is(typeof(n) == shared int)); } + if (shared const(int) n = 1) { static assert(is(typeof(n) == shared const int)); } + if ( inout(int) n = 1) { static assert(is(typeof(n) == inout int)); } + if (shared inout(int) n = 1) { static assert(is(typeof(n) == shared inout int)); } + + if (immutable(int)[] n = [1]) { static assert(is(typeof(n) == immutable(int)[])); } +} + +/***************************************************/ +// 9901 + +template isGood9901(T) +{ + enum isGood9901 = true; +} +void test9901() +{ + string foo(R)(R data) if (isGood9901!R) + { + return ""; + } + foo(1); +} + +/***************************************************/ +// 10199 + +void test10199() +{ + goto label; +label: +} + +/***************************************************/ +// 12460 + +void f12460(T)() +{ + static if (is(T == int)) + { + goto end; + } +end: +} + +void test12460() +{ + f12460!int(); +} + +/***************************************************/ +// 11689 + +void test11689() +{ + deprecated void foo() {} +} + +/***************************************************/ +// 11751 + +static assert(is(float == typeof(0x0.1p1F))); + +/***************************************************/ +// 11957 + +extern(C++) class C11957 +{ + void x() {} +} + +void test11957() +{ + extern(C++) class D : C11957 + { + override void x() {} + } +} + +/***************************************************/ +// 13049 + +enum mangle13049(T) = T.mangleof; +alias FP13049 = void function(scope int); // OK +static assert(mangle13049!FP13049 == mangle13049!(void function(scope int))); // OK <- NG diff --git a/gcc/testsuite/gdc.test/compilable/testpostblit.d b/gcc/testsuite/gdc.test/compilable/testpostblit.d new file mode 100644 index 00000000000..60a0f4a1ce9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testpostblit.d @@ -0,0 +1,17 @@ +struct Test1a +{ + this(this) + { + } +} + +struct Test1b +{ + Test1a a; +} + +struct Test1c +{ + const Test1b b; + @disable this(this); +} diff --git a/gcc/testsuite/gdc.test/compilable/testprofile.d b/gcc/testsuite/gdc.test/compilable/testprofile.d new file mode 100644 index 00000000000..2f7beebbe43 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testprofile.d @@ -0,0 +1,23 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -profile + +template LaLa(E...) { + class LaLa { + this() { + + } + } +} + +void main() { + // doesn't work + new LaLa!("lala", "lalalalala", "lala", + "lala", "lala", "lala", "lalalala", + "lala", "lala", "lala", "lalala", + "lala", "lala", "lala", "lala", + "lala", "lala", "lala", "lala", + "lala", "lala", "lala", "lala", + "lala", "lala", "lala", "lala"); + +} + diff --git a/gcc/testsuite/gdc.test/compilable/uda.d b/gcc/testsuite/gdc.test/compilable/uda.d new file mode 100644 index 00000000000..cb9413b06f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/uda.d @@ -0,0 +1,7 @@ +/************************************************/ +// 15180: [REG2.069.0-b1] Segfault with empty struct used as UDA + +struct foo { } +@foo bar () { } + +/************************************************/ diff --git a/gcc/testsuite/gdc.test/compilable/udamodule1.d b/gcc/testsuite/gdc.test/compilable/udamodule1.d new file mode 100644 index 00000000000..4631642afb3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/udamodule1.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +compilable/udamodule1.d(9): Deprecation: module imports.udamodule1 is deprecated - This module will be removed. +--- +*/ +import imports.udamodule1; + +void main() { foo(); } diff --git a/gcc/testsuite/gdc.test/compilable/udamodule2.d b/gcc/testsuite/gdc.test/compilable/udamodule2.d new file mode 100644 index 00000000000..f2c0794e582 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/udamodule2.d @@ -0,0 +1,5 @@ +import imports.udamodule2; +import imports.udamodule2a; + +enum Attrib = __traits(getAttributes, imports.udamodule2); +static assert(Attrib[0] == UDA(1) && Attrib[1] == UDA(2)); diff --git a/gcc/testsuite/gdc.test/compilable/verrors_spec.d b/gcc/testsuite/gdc.test/compilable/verrors_spec.d new file mode 100644 index 00000000000..b858008922b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/verrors_spec.d @@ -0,0 +1,14 @@ +/* +PERMUTE_ARGS: +REQUIRED_ARGS: -verrors=spec +TEST_OUTPUT: +--- +(spec:1) compilable/verrors_spec.d(13): Error: cannot implicitly convert expression `& i` of type `int*` to `int` +--- +*/ + +void foo(int i) +{ + int p; + bool b = __traits(compiles, {p = &i;}); +} diff --git a/gcc/testsuite/gdc.test/compilable/vgc1.d b/gcc/testsuite/gdc.test/compilable/vgc1.d new file mode 100644 index 00000000000..87b35a41cbc --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/vgc1.d @@ -0,0 +1,87 @@ +// REQUIRED_ARGS: -vgc -o- +// PERMUTE_ARGS: + +/***************** NewExp *******************/ + +struct S1 { } +struct S2 { this(int); } +struct S3 { this(int) @nogc; } +struct S4 { new(size_t); } +struct S5 { @nogc new(size_t); } + +/* +TEST_OUTPUT: +--- +compilable/vgc1.d(27): vgc: 'new' causes GC allocation +compilable/vgc1.d(29): vgc: 'new' causes GC allocation +compilable/vgc1.d(30): vgc: 'new' causes GC allocation +compilable/vgc1.d(32): vgc: 'new' causes GC allocation +compilable/vgc1.d(33): vgc: 'new' causes GC allocation +compilable/vgc1.d(34): vgc: 'new' causes GC allocation +compilable/vgc1.d(38): vgc: 'new' causes GC allocation +--- +*/ + +void testNew() +{ + int* p1 = new int; + + int[] a1 = new int[3]; + int[][] a2 = new int[][](2, 3); + + S1* ps1 = new S1(); + S2* ps2 = new S2(1); + S3* ps3 = new S3(1); + S4* ps4 = new S4; // no error + S5* ps5 = new S5; // no error + + Object o1 = new Object(); +} + +/* +TEST_OUTPUT: +--- +compilable/vgc1.d(55): vgc: 'new' causes GC allocation +compilable/vgc1.d(57): vgc: 'new' causes GC allocation +compilable/vgc1.d(58): vgc: 'new' causes GC allocation +compilable/vgc1.d(60): vgc: 'new' causes GC allocation +compilable/vgc1.d(61): vgc: 'new' causes GC allocation +compilable/vgc1.d(62): vgc: 'new' causes GC allocation +--- +*/ + +void testNewScope() +{ + scope int* p1 = new int; + + scope int[] a1 = new int[3]; + scope int[][] a2 = new int[][](2, 3); + + scope S1* ps1 = new S1(); + scope S2* ps2 = new S2(1); + scope S3* ps3 = new S3(1); + scope S4* ps4 = new S4; // no error + scope S5* ps5 = new S5; // no error + + scope Object o1 = new Object(); // no error + scope o2 = new Object(); // no error + scope Object o3; + o3 = o2; // no error +} + +/***************** DeleteExp *******************/ + +/* +TEST_OUTPUT: +--- +compilable/vgc1.d(84): vgc: 'delete' requires GC +compilable/vgc1.d(85): vgc: 'delete' requires GC +compilable/vgc1.d(86): vgc: 'delete' requires GC +--- +*/ +void testDelete(int* p, Object o, S1* s) +{ + delete p; + delete o; + delete s; +} diff --git a/gcc/testsuite/gdc.test/compilable/vgc2.d b/gcc/testsuite/gdc.test/compilable/vgc2.d new file mode 100644 index 00000000000..b1a7f187a23 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/vgc2.d @@ -0,0 +1,104 @@ +// REQUIRED_ARGS: -vgc -o- +// PERMUTE_ARGS: + +/***************** CatExp *******************/ + +/* +TEST_OUTPUT: +--- +compilable/vgc2.d(21): vgc: operator ~ may cause GC allocation +compilable/vgc2.d(22): vgc: operator ~ may cause GC allocation +compilable/vgc2.d(23): vgc: operator ~ may cause GC allocation +compilable/vgc2.d(25): vgc: operator ~ may cause GC allocation +compilable/vgc2.d(26): vgc: operator ~ may cause GC allocation +compilable/vgc2.d(27): vgc: operator ~ may cause GC allocation +compilable/vgc2.d(28): vgc: operator ~ may cause GC allocation +compilable/vgc2.d(29): vgc: operator ~ may cause GC allocation +--- +*/ +void testCat(int[] a, string s) +{ + int[] a1 = a ~ a; + int[] a2 = a ~ 1; + int[] a3 = 1 ~ a; + + string s1 = s ~ s; + string s2 = s ~ "a"; + string s3 = "a" ~ s; + string s4 = s ~ 'c'; + string s5 = 'c' ~ s; + + string s6 = "a" ~ "b"; // no error + string s7 = "a" ~ 'c'; // no error + string s8 = 'c' ~ "b"; // no error +} + +/***************** CatAssignExp *******************/ + +/* +TEST_OUTPUT: +--- +compilable/vgc2.d(48): vgc: operator ~= may cause GC allocation +compilable/vgc2.d(50): vgc: operator ~= may cause GC allocation +compilable/vgc2.d(51): vgc: operator ~= may cause GC allocation +--- +*/ +void testCatAssign(int[] a, string s) +{ + a ~= 1; + + s ~= "a"; + s ~= 'c'; +} + +/***************** ArrayLiteralExp *******************/ + +int* barA(); + +/* +TEST_OUTPUT: +--- +compilable/vgc2.d(70): vgc: array literal may cause GC allocation +compilable/vgc2.d(71): vgc: array literal may cause GC allocation +--- +*/ +void testArray() +{ + enum arrLiteral = [null, null]; + + int* p; + auto a = [p, p, barA()]; + a = arrLiteral; +} + +/***************** AssocArrayLiteralExp *******************/ + +/* +TEST_OUTPUT: +--- +compilable/vgc2.d(87): vgc: associative array literal may cause GC allocation +compilable/vgc2.d(88): vgc: associative array literal may cause GC allocation +--- +*/ +void testAssocArray() +{ + enum aaLiteral = [10: 100]; + + auto aa = [1:1, 2:3, 4:5]; + aa = aaLiteral; +} + +/***************** IndexExp *******************/ + +/* +TEST_OUTPUT: +--- +compilable/vgc2.d(102): vgc: indexing an associative array may cause GC allocation +compilable/vgc2.d(103): vgc: indexing an associative array may cause GC allocation +--- +*/ +void testIndex(int[int] aa) +{ + aa[1] = 0; + int n = aa[1]; +} diff --git a/gcc/testsuite/gdc.test/compilable/vgc3.d b/gcc/testsuite/gdc.test/compilable/vgc3.d new file mode 100644 index 00000000000..4bf889ce997 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/vgc3.d @@ -0,0 +1,68 @@ +// REQUIRED_ARGS: -vgc -o- +// PERMUTE_ARGS: + +/***************** AssignExp *******************/ + +/* +TEST_OUTPUT: +--- +compilable/vgc3.d(16): vgc: setting 'length' may cause GC allocation +compilable/vgc3.d(17): vgc: setting 'length' may cause GC allocation +compilable/vgc3.d(18): vgc: setting 'length' may cause GC allocation +--- +*/ +void testArrayLength(int[] a) +{ + a.length = 3; + a.length += 1; + a.length -= 1; +} + +/***************** CallExp *******************/ + +void barCall(); + +/* +TEST_OUTPUT: +--- +--- +*/ + + +void testCall() +{ + auto fp = &barCall; + (*fp)(); + barCall(); +} + +/****************** Closure ***********************/ + +@nogc void takeDelegate2(scope int delegate() dg) {} +@nogc void takeDelegate3( int delegate() dg) {} + +/* +TEST_OUTPUT: +--- +compilable/vgc3.d(51): vgc: using closure causes GC allocation +compilable/vgc3.d(63): vgc: using closure causes GC allocation +--- +*/ +auto testClosure1() +{ + int x; + int bar() { return x; } + return &bar; +} +void testClosure2() +{ + int x; + int bar() { return x; } + takeDelegate2(&bar); // no error +} +void testClosure3() +{ + int x; + int bar() { return x; } + takeDelegate3(&bar); +} diff --git a/gcc/testsuite/gdc.test/compilable/warn3882.d b/gcc/testsuite/gdc.test/compilable/warn3882.d new file mode 100644 index 00000000000..bf824b8c035 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/warn3882.d @@ -0,0 +1,84 @@ +// PERMUTE_ARGS: -w -wi -debug +/* +TEST_OUTPUT: +--- +--- +*/ + +@safe pure nothrow void strictVoidReturn(T)(T x) {} +@safe pure nothrow void nonstrictVoidReturn(T)(ref T x) {} + +void test3882() +{ + int x = 3; + strictVoidReturn(x); + nonstrictVoidReturn(x); +} + +/******************************************/ +// 12619 + +extern (C) @system nothrow pure void* memcpy(void* s1, in void* s2, size_t n); +// -> weakly pure + +void test12619() pure +{ + ubyte[10] a, b; + debug memcpy(a.ptr, b.ptr, 5); // memcpy call should have side effect +} + +/******************************************/ +// 12760 + +struct S12760(T) +{ + T i; + this(T j) inout {} +} + +struct K12760 +{ + S12760!int nullable; + + this(int) + { + nullable = 0; // weak purity + } +} + +/******************************************/ +// 12909 + +int f12909(immutable(int[])[int] aa) pure nothrow +{ + //aa[0] = []; // fix for issue 13701 + return 0; +} + +void test12909() +{ + immutable(int[])[int] aa; + f12909(aa); + + // from 12910 + const(int[])[int] makeAA() { return null; } // to make r-value + makeAA().rehash(); +} + +/******************************************/ +// 13899 + +const struct Foo13899 +{ + int opApply(immutable int delegate(in ref int) pure nothrow dg) pure nothrow + { + return 1; + } +} + +void test13899() +{ + foreach (x; Foo13899()) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d b/gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d new file mode 100644 index 00000000000..397f36d0346 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/aacmp10381.d(12): Error: > is not defined for associative arrays +--- +*/ + +bool test10381() +{ + int[int] aa1 = [0: 1]; + int[int] aa2 = [0: 1]; + return aa1 > aa2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/b3841.d b/gcc/testsuite/gdc.test/fail_compilation/b3841.d new file mode 100644 index 00000000000..4a99e9a6963 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/b3841.d @@ -0,0 +1,78 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -w -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/b3841.d-mixin-31(31): Warning: char += float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: int += float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: long += double is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: char -= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: int -= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: long -= double is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: char *= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: int *= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: long *= double is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: char /= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: int /= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: long /= double is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: char %= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: int %= float is performing truncating conversion +fail_compilation/b3841.d-mixin-31(31): Warning: long %= double is performing truncating conversion +--- +*/ + + +void f(string op, LHS, RHS)() +{ + // pragma(msg, LHS, " += ", RHS); + LHS a; + RHS b; + mixin("a "~op~" b;"); +} + +template Ops(T...) +{ + alias Ops = T; +} + +void main() +{ + foreach (string op; Ops!("+=", "-=", "*=", "/=", "%=")) + { + // OK + f!(op, int, int)(); + f!(op, long, int)(); + f!(op, long, short)(); + f!(op, float, long)(); + f!(op, cfloat, long)(); + f!(op, double, float)(); + + // Should that really be OK ? + f!(op, short, int)(); + f!(op, float, double)(); + + // Not OK, truncating conversion. + f!(op, char, float)(); + f!(op, int, float)(); + f!(op, long, double)(); + } + + foreach (string op; Ops!("+=", "-=")) + { + // OK + f!(op, idouble, ifloat)(); + + // Should that really be OK ? + f!(op, ifloat, idouble)(); + } + + // OK + f!("^^=", int, int)(); + f!("^^=", long, int)(); + f!("^^=", long, short)(); + f!("^^=", float, long)(); + f!("^^=", double, float)(); + // Should that really be OK ? + f!("^^=", float, double)(); +} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug4283.d b/gcc/testsuite/gdc.test/fail_compilation/bug4283.d new file mode 100644 index 00000000000..6668371860e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/bug4283.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/bug4283.d(12): Error: declaration expected, not `}` +--- +*/ + +template Foo(bool b) { + static if (b) + enum bool Foo = 1; + else +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug5.d b/gcc/testsuite/gdc.test/fail_compilation/bug5.d new file mode 100644 index 00000000000..7878af75b54 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/bug5.d @@ -0,0 +1,8 @@ +// REQUIRED_ARGS: + +int test1() +{ + if (false) + return 0; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug5b.d b/gcc/testsuite/gdc.test/fail_compilation/bug5b.d new file mode 100644 index 00000000000..ca7ddd905e4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/bug5b.d @@ -0,0 +1,6 @@ +// REQUIRED_ARGS: + +int test1() +{ +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d b/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d new file mode 100644 index 00000000000..906b73c3fcc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d @@ -0,0 +1,13 @@ +// Bugzilla 8150: nothrow check doesn't work for constructor + +struct Foo +{ + this(int) nothrow + { + throw new Exception("something"); + } +} + +void main() { + Foo(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d b/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d new file mode 100644 index 00000000000..b861aeecc8b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d @@ -0,0 +1,13 @@ +// Bugzilla 8150: nothrow check doesn't work for constructor + +struct Foo +{ + this()(int) nothrow + { + throw new Exception("something"); + } +} + +void main() { + Foo(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8891.d b/gcc/testsuite/gdc.test/fail_compilation/bug8891.d new file mode 100644 index 00000000000..b58256eae2b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/bug8891.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/bug8891.d(21): Error: need 'this' for 'opCall' of type 'S(int n)' +--- +*/ + +struct S +{ + int value = 10; + S opCall(int n) // non-static + { + //printf("this.value = %d\n", this.value); // prints garbage! + S s; + s.value = n; + return s; + } +} +void main() +{ + S s = 10; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports1a.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports1a.d new file mode 100644 index 00000000000..a27ddea9591 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports1a.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -transition=checkimports -de +/* +TEST_OUTPUT: +--- +fail_compilation/checkimports1a.d(16): Deprecation: local import search method found struct imports.diag12598a.lines instead of variable checkimports1a.C.lines +--- +*/ + + +// new lookup + information +class C +{ + void f() + { + import imports.diag12598a; + lines ~= ""; + } + + string[] lines; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports1b.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports1b.d new file mode 100644 index 00000000000..60d3ae82b92 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports1b.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -transition=import -transition=checkimports +/* +TEST_OUTPUT: +--- +fail_compilation/checkimports1b.d(16): Deprecation: local import search method found struct imports.diag12598a.lines instead of variable checkimports1b.C.lines +fail_compilation/checkimports1b.d(16): Error: struct 'lines' is a type, not an lvalue +--- +*/ + +// old lookup + information +class C +{ + void f() + { + import imports.diag12598a; + lines ~= ""; + } + + string[] lines; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports1c.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports1c.d new file mode 100644 index 00000000000..f6587ef9219 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports1c.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -transition=checkimports -transition=import +/* +TEST_OUTPUT: +--- +fail_compilation/checkimports1c.d(16): Deprecation: local import search method found struct imports.diag12598a.lines instead of variable checkimports1c.C.lines +fail_compilation/checkimports1c.d(16): Error: struct 'lines' is a type, not an lvalue +--- +*/ + +// old lookup + information (the order of switches is reverse) +class C +{ + void f() + { + import imports.diag12598a; + lines ~= ""; + } + + string[] lines; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d new file mode 100644 index 00000000000..567a30844c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d @@ -0,0 +1,37 @@ +// REQUIRED_ARGS: -transition=checkimports +/* +TEST_OUTPUT: +--- +fail_compilation/checkimports2a.d(26): Deprecation: local import search method found variable imports.imp2.X instead of variable checkimports2a.X +fail_compilation/checkimports2a.d(32): Deprecation: local import search method found variable imports.imp2.X instead of nothing +fail_compilation/checkimports2a.d(32): Error: no property 'X' for type 'checkimports2a.B' +fail_compilation/checkimports2a.d(32): while evaluating: `static assert((B).X == 0)` +fail_compilation/checkimports2a.d(33): Deprecation: local import search method found variable imports.imp2.Y instead of nothing +fail_compilation/checkimports2a.d(33): Error: no property 'Y' for type 'checkimports2a.B' +fail_compilation/checkimports2a.d(33): while evaluating: `static assert((B).Y == 2)` +fail_compilation/checkimports2a.d(35): Deprecation: local import search method found variable imports.imp2.X instead of variable checkimports2a.X +fail_compilation/checkimports2a.d(36): Deprecation: local import search method found variable imports.imp2.Y instead of variable imports.imp1.Y +--- +*/ + +// new lookup + information + +import imports.imp1; + +enum X = 0; + +class B +{ + import imports.imp2; + static assert(X == 0); // imp2.X --> .X + int[Y] aa; // imp2.Y +} + +class C : B +{ + static assert(B.X == 0); // imp2.X --> error + static assert(B.Y == 2); // imp2.Y --> error + + static assert(X == 0); // imp2.X --> .X + static assert(Y == 1); // imp2.Y --> imp1.Y +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d new file mode 100644 index 00000000000..4f52521dd26 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d @@ -0,0 +1,38 @@ +// REQUIRED_ARGS: -transition=import -transition=checkimports -de +/* +TEST_OUTPUT: +--- +fail_compilation/checkimports2b.d(27): Deprecation: local import search method found variable imports.imp2.X instead of variable checkimports2b.X +fail_compilation/checkimports2b.d(27): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2b.d(33): Deprecation: local import search method found variable imports.imp2.X instead of nothing +fail_compilation/checkimports2b.d(33): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2b.d(34): Deprecation: local import search method found variable imports.imp2.Y instead of nothing +fail_compilation/checkimports2b.d(34): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2b.d(36): Deprecation: local import search method found variable imports.imp2.X instead of variable checkimports2b.X +fail_compilation/checkimports2b.d(36): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2b.d(37): Deprecation: local import search method found variable imports.imp2.Y instead of variable imports.imp1.Y +fail_compilation/checkimports2b.d(37): while evaluating: `static assert(2 == 2)` +--- +*/ + +// old lookup + information + +import imports.imp1; + +enum X = 0; + +class B +{ + import imports.imp2; + static assert(X == 2); // imp2.X --> .X (information) + int[Y] aa; // imp2.Y +} + +class C : B +{ + static assert(B.X == 2); // imp2.X --> error (keep old lookup rule) + static assert(B.Y == 2); // imp2.Y --> error (keep old lookup rule) + + static assert(X == 2); // imp2.X --> .X (information) + static assert(Y == 2); // imp2.Y --> imp1.Y (information) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d new file mode 100644 index 00000000000..f56da9c013b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d @@ -0,0 +1,39 @@ +// REQUIRED_ARGS: -transition=checkimports -transition=import -de +/* +TEST_OUTPUT: +--- + +fail_compilation/checkimports2c.d(28): Deprecation: local import search method found variable imports.imp2.X instead of variable checkimports2c.X +fail_compilation/checkimports2c.d(28): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2c.d(34): Deprecation: local import search method found variable imports.imp2.X instead of nothing +fail_compilation/checkimports2c.d(34): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2c.d(35): Deprecation: local import search method found variable imports.imp2.Y instead of nothing +fail_compilation/checkimports2c.d(35): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2c.d(37): Deprecation: local import search method found variable imports.imp2.X instead of variable checkimports2c.X +fail_compilation/checkimports2c.d(37): while evaluating: `static assert(2 == 2)` +fail_compilation/checkimports2c.d(38): Deprecation: local import search method found variable imports.imp2.Y instead of variable imports.imp1.Y +fail_compilation/checkimports2c.d(38): while evaluating: `static assert(2 == 2)` +--- +*/ + +// old lookup + information (the order of switches is reverse) + +import imports.imp1; + +enum X = 0; + +class B +{ + import imports.imp2; + static assert(X == 2); // imp2.X --> .X (information) + int[Y] aa; // imp2.Y +} + +class C : B +{ + static assert(B.X == 2); // imp2.X --> error (keep old lookup rule) + static assert(B.Y == 2); // imp2.Y --> error (keep old lookup rule) + + static assert(X == 2); // imp2.X --> .X (information) + static assert(Y == 2); // imp2.Y --> imp1.Y (information) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports3.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports3.d new file mode 100644 index 00000000000..e9d44a71b26 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports3.d @@ -0,0 +1,15 @@ +/* +REQUIRED_ARGS: -transition=checkimports -de +TEST_OUTPUT: +--- +fail_compilation/checkimports3.d(14): Deprecation: local import search method found overloadset checkimports3.foo (3 overloads) instead of overloadset checkimports3.foo (2 overloads) +--- +*/ +import imports.checkimports3a; +import imports.checkimports3b; +import imports.checkimports3c; + +void test() +{ + foo(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/circ10280.d b/gcc/testsuite/gdc.test/fail_compilation/circ10280.d new file mode 100644 index 00000000000..b839b9f4702 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/circ10280.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/circ10280.d(11): Error: circular initialization of variable 'circ10280.q10280' +fail_compilation/circ10280.d(10): called from here: foo10280() +--- +*/ +// 10280 + +const int q10280 = foo10280(); +int foo10280() { return q10280; } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/class1.d b/gcc/testsuite/gdc.test/fail_compilation/class1.d new file mode 100644 index 00000000000..261652c6412 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/class1.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/class1.d(11): Error: class class1.C identity assignment operator overload is illegal +--- +*/ + +class C +{ + // Non-templated identity opAssign + void opAssign(C rhs){} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/class2.d b/gcc/testsuite/gdc.test/fail_compilation/class2.d new file mode 100644 index 00000000000..f4894ee7ba3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/class2.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/class2.d(11): Error: class class2.C identity assignment operator overload is illegal +--- +*/ + +class C +{ + // Templated identity opAssign + void opAssign(T)(T rhs){} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/commaexp.d b/gcc/testsuite/gdc.test/fail_compilation/commaexp.d new file mode 100644 index 00000000000..3296046e234 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/commaexp.d @@ -0,0 +1,43 @@ +/* REQUIRED_ARGS: -o- -de +TEST_OUTPUT: +--- +fail_compilation/commaexp.d(24): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/commaexp.d(36): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/commaexp.d(37): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/commaexp.d(38): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/commaexp.d(39): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/commaexp.d(41): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/commaexp.d(42): Deprecation: Using the result of a comma expression is deprecated +--- +*/ + +class Entry {} +class MyContainerClass { bool append (Entry) { return false; } } + +int main () { + bool ok; + size_t aggr; + MyContainerClass mc; + + // Bug 15997 + enum WINHTTP_ERROR_BASE = 4200; + enum ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED = (WINHTTP_ERROR_BASE, + 44); + + // OK + for (size_t i; i < 5; ++i, i += 1) {} + for (size_t i; i < 5; ++i, i += 1, i++) {} + if (!mc) + mc = new MyContainerClass, mc.append(new Entry); + if (Object o = cast(Object)mc) {} // Lowering + ok = true, mc.append(new Entry); + assert(ok); + + // NOPE + for (size_t i; i < 5; ++i, i += (i++, 1)) {} + for (; aggr++, aggr > 5;) {} + if (Object o = (ok = true, null)) {} + ok = (true, mc.append(new Entry)); + assert(!ok); + ok = true, (ok = (true, false)); + return 42, 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/cppeh1.d b/gcc/testsuite/gdc.test/fail_compilation/cppeh1.d new file mode 100644 index 00000000000..e60368c1506 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/cppeh1.d @@ -0,0 +1,30 @@ +// DISABLED: win32 win64 +/* +TEST_OUTPUT: +--- +fail_compilation/cppeh1.d(26): Error: cannot catch C++ class objects in @safe code +--- +*/ + +version (Windows) static assert(0, "This test should not run on this platform"); + +extern (C++, std) +{ + class exception { } +} + +@safe: +void bar(); +void abc(); + +void foo() +{ + try + { + bar(); + } + catch (std.exception e) + { + abc(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/cppeh2.d b/gcc/testsuite/gdc.test/fail_compilation/cppeh2.d new file mode 100644 index 00000000000..1d3ddc67e7f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/cppeh2.d @@ -0,0 +1,33 @@ +// DISABLED: win32 win64 +/* +TEST_OUTPUT: +--- +fail_compilation/cppeh2.d(21): Error: cannot mix catching D and C++ exceptions in the same try-catch +--- +*/ + +version(Windows) static assert(0, "This test should not run on this platform"); + +extern (C++, std) +{ + class exception { } +} + +void bar(); +void abc(); + +void foo() +{ + try + { + bar(); + } + catch (std.exception e) + { + abc(); + } + catch (Exception e) + { + abc(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d new file mode 100644 index 00000000000..22b6dbb6c44 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d @@ -0,0 +1,36 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe10989.d(11): Error: uncaught CTFE exception object.Exception("abc"c) +fail_compilation/ctfe10989.d(14): called from here: throwing() +fail_compilation/ctfe10989.d(14): while evaluating: `static assert(throwing())` +--- +*/ +int throwing() +{ + throw new Exception(['a', 'b', 'c']); + return 0; +} +static assert(throwing()); + +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe10989.d(33): Error: uncaught CTFE exception object.Exception("abc"c) +fail_compilation/ctfe10989.d(36): called from here: throwing2() +fail_compilation/ctfe10989.d(36): while evaluating: `static assert(throwing2())` +--- +*/ +int throwing2() +{ + string msg = "abc"; + + char[] arr; + arr.length = msg.length; + arr = arr[0 .. $]; + arr[] = msg; + + throw new Exception(cast(string)arr); + return 0; +} +static assert(throwing2()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d new file mode 100644 index 00000000000..ca424956c78 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe10995.d(19): Error: cannot read uninitialized variable a in CTFE +fail_compilation/ctfe10995.d(25): Error: cannot read uninitialized variable a in CTFE +--- +*/ +struct T +{ + short a = void; +} + +T foo() +{ + auto t = T.init; + return t; +} + +enum i = foo().a; + +struct T2 +{ + short a = void; +} +enum i2 = T2.init.a; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d new file mode 100644 index 00000000000..f7b25778893 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d @@ -0,0 +1,52 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe11467.d(15): Error: overlapping slice assignment [0..4] = [1..5] +fail_compilation/ctfe11467.d(24): called from here: test11467a() +fail_compilation/ctfe11467.d(24): while evaluating: `static assert(test11467a())` +fail_compilation/ctfe11467.d(21): Error: overlapping slice assignment [1..5] = [0..4] +fail_compilation/ctfe11467.d(25): called from here: test11467b() +fail_compilation/ctfe11467.d(25): while evaluating: `static assert(test11467b())` +--- +*/ +int test11467a() +{ + auto a = [0, 1, 2, 3, 4]; + a[0 .. 4] = a[1 .. 5]; + return 1; +} +int test11467b() +{ + auto a = [0, 1, 2, 3, 4]; + a[1 .. 5] = a[0 .. 4]; + return 1; +} +static assert(test11467a()); +static assert(test11467b()); + +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe11467.d(41): Error: overlapping slice assignment [0..4] = [1..5] +fail_compilation/ctfe11467.d(50): called from here: test11467c() +fail_compilation/ctfe11467.d(50): while evaluating: `static assert(test11467c())` +fail_compilation/ctfe11467.d(47): Error: overlapping slice assignment [1..5] = [0..4] +fail_compilation/ctfe11467.d(51): called from here: test11467d() +fail_compilation/ctfe11467.d(51): while evaluating: `static assert(test11467d())` +--- +*/ +int test11467c() +{ + auto a = "abcde".dup; + a[0 .. 4] = a[1 .. 5]; + return 1; +} +int test11467d() +{ + auto a = "abcde".dup; + a[1 .. 5] = a[0 .. 4]; + return 1; +} +static assert(test11467c()); +static assert(test11467d()); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d new file mode 100644 index 00000000000..b7ab79e507f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe13612.d(15): Error: function ctfe13612.S.recurse CTFE recursion limit exceeded +fail_compilation/ctfe13612.d(20): called from here: s.recurse() +fail_compilation/ctfe13612.d(15): 1000 recursive calls to function recurse +fail_compilation/ctfe13612.d(23): called from here: (new S).recurse() +fail_compilation/ctfe13612.d(23): while evaluating: `static assert((new S).recurse())` +--- +*/ + +class S +{ + int x; + int recurse() + { + S s; + assert(!x); // Error: class 'this' is null and cannot be dereferenced + s = new S(); + return s.recurse(); + } +} +static assert(new S().recurse()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d new file mode 100644 index 00000000000..511f7553c2d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe14207.d(13): Error: cannot convert &immutable(ulong) to ubyte[8]* at compile time +fail_compilation/ctfe14207.d(18): called from here: nativeToBigEndian() +fail_compilation/ctfe14207.d(22): called from here: digest() +--- +*/ + +ubyte[8] nativeToBigEndian() +{ + immutable ulong res = 1; + return *cast(ubyte[8]*) &res; +} + +auto digest() +{ + ubyte[8] bits = nativeToBigEndian(); + return bits; +} + +enum h = digest(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d new file mode 100644 index 00000000000..9106d3daa5b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe14465.d(19): Error: uncaught CTFE exception ctfe14465.E("message") +fail_compilation/ctfe14465.d(22): called from here: foo() +fail_compilation/ctfe14465.d(22): while evaluating: `static assert(foo())` +--- +*/ +class E : Exception +{ + this(string msg) + { + super(msg); + } +} + +bool foo() +{ + throw new E("message"); +} + +static assert(foo()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d new file mode 100644 index 00000000000..78e0891f3d6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ctfe14731.d(16): Error: cannot implicitly convert expression `["a b"]` of type `string[]` to `string` +fail_compilation/ctfe14731.d(17): Error: cannot implicitly convert expression `split("a b")` of type `string[]` to `string` +--- +*/ + +string[] split(string a) +{ + return [a]; +} + +void main() +{ + enum string list1 = "a b".split(); + string list2 = "a b".split(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/cwords.d b/gcc/testsuite/gdc.test/fail_compilation/cwords.d new file mode 100644 index 00000000000..bd2f944080a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/cwords.d @@ -0,0 +1,17 @@ +/* TEST_OUTPUT: +--- +fail_compilation/cwords.d(13): Error: undefined identifier `FALSE`, did you mean `false`? +fail_compilation/cwords.d(14): Error: undefined identifier `TRUE`, did you mean `true`? +fail_compilation/cwords.d(15): Error: undefined identifier `NULL`, did you mean `null`? +fail_compilation/cwords.d(16): Error: undefined identifier `unsigned`, did you mean `uint`? +--- +*/ + + +void foo() +{ + bool a = FALSE; + bool b = TRUE; + int* p = NULL; + unsigned u; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/depmsg.d b/gcc/testsuite/gdc.test/fail_compilation/depmsg.d new file mode 100644 index 00000000000..186576a5473 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/depmsg.d @@ -0,0 +1,106 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/depmsg.d(40): Deprecation: struct depmsg.main.Inner.A is deprecated - With message! +fail_compilation/depmsg.d(40): Deprecation: struct depmsg.main.Inner.A is deprecated - With message! +fail_compilation/depmsg.d(41): Deprecation: class depmsg.main.Inner.B is deprecated - With message! +fail_compilation/depmsg.d(41): Deprecation: class depmsg.main.Inner.B is deprecated - With message! +fail_compilation/depmsg.d(42): Deprecation: interface depmsg.main.Inner.C is deprecated - With message! +fail_compilation/depmsg.d(42): Deprecation: interface depmsg.main.Inner.C is deprecated - With message! +fail_compilation/depmsg.d(43): Deprecation: union depmsg.main.Inner.D is deprecated - With message! +fail_compilation/depmsg.d(43): Deprecation: union depmsg.main.Inner.D is deprecated - With message! +fail_compilation/depmsg.d(44): Deprecation: enum depmsg.main.Inner.E is deprecated - With message! +fail_compilation/depmsg.d(44): Deprecation: enum depmsg.main.Inner.E is deprecated - With message! +fail_compilation/depmsg.d(46): Deprecation: alias depmsg.main.Inner.G is deprecated - With message! +fail_compilation/depmsg.d(47): Deprecation: variable depmsg.main.Inner.H is deprecated - With message! +fail_compilation/depmsg.d(48): Deprecation: class depmsg.main.Inner.I!().I is deprecated - With message! +--- +*/ + +void main() +{ + class Inner + { + deprecated("With message!") + { + struct A { } + class B { } + interface C { } + union D { } + enum E { e }; + //typedef int F; + alias int G; + static int H; + template I() { class I {} } + } + } + with(Inner) + { + A a; + B b; + C c; + D d; + E e; + //F f; + G g; + auto h = H; + I!() i; + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/depmsg.d(94): Deprecation: function depmsg.test12954.Foo.bar1 is deprecated - [C] Use Foo.bar42 instead +fail_compilation/depmsg.d(95): Deprecation: function depmsg.test12954.Foo.bar2 is deprecated - [E] Use Foo.bar42 instead +fail_compilation/depmsg.d(96): Deprecation: function depmsg.test12954.Foo.bar3 is deprecated - [S] Use Foo.bar42 instead +fail_compilation/depmsg.d(97): Deprecation: function depmsg.test12954.Foo.bar4 is deprecated - [F] Use Foo.bar42 instead +fail_compilation/depmsg.d(98): Deprecation: variable depmsg.test12954.Foo.v2 is deprecated - Forward reference +fail_compilation/depmsg.d(105): Deprecation: class depmsg.test12954.Obsolete is deprecated +fail_compilation/depmsg.d(105): Deprecation: function depmsg.test12954.Obsolete.obs is deprecated - Function is obsolete +--- +*/ +void test12954() +{ + struct Foo + { + enum DeprecatedReasonEnum = "[E] Use Foo.bar42 instead"; + static const DeprecatedReasonStatic = "[S] Use Foo.bar42 instead"; + static immutable DeprecatedReasonFunc = reason("Foo.bar42"); + + static string reason (string name) + { + return "[F] Use " ~ name ~ " instead"; + } + + deprecated("[C] Use " ~ `Foo.bar42 instead`) + void bar1 () {} + + deprecated(DeprecatedReasonEnum) + void bar2 () {} + + deprecated(DeprecatedReasonStatic) + void bar3 () {} + + deprecated(DeprecatedReasonFunc) + void bar4 () {} + + deprecated(Forward ~ Reference) int v2 = 2; + enum Forward = "Forward ", Reference = "reference"; + } + + Foo f; + f.bar1; + f.bar2; + f.bar3; + f.bar4; + assert(f.v2 == 2); + + deprecated class Obsolete + { + deprecated("Function is obsolete") void obs() {} + } + + (new Obsolete).obs(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d b/gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d new file mode 100644 index 00000000000..1a2b9f89d39 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/depmsg15814.d(9): Deprecation: function depmsg15814.get15814 is deprecated - bug15814 +--- +*/ +deprecated("bug15814") int get15814() { return 0; } +enum val15814 = get15814(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d b/gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d new file mode 100644 index 00000000000..72abbd77306 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d @@ -0,0 +1,23 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/depmsg15815.d(23): Deprecation: alias depmsg15815.Alias!(const(Foo)).Alias is deprecated - message +Foo +--- +*/ + +template Unqual(T) +{ + static if (is(T U == const U)) alias Unqual = U; + else alias Unqual = T; +} + +deprecated("message") +template Alias(T) +{ + alias Alias = Unqual!T; +} + +struct Foo {} +pragma(msg, Alias!(const(Foo))); diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecate12979a.d b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979a.d new file mode 100644 index 00000000000..5b2cd56c9f9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979a.d @@ -0,0 +1,18 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecate12979a.d(14): Deprecation: asm statement is assumed to throw - mark it with `nothrow` if it does not +fail_compilation/deprecate12979a.d(12): Error: nothrow function `deprecate12979a.foo` may throw +--- +*/ + +void foo() nothrow +{ + asm + { + ret; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecate12979b.d b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979b.d new file mode 100644 index 00000000000..0d675cb558f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979b.d @@ -0,0 +1,17 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecate12979b.d(13): Deprecation: asm statement is assumed to be impure - mark it with 'pure' if it is not +--- +*/ + +void foo() pure +{ + asm + { + ret; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecate12979c.d b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979c.d new file mode 100644 index 00000000000..782700469cd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979c.d @@ -0,0 +1,17 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecate12979c.d(13): Deprecation: asm statement is assumed to use the GC - mark it with '@nogc' if it does not +--- +*/ + +void foo() @nogc +{ + asm + { + ret; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecate12979d.d b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979d.d new file mode 100644 index 00000000000..afff5671027 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecate12979d.d @@ -0,0 +1,16 @@ +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecate12979d.d(12): Error: asm statement is assumed to be @system - mark it with '@trusted' if it is not +--- +*/ + +void foo() @safe +{ + asm + { + ret; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d b/gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d new file mode 100644 index 00000000000..4a03a6fa41b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecate1553.d(19): Deprecation: cannot use foreach_reverse with a delegate +--- +*/ + +struct S +{ + int dg(int delegate(ref int a)) { return 0; } +} + +void main() +{ + S s; + foreach_reverse(a; &s.dg) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d b/gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d new file mode 100644 index 00000000000..07b9527e087 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecated6760.d(13): Deprecation: function deprecated6760.Foo.opEquals overridden functions cannot be annotated @disable +fail_compilation/deprecated6760.d(18): Deprecation: function deprecated6760.Bar.opEquals deprecated functions cannot be annotated @disable +--- +*/ + +class Foo +{ + @disable override bool opEquals(Object); +} + +class Bar +{ + deprecated override bool opEquals(Object); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10089.d b/gcc/testsuite/gdc.test/fail_compilation/diag10089.d new file mode 100644 index 00000000000..be0fddcad34 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10089.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10089.d(15): Error: undefined identifier `chunks` in package `imports` +fail_compilation/diag10089.d(17): Error: template Foo() does not have property 'chunks' +--- +*/ + +import imports.diag10089a, imports.diag10089b; + +template Foo() {} + +void main() +{ + imports.chunks("abcdef", 2); + + Foo.chunks("abcdef", 2); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10099.d b/gcc/testsuite/gdc.test/fail_compilation/diag10099.d new file mode 100644 index 00000000000..a26ca85e19d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10099.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10099.d(15): Error: variable diag10099.main.s default construction is disabled for type S +--- +*/ + +struct S +{ + @disable this(); +} + +void main() +{ + S s; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10141.d b/gcc/testsuite/gdc.test/fail_compilation/diag10141.d new file mode 100644 index 00000000000..e9ca913767f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10141.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10141.d(9): Error: module imports.diag10141a import 'unexisting_symbol' not found +--- +*/ + +import imports.diag10141a; +import imports.diag10141a : unexisting_symbol; + +Tuple!(int) fun() +{ + return Tuple!(int).init; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10169.d b/gcc/testsuite/gdc.test/fail_compilation/diag10169.d new file mode 100644 index 00000000000..2a9714ddf1b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10169.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10169.d(12): Deprecation: imports.a10169.B.x is not visible from module diag10169 +fail_compilation/diag10169.d(12): Error: struct imports.a10169.B member `x` is not accessible +--- +*/ +import imports.a10169; + +void main() +{ + auto a = B.init.x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10221.d b/gcc/testsuite/gdc.test/fail_compilation/diag10221.d new file mode 100644 index 00000000000..14338ec4a46 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10221.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10221.d(10): Error: cannot implicitly convert expression `256` of type `int` to `ubyte` +--- +*/ + +void main() +{ + foreach(ref ubyte i; 0..256) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10221a.d b/gcc/testsuite/gdc.test/fail_compilation/diag10221a.d new file mode 100644 index 00000000000..32b1f07d902 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10221a.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10221a.d(10): Error: cannot implicitly convert expression `257` of type `int` to `ubyte` +--- +*/ + +void main() +{ + foreach(ubyte i; 0..257) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d new file mode 100644 index 00000000000..a11e120fa8e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10319.d(25): Error: pure function 'D main' cannot call impure function 'diag10319.foo' +fail_compilation/diag10319.d(25): Error: @safe function 'D main' cannot call @system function 'diag10319.foo' +fail_compilation/diag10319.d(26): Error: pure function 'D main' cannot call impure function 'diag10319.bar!int.bar' +fail_compilation/diag10319.d(26): Error: @safe function 'D main' cannot call @system function 'diag10319.bar!int.bar' +fail_compilation/diag10319.d(25): Error: function `diag10319.foo` is not nothrow +fail_compilation/diag10319.d(26): Error: function `diag10319.bar!int.bar` is not nothrow +fail_compilation/diag10319.d(23): Error: nothrow function `D main` may throw +--- +*/ + +void foo() {} + +void bar(T)() +{ + static int g; g = 10; // impure + int x; auto p = &x; // system + throw new Exception(""); // may throw +} + +@safe pure nothrow void main() // L23 +{ + foo(); // L25 + bar!int(); // L26 +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10327.d b/gcc/testsuite/gdc.test/fail_compilation/diag10327.d new file mode 100644 index 00000000000..1d163c770ea --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10327.d @@ -0,0 +1 @@ +import imports.test10327; // package.d missing diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10359.d b/gcc/testsuite/gdc.test/fail_compilation/diag10359.d new file mode 100644 index 00000000000..142cec98e0c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10359.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10359.d(10): Error: pointer slicing not allowed in safe functions +--- +*/ + +void foo(int* p) @safe +{ + auto a = p[0 .. 10]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10405.d b/gcc/testsuite/gdc.test/fail_compilation/diag10405.d new file mode 100644 index 00000000000..c80c821ebd0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10405.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10405.d(10): Error: cannot return non-void from void function +--- +*/ + +void main() +{ + return 10; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d new file mode 100644 index 00000000000..a92b7a474ff --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d @@ -0,0 +1,40 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10415.d(36): Error: none of the overloads of 'x' are callable using argument types (int) const, candidates are: +fail_compilation/diag10415.d(13): diag10415.C.x() +fail_compilation/diag10415.d(18): diag10415.C.x(int _param_0) +fail_compilation/diag10415.d(39): Error: d.x is not an lvalue +--- +*/ + +class C +{ + @property int x() const + { + return 0; + } + + @property void x(int) + { + } +} + +template AddProp() { @property int x() { return 1; } } +template AddFunc() { void x(int, int) {} } + +class D +{ + // overloadset + mixin AddProp; + mixin AddFunc; +} + +void main() +{ + const c = new C(); + c.x = 1; + + auto d = new D(); + d.x = 1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10688.d b/gcc/testsuite/gdc.test/fail_compilation/diag10688.d new file mode 100644 index 00000000000..70db7f96fe0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10688.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10688.d(12): Error: function diag10688.Bar.foo private method is not virtual and cannot override +fail_compilation/diag10688.d(14): Error: function diag10688.Bar.bar package method is not virtual and cannot override +--- +*/ + +class Bar +{ +private: + override void foo() { } +package: + override void bar() { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10768.d b/gcc/testsuite/gdc.test/fail_compilation/diag10768.d new file mode 100644 index 00000000000..03b18a10689 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10768.d @@ -0,0 +1,42 @@ +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +fail_compilation/diag10768.d(36): Error: cannot implicitly override base class method diag10768.Frop.frop with diag10768.Foo.frop; add 'override' attribute +--- +*/ + +struct CirBuff(T) +{ + import std.traits: isArray; + CirBuff!T opAssign(R)(R) if (isArray!R) + {} + + T[] toArray() + { + T[] ret; // = new T[this.length]; + return ret; + } + alias toArray this; +} + +class Bar(T=int) +{ + CirBuff!T _bar; +} + +class Once +{ + Bar!Foo _foobar; +} + +class Foo : Frop +{ + // override + public int frop() { return 1; } +} + +class Frop +{ + public int frop() { return 0; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10783.d b/gcc/testsuite/gdc.test/fail_compilation/diag10783.d new file mode 100644 index 00000000000..d74a66d3cee --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10783.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10783.d(14): Error: no property 'type' for type 'Event' +fail_compilation/diag10783.d(14): Error: undefined identifier `En` +--- +*/ + +struct Event { } + +void main() +{ + Event event; + switch (event.type) with (En) + { + default: + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10792.d b/gcc/testsuite/gdc.test/fail_compilation/diag10792.d new file mode 100644 index 00000000000..d54e50fee5a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10792.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10792.d(9): Error: semicolon expected following auto declaration, not `EOF` +--- +*/ + +enum isPred(T) = asdf diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d new file mode 100644 index 00000000000..627fe825b53 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10805.d(11): Error: delimited string must end in FOO" +fail_compilation/diag10805.d(13): Error: unterminated string constant starting at fail_compilation/diag10805.d(13) +fail_compilation/diag10805.d(13): Deprecation: Implicit string concatenation is deprecated, use "" ~ "" instead +fail_compilation/diag10805.d(14): Error: semicolon expected following auto declaration, not `EOF` +--- +*/ + +enum s = q"FOO +FOO +"; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d new file mode 100644 index 00000000000..62968f28e43 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d @@ -0,0 +1,90 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10862.d(28): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(29): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(30): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(31): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(32): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(34): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(35): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(36): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(37): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(39): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(40): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(41): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(42): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(44): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(45): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(46): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(47): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(49): Error: undefined identifier `semanticError` +--- +*/ +void test1() +{ + int a, b; + + if (a = b) {} + if ((a = b) = 0) {} + if ((a = b) = (a = b)) {} + if (a = 0, b = 0) {} // Bugzilla 15384 + if (auto x = a = b) {} // this is error, today + + while (a = b) {} + while ((a = b) = 0) {} + while ((a = b) = (a = b)) {} + while (a = 0, b = 0) {} // Bugzilla 15384 + + do {} while (a = b); + do {} while ((a = b) = 0); + do {} while ((a = b) = (a = b)); + do {} while (a = 0, b = 0); // Bugzilla 15384 + + for (; a = b; ) {} + for (; (a = b) = 0; ) {} + for (; (a = b) = (a = b); ) {} + for (; a = 0, b = 0; ) {} // Bugzilla 15384 + + semanticError; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag10862.d(74): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d(77): Error: assignment cannot be used as a condition, perhaps `==` was meant? +fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps == was meant? +fail_compilation/diag10862.d-mixin-81(81): Error: assignment cannot be used as a condition, perhaps == was meant? +fail_compilation/diag10862.d-mixin-82(82): Error: assignment cannot be used as a condition, perhaps == was meant? +fail_compilation/diag10862.d-mixin-83(83): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/diag10862.d-mixin-83(83): Error: assignment cannot be used as a condition, perhaps == was meant? +fail_compilation/diag10862.d-mixin-86(86): Error: a + b is not an lvalue +fail_compilation/diag10862.d-mixin-87(87): Error: undefined identifier `c` +fail_compilation/diag10862.d(89): Error: undefined identifier `semanticError` +--- +*/ +void test2() +{ + int a, b; + + // (a + b) cannot be an assignment target. + // However checkAssignAsCondition specilatively rerites it to EqualExp, + // then the pointless error "is not an lvalue" would not happen. + if (a + b = a * b) {} + + // The suggestion error masks "undefined identifier" error + if (a = undefinedIdentifier) {} + + // If the condition is a mixin expression + if (mixin("a = b")) {} + if (mixin("(a = b) = 0")) {} + if (mixin("(a = b) = (a = b)")) {} + if (mixin("a = 0, b = 0")) {} + if (auto x = mixin("a = b")) {} // Note: no error + + if (mixin("a + b = a * b")) {} // Note: "a + b is not an lvalue" + if (mixin("a = c")) {} + + semanticError; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10926.d b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d new file mode 100644 index 00000000000..bd590ba2151 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10926.d(11): Error: cast(const(int)[])c is not an lvalue +--- +*/ + +void main() { + const(int)[] a, b; + int[] c, d; + (true ? a : c) ~= 20; // line 6, Error: a is not an lvalue +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10984.d b/gcc/testsuite/gdc.test/fail_compilation/diag10984.d new file mode 100644 index 00000000000..33e0eaf25d9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10984.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag10984.d(11): Error: static function diag10984.f.n cannot access frame of function diag10984.f +--- +*/ + +void f() +{ + int x; + static void n() { x++; } +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11078.d b/gcc/testsuite/gdc.test/fail_compilation/diag11078.d new file mode 100644 index 00000000000..7507875c947 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11078.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11078.d(19): Error: none of the overloads of 'value' are callable using argument types (double), candidates are: +fail_compilation/diag11078.d(12): diag11078.S1.value() +fail_compilation/diag11078.d(13): diag11078.S1.value(int n) +--- +*/ + +struct S1 +{ + @property int value() { return 1; } + @property void value(int n) { } +} + +void main() +{ + S1 s1; + s1.value = 1.0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11132.d b/gcc/testsuite/gdc.test/fail_compilation/diag11132.d new file mode 100644 index 00000000000..74062c2dc2e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11132.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11132.d(22): Error: overlapping initialization for field a and b +--- +*/ + +struct S +{ + int x; + union + { + int a; + int b; + } + + int z; +} + +void main() +{ + S s = { 1, 2, 3 }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d new file mode 100644 index 00000000000..ebefa4dc6af --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11198.d(11): Error: version conditions can only be declared at module scope +fail_compilation/diag11198.d(12): Error: debug conditions can only be declared at module scope +--- +*/ + +void main() +{ + version = blah; + debug = blah; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11423.d b/gcc/testsuite/gdc.test/fail_compilation/diag11423.d new file mode 100644 index 00000000000..b13588ee0c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11423.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11423.d(9): Error: undefined identifier `Foo` +--- +*/ +void main() +{ + auto foo = new shared Foo(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11425.d b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d new file mode 100644 index 00000000000..16c99cc4116 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11425.d(13): Error: variable x is shadowing variable diag11425.main.x +--- +*/ + +void main() +{ + int x; + + { + int x = 1; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11727.d b/gcc/testsuite/gdc.test/fail_compilation/diag11727.d new file mode 100644 index 00000000000..907c9bb404d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11727.d @@ -0,0 +1,39 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11727.d(10): Error: type n is not an expression +--- +*/ +auto returnEnum() +{ + enum n; + return n; +} +void main() +{ + assert(returnEnum() == 0); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag11727.d(26): Error: type void is not an expression +--- +*/ +auto returnVoid() +{ + alias v = void; + return v; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag11727.d(38): Error: template t() has no type +--- +*/ +auto returnTemplate() +{ + template t() {} + return t; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11756.d b/gcc/testsuite/gdc.test/fail_compilation/diag11756.d new file mode 100644 index 00000000000..3d56b99564d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11756.d @@ -0,0 +1,39 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11756.d(15): Error: cannot read uninitialized variable cnt in CTFE +fail_compilation/diag11756.d(34): called from here: foo.ptr2.opAssign(Ptr(& n)) +fail_compilation/diag11756.d(39): called from here: test() +fail_compilation/diag11756.d(39): while evaluating: `static assert(test())` +--- +*/ + +struct Ptr +{ + void opAssign(Ptr other) + { + (*cnt)--; // error + cnt = other.cnt; + (*cnt)++; + } + size_t *cnt; +} + +union Foo +{ + size_t *ptr1; + Ptr ptr2; +} + +bool test() +{ + Foo foo; + size_t cnt = 1; + foo.ptr1 = &cnt; + size_t n; + foo.ptr2 = Ptr(&n); + assert(cnt == 0); + + return true; +} +static assert(test()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11759.d b/gcc/testsuite/gdc.test/fail_compilation/diag11759.d new file mode 100644 index 00000000000..e0b7b864c13 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11759.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11759.d(8): Error: lower case integer suffix 'l' is not allowed. Please use 'L' instead +--- +*/ + +ulong x = 123ul; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11769.d b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d new file mode 100644 index 00000000000..bfe4e1b4c8d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11769.d(18): Error: diag11769.foo!string.bar called with argument types (string) matches both: +fail_compilation/diag11769.d(13): diag11769.foo!string.bar(wstring _param_0) +and: +fail_compilation/diag11769.d(14): diag11769.foo!string.bar(dstring _param_0) +--- +*/ + +template foo(T) +{ + void bar(wstring) {} + void bar(dstring) {} +} +void main() +{ + foo!string.bar("abc"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11819a.d b/gcc/testsuite/gdc.test/fail_compilation/diag11819a.d new file mode 100644 index 00000000000..3cad44d72b5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11819a.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11819a.d(30): Error: unrecognized trait `DoesNotExist` +fail_compilation/diag11819a.d(31): Error: unrecognized trait `IsAbstractClass`, did you mean `isAbstractClass`? +fail_compilation/diag11819a.d(32): Error: unrecognized trait `IsArithmetic`, did you mean `isArithmetic`? +fail_compilation/diag11819a.d(33): Error: unrecognized trait `IsAssociativeArray`, did you mean `isAssociativeArray`? +fail_compilation/diag11819a.d(34): Error: unrecognized trait `IsFinalClass`, did you mean `isFinalClass`? +fail_compilation/diag11819a.d(35): Error: unrecognized trait `IsPOD`, did you mean `isPOD`? +fail_compilation/diag11819a.d(36): Error: unrecognized trait `IsNested`, did you mean `isNested`? +fail_compilation/diag11819a.d(37): Error: unrecognized trait `IsFloating`, did you mean `isFloating`? +fail_compilation/diag11819a.d(38): Error: unrecognized trait `IsIntegral`, did you mean `isIntegral`? +fail_compilation/diag11819a.d(39): Error: unrecognized trait `IsScalar`, did you mean `isScalar`? +fail_compilation/diag11819a.d(40): Error: unrecognized trait `IsStaticArray`, did you mean `isStaticArray`? +fail_compilation/diag11819a.d(41): Error: unrecognized trait `IsUnsigned`, did you mean `isUnsigned`? +fail_compilation/diag11819a.d(42): Error: unrecognized trait `IsVirtualFunction`, did you mean `isVirtualFunction`? +fail_compilation/diag11819a.d(43): Error: unrecognized trait `IsVirtualMethod`, did you mean `isVirtualMethod`? +fail_compilation/diag11819a.d(44): Error: unrecognized trait `IsAbstractFunction`, did you mean `isAbstractFunction`? +fail_compilation/diag11819a.d(45): Error: unrecognized trait `IsFinalFunction`, did you mean `isFinalFunction`? +fail_compilation/diag11819a.d(46): Error: unrecognized trait `IsOverrideFunction`, did you mean `isOverrideFunction`? +fail_compilation/diag11819a.d(47): Error: unrecognized trait `IsStaticFunction`, did you mean `isStaticFunction`? +fail_compilation/diag11819a.d(48): Error: unrecognized trait `IsRef`, did you mean `isRef`? +fail_compilation/diag11819a.d(49): Error: unrecognized trait `IsOut`, did you mean `isOut`? +fail_compilation/diag11819a.d(50): Error: unrecognized trait `IsLazy`, did you mean `isLazy`? +--- +*/ + +void main() +{ + if (__traits(DoesNotExist)) { } + if (__traits(IsAbstractClass)) { } + if (__traits(IsArithmetic)) { } + if (__traits(IsAssociativeArray)) { } + if (__traits(IsFinalClass)) { } + if (__traits(IsPOD)) { } + if (__traits(IsNested)) { } + if (__traits(IsFloating)) { } + if (__traits(IsIntegral)) { } + if (__traits(IsScalar)) { } + if (__traits(IsStaticArray)) { } + if (__traits(IsUnsigned)) { } + if (__traits(IsVirtualFunction)) { } + if (__traits(IsVirtualMethod)) { } + if (__traits(IsAbstractFunction)) { } + if (__traits(IsFinalFunction)) { } + if (__traits(IsOverrideFunction)) { } + if (__traits(IsStaticFunction)) { } + if (__traits(IsRef)) { } + if (__traits(IsOut)) { } + if (__traits(IsLazy)) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11819b.d b/gcc/testsuite/gdc.test/fail_compilation/diag11819b.d new file mode 100644 index 00000000000..2280691abf6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11819b.d @@ -0,0 +1,47 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11819b.d(28): Error: unrecognized trait `HasMember`, did you mean `hasMember`? +fail_compilation/diag11819b.d(29): Error: unrecognized trait `Identifier`, did you mean `identifier`? +fail_compilation/diag11819b.d(30): Error: unrecognized trait `GetProtection`, did you mean `getProtection`? +fail_compilation/diag11819b.d(31): Error: unrecognized trait `Parent`, did you mean `parent`? +fail_compilation/diag11819b.d(32): Error: unrecognized trait `GetMember`, did you mean `getMember`? +fail_compilation/diag11819b.d(33): Error: unrecognized trait `GetOverloads`, did you mean `getOverloads`? +fail_compilation/diag11819b.d(34): Error: unrecognized trait `GetVirtualFunctions`, did you mean `getVirtualFunctions`? +fail_compilation/diag11819b.d(35): Error: unrecognized trait `GetVirtualMethods`, did you mean `getVirtualMethods`? +fail_compilation/diag11819b.d(36): Error: unrecognized trait `ClassInstanceSize`, did you mean `classInstanceSize`? +fail_compilation/diag11819b.d(37): Error: unrecognized trait `AllMembers`, did you mean `allMembers`? +fail_compilation/diag11819b.d(38): Error: unrecognized trait `DerivedMembers`, did you mean `derivedMembers`? +fail_compilation/diag11819b.d(39): Error: unrecognized trait `IsSame`, did you mean `isSame`? +fail_compilation/diag11819b.d(40): Error: unrecognized trait `Compiles`, did you mean `compiles`? +fail_compilation/diag11819b.d(41): Error: unrecognized trait `Parameters`, did you mean `parameters`? +fail_compilation/diag11819b.d(42): Error: unrecognized trait `GetAliasThis`, did you mean `getAliasThis`? +fail_compilation/diag11819b.d(43): Error: unrecognized trait `GetAttributes`, did you mean `getAttributes`? +fail_compilation/diag11819b.d(44): Error: unrecognized trait `GetFunctionAttributes`, did you mean `getFunctionAttributes`? +fail_compilation/diag11819b.d(45): Error: unrecognized trait `GetUnitTests`, did you mean `getUnitTests`? +fail_compilation/diag11819b.d(46): Error: unrecognized trait `GetVirtualIndex`, did you mean `getVirtualIndex`? +--- +*/ + +void main() +{ + if (__traits(HasMember)) { } + if (__traits(Identifier)) { } + if (__traits(GetProtection)) { } + if (__traits(Parent)) { } + if (__traits(GetMember)) { } + if (__traits(GetOverloads)) { } + if (__traits(GetVirtualFunctions)) { } + if (__traits(GetVirtualMethods)) { } + if (__traits(ClassInstanceSize)) { } + if (__traits(AllMembers)) { } + if (__traits(DerivedMembers)) { } + if (__traits(IsSame)) { } + if (__traits(Compiles)) { } + if (__traits(Parameters)) { } + if (__traits(GetAliasThis)) { } + if (__traits(GetAttributes)) { } + if (__traits(GetFunctionAttributes)) { } + if (__traits(GetUnitTests)) { } + if (__traits(GetVirtualIndex)) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11840.d b/gcc/testsuite/gdc.test/fail_compilation/diag11840.d new file mode 100644 index 00000000000..4bd9a41de3d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11840.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag11840.d(12): Error: undefined identifier `i` +fail_compilation/diag11840.d(12): Error: undefined identifier `j` +--- +*/ + +void main() +{ + int[10] data; + data[i .. j] = 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12063.d b/gcc/testsuite/gdc.test/fail_compilation/diag12063.d new file mode 100644 index 00000000000..e029810b1dc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12063.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12063.d(11): Error: no property 'max' for type 'Foo' +fail_compilation/diag12063.d(14): Error: incompatible types for ((Foo()) + (1)): 'Bar' and 'int' +--- +*/ + +struct Foo {} + +enum Bar : Foo +{ + a = Foo(), + b +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12124.d b/gcc/testsuite/gdc.test/fail_compilation/diag12124.d new file mode 100644 index 00000000000..320cfb2291e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12124.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12124.d(14): Error: struct diag12124.S1 static opCall is hidden by constructors and can never be called +fail_compilation/diag12124.d(14): Please use a factory method instead, or replace all constructors with static opCall. +fail_compilation/diag12124.d(20): Error: struct diag12124.S2 static opCall is hidden by constructors and can never be called +fail_compilation/diag12124.d(20): Please use a factory method instead, or replace all constructors with static opCall. +--- +*/ + +struct S1 +{ + this(int) {} + static S1 opCall() { assert(0); } +} + +struct S2 +{ + this(int) {} + static S2 opCall()() { assert(0); } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12280.d b/gcc/testsuite/gdc.test/fail_compilation/diag12280.d new file mode 100644 index 00000000000..f125ff31b81 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12280.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12280.d(15): Error: undefined identifier `nonexistent` +fail_compilation/diag12280.d(13): Error: template instance diag12280.f!10 error instantiating +fail_compilation/diag12280.d(18): 11 recursive instantiations from here: f!0 +--- +*/ + +void f(int i)() +{ + static if (i < 10) + f!(i + 1); + else + nonexistent(); +} + +alias f0 = f!0; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12312.d b/gcc/testsuite/gdc.test/fail_compilation/diag12312.d new file mode 100644 index 00000000000..7120a8f0d21 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12312.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12312.d(10): Error: variable diag12312.main.arr void[16] does not have a default initializer +--- +*/ + +void main() +{ + void[16] arr; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12380.d b/gcc/testsuite/gdc.test/fail_compilation/diag12380.d new file mode 100644 index 00000000000..f6434f05d96 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12380.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12380.d(12): Error: cannot implicitly convert expression `cast(E)0` of type `E` to `void*` +--- +*/ + +enum E { a, b, } + +void main() +{ + void* a = E.init; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12432.d b/gcc/testsuite/gdc.test/fail_compilation/diag12432.d new file mode 100644 index 00000000000..10755d84a03 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12432.d @@ -0,0 +1,61 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12432.d(55): Error: cannot infer argument types, expected 1 argument, not 2 +fail_compilation/diag12432.d(56): Error: cannot infer argument types, expected 2 arguments, not 3 +fail_compilation/diag12432.d(57): Error: cannot infer argument types, expected 1 argument, not 2 +fail_compilation/diag12432.d(58): Error: cannot infer argument types, expected 1 argument, not 2 +fail_compilation/diag12432.d(59): Error: cannot infer argument types, expected 2 arguments, not 3 +fail_compilation/diag12432.d(60): Error: cannot infer argument types, expected 2 arguments, not 3 +--- +*/ + +struct R1 +{ + @property int front() { return 0; } + enum bool empty = false; + void popFront() { } +} + +struct Tuple(T...) +{ + T t; + alias t this; +} + +struct R2 +{ + @property Tuple!(int, float) front() { return typeof(return).init; } + enum bool empty = false; + void popFront() { } +} + +struct OpApply1Func +{ + int opApply(int function(int)) { return 0; } +} + +struct OpApply1Deleg +{ + int opApply(int delegate(int)) { return 0; } +} + +struct OpApply2Func +{ + int opApply(int function(int, float)) { return 0; } +} + +struct OpApply2Deleg +{ + int opApply(int delegate(int, float)) { return 0; } +} + +void main() +{ + foreach (a, b; R1()) { } + foreach (a, b, c; R2()) { } + foreach (a, b; OpApply1Func()) { } + foreach (a, b; OpApply1Deleg()) { } + foreach (a, b, c; OpApply2Func()) { } + foreach (a, b, c; OpApply2Deleg()) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12480.d b/gcc/testsuite/gdc.test/fail_compilation/diag12480.d new file mode 100644 index 00000000000..1989874d200 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12480.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/diag12480.d(12): Error: static assert `2u == 3u` is false +--- +*/ + +module diag12480; + +static immutable arr = ["a", "b"]; +static assert(arr.length == 3); diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12487.d b/gcc/testsuite/gdc.test/fail_compilation/diag12487.d new file mode 100644 index 00000000000..b9193231e8a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12487.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12487.d(15): Error: recursive expansion of template instance 'diag12487.recTemplate!int' +fail_compilation/diag12487.d(25): Error: template instance diag12487.recTemplate!int error instantiating +fail_compilation/diag12487.d(18): Error: function diag12487.recFunction CTFE recursion limit exceeded +fail_compilation/diag12487.d(20): called from here: recFunction(i) +fail_compilation/diag12487.d(18): 1000 recursive calls to function recFunction +fail_compilation/diag12487.d(27): called from here: recFunction(0) +--- +*/ + +template recTemplate(T) +{ + enum bool recTemplate = recTemplate!T; +} + +bool recFunction(int i) +{ + return recFunction(i); +} + +void main() +{ + enum bool value1 = recTemplate!int; + + enum bool value2 = recFunction(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12598.d b/gcc/testsuite/gdc.test/fail_compilation/diag12598.d new file mode 100644 index 00000000000..236692d3866 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12598.d @@ -0,0 +1,22 @@ +/* +REQUIRED_ARGS: -transition=import +TEST_OUTPUT: +--- +fail_compilation/diag12598.d(14): Error: struct 'lines' is a type, not an lvalue +--- +*/ + +class C +{ + void f() + { + import imports.diag12598a; + lines ~= ""; + } + + string[] lines; +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12640.d b/gcc/testsuite/gdc.test/fail_compilation/diag12640.d new file mode 100644 index 00000000000..fc1a1975e64 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12640.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12640.d(14): Error: undefined identifier `asdf` +fail_compilation/diag12640.d(23): Error: undefined identifier `asdf` +--- +*/ + +void main() +{ + switch (1) + { + case 0: + asdf; + break; + + default: + } + + switch (1) + { + default: + asdf; + break; + + case 0: + } + +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12678.d b/gcc/testsuite/gdc.test/fail_compilation/diag12678.d new file mode 100644 index 00000000000..afe56fb51b3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12678.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12678.d(19): Error: const field 'cf1' initialized multiple times +fail_compilation/diag12678.d(22): Error: immutable field 'if1' initialized multiple times +fail_compilation/diag12678.d(25): Error: const field 'cf2' initialization is not allowed in loops or after labels +--- +*/ + +struct S +{ + const int cf1; + const int cf2; + immutable int if1; + + this(int x) + { + cf1 = x; + cf1 = x; + + if1 = x; + if1 = x; + + foreach (i; 0 .. 5) + cf2 = x; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12777.d b/gcc/testsuite/gdc.test/fail_compilation/diag12777.d new file mode 100644 index 00000000000..1eefd29bf05 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12777.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12777.d(14): Error: cannot modify this.v in const function +fail_compilation/diag12777.d(15): Error: cannot modify this.v in immutable function +fail_compilation/diag12777.d(21): Error: cannot modify this.v in const function +fail_compilation/diag12777.d(22): Error: cannot modify this.v in immutable function +--- +*/ + +struct S +{ + int v; + void fun() const { v++; } + void gun() immutable { v++; } +} + +class C +{ + int v; + void fun() const { v++; } + void gun() immutable { v++; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d new file mode 100644 index 00000000000..dcaa9f04b82 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d @@ -0,0 +1,37 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag12829.d(12): Error: function diag12829.test1 is @nogc yet allocates closures with the GC +fail_compilation/diag12829.d(15): diag12829.test1.__lambda1 closes over variable x at fail_compilation/diag12829.d(14) +fail_compilation/diag12829.d(19): diag12829.test1.bar closes over variable x at fail_compilation/diag12829.d(14) +fail_compilation/diag12829.d(26): Error: function diag12829.test2 is @nogc yet allocates closures with the GC +fail_compilation/diag12829.d(31): diag12829.test2.S.foo closes over variable x at fail_compilation/diag12829.d(28) +--- +*/ + +auto test1() @nogc +{ + int x; + void delegate() @nogc foo = () { + int y = x; + }; + + void bar() + { + int y = x; + } + auto dg = &bar; +} + +auto test2() @nogc +{ + int x; + struct S + { + void foo() + { + int y = x; + } + } + return S(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13028.d b/gcc/testsuite/gdc.test/fail_compilation/diag13028.d new file mode 100644 index 00000000000..d26cb946d7e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13028.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13028.d(15): Error: variable dg cannot be read at compile time +fail_compilation/diag13028.d(22): Error: variable a cannot be read at compile time +fail_compilation/diag13028.d(28): Error: CTFE failed because of previous errors in foo +fail_compilation/diag13028.d(28): while evaluating: `static assert(foo(() => 1) == 1)` +fail_compilation/diag13028.d(29): Error: CTFE failed because of previous errors in bar +fail_compilation/diag13028.d(29): while evaluating: `static assert(bar(delegate int() => 1) == 1)` +--- +*/ + +int foo(int delegate() dg) +{ + enum b = dg(); + return b; +} + + +int bar(lazy int a) +{ + enum b = a; + return a; +} + +void main() +{ + static assert(foo(() => 1) == 1); + static assert(bar(1) == 1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13082.d b/gcc/testsuite/gdc.test/fail_compilation/diag13082.d new file mode 100644 index 00000000000..13259cef004 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13082.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13082.d(22): Error: constructor diag13082.C.this (int a) is not callable using argument types (string) +fail_compilation/diag13082.d(23): Error: constructor diag13082.S.this (int a) is not callable using argument types (string) +--- +*/ + +class C +{ + this(int a) {} +} + +struct S +{ + this(int a) {} +} + +void main() +{ + string b; + auto c = new C(b); + auto s = new S(b); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13142.d b/gcc/testsuite/gdc.test/fail_compilation/diag13142.d new file mode 100644 index 00000000000..bbdffb08950 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13142.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13142.d(25): Error: cannot implicitly convert expression `3` of type `int` to `TYPE` +--- +*/ + +class Button +{ + enum TYPE // button type + { + COMMAND, + CHECK, + OPTION, + } +} + +class Toolbar +{ + enum ButtonTYPE // button type + { + COMMAND = Button.TYPE.COMMAND, + CHECK = Button.TYPE.CHECK, + OPTION = Button.TYPE.OPTION, + DELIMETER = Button.TYPE.max + 1 + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13281.d b/gcc/testsuite/gdc.test/fail_compilation/diag13281.d new file mode 100644 index 00000000000..c59b300900d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13281.d @@ -0,0 +1,32 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13281.d(20): Error: cannot implicitly convert expression `123` of type `int` to `string` +fail_compilation/diag13281.d(21): Error: cannot implicitly convert expression `123u` of type `uint` to `string` +fail_compilation/diag13281.d(22): Error: cannot implicitly convert expression `123L` of type `long` to `string` +fail_compilation/diag13281.d(23): Error: cannot implicitly convert expression `123LU` of type `ulong` to `string` +fail_compilation/diag13281.d(24): Error: cannot implicitly convert expression `123.4` of type `double` to `int` +fail_compilation/diag13281.d(25): Error: cannot implicitly convert expression `123.4F` of type `float` to `int` +fail_compilation/diag13281.d(26): Error: cannot implicitly convert expression `123.4L` of type `real` to `int` +fail_compilation/diag13281.d(27): Error: cannot implicitly convert expression `123.4i` of type `idouble` to `int` +fail_compilation/diag13281.d(28): Error: cannot implicitly convert expression `123.4Fi` of type `ifloat` to `int` +fail_compilation/diag13281.d(29): Error: cannot implicitly convert expression `123.4Li` of type `ireal` to `int` +fail_compilation/diag13281.d(30): Error: cannot implicitly convert expression `(123.4+5.6i)` of type `cdouble` to `int` +fail_compilation/diag13281.d(31): Error: cannot implicitly convert expression `(123.4F+5.6Fi)` of type `cfloat` to `int` +fail_compilation/diag13281.d(32): Error: cannot implicitly convert expression `(123.4L+5.6Li)` of type `creal` to `int` +--- +*/ + +string x1 = 123; +string x2 = 123u; +string x3 = 123L; +string x4 = 123uL; +int y1 = 123.4; +int y2 = 123.4f; +int y3 = 123.4L; +int y4 = 123.4i; +int y5 = 123.4fi; +int y6 = 123.4Li; +int y7 = 123.4 +5.6i; +int y8 = 123.4f+5.6fi; +int y9 = 123.4L+5.6Li; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13320.d b/gcc/testsuite/gdc.test/fail_compilation/diag13320.d new file mode 100644 index 00000000000..46a00320aaa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13320.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13320.d(13): Error: 'f += 1' is not a scalar, it is a Foo +--- +*/ + +struct Foo {} + +void main() +{ + Foo f; + ++f; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13333.d b/gcc/testsuite/gdc.test/fail_compilation/diag13333.d new file mode 100644 index 00000000000..f318a31ae72 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13333.d @@ -0,0 +1,40 @@ +/* +TEST_OUTPUT* +--- +fail_compilation/diag13333.d(29): Error: template instance VariantN!(maxSize!(S), T) recursive template expansion +fail_compilation/diag13333.d(29): Error: template instance diag13333.maxSize!(S) error instantiating +fail_compilation/diag13333.d(34): instantiated from here: Algebraic!(S) +--- +*/ + +template maxSize(T...) +{ + static if (T.length == 1) + { + enum size_t maxSize = T[0].sizeof; + } + else + { + enum size_t maxSize = T[0].sizeof >= maxSize!(T[1 .. $]) + ? T[0].sizeof : maxSize!(T[1 .. $]); + } +} + +struct VariantN(size_t maxDataSize, AllowedTypesX...) +{ +} + +template Algebraic(T...) +{ + alias Algebraic = VariantN!(maxSize!T, T); +} + +struct DummyScope +{ + alias A = Algebraic!S; + + static struct S // <- class + { + A entity; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13528.d b/gcc/testsuite/gdc.test/fail_compilation/diag13528.d new file mode 100644 index 00000000000..493cbc7fff3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13528.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13528.d(13): Error: value of 'this' is not known at compile time +fail_compilation/diag13528.d(13): while evaluating pragma(msg, __traits(getMember, A, "foo")) +--- +*/ + +mixin template MyTemplate() +{ + void foo() + { + pragma(msg, __traits(getMember, typeof(this), "foo")); + } +} + +class A +{ + mixin MyTemplate; +} + +void main() +{ + auto a = new A(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13609a.d b/gcc/testsuite/gdc.test/fail_compilation/diag13609a.d new file mode 100644 index 00000000000..039129e770f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13609a.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13609a.d(11): Error: `}` expected following members in `class` declaration at fail_compilation/diag13609a.d(8) +--- +*/ + +class C +{ + void foo() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13609b.d b/gcc/testsuite/gdc.test/fail_compilation/diag13609b.d new file mode 100644 index 00000000000..dccb9c7cb3c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13609b.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13609b.d(10): Error: base classes are not allowed for `struct`, did you mean `;`? +fail_compilation/diag13609b.d(11): Error: basic type expected, not `EOF` +fail_compilation/diag13609b.d(11): Error: { } expected following `struct` declaration +--- +*/ + +struct S : diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13787.d b/gcc/testsuite/gdc.test/fail_compilation/diag13787.d new file mode 100644 index 00000000000..99162edc144 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13787.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/diag13787.d(12): Error: cannot slice function pointer & main +fail_compilation/diag13787.d(13): Error: cannot index function pointer & main +--- +*/ + +void main() +{ + auto a = (&main)[0..1]; + auto x = (&main)[0]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13884.d b/gcc/testsuite/gdc.test/fail_compilation/diag13884.d new file mode 100644 index 00000000000..71909e28869 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13884.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13884.d(14): Error: functions cannot return a tuple +fail_compilation/diag13884.d(21): instantiated from here: MapResult!((t) => t.tupleof, Foo[]) +fail_compilation/diag13884.d(14): instantiated from here: map!(Foo[]) +--- +*/ + +struct Foo { int x; } + +void main() +{ + [Foo(1)].map!(t => t.tupleof); +} + +template map(fun...) +{ + auto map(Range)(Range r) + { + return MapResult!(fun, Range)(r); + } +} + +struct MapResult(alias fun, R) +{ + R _input; + + @property auto ref front() + { + return fun(_input[0]); + } + +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d new file mode 100644 index 00000000000..9abea3c0309 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag13942.d(18): Error: template instance isRawStaticArray!() does not match template declaration isRawStaticArray(T, A...) +fail_compilation/diag13942.d(26): Error: template diag13942.to!double.to cannot deduce function from argument types !()(), candidates are: +fail_compilation/diag13942.d(17): diag13942.to!double.to(A...)(A args) if (!isRawStaticArray!A) +--- +*/ + +template isRawStaticArray(T, A...) +{ + enum isRawStaticArray = false; +} + +template to(T) +{ + T to(A...)(A args) + if (!isRawStaticArray!A) + { + return 0; + } +} + +void main(string[] args) +{ + auto t = to!double(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14102.d b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d new file mode 100644 index 00000000000..c142b9727f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag14102.d(14): Error: -x is not an lvalue +fail_compilation/diag14102.d(15): Error: -(x -= 1) is not an lvalue +fail_compilation/diag14102.d(16): Error: -(x -= 1 -= 1) is not an lvalue +fail_compilation/diag14102.d(17): Error: -(x -= 1 -= 1 -= 1) is not an lvalue +--- +*/ + +int main() +{ + int x; + return -- -x; // error: -x is not an lvalue + return -- - --x; // error: -(x -= 1) is not an lvalue + return -- - -- --x; // error: -((x -= 1 , x) -= 1) is not an lvalue + return -- - -- -- --x; // error: -((ref int __assignop1 = x -= 1 , __assignop1 = x; , __assignop1 -= 1 , __assignop1) -= 1) is not an lvalue +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14163.d b/gcc/testsuite/gdc.test/fail_compilation/diag14163.d new file mode 100644 index 00000000000..8fe63433eb6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14163.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag14163.d(16): Error: constructor diag14163.Bar.this cannot call super() implicitly because it is annotated with @disable +--- +*/ + +class Foo +{ + @disable this(); +} + +class Bar : Foo +{ + @disable this(); + this(int i) {} +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14235.d b/gcc/testsuite/gdc.test/fail_compilation/diag14235.d new file mode 100644 index 00000000000..4880bdf3e05 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14235.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag14235.d(11): Error: template identifier 'Undefined' is not a member of module 'imports.a14235' +fail_compilation/diag14235.d(12): Error: template identifier 'Something' is not a member of module 'imports.a14235', did you mean struct 'SomeThing(T...)'? +fail_compilation/diag14235.d(13): Error: imports.a14235.SomeClass is not a template, it is a class +--- +*/ + +import imports.a14235; +imports.a14235.Undefined!Object a; +imports.a14235.Something!Object b; +imports.a14235.SomeClass!Object c; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14818.d b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d new file mode 100644 index 00000000000..4eef7487692 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d @@ -0,0 +1,37 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag14818.d(34): Error: none of the overloads of 'func' are callable using argument types (string), candidates are: +fail_compilation/diag14818.d(12): diag14818.foo(int _param_0) +fail_compilation/diag14818.d(13): diag14818.bar(double _param_0) +fail_compilation/diag14818.d(35): Error: overload alias diag14818.X does not match any template declaration +fail_compilation/diag14818.d(36): Error: overloadset diag14818.M does not match any template declaration +--- +*/ + +void foo(int) {} +void bar(double) {} +alias func = foo; +alias func = bar; +// in here, func is a FuncAliasDeclaration; + +template Foo(T) if (is(T == int)) {} +template Bar(T) if (is(T == double)) {} + +alias X = Foo; +alias X = Bar; +// in here, X is an OverDeclaration + +template Mix1() { alias M = Foo; } +template Mix2() { alias M = Bar; } +mixin Mix1; +mixin Mix2; +alias Y = M; +// in here, Y is an OverloadSet + +void main() +{ + func("abc"); + alias x = X!string; + alias y = Y!string; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14875.d b/gcc/testsuite/gdc.test/fail_compilation/diag14875.d new file mode 100644 index 00000000000..52a6127b021 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14875.d @@ -0,0 +1,76 @@ +// REQUIRED_ARGS: -o- + +deprecated class Dep { } +deprecated immutable int depVar = 10; + +/* +TEST_OUTPUT: +--- +fail_compilation/diag14875.d(16): Deprecation: class diag14875.Dep is deprecated +1: Dep +2: Dep +3: Dep +--- +*/ + +alias X = Foo!Dep; // deprecation + +template Foo(T) +{ + pragma(msg, "1: ", T); // no message + enum Foo = cast(void*)Bar!T; +} +template Bar(T) +{ + pragma(msg, "2: ", T); // no message + enum Bar = &Baz!T; +} +template Baz(T) +{ + pragma(msg, "3: ", T); // no message + immutable Baz = 1234; +} + +// --- + +/* +TEST_OUTPUT: +--- +fail_compilation/diag14875.d(47): Deprecation: class diag14875.Dep is deprecated +fail_compilation/diag14875.d(51): Deprecation: variable diag14875.depVar is deprecated +4: Dep +fail_compilation/diag14875.d(58): Deprecation: variable diag14875.depVar is deprecated +fail_compilation/diag14875.d(59): Deprecation: variable diag14875.Vaz!(Dep).Vaz is deprecated +--- +*/ + +alias Y = Voo!Dep; // deprecation + +template Voo(T) +{ + enum n = depVar; // deprecation + struct A { alias B = T; } // no message + pragma(msg, "4: ", A.B); // B is not deprecated + enum Voo = cast(void*)Var!T; +} +template Var(T) +{ + enum n = depVar; // deprecation + enum Var = &Vaz!T; // deprecation +} +deprecated template Vaz(T) +{ + enum n = depVar; // no message + immutable Vaz = 1234; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag14875.d(75): Error: static assert `0` is false +--- +*/ +void main() +{ + static assert(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14876.d b/gcc/testsuite/gdc.test/fail_compilation/diag14876.d new file mode 100644 index 00000000000..dcc440f003b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14876.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag14876.d(17): Deprecation: class diag14876.Dep is deprecated +fail_compilation/diag14876.d(18): Deprecation: class diag14876.Dep is deprecated +fail_compilation/diag14876.d(19): Deprecation: class diag14876.Dep is deprecated +fail_compilation/diag14876.d(20): Deprecation: class diag14876.Dep is deprecated +fail_compilation/diag14876.d(21): Deprecation: class diag14876.Dep is deprecated +fail_compilation/diag14876.d(22): Deprecation: class diag14876.Dep is deprecated +fail_compilation/diag14876.d(23): Deprecation: class diag14876.Dep is deprecated +fail_compilation/diag14876.d(23): Error: can only slice tuple types, not diag14876.Dep +--- +*/ + +deprecated class Dep { class Mem {} } + +alias X1 = Foo!(Dep[]); +alias X2 = Foo!(Dep[1]); +alias X3 = Foo!(Dep[int]); +alias X4 = Foo!(int[Dep]); +alias X5 = Foo!(Dep*); +alias X6 = Foo!(Dep.Mem); +alias X7 = Foo!(Dep[3..4]); + +template Foo(T) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15001.d b/gcc/testsuite/gdc.test/fail_compilation/diag15001.d new file mode 100644 index 00000000000..3763d795735 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15001.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/diag15001.d(11): Error: undefined identifier `X` +--- +*/ + +void main() +{ + if (X x = 1) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15186.d b/gcc/testsuite/gdc.test/fail_compilation/diag15186.d new file mode 100644 index 00000000000..70177f4169d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15186.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag15186.d(14): Error: use `.` for member lookup, not `::` +fail_compilation/diag15186.d(15): Error: use `.` for member lookup, not `->` +--- +*/ + +void main() +{ + struct S { static int x; int y; } + S* s; + + S::x = 1; + s->y = 2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15209.d b/gcc/testsuite/gdc.test/fail_compilation/diag15209.d new file mode 100644 index 00000000000..341e02653b3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15209.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag15209.d(18): Error: need 'this' for 'x' of type 'int' +fail_compilation/diag15209.d(21): Error: need 'this' for 'x' of type 'int' +--- +*/ + +class C1 { int x; } +struct S1 { alias y = C1.x; } + +struct S2 { int x; } +class C2 { alias y = S2.x; } + +void main() +{ + S1 s1; + s1.y = 10; // invalid field variable access + + auto c2 = new C2(); + c2.y = 10; // invalid field variable access +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15340.d b/gcc/testsuite/gdc.test/fail_compilation/diag15340.d new file mode 100644 index 00000000000..89017043884 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15340.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag15340.d(11): Error: undefined identifier `undef1` +fail_compilation/diag15340.d(12): Error: undefined identifier `undef2` +--- +*/ + +class C +{ + auto a = undef1; + auto b = undef2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15411.d b/gcc/testsuite/gdc.test/fail_compilation/diag15411.d new file mode 100644 index 00000000000..bc77d81a8ba --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15411.d @@ -0,0 +1,15 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/diag15411.d(13): Error: function diag15411.test15411.__funcliteral1 cannot access frame of function diag15411.test15411 +fail_compilation/diag15411.d(14): Error: function diag15411.test15411.__funcliteral2 cannot access frame of function diag15411.test15411 +--- +*/ + +void test15411() +{ + auto i = 0; + auto j = (function() { return i; })(); + auto f = function() { return i; }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag1566.d b/gcc/testsuite/gdc.test/fail_compilation/diag1566.d new file mode 100644 index 00000000000..28ffc8d48d5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag1566.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag1566.d(23): Error: multiple ! arguments are not allowed +fail_compilation/diag1566.d(24): Error: multiple ! arguments are not allowed +fail_compilation/diag1566.d(25): Error: multiple ! arguments are not allowed +fail_compilation/diag1566.d(26): Error: multiple ! arguments are not allowed +fail_compilation/diag1566.d(28): Error: multiple ! arguments are not allowed +fail_compilation/diag1566.d(29): Error: multiple ! arguments are not allowed +--- +*/ + +template T(int n) +{ + template T(char c) + { + alias long T; + } +} + +void main() +{ + static assert(is(long == T!(3)!('b'))); + static assert(is(long == T! 3 ! 'b' )); + static assert(is(long == T!(3)! 'b' )); + static assert(is(long == T! 3 !('b'))); + + static assert(is(long == T!(3)! 'b' !"s")); + static assert(is(long == T! 3 !('b')!"s")); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15669.d b/gcc/testsuite/gdc.test/fail_compilation/diag15669.d new file mode 100644 index 00000000000..a2ab4aa2d17 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15669.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag15669.d(14): Error: variable __b_field_0 cannot be read at compile time +--- +*/ + +alias AliasSeq(A ...) = A; + +void foo() +{ + AliasSeq!int a; + AliasSeq!int b; + a[b]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d new file mode 100644 index 00000000000..14f2d8432b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d @@ -0,0 +1,49 @@ +/* +--- +fail_compilation/diag15713.d(18): Error: no property 'widthSign' for type 'Data' +fail_compilation/diag15713.d(38): Error: template instance test.conwritefImpl!("parse-int", "width", "\x0a", Data()) error instantiating +fail_compilation/diag15713.d(43): instantiated from here: conwritefImpl!("main", "\x0a", Data()) +fail_compilation/diag15713.d(48): instantiated from here: fdwritef!() +--- +*/ + +void wrWriteWidthChar() {} + +auto WrData(int , int ) +{ + struct Data + { + auto initInt(string name)() + { + __traits(getMember, this, name ~ "Sign"); + } + } + return Data(); +} + +template conwritefImpl(string state, string field, string fmt, alias data, AA...) +if (state == "parse-int") +{ + enum conwritefImpl = data.initInt!field; +} + +template baz(string state, string fmt, alias data, AA...) {} +template bar(string state, string fmt, alias data, AA...) {} + + enum a = "parse-format"; + +template conwritefImpl(string state, string fmt, alias data, AA...) +if (state == "main") +{ + enum conwritefImpl = conwritefImpl!("parse-int", "width", fmt, data); +} + +void fdwritef()() +{ + conwritefImpl!("main", "\n", WrData(0, 0)); +} + +void conwriteln() +{ + fdwritef(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15974.d b/gcc/testsuite/gdc.test/fail_compilation/diag15974.d new file mode 100644 index 00000000000..a6b30773180 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag15974.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag15974.d(21): Error: variable f cannot be read at compile time +fail_compilation/diag15974.d(21): called from here: format("%s", f) +fail_compilation/diag15974.d(26): Error: variable f cannot be read at compile time +fail_compilation/diag15974.d(26): called from here: format("%s", f) +--- +*/ + +void test15974() +{ + string format(Args...)(string fmt, Args args) + { + return ""; + } + + string f = "vkCreateSampler"; + + // CompileStatement + mixin(format("%s", f)); + + struct S + { + // CompileDeclaration + mixin(format("%s", f)); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16499.d b/gcc/testsuite/gdc.test/fail_compilation/diag16499.d new file mode 100644 index 00000000000..5d0c6ff581f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag16499.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag16499.d(22): Error: incompatible types for ((2) in (foo)): 'int' and 'A' +fail_compilation/diag16499.d(24): Error: incompatible types for ((1.00000) in (bar)): 'double' and 'B' +--- +*/ + +struct A {} +struct B { + void* opBinaryRight(string op)(int b) if (op == "in") + { + return null; + } +} + +void main() +{ + A foo; + B bar; + + 2 in foo; + 2 in bar; // OK + 1.0 in bar; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d new file mode 100644 index 00000000000..0754fc6a8e2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d @@ -0,0 +1,31 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag16977.d(22): Error: undefined identifier `undefined`, did you mean function `undefinedId`? +fail_compilation/diag16977.d(23): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` +fail_compilation/diag16977.d(24): Error: template diag16977.templ cannot deduce function from argument types !()(int), candidates are: +fail_compilation/diag16977.d(17): diag16977.templ(S)(S s) if (false) +fail_compilation/diag16977.d(25): Error: cannot implicitly convert expression `5` of type `int` to `string` +fail_compilation/diag16977.d(27): Error: template instance diag16977.test.funcTemplate!string error instantiating +--- +*/ + +// when copying the expression of a default argument, location information is +// replaced by the location of the caller to improve debug information +// verify error messages are displayed for the original location only + +string templ(S)(S s) if(false) { return null; } + +void test() +{ + // local functions to defer evaluation into semantic3 pass + void undefinedId(int x, int y = undefined) {} + void badOp(int x, int y = 1 ~ "string") {} + void lazyTemplate(int x, lazy int y = 4.templ) {} + void funcTemplate(T)(T y = 5) {} + + funcTemplate!string(); + undefinedId(1); + badOp(2); + lazyTemplate(3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag1730.d b/gcc/testsuite/gdc.test/fail_compilation/diag1730.d new file mode 100644 index 00000000000..697cd5af294 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag1730.d @@ -0,0 +1,90 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag1730.d(38): Error: mutable method diag1730.S.func is not callable using a inout object +fail_compilation/diag1730.d(40): Error: immutable method diag1730.S.iFunc is not callable using a inout object +fail_compilation/diag1730.d(41): Error: shared mutable method diag1730.S.sFunc is not callable using a non-shared inout object +fail_compilation/diag1730.d(42): Error: shared const method diag1730.S.scFunc is not callable using a non-shared inout object +fail_compilation/diag1730.d(57): Error: immutable method diag1730.S.iFunc is not callable using a mutable object +fail_compilation/diag1730.d(58): Error: shared method diag1730.S.sFunc is not callable using a non-shared object +fail_compilation/diag1730.d(59): Error: shared const method diag1730.S.scFunc is not callable using a non-shared mutable object +fail_compilation/diag1730.d(62): Error: mutable method diag1730.S.func is not callable using a const object +fail_compilation/diag1730.d(64): Error: immutable method diag1730.S.iFunc is not callable using a const object +fail_compilation/diag1730.d(65): Error: shared mutable method diag1730.S.sFunc is not callable using a non-shared const object +fail_compilation/diag1730.d(66): Error: shared const method diag1730.S.scFunc is not callable using a non-shared const object +fail_compilation/diag1730.d(69): Error: mutable method diag1730.S.func is not callable using a immutable object +fail_compilation/diag1730.d(72): Error: shared mutable method diag1730.S.sFunc is not callable using a immutable object +fail_compilation/diag1730.d(76): Error: non-shared method diag1730.S.func is not callable using a shared object +fail_compilation/diag1730.d(77): Error: non-shared const method diag1730.S.cFunc is not callable using a shared mutable object +fail_compilation/diag1730.d(78): Error: immutable method diag1730.S.iFunc is not callable using a shared mutable object +fail_compilation/diag1730.d(81): Error: non-shared inout method diag1730.S.wFunc is not callable using a shared mutable object +fail_compilation/diag1730.d(83): Error: non-shared mutable method diag1730.S.func is not callable using a shared const object +fail_compilation/diag1730.d(84): Error: non-shared const method diag1730.S.cFunc is not callable using a shared const object +fail_compilation/diag1730.d(85): Error: immutable method diag1730.S.iFunc is not callable using a shared const object +fail_compilation/diag1730.d(86): Error: shared mutable method diag1730.S.sFunc is not callable using a shared const object +fail_compilation/diag1730.d(88): Error: non-shared inout method diag1730.S.wFunc is not callable using a shared const object +--- +*/ +struct S +{ + void func() { } + void cFunc() const { } + void iFunc() immutable { } + void sFunc() shared { } + void scFunc() shared const { } + void wFunc() inout { } + static void test(inout(S) s) + { + s.func(); // ng + s.cFunc(); + s.iFunc(); // ng + s.sFunc(); // ng + s.scFunc(); // ng + s.wFunc(); + } +} + +void main() +{ + S obj; + const(S) cObj; + immutable(S) iObj; + shared(S) sObj; + shared(const(S)) scObj; + + obj.func(); + obj.cFunc(); + obj.iFunc(); // ng + obj.sFunc(); // ng + obj.scFunc(); // ng + obj.wFunc(); + + cObj.func(); // ng + cObj.cFunc(); + cObj.iFunc(); // ng + cObj.sFunc(); // ng + cObj.scFunc(); // ng + cObj.wFunc(); + + iObj.func(); // ng + iObj.cFunc(); + iObj.iFunc(); + iObj.sFunc(); // ng + iObj.scFunc(); + iObj.wFunc(); + + sObj.func(); // ng + sObj.cFunc(); // ng + sObj.iFunc(); // ng + sObj.sFunc(); + sObj.scFunc(); + sObj.wFunc(); // ng + + scObj.func(); // ng + scObj.cFunc(); // ng + scObj.iFunc(); // ng + scObj.sFunc(); // ng + scObj.scFunc(); + scObj.wFunc(); // ng +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag2452.d b/gcc/testsuite/gdc.test/fail_compilation/diag2452.d new file mode 100644 index 00000000000..0c12e801531 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag2452.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag2452.d(14): Error: class diag2452.C interface function 'void f(float p)' is not implemented +--- +*/ + +interface I +{ + void f(int p); + void f(float p); +} + +class C : I +{ + void f(int p) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3013.d b/gcc/testsuite/gdc.test/fail_compilation/diag3013.d new file mode 100644 index 00000000000..c57b4b9c84b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3013.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag3013.d(11): Error: cannot pass type string as a function argument +--- +*/ + +int format(string, string, string); + +void main() { + int s = string.format("abc", "def"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3438.d b/gcc/testsuite/gdc.test/fail_compilation/diag3438.d new file mode 100644 index 00000000000..3c22ca8acbc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3438.d @@ -0,0 +1,21 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/diag3438.d(16): Deprecation: constructor diag3438.F1.this all parameters have default arguments, but structs cannot have default constructors. +fail_compilation/diag3438.d(17): Deprecation: constructor diag3438.F2.this all parameters have default arguments, but structs cannot have default constructors. +fail_compilation/diag3438.d(20): Deprecation: constructor diag3438.F5.this @disable'd constructor cannot have default arguments for all parameters. +fail_compilation/diag3438.d(20): Use @disable this(); if you want to disable default initialization. +fail_compilation/diag3438.d(21): Deprecation: constructor diag3438.F6.this @disable'd constructor cannot have default arguments for all parameters. +fail_compilation/diag3438.d(21): Use @disable this(); if you want to disable default initialization. +--- +*/ + +import core.vararg; + +struct F1 { this(int x = 1) { } } +struct F2 { this(int x = 1, ...) { } } +struct F3 { this(...) { } } // ok +struct F4 { this(int[] x...) { } } // ok +struct F5 { @disable this(int x = 1); } +struct F6 { @disable this(int x = 1) { } } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3438b.d b/gcc/testsuite/gdc.test/fail_compilation/diag3438b.d new file mode 100644 index 00000000000..46a197d2a24 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3438b.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag3438b.d(9): Error: default argument expected for `y` +--- +*/ + +// Make sure the deprecation doesn't interfere w/ the check for default arguments +struct S { this(int x = 1, int y) { } } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3672.d b/gcc/testsuite/gdc.test/fail_compilation/diag3672.d new file mode 100644 index 00000000000..ab3c2248c94 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3672.d @@ -0,0 +1,57 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/diag3672.d(36): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 1) instead. +fail_compilation/diag3672.d(37): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 1) instead. +fail_compilation/diag3672.d(38): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(x, 1) instead. +fail_compilation/diag3672.d(39): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(x, 1) instead. +fail_compilation/diag3672.d(40): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 1) instead. +fail_compilation/diag3672.d(41): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 2) instead. +fail_compilation/diag3672.d(42): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(x, 3) instead. +fail_compilation/diag3672.d(43): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"|="(x, y) instead. +fail_compilation/diag3672.d(44): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"*="(x, y) instead. +fail_compilation/diag3672.d(45): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"/="(x, y) instead. +fail_compilation/diag3672.d(46): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"%="(x, y) instead. +fail_compilation/diag3672.d(47): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"&="(x, y) instead. +fail_compilation/diag3672.d(48): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"^="(x, y) instead. +fail_compilation/diag3672.d(49): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"<<="(x, y) instead. +fail_compilation/diag3672.d(50): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!">>="(x, y) instead. +fail_compilation/diag3672.d(51): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!">>>="(x, y) instead. +fail_compilation/diag3672.d(52): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"^^="(x, y) instead. +fail_compilation/diag3672.d(53): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(ptr, 1) instead. +fail_compilation/diag3672.d(54): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(ptr, 1) instead. +fail_compilation/diag3672.d(55): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(ptr, 1) instead. +fail_compilation/diag3672.d(56): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(ptr, 1) instead. +--- +*/ +shared int x; +shared int y; +shared int* ptr; +shared static this() { ptr = new int; } // silence null-dereference errors + +void main() +{ + ++x; + x++; + --x; + x--; + x += 1; + x += 2; + x -= 3; + x |= y; + x *= y; + x /= y; + x %= y; + x &= y; + x ^= y; + x <<= y; + x >>= y; + x >>>= y; + x ^^= y; + ++ptr; + ptr++; + --ptr; + ptr--; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3672a.d b/gcc/testsuite/gdc.test/fail_compilation/diag3672a.d new file mode 100644 index 00000000000..6c9f701c9b2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3672a.d @@ -0,0 +1,34 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/diag3672a.d(16): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(ns.x, 1) instead. +fail_compilation/diag3672a.d(18): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(s.sx, 1) instead. +--- +*/ +class NS { shared int x; } +shared class S { int sx; } + +void main() +{ + NS ns = new NS; + ns.x++; + S s = new S; + s.sx++; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag3672a.d(32): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(s.var, 1) instead. +fail_compilation/diag3672a.d(33): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(s.var, 2) instead. +--- +*/ +void test13003() +{ + struct S { int var; } + shared S s; + s.var++; + s.var -= 2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3673.d b/gcc/testsuite/gdc.test/fail_compilation/diag3673.d new file mode 100644 index 00000000000..a2e30912333 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3673.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag3673.d(9): Error: template constraints appear both before and after BaseClassList, put them before +--- +*/ + +class A {} +class B(T) if(false) : A if (true) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3869.d b/gcc/testsuite/gdc.test/fail_compilation/diag3869.d new file mode 100644 index 00000000000..62e8993fc48 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3869.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag3869.d(10): Error: template instance diag3869.sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!int)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) recursive expansion +--- +*/ + +struct sum(A) +{ + auto blah(int a) { return .sum!(sum)(); } +} + +sum!(int) z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3913.d b/gcc/testsuite/gdc.test/fail_compilation/diag3913.d new file mode 100644 index 00000000000..e176e9dc207 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag3913.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag3913.d(12): Error: no property 'foobardoo' for type 'Foo' +fail_compilation/diag3913.d(13): Error: no property 'secon' for type 'Foo'. Did you mean 'Foo.second' ? +--- +*/ + +void main() +{ + enum Foo { first, second } + auto a = Foo.foobardoo; + auto b = Foo.secon; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4479.d b/gcc/testsuite/gdc.test/fail_compilation/diag4479.d new file mode 100644 index 00000000000..553f9efdd87 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag4479.d @@ -0,0 +1,11 @@ +// EXTRA_SOURCES: imports/fail4479.d +/* +TEST_OUTPUT: +--- +fail_compilation/diag4479.d(10): Error: module imports.fail4479mod from file fail_compilation/imports/fail4479.d must be imported with 'import imports.fail4479mod;' +--- +*/ + +module diag4479; +import imports.fail4479; +void main() { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4528.d b/gcc/testsuite/gdc.test/fail_compilation/diag4528.d new file mode 100644 index 00000000000..accadbcad88 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag4528.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag4528.d(14): Error: function diag4528.Foo.pva private functions cannot be abstract +fail_compilation/diag4528.d(15): Error: function diag4528.Foo.pka package functions cannot be abstract +fail_compilation/diag4528.d(16): Error: function diag4528.Foo.pvsa static functions cannot be abstract +fail_compilation/diag4528.d(17): Error: function diag4528.Foo.pksa static functions cannot be abstract +fail_compilation/diag4528.d(18): Error: function diag4528.Foo.pbsa static functions cannot be abstract +--- +*/ + +class Foo +{ + private abstract void pva(); + package abstract void pka(); + private static abstract void pvsa(); + package static abstract void pksa(); + public static abstract void pbsa(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4540.d b/gcc/testsuite/gdc.test/fail_compilation/diag4540.d new file mode 100644 index 00000000000..f26e231b068 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag4540.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag4540.d(11): Error: `x` must be of integral or string type, it is a `float` +--- +*/ + +void main() +{ + float x; + switch (x) + { + default: + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d new file mode 100644 index 00000000000..368f67ec439 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag4596.d(15): Error: this is not an lvalue +fail_compilation/diag4596.d(16): Error: 1 ? this : this is not an lvalue +fail_compilation/diag4596.d(18): Error: super is not an lvalue +fail_compilation/diag4596.d(19): Error: 1 ? super : super is not an lvalue +--- +*/ + +class NoGo4596 +{ + void fun() + { + this = new NoGo4596; + (1?this:this) = new NoGo4596; + + super = new Object; + (1?super:super) = new Object; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag5385.d b/gcc/testsuite/gdc.test/fail_compilation/diag5385.d new file mode 100644 index 00000000000..131659c3170 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag5385.d @@ -0,0 +1,35 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag5385.d(27): Deprecation: imports.fail5385.C.privX is not visible from module diag5385 +fail_compilation/diag5385.d(27): Error: class imports.fail5385.C member `privX` is not accessible +fail_compilation/diag5385.d(28): Deprecation: imports.fail5385.C.packX is not visible from module diag5385 +fail_compilation/diag5385.d(28): Error: class imports.fail5385.C member `packX` is not accessible +fail_compilation/diag5385.d(29): Deprecation: imports.fail5385.C.privX2 is not visible from module diag5385 +fail_compilation/diag5385.d(29): Error: class imports.fail5385.C member `privX2` is not accessible +fail_compilation/diag5385.d(30): Deprecation: imports.fail5385.C.packX2 is not visible from module diag5385 +fail_compilation/diag5385.d(30): Error: class imports.fail5385.C member `packX2` is not accessible +fail_compilation/diag5385.d(31): Deprecation: imports.fail5385.S.privX is not visible from module diag5385 +fail_compilation/diag5385.d(31): Error: struct imports.fail5385.S member `privX` is not accessible +fail_compilation/diag5385.d(32): Deprecation: imports.fail5385.S.packX is not visible from module diag5385 +fail_compilation/diag5385.d(32): Error: struct imports.fail5385.S member `packX` is not accessible +fail_compilation/diag5385.d(33): Deprecation: imports.fail5385.S.privX2 is not visible from module diag5385 +fail_compilation/diag5385.d(33): Error: struct imports.fail5385.S member `privX2` is not accessible +fail_compilation/diag5385.d(34): Deprecation: imports.fail5385.S.packX2 is not visible from module diag5385 +fail_compilation/diag5385.d(34): Error: struct imports.fail5385.S member `packX2` is not accessible +--- +*/ + +import imports.fail5385; + +void main() +{ + C.privX = 1; + C.packX = 1; + C.privX2 = 1; + C.packX2 = 1; + S.privX = 1; + S.packX = 1; + S.privX2 = 1; + S.packX2 = 1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag5450.d b/gcc/testsuite/gdc.test/fail_compilation/diag5450.d new file mode 100644 index 00000000000..495fea9c955 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag5450.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag5450.d(18): Error: class diag5450.C cannot implicitly generate a default ctor when base class diag5450.B is missing a default ctor +--- +*/ + +class A +{ + this() { } +} + +class B : A +{ + this(int f) {} +} + +class C : B +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6373.d b/gcc/testsuite/gdc.test/fail_compilation/diag6373.d new file mode 100644 index 00000000000..d5e396d2c07 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag6373.d @@ -0,0 +1,20 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/diag6373.d(15): Error: class diag6373.Bar use of `diag6373.Foo.method(double x)` is hidden by `Bar`; use `alias method = Foo.method;` to introduce base class overload set +--- +*/ + +class Foo +{ + void method(int x) { } + void method(double x) { } +} + +class Bar : Foo +{ + override void method(int x) { } +} + +void main() { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6539.d b/gcc/testsuite/gdc.test/fail_compilation/diag6539.d new file mode 100644 index 00000000000..eddb5d2ef83 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag6539.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag6539.d(21): Error: overloadset diag6539.Rectangle is used as a type +--- +*/ + +mixin template foo() +{ + struct Rectangle(T) {} +} + +mixin template bar() +{ + bool Rectangle(bool, int, int, int, int) {} +} + +mixin foo; +mixin bar; + +void test(Rectangle rect) +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6677.d b/gcc/testsuite/gdc.test/fail_compilation/diag6677.d new file mode 100644 index 00000000000..9f9c6dca868 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag6677.d @@ -0,0 +1,28 @@ +// REQUIRED_ARGS: +/* +TEST_OUTPUT: +--- +fail_compilation/diag6677.d(18): Error: static constructor cannot be `const` +fail_compilation/diag6677.d(19): Error: static constructor cannot be `inout` +fail_compilation/diag6677.d(20): Error: static constructor cannot be `immutable` +fail_compilation/diag6677.d(21): Error: use `shared static this()` to declare a shared static constructor +fail_compilation/diag6677.d(22): Error: use `shared static this()` to declare a shared static constructor +fail_compilation/diag6677.d(24): Error: shared static constructor cannot be `const` +fail_compilation/diag6677.d(25): Error: shared static constructor cannot be `inout` +fail_compilation/diag6677.d(26): Error: shared static constructor cannot be `immutable` +fail_compilation/diag6677.d(27): Error: redundant attribute `shared` +fail_compilation/diag6677.d(28): Error: redundant attribute `shared` +--- +*/ + +static this() const { } +static this() inout { } +static this() immutable { } +static this() shared { } +static this() const shared { } + +shared static this() const { } +shared static this() inout { } +shared static this() immutable { } +shared static this() shared { } +shared static this() const shared { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6699.d b/gcc/testsuite/gdc.test/fail_compilation/diag6699.d new file mode 100644 index 00000000000..34b2c7716f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag6699.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag6699.d(8): Error: no property 'x' for type 'int' +--- +*/ +alias int b6699; +alias b6699.x b6699a; + +/* +TEST_OUTPUT: +--- +fail_compilation/diag6699.d(18): Error: undefined identifier `junk1` +fail_compilation/diag6699.d(18): Error: undefined identifier `junk2` +fail_compilation/diag6699.d(19): Error: undefined identifier `junk3` +--- +*/ +class X : junk1, junk2 {} +interface X2 : junk3 {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6707.d b/gcc/testsuite/gdc.test/fail_compilation/diag6707.d new file mode 100644 index 00000000000..cabdec3f1ad --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag6707.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag6707.d(16): Error: mutable method diag6707.Foo.value is not callable using a const object +--- +*/ + +module diag6707; + +struct Foo +{ + @property bool value() { return true; } + + void test() const + { + auto x = value; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6717.d b/gcc/testsuite/gdc.test/fail_compilation/diag6717.d new file mode 100644 index 00000000000..fe30f898293 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag6717.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag6717.d(12): Error: end of instruction expected, not 'h' +--- +*/ + +void main() +{ + asm + { + mov AX, 12h ; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6796.d b/gcc/testsuite/gdc.test/fail_compilation/diag6796.d new file mode 100644 index 00000000000..c8be130fd5f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag6796.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag6796.d(11): Error: cannot implicitly convert expression `0` of type `int` to `int[]` +fail_compilation/diag6796.d(11): Error: cannot implicitly convert expression `1` of type `int` to `int[]` +--- +*/ + +void main() +{ + enum int[][] array = [0, 1]; + array[0] *= 10; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7050a.d b/gcc/testsuite/gdc.test/fail_compilation/diag7050a.d new file mode 100644 index 00000000000..ddee70cf412 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag7050a.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag7050a.d(14): Error: @safe function 'diag7050a.foo' cannot call @system constructor 'diag7050a.Foo.this' +--- +*/ + +struct Foo +{ + this (int a) {} +} +@safe void foo() +{ + auto f = Foo(3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7050b.d b/gcc/testsuite/gdc.test/fail_compilation/diag7050b.d new file mode 100644 index 00000000000..ecbfd8127e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag7050b.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag7050b.d(12): Error: pure function 'diag7050b.f.g' cannot call impure function 'diag7050b.f' +--- +*/ + +void f() +{ + pure void g() + { + f(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7050c.d b/gcc/testsuite/gdc.test/fail_compilation/diag7050c.d new file mode 100644 index 00000000000..3fa75fc524c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag7050c.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag7050c.d(13): Error: @safe destructor 'diag7050c.B.~this' cannot call @system destructor 'diag7050c.A.~this' +--- +*/ + +struct A +{ + ~this(){} +} + +@safe struct B +{ + A a; +} + +@safe void f() +{ + auto x = B.init; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7420.d b/gcc/testsuite/gdc.test/fail_compilation/diag7420.d new file mode 100644 index 00000000000..80077eb4ec9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag7420.d @@ -0,0 +1,24 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/diag7420.d(20): Error: static variable x cannot be read at compile time +fail_compilation/diag7420.d(20): while evaluating: `static assert(x < 4)` +fail_compilation/diag7420.d(21): Error: static variable y cannot be read at compile time +fail_compilation/diag7420.d(21): while evaluating: `static assert(y == "abc")` +fail_compilation/diag7420.d(22): Error: static variable y cannot be read at compile time +fail_compilation/diag7420.d(22): while evaluating: `static assert(cast(ubyte[])y != null)` +fail_compilation/diag7420.d(23): Error: static variable y cannot be read at compile time +fail_compilation/diag7420.d(23): while evaluating: `static assert(cast(int)y[0] == 1)` +fail_compilation/diag7420.d(24): Error: static variable y cannot be read at compile time +fail_compilation/diag7420.d(24): while evaluating: `static assert(y[0..1].length == 1u)` +--- +*/ + +int x = 2; +char[] y = "abc".dup; +static assert(x < 4); +static assert(y == "abc"); +static assert(cast(ubyte[])y != null); +static assert(y[0] == 1); +static assert(y[0..1].length == 1); diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7477.d b/gcc/testsuite/gdc.test/fail_compilation/diag7477.d new file mode 100644 index 00000000000..1c971847bc8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag7477.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag7477.d(13): Error: cannot implicitly convert expression `0` of type `int` to `Foo` +fail_compilation/diag7477.d(20): Error: cannot implicitly convert expression `0` of type `int` to `string` +--- +*/ + +struct Foo { int x; } + +enum Bar : Foo +{ + a, + b, + c +} + +enum Baz : string +{ + a, + b, +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7747.d b/gcc/testsuite/gdc.test/fail_compilation/diag7747.d new file mode 100644 index 00000000000..0756911cab3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag7747.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag7747.d(8): Error: forward reference to inferred return type of function call 'fact(n - 1)' +--- +*/ + +auto fact(int n) { return n > 1 ? fact(n - 1) : 0; } + +void main() +{ + fact(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7998.d b/gcc/testsuite/gdc.test/fail_compilation/diag7998.d new file mode 100644 index 00000000000..68f61f3361c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag7998.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag7998.d(10): Error: static assert "abcxe" +--- +*/ + +module diag7998; + +static assert(false, "abc" ~['x'] ~ "e"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d new file mode 100644 index 00000000000..6fc38099048 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d @@ -0,0 +1,63 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8101.d(56): Error: function diag8101.f_0 (int) is not callable using argument types () +fail_compilation/diag8101.d(57): Error: none of the overloads of 'f_1' are callable using argument types (), candidates are: +fail_compilation/diag8101.d(32): diag8101.f_1(int) +fail_compilation/diag8101.d(33): diag8101.f_1(int, int) +fail_compilation/diag8101.d(58): Error: none of the overloads of 'f_2' are callable using argument types (), candidates are: +fail_compilation/diag8101.d(35): diag8101.f_2(int) +fail_compilation/diag8101.d(36): diag8101.f_2(int, int) +fail_compilation/diag8101.d(37): diag8101.f_2(int, int, int) +fail_compilation/diag8101.d(38): diag8101.f_2(int, int, int, int) +fail_compilation/diag8101.d(39): diag8101.f_2(int, int, int, int, int) +fail_compilation/diag8101.d(58): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(60): Error: template diag8101.t_0 cannot deduce function from argument types !()(), candidates are: +fail_compilation/diag8101.d(42): diag8101.t_0(T1)() +fail_compilation/diag8101.d(61): Error: template diag8101.t_1 cannot deduce function from argument types !()(), candidates are: +fail_compilation/diag8101.d(44): diag8101.t_1(T1)() +fail_compilation/diag8101.d(45): diag8101.t_1(T1, T2)() +fail_compilation/diag8101.d(62): Error: template diag8101.t_2 cannot deduce function from argument types !()(), candidates are: +fail_compilation/diag8101.d(47): diag8101.t_2(T1)() +fail_compilation/diag8101.d(48): diag8101.t_2(T1, T2)() +fail_compilation/diag8101.d(49): diag8101.t_2(T1, T2, T3)() +fail_compilation/diag8101.d(50): diag8101.t_2(T1, T2, T3, T4)() +fail_compilation/diag8101.d(51): diag8101.t_2(T1, T2, T3, T4, T5)() +fail_compilation/diag8101.d(62): ... (1 more, -v to show) ... +--- +*/ + +void f_0(int); + +void f_1(int); +void f_1(int, int); + +void f_2(int); +void f_2(int, int); +void f_2(int, int, int); +void f_2(int, int, int, int); +void f_2(int, int, int, int, int); +void f_2(int, int, int, int, int, int); + +void t_0(T1)(); + +void t_1(T1)(); +void t_1(T1, T2)(); + +void t_2(T1)(); +void t_2(T1, T2)(); +void t_2(T1, T2, T3)(); +void t_2(T1, T2, T3, T4)(); +void t_2(T1, T2, T3, T4, T5)(); +void t_2(T1, T2, T3, T4, T5, T6)(); + +void main() +{ + f_0(); + f_1(); + f_2(); + + t_0(); + t_1(); + t_2(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d new file mode 100644 index 00000000000..a3baa272fae --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8101b.d(26): Error: none of the overloads of 'foo' are callable using argument types (double), candidates are: +fail_compilation/diag8101b.d(17): diag8101b.S.foo(int _param_0) +fail_compilation/diag8101b.d(18): diag8101b.S.foo(int _param_0, int _param_1) +fail_compilation/diag8101b.d(28): Error: function diag8101b.S.bar (int _param_0) is not callable using argument types (double) +fail_compilation/diag8101b.d(31): Error: none of the overloads of 'foo' are callable using a const object, candidates are: +fail_compilation/diag8101b.d(17): diag8101b.S.foo(int _param_0) +fail_compilation/diag8101b.d(18): diag8101b.S.foo(int _param_0, int _param_1) +fail_compilation/diag8101b.d(33): Error: mutable method diag8101b.S.bar is not callable using a const object +--- +*/ + +struct S +{ + void foo(int) { } + void foo(int, int) { } + + void bar(int) { } +} + +void main() +{ + S s; + s.foo(1.0); + + s.bar(1.0); + + const(S) cs; + cs.foo(1); + + cs.bar(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8178.d b/gcc/testsuite/gdc.test/fail_compilation/diag8178.d new file mode 100644 index 00000000000..491a6255742 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8178.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8178.d(14): Error: cannot modify manifest constant 's' +--- +*/ + +struct Foo +{ + enum string s = ""; +} +void main() +{ + Foo.s = ""; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8318.d b/gcc/testsuite/gdc.test/fail_compilation/diag8318.d new file mode 100644 index 00000000000..d319532fd5c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8318.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8318.d(13): Error: function diag8318.Bar8318.foo return type inference is not supported if may override base class function +--- +*/ +class Foo8318 +{ + auto foo() { return "Foo.foo"; } +} +class Bar8318 : Foo8318 +{ + override auto foo() { return "Bar.foo"; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag8318.d(24): Error: function diag8318.C10021.makeI return type inference is not supported if may override base class function +--- +*/ +interface I10021 { I10021 makeI(); } +class D10021 : I10021 { D10021 makeI() { return this; } } +class C10021 : I10021 { auto makeI() { return this; } } + +/* +TEST_OUTPUT: +--- +fail_compilation/diag8318.d(38): Error: function diag8318.Bar10195.baz return type inference is not supported if may override base class function +--- +*/ +interface Foo10195 +{ + int baz(); +} +class Bar10195 : Foo10195 +{ + override auto baz() { return 1; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag8318.d(50): Error: function diag8318.B14173.foo does not override any function +--- +*/ +class A14173 {} +class B14173 : A14173 +{ + override foo() {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8425.d b/gcc/testsuite/gdc.test/fail_compilation/diag8425.d new file mode 100644 index 00000000000..14dbb1cf1ad --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8425.d @@ -0,0 +1,16 @@ +/* +REQUIRED_ARGS: -m64 -o- +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/diag8425.d(13): Error: T in __vector(T) must be a static array, not void +fail_compilation/diag8425.d(14): Error: 1 byte vector type __vector(void[1]) is not supported on this platform +fail_compilation/diag8425.d(15): Error: 99 byte vector type __vector(void[99]) is not supported on this platform +fail_compilation/diag8425.d(16): Error: vector type __vector(void*[4]) is not supported on this platform +--- +*/ + +alias a = __vector(void); // not static array +alias b = __vector(void[1]); // wrong size +alias c = __vector(void[99]); // wrong size +alias d = __vector(void*[4]); // wrong base type diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8510.d b/gcc/testsuite/gdc.test/fail_compilation/diag8510.d new file mode 100644 index 00000000000..d1a897a40c6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8510.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8510.d(10): Error: alias diag8510.a conflicts with alias diag8510.a at fail_compilation/diag8510.d(9) +fail_compilation/diag8510.d(15): Error: alias diag8510.S.a conflicts with alias diag8510.S.a at fail_compilation/diag8510.d(14) +--- +*/ + +alias int a; +alias int a; + +int g; +struct S { + alias g a; + alias g a; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8559.d b/gcc/testsuite/gdc.test/fail_compilation/diag8559.d new file mode 100644 index 00000000000..5dc2b9d3a26 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8559.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8559.d(12): Error: void does not have a default initializer +fail_compilation/diag8559.d(13): Error: function does not have a default initializer +--- +*/ + +void foo(){} +void main() +{ + auto x = void.init; + auto y = typeof(foo).init; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d new file mode 100644 index 00000000000..fa96d5cfd3e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d @@ -0,0 +1,33 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8648.d(18): Error: undefined identifier `X` +fail_compilation/diag8648.d(29): Error: template diag8648.foo cannot deduce function from argument types !()(Foo!(int, 1)), candidates are: +fail_compilation/diag8648.d(18): diag8648.foo(T, n)(X!(T, n)) +fail_compilation/diag8648.d(20): Error: undefined identifier `a` +fail_compilation/diag8648.d(31): Error: template diag8648.bar cannot deduce function from argument types !()(Foo!(int, 1)), candidates are: +fail_compilation/diag8648.d(20): diag8648.bar(T)(Foo!(T, a)) +fail_compilation/diag8648.d(20): Error: undefined identifier `a` +fail_compilation/diag8648.d(32): Error: template diag8648.bar cannot deduce function from argument types !()(Foo!(int, f)), candidates are: +fail_compilation/diag8648.d(20): diag8648.bar(T)(Foo!(T, a)) +--- +*/ + +struct Foo(T, alias a) {} + +void foo(T, n)(X!(T, n) ) {} // undefined identifier 'X' + +void bar(T)(Foo!(T, a) ) {} // undefined identifier 'a' + +void main() +{ + template f() {} + + Foo!(int, 1) x; + Foo!(int, f) y; + + foo(x); + + bar(x); // expression '1' vs undefined Type 'a' + bar(y); // symbol 'f' vs undefined Type 'a' +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8697.d b/gcc/testsuite/gdc.test/fail_compilation/diag8697.d new file mode 100644 index 00000000000..b1a10089997 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8697.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8697.d(10): Error: no property 'Invalid' for type 'diag8697.Base' +--- +*/ +interface InterBase : InterRoot { } +class Base : InterBase { } + +void test(Base.Invalid) { } + +interface InterRoot { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8714.d b/gcc/testsuite/gdc.test/fail_compilation/diag8714.d new file mode 100644 index 00000000000..3a7ffd87e0d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8714.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8714.d(9): Error: function diag8714.foo circular dependency. Functions cannot be interpreted while being compiled +fail_compilation/diag8714.d(15): called from here: foo("somestring") +--- +*/ + +string foo(string f) +{ + if (f == "somestring") + { + return "got somestring"; + } + return bar!(foo("somestring")); +} + +template bar(string s) +{ + enum bar = s; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8777.d b/gcc/testsuite/gdc.test/fail_compilation/diag8777.d new file mode 100644 index 00000000000..f289da92a85 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8777.d @@ -0,0 +1,44 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8777.d(12): Error: constructor diag8777.Foo1.this missing initializer for immutable field x +fail_compilation/diag8777.d(12): Error: constructor diag8777.Foo1.this missing initializer for const field y +--- +*/ +class Foo1 +{ + immutable int[5] x; + const int[5] y; + this() {} +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag8777.d(25): Error: cannot modify immutable expression x +fail_compilation/diag8777.d(28): Error: cannot modify const expression y +--- +*/ +void test2() +{ + immutable int x; + x = 1; + + const int y; + y = 1; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag8777.d(42): Error: cannot remove key from immutable associative array hashx +fail_compilation/diag8777.d(43): Error: cannot remove key from const associative array hashy +--- +*/ +immutable(int[int]) hashx; +const(int[int]) hashy; +void test3() +{ + hashx.remove(1); + hashy.remove(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8787.d b/gcc/testsuite/gdc.test/fail_compilation/diag8787.d new file mode 100644 index 00000000000..dde80abc9af --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8787.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8787.d(10): Error: function diag8787.I.f function body only allowed in final functions in interface I +--- +*/ + +interface I +{ + void f() { } +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8825.d b/gcc/testsuite/gdc.test/fail_compilation/diag8825.d new file mode 100644 index 00000000000..68dcaa15e59 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8825.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8825.d(13): Error: undefined identifier `foo` +--- +*/ + +template t(alias a){ + alias int t; +} + +void main(){ + t!(foo // line 13 + + + + + + ) i; // line 19 + return; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8892.d b/gcc/testsuite/gdc.test/fail_compilation/diag8892.d new file mode 100644 index 00000000000..1bf6192175b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8892.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8892.d(14): Error: cannot implicitly convert expression `['A']` of type `char[]` to `char[2]` +--- +*/ +struct Foo +{ + char[2] data; +} + +void main() +{ + auto f = Foo(['A']); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8894.d b/gcc/testsuite/gdc.test/fail_compilation/diag8894.d new file mode 100644 index 00000000000..9b66bf0f032 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8894.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8894.d(16): Error: no property 'x' for type 'Foo' +fail_compilation/diag8894.d(17): Error: no property 'y' for type 'Foo' +fail_compilation/diag8894.d(18): Error: no property 'x' for type 'Foo' +fail_compilation/diag8894.d(19): Error: no property 'x' for type 'Foo' +--- +*/ + +struct Foo { } + +void main() +{ + Foo f; + f.x; // UFCS getter1 + f.y!int; // UFCS getter2 + f.x = 10; // UFCS setter1 + f.x!int = 10; // UFCS setter2 +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8928.d b/gcc/testsuite/gdc.test/fail_compilation/diag8928.d new file mode 100644 index 00000000000..bdd1ae8b61e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8928.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag8928.d(18): Error: class diag8928.Z cannot implicitly generate a default ctor when base class diag8928.X is missing a default ctor +--- +*/ + +class X +{ + this(int n) {} +} + +class Y : X +{ + this() {} +} + +class Z : X +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d new file mode 100644 index 00000000000..19852758252 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9004.d(21): Error: template diag9004.bar cannot deduce function from argument types !()(Foo!int, int), candidates are: +fail_compilation/diag9004.d(14): diag9004.bar(FooT)(FooT foo, FooT.T x) +--- +*/ + +struct Foo(_T) +{ + alias _T T; +} + +void bar(FooT)(FooT foo, FooT.T x) +{ +} + +void main() +{ + Foo!int foo; + bar(foo, 1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9148.d b/gcc/testsuite/gdc.test/fail_compilation/diag9148.d new file mode 100644 index 00000000000..0a7707e659f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9148.d @@ -0,0 +1,55 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9148.d(19): Error: pure function 'diag9148.test9148a.foo' cannot access mutable static data 'g' +fail_compilation/diag9148.d(23): Error: pure function 'diag9148.test9148a.bar' cannot access mutable static data 'g' +fail_compilation/diag9148.d(24): Error: immutable function 'diag9148.test9148a.bar' cannot access mutable data 'x' +fail_compilation/diag9148.d(31): Error: pure function 'diag9148.test9148a.S.foo' cannot access mutable static data 'g' +fail_compilation/diag9148.d(35): Error: pure function 'diag9148.test9148a.S.bar' cannot access mutable static data 'g' +fail_compilation/diag9148.d(36): Error: immutable function 'diag9148.test9148a.S.bar' cannot access mutable data 'x' +--- +*/ +void test9148a() pure +{ + static int g; + int x; + + void foo() /+pure+/ + { + g++; + } + void bar() immutable /+pure+/ + { + g++; + x++; + } + + struct S + { + void foo() /+pure+/ + { + g++; + } + void bar() immutable /+pure+/ + { + g++; + x++; + } + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/diag9148.d(53): Error: static function diag9148.test9148b.foo cannot access frame of function diag9148.test9148b +--- +*/ + +void test9148b() +{ + int x; + static void foo() pure + { + int y = x; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9191.d b/gcc/testsuite/gdc.test/fail_compilation/diag9191.d new file mode 100644 index 00000000000..50e5445d3e0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9191.d @@ -0,0 +1,41 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9191.d(16): Error: function diag9191.C1.aaa does not override any function, did you mean to override 'diag9191.B1.aa'? +fail_compilation/diag9191.d(21): Error: function diag9191.C2.aaa does not override any function +fail_compilation/diag9191.d(31): Error: function diag9191.C3.foo does not override any function, did you mean to override 'diag9191.B2._foo'? +fail_compilation/diag9191.d(36): Error: function diag9191.C4.toStringa does not override any function, did you mean to override 'object.Object.toString'? +--- +*/ + +interface I1 { void a(); } +class B1 { void aa(); } + +class C1 : B1, I1 +{ + override void aaa(); +} + +class C2 : I1 +{ + override void aaa(); +} + +class B2 +{ + void _foo(){} +} + +class C3 : B2 +{ + override void foo(){} +} + +class C4 +{ + override void toStringa(){} +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9210a.d b/gcc/testsuite/gdc.test/fail_compilation/diag9210a.d new file mode 100644 index 00000000000..ac3609f48f1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9210a.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/imports/diag9210b.d(6): Error: undefined identifier `A` +--- +*/ + +import imports.diag9210b; +interface A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9247.d b/gcc/testsuite/gdc.test/fail_compilation/diag9247.d new file mode 100644 index 00000000000..e22634559cb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9247.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9247.d(11): Error: functions cannot return opaque type S by value +fail_compilation/diag9247.d(12): Error: functions cannot return opaque type S by value +--- +*/ + +struct S; + +S foo(); +S function() bar; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9250.d b/gcc/testsuite/gdc.test/fail_compilation/diag9250.d new file mode 100644 index 00000000000..177a05cf396 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9250.d @@ -0,0 +1,24 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/diag9250.d(19): Error: cannot implicitly convert expression `10u` of type `uint` to `Foo` +fail_compilation/diag9250.d(22): Error: cannot implicitly convert expression `10u` of type `uint` to `void*` +--- +*/ + +struct Foo +{ + ubyte u; +} + +void main() +{ + uint[10] bar; + + Foo x = bar.length; // error here + + void* y = bar.length ? + bar.length : // error here + bar.length; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9312.d b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d new file mode 100644 index 00000000000..41c136090b0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9312.d(10): Error: with expressions must be aggregate types or pointers to them, not `int` +--- +*/ + +void main() +{ + with (1) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9357.d b/gcc/testsuite/gdc.test/fail_compilation/diag9357.d new file mode 100644 index 00000000000..f26b1c4482e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9357.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9357.d(14): Error: cannot implicitly convert expression `1.00000` of type `double` to `int` +fail_compilation/diag9357.d(15): Error: cannot implicitly convert expression `10.0000` of type `double` to `int` +fail_compilation/diag9357.d(16): Error: cannot implicitly convert expression `11.0000` of type `double` to `int` +fail_compilation/diag9357.d(17): Error: cannot implicitly convert expression `99.0000` of type `double` to `int` +fail_compilation/diag9357.d(18): Error: cannot implicitly convert expression `1.04858e+06L` of type `real` to `int` +fail_compilation/diag9357.d(19): Error: cannot implicitly convert expression `1.04858e+06L` of type `real` to `int` +--- +*/ +void main() +{ + { int x = 1.0; } + { int x = 10.0; } + { int x = 11.0; } + { int x = 99.0; } + { int x = 1048575.0L; } + { int x = 1048576.0L; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9358.d b/gcc/testsuite/gdc.test/fail_compilation/diag9358.d new file mode 100644 index 00000000000..d368ae2dd7e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9358.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9358.d(12): Error: `x` must be of integral or string type, it is a `double` +fail_compilation/diag9358.d(14): Error: case must be a string or an integral constant, not `1.1` +fail_compilation/diag9358.d(15): Error: case must be a string or an integral constant, not `2.1` +--- +*/ +void main() +{ + double x; + switch (x) + { + case 1.1: break; + case 2.1: break; + default: + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9398.d b/gcc/testsuite/gdc.test/fail_compilation/diag9398.d new file mode 100644 index 00000000000..67900c9bc6c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9398.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9398.d(11): Error: incompatible types for ((f) : (s)): 'float' and 'string' +--- +*/ +void main() +{ + float f; + string s; + auto a = (true ? f : s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9420.d b/gcc/testsuite/gdc.test/fail_compilation/diag9420.d new file mode 100644 index 00000000000..dfaf7c84a09 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9420.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT +--- +fail_compilation/diag9420.d(20): Error: function diag9420.S.t3!().tx () is not callable using argument types (int) +--- +*/ + +mixin template Mixin() { } +struct S +{ + template t3(T...) + { + void tx(T){} + alias t3 = tx; + } +} +void main() +{ + S s1; + s1.t3!()(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9451.d b/gcc/testsuite/gdc.test/fail_compilation/diag9451.d new file mode 100644 index 00000000000..a9121fc338f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9451.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9451.d(26): Error: cannot create instance of abstract class C2 +fail_compilation/diag9451.d(26): function 'void f1()' is not implemented +fail_compilation/diag9451.d(26): function 'void f2(int)' is not implemented +fail_compilation/diag9451.d(26): function 'void f2(float) const' is not implemented +fail_compilation/diag9451.d(26): function 'int f2(float) pure' is not implemented +--- +*/ + +class C1 +{ + abstract void f1(); + abstract void f2(int); + abstract void f2(float) const; + abstract int f2(float) pure; +} + +class C2 : C1 +{ +} + +void main() +{ + auto c2 = new C2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9479.d b/gcc/testsuite/gdc.test/fail_compilation/diag9479.d new file mode 100644 index 00000000000..25cd408b939 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9479.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9479.d(10): Error: undefined identifier `something_undefined` +--- +*/ + +int delegate() bug9479() +{ + return { return something_undefined; }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9574.d b/gcc/testsuite/gdc.test/fail_compilation/diag9574.d new file mode 100644 index 00000000000..b280b3bda92 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9574.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9574.d(12): Error: cannot use syntax `alias this = x`, use `alias x this` instead +fail_compilation/diag9574.d(18): Error: cannot use syntax `alias this = x`, use `alias x this` instead +--- +*/ + +struct S +{ + int x; + alias this = x; +} + +class C +{ + int x; + alias this = x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9620.d b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d new file mode 100644 index 00000000000..5d50cb8c7ac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9620.d(18): Error: pure function 'diag9620.main.bar' cannot call impure function 'diag9620.foo1' +fail_compilation/diag9620.d(19): Error: pure function 'diag9620.main.bar' cannot call impure function 'diag9620.foo2!().foo2' +--- +*/ + +int x; + +void foo1() { x = 3; } +void foo2()() { x = 3; } + +void main() pure +{ + void bar() + { + foo1(); + foo2(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9635.d b/gcc/testsuite/gdc.test/fail_compilation/diag9635.d new file mode 100644 index 00000000000..0e15aa2b9a5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9635.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/diag9635.d(17): Error: need 'this' for 'i' of type 'int' +fail_compilation/diag9635.d(18): Error: need 'this' for 'foo' of type 'pure nothrow @nogc @safe void()' +--- +*/ + +struct Foo +{ + int i; + void foo()() { } + + static void bar() + { + i = 4; + foo(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9679.d b/gcc/testsuite/gdc.test/fail_compilation/diag9679.d new file mode 100644 index 00000000000..a19d99debd0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9679.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9679.d(11): Error: variable diag9679.main.n only parameters or foreach declarations can be ref +fail_compilation/diag9679.d(12): Error: variable diag9679.main.n storage class 'auto' has no effect if type is not inferred, did you mean 'scope'? +--- +*/ + +void main() +{ + if (ref n = 1) {} + if (auto int n = 1) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9765.d b/gcc/testsuite/gdc.test/fail_compilation/diag9765.d new file mode 100644 index 00000000000..fa629a228e8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9765.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9765.d(9): Error: cannot implicitly convert expression `'x'` of type `char` to `char[]` +--- +*/ + +struct S9765 { char[] x; } +const S9765 s9765 = S9765('x'); +const char s9765b = s9765.x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d new file mode 100644 index 00000000000..8882f66efc8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9831.d(12): Error: function diag9831.main.__lambda1 cannot access frame of function D main +--- +*/ + +void main() +{ + immutable int c; + int function(int x) func; + func = x => c; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9861.d b/gcc/testsuite/gdc.test/fail_compilation/diag9861.d new file mode 100644 index 00000000000..6c7d89f8cc1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9861.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9861.d(8): Error: no property 'epsilon' for type 'int' +fail_compilation/diag9861.d(9): while looking for match for Foo!int +--- +*/ +struct Foo(T, real x = T.epsilon) {} +Foo!(int) q; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9880.d b/gcc/testsuite/gdc.test/fail_compilation/diag9880.d new file mode 100644 index 00000000000..9d893b8d5de --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9880.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9880.d(9): Error: template instance diag9880.foo!string does not match template declaration foo(T)(int) if (is(T == int)) +--- +*/ + +void foo(T)(int) if (is(T == int)) {} +void main() { alias f = foo!string; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9961.d b/gcc/testsuite/gdc.test/fail_compilation/diag9961.d new file mode 100644 index 00000000000..6b758e5d78d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9961.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag9961.d(11): Error: cannot implicitly convert expression `""` of type `string` to `int` +fail_compilation/diag9961.d(14): Error: template instance diag9961.foo!int error instantiating +fail_compilation/diag9961.d(11): Error: cannot implicitly convert expression `""` of type `string` to `int` +fail_compilation/diag9961.d(15): Error: template instance diag9961.foo!char error instantiating +--- +*/ + +void foo(T)(T) { int x = ""; } +void main() +{ + 100.foo(); + 'a'.foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d b/gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d new file mode 100644 index 00000000000..1b1cd0c458a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d @@ -0,0 +1,21 @@ +// REQUIRED_ARGS: +/* +TEST_OUTPUT: +--- +fail_compilation/diag_cstyle.d(14): Error: instead of C-style syntax, use D-style `int function(int) fp1` +fail_compilation/diag_cstyle.d(15): Error: instead of C-style syntax, use D-style `int function(int)* fp3` +fail_compilation/diag_cstyle.d(17): Error: instead of C-style syntax, use D-style `int function(int) FP` +fail_compilation/diag_cstyle.d(19): Error: instead of C-style syntax, use D-style `int function() fp` +fail_compilation/diag_cstyle.d(19): Deprecation: instead of C-style syntax, use D-style syntax `int[] arr` +fail_compilation/diag_cstyle.d(21): Deprecation: instead of C-style syntax, use D-style syntax `string[] result` +--- +*/ + +int (*fp1)(int); +int (*(*fp3))(int); + +alias int(*FP)(int); + +void foo(int(*fp)(), int arr[]) {} + +string result[]() = "abc"; diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_err1.d b/gcc/testsuite/gdc.test/fail_compilation/diag_err1.d new file mode 100644 index 00000000000..50e16b43759 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag_err1.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/diag_err1.d(21): Error: undefined identifier `x` +fail_compilation/diag_err1.d(21): while evaluating pragma(msg, [1, 2, x].length) +fail_compilation/diag_err1.d(22): Error: undefined identifier `x` +fail_compilation/diag_err1.d(22): Error: undefined identifier `y` +fail_compilation/diag_err1.d(22): while evaluating pragma(msg, (x + y).sizeof) +fail_compilation/diag_err1.d(23): Error: undefined identifier `x` +fail_compilation/diag_err1.d(23): while evaluating pragma(msg, (n += x).sizeof) +fail_compilation/diag_err1.d(24): Error: incompatible types for ((s) ~ (n)): 'string' and 'int' +fail_compilation/diag_err1.d(24): while evaluating pragma(msg, (s ~ n).sizeof) +--- +*/ + +void main() +{ + int n; + string s; + + pragma(msg, [1,2,x].length); + pragma(msg, (x + y).sizeof); + pragma(msg, (n += x).sizeof); + pragma(msg, (s ~ n).sizeof); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22a.d b/gcc/testsuite/gdc.test/fail_compilation/dip22a.d new file mode 100644 index 00000000000..7497b428d3d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/dip22a.d @@ -0,0 +1,26 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/dip22a.d(21): Deprecation: imports.dip22a.Klass.bar is not visible from module dip22a +fail_compilation/dip22a.d(21): Error: class imports.dip22a.Klass member `bar` is not accessible +fail_compilation/dip22a.d(22): Deprecation: imports.dip22a.Struct.bar is not visible from module dip22a +fail_compilation/dip22a.d(22): Error: struct imports.dip22a.Struct member `bar` is not accessible +fail_compilation/dip22a.d(23): Error: imports.dip22a.bar is not visible from module dip22a +fail_compilation/dip22a.d(23): Error: function `imports.dip22a.bar` is not accessible from module `dip22a` +fail_compilation/dip22a.d(24): Error: imports.dip22a.Template!int.bar is not visible from module dip22a +fail_compilation/dip22a.d(24): Error: function `imports.dip22a.Template!int.bar` is not accessible from module `dip22a` +fail_compilation/dip22a.d(25): Deprecation: imports.dip22a.bar is not visible from module dip22a +fail_compilation/dip22a.d(25): Error: function `imports.dip22a.bar` is not accessible from module `dip22a` +--- +*/ +import imports.dip22a; + +void test() +{ + new Klass().bar(); + Struct().bar(); + imports.dip22a.bar(); + Template!int.bar(); + 12.bar(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22b.d b/gcc/testsuite/gdc.test/fail_compilation/dip22b.d new file mode 100644 index 00000000000..7aca88c09cb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/dip22b.d @@ -0,0 +1,12 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/dip22b.d(12): Deprecation: pkg.dip22c.Foo is not visible from module dip22 +--- +*/ +module pkg.dip22; + +import imports.dip22b; + +Foo foo; diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22d.d b/gcc/testsuite/gdc.test/fail_compilation/dip22d.d new file mode 100644 index 00000000000..dd1b8ef31ce --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/dip22d.d @@ -0,0 +1,12 @@ +/* +REQUIRED_ARGS: -transition=import +TEST_OUTPUT: +--- +fail_compilation/dip22d.d(12): Error: imports.dip22d.Foo at fail_compilation/imports/dip22d.d(3) conflicts with imports.dip22e.Foo at fail_compilation/imports/dip22e.d(3) +fail_compilation/dip22d.d(12): Error: module dip22d struct imports.dip22d.Foo is private +--- +*/ +import imports.dip22d; +import imports.dip22e; + +Foo foo; diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22e.d b/gcc/testsuite/gdc.test/fail_compilation/dip22e.d new file mode 100644 index 00000000000..f82d8e73cda --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/dip22e.d @@ -0,0 +1,18 @@ +/* +REQUIRED_ARGS: -transition=checkimports -de +TEST_OUTPUT: +--- +fail_compilation/dip22e.d(16): Deprecation: imports.dip22d.foo is not visible from module dip22e +fail_compilation/dip22e.d(16): Error: function `imports.dip22d.foo` is not accessible from module `dip22e` +fail_compilation/dip22e.d(17): Deprecation: local import search method found overloadset dip22e.bar (2 overloads) instead of function imports.dip22e.bar +--- +*/ + +import imports.dip22d; +import imports.dip22e; + +void test() +{ + foo(); + bar(12); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/disable.d b/gcc/testsuite/gdc.test/fail_compilation/disable.d new file mode 100644 index 00000000000..517fddd9940 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/disable.d @@ -0,0 +1,77 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/disable.d(50): Error: function disable.DisabledOpAssign.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(53): Error: function disable.DisabledPostblit.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(56): Error: function disable.HasDtor.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(60): Error: generated function disable.Nested!(DisabledOpAssign).Nested.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(63): Error: generated function disable.Nested!(DisabledPostblit).Nested.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(66): Error: generated function disable.Nested!(HasDtor).Nested.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(70): Error: generated function disable.NestedDtor!(DisabledOpAssign).NestedDtor.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(73): Error: generated function disable.NestedDtor!(DisabledPostblit).NestedDtor.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(76): Error: generated function disable.NestedDtor!(HasDtor).NestedDtor.opAssign is not callable because it is annotated with @disable +--- + */ +struct DisabledOpAssign { + int x; + @disable void opAssign(const DisabledOpAssign); +} + +struct DisabledPostblit { + int x; + @disable void opAssign(const DisabledPostblit); + // Doesn't require opAssign + @disable this(this); +} + +struct HasDtor { + int x; + @disable void opAssign(const HasDtor); + ~this() {} // Makes opAssign mandatory +} + + +struct Nested (T) +{ + T b; +} + +struct NestedDtor (T) +{ + T b; + + // Requires an identity opAssign + ~this() {} +} + +void main () +{ + DisabledOpAssign o; + o = DisabledOpAssign(); + + DisabledPostblit p; + p = DisabledPostblit(); + + HasDtor d; + d = HasDtor(); + + + Nested!(DisabledOpAssign) no; + no = Nested!(DisabledOpAssign)(); + + Nested!(DisabledPostblit) np; + np = Nested!(DisabledPostblit)(); + + Nested!(HasDtor) nd; + nd = Nested!(HasDtor)(); + + + NestedDtor!(DisabledOpAssign) ndo; + ndo = NestedDtor!(DisabledOpAssign)(); + + NestedDtor!(DisabledPostblit) ndp; + ndp = NestedDtor!(DisabledPostblit)(); + + NestedDtor!(HasDtor) ndd; + ndd = NestedDtor!(HasDtor)(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/enum9921.d b/gcc/testsuite/gdc.test/fail_compilation/enum9921.d new file mode 100644 index 00000000000..54c76b9f5cd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/enum9921.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/enum9921.d(9): Error: enum enum9921.X base type must not be void +fail_compilation/enum9921.d(11): Error: enum enum9921.Z base type must not be void +--- +*/ + +enum X : void; + +enum Z : void { Y }; diff --git a/gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d b/gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d new file mode 100644 index 00000000000..5e19c1e7501 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d @@ -0,0 +1,6 @@ +module a14446; + +struct CDBMaker +{ + import ice14446; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/extra-files/bar11453.d b/gcc/testsuite/gdc.test/fail_compilation/extra-files/bar11453.d new file mode 100644 index 00000000000..126e0f9c7ef --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/extra-files/bar11453.d @@ -0,0 +1 @@ +module foo11453.bar11453; diff --git a/gcc/testsuite/gdc.test/fail_compilation/extra-files/foo11453.d b/gcc/testsuite/gdc.test/fail_compilation/extra-files/foo11453.d new file mode 100644 index 00000000000..c97e3e1ed30 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/extra-files/foo11453.d @@ -0,0 +1 @@ +module foo11453; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10.d b/gcc/testsuite/gdc.test/fail_compilation/fail10.d new file mode 100644 index 00000000000..9d73537216d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10.d(18): Error: mixin Foo!y cannot resolve forward reference +--- +*/ + +template Foo(alias b) +{ + int a() + { + return b; + } +} + +void test() +{ + mixin Foo!(y) y; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail100.d b/gcc/testsuite/gdc.test/fail_compilation/fail100.d new file mode 100644 index 00000000000..1dd80508a6a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail100.d @@ -0,0 +1,38 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail100.d(24): Error: cannot implicitly convert expression `f` of type `Class[]` to `I[]` +--- +*/ + +// Issue 85 - Array of classes doesn't function as array of interfaces + +interface I +{ + I[] foo(); + uint x(); +} + +class Class : I +{ + I[] foo() + { + // changing this to I[] f = new Class[1] fixes the bug + Class[] f = new Class[1]; + //I[] f = new Class[1]; + f[0] = new Class; + return f; + } + + uint x() + { + return 0; + } +} + +void main() +{ + Class c = new Class(); + assert(c.x == 0); + assert(c.foo[0].x == 0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10082.d b/gcc/testsuite/gdc.test/fail_compilation/fail10082.d new file mode 100644 index 00000000000..fd3080109d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10082.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10082.d(24): Error: cannot infer type from overloaded function symbol &foo +--- +*/ + +mixin template T() +{ + int foo() + { + return 0; + } +} + +class A +{ + mixin T; + mixin T; +} + +void main() +{ + auto x = &A.foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail101.d b/gcc/testsuite/gdc.test/fail_compilation/fail101.d new file mode 100644 index 00000000000..35d23e3edd2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail101.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail101.d(8): Error: cannot implicitly convert expression `1` of type `int` to `creal` +--- +*/ + +creal c = 1; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10102.d b/gcc/testsuite/gdc.test/fail_compilation/fail10102.d new file mode 100644 index 00000000000..2c974ea90c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10102.d @@ -0,0 +1,52 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10102.d(48): Error: variable fail10102.main.m default construction is disabled for type NotNull!(int*) +fail_compilation/fail10102.d(49): Error: variable fail10102.main.a default construction is disabled for type NotNull!(int*)[3] +fail_compilation/fail10102.d(50): Error: default construction is disabled for type NotNull!(int*) +fail_compilation/fail10102.d(51): Error: field `S.m` must be initialized because it has no default constructor +--- +*/ + +struct NotNull(T) +{ + T p; + + alias p this; + + this(T p) + { + assert(p != null, "pointer is null"); + this.p = p; + } + + @disable this(); + + NotNull opAssign(T p) + { + assert(p != null, "assigning null to NotNull"); + this.p = p; + return this; + } +} + +void main() +{ + struct S + { + NotNull!(int *) m; + // should fail: an explicit constructor must be required for S + } + + int i; + NotNull!(int*) n = &i; + *n = 3; + assert(i == 3); + n = &i; + n += 1; + + NotNull!(int*) m; // should fail + NotNull!(int*)[3] a; // should fail + auto b = new NotNull!(int*)[3]; // should fail + S s = S(); // should fail +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10115.d b/gcc/testsuite/gdc.test/fail_compilation/fail10115.d new file mode 100644 index 00000000000..e94ae876e8e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10115.d @@ -0,0 +1,48 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10115.d(35): Error: cannot have out parameter of type S because the default construction is disabled +fail_compilation/fail10115.d(35): Error: cannot have out parameter of type E because the default construction is disabled +fail_compilation/fail10115.d(35): Error: cannot have out parameter of type U because the default construction is disabled +fail_compilation/fail10115.d(40): Error: struct fail10115.S default construction is disabled +fail_compilation/fail10115.d(41): Error: struct fail10115.S default construction is disabled +fail_compilation/fail10115.d(42): Error: union fail10115.U default construction is disabled +--- +*/ + +struct S +{ + int a; + @disable this(); + //this(int) { a = 1; } + //~this() { assert(a !is 0); } +} + +enum E : S +{ + A = S.init +} + +union U +{ + S s; + //this(this) { assert (s.a !is 0); } + //~this() { assert (s.a !is 0); } +} + +void main() +{ + void foo(out S s, out E e, out U u) { } + + S[] a; + E[] e; + U[] u; + a.length = 5; // compiles -> NG + e.length = 5; // compiles -> NG + u.length = 5; // compiles -> NG + + S[1] x = (S[1]).init; + foo(a[0], // compiles -> NG + e[0], // compiles -> NG + u[0]); // compiles -> NG +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10207.d b/gcc/testsuite/gdc.test/fail_compilation/fail10207.d new file mode 100644 index 00000000000..ac8b4eef11a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10207.d @@ -0,0 +1,7 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10207.d(7): Error: user defined attributes not allowed for `alias` declarations +--- +*/ +alias @Safe int __externC; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10254.d b/gcc/testsuite/gdc.test/fail_compilation/fail10254.d new file mode 100644 index 00000000000..0d402e12b85 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10254.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10254.d(18): Error: pure function 'fail10254.foo' cannot call impure constructor 'fail10254.C.this' +fail_compilation/fail10254.d(18): Error: @safe function 'fail10254.foo' cannot call @system constructor 'fail10254.C.this' +fail_compilation/fail10254.d(19): Error: pure function 'fail10254.foo' cannot call impure constructor 'fail10254.S.this' +fail_compilation/fail10254.d(19): Error: @safe function 'fail10254.foo' cannot call @system constructor 'fail10254.S.this' +--- +*/ + +int a; + +class C { this() { a = 2; } } +struct S { this(int) { a = 2; } } + +void foo() pure @safe +{ + auto c = new C; // This line should be a compilation error. + auto s = new S(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10277.d b/gcc/testsuite/gdc.test/fail_compilation/fail10277.d new file mode 100644 index 00000000000..6173d37c2e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10277.d @@ -0,0 +1,29 @@ +module fail10227; + +/* +TEST_OUTPUT: +--- +fail_compilation/imports/fail10277.d(3): Error: class TypeInfo only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(4): Error: class TypeInfo_Class only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(5): Error: class TypeInfo_Interface only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(6): Error: class TypeInfo_Struct only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(8): Error: class TypeInfo_Pointer only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(9): Error: class TypeInfo_Array only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(10): Error: class TypeInfo_AssociativeArray only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(11): Error: class TypeInfo_Enum only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(12): Error: class TypeInfo_Function only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(13): Error: class TypeInfo_Delegate only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(14): Error: class TypeInfo_Tuple only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(15): Error: class TypeInfo_Const only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(16): Error: class TypeInfo_Invariant only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(17): Error: class TypeInfo_Shared only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(18): Error: class TypeInfo_Inout only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(19): Error: class TypeInfo_Vector only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(20): Error: class Object only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(21): Error: class Throwable only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(22): Error: class Exception only object.d can define this reserved class name +fail_compilation/imports/fail10277.d(23): Error: class Error only object.d can define this reserved class name +--- +*/ + +import imports.fail10277; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10285.d b/gcc/testsuite/gdc.test/fail_compilation/fail10285.d new file mode 100644 index 00000000000..3277b19e2aa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10285.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10285.d(9): Error: no identifier for declarator `int` +--- +*/ +enum +{ + int = 5 +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10299.d b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d new file mode 100644 index 00000000000..29475aa849a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10299.d(11): Error: foo!string is not an lvalue +--- +*/ + +template foo(T) +{ +} +auto fp = &foo!string; // ICE diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10346.d b/gcc/testsuite/gdc.test/fail_compilation/fail10346.d new file mode 100644 index 00000000000..304c00d58fb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10346.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10346.d(9): Error: undefined identifier `T` +--- +*/ + +struct Foo(T) {} +void bar(T x, T)(Foo!T) {} +void main() +{ + Foo!int spam; + bar!10(spam); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail104.d b/gcc/testsuite/gdc.test/fail_compilation/fail104.d new file mode 100644 index 00000000000..7e455f37532 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail104.d @@ -0,0 +1,25 @@ +// Issue 76 - Using a non-template struct as a template +// Compiling leads to "Assertion failure: 's->parent' on line 1694 in file +// 'template.c'" + +struct S +{ + template T() + { + void x(int i) + { + } + } +} + +class C(P) +{ + mixin P!().T!(); +} + +int main(char[][] args) +{ + auto c = new C!(S); + + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10481.d b/gcc/testsuite/gdc.test/fail_compilation/fail10481.d new file mode 100644 index 00000000000..878cbe8f05e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10481.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10481.d(11): Error: undefined identifier `T1`, did you mean alias `T0`? +fail_compilation/fail10481.d(15): Error: cannot infer type from template instance get!(A) +--- +*/ + +struct A {} + +void get(T0 = T1.Req, Params...)(Params , T1) {} + +void main() +{ + auto xxx = get!A; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail105.d b/gcc/testsuite/gdc.test/fail_compilation/fail105.d new file mode 100644 index 00000000000..8702cac2f12 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail105.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail105.d(11): Error: cannot cast "bar" to int at compile time +--- +*/ + +//int foo = "foo"; + +// just Access Violation happens. +int bar = cast(int)cast(char*)"bar"; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10528.d b/gcc/testsuite/gdc.test/fail_compilation/fail10528.d new file mode 100644 index 00000000000..c05a29a39c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10528.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10528.d(23): Error: module fail10528 variable a10528.a is private +fail_compilation/fail10528.d(23): Deprecation: a10528.a is not visible from module fail10528 +fail_compilation/fail10528.d(24): Error: a10528.a is not visible from module fail10528 +fail_compilation/fail10528.d(26): Error: module fail10528 enum member a10528.b is private +fail_compilation/fail10528.d(26): Deprecation: a10528.b is not visible from module fail10528 +fail_compilation/fail10528.d(27): Error: a10528.b is not visible from module fail10528 +fail_compilation/fail10528.d(29): Deprecation: a10528.S.c is not visible from module fail10528 +fail_compilation/fail10528.d(29): Error: variable `a10528.S.c` is not accessible from module `fail10528` +fail_compilation/fail10528.d(30): Error: variable `a10528.S.c` is not accessible from module `fail10528` +fail_compilation/fail10528.d(32): Deprecation: a10528.C.d is not visible from module fail10528 +fail_compilation/fail10528.d(32): Error: variable `a10528.C.d` is not accessible from module `fail10528` +fail_compilation/fail10528.d(33): Error: variable `a10528.C.d` is not accessible from module `fail10528` +--- +*/ + +import imports.a10528; + +void main() +{ + auto a1 = a; + auto a2 = imports.a10528.a; + + auto b1 = b; + auto b2 = imports.a10528.b; + + auto c1 = S.c; + with (S) auto c2 = c; + + auto d1 = C.d; + with (C) auto d2 = d; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10534.d b/gcc/testsuite/gdc.test/fail_compilation/fail10534.d new file mode 100644 index 00000000000..2516135089e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10534.d @@ -0,0 +1,41 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10534.d(28): Error: 'a' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(28): Error: 'b' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(29): Error: 'a' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(29): Error: 'b' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(30): Error: 'a' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(30): Error: 'b' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(31): Error: 'a' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(31): Error: 'b' is not of arithmetic type, it is a int delegate() +fail_compilation/fail10534.d(36): Error: 'a' is not of arithmetic type, it is a int function() +fail_compilation/fail10534.d(36): Error: 'b' is not of arithmetic type, it is a int function() +fail_compilation/fail10534.d(37): Error: 'a' is not of arithmetic type, it is a int function() +fail_compilation/fail10534.d(37): Error: 'b' is not of arithmetic type, it is a int function() +fail_compilation/fail10534.d(38): Error: 'a' is not of arithmetic type, it is a int function() +fail_compilation/fail10534.d(38): Error: 'b' is not of arithmetic type, it is a int function() +fail_compilation/fail10534.d(39): Error: 'a' is not of arithmetic type, it is a int function() +fail_compilation/fail10534.d(39): Error: 'b' is not of arithmetic type, it is a int function() +--- +*/ + +void main() +{ + { + int delegate() a = ()=>5; + int delegate() b = ()=>5; + auto c1 = a + b; // passes (and will crash if c1() called) + auto c2 = a - b; // passes (and will crash if c2() called) + auto c3 = a / b; // a & b not of arithmetic type + auto c4 = a * b; // a & b not of arithmetic type + } + { + int function() a = ()=>5; + int function() b = ()=>5; + auto c1 = a + b; + auto c2 = a - b; + auto c3 = a / b; + auto c4 = a * b; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail106.d b/gcc/testsuite/gdc.test/fail_compilation/fail106.d new file mode 100644 index 00000000000..f6dc2eaadd6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail106.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail106.d(12): Error: cannot modify immutable expression 'C' +--- +*/ + +// Issue 239 - Internal error: changing string literal elements + +void main() +{ + "ABC"[2] = 's'; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10630.d b/gcc/testsuite/gdc.test/fail_compilation/fail10630.d new file mode 100644 index 00000000000..738bdd14e34 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10630.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10630.d(12): Error: cannot have out parameter of type S because the default construction is disabled +--- +*/ + +struct S +{ + @disable this(); +} +void foo(out S) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10666.d b/gcc/testsuite/gdc.test/fail_compilation/fail10666.d new file mode 100644 index 00000000000..2e1747d4d2b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10666.d @@ -0,0 +1,22 @@ +// REQUIRED_ARGS: -c +/* +TEST_OUTPUT: +--- +fail_compilation/fail10666.d(16): Error: variable fail10666.foo10666.s1 has scoped destruction, cannot build closure +--- +*/ + + +struct S10666 +{ + int val; + ~this() {} +} + +void foo10666(S10666 s1) +{ + auto f1 = (){ return () => s1.val; }(); // NG + + S10666 s2; + auto f2 = (){ return () => s2.val; }(); // (should be NG) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail109.d b/gcc/testsuite/gdc.test/fail_compilation/fail109.d new file mode 100644 index 00000000000..4fd53213385 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail109.d @@ -0,0 +1,92 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail109.d(12): Error: enum member fail109.Bool.Unknown initialization with `Bool.True+1` causes overflow for type `bool` +--- +*/ + +enum Bool : bool +{ + False, + True, + Unknown +} + +/* Bugzilla 11088 +TEST_OUTPUT: +--- +fail_compilation/fail109.d(25): Error: enum member fail109.E.B initialization with `E.A+1` causes overflow for type `int` +fail_compilation/fail109.d(31): Error: enum member fail109.E1.B initialization with `E1.A+1` causes overflow for type `short` +--- +*/ +enum E +{ + A = int.max, + B +} + +enum E1 : short +{ + A = short.max, + B +} + +/* Bugzilla 14950 +TEST_OUTPUT: +--- +fail_compilation/fail109.d(50): Deprecation: Comparison between different enumeration types `B` and `C`; If this behavior is intended consider using `std.conv.asOriginalType` +fail_compilation/fail109.d(50): Error: enum member fail109.B.end initialization with `B.start+1` causes overflow for type `C` +--- +*/ +enum C +{ + start, + end +} + +enum B +{ + start = C.end, + end +} + +/* Bugzilla 11849 +TEST_OUTPUT: +--- +fail_compilation/fail109.d(72): Error: enum fail109.RegValueType1a recursive definition of `.max` property +fail_compilation/fail109.d(79): Error: enum fail109.RegValueType1b recursive definition of `.max` property +fail_compilation/fail109.d(84): Error: enum fail109.RegValueType2a recursive definition of `.min` property +fail_compilation/fail109.d(91): Error: enum fail109.RegValueType2b recursive definition of `.min` property +--- +*/ + +alias DWORD = uint; + +enum : DWORD +{ + REG_DWORD = 4 +} + +enum RegValueType1a : DWORD +{ + Unknown = DWORD.max, + DWORD = REG_DWORD, +} + +enum RegValueType1b : DWORD +{ + DWORD = REG_DWORD, + Unknown = DWORD.max, +} + +enum RegValueType2a : DWORD +{ + Unknown = DWORD.min, + DWORD = REG_DWORD, +} + +enum RegValueType2b : DWORD +{ + DWORD = REG_DWORD, + Unknown = DWORD.min, +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10905.d b/gcc/testsuite/gdc.test/fail_compilation/fail10905.d new file mode 100644 index 00000000000..2028648d308 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10905.d @@ -0,0 +1,16 @@ + +struct Foo +{ + enum __vector(long[2]) y = 1; +} + +struct Bar +{ + __vector(long[2]) x; + + bool spam() const + { + return x == Foo.y; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10947.d b/gcc/testsuite/gdc.test/fail_compilation/fail10947.d new file mode 100644 index 00000000000..da847809a22 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10947.d @@ -0,0 +1,31 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10947.d(21): Error: cannot have immutable out parameter of type immutable(S) +fail_compilation/fail10947.d(22): Error: cannot have immutable out parameter of type immutable(S) +fail_compilation/fail10947.d(23): Error: cannot have immutable out parameter of type immutable(S) +fail_compilation/fail10947.d(25): Error: cannot have const out parameter of type const(S) +fail_compilation/fail10947.d(26): Error: cannot have const out parameter of type const(S) +fail_compilation/fail10947.d(27): Error: cannot have const out parameter of type const(S) +fail_compilation/fail10947.d(29): Error: cannot have inout out parameter of type inout(S) +fail_compilation/fail10947.d(30): Error: cannot have inout out parameter of type inout(S) +fail_compilation/fail10947.d(31): Error: cannot have inout out parameter of type inout(S) +--- +*/ + +struct S {} +alias SI = immutable S; +alias SC = const S; +alias SW = inout S; + +void fooi1(out SI) {} +void fooi2(out immutable(S)) {} +void fooi3(out immutable S) {} + +void fooc1(out SC) {} +void fooc2(out const(S)) {} +void fooc3(out const S) {} + +void foow1(out SW) {} +void foow2(out inout(S)) {} +void foow3(out inout S) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d new file mode 100644 index 00000000000..7b7c826d354 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d @@ -0,0 +1,36 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10964.d(28): Error: function `fail10964.S.__postblit` is not nothrow +fail_compilation/fail10964.d(29): Error: function `fail10964.S.__postblit` is not nothrow +fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is not nothrow +fail_compilation/fail10964.d(33): Error: function `fail10964.S.__postblit` is not nothrow +fail_compilation/fail10964.d(34): Error: function `fail10964.S.__postblit` is not nothrow +fail_compilation/fail10964.d(35): Error: function `fail10964.S.__postblit` is not nothrow +fail_compilation/fail10964.d(22): Error: nothrow function `fail10964.foo` may throw +--- +*/ + +struct S +{ + this(this) + { + throw new Exception("BOOM!"); + } +} + +void foo() nothrow +{ + S ss; + S[1] sa; + + // TOKassign + ss = ss; + sa = ss; + sa = sa; + + // TOKconstruct + S ss2 = ss; + S[1] sa2 = ss; + S[1] sa3 = sa; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d new file mode 100644 index 00000000000..ef75f910180 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d @@ -0,0 +1,74 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10968.d(33): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(33): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(34): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(34): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(35): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(35): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(38): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(38): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(39): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(39): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(40): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit' +fail_compilation/fail10968.d(40): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit' +--- +*/ + +struct SA +{ + this(this) + { + throw new Exception("BOOM!"); + } +} + +void bar() pure @safe +{ + SA ss; + SA[1] sa; + + // TOKassign + ss = ss; + sa = ss; + sa = sa; + + // TOKconstruct + SA ss2 = ss; + SA[1] sa2 = ss; + SA[1] sa3 = sa; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail10968.d(66): Error: struct fail10968.SD is not copyable because it is annotated with @disable +fail_compilation/fail10968.d(67): Error: struct fail10968.SD is not copyable because it is annotated with @disable +fail_compilation/fail10968.d(68): Error: struct fail10968.SD is not copyable because it is annotated with @disable +fail_compilation/fail10968.d(71): Error: struct fail10968.SD is not copyable because it is annotated with @disable +fail_compilation/fail10968.d(72): Error: struct fail10968.SD is not copyable because it is annotated with @disable +fail_compilation/fail10968.d(73): Error: struct fail10968.SD is not copyable because it is annotated with @disable +--- +*/ + +struct SD +{ + this(this) @disable; +} + +void baz() +{ + SD ss; + SD[1] sa; + + // TOKassign + ss = ss; + sa = ss; + sa = sa; + + // TOKconstruct + SD ss2 = ss; + SD[1] sa2 = ss; + SD[1] sa3 = sa; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10980.d b/gcc/testsuite/gdc.test/fail_compilation/fail10980.d new file mode 100644 index 00000000000..eb50de34ebe --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10980.d @@ -0,0 +1,44 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail10980.d(22): Error: variable fail10980.s1b of type struct immutable(S1) uses this(this), which is not allowed in static initialization +fail_compilation/fail10980.d(28): Error: variable fail10980.s1d of type struct immutable(S1) uses this(this), which is not allowed in static initialization +fail_compilation/fail10980.d(27): Error: static variable s1x cannot be read at compile time +fail_compilation/fail10980.d(28): called from here: bar1() +fail_compilation/fail10980.d(38): Error: variable fail10980.s2b of type struct immutable(S2) uses this(this), which is not allowed in static initialization +fail_compilation/fail10980.d(44): Error: variable fail10980.s2d of type struct immutable(S2) uses this(this), which is not allowed in static initialization +fail_compilation/fail10980.d(43): Error: static variable s2x cannot be read at compile time +fail_compilation/fail10980.d(44): called from here: bar2() +--- +*/ + +struct S1 +{ + this(int) immutable {} + this(this) {} +} +alias immutable(S1) IS1; +static immutable S1 s1a = IS1(1); // OK +static immutable S1 s1b = s1a; // NG + +S1 foo1() { S1 s1x; S1 s1y = s1x; return s1y; } +static immutable S1 s1c = foo1(); // OK + +ref S1 bar1() { static S1 s1x; return s1x; } +static immutable S1 s1d = bar1(); // NG + + +struct S2 +{ + int val; + this(this) {} +} +alias immutable(S2) IS2; +static immutable S2 s2a = IS2(1); // OK +static immutable S2 s2b = s2a; // NG + +S2 foo2() { S2 s2x; S2 s2y = s2x; return s2y; } +static immutable S2 s2c = foo2(); // OK + +ref S2 bar2() { static S2 s2x; return s2x; } +static immutable S2 s2d = bar2(); // NG diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11.d b/gcc/testsuite/gdc.test/fail_compilation/fail11.d new file mode 100644 index 00000000000..524e6154805 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11.d(12): Error: `type` has no effect in expression `int*` +--- +*/ + +// http://forum.dlang.org/thread/c738o9$1p7i$1@digitaldaemon.com + +void main() +{ + TFoo!(int).t; // should produce a "no identifier" error. +} +template TFoo(T) { alias T* t; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail110.d b/gcc/testsuite/gdc.test/fail_compilation/fail110.d new file mode 100644 index 00000000000..3e9beb02121 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail110.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail110.d(16): Error: variable i is shadowing variable fail110.main.i +fail_compilation/fail110.d(17): Error: variable i is shadowing variable fail110.main.i +fail_compilation/fail110.d(18): Error: variable i is shadowing variable fail110.main.i +--- +*/ + +// Issue 297 - Shadowing declarations allowed in foreach type lists + +void main() +{ + int i; + int[] a; + foreach (i; a) {} + foreach (int i, n; a) {} + for (int i;;) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11042.d b/gcc/testsuite/gdc.test/fail_compilation/fail11042.d new file mode 100644 index 00000000000..6123f175e70 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11042.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11042.d(8): Error: undefined identifier `error`, did you mean class `Error`? +fail_compilation/fail11042.d(9): Error: undefined identifier `error`, did you mean class `Error`? +--- +*/ +static if ({ return true || error; }()) {} // NG +static if ({ return false && error; }()) {} // NG diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail111.d b/gcc/testsuite/gdc.test/fail_compilation/fail111.d new file mode 100644 index 00000000000..3a5fed4b06f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail111.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail111.d(12): Error: can't have array of int(int) +--- +*/ + +// Issue 289 - Compiler allows (and crashes on) dynamic arrays of typedefs of "immediate"-function types + +alias int ft(int); + +ft[] x; // is allowed + +void test() +{ + x.length = 2; // crashes DMD +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11125.d b/gcc/testsuite/gdc.test/fail_compilation/fail11125.d new file mode 100644 index 00000000000..b42cb88d1eb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11125.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11125.d(20): Error: template instance fail11125.filter!(function (int a) => a + 1) does not match template declaration filter(alias predfun) if (is(ReturnType!predfun == bool)) +fail_compilation/fail11125.d(21): Error: template instance fail11125.filter!(function (int a) => a + 1) does not match template declaration filter(alias predfun) if (is(ReturnType!predfun == bool)) +--- +*/ + +template ReturnType(alias fun) { alias int ReturnType; } + +template filter(alias predfun) + if (is(ReturnType!predfun == bool)) +{ + static assert(is(ReturnType!predfun == bool)); + auto filter(Range)(Range r) { } +} + +void main() +{ + filter!((int a) => a + 1)([1]); // fails in constraint + [1].filter!((int a) => a + 1); // fails internally in static assert! +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11151.d b/gcc/testsuite/gdc.test/fail_compilation/fail11151.d new file mode 100644 index 00000000000..61843174c57 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11151.d @@ -0,0 +1,36 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11151.d(30): Error: overlapping initialization for field a and y +--- +*/ + +//extern(C) int printf(const char*, ...); + +union U +{ + struct + { + align(1) long a; + align(1) int b; + } + struct + { + align(1) int x; + align(1) long y; + } +} +void main() +{ + static assert(U.a.offsetof == 0); + static assert(U.b.offsetof == 8); + static assert(U.x.offsetof == 0); + static assert(U.y.offsetof == 4); + + U u = {a:1, y:2}; // overlapped initializing U.a and U.y + + //printf("u.a = %lld\n", u.a); // 8589934593 , Wrong! + //printf("u.b = %d\n", u.b); // 0 + //printf("u.x = %d\n", u.x); // 1 + //printf("u.y = %lld\n", u.y); // 2 +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11163.d b/gcc/testsuite/gdc.test/fail_compilation/fail11163.d new file mode 100644 index 00000000000..3966c05e5e9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11163.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11163.d(12): Error: cannot implicitly convert expression `foo()` of type `int[]` to `immutable(int[])` +fail_compilation/fail11163.d(13): while evaluating pragma(msg, a) +--- +*/ +int[] foo() { + return [1]; +} +void main() { + immutable a = foo(); + pragma(msg, a); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11169.d b/gcc/testsuite/gdc.test/fail_compilation/fail11169.d new file mode 100644 index 00000000000..e6ab4a64886 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11169.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11169.d(16): Error: error evaluating static if expression +--- +*/ + +class A +{ + abstract void foo(); +} + +class B : A +{ + // __traits(isAbstractClass) is not usable in static if condition. + static if (__traits(isAbstractClass, typeof(this))) + { + } + + override void foo() + { + } +} + +void main() +{ + B b = new B(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail113.d b/gcc/testsuite/gdc.test/fail_compilation/fail113.d new file mode 100644 index 00000000000..8271b025d40 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail113.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail113.d(10): Error: forward reference to 'test' +--- +*/ + +// Issue 370 - Compiler stack overflow on recursive typeof in function declaration. + +void test(typeof(test) p) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11355.d b/gcc/testsuite/gdc.test/fail_compilation/fail11355.d new file mode 100644 index 00000000000..474d376794f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11355.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11355.d(28): Error: struct fail11355.A is not copyable because it is annotated with @disable +--- +*/ + +T move(T)(ref T source) +{ + return T.init; // Dummy rvalue +} + +struct A +{ + ~this() {} + @disable this(this); // Prevent copying +} + +struct B +{ + A a; + alias a this; +} + +void main() +{ + B b; + A a = move(b); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d new file mode 100644 index 00000000000..ba27a08641f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not nothrow +fail_compilation/fail11375.d(15): Error: nothrow function `D main` may throw +--- +*/ + +class B { + this() {} +} + +class D() : B {} + +void main() nothrow +{ + auto d = new D!()(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail114.d b/gcc/testsuite/gdc.test/fail_compilation/fail114.d new file mode 100644 index 00000000000..5bb9cec8a81 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail114.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail114.d(12): Error: forward reference to 'funcA' +--- +*/ + +// Issue 371 - ICE on mutual recursive typeof in function declarations + +void funcA(typeof(&funcB) p) {} + +void funcB(typeof(&funcA) p) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11426.d b/gcc/testsuite/gdc.test/fail_compilation/fail11426.d new file mode 100644 index 00000000000..7b2dc4fd6e5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11426.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11426.d(15): Error: cannot implicitly convert expression `udarr` of type `uint[]` to `int[]` +fail_compilation/fail11426.d(16): Error: cannot implicitly convert expression `usarr` of type `uint[1]` to `int[]` +fail_compilation/fail11426.d(18): Error: cannot implicitly convert expression `udarr` of type `uint[]` to `int[]` +fail_compilation/fail11426.d(19): Error: cannot implicitly convert expression `usarr` of type `uint[1]` to `int[]` +--- +*/ +void main() +{ + uint[] udarr; + uint[1] usarr; + + int[1] arr1; arr1 = udarr; // Error, OK + int[1] arr2; arr2 = usarr; // Error, OK + + int[1] arr3 = udarr; // accepted, BAD! + int[1] arr4 = usarr; // accepted, BAD! +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11445.d b/gcc/testsuite/gdc.test/fail_compilation/fail11445.d new file mode 100644 index 00000000000..a3cfc11ed19 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11445.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11445.d(11): Error: incompatible types for ((a) + (b)): 'double[string]' and 'double[string]' +--- +*/ + +void main() { + double[string] a = [ "foo" : 22.2 ]; + double[string] b = [ "bar" : 22.2 ]; + auto c = a + b; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11453a.d b/gcc/testsuite/gdc.test/fail_compilation/fail11453a.d new file mode 100644 index 00000000000..488bc6e0ff9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11453a.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -Ifail_compilation/extra-files +// EXTRA_SOURCES: extra-files/foo11453.d extra-files/bar11453.d +/* +TEST_OUTPUT +--- +fail_compilation/extra-files/bar11453.d(1): Error: package name 'foo11453' conflicts with usage as a module name in file fail_compilation/extra-files/foo11453.d +--- +*/ + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11453b.d b/gcc/testsuite/gdc.test/fail_compilation/fail11453b.d new file mode 100644 index 00000000000..c7bdce5ef83 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11453b.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -Ifail_compilation/extra-files +// EXTRA_SOURCES: extra-files/bar11453.d extra-files/foo11453.d +/* +TEST_OUTPUT +--- +fail_compilation/extra-files/foo11453.d(1): Error: module foo11453 from file fail_compilation/extra-files/foo11453.d conflicts with package name foo11453 +--- +*/ + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail115.d b/gcc/testsuite/gdc.test/fail_compilation/fail115.d new file mode 100644 index 00000000000..e9d5a67d293 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail115.d @@ -0,0 +1,11 @@ +// Issue 402 - compiler crash with mixin and forward reference + +template Foo(alias b) +{ + int a() { return b; } +} + +void main() +{ + mixin Foo!(y) y; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11503a.d b/gcc/testsuite/gdc.test/fail_compilation/fail11503a.d new file mode 100644 index 00000000000..28f7befdf91 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11503a.d @@ -0,0 +1,21 @@ +struct S +{ + immutable(S)* s; + this(int) immutable pure + { + s = &this; + } + int data; +} + +immutable(S)* makes() pure +{ + return new immutable S(0); +} + +void main() +{ + S* s = makes(); // s is mutable and contains an immutable reference to itself + //s.s.data = 7; // this is immutable + s.data = 3; // but this is not!!! +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11503b.d b/gcc/testsuite/gdc.test/fail_compilation/fail11503b.d new file mode 100644 index 00000000000..80549de8e6c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11503b.d @@ -0,0 +1,13 @@ +immutable int[] x = [1, 2, 3]; + +auto makes() pure +{ + return x; +} + +int main() +{ + auto a = x; + int[] b = makes(); + return b[1]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11503c.d b/gcc/testsuite/gdc.test/fail_compilation/fail11503c.d new file mode 100644 index 00000000000..dc45eefc093 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11503c.d @@ -0,0 +1,15 @@ +struct Data +{ + char[256] buffer; + @property const(char)[] filename() const pure nothrow + { + return buffer[]; + } +} + +void main() +{ + Data d; + string f = d.filename; + d.buffer[0] = 'a'; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11503d.d b/gcc/testsuite/gdc.test/fail_compilation/fail11503d.d new file mode 100644 index 00000000000..d96e2a8b249 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11503d.d @@ -0,0 +1,22 @@ +struct Data2 +{ + char buffer; +} + +@property const(char)[] filename(const ref Data2 d) pure nothrow +{ + return (&d.buffer)[0 .. 1]; +} + +@property const(char)[] filename2(const Data2* d) pure nothrow +{ + return (&d.buffer)[0 .. 1]; +} + +void main() +{ + Data2 d; + string f = d.filename; + string g = (&d).filename2; + d.buffer = 'a'; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11510.d b/gcc/testsuite/gdc.test/fail_compilation/fail11510.d new file mode 100644 index 00000000000..13913a0a46d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11510.d @@ -0,0 +1,40 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11510.d(25): Error: reinterpretation through overlapped field y is not allowed in CTFE +fail_compilation/fail11510.d(29): called from here: test11510a() +fail_compilation/fail11510.d(36): Error: reinterpretation through overlapped field y is not allowed in CTFE +fail_compilation/fail11510.d(40): called from here: test11510b() +--- +*/ + +struct S11510 +{ + union + { + size_t x; + int* y; // pointer field + } +} + +bool test11510a() +{ + S11510 s; + + s.y = [1,2,3].ptr; + auto x = s.x; // reinterpretation + + return true; +} +enum a = test11510a(); + +bool test11510b() +{ + S11510 s; + + s.x = 10; + auto y = s.y; // reinterpretation + + return true; +} +enum b = test11510b(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11532.d b/gcc/testsuite/gdc.test/fail_compilation/fail11532.d new file mode 100644 index 00000000000..7f4c770527e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11532.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11532.d(17): Error: cannot pass static arrays to extern(C) vararg functions +fail_compilation/fail11532.d(18): Error: cannot pass dynamic arrays to extern(C) vararg functions +fail_compilation/fail11532.d(19): Error: cannot pass static arrays to extern(C++) vararg functions +fail_compilation/fail11532.d(20): Error: cannot pass dynamic arrays to extern(C++) vararg functions +--- +*/ + +extern(C) void cvararg(int, ...); +extern(C++) void cppvararg(int, ...); + +void main() +{ + int[2] arr = [0x99999999, 0x88888888]; + cvararg(0, arr); + cvararg(0, arr[]); + cppvararg(0, arr); + cppvararg(0, arr[]); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11542.d b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d new file mode 100644 index 00000000000..22d29ac5570 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d @@ -0,0 +1,73 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/fail11542.d(16): Error: `object.Exception` is thrown but not caught +fail_compilation/fail11542.d(13): Error: nothrow function `fail11542.test_success1` may throw +fail_compilation/fail11542.d(26): Error: `object.Exception` is thrown but not caught +fail_compilation/fail11542.d(23): Error: nothrow function `fail11542.test_success3` may throw +--- +*/ +void test_success1() nothrow +{ + scope(success) {} + throw new Exception(""); // error +} +void test_success2() nothrow +{ + scope(success) {} + throw new Error(""); // no error +} +void test_success3() nothrow +{ + scope(success) assert(0); + throw new Exception(""); // error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail11542.d(39): Error: `object.Exception` is thrown but not caught +fail_compilation/fail11542.d(36): Error: nothrow function `fail11542.test_failure1` may throw +--- +*/ +void test_failure1() nothrow +{ + scope(failure) {} + throw new Exception(""); // error +} +void test_failure2() nothrow +{ + scope(failure) {} + throw new Error(""); // no error +} +void est_failure3() nothrow +{ + scope(failure) assert(0); + throw new Exception(""); // no error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail11542.d(62): Error: `object.Exception` is thrown but not caught +fail_compilation/fail11542.d(59): Error: nothrow function `fail11542.test_exit1` may throw +--- +*/ +void test_exit1() nothrow +{ + scope(exit) {} + throw new Exception(""); // error +} +void test_exit2() nothrow +{ + scope(exit) {} + throw new Error(""); // no error +} +void test_exit3() nothrow +{ + scope(exit) assert(0); + throw new Exception(""); // no error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11545.d b/gcc/testsuite/gdc.test/fail_compilation/fail11545.d new file mode 100644 index 00000000000..514cb87854a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11545.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11545.d(14): Error: need 'this' for 'x' of type 'int' +fail_compilation/fail11545.d(18): Error: need 'this' for 'x' of type 'int' +--- +*/ + +class C +{ + int x = 42; + + int function() f1 = function() { + return x; + }; + + int function() f2 = { + return x; + }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11552.d b/gcc/testsuite/gdc.test/fail_compilation/fail11552.d new file mode 100644 index 00000000000..51165227fbd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11552.d @@ -0,0 +1,13 @@ +/* +REQUIRED_ARGS: -o- +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/fail11552.d(12): Error: label `label` is undefined +--- +*/ + +void main() +{ + goto label; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11562.d b/gcc/testsuite/gdc.test/fail_compilation/fail11562.d new file mode 100644 index 00000000000..0377456a5b3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11562.d @@ -0,0 +1,67 @@ +/* +REQUIRED_ARGS: -o- +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/fail11562.d(16): Error: cannot goto in or out of `finally` block +fail_compilation/fail11562.d(37): Error: cannot goto in or out of `finally` block +fail_compilation/fail11562.d(49): Error: cannot goto in or out of `finally` block +fail_compilation/fail11562.d(64): Error: cannot goto in or out of `finally` block +--- +*/ + +// Goto into finally block (forwards) +int w(bool b) +{ + if (b) goto label; + try + { + } + finally + { + label: {} + } + return 1; +} + +// // Goto into finally block (backwards) +int x(bool b) +{ + try + { + } + finally + { + label: {} + } + if (b) goto label; + return 1; +} + +// Goto out of finally block (forwards) +int y(bool b) +{ + try + { + } + finally + { + if (b) goto label; + } + label: {} + return 1; +} + +// // Goto out of finally block (backwards) +int z(bool b) +{ + label: {} + try + { + } + finally + { + if (b) goto label; + } + return 1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11591b.d b/gcc/testsuite/gdc.test/fail_compilation/fail11591b.d new file mode 100644 index 00000000000..42e89c96459 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11591b.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11591b.d(16): Error: AA key type S11591 does not have 'bool opEquals(ref const S11591) const' +--- +*/ + +struct S11591 +{ + bool opEquals(int i) { return false; } + Object o; // needed to suppress compiler generated opEquals +} + +void test11591() +{ + int[S11591] aa; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail11591b.d(30): Error: AA key type S12307a does not have 'bool opEquals(ref const S12307a) const' +fail_compilation/fail11591b.d(31): Error: AA key type S12307b does not have 'bool opEquals(ref const S12307b) const' +--- +*/ +struct S12307a { bool opEquals(T : typeof(this))(T) { return false; } } + +void test12307() +{ + int[S12307a] aa1; // a + int[S12307b] aa2; // b +} + +struct S12307b { bool opEquals(T : typeof(this))(T) { return false; } } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail116.d b/gcc/testsuite/gdc.test/fail_compilation/fail116.d new file mode 100644 index 00000000000..87e451bcf09 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail116.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail116.d(11): Error: circular typeof definition +fail_compilation/fail116.d(16): Error: template instance square!1.2 does not match template declaration square(_error_ x) +--- +*/ + +// Issue 405 - typeof in TemplateParameterList causes compiletime segmentfault + +template square(typeof(x) x) +{ + const square = x * x; +} + +const b = square!(1.2); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11653.d b/gcc/testsuite/gdc.test/fail_compilation/fail11653.d new file mode 100644 index 00000000000..fa69edb573e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11653.d @@ -0,0 +1,27 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/fail11653.d(19): Deprecation: switch case fallthrough - use 'goto case;' if intended +fail_compilation/fail11653.d(24): Deprecation: switch case fallthrough - use 'goto default;' if intended +--- +*/ + +void main() +{ + int test = 12412; + int output = 0; + switch(test) + { + case 1: + output = 1; + //break; //Oops.. + case 2: .. case 3: + output = 2; + break; + case 4: + output = 3; + default: + output = 4; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail117.d b/gcc/testsuite/gdc.test/fail_compilation/fail117.d new file mode 100644 index 00000000000..f39a48db67c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail117.d @@ -0,0 +1,37 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail117.d(35): Error: expression has no value +fail_compilation/fail117.d(36): Error: expression has no value +--- +*/ + +// Issue 420 - mixin make dmd break + +//import std.stdio; + +template MGettor(alias Fld) +{ + typeof(Fld) opCall() + { + //writefln("getter"); + return Fld; + } +} + +class Foo +{ + int a = 1, + b = 2; + + mixin MGettor!(a) geta; + mixin MGettor!(b) getb; +} + +void main() +{ + auto foo = new Foo; + + int a = foo.geta; + int b = foo.getb; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11717.d b/gcc/testsuite/gdc.test/fail_compilation/fail11717.d new file mode 100644 index 00000000000..c6d505ca02d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11717.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11717.d(13): Error: cannot interpret array literal expression [1, 2, 3, 4] + [1, 2, 3, 4] at compile time +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=11717 + +enum int[4] A = [1,2,3,4]; +enum int[4] B = [1,2,3,4]; +// Internal Compiler Error: non-constant value [1, 2, 3, 4] +enum int[4] C = A[] + B[]; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11720.d b/gcc/testsuite/gdc.test/fail_compilation/fail11720.d new file mode 100644 index 00000000000..8ad1d862d6b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11720.d @@ -0,0 +1,33 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail11720.d(23): Error: declaration fail11720.foo!().foo.temp is already defined in another scope in foo +fail_compilation/fail11720.d(13): Error: template instance fail11720.foo!() error instantiating +fail_compilation/fail11720.d(31): Error: declaration fail11720.bar.temp is already defined in another scope in bar +--- +*/ + +void main() +{ + foo(); + bar(); +} + +alias TypeTuple(T...) = T; + +void foo()() +{ + foreach (T; TypeTuple!(int, double)) + { + static temp = T.stringof; + } +} + +void bar() +{ + foreach (T; TypeTuple!(int, double)) + { + static temp = T.stringof; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11746.d b/gcc/testsuite/gdc.test/fail_compilation/fail11746.d new file mode 100644 index 00000000000..6ca07fc2d1e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11746.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11746.d(18): Error: cannot implicitly convert expression `1` of type `int` to `string` +fail_compilation/fail11746.d(25): Error: cannot implicitly convert expression `1` of type `int` to `string` +fail_compilation/fail11746.d(26): Error: cannot implicitly convert expression `2` of type `int` to `string` +--- +*/ + +string bb(T, U)(T x, U y) +{ + return "3"; +} + +enum E1 +{ + foo = bb(bar, baz), + bar = 1, + baz = "2", +} + +enum E2 +{ + foo = bb(bar, baz), + bar = 1, + baz = 2 +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11748.d b/gcc/testsuite/gdc.test/fail_compilation/fail11748.d new file mode 100644 index 00000000000..95b78fa0340 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11748.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11748.d(12): Error: expression my_function(0) is void and has no value +--- +*/ + +void main() +{ + enum my_template(alias T) = T.stringof; + void my_function(int i) { } + my_template!(my_function(0)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11751.d b/gcc/testsuite/gdc.test/fail_compilation/fail11751.d new file mode 100644 index 00000000000..36d7f9d8e30 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11751.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail11751.d(10): Error: missing exponent +fail_compilation/fail11751.d(10): Error: semicolon expected following auto declaration, not `ABC` +fail_compilation/fail11751.d(10): Error: no identifier for declarator `ABC` +--- +*/ + +auto x = 0x1.FFFFFFFFFFFFFpABC; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail118.d b/gcc/testsuite/gdc.test/fail_compilation/fail118.d new file mode 100644 index 00000000000..e17b954e5d8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail118.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail118.d(26): Error: invalid foreach aggregate `Iter`, define opApply(), range primitives, or use .tupleof +fail_compilation/fail118.d(27): Error: invalid foreach aggregate `Iter`, define opApply(), range primitives, or use .tupleof +--- +*/ + +// Issue 441 - Crash on foreach of mixed-in aggregate. + +template opHackedApply() +{ + struct Iter + { + } +} + +class Foo +{ + mixin opHackedApply!() oldIterMix; +} + +void main() +{ + Foo f = new Foo; + foreach (int i; f.oldIterMix.Iter) {} + foreach ( i; f.oldIterMix.Iter) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12.d b/gcc/testsuite/gdc.test/fail_compilation/fail12.d new file mode 100644 index 00000000000..ad38cd790b8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12.d @@ -0,0 +1,13 @@ +template Foo(alias b) +{ + int abc() { return b; } +} + +void main() +{ + int y = 8; + mixin Foo!(y); + mixin Foo!(y); + assert(abc() == 8); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail120.d b/gcc/testsuite/gdc.test/fail_compilation/fail120.d new file mode 100644 index 00000000000..ae0f5b1093b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail120.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail120.d(12): Error: need 'this' for 'nodes' of type 'int[2]' +fail_compilation/fail120.d(13): Error: need 'this' for 'nodes' of type 'int[2]' +--- +*/ + +class Foo +{ + int[2] nodes; + auto left = (){ return nodes[0]; }; + auto right = (){ return nodes[1]; }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12047.d b/gcc/testsuite/gdc.test/fail_compilation/fail12047.d new file mode 100644 index 00000000000..b948b6771d1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12047.d @@ -0,0 +1,21 @@ +// REQUIRED_ARGS: -d +/* +TEST_OUTPUT: +--- +fail_compilation/fail12047.d(15): Error: undefined identifier `asdf` +fail_compilation/fail12047.d(16): Error: undefined identifier `asdf` +fail_compilation/fail12047.d(17): Error: undefined identifier `asdf` +fail_compilation/fail12047.d(18): Error: undefined identifier `asdf` +fail_compilation/fail12047.d(19): Error: undefined identifier `asdf` +fail_compilation/fail12047.d(20): Error: undefined identifier `asdf` +fail_compilation/fail12047.d(21): Error: undefined identifier `asdf` +--- +*/ + +@asdf void func() { } +@asdf int var = 1; +@asdf enum E : int { a } +@asdf struct S {} +@asdf class C {} +@asdf interface I {} +@asdf alias int myint; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail121.d b/gcc/testsuite/gdc.test/fail_compilation/fail121.d new file mode 100644 index 00000000000..4bc8179d282 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail121.d @@ -0,0 +1,17 @@ +// PERMUTE_ARGS: -d -dw +// segfault on DMD0.150, never failed if use typeid() instead. + +struct myobject +{ + TypeInfo objecttype; + void* offset; +} + +myobject[] list; + +void foo() +{ + int i; + + list[1].typeinfo = i.typeinfo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail122.d b/gcc/testsuite/gdc.test/fail_compilation/fail122.d new file mode 100644 index 00000000000..f4ba30198c4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail122.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail122.d(12): Error: undefined identifier `y` +--- +*/ + +// Issue 228 - Crash on inferring function literal return type after prior errors + +void main() +{ + y = 2; + auto x = function(){}; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d new file mode 100644 index 00000000000..ea950667976 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d @@ -0,0 +1,33 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12236.d(16): Error: forward reference to inferred return type of function 'f1' +fail_compilation/fail12236.d(16): while evaluating pragma(msg, f1.mangleof) +fail_compilation/fail12236.d(21): Error: forward reference to inferred return type of function 'f2' +fail_compilation/fail12236.d(21): while evaluating pragma(msg, f2(T)(T).mangleof) +fail_compilation/fail12236.d(27): Error: template instance fail12236.f2!int error instantiating +fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function '__lambda1' +fail_compilation/fail12236.d(31): while evaluating pragma(msg, __lambda1.mangleof) +--- +*/ + +auto f1(int) +{ + pragma(msg, f1.mangleof); // forward reference error +} + +auto f2(T)(T) +{ + pragma(msg, f2.mangleof); // error <- weird output: "v" +} + +void main() +{ + f1(1); + f2(1); + + (a) { + int x; + pragma(msg, __traits(parent, x).mangleof); + } (1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12255.d b/gcc/testsuite/gdc.test/fail_compilation/fail12255.d new file mode 100644 index 00000000000..4531e86e8c0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12255.d @@ -0,0 +1,139 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12255.d(29): Error: AA key type SC1 does not have 'bool opEquals(ref const SC1) const' +fail_compilation/fail12255.d(30): Error: AA key type SC2 does not support const equality +fail_compilation/fail12255.d(35): Error: AA key type SD1 should have 'size_t toHash() const nothrow @safe' if opEquals defined +fail_compilation/fail12255.d(36): Error: AA key type SD2 supports const equality but doesn't support const hashing +fail_compilation/fail12255.d(40): Error: AA key type SE1 should have 'size_t toHash() const nothrow @safe' if opEquals defined +fail_compilation/fail12255.d(41): Error: AA key type SE2 supports const equality but doesn't support const hashing +--- +*/ + +void main() +{ + /* Key comparison and hashing are based on object bit representation, + * and they fully supported in runtime (TypeInfo.equals and TypeInfo.getHash) + */ + int[SA1] a1; // OK + int[SA2] a2; // OK + + /* If only toHash is defined, AA assumes that is customized object hashing. + */ + int[SB1] b1; // OK + int[SB2] b2; // OK + + /* If key does not support const equality, + * it is disallowed, because TypeInfo.equals will throw Error. + */ + int[SC1] c1; // NG + int[SC2] c2; // NG + + /* If opEquals defined for const equality, corresponding toHash method + * is required to guarantee (a != b || a.toHash() == b.toHash()). + */ + int[SD1] d1; // NG + int[SD2] d2; // NG + + /* same as SD cases + */ + int[SE1] e1; // NG + int[SE2] e2; // NG +} + +struct SA1 { int val; } +struct SA2 { SA1 s; } + +struct SB1 +{ + // AA assumes this is specialized hashing (?) + size_t toHash() const nothrow @safe { return 0; } +} +struct SB2 +{ + SB1 s; + // implicit generated toHash() calls s.toHash(). +} + +struct SC1 +{ + // does not support const equality + bool opEquals(typeof(this)) /*const*/ { return true; } +} +struct SC2 +{ + SC1 s; +} + +struct SD1 +{ + // Supports const equality, but + // does not have corresponding toHash() + bool opEquals(typeof(this)) const { return true; } +} +struct SD2 +{ + SD1 s; +} + +struct SE1 +{ + // Supports const equality, but + // does not have corresponding valid toHash() + bool opEquals(typeof(this)) const { return true; } + size_t toHash() @system { return 0; } +} +struct SE2 +{ + SE1 s; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12255.d(108): Error: bottom of AA key type SC1 does not have 'bool opEquals(ref const SC1) const' +fail_compilation/fail12255.d(109): Error: bottom of AA key type SC2 does not support const equality +fail_compilation/fail12255.d(110): Error: bottom of AA key type SD1 should have 'size_t toHash() const nothrow @safe' if opEquals defined +fail_compilation/fail12255.d(111): Error: bottom of AA key type SD2 supports const equality but doesn't support const hashing +fail_compilation/fail12255.d(112): Error: bottom of AA key type SE1 should have 'size_t toHash() const nothrow @safe' if opEquals defined +fail_compilation/fail12255.d(113): Error: bottom of AA key type SE2 supports const equality but doesn't support const hashing +--- +*/ +void testSArray() +{ + int[SA1[1]] a1; // OK + int[SA2[1]] a2; // OK + int[SB1[1]] b1; // OK + int[SB2[1]] b2; // OK + int[SC1[1]] c1; // NG + int[SC2[1]] c2; // NG + int[SD1[1]] d1; // NG + int[SD2[1]] d2; // NG + int[SE1[1]] e1; // NG + int[SE2[1]] e2; // NG +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12255.d(133): Error: bottom of AA key type SC1 does not have 'bool opEquals(ref const SC1) const' +fail_compilation/fail12255.d(134): Error: bottom of AA key type SC2 does not support const equality +fail_compilation/fail12255.d(135): Error: bottom of AA key type SD1 should have 'size_t toHash() const nothrow @safe' if opEquals defined +fail_compilation/fail12255.d(136): Error: bottom of AA key type SD2 supports const equality but doesn't support const hashing +fail_compilation/fail12255.d(137): Error: bottom of AA key type SE1 should have 'size_t toHash() const nothrow @safe' if opEquals defined +fail_compilation/fail12255.d(138): Error: bottom of AA key type SE2 supports const equality but doesn't support const hashing +--- +*/ +void testDArray() +{ + int[SA1[]] a1; // OK + int[SA2[]] a2; // OK + int[SB1[]] b1; // OK + int[SB2[]] b2; // OK + int[SC1[]] c1; // NG + int[SC2[]] c2; // NG + int[SD1[]] d1; // NG + int[SD2[]] d2; // NG + int[SE1[]] e1; // NG + int[SE2[]] e2; // NG +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail123.d b/gcc/testsuite/gdc.test/fail_compilation/fail123.d new file mode 100644 index 00000000000..fd1aef0e87c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail123.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail123.d(11): Error: undefined identifier `type` +fail_compilation/fail123.d(17): Error: enum fail123.foo2 base type must not be void +--- +*/ + +// Issue 355 - ICE from enum : nonexistent type + +enum foo : type +{ + blah1, + blah2 +} + +enum foo2 : void { a, b } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12378.d b/gcc/testsuite/gdc.test/fail_compilation/fail12378.d new file mode 100644 index 00000000000..6f787305a71 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12378.d @@ -0,0 +1,145 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12378.d(18): Error: undefined identifier `ANYTHING` +fail_compilation/fail12378.d(18): Error: undefined identifier `GOES` +fail_compilation/fail12378.d(91): instantiated from here: MapResultS!((x0) => ANYTHING - GOES, Result) +fail_compilation/fail12378.d(17): instantiated from here: mapS!(Result) +fail_compilation/fail12378.d(100): instantiated from here: __lambda1!int +fail_compilation/fail12378.d(91): instantiated from here: MapResultS!((y0) => iota(2).mapS!((x0) => ANYTHING - GOES), Result) +fail_compilation/fail12378.d(16): instantiated from here: mapS!(Result) +--- +*/ +void testS() +{ + auto r = + iota(1).mapS!(y0 => + iota(2).mapS!(x0 => + ANYTHING-GOES + ) + ); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12378.d(40): Error: undefined identifier `ANYTHING` +fail_compilation/fail12378.d(40): Error: undefined identifier `GOES` +fail_compilation/fail12378.d(112): instantiated from here: MapResultC!((x0) => ANYTHING - GOES, Result) +fail_compilation/fail12378.d(39): instantiated from here: mapC!(Result) +fail_compilation/fail12378.d(123): instantiated from here: __lambda1!int +fail_compilation/fail12378.d(112): instantiated from here: MapResultC!((y0) => iota(2).mapC!((x0) => ANYTHING - GOES), Result) +fail_compilation/fail12378.d(38): instantiated from here: mapC!(Result) +--- +*/ +void testC() +{ + auto r = + iota(1).mapC!(y0 => + iota(2).mapC!(x0 => + ANYTHING-GOES + ) + ); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12378.d(64): Error: undefined identifier `ANYTHING` +fail_compilation/fail12378.d(64): Error: undefined identifier `GOES` +fail_compilation/fail12378.d(135): instantiated from here: MapResultI!((x0) => ANYTHING - GOES, Result) +fail_compilation/fail12378.d(63): instantiated from here: mapI!(Result) +fail_compilation/fail12378.d(143): instantiated from here: __lambda1!int +fail_compilation/fail12378.d(135): instantiated from here: MapResultI!((y0) => iota(2).mapI!((x0) => ANYTHING - GOES), Result) +fail_compilation/fail12378.d(62): instantiated from here: mapI!(Result) +--- +*/ + + +void testI() +{ + auto r = + iota(1).mapI!(y0 => + iota(2).mapI!(x0 => + ANYTHING-GOES + ) + ); +} + +auto iota(E)(E end) +{ + alias Value = E; + + static struct Result + { + private Value current, pastLast; + + @property inout(Value) front() inout { return current; } + } + + return Result(0, end); +} + +template mapS(fun...) +{ + auto mapS(R)(R r) + { + alias AppliedReturnType(alias f) = typeof(f(r.front)); + static assert(!is(AppliedReturnType!fun == void), + "Mapping function must not return void."); + + return MapResultS!(fun, R)(r); + } +} +struct MapResultS(alias fun, R) +{ + R _input; + + @property auto ref front() + { + return fun(_input.front); + } +} + +template mapC(fun...) +{ + auto mapC(R)(R r) + { + alias AppliedReturnType(alias f) = typeof(f(r.front)); + static assert(!is(AppliedReturnType!fun == void), + "Mapping function must not return void."); + + return new MapResultC!(fun, R)(r); + } +} +class MapResultC(alias fun, R) +{ + R _input; + + this(R r) { _input = r; } + + @property auto ref front() + { + return fun(_input.front); + } +} + +template mapI(fun...) +{ + auto mapI(R)(R r) + { + alias AppliedReturnType(alias f) = typeof(f(r.front)); + static assert(!is(AppliedReturnType!fun == void), + "Mapping function must not return void."); + + return MapResultI!(fun, R).init; + } +} +interface MapResultI(alias fun, R) +{ + static @property auto ref front() + { + R _input; + return fun(_input.front); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d new file mode 100644 index 00000000000..cb1eb8a6bf1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12390.d(14): Error: `==` has no effect in expression `fun().i == 4` +--- +*/ + +struct S { int i; } + +S fun() { return S(42); } + +void main() +{ + fun().i == 4; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail124.d b/gcc/testsuite/gdc.test/fail_compilation/fail124.d new file mode 100644 index 00000000000..62b5894f68e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail124.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail124.d(15): Error: class fail124.CC inherits from duplicate interface C +--- +*/ + +//import std.stdio; + +interface C +{ + void f(); +} + +class CC : C, C +{ + void f() { /*writefln("hello");*/ } +} + +void main() +{ + CC cc = new CC(); + cc.f(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12436.d b/gcc/testsuite/gdc.test/fail_compilation/fail12436.d new file mode 100644 index 00000000000..605ab054e9e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12436.d @@ -0,0 +1,77 @@ +alias void FuncType(); + +struct Opaque; + +template Tuple(T...) { alias T Tuple; } +alias Tuple!(int, int) TupleType; + +/******************************************/ +// return type + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12436.d(18): Error: functions cannot return a function +fail_compilation/fail12436.d(19): Error: functions cannot return a tuple +--- +*/ +FuncType test1(); +TupleType test2(); + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12436.d(28): Error: functions cannot return opaque type Opaque by value +fail_compilation/fail12436.d(29): Error: functions cannot return opaque type Opaque[1] by value +--- +*/ +Opaque ret12436a(); // error +Opaque[1] ret12436b(); // error +Opaque* ret12436c(); // no error +Opaque[] ret12436d(); // no error +Opaque[]* ret12436e(); // no error + +ref Opaque ret12436f(); // no error +ref Opaque[1] ret12436g(); // no error + +/******************************************/ +// parameter type + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12436.d(46): Error: cannot have parameter of function type void() +--- +*/ +void test3(FuncType) {} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12436.d(55): Error: cannot have parameter of opaque type Opaque by value +fail_compilation/fail12436.d(56): Error: cannot have parameter of opaque type Opaque[1] by value +--- +*/ +void param12436a(Opaque); // error +void param12436b(Opaque[1]); // error +void param12436c(Opaque*); // no error +void param12436d(Opaque[]); // no error +void param12436e(Opaque[]*); // no error + +void param12436f(ref Opaque); // no error +void param12436g(ref Opaque[1]); // no error +void param12436h(out Opaque); // no error +void param12436i(out Opaque[1]); // no error + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12436.d(75): Error: cannot have parameter of opaque type A14906 by value +fail_compilation/fail12436.d(76): Error: cannot have parameter of opaque type A14906[3] by value +fail_compilation/fail12436.d(77): Error: cannot have parameter of opaque type A14906[3][3] by value +--- +*/ +enum A14906; +void f14906a(A14906) {} +void f14906b(A14906[3]) {} +void f14906c(A14906[3][3]) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12485.d b/gcc/testsuite/gdc.test/fail_compilation/fail12485.d new file mode 100644 index 00000000000..71f8698db99 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12485.d @@ -0,0 +1,11 @@ +void dorecursive() +{ + recursive([0]); +} + +void recursive(R)(R r) +{ + import std.algorithm; + recursive( r.filter!(e=>true) ); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail125.d b/gcc/testsuite/gdc.test/fail_compilation/fail125.d new file mode 100644 index 00000000000..0e0f5ea8a7e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail125.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail125.d(15): Error: array index [2] is outside array bounds [0 .. 2] +fail_compilation/fail125.d(18): Error: template instance fail125.main.recMove!(1, a, b) error instantiating +fail_compilation/fail125.d(25): instantiated from here: recMove!(0, a, b) +--- +*/ + + +template recMove(int i, X...) +{ + void recMove() + { + X[i] = X[i+1]; + // I know the code is logically wrong, should test (i+2 < X.length) + static if (i+1 < X.length) + recMove!(i+1, X); + } +} + +void main() +{ + int a, b; + recMove!(0, a, b); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12567.d b/gcc/testsuite/gdc.test/fail_compilation/fail12567.d new file mode 100644 index 00000000000..e1ecd19fee1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12567.d @@ -0,0 +1,8 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail12567.d(8): Error: string expected, not '"a" ~ "b"' +--- +*/ +deprecated("a" ~ "b") module fail12567; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail126.d b/gcc/testsuite/gdc.test/fail_compilation/fail126.d new file mode 100644 index 00000000000..280fde90aaa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail126.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail126.d(8): Error: forward reference to 'test' +--- +*/ + +void test(typeof(test) p) +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12604.d b/gcc/testsuite/gdc.test/fail_compilation/fail12604.d new file mode 100644 index 00000000000..2ed8ebf9cc9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12604.d @@ -0,0 +1,79 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12604.d(14): Error: mismatched array lengths, 1 and 3 +fail_compilation/fail12604.d(15): Error: mismatched array lengths, 1 and 3 +fail_compilation/fail12604.d(17): Error: mismatched array lengths, 1 and 3 +fail_compilation/fail12604.d(18): Error: mismatched array lengths, 1 and 3 +fail_compilation/fail12604.d(20): Error: cannot implicitly convert expression `[65536]` of type `int[]` to `short[]` +fail_compilation/fail12604.d(21): Error: cannot implicitly convert expression `[65536, 2, 3]` of type `int[]` to `short[]` +--- +*/ +void main() +{ + int[1] a1 = [1,2,3]; + short[1] a2 = [1,2,3]; + + int[1] b1; b1 = [1,2,3]; + short[1] b2; b2 = [1,2,3]; + + short[1] c = [65536]; + short[1] d = [65536,2,3]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12604.d(39): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(40): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(41): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(42): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(43): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(44): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(45): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(46): Error: mismatched array lengths, 2 and 3 +--- +*/ +void test12606a() // AssignExp::semantic +{ + uint[2] a1 = [1, 2, 3][]; + ushort[2] a2 = [1, 2, 3][]; + uint[2] a3 = [1, 2, 3][0 .. 3]; + ushort[2] a4 = [1, 2, 3][0 .. 3]; + a1 = [1, 2, 3][]; + a2 = [1, 2, 3][]; + a3 = [1, 2, 3][0 .. 3]; + a4 = [1, 2, 3][0 .. 3]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12604.d(60): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(61): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(62): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail12604.d(63): Error: mismatched array lengths, 2 and 3 +--- +*/ +void test12606b() // ExpInitializer::semantic +{ + static uint[2] a1 = [1, 2, 3][]; + static uint[2] a2 = [1, 2, 3][0 .. 3]; + static ushort[2] a3 = [1, 2, 3][]; + static ushort[2] a4 = [1, 2, 3][0 .. 3]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12604.d(77): Error: mismatched array lengths, 4 and 3 +fail_compilation/fail12604.d(78): Error: mismatched array lengths, 4 and 3 +--- +*/ +void testc() +{ + int[4] sa1; + int[3] sa2; + sa1[0..4] = [1,2,3]; + sa1[0..4] = sa2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12622.d b/gcc/testsuite/gdc.test/fail_compilation/fail12622.d new file mode 100644 index 00000000000..04bb8d6c020 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12622.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12622.d(25): Error: pure function 'fail12622.foo' cannot call impure function pointer 'fp' +fail_compilation/fail12622.d(25): Error: @nogc function 'fail12622.foo' cannot call non-@nogc function pointer 'fp' +fail_compilation/fail12622.d(25): Error: @safe function 'fail12622.foo' cannot call @system function pointer 'fp' +fail_compilation/fail12622.d(27): Error: pure function 'fail12622.foo' cannot call impure function pointer 'fp' +fail_compilation/fail12622.d(27): Error: @nogc function 'fail12622.foo' cannot call non-@nogc function pointer 'fp' +fail_compilation/fail12622.d(27): Error: @safe function 'fail12622.foo' cannot call @system function pointer 'fp' +fail_compilation/fail12622.d(29): Error: pure function 'fail12622.foo' cannot call impure function 'fail12622.bar' +fail_compilation/fail12622.d(29): Error: @safe function 'fail12622.foo' cannot call @system function 'fail12622.bar' +fail_compilation/fail12622.d(29): Error: @nogc function 'fail12622.foo' cannot call non-@nogc function 'fail12622.bar' +--- +*/ +// Note that, today nothrow violation errors are accidentally hidden. + + + +void bar(); + +pure nothrow @nogc @safe void foo() +{ + auto fp = &bar; + + (*fp)(); + + fp(); + + bar(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12635.d b/gcc/testsuite/gdc.test/fail_compilation/fail12635.d new file mode 100644 index 00000000000..b00cc47b300 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12635.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12635.d(19): Error: Cannot generate a segment prefix for a branching instruction +--- +*/ + +void foo() +{ + enum NOP = 0x9090_9090_9090_9090; + + asm + { + L1: + dq NOP,NOP,NOP,NOP; // 32 + dq NOP,NOP,NOP,NOP; // 64 + dq NOP,NOP,NOP,NOP; // 96 + dq NOP,NOP,NOP,NOP; // 128 + jmp DS:L1; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12636.d b/gcc/testsuite/gdc.test/fail_compilation/fail12636.d new file mode 100644 index 00000000000..9a243a5c716 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12636.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12636.d(13): Error: C++ class 'fail12636.C' cannot implement D interface 'fail12636.D' +--- +*/ + +interface D +{ + void foo(); +} + +extern(C++) class C : D +{ + extern(D) override void foo() { } +} + +void main() +{ + auto c = new C; + c.foo(); // works + D d = c; + d.foo(); // segfault +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail127.d b/gcc/testsuite/gdc.test/fail_compilation/fail127.d new file mode 100644 index 00000000000..449dbc5de68 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail127.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail127.d(9): Error: a struct is not a valid initializer for a char[][] +fail_compilation/fail127.d(10): Error: a struct is not a valid initializer for a string[] +--- +*/ + +char[][] Level2Text1 = {"LOW", "MEDIUM", "HIGH"}; +string[] Level2Text2 = {"LOW", "MEDIUM", "HIGH"}; // for D2 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d new file mode 100644 index 00000000000..f1216b58d7a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d @@ -0,0 +1,69 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes 'ref' and 'out' +fail_compilation/fail12744.d(52): Error: template instance fail12744.bar12744R!(foo12744O) error instantiating +fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes 'ref' and 'lazy' +fail_compilation/fail12744.d(53): Error: template instance fail12744.bar12744R!(foo12744L) error instantiating +fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes 'out' and 'ref' +fail_compilation/fail12744.d(56): Error: template instance fail12744.bar12744O!(foo12744R) error instantiating +fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes 'out' and 'lazy' +fail_compilation/fail12744.d(58): Error: template instance fail12744.bar12744O!(foo12744L) error instantiating +fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes 'lazy' and 'ref' +fail_compilation/fail12744.d(61): Error: template instance fail12744.bar12744L!(foo12744R) error instantiating +fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes 'lazy' and 'out' +fail_compilation/fail12744.d(62): Error: template instance fail12744.bar12744L!(foo12744O) error instantiating +fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes 'auto ref' and 'out' +fail_compilation/fail12744.d(67): Error: template fail12744.bar12744A cannot deduce function from argument types !(foo12744O)(int), candidates are: +fail_compilation/fail12744.d(41): fail12744.bar12744A(alias f)(auto ref PTT12744!f args) +fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes 'auto ref' and 'lazy' +fail_compilation/fail12744.d(68): Error: template fail12744.bar12744A cannot deduce function from argument types !(foo12744L)(int), candidates are: +fail_compilation/fail12744.d(41): fail12744.bar12744A(alias f)(auto ref PTT12744!f args) +--- +*/ +template PTT12744(func...) +{ + static if (is(typeof(func[0]) P == function)) + alias PTT12744 = P; + else + static assert(0); +} + +void foo12744N( int x) {} +void foo12744R( ref int x) {} +void foo12744O( out int x) {} +void foo12744L(lazy int x) {} + +void bar12744N(alias f)( PTT12744!f args) {} +void bar12744R(alias f)( ref PTT12744!f args) {} +void bar12744O(alias f)( out PTT12744!f args) {} +void bar12744L(alias f)( lazy PTT12744!f args) {} +void bar12744A(alias f)(auto ref PTT12744!f args) {} + +void main() +{ + alias bNN = bar12744N!foo12744N; + alias bNR = bar12744N!foo12744R; + alias bNO = bar12744N!foo12744O; + alias bNL = bar12744N!foo12744L; + + alias bRN = bar12744R!foo12744N; + alias bRR = bar12744R!foo12744R; + alias bRO = bar12744R!foo12744O; // error + alias bRL = bar12744R!foo12744L; // error + + alias bON = bar12744O!foo12744N; + alias bOR = bar12744O!foo12744R; // error + alias bOO = bar12744O!foo12744O; + alias bOL = bar12744O!foo12744L; // error + + alias bLN = bar12744L!foo12744N; + alias bLR = bar12744L!foo12744R; // error + alias bLO = bar12744L!foo12744O; // error + alias bLL = bar12744L!foo12744L; + + bar12744A!foo12744N(1); + bar12744A!foo12744R(1); + bar12744A!foo12744O(1); // error + bar12744A!foo12744L(1); // error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12749.d b/gcc/testsuite/gdc.test/fail_compilation/fail12749.d new file mode 100644 index 00000000000..149d1209829 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12749.d @@ -0,0 +1,62 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12749.d(19): Error: immutable field 'inum' initialization is not allowed in foreach loop +fail_compilation/fail12749.d(20): Error: const field 'cnum' initialization is not allowed in foreach loop +fail_compilation/fail12749.d(25): Error: immutable field 'inum' initialization is not allowed in nested function 'set' +fail_compilation/fail12749.d(26): Error: const field 'cnum' initialization is not allowed in nested function 'set' +--- +*/ +struct S +{ + immutable int inum; + const int cnum; + + this(int i) + { + foreach (n; Aggr()) + { + inum = i; + cnum = i; + } + + void set(int i) + { + inum = i; + cnum = i; + } + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12749.d(48): Error: immutable variable 'inum' initialization is not allowed in foreach loop +fail_compilation/fail12749.d(49): Error: const variable 'cnum' initialization is not allowed in foreach loop +fail_compilation/fail12749.d(54): Error: immutable variable 'inum' initialization is not allowed in nested function 'set' +fail_compilation/fail12749.d(55): Error: const variable 'cnum' initialization is not allowed in nested function 'set' +--- +*/ +immutable int inum; +const int cnum; +static this() +{ + int i = 10; + + foreach (n; Aggr()) + { + inum = i; + cnum = i; + } + + void set(int i) + { + inum = i; + cnum = i; + } +} + +struct Aggr +{ + int opApply(int delegate(int) dg) { return dg(1); } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12809.d b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d new file mode 100644 index 00000000000..7c086839b0c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d @@ -0,0 +1,80 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +bool cond; + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12809.d(19): Error: `object.Exception` is thrown but not caught +fail_compilation/fail12809.d(16): Error: nothrow function `fail12809.test_finally1` may throw +fail_compilation/fail12809.d(35): Error: `object.Exception` is thrown but not caught +fail_compilation/fail12809.d(39): Error: `object.Exception` is thrown but not caught +fail_compilation/fail12809.d(32): Error: nothrow function `fail12809.test_finally3` may throw +--- +*/ +void test_finally1() nothrow +{ + try + throw new Exception(""); // error + finally + {} +} + +void test_finally2() nothrow +{ + try + throw new Exception(""); // no error + finally + assert(0); // unconditional halt +} + +void test_finally3() nothrow +{ + try + throw new Exception(""); // error + finally + { + if (cond) + throw new Exception(""); // error + assert(0); // conditional halt + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail12809.d(59): Error: `object.Exception` is thrown but not caught +fail_compilation/fail12809.d(54): Error: nothrow function `fail12809.test_finally4` may throw +fail_compilation/fail12809.d(75): Error: `object.Exception` is thrown but not caught +fail_compilation/fail12809.d(79): Error: `object.Exception` is thrown but not caught +fail_compilation/fail12809.d(70): Error: nothrow function `fail12809.test_finally6` may throw +--- +*/ +void test_finally4() nothrow +{ + try + {} + finally + throw new Exception(""); // error +} + +void test_finally5() nothrow +{ + try + assert(0); // unconditional halt + finally + throw new Exception(""); // no error +} + +void test_finally6() nothrow +{ + try + { + if (cond) + throw new Exception(""); // error + assert(0); // conditional halt + } + finally + throw new Exception(""); // error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail129.d b/gcc/testsuite/gdc.test/fail_compilation/fail129.d new file mode 100644 index 00000000000..2bf436964e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail129.d @@ -0,0 +1,14 @@ +Ä ä; + +/* +TEST_OUTPUT: +--- +fail_compilation/fail129.d: Error: module fail129 source file must start with BOM or ASCII character, not \xC3 +--- +*/ + +class Ä +{ +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12901.d b/gcc/testsuite/gdc.test/fail_compilation/fail12901.d new file mode 100644 index 00000000000..8d62c3e04ca --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12901.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12901.d(11): Error: constructor fail12901.S.this in and out contracts require function body +--- +*/ + +struct S +{ + int a; + this(int n) + in { a = n; } + // no body +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12908.d b/gcc/testsuite/gdc.test/fail_compilation/fail12908.d new file mode 100644 index 00000000000..c238028309e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12908.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12908.d(14): Error: pure delegate 'fail12908.main.__foreachbody1' cannot call impure function 'fail12908.g' +--- +*/ + +void g() {} + +void main() pure +{ + foreach (k, v; ["": ""]) + { + g(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12932.d b/gcc/testsuite/gdc.test/fail_compilation/fail12932.d new file mode 100644 index 00000000000..871abfea02c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12932.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12932.d(11): Error: array literal in @nogc function 'fail12932.foo' may cause GC allocation +fail_compilation/fail12932.d(15): Error: array literal in @nogc function 'fail12932.foo' may cause GC allocation +--- +*/ + +int* foo() @nogc +{ + foreach (ref e; [1,2,3]) + { + } + + foreach (ref e; [1,2,3]) + { + return &e; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13064.d b/gcc/testsuite/gdc.test/fail_compilation/fail13064.d new file mode 100644 index 00000000000..be434600510 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13064.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13064.d(8): Error: function fail13064.f storage class 'auto' has no effect if return type is not inferred +--- +*/ + +auto void f() { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail131.d b/gcc/testsuite/gdc.test/fail_compilation/fail131.d new file mode 100644 index 00000000000..e0f568fcf64 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail131.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail131.d(8): Error: function D main parameters must be main() or main(string[] args) +--- +*/ + +int main(lazy char[][] args) +{ + return args.length; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d new file mode 100644 index 00000000000..fe1180caff2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13116.d(13): Error: this is not an lvalue +--- +*/ +struct S +{ + ref S notEvil() { return this; } // this should be accepted +} +class C +{ + ref C evil() { return this; } // this should be rejected +} +void main() +{ +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13116.d(28): Error: super is not an lvalue +--- +*/ +class Base { } +class Derived : Base +{ + ref Base evil() { return super; } // should be rejected +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d new file mode 100644 index 00000000000..1acda7b2db1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d @@ -0,0 +1,35 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13120.d(13): Error: pure delegate 'fail13120.g1.__foreachbody2' cannot call impure function 'fail13120.f1' +fail_compilation/fail13120.d(13): Error: @nogc delegate 'fail13120.g1.__foreachbody2' cannot call non-@nogc function 'fail13120.f1' +--- +*/ +void f1() {} + +void g1(char[] s) pure @nogc +{ + foreach (dchar dc; s) + f1(); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13120.d(34): Error: pure function 'fail13120.h2' cannot call impure function 'fail13120.g2!().g2' +fail_compilation/fail13120.d(34): Error: @safe function 'fail13120.h2' cannot call @system function 'fail13120.g2!().g2' +fail_compilation/fail13120.d(34): Error: @nogc function 'fail13120.h2' cannot call non-@nogc function 'fail13120.g2!().g2' +--- +*/ +void f2() {} + +void g2()(char[] s) +{ + foreach (dchar dc; s) + f2(); +} + +void h2() @safe pure @nogc +{ + g2(null); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13187.d b/gcc/testsuite/gdc.test/fail_compilation/fail13187.d new file mode 100644 index 00000000000..3799d7711e4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13187.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13187.d(12): Error: pure function 'fail13187.test' cannot access mutable static data 'my_func_ptr' +--- +*/ + +int function(int) pure my_func_ptr; + +void test() pure +{ + my_func_ptr(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail132.d b/gcc/testsuite/gdc.test/fail_compilation/fail132.d new file mode 100644 index 00000000000..34631840b23 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail132.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail132.d(19): Error: outer class A 'this' needed to 'new' nested class B +--- +*/ + +//import std.stdio; + +class A +{ + class B + { + } +} + +void main() +{ + A.B c = new A.B; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13203.d b/gcc/testsuite/gdc.test/fail_compilation/fail13203.d new file mode 100644 index 00000000000..86d30a4b093 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13203.d @@ -0,0 +1,45 @@ +int v1, v2; + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13203.d(15): Error: alias fail13203.FA1!1.T conflicts with alias fail13203.FA1!1.T at fail_compilation/fail13203.d(14) +fail_compilation/fail13203.d(22): Error: template instance fail13203.FA1!1 error instantiating +fail_compilation/fail13203.d(20): Error: alias fail13203.FA2!1.T conflicts with alias fail13203.FA2!1.T at fail_compilation/fail13203.d(19) +fail_compilation/fail13203.d(23): Error: template instance fail13203.FA2!1 error instantiating +--- +*/ +template FA1(int b) +{ + alias T = int; + static if (b) alias T = uint; +} +template FA2(int b) +{ + alias T = v1; + static if (b) alias T = v2; +} +alias A1 = FA1!1; // type is not overloadable +alias A2 = FA2!1; // variable symbol is not overloadable + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13203.d(36): Error: alias fail13203.FB1!1.T conflicts with alias fail13203.FB1!1.T at fail_compilation/fail13203.d(37) +fail_compilation/fail13203.d(44): Error: template instance fail13203.FB1!1 error instantiating +fail_compilation/fail13203.d(41): Error: alias fail13203.FB2!1.T conflicts with alias fail13203.FB2!1.T at fail_compilation/fail13203.d(42) +fail_compilation/fail13203.d(45): Error: template instance fail13203.FB2!1 error instantiating +--- +*/ +template FB1(int b) +{ + static if (b) alias T = uint; + alias T = int; +} +template FB2(int b) +{ + static if (b) alias T = v2; + alias T = v1; +} +alias B1 = FB1!1; +alias B2 = FB2!1; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail133.d b/gcc/testsuite/gdc.test/fail_compilation/fail133.d new file mode 100644 index 00000000000..e189ad5a8c0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail133.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail133.d(13): Error: function D main circular dependency. Functions cannot be interpreted while being compiled +fail_compilation/fail133.d(15): called from here: main() +--- +*/ + +template t(int t) +{ +} + +int main() +{ + return t!(main() + 8); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d new file mode 100644 index 00000000000..5ab7e6c56f1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13336a.d(28): Error: choose(true) is not an lvalue +--- +*/ + +class Animal {} +class Cat : Animal {} +class Dog : Animal {} + +Animal animal; +Cat cat; + +auto ref choose(bool f) +{ + if (f) + return cat; + else + return animal; +} + +void main() +{ + //pragma(msg, typeof(&choose)); + static assert(is(typeof(&choose) == Animal function(bool) nothrow @nogc @safe)); // pass + + choose(true) = new Dog(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d new file mode 100644 index 00000000000..9d30d2c9f30 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d @@ -0,0 +1,31 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +int sx; +double sy; + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13336b.d(16): Error: cast(double)sx is not an lvalue +--- +*/ +ref f1(bool f) +{ + if (f) + return sx; + return sy; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13336b.d(30): Error: cast(double)sx is not an lvalue +--- +*/ +ref f2(bool f) +{ + if (f) + return sy; + return sx; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail134.d b/gcc/testsuite/gdc.test/fail_compilation/fail134.d new file mode 100644 index 00000000000..d7b4a36ffc8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail134.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail134.d(13): Error: template instance foo!(f) does not match template declaration foo(T) +fail_compilation/fail134.d(14): Error: template instance fail134.bar!(f) error instantiating +--- +*/ + +// Issue 651 - Assertion failure: 'global.errors' on line 2622 in file 'template.c' + +void f() {} +template foo(T) {} +template bar(T...) { alias foo!(T) buz; } +alias bar!(f) a; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13424.d b/gcc/testsuite/gdc.test/fail_compilation/fail13424.d new file mode 100644 index 00000000000..31bed563ded --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13424.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13424.d(12): Error: delegate fail13424.S.__lambda2 cannot be struct members +fail_compilation/fail13424.d(17): Error: delegate fail13424.U.__lambda2 cannot be union members +fail_compilation/fail13424.d(22): Error: delegate fail13424.C.__lambda2 cannot be class members +--- +*/ + +struct S +{ + void delegate(dchar) onChar = (dchar) {}; +} + +union U +{ + void delegate(dchar) onChar = (dchar) {}; +} + +class C +{ + void delegate(dchar) onChar = (dchar) {}; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13434_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail13434_m32.d new file mode 100644 index 00000000000..0b1baaac2ad --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13434_m32.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/fail13434_m32.d(13): Error: cannot implicitly convert expression `()` of type `()` to `uint` +--- +*/ + +alias tuple(A...) = A; +void main() +{ + float[] arr; + arr[tuple!()] = 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13434_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail13434_m64.d new file mode 100644 index 00000000000..a92282bb737 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13434_m64.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -m64 +/* +TEST_OUTPUT: +--- +fail_compilation/fail13434_m64.d(13): Error: cannot implicitly convert expression `()` of type `()` to `ulong` +--- +*/ + +alias tuple(A...) = A; +void main() +{ + float[] arr; + arr[tuple!()] = 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13498.d b/gcc/testsuite/gdc.test/fail_compilation/fail13498.d new file mode 100644 index 00000000000..c18d2e31c69 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13498.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13498.d(11): Error: cannot implicitly convert expression `"foo"` of type `string` to `int` +fail_compilation/fail13498.d(16): Error: template instance fail13498.foo!() error instantiating +--- +*/ + +int foo()() +{ + return "foo"; // should fail as well +} + +void main() +{ + foo(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13574.d b/gcc/testsuite/gdc.test/fail_compilation/fail13574.d new file mode 100644 index 00000000000..081f8b57b6b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13574.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13574.d(21): Error: '$' is not an lvalue +fail_compilation/fail13574.d(27): Error: '$' is not an lvalue +--- +*/ + +struct Foo +{ + void opSlice(size_t a, size_t b) { } + alias opDollar = length; + size_t length; +} + +void main() +{ + Foo foo; + foo[0 .. foo.length = 1]; + assert(foo.length == 1); + foo[0 .. $ = 2]; // assigns to the temporary dollar variable + //assert(foo.length == 2); + + int[] arr = [1,2,3]; + auto x = arr[0 .. arr.length = 1]; + assert(arr.length == 1); + auto y = arr[0 .. $ = 2]; // should also be disallowed + //assert(arr.length == 2); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail136.d b/gcc/testsuite/gdc.test/fail_compilation/fail136.d new file mode 100644 index 00000000000..bba0c511e8c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail136.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail136.d(10): Error: `string` has no effect in expression `"\xef\xbb\xbf"` +--- +*/ + +void main() +{ + x"EF BB BF"; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13601.d b/gcc/testsuite/gdc.test/fail_compilation/fail13601.d new file mode 100644 index 00000000000..e1aa2d5db99 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13601.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13601.d(13): Error: variable `__ctfe` cannot be read at compile time +fail_compilation/fail13601.d(14): Error: variable `__ctfe` cannot be read at compile time +fail_compilation/fail13601.d(15): Error: variable `__ctfe` cannot be read at compile time +fail_compilation/fail13601.d(16): Error: variable __ctfe cannot be read at compile time +--- +*/ + +void test() +{ + static if (__ctfe) {} + enum a = __ctfe ? "a" : "b"; + static int b = __ctfe * 2; + int[__ctfe] sarr; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail137.d b/gcc/testsuite/gdc.test/fail_compilation/fail137.d new file mode 100644 index 00000000000..80a2a25a51a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail137.d @@ -0,0 +1,23 @@ +// 751 Compiler segfault on template expansion + + template TypeTuple( TList... ) + { + alias TList TypeTuple; + } + + template IndexOf( T, TList... ) + { + static if( TList.length == 0 ) + const size_t IndexOf = 1; + else static if( is( T == typeof( TList[0] ) ) ) + const size_t IndexOf = 0; + else + const size_t IndexOf = 1 + IndexOf!( T, (TList[1 .. $]) ); + } + + void main() + { + TypeTuple!(int, long) T; + printf( "%u\n", IndexOf!(long, T) ); + } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13701.d b/gcc/testsuite/gdc.test/fail_compilation/fail13701.d new file mode 100644 index 00000000000..c0bdfccb3ea --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13701.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13701.d(16): Error: cannot modify immutable expression this.aa[10] +fail_compilation/fail13701.d(23): Error: cannot modify immutable expression aa[10] +fail_compilation/fail13701.d(24): Error: cannot modify immutable expression aa[10] +--- +*/ + +struct S +{ + immutable(int)[int] aa; + this(int n) + { + aa[10] = 20; // initializing + aa[10] = 30; // assignment + } +} + +void main() +{ + immutable(int)[int] aa; + aa[10] = 20; + aa[10]++; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13756.d b/gcc/testsuite/gdc.test/fail_compilation/fail13756.d new file mode 100644 index 00000000000..38dfeb87825 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13756.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail13756.d(11): Error: foreach: index must be type `const(int)`, not `int` +--- +*/ + +void maiin() +{ + int[int] aa = [1:2]; + foreach (ref int k, v; aa) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13775.d b/gcc/testsuite/gdc.test/fail_compilation/fail13775.d new file mode 100644 index 00000000000..8649d591b69 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13775.d @@ -0,0 +1,21 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail13775.d(17): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `ubyte[1]` +fail_compilation/fail13775.d(18): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `ubyte[3]` +fail_compilation/fail13775.d(19): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `byte[1]` +fail_compilation/fail13775.d(20): Error: cannot cast expression `ubytes[0..2]` of type `ubyte[2]` to `byte[3]` +--- +*/ + +void main() +{ + ubyte[4] ubytes = [1,2,3,4]; + + // CT-known slicing succeeds but sizes cannot match + auto ng1 = cast(ubyte[1]) ubytes[0 .. 2]; // ubyte[2] to ubyte[1] + auto ng2 = cast(ubyte[3]) ubytes[0 .. 2]; // ubyte[2] to ubyte[3] + auto ng3 = cast( byte[1]) ubytes[0 .. 2]; // ubyte[2] to byte[1] + auto ng4 = cast( byte[3]) ubytes[0 .. 2]; // ubyte[2] to byte[3] +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail139.d b/gcc/testsuite/gdc.test/fail_compilation/fail139.d new file mode 100644 index 00000000000..22fc616c87c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail139.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail139.d(8): Error: forward reference to 'test' +--- +*/ + +void test(typeof(&test) p) +{ +} + +void main() +{ + test(null); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d new file mode 100644 index 00000000000..fbe4b4a6713 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d @@ -0,0 +1,337 @@ +// REQUIRED_ARGS: -o- -d -m64 + +struct S1 { int v; } +struct S2 { int* p; } +class C { int v; } + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(32): Error: returning `& x` escapes a reference to local variable `x` +fail_compilation/fail13902.d(33): Error: returning `&s1.v` escapes a reference to local variable `s1` +fail_compilation/fail13902.d(38): Error: returning `& sa1` escapes a reference to local variable `sa1` +fail_compilation/fail13902.d(39): Error: returning `&sa2[0][0]` escapes a reference to local variable `sa2` +fail_compilation/fail13902.d(40): Error: returning `& x` escapes a reference to local variable `x` +fail_compilation/fail13902.d(41): Error: returning `(& x+4)` escapes a reference to local variable `x` +fail_compilation/fail13902.d(42): Error: returning `& x + cast(long)x * 4L` escapes a reference to local variable `x` +fail_compilation/fail13902.d(45): Error: returning `& y` escapes a reference to local variable `y` +--- +*/ +int* testEscape1() +{ + int x, y; + int[] da1; + int[][] da2; + int[1] sa1; + int[1][1] sa2; + int* ptr; + S1 s1; + S2 s2; + C c; + + if (0) return &x; // VarExp + if (0) return &s1.v; // DotVarExp + if (0) return s2.p; // no error + if (0) return &c.v; // no error + if (0) return &da1[0]; // no error + if (0) return &da2[0][0]; // no error + if (0) return &sa1[0]; // IndexExp + if (0) return &sa2[0][0]; // IndexExp + if (0) return &x; + if (0) return &x + 1; // optimized to SymOffExp == (& x+4) + if (0) return &x + x; + //if (0) return ptr += &x + 1; // semantic error + if (0) ptr -= &x - &y; // no error + if (0) return (&x, &y); // CommaExp + + return null; // ok +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to parameter `x`, perhaps annotate with `return` +fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to parameter `s1`, perhaps annotate with `return` +fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return` +fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to parameter `sa2`, perhaps annotate with `return` +fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to parameter `x`, perhaps annotate with `return` +fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to parameter `x`, perhaps annotate with `return` +fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to parameter `x`, perhaps annotate with `return` +fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to parameter `y`, perhaps annotate with `return` +--- +*/ +int* testEscape2( + int x, int y, + int[] da1, + int[][] da2, + int[1] sa1, + int[1][1] sa2, + int* ptr, + S1 s1, + S2 s2, + C c, +) +{ + if (0) return &x; // VarExp + if (0) return &s1.v; // DotVarExp + if (0) return s2.p; // no error + if (0) return &c.v; // no error + if (0) return &da1[0]; // no error + if (0) return &da2[0][0]; // no error + if (0) return &sa1[0]; // IndexExp + if (0) return &sa2[0][0]; // IndexExp + if (0) return &x; + if (0) return &x + 1; // optimized to SymOffExp == (& x+4) + if (0) return &x + x; + //if (0) return ptr += &x + 1; // semantic error + if (0) ptr -= &x - &y; // no error + if (0) return (&x, &y); // CommaExp + + return null; // ok +} + +/* +TEST_OUTPUT: +--- +--- +*/ +int* testEscape3( + ref int x, ref int y, + ref int[] da1, + ref int[][] da2, + ref int[1] sa1, + ref int[1][1] sa2, + ref int* ptr, + ref S1 s1, + ref S2 s2, + ref C c, +) +{ + if (0) return &x; // VarExp + if (0) return &s1.v; // DotVarExp + if (0) return s2.p; // no error + if (0) return &c.v; // no error + if (0) return &da1[0]; // no error + if (0) return &da2[0][0]; // no error + if (0) return &sa1[0]; // IndexExp + if (0) return &sa2[0][0]; // IndexExp + if (0) return ptr = &x; + if (0) return ptr = &x + 1; // optimized to SymOffExp == (& x+4) + if (0) return ptr = &x + x; + //if (0) return ptr += &x + 1; // semantic error + if (0) return ptr -= &x - &y; // no error + if (0) return (&x, &y); // CommaExp + + return null; // ok +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return` +fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return` +fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to parameter `sa1`, perhaps annotate with `return` +fail_compilation/fail13902.d(155): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2` +fail_compilation/fail13902.d(156): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2` +fail_compilation/fail13902.d(157): Error: returning `sa2[]` escapes a reference to local variable `sa2` +fail_compilation/fail13902.d(161): Error: returning `cast(int[])s.sa` escapes a reference to local variable `s` +fail_compilation/fail13902.d(162): Error: returning `cast(int[])s.sa` escapes a reference to local variable `s` +fail_compilation/fail13902.d(163): Error: returning `s.sa[]` escapes a reference to local variable `s` +fail_compilation/fail13902.d(166): Error: escaping reference to stack allocated value returned by `makeSA()` +fail_compilation/fail13902.d(167): Error: escaping reference to stack allocated value returned by `makeSA()` +fail_compilation/fail13902.d(168): Error: escaping reference to stack allocated value returned by `makeSA()` +fail_compilation/fail13902.d(171): Error: escaping reference to stack allocated value returned by `makeS()` +fail_compilation/fail13902.d(172): Error: escaping reference to stack allocated value returned by `makeS()` +fail_compilation/fail13902.d(173): Error: escaping reference to stack allocated value returned by `makeS()` +--- +*/ +int[] testEscape4(int[3] sa1) // Bugzilla 9279 +{ + if (0) return sa1; // error <- no error + if (0) return cast(int[])sa1; // error <- no error + if (0) return sa1[]; // error + + int[3] sa2; + if (0) return sa2; // error + if (0) return cast(int[])sa2; // error + if (0) return sa2[]; // error + + struct S { int[3] sa; } + S s; + if (0) return s.sa; // error <- no error + if (0) return cast(int[])s.sa; // error <- no error + if (0) return s.sa[]; // error + + int[3] makeSA() { int[3] ret; return ret; } + if (0) return makeSA(); // error <- no error + if (0) return cast(int[])makeSA(); // error <- no error + if (0) return makeSA()[]; // error <- no error + + S makeS() { S s; return s; } + if (0) return makeS().sa; // error <- no error + if (0) return cast(int[])makeS().sa; // error <- no error + if (0) return makeS().sa[]; // error <- no error + + return null; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(201): Error: returning `x` escapes a reference to local variable `x` +fail_compilation/fail13902.d(202): Error: returning `s1.v` escapes a reference to local variable `s1` +fail_compilation/fail13902.d(206): Error: returning `sa1[0]` escapes a reference to local variable `sa1` +fail_compilation/fail13902.d(207): Error: returning `sa2[0][0]` escapes a reference to local variable `sa2` +fail_compilation/fail13902.d(208): Error: returning `x = 1` escapes a reference to local variable `x` +fail_compilation/fail13902.d(209): Error: returning `x += 1` escapes a reference to local variable `x` +fail_compilation/fail13902.d(210): Error: returning `s1.v = 1` escapes a reference to local variable `s1` +fail_compilation/fail13902.d(211): Error: returning `s1.v += 1` escapes a reference to local variable `s1` +--- +*/ +ref int testEscapeRef1() +{ + int x; + int[] da1; + int[][] da2; + int[1] sa1; + int[1][1] sa2; + S1 s1; + C c; + + if (0) return x; // VarExp + if (0) return s1.v; // DotVarExp + if (0) return c.v; // no error + if (0) return da1[0]; // no error + if (0) return da2[0][0]; // no error + if (0) return sa1[0]; // IndexExp + if (0) return sa2[0][0]; // IndexExp + if (0) return x = 1; // AssignExp + if (0) return x += 1; // BinAssignExp + if (0) return s1.v = 1; // AssignExp (e1 is DotVarExp) + if (0) return s1.v += 1; // BinAssignExp (e1 is DotVarExp) + + static int g; + return g; // ok +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to parameter `x`, perhaps annotate with `return` +fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to parameter `s1`, perhaps annotate with `return` +fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to parameter `sa1`, perhaps annotate with `return` +fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to parameter `sa2`, perhaps annotate with `return` +fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to parameter `x`, perhaps annotate with `return` +fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to parameter `x`, perhaps annotate with `return` +fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to parameter `s1`, perhaps annotate with `return` +fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to parameter `s1`, perhaps annotate with `return` +--- +*/ +ref int testEscapeRef2( + int x, + int[] da1, + int[][] da2, + int[1] sa1, + int[1][1] sa2, + S1 s1, + C c, +) +{ + if (0) return x; // VarExp + if (0) return s1.v; // DotVarExp + if (0) return c.v; // no error + if (0) return da1[0]; // no error + if (0) return da2[0][0]; // no error + if (0) return sa1[0]; // IndexExp + if (0) return sa2[0][0]; // IndexExp + if (0) return x = 1; // AssignExp + if (0) return x += 1; // BinAssignExp + if (0) return s1.v = 1; // AssignExp (e1 is DotVarExp) + if (0) return s1.v += 1; // BinAssignExp (e1 is DotVarExp) + + static int g; + return g; // ok +} + +/* +TEST_OUTPUT: +--- +--- +*/ +ref int testEscapeRef2( + ref int x, + ref int[] da1, + ref int[][] da2, + ref int[1] sa1, + ref int[1][1] sa2, + ref S1 s1, + ref C c, +) +{ + if (0) return x; // VarExp + if (0) return s1.v; // DotVarExp + if (0) return c.v; // no error + if (0) return da1[0]; // no error + if (0) return da2[0][0]; // no error + if (0) return sa1[0]; // IndexExp + if (0) return sa2[0][0]; // IndexExp + if (0) return x = 1; // AssignExp + if (0) return x += 1; // BinAssignExp + if (0) return s1.v = 1; // AssignExp (e1 is DotVarExp) + if (0) return s1.v += 1; // BinAssignExp (e1 is DotVarExp) + + static int g; + return g; // ok +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(294): Error: returning `[& x]` escapes a reference to local variable `x` +fail_compilation/fail13902.d(295): Error: returning `[& x]` escapes a reference to local variable `x` +--- +*/ +int*[] testArrayLiteral1() { int x; return [&x]; } +int*[1] testArrayLiteral2() { int x; return [&x]; } + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(304): Error: returning `S2(& x)` escapes a reference to local variable `x` +fail_compilation/fail13902.d(305): Error: returning `new S2(& x)` escapes a reference to local variable `x` +--- +*/ +S2 testStructLiteral1() { int x; return S2(&x); } +S2* testStructLiteral2() { int x; return new S2(&x); } + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(314): Error: returning `sa[]` escapes a reference to local variable `sa` +fail_compilation/fail13902.d(315): Error: returning `sa[cast(ulong)n..2][1..2]` escapes a reference to local variable `sa` +--- +*/ +int[] testSlice1() { int[3] sa; return sa[]; } +int[] testSlice2() { int[3] sa; int n; return sa[n..2][1..2]; } + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(324): Error: returning `vda[0]` escapes a reference to parameter `vda`, perhaps annotate with `return` +fail_compilation/fail13902.d(325): Error: returning `vda[]` escapes a reference to variadic parameter `vda` +--- +*/ +ref int testDynamicArrayVariadic1(int[] vda...) { return vda[0]; } +int[] testDynamicArrayVariadic2(int[] vda...) { return vda[]; } +int[3] testDynamicArrayVariadic3(int[] vda...) { return vda[0..3]; } // no error + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to parameter `vsa`, perhaps annotate with `return` +fail_compilation/fail13902.d(336): Error: returning `vsa[]` escapes a reference to variadic parameter `vsa` +--- +*/ +ref int testStaticArrayVariadic1(int[3] vsa...) { return vsa[0]; } +int[] testStaticArrayVariadic2(int[3] vsa...) { return vsa[]; } +int[3] testStaticArrayVariadic3(int[3] vsa...) { return vsa[0..3]; } // no error diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13938.d b/gcc/testsuite/gdc.test/fail_compilation/fail13938.d new file mode 100644 index 00000000000..bd18ef2808f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13938.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail13938.d(14): Error: cannot directly load TLS variable 'val' +--- +*/ + +void test1() +{ + static int val; + asm + { + mov EAX, val; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13939.d b/gcc/testsuite/gdc.test/fail_compilation/fail13939.d new file mode 100644 index 00000000000..074c22c89aa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13939.d @@ -0,0 +1,17 @@ +// REQUIRED_ARGS: -o- -fPIC +// DISABLED: win32 win64 +/* +TEST_OUTPUT: +--- +fail_compilation/fail13939.d(15): Error: cannot directly load global variable 'val' with PIC code +--- +*/ +version(Windows) static assert(0); +void test1() +{ + __gshared int val; + asm + { + mov EAX, val; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14.d b/gcc/testsuite/gdc.test/fail_compilation/fail14.d new file mode 100644 index 00000000000..0da6dc4b134 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14.d @@ -0,0 +1,11 @@ + +class A(T) +{ + .A!(A) x; + +} + +void main() +{ + A!(int); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14009.d b/gcc/testsuite/gdc.test/fail_compilation/fail14009.d new file mode 100644 index 00000000000..84f72c27f39 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14009.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail14009.d(12): Error: expression expected not : +--- +*/ + +void main() +{ + asm { + mov EAX, FS: 1 ? 2 : 3; // accepted + mov EAX, FS: 1 ? 2 : : 3; // rejected + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14089.d b/gcc/testsuite/gdc.test/fail_compilation/fail14089.d new file mode 100644 index 00000000000..df1221a2cb4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14089.d @@ -0,0 +1,46 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail14089.d(41): Error: `long` has no effect in expression `1` +fail_compilation/fail14089.d(41): Error: `long` has no effect in expression `1` +fail_compilation/fail14089.d(42): Error: `long` has no effect in expression `1` +fail_compilation/fail14089.d(42): Error: `var` has no effect in expression `n` +fail_compilation/fail14089.d(43): Error: `long` has no effect in expression `1` +fail_compilation/fail14089.d(43): Error: `dotvar` has no effect in expression `s.val` +fail_compilation/fail14089.d(44): Error: `var` has no effect in expression `n` +fail_compilation/fail14089.d(44): Error: `long` has no effect in expression `1` +fail_compilation/fail14089.d(45): Error: `dotvar` has no effect in expression `s.val` +fail_compilation/fail14089.d(45): Error: `long` has no effect in expression `1` +--- +*/ + +bool cond; + +void main() +{ + int foo() { return 0; } + int n; + struct S { int val; } + S s; + + // The whole of each CondExps has side effects, So no error. + cond ? foo() : n; + cond ? foo() : s.val; + cond ? 1 : foo(); + cond ? n : foo(); + cond ? s.val : foo(); + + cond ? (n = 1) : 1; + cond ? (n = 1) : n; + cond ? (n = 1) : s.val; + cond ? 1 : (n = 1); + cond ? n : (n = 1); + cond ? s.val : (n = 1); + + // errors + cond ? 1 : 1; + cond ? 1 : n; + cond ? 1 : s.val; + cond ? n : 1; + cond ? s.val : 1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail142.d b/gcc/testsuite/gdc.test/fail_compilation/fail142.d new file mode 100644 index 00000000000..e89b576adb4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail142.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail142.d(20): Error: cannot create instance of abstract class B +fail_compilation/fail142.d(20): function 'void test()' is not implemented +--- +*/ + +class A +{ + abstract void test() {} +} + +class B : A +{ +} + +void main() +{ + B b = new B(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14249.d b/gcc/testsuite/gdc.test/fail_compilation/fail14249.d new file mode 100644 index 00000000000..c895c5504f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14249.d @@ -0,0 +1,40 @@ +/* +REQUIRED_ARGS: -unittest +TEST_OUTPUT: +--- +fail_compilation/fail14249.d(23): Error: shared static constructor can only be member of module/aggregate/template, not function main +fail_compilation/fail14249.d(24): Error: shared static destructor can only be member of module/aggregate/template, not function main +fail_compilation/fail14249.d(25): Error: static constructor can only be member of module/aggregate/template, not function main +fail_compilation/fail14249.d(26): Error: static destructor can only be member of module/aggregate/template, not function main +fail_compilation/fail14249.d(27): Error: unittest can only be a member of module/aggregate/template, not function main +fail_compilation/fail14249.d(28): Error: invariant can only be a member of aggregate, not function main +fail_compilation/fail14249.d(29): Error: alias this can only be a member of aggregate, not function `main` +fail_compilation/fail14249.d(30): Error: allocator can only be a member of aggregate, not function main +fail_compilation/fail14249.d(31): Error: deallocator can only be a member of aggregate, not function main +fail_compilation/fail14249.d(32): Error: constructor can only be a member of aggregate, not function main +fail_compilation/fail14249.d(33): Error: destructor can only be a member of aggregate, not function main +fail_compilation/fail14249.d(34): Error: postblit can only be a member of struct/union, not function main +fail_compilation/fail14249.d(35): Error: anonymous union can only be a part of an aggregate, not function `main` +fail_compilation/fail14249.d(39): Error: mixin fail14249.main.Mix!() error instantiating +--- +*/ +mixin template Mix() +{ + shared static this() {} + shared static ~this() {} + static this() {} // from fail197.d, 1510 ICE: Assertion failure: 'ad' on line 925 in file 'func.c' + static ~this() {} + unittest {} + invariant {} + alias a this; + new(size_t sz) { return null; } + delete(void* p) { } + this() {} // from fail268.d + ~this() {} // from fail268.d + this(this) {} + union { int x; double y; } +} +void main() +{ + mixin Mix!(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail143.d b/gcc/testsuite/gdc.test/fail_compilation/fail143.d new file mode 100644 index 00000000000..0a0986ac996 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail143.d @@ -0,0 +1,36 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail143.d(23): Error: need 'this' for 'next' of type 'uint()' +fail_compilation/fail143.d(30): Error: template instance fail143.Foo!int error instantiating +--- +*/ + +class Quux +{ + uint x; + + final uint next() + { + return x; + } +} + +template Foo(T) +{ + void bar() + { + int r = Quux.next; + } +} + +int main(char[][] args) +{ + auto prng = new Quux(); + alias Foo!(int).bar baz; + + int x = prng.next; + baz(); + + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14304.d b/gcc/testsuite/gdc.test/fail_compilation/fail14304.d new file mode 100644 index 00000000000..472b33d1543 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14304.d @@ -0,0 +1,70 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail14304.d(26): Error: cannot modify read-only constant S14304(1) +fail_compilation/fail14304.d(58): called from here: sle14304.modify() +fail_compilation/fail14304.d(35): Error: cannot modify read-only constant [1:1, 2:2] +fail_compilation/fail14304.d(61): called from here: modify14304(aae14304) +fail_compilation/fail14304.d(41): Error: cannot modify read-only constant [1, 2, 3] +fail_compilation/fail14304.d(64): called from here: modify14304(cast(const(int)[])index14304) +fail_compilation/fail14304.d(47): Error: cannot modify read-only constant [1.414, 1.732, 2.00000] +fail_compilation/fail14304.d(67): called from here: modify14304(cast(const(double)[])slice14304) +fail_compilation/fail14304.d(53): Error: cannot modify read-only string literal "abc" +fail_compilation/fail14304.d(70): called from here: modify14304(cast(const(char)[])str14304) +--- +*/ + +struct S14304 +{ + int x; + + int modify() const + { + assert(x == 1); + + // This force modification must not affect to ghe s14304 value. + (cast(S14304*)&this).x = 10; + + assert(x == 10); + return x; + } +} +int modify14304(immutable int[int] aa) +{ + auto p = cast(int*)&aa[1]; + *p = 10; + return aa[1]; +} +int modify14304(const(int)[] arr) +{ + auto a = cast(int[])arr; + a[0] = 10; + return arr[0]; +} +int modify14304(const(double)[] arr) +{ + auto a = cast(double[])arr; + a[] = 3.14; + return cast(int)arr[0]; +} +int modify14304(const(char)[] str) +{ + auto s = cast(char[])str; + s[0] = 'z'; + return str[0]; +} + +static immutable sle14304 = immutable S14304(1); +static immutable v14304 = sle14304.modify(); + +static immutable aae14304 = [1:1, 2:2]; +static immutable w14304 = modify14304(aae14304); + +static immutable index14304 = [1, 2, 3]; +static immutable x14304 = modify14304(index14304); + +static immutable slice14304 = [1.414, 1.732, 2]; +static immutable y14304 = modify14304(slice14304); + +static immutable str14304 = "abc"; +static immutable z14304 = modify14304(str14304); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail144.d b/gcc/testsuite/gdc.test/fail_compilation/fail144.d new file mode 100644 index 00000000000..574d1675049 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail144.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail144.d(13): Error: "message" +fail_compilation/fail144.d(26): called from here: bar(7) +--- +*/ + +//import core.stdc.stdio : printf; + +int bar(int i) +{ + assert(i < 0, "message"); + foreach_reverse (k, v; "hello") + { + i <<= 1; + if (k == 2) + break; + i += v; + } + return i; +} + +void main() +{ + static b = bar(7); + auto c = bar(7); + //printf("b = %d, %d\n", b, c); + assert(b == 674); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14406.d b/gcc/testsuite/gdc.test/fail_compilation/fail14406.d new file mode 100644 index 00000000000..09f481691e9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14406.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail14406.d-mixin-20(20): Error: variable fail14406.CFrop.bar_obj cannot be further field because it will change the determined CFrop size +fail_compilation/fail14406.d-mixin-25(25): Error: variable fail14406.IFrop.bar_obj field not allowed in interface +--- +*/ + +class Foo {} + +string strMixin(T)() +{ + static if (T.tupleof.length) {} + return "Bar bar_obj; + static class Bar { Foo foo; }"; +} + +class CFrop +{ + mixin(strMixin!(typeof(this))); +} + +interface IFrop +{ + mixin(strMixin!(typeof(this))); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14407.d b/gcc/testsuite/gdc.test/fail_compilation/fail14407.d new file mode 100644 index 00000000000..341c5cad1d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14407.d @@ -0,0 +1,47 @@ +import imports.a14407; + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14407.d(23): Deprecation: class imports.a14407.C is deprecated +fail_compilation/fail14407.d(23): Deprecation: allocator imports.a14407.C.new is deprecated +fail_compilation/fail14407.d(23): Error: pure function 'fail14407.testC' cannot call impure allocator 'imports.a14407.C.new' +fail_compilation/fail14407.d(23): Error: @safe function 'fail14407.testC' cannot call @system allocator 'imports.a14407.C.new' +fail_compilation/fail14407.d(23): Error: @nogc function 'fail14407.testC' cannot call non-@nogc allocator 'imports.a14407.C.new' +fail_compilation/fail14407.d(23): Error: class imports.a14407.C member `new` is not accessible +fail_compilation/fail14407.d(23): Error: pure function 'fail14407.testC' cannot call impure constructor 'imports.a14407.C.this' +fail_compilation/fail14407.d(23): Error: @safe function 'fail14407.testC' cannot call @system constructor 'imports.a14407.C.this' +fail_compilation/fail14407.d(23): Error: @nogc function 'fail14407.testC' cannot call non-@nogc constructor 'imports.a14407.C.this' +fail_compilation/fail14407.d(23): Error: class imports.a14407.C member `this` is not accessible +fail_compilation/fail14407.d(23): Error: allocator `imports.a14407.C.new` is not nothrow +fail_compilation/fail14407.d(23): Error: constructor `imports.a14407.C.this` is not nothrow +fail_compilation/fail14407.d(21): Error: nothrow function `fail14407.testC` may throw +--- +*/ +void testC() pure nothrow @safe @nogc +{ + new("arg") C(0); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14407.d(46): Deprecation: struct imports.a14407.S is deprecated +fail_compilation/fail14407.d(46): Deprecation: allocator imports.a14407.S.new is deprecated +fail_compilation/fail14407.d(46): Error: pure function 'fail14407.testS' cannot call impure allocator 'imports.a14407.S.new' +fail_compilation/fail14407.d(46): Error: @safe function 'fail14407.testS' cannot call @system allocator 'imports.a14407.S.new' +fail_compilation/fail14407.d(46): Error: @nogc function 'fail14407.testS' cannot call non-@nogc allocator 'imports.a14407.S.new' +fail_compilation/fail14407.d(46): Error: struct imports.a14407.S member `new` is not accessible +fail_compilation/fail14407.d(46): Error: pure function 'fail14407.testS' cannot call impure constructor 'imports.a14407.S.this' +fail_compilation/fail14407.d(46): Error: @safe function 'fail14407.testS' cannot call @system constructor 'imports.a14407.S.this' +fail_compilation/fail14407.d(46): Error: @nogc function 'fail14407.testS' cannot call non-@nogc constructor 'imports.a14407.S.this' +fail_compilation/fail14407.d(46): Error: struct imports.a14407.S member `this` is not accessible +fail_compilation/fail14407.d(46): Error: allocator `imports.a14407.S.new` is not nothrow +fail_compilation/fail14407.d(46): Error: constructor `imports.a14407.S.this` is not nothrow +fail_compilation/fail14407.d(44): Error: nothrow function `fail14407.testS` may throw +--- +*/ +void testS() pure nothrow @safe @nogc +{ + new("arg") S(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14416.d b/gcc/testsuite/gdc.test/fail_compilation/fail14416.d new file mode 100644 index 00000000000..b0518c85e75 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14416.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail14416.d(13): Error: template S(T) does not have property 'sizeof' +--- +*/ + +struct S(T) +{ + int x; +} + +enum n = S.sizeof; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d new file mode 100644 index 00000000000..ca209aa5b98 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d @@ -0,0 +1,149 @@ +// REQUIRED_ARGS: -o- + +class C0a { } +class C1a { ~this() {} } +class C2a { ~this() {} @nogc pure @safe delete(void* p) {} } +class C3a { @nogc pure @safe ~this() {} delete(void* p) {} } +class C4a { @nogc pure @safe ~this() {} @nogc pure @safe delete(void* p) {} } + +class C0b { } +class C1b { ~this() {} } +class C2b { ~this() {} nothrow delete(void* p) {} } +class C3b { nothrow ~this() {} delete(void* p) {} } +class C4b { nothrow ~this() {} nothrow delete(void* p) {} } + +struct S0a { } +struct S1a { ~this() {} } +struct S2a { ~this() {} @nogc pure @safe delete(void* p) {} } +struct S3a { @nogc pure @safe ~this() {} delete(void* p) {} } +struct S4a { @nogc pure @safe ~this() {} @nogc pure @safe delete(void* p) {} } + +struct S0b { } +struct S1b { ~this() {} } +struct S2b { ~this() {} nothrow delete(void* p) {} } +struct S3b { nothrow ~this() {} delete(void* p) {} } +struct S4b { nothrow ~this() {} nothrow delete(void* p) {} } + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14486.d(44): Error: delete c0 is not @safe but is used in @safe function test1a +fail_compilation/fail14486.d(45): Error: pure function 'fail14486.test1a' cannot call impure destructor 'fail14486.C1a.~this' +fail_compilation/fail14486.d(45): Error: @safe function 'fail14486.test1a' cannot call @system destructor 'fail14486.C1a.~this' +fail_compilation/fail14486.d(45): Error: @nogc function 'fail14486.test1a' cannot call non-@nogc destructor 'fail14486.C1a.~this' +fail_compilation/fail14486.d(46): Error: pure function 'fail14486.test1a' cannot call impure destructor 'fail14486.C2a.~this' +fail_compilation/fail14486.d(46): Error: @safe function 'fail14486.test1a' cannot call @system destructor 'fail14486.C2a.~this' +fail_compilation/fail14486.d(46): Error: @nogc function 'fail14486.test1a' cannot call non-@nogc destructor 'fail14486.C2a.~this' +fail_compilation/fail14486.d(47): Error: pure function 'fail14486.test1a' cannot call impure deallocator 'fail14486.C3a.delete' +fail_compilation/fail14486.d(47): Error: @safe function 'fail14486.test1a' cannot call @system deallocator 'fail14486.C3a.delete' +fail_compilation/fail14486.d(47): Error: @nogc function 'fail14486.test1a' cannot call non-@nogc deallocator 'fail14486.C3a.delete' +fail_compilation/fail14486.d(48): Error: delete c4 is not @safe but is used in @safe function test1a +---*/ +void test1a() @nogc pure @safe +{ + C0a c0; delete c0; // error + C1a c1; delete c1; // error + C2a c2; delete c2; // error + C3a c3; delete c3; // error + C4a c4; delete c4; // no error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14486.d(63): Error: destructor `fail14486.C1b.~this` is not nothrow +fail_compilation/fail14486.d(64): Error: destructor `fail14486.C2b.~this` is not nothrow +fail_compilation/fail14486.d(65): Error: deallocator `fail14486.C3b.delete` is not nothrow +fail_compilation/fail14486.d(60): Error: nothrow function `fail14486.test1b` may throw +--- +*/ +void test1b() nothrow +{ + C0b c0; delete c0; // no error + C1b c1; delete c1; // error + C2b c2; delete c2; // error + C3b c3; delete c3; // error + C4b c4; delete c4; // no error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14486.d(86): Error: delete s0 is not @safe but is used in @safe function test2a +fail_compilation/fail14486.d(87): Error: pure function 'fail14486.test2a' cannot call impure destructor 'fail14486.S1a.~this' +fail_compilation/fail14486.d(87): Error: @safe function 'fail14486.test2a' cannot call @system destructor 'fail14486.S1a.~this' +fail_compilation/fail14486.d(87): Error: @nogc function 'fail14486.test2a' cannot call non-@nogc destructor 'fail14486.S1a.~this' +fail_compilation/fail14486.d(88): Error: pure function 'fail14486.test2a' cannot call impure destructor 'fail14486.S2a.~this' +fail_compilation/fail14486.d(88): Error: @safe function 'fail14486.test2a' cannot call @system destructor 'fail14486.S2a.~this' +fail_compilation/fail14486.d(88): Error: @nogc function 'fail14486.test2a' cannot call non-@nogc destructor 'fail14486.S2a.~this' +fail_compilation/fail14486.d(89): Error: pure function 'fail14486.test2a' cannot call impure deallocator 'fail14486.S3a.delete' +fail_compilation/fail14486.d(89): Error: @safe function 'fail14486.test2a' cannot call @system deallocator 'fail14486.S3a.delete' +fail_compilation/fail14486.d(89): Error: @nogc function 'fail14486.test2a' cannot call non-@nogc deallocator 'fail14486.S3a.delete' +--- +*/ +void test2a() @nogc pure @safe +{ + S0a* s0; delete s0; // error + S1a* s1; delete s1; // error + S2a* s2; delete s2; // error + S3a* s3; delete s3; // error + S4a* s4; delete s4; // no error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14486.d(105): Error: destructor `fail14486.S1b.~this` is not nothrow +fail_compilation/fail14486.d(106): Error: destructor `fail14486.S2b.~this` is not nothrow +fail_compilation/fail14486.d(107): Error: deallocator `fail14486.S3b.delete` is not nothrow +fail_compilation/fail14486.d(102): Error: nothrow function `fail14486.test2b` may throw +--- +*/ +void test2b() nothrow +{ + S0b* s0; delete s0; // no error + S1b* s1; delete s1; // error + S2b* s2; delete s2; // error + S3b* s3; delete s3; // error + S4b* s4; delete s4; // no error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14486.d(127): Error: delete a0 is not @safe but is used in @safe function test3a +fail_compilation/fail14486.d(128): Error: pure function 'fail14486.test3a' cannot call impure destructor 'fail14486.S1a.~this' +fail_compilation/fail14486.d(128): Error: @safe function 'fail14486.test3a' cannot call @system destructor 'fail14486.S1a.~this' +fail_compilation/fail14486.d(128): Error: @nogc function 'fail14486.test3a' cannot call non-@nogc destructor 'fail14486.S1a.~this' +fail_compilation/fail14486.d(129): Error: pure function 'fail14486.test3a' cannot call impure destructor 'fail14486.S2a.~this' +fail_compilation/fail14486.d(129): Error: @safe function 'fail14486.test3a' cannot call @system destructor 'fail14486.S2a.~this' +fail_compilation/fail14486.d(129): Error: @nogc function 'fail14486.test3a' cannot call non-@nogc destructor 'fail14486.S2a.~this' +fail_compilation/fail14486.d(130): Error: delete a3 is not @safe but is used in @safe function test3a +fail_compilation/fail14486.d(131): Error: delete a4 is not @safe but is used in @safe function test3a +--- +*/ +void test3a() @nogc pure @safe +{ + S0a[] a0; delete a0; // error + S1a[] a1; delete a1; // error + S2a[] a2; delete a2; // error + S3a[] a3; delete a3; // error + S4a[] a4; delete a4; // error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14486.d(145): Error: destructor `fail14486.S1b.~this` is not nothrow +fail_compilation/fail14486.d(146): Error: destructor `fail14486.S2b.~this` is not nothrow +fail_compilation/fail14486.d(142): Error: nothrow function `fail14486.test3b` may throw +--- +*/ +void test3b() nothrow +{ + S0b[] a0; delete a0; // no error + S1b[] a1; delete a1; // error + S2b[] a2; delete a2; // error + S3b[] a3; delete a3; // no error + S4b[] a4; delete a4; // no error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail145.d b/gcc/testsuite/gdc.test/fail_compilation/fail145.d new file mode 100644 index 00000000000..9d285dc1525 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail145.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail145.d(13): Error: assert(i < 0) failed +fail_compilation/fail145.d(26): called from here: bar(7) +--- +*/ + +//import core.stdc.stdio : printf; + +int bar(int i) +{ + assert(i < 0); + foreach_reverse (k, v; "hello") + { + i <<= 1; + if (k == 2) + break; + i += v; + } + return i; +} + +void main() +{ + static b = bar(7); + auto c = bar(7); + //printf("b = %d, %d\n", b, c); + assert(b == 674); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14554.d b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d new file mode 100644 index 00000000000..5d4e96cdc64 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d @@ -0,0 +1,30 @@ +// REQUIRED_ARGS: -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14554.d(28): Error: fail14554.issue14554_1.foo called with argument types (int) matches both: +fail_compilation/fail14554.d(17): fail14554.issue14554_1.foo!bool.foo(int j) +and: +fail_compilation/fail14554.d(18): fail14554.issue14554_1.foo!bool.foo(int j) +fail_compilation/fail14554.d(29): Error: fail14554.issue14554_2.foo called with argument types (int) matches both: +fail_compilation/fail14554.d(22): fail14554.issue14554_2.foo!bool.foo(int j) +and: +fail_compilation/fail14554.d(23): fail14554.issue14554_2.foo!bool.foo(int j) +--- +*/ +struct issue14554_1 { + void foo(T)(int j) {} + static void foo(T)(int j) {} +} + +struct issue14554_2 { + static void foo(T)(int j) {} + void foo(T)(int j) {} +} + +void test14554() +{ + issue14554_1.foo!bool(1); + issue14554_2.foo!bool(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d new file mode 100644 index 00000000000..89840010eb4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d @@ -0,0 +1,43 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail14669.d(11): Error: 'auto' can only be used as part of 'auto ref' for template function parameters +fail_compilation/fail14669.d(16): Error: template instance fail14669.foo1!() error instantiating +fail_compilation/fail14669.d(12): Error: 'auto' can only be used as part of 'auto ref' for template function parameters +fail_compilation/fail14669.d(17): Error: template fail14669.foo2 cannot deduce function from argument types !()(int), candidates are: +fail_compilation/fail14669.d(12): fail14669.foo2()(auto int a) +--- +*/ +void foo1()(auto int a) {} +void foo2()(auto int a) {} + +void test1() +{ + alias f1 = foo1!(); + foo2(1); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail14669.d(29): Error: 'auto' can only be used as part of 'auto ref' for template function parameters +fail_compilation/fail14669.d(38): Error: template instance fail14669.bar1!int error instantiating +fail_compilation/fail14669.d(30): Error: 'auto' can only be used as part of 'auto ref' for template function parameters +fail_compilation/fail14669.d(40): Error: template instance fail14669.bar2!int error instantiating +--- +*/ +void bar1(T)(auto ref T x) {} +void bar2(T)(auto ref T x) {} + +void test2() +{ + int n; + + bar1(1); + bar1(n); + alias b1 = bar1!(int); + + alias b2 = bar2!(int); + bar2(n); + bar2(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14965.d b/gcc/testsuite/gdc.test/fail_compilation/fail14965.d new file mode 100644 index 00000000000..f1a1ec152e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14965.d @@ -0,0 +1,38 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail14965.d(19): Error: forward reference to inferred return type of function 'foo1' +fail_compilation/fail14965.d(20): Error: forward reference to inferred return type of function 'foo2' +fail_compilation/fail14965.d(22): Error: forward reference to inferred return type of function 'bar1' +fail_compilation/fail14965.d(23): Error: forward reference to inferred return type of function 'bar2' +fail_compilation/fail14965.d(25): Error: forward reference to inferred return type of function 'baz1' +fail_compilation/fail14965.d(26): Error: forward reference to inferred return type of function 'baz2' +fail_compilation/fail14965.d(30): Error: forward reference to inferred return type of function 'foo1' +fail_compilation/fail14965.d(31): Error: forward reference to inferred return type of function 'foo2' +fail_compilation/fail14965.d(33): Error: forward reference to inferred return type of function 'bar1' +fail_compilation/fail14965.d(34): Error: forward reference to inferred return type of function 'bar2' +fail_compilation/fail14965.d(36): Error: forward reference to inferred return type of function 'baz1' +fail_compilation/fail14965.d(37): Error: forward reference to inferred return type of function 'baz2' +--- +*/ + +auto foo1() { alias F = typeof(foo1); } // TypeTypeof +auto foo2() { alias FP = typeof(&foo2); } // TypeTypeof + +auto bar1() { auto fp = &bar1; } // ExpInitializer +auto bar2() { auto fp = cast(void function())&bar2; } // castTo + +auto baz1() { return &baz1; } // ReturnStatement +auto baz2() { (&baz2); } // ExpStatement + +class C +{ + auto foo1() { alias F = typeof(this.foo1); } + auto foo2() { alias FP = typeof(&this.foo2); } + + auto bar1() { auto fp = &this.bar1; } + auto bar2() { auto dg = cast(void delegate())&this.bar2; } + + auto baz1() { return &baz1; } + auto baz2() { (&baz2); } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15.d b/gcc/testsuite/gdc.test/fail_compilation/fail15.d new file mode 100644 index 00000000000..564ddda7eec --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15.d @@ -0,0 +1,21 @@ +/* +Segfault on DMD 0.095 +http://www.digitalmars.com/d/archives/digitalmars/D/bugs/926.html +*/ +module test; + +template Test() +{ + bool opIndex(bool x) + { + return !x; + } +} + +void main() +{ + mixin Test!() xs; + bool x = xs[false]; +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail150.d b/gcc/testsuite/gdc.test/fail_compilation/fail150.d new file mode 100644 index 00000000000..4a53053af66 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail150.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail150.d(22): Error: e.new is only for allocating nested classes +--- +*/ + +//import std.stdio; + +class Class1 +{ +} + +class Foo +{ +} + +int main(char[][] argv) +{ + Class1 myclass = new Class1; + + myclass.new Foo(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15044.d b/gcc/testsuite/gdc.test/fail_compilation/fail15044.d new file mode 100644 index 00000000000..8674b8d08c6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15044.d @@ -0,0 +1,32 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail15044.d(30): Error: generated function fail15044.V.opAssign is not callable because it is annotated with @disable +--- +*/ + +struct S +{ + void opAssign(S) {} +} + +struct V +{ + // `s` has opAssign, so struct V needs to generate member-wise opAssign. + // But S.opAssign is not callable on const object, so V.opAssign should be + // @disable. + const S s; + + // Here, the initializer of x is evaluated in V.semantic2. But + // V.opAssign.semantic3 is not yet invoked, so its attribute should be + // lazily inferred in functionSemantic even though it's non-instantiated function. + enum int x = () + { + // Here, the initializer of x is evaluated in V.semantic2, and + // V.opAssign.semantic3 is not yet invoked in this time. + // Therefore its @disable attribute needs to be inferred by + // functionSemantic, even though it's non-instantiated function. + V v; + v = v; + }(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15089.d b/gcc/testsuite/gdc.test/fail_compilation/fail15089.d new file mode 100644 index 00000000000..221a97871bf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15089.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail15089.d(10): Error: cannot implicitly convert expression `130` of type `int` to `byte` +--- +*/ + +enum Pieces {Rook = 2} /* line 1 */ +immutable int color = 0b10000000; +byte piece = Pieces.Rook ^ color; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail152.d b/gcc/testsuite/gdc.test/fail_compilation/fail152.d new file mode 100644 index 00000000000..60cf4ce2782 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail152.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail152.d(15): Error: cannot use type double as an operand +--- +*/ + +// 1028 Segfault using tuple inside asm code. + +void a(X...)(X expr) +{ + alias X[0] var1; + version(GNU) + { + version(X86) asm {"fstpd %0;" : "=m" (var1) : : ;} + else version(X86_64) asm {"fstpd %0;" : "=m" (var1) : : ;} + else static assert(false, "ASM code not implemented for this architecture"); + } + else asm { + //fld double ptr X[0]; // (1) segfaults + fstp double ptr var1; // (2) ICE + } +} + +void main() +{ + a(3.6); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15292.d b/gcc/testsuite/gdc.test/fail_compilation/fail15292.d new file mode 100644 index 00000000000..3b3602fc502 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15292.d @@ -0,0 +1,28 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail15292.d(27): Error: cannot compare S15292 because its auto generated member-wise equality has recursive definition +--- +*/ + +struct NullableRef15292(T) +{ + inout(T) get() inout + { + assert(false); + } + + alias get this; +} + +struct S15292 +{ + NullableRef15292!S15292 n; +} + +void main() +{ + S15292 s; + assert(s == s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail153.d b/gcc/testsuite/gdc.test/fail_compilation/fail153.d new file mode 100644 index 00000000000..8e397e3d10c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail153.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail153.d(10): Error: class fail153.Bar cannot inherit from final class Foo +--- +*/ + +final class Foo { } + +class Bar : Foo { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail154.d b/gcc/testsuite/gdc.test/fail_compilation/fail154.d new file mode 100644 index 00000000000..8b5fefc3820 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail154.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail154.d(18): Error: template instance X!(MYP!int) does not match template declaration X(T : Policy!T, alias Policy) +--- +*/ + +class X(T:Policy!(T), alias Policy) +{ + mixin Policy!(T); +} + +template MYP(T) +{ + void foo(T); +} + +X!(MYP!(int)) x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail155.d b/gcc/testsuite/gdc.test/fail_compilation/fail155.d new file mode 100644 index 00000000000..cc1e03c3a5c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail155.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail155.d(19): Error: overlapping initialization for y +--- +*/ + +struct S +{ + int i; + union + { + int x; + int y; + } + int j; +} + +S s = S( 1, 2, 3, 4 ); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15535.d b/gcc/testsuite/gdc.test/fail_compilation/fail15535.d new file mode 100644 index 00000000000..d53e4d7f2d1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15535.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail15535.d(17): Error: goto default not allowed in final switch statement +--- +*/ + +void test() +{ + int i; + switch (i) + { + case 0: + final switch (i) + { + case 1: + goto default; + } + default: + break; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15550.d b/gcc/testsuite/gdc.test/fail_compilation/fail15550.d new file mode 100644 index 00000000000..e20a7f294f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15550.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail15550.d(25): Error: partial template instance foo!int has no type +fail_compilation/fail15550.d(26): Error: partial template instance opDispatch!"_isMatrix" has no type +fail_compilation/fail15550.d(27): Error: partial template instance baz!"_isMatrix" has no type +--- +*/ + +T foo(T, T2)(T2) +{ +} + +struct Vector +{ + void opDispatch(string, U)(U) + { + } + + void baz(string, U)(U) + { + } +} + +alias T1 = typeof(foo!int); +alias T2 = typeof(Vector._isMatrix); +alias T3 = typeof(Vector.baz!"_isMatrix"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail156.d b/gcc/testsuite/gdc.test/fail_compilation/fail156.d new file mode 100644 index 00000000000..cfd5b83a01b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail156.d @@ -0,0 +1,46 @@ +// REQUIRED_ARGS: -d +/* +TEST_OUTPUT: +--- +fail_compilation/fail156.d(33): Error: overlapping initialization for y +fail_compilation/fail156.d(40): Error: overlapping initialization for y +--- +*/ + +alias int myint; + +struct S +{ + int i; + union + { + int x = 2; + int y; + } + int j = 3; + myint k = 4; +} + +void main() +{ + S s = S( 1, 5 ); + assert(s.i == 1); + assert(s.x == 5); + assert(s.y == 5); + assert(s.j == 3); + assert(s.k == 4); + + static S t = S( 1, 6, 6 ); + assert(t.i == 1); + assert(t.x == 6); + assert(t.y == 6); + assert(t.j == 3); + assert(t.k == 4); + + S u = S( 1, 5, 6 ); + assert(u.i == 1); + assert(u.x == 5); + assert(u.y == 5); + assert(u.j == 3); + assert(u.k == 4); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d b/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d new file mode 100644 index 00000000000..9726e3df339 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d @@ -0,0 +1,42 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail15616a.d(41): Error: none of the overloads of 'foo' are callable using argument types (double), candidates are: +fail_compilation/fail15616a.d(14): fail15616a.foo(int a) +fail_compilation/fail15616a.d(17): fail15616a.foo(int a, int b) +fail_compilation/fail15616a.d(26): fail15616a.foo(int a, int b, int c) +fail_compilation/fail15616a.d(29): fail15616a.foo(string a) +fail_compilation/fail15616a.d(32): fail15616a.foo(string a, string b) +fail_compilation/fail15616a.d(41): ... (3 more, -v to show) ... +--- +*/ + +void foo(int a) +{} + +void foo(int a, int b) +{} + +void foo(T)(T a) if (is(T == float)) +{} + +void foo(T)(T a) if (is(T == char)) +{} + +void foo(int a, int b, int c) +{} + +void foo(string a) +{} + +void foo(string a, string b) +{} + +void foo(string a, string b, string c) +{} + + +void main() +{ + foo(3.14); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15616b.d b/gcc/testsuite/gdc.test/fail_compilation/fail15616b.d new file mode 100644 index 00000000000..53defaea1c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15616b.d @@ -0,0 +1,44 @@ +/* +REQUIRED_ARGS: -v +--- +fail_compilation/fail15616b.d(43): Error: none of the overloads of 'foo' are callable using argument types (double), candidates are: +fail_compilation/fail15616b.d(16): fail15616b.foo(int a) +fail_compilation/fail15616b.d(19): fail15616b.foo(int a, int b) +fail_compilation/fail15616b.d(28): fail15616b.foo(int a, int b, int c) +fail_compilation/fail15616b.d(31): fail15616b.foo(string a) +fail_compilation/fail15616b.d(34): fail15616b.foo(string a, string b) +fail_compilation/fail15616b.d(37): fail15616b.foo(string a, string b, string c) +fail_compilation/fail15616b.d(22): fail15616b.foo(T)(T a) if (is(T == float)) +fail_compilation/fail15616b.d(25): fail15616b.foo(T)(T a) if (is(T == char)) +--- +*/ + +void foo(int a) +{} + +void foo(int a, int b) +{} + +void foo(T)(T a) if (is(T == float)) +{} + +void foo(T)(T a) if (is(T == char)) +{} + +void foo(int a, int b, int c) +{} + +void foo(string a) +{} + +void foo(string a, string b) +{} + +void foo(string a, string b, string c) +{} + + +void main() +{ + foo(3.14); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15626.d b/gcc/testsuite/gdc.test/fail_compilation/fail15626.d new file mode 100644 index 00000000000..3b7020539c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15626.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail15626.d(12): Error: class fail15626.D C++ base class C needs at least one virtual function +--- +*/ + +extern (C++) +{ + class C { } + interface I { void f(); } + class D : C, I + { + void f() { } + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15667.d b/gcc/testsuite/gdc.test/fail_compilation/fail15667.d new file mode 100644 index 00000000000..f23963f0a8c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15667.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/imports/a15667.d(16): Error: basic type expected, not `;` +fail_compilation/imports/a15667.d(19): Error: declaration expected following attribute, not end of file +--- +*/ + +void main() +{ + import imports.a15667; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail158.d b/gcc/testsuite/gdc.test/fail_compilation/fail158.d new file mode 100644 index 00000000000..353874f598b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail158.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail158.d(17): Error: more initializers than fields (2) of S +--- +*/ + +struct S +{ + int i; + int j = 3; +} + + +void main() +{ + S s = S( 1, 5, 6 ); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail159.d b/gcc/testsuite/gdc.test/fail_compilation/fail159.d new file mode 100644 index 00000000000..13be8eeefac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail159.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail159.d(24): Error: static assert `foo(S(1, 5), S(1, 4)) == 0` is false +--- +*/ + +struct S +{ + int i; + int j = 3; + + int opEquals(S e2) { return 1; } +} + +int foo(S s1, S s2) +{ + return s1 == s2; +} + +void main() +{ + static assert(foo( S(1,5), S(1,5) ) == 1); + static assert(foo( S(1,5), S(1,4) ) == 0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16.d b/gcc/testsuite/gdc.test/fail_compilation/fail16.d new file mode 100644 index 00000000000..c9af9d30088 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16.d @@ -0,0 +1,20 @@ +// ICE(template.c) in DMD0.080 + +int i; + +template bar(T) +{ + void bar(int x) {} +} + +template foo(alias X) +{ + bar!(typeof(X))(X); +} + + +void main() +{ + foo!(i); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail160.d b/gcc/testsuite/gdc.test/fail_compilation/fail160.d new file mode 100644 index 00000000000..1e2414cf74b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail160.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail160.d(22): Error: typeid(fail160.Foo).vtbl is not yet implemented at compile time +--- +*/ + +interface Foo +{ + void work(); +} +template Wrapper(B, alias Func, int func) +{ + alias typeof(&Func) FuncPtr; + + private static FuncPtr get_funcptr() { return func; } +} + + +int main(char[][] args) +{ + auto x = new Wrapper!(Foo, Foo.work, cast(int)(Foo.classinfo.vtbl[0]))(); + + return 0; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail161.d b/gcc/testsuite/gdc.test/fail_compilation/fail161.d new file mode 100644 index 00000000000..d0aa940c043 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail161.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail161.d(15): Error: template instance MetaString!"2 == 1" does not match template declaration MetaString(String) +--- +*/ + +template MetaString(String) +{ + alias String Value; +} + +void main() +{ + alias MetaString!("2 == 1") S; + assert(mixin(S.Value)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail162.d b/gcc/testsuite/gdc.test/fail_compilation/fail162.d new file mode 100644 index 00000000000..f49fbac6497 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail162.d @@ -0,0 +1,32 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail162.d(25): Error: template fail162.testHelper cannot deduce function from argument types !()(string, string), candidates are: +fail_compilation/fail162.d(10): fail162.testHelper(A...)() +fail_compilation/fail162.d(30): Error: template instance fail162.test!("hello", "world") error instantiating +--- +*/ + +template testHelper(A ...) +{ + char[] testHelper() + { + char[] result; + foreach (t; a) + { + result ~= "int " ~ t ~ ";\r\n"; + } + return result; + } +} + +template test(A...) +{ + const char[] test = testHelper(A); +} + +int main(char[][] args) +{ + mixin(test!("hello", "world")); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail163.d b/gcc/testsuite/gdc.test/fail_compilation/fail163.d new file mode 100644 index 00000000000..c2eb1fdd142 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail163.d @@ -0,0 +1,90 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail163.d(11): Error: cannot implicitly convert expression `q` of type `const(char)[]` to `char[]` +--- +*/ +void test1() +{ + char[] p; + const(char)[] q; + p = q; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail163.d(24): Error: cannot implicitly convert expression `p` of type `const(int***)` to `const(int)***` +--- +*/ +void test2() +{ + const int*** p; + const(int)*** cp; + cp = p; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail163.d(37): Error: cannot modify const expression p +--- +*/ +void test3() +{ + const(uint***) p; + const(int)*** cp; + p = cp; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail163.d(50): Error: cannot implicitly convert expression `cp` of type `const(int)***[]` to `const(uint***)[]` +--- +*/ +void test4() +{ + const(uint***)[] p; + const(int)***[] cp; + p = cp; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail163.d(63): Error: cannot modify const expression *p +--- +*/ +void test5() +{ + int x; + const(int)* p = &x; + *p = 3; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail163.d(76): Error: cannot implicitly convert expression `& x` of type `int*` to `immutable(int)*` +fail_compilation/fail163.d(77): Error: cannot modify immutable expression *p +--- +*/ +void test6() +{ + int x; + immutable(int)* p = &x; + *p = 3; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail163.d(89): Error: cannot implicitly convert expression `& x` of type `const(int)*` to `int*` +--- +*/ +void test7() +{ + const(int) x = 3; + int* p = &x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16600.d b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d new file mode 100644 index 00000000000..a7f30d9187c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d @@ -0,0 +1,26 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail16600.d(22): Error: fail16600.S.__ctor called with argument types (string) const matches both: +fail_compilation/fail16600.d(16): fail16600.S.this(string _param_0) +and: +fail_compilation/fail16600.d(17): fail16600.S.this(string _param_0) immutable +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=16600 + +struct S +{ + int i; + + this(string) { i = 1; } + this(string) immutable { i = 2; } +} + +void main() +{ + auto a = const(S)("abc"); + assert(a.i == 2); +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail169.d b/gcc/testsuite/gdc.test/fail_compilation/fail169.d new file mode 100644 index 00000000000..bd1da0bf6b2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail169.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail169.d(8): Error: cannot have const out parameter of type const(int) +--- +*/ + +void foo(const out int x) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17.d b/gcc/testsuite/gdc.test/fail_compilation/fail17.d new file mode 100644 index 00000000000..fa3b4888c12 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17.d @@ -0,0 +1,8 @@ +struct A(T) +{ + mixin B!(T, A!(T)); +} + +A!(int) x; + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail170.d b/gcc/testsuite/gdc.test/fail_compilation/fail170.d new file mode 100644 index 00000000000..a78fc035dde --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail170.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail170.d(8): Error: variable fail170.foo.x cannot be final, perhaps you meant const? +--- +*/ + +void foo(final out int x) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail172.d b/gcc/testsuite/gdc.test/fail_compilation/fail172.d new file mode 100644 index 00000000000..c7ccdc16b8d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail172.d @@ -0,0 +1,32 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail172.d(25): Error: cannot modify const expression c1.x +fail_compilation/fail172.d(26): Error: cannot modify const expression c2.x +fail_compilation/fail172.d(30): Error: cannot modify const expression s1.x +fail_compilation/fail172.d(31): Error: cannot modify const expression s2.x +--- +*/ + +class C +{ + int x; +} + +struct S +{ + int x; +} + +void main() +{ + const(C) c1 = new C(); + const C c2 = new C(); + c1.x = 3; + c2.x = 3; + + const(S) s1; + const S s2; + s1.x = 3; + s2.x = 3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17275.d b/gcc/testsuite/gdc.test/fail_compilation/fail17275.d new file mode 100644 index 00000000000..fcccdf2eecd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17275.d @@ -0,0 +1,20 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail17275.d(12): Error: undefined identifier `ModuleGroup`, did you mean function `moduleGroup`? +fail_compilation/fail17275.d(12): Error: inout on return means inout must be on a parameter as well for inout(ModuleGroup)() +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17275 + +struct DSO +{ + inout(ModuleGroup) moduleGroup() { } +} + +struct ThreadDSO +{ + DSO* _pdso; + void[] _tlsRange; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17354.d b/gcc/testsuite/gdc.test/fail_compilation/fail17354.d new file mode 100644 index 00000000000..e09f1e57914 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17354.d @@ -0,0 +1,19 @@ +/* REQUIRED_ARGS: -de + * TEST_OUTPUT: +--- +fail_compilation/fail17354.d(13): Deprecation: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Foo.opEquals`; add `override` attribute +fail_compilation/fail17354.d(18): Deprecation: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Bar.opEquals`; add `override` attribute +--- + */ + +// https://issues.dlang.org/show_bug.cgi?id=17354 + +final class Foo +{ + bool opEquals(const Object) const {return true;} +} + +class Bar +{ + bool opEquals(const Object) const {return true;} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17419.d b/gcc/testsuite/gdc.test/fail_compilation/fail17419.d new file mode 100644 index 00000000000..82d416026e5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17419.d @@ -0,0 +1,12 @@ + +// https://issues.dlang.org/show_bug.cgi?id=17419 +/* TEST_OUTPUT: +--- +fail_compilation/fail17419.d(10): Error: argument to `__traits(getLinkage, 64)` is not a declaration +fail_compilation/fail17419.d(11): Error: expected 1 arguments for `getLinkage` but had 2 +--- +*/ + +enum s = __traits(getLinkage, 8 * 8); +enum t = __traits(getLinkage, 8, 8); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17421.d b/gcc/testsuite/gdc.test/fail_compilation/fail17421.d new file mode 100644 index 00000000000..c308ad5f150 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17421.d @@ -0,0 +1,16 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail17421.d(14): Error: argument to `__traits(getFunctionVariadicStyle, 1)` is not a function +fail_compilation/fail17421.d(14): while evaluating: `static assert(__traits(getFunctionVariadicStyle, 1) == "none")` +fail_compilation/fail17421.d(15): Error: argument to `__traits(getFunctionVariadicStyle, int*)` is not a function +fail_compilation/fail17421.d(15): while evaluating: `static assert(__traits(getFunctionVariadicStyle, int*) == "none")` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17421 + +alias int* x; + +static assert(__traits(getFunctionVariadicStyle, 1) == "none"); +static assert(__traits(getFunctionVariadicStyle, x) == "none"); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17491.d b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d new file mode 100644 index 00000000000..4902392cf0f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d @@ -0,0 +1,41 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail17491.d(24): Error: (S17491).init is not an lvalue +fail_compilation/fail17491.d(25): Error: S17491(0) is not an lvalue +fail_compilation/fail17491.d(27): Error: constant S17491(0).field is not an lvalue +fail_compilation/fail17491.d(28): Error: constant *&S17491(0).field is not an lvalue +fail_compilation/fail17491.d(33): Error: S17491(0) is not an lvalue +fail_compilation/fail17491.d(34): Error: S17491(0) is not an lvalue +fail_compilation/fail17491.d(36): Error: constant S17491(0).field is not an lvalue +fail_compilation/fail17491.d(37): Error: constant *&S17491(0).field is not an lvalue +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17491 + +struct S17491 +{ + int field; + static int var; +} + +void test17491() +{ + S17491.init = S17491(42); // NG + *&S17491.init = S17491(42); // NG + + S17491.init.field = 42; // NG + *&S17491.init.field = 42; // Should be NG + + S17491.init.var = 42; // OK + *&S17491.init.var = 42; // OK + + S17491(0) = S17491(42); // NG + *&S17491(0) = S17491(42); // NG + + S17491(0).field = 42; // NG + *&S17491(0).field = 42; // Should be NG + + S17491(0).var = 42; // OK + *&S17491(0).var = 42; // OK +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17492.d b/gcc/testsuite/gdc.test/fail_compilation/fail17492.d new file mode 100644 index 00000000000..e45c2e59359 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17492.d @@ -0,0 +1,23 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail17492.d(19): Error: class fail17492.C.testE.I already exists at fail_compilation/fail17492.d(12). Perhaps in another function with the same name? +--- +https://issues.dlang.org/show_bug.cgi?id=17492 +*/ + +class C +{ + void testE() + { + class I + { + } + } + + void testE() + { + class I + { + } + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17502.d b/gcc/testsuite/gdc.test/fail_compilation/fail17502.d new file mode 100644 index 00000000000..8202b1e9380 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17502.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail17502.d(12): Error: function fail17502.Foo.foo void functions have no result +fail_compilation/fail17502.d(13): Error: cannot have parameter of type const(void) +fail_compilation/fail17502.d(16): Error: function fail17502.Foo.bar void functions have no result +fail_compilation/fail17502.d(17): Error: cannot have parameter of type const(void) +--- +*/ +class Foo +{ + void foo() + out (res) { assert(res > 5); } + body {} + + auto bar() + out (res) { assert (res > 5); } + body { return; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail176.d b/gcc/testsuite/gdc.test/fail_compilation/fail176.d new file mode 100644 index 00000000000..908d08cd3aa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail176.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail176.d(13): Error: cannot modify immutable expression a[1] +fail_compilation/fail176.d(16): Error: cannot modify immutable expression b[1] +fail_compilation/fail176.d(19): Error: cannot modify const expression c[1] +--- +*/ + +void foo() +{ + auto a = "abc"; + a[1] = 'd'; + + immutable char[3] b = "abc"; + b[1] = 'd'; + + const char[3] c = "abc"; + c[1] = 'd'; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17612.d b/gcc/testsuite/gdc.test/fail_compilation/fail17612.d new file mode 100644 index 00000000000..4ae1e0ad616 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17612.d @@ -0,0 +1,17 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail17612.d(14): Error: undefined identifier `string` +fail_compilation/fail17612.d(17): Error: class object.TypeInfo missing or corrupt object.d +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17612 + +module object; + +class Object +{ + string toString(); +} + +class TypeInfo {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17646.d b/gcc/testsuite/gdc.test/fail_compilation/fail17646.d new file mode 100644 index 00000000000..416b0d4afd6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17646.d @@ -0,0 +1,19 @@ +/* +REQUIRED_ARGS: -o- +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/imports/fail17646.d(10): Error: found `}` instead of statement +fail_compilation/imports/fail17646.d(7): Error: function imports.fail17646.allTestData!"".allTestData has no return statement, but is expected to return a value of type const(TestData)[] +fail_compilation/fail17646.d(16): Error: template instance imports.fail17646.allTestData!"" error instantiating +fail_compilation/fail17646.d(19): instantiated from here: runTests!"" +--- +*/ +int runTests(Modules...)() +{ + import imports.fail17646; + + allTestData!Modules; +} + +alias fail = runTests!""; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17689.d b/gcc/testsuite/gdc.test/fail_compilation/fail17689.d new file mode 100644 index 00000000000..512a6b56b50 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17689.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail17689.d(10): Error: undefined identifier `x` +--- +*/ +void main(){ + try{} + finally int x=3; + assert(x==3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail177.d b/gcc/testsuite/gdc.test/fail_compilation/fail177.d new file mode 100644 index 00000000000..1e1207732a0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail177.d @@ -0,0 +1,31 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail177.d(22): Error: cannot modify immutable expression j +fail_compilation/fail177.d(24): Error: cannot modify const expression i +fail_compilation/fail177.d(26): Error: cannot modify const expression s1.x +fail_compilation/fail177.d(27): Error: cannot modify const expression *s1.p +fail_compilation/fail177.d(29): Error: cannot modify const expression s2.x +fail_compilation/fail177.d(30): Error: cannot modify const expression *s2.p +--- +*/ + +struct S +{ + int x; + int* p; +} + +void test(const(S) s1, const S s2, const(int) i) +{ + immutable int j = 3; + j = 4; + + i = 4; + + s1.x = 3; + *s1.p = 4; + + s2.x = 3; + *s2.p = 4; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17722a.d b/gcc/testsuite/gdc.test/fail_compilation/fail17722a.d new file mode 100644 index 00000000000..b6ede294a03 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17722a.d @@ -0,0 +1,13 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail17722a.d(12): Error: static assert `__traits(compiles, a1 && a2)` is false +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17722 + +void fail17722a() +{ + byte[16] a1, a2; + static assert(__traits(compiles, a1 && a2)); // diagnostic was (__error) && (__error) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17722b.d b/gcc/testsuite/gdc.test/fail_compilation/fail17722b.d new file mode 100644 index 00000000000..848db15f3a1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17722b.d @@ -0,0 +1,13 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail17722b.d(12): Error: static assert `__traits(compiles, a1 || a2)` is false +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17722 + +void fail17722b() +{ + byte[16] a1, a2; + static assert(__traits(compiles, a1 || a2)); // diagnostic was (__error) || (__error) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail179.d b/gcc/testsuite/gdc.test/fail_compilation/fail179.d new file mode 100644 index 00000000000..bd0e1557246 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail179.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail179.d(11): Error: variable fail179.main.px cannot be final, perhaps you meant const? +--- +*/ + +void main() +{ + int x = 3; + final px = &x; + *px = 4; + auto ppx = &px; + **ppx = 5; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18.d b/gcc/testsuite/gdc.test/fail_compilation/fail18.d new file mode 100644 index 00000000000..55a4af1f45d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail18.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail18.d(14): Error: need upper and lower bound to slice pointer +--- +*/ + +// 7/25 +// Internal error: ..\ztc\cgcod.c 1464 + +void main () +{ + int x = 3; + int[] a = (&x)[]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail180.d b/gcc/testsuite/gdc.test/fail_compilation/fail180.d new file mode 100644 index 00000000000..64ba3ef4271 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail180.d @@ -0,0 +1,65 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail180.d(23): Error: cannot modify this.x in const function +fail_compilation/fail180.d(24): Error: cannot modify this.x in const function +fail_compilation/fail180.d(38): Error: cannot modify this.x in const function +fail_compilation/fail180.d(39): Error: cannot modify this.x in const function +fail_compilation/fail180.d(50): Error: variable fail180.main.t cannot be final, perhaps you meant const? +fail_compilation/fail180.d(62): Error: variable fail180.test.d cannot be final, perhaps you meant const? +--- +*/ + +struct S59 +{ + int x; + + void foo() + { + x = 3; + } + const void bar() + { + x = 4; + this.x = 5; + } +} + +class C +{ + int x; + + void foo() + { + x = 3; + } + const void bar() + { + x = 4; + this.x = 5; + } +} + +void main() +{ + S59 s; + + s.foo(); + s.bar(); + + final S59 t; + t.foo(); + t.bar(); +} + +void test() +{ + C c = new C; + + c.foo(); + c.bar(); + + final C d = new C; + d.foo(); + d.bar(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail183.d b/gcc/testsuite/gdc.test/fail_compilation/fail183.d new file mode 100644 index 00000000000..c43d377e9f9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail183.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail183.d(10): Error: redundant attribute `const` +fail_compilation/fail183.d(10): Error: redundant attribute `scope` +fail_compilation/fail183.d(11): Error: redundant attribute `in` +--- +*/ + +void f(in final const scope int x) {} +void g(final const scope in int x) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail184.d b/gcc/testsuite/gdc.test/fail_compilation/fail184.d new file mode 100644 index 00000000000..03477a84a69 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail184.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail184.d(8): Error: redundant attribute `final` +--- +*/ + +final final int x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail185.d b/gcc/testsuite/gdc.test/fail_compilation/fail185.d new file mode 100644 index 00000000000..7197531d8e5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail185.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail185.d(10): Error: static assert "An error message + that spans multiple lines, and also contains such characters as a tab, +\ and "." +--- +*/ + +static assert (false, +"An error message +\tthat spans multiple lines, and also contains such characters as a tab, +\\ and \"."); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail187.d b/gcc/testsuite/gdc.test/fail_compilation/fail187.d new file mode 100644 index 00000000000..b985493d5fd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail187.d @@ -0,0 +1,28 @@ +// REQUIRED_ARGS: -d +/* +TEST_OUTPUT: +--- +fail_compilation/fail187.d(16): Error: catch at fail_compilation/fail187.d(20) hides catch at fail_compilation/fail187.d(24) +--- +*/ + +// On DMD 2.000 bug only with typedef, not alias + +alias Exception A; +alias Exception B; + +void main() +{ + try + { + throw new A("test"); + } + catch (B) + { + // this shouldn't happen, but does + } + catch (A) + { + // this ought to happen? + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail188.d b/gcc/testsuite/gdc.test/fail_compilation/fail188.d new file mode 100644 index 00000000000..cd201d025bc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail188.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail188.d(15): Error: function fail188.Derived.foo cannot override final function fail188.Base.foo +--- +*/ + +class Base +{ + final void foo() {} +} + +class Derived : Base +{ + void foo() {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail189.d b/gcc/testsuite/gdc.test/fail_compilation/fail189.d new file mode 100644 index 00000000000..adc6f7e7fdf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail189.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail189.d(10): Error: undefined identifier `foo` +--- +*/ + +void bar() +{ + foo(); // should fail +} + +version(none): +void foo() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail190.d b/gcc/testsuite/gdc.test/fail_compilation/fail190.d new file mode 100644 index 00000000000..6f4046a4eec --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail190.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail190.d(9): Error: can't have pointer to (int, int, int) +fail_compilation/fail190.d(16): Error: template instance fail190.f!(int, int, int) error instantiating +--- +*/ + +T* f(T...)(T x) +{ + return null; +} + +void main() +{ + auto x = f(2,3,4); + *x = *x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail1900.d b/gcc/testsuite/gdc.test/fail_compilation/fail1900.d new file mode 100644 index 00000000000..cabfbdff8dc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail1900.d @@ -0,0 +1,66 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail1900.d(26): Error: template fail1900.Mix1a!().Foo matches more than one template declaration: +fail_compilation/fail1900.d(13): Foo(ubyte x) +and +fail_compilation/fail1900.d(14): Foo(byte x) +--- +*/ + +template Mix1a() +{ + template Foo(ubyte x) {} + template Foo(byte x) {} +} +template Mix1b() +{ + template Foo(int x) {} +} + +mixin Mix1a; +mixin Mix1b; + +void test1900a() +{ + alias x = Foo!1; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail1900.d(41): Error: imports.fail1900b.Bar(short n) at fail_compilation/imports/fail1900b.d(2) conflicts with imports.fail1900a.Bar(int n) at fail_compilation/imports/fail1900a.d(2) +--- +*/ + +import imports.fail1900a; +import imports.fail1900b; + +void test1900b() +{ + enum x = Bar!1; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail1900.d(65): Error: fail1900.Mix2b!().Baz(int x) at fail_compilation/fail1900.d(57) conflicts with fail1900.Mix2a!().Baz(byte x) at fail_compilation/fail1900.d(53) +--- +*/ + +template Mix2a() +{ + template Baz(byte x) {} +} +template Mix2b() +{ + template Baz(int x) {} +} + +mixin Mix2a; +mixin Mix2b; + +void test1900c() +{ + alias x = Baz!1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail192.d b/gcc/testsuite/gdc.test/fail_compilation/fail192.d new file mode 100644 index 00000000000..3c485e6948e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail192.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail192.d(15): Error: outer function context of fail192.foo is needed to 'new' nested class fail192.foo.DummyClass +fail_compilation/fail192.d(26): Error: template instance fail192.X!(DummyClass) error instantiating +--- +*/ + +// 1336 Internal error when trying to construct a class declared within a unittest from a templated class. + +class X(T) +{ + void bar() + { + auto t = new T; + } +} + +void foo() +{ + class DummyClass + { + } + + //auto x = new X!(DummyClass); + X!(DummyClass) x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail193.d b/gcc/testsuite/gdc.test/fail_compilation/fail193.d new file mode 100644 index 00000000000..c3093c74bac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail193.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail193.d(14): Error: cannot infer type from overloaded function symbol & foo +--- +*/ + +void foo() { } +void foo(int) { } + +void main() +{ + //void function(int) fp = &foo; + auto fp = &foo; + fp(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail194.d b/gcc/testsuite/gdc.test/fail_compilation/fail194.d new file mode 100644 index 00000000000..2ce4ab86881 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail194.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail194.d(18): Error: function & foo is overloaded +--- +*/ + +import core.vararg; + +void bar(int i, ...) { } + +void foo() { } +void foo(int) { } + +void main() +{ + //bar(1, cast(void function())&foo); + bar(1, &foo); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail195.d b/gcc/testsuite/gdc.test/fail_compilation/fail195.d new file mode 100644 index 00000000000..57a6bdc2918 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail195.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail195.d(22): Error: struct Foo does not overload () +--- +*/ + +// 1384 Compiler segfaults when using struct variable like a function with no opCall member. + +struct Foo +{ + union + { + int a; + int b; + } +} + +void bla() +{ + Foo next; + next(); // Error: structliteral has no effect in expression (Foo(0)) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail196.d b/gcc/testsuite/gdc.test/fail_compilation/fail196.d new file mode 100644 index 00000000000..2a2812bb479 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail196.d @@ -0,0 +1,21 @@ + +void main() +{ + string s = q"(foo(xxx)) "; + assert(s == "foo(xxx)"); + + s = q"[foo[xxx]]"; + assert(s == "foo[xxx]"); + + s = q"{foo{xxx}}"; + assert(s == "foo{xxx}"); + + s = q">"; + assert(s == "foo"); + + s = q"[foo(]"; + assert(s == "foo("); + + s = q"/foo]/"; + assert(s == "foo]"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail198.d b/gcc/testsuite/gdc.test/fail_compilation/fail198.d new file mode 100644 index 00000000000..4cb63b4870e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail198.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail198.d(8): Error: template instance test!42 template 'test' is not defined +--- +*/ + +int x = test!(42); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail199.d b/gcc/testsuite/gdc.test/fail_compilation/fail199.d new file mode 100644 index 00000000000..e293aa1c92c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail199.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -de + +//import std.stdio; + +deprecated class DepClass +{ + void test() + { + //writefln("Accessing what's deprecated!"); + } +} + +class Derived : DepClass {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20.d b/gcc/testsuite/gdc.test/fail_compilation/fail20.d new file mode 100644 index 00000000000..821cc843e07 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail20.d(16): Error: need member function opCmp() for struct FOO to compare +--- +*/ + +// ICE(cod3) DMD0.080 + +struct FOO{} + +void main() +{ + FOO one; + FOO two; + if (one < two){} // This should tell me that there + // is no opCmp() defined instead + // of crashing. +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail200.d b/gcc/testsuite/gdc.test/fail_compilation/fail200.d new file mode 100644 index 00000000000..c0ba46ca96f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail200.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -de + +//import std.stdio; + +deprecated interface DepClass +{ + void test(); +} + +class Derived : DepClass +{ + void test() + { + //writefln("Accessing what's deprecated!"); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail201.d b/gcc/testsuite/gdc.test/fail_compilation/fail201.d new file mode 100644 index 00000000000..d9655b3bc27 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail201.d @@ -0,0 +1,5 @@ +void main() { + int c; + c = c >>> 33; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail202.d b/gcc/testsuite/gdc.test/fail_compilation/fail202.d new file mode 100644 index 00000000000..78cf21a9e84 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail202.d @@ -0,0 +1,5 @@ +void main() { + int c; + c = c >> 33; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail203.d b/gcc/testsuite/gdc.test/fail_compilation/fail203.d new file mode 100644 index 00000000000..3d96e0cba1f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail203.d @@ -0,0 +1,5 @@ +void main() { + int c; + c = c << 33; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail204.d b/gcc/testsuite/gdc.test/fail_compilation/fail204.d new file mode 100644 index 00000000000..41b7c297fb3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail204.d @@ -0,0 +1,5 @@ +void main() { + long c; + c >>= 65; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail205.d b/gcc/testsuite/gdc.test/fail_compilation/fail205.d new file mode 100644 index 00000000000..04ef95ead00 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail205.d @@ -0,0 +1,5 @@ +void main() { + long c; + c <<= 65; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail206.d b/gcc/testsuite/gdc.test/fail_compilation/fail206.d new file mode 100644 index 00000000000..6c0bf4630af --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail206.d @@ -0,0 +1,5 @@ +void main() { + long c; + c >>>= 65; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail207.d b/gcc/testsuite/gdc.test/fail_compilation/fail207.d new file mode 100644 index 00000000000..becf49bfeaf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail207.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail207.d(10): Error: found end of file instead of initializer +fail_compilation/fail207.d(10): Error: semicolon expected, not `EOF` +--- +*/ + +int x = { diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail208.d b/gcc/testsuite/gdc.test/fail_compilation/fail208.d new file mode 100644 index 00000000000..8abcc3e4af3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail208.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail208.d(18): Error: return expression expected +fail_compilation/fail208.d(21): called from here: MakeA() +--- +*/ + + +// Issue 1593 - ICE compiler crash empty return statement in function + +struct A +{ +} + +A MakeA() +{ + return ; +} + +static const A aInstance = MakeA(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail209.d b/gcc/testsuite/gdc.test/fail_compilation/fail209.d new file mode 100644 index 00000000000..a0211aaf4b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail209.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail209.d(20): Error: incompatible types for ((a) -= (x)): 'float' and 'fail209.X' +--- +*/ + +// Issue 725 - expression.c:6516: virtual Expression* MinAssignExp::semantic(Scope*): Assertion `e2->type->isfloating()' failed + +class X +{ + float a; +} + +void main() +{ + X x; + float a; + + a -= x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail212.d b/gcc/testsuite/gdc.test/fail_compilation/fail212.d new file mode 100644 index 00000000000..63c573eb63d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail212.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail212.d(14): Error: function fail212.S.bar without 'this' cannot be const +--- +*/ + +struct S +{ + void foo() const + { + } + + static void bar() const + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail213.d b/gcc/testsuite/gdc.test/fail_compilation/fail213.d new file mode 100644 index 00000000000..d00238273a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail213.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail213.d(18): Error: template instance Foo!int does not match template declaration Foo(T : immutable(T)) +fail_compilation/fail213.d(25): Error: template instance Foo!(const(int)) does not match template declaration Foo(T : immutable(T)) +--- +*/ + +template Foo(T:immutable(T)) +{ + alias T Foo; +} + +void main() +{ + { + int x; + alias Foo!(typeof(x)) f; + //printf("%s\n", typeid(f).toString().ptr); + assert(is(typeof(x) == int)); + assert(is(f == int)); + } + { + const int x; + alias Foo!(typeof(x)) f; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail215.d b/gcc/testsuite/gdc.test/fail_compilation/fail215.d new file mode 100644 index 00000000000..f9427230751 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail215.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail215.d(10): Error: function fail215.b.k cannot be both final and abstract +--- +*/ + +class b +{ + final abstract void k(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail216.d b/gcc/testsuite/gdc.test/fail_compilation/fail216.d new file mode 100644 index 00000000000..98dcbb8dcfb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail216.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail216.d(16): Error: expression foo() is void and has no value +fail_compilation/fail216.d(14): Error: function fail216.bar has no return statement, but is expected to return a value of type int +fail_compilation/fail216.d(19): called from here: bar() +--- +*/ + +// Issue 1744 - CTFE: crash on assigning void-returning function to variable + +void foo() {} + +int bar() +{ + int x = foo(); +} + +const y = bar(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail217.d b/gcc/testsuite/gdc.test/fail_compilation/fail217.d new file mode 100644 index 00000000000..67c28cd8f40 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail217.d @@ -0,0 +1,18 @@ + +class Message + { + public int notifier; + + this( int notifier_object ) + { + notifier = notifier_object; + } + } + +void +main() + { + auto m2 = new immutable(Message)(2); + m2.notifier = 3; + } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail218.d b/gcc/testsuite/gdc.test/fail_compilation/fail218.d new file mode 100644 index 00000000000..e180e77c7ec --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail218.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail218.d(15): Error: cannot modify string literal ", " +--- +*/ + +// Issue 1788 - dmd segfaults without info + +void main() +{ + string a = "abc"; + double b = 7.5; + + a ~= ", " ~= b; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22.d b/gcc/testsuite/gdc.test/fail_compilation/fail22.d new file mode 100644 index 00000000000..1de2a13044a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail22.d(13): Error: no identifier for declarator `char` +--- +*/ + +// infinite loop on DMD0.080 + +void main() +{ + char[] bug = "Crash"; + foreach(char ; bug) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail220.d b/gcc/testsuite/gdc.test/fail_compilation/fail220.d new file mode 100644 index 00000000000..5e2f1305eb1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail220.d @@ -0,0 +1,8 @@ +template types (T) { + static if (is (T V : V[K], K == class)) { + static assert (false, "assoc"); + } + static const int types = 4; +} + +int i = types!(int); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail221.d b/gcc/testsuite/gdc.test/fail_compilation/fail221.d new file mode 100644 index 00000000000..9bada5b95cc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail221.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail221.d(11): Error: expression cast(void)0 is void and has no value +--- +*/ + +void main() +{ + void[] data; + data ~= cast(void) 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail222.d b/gcc/testsuite/gdc.test/fail_compilation/fail222.d new file mode 100644 index 00000000000..c377239fe96 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail222.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail222.d(10): Error: template fail222.getMixin(TArg..., int i = 0)() template tuple parameter must be last one +fail_compilation/fail222.d(17): Error: template instance getMixin!() does not match template declaration getMixin(TArg..., int i = 0)() +fail_compilation/fail222.d(20): Error: template instance fail222.Thing!() error instantiating +--- +*/ + +string getMixin(TArg..., int i = 0)() +{ + return ``; +} + +class Thing(TArg...) +{ + mixin(getMixin!(TArg)()); +} + +public Thing!() stuff; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail223.d b/gcc/testsuite/gdc.test/fail_compilation/fail223.d new file mode 100644 index 00000000000..99e26ea7d36 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail223.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail223.d(14): Error: cannot modify this.x in const function +--- +*/ + +//import std.stdio; + +class A +{ +public: + int x = 0; + void setX(int nx) const { x = nx; } +} + +void foo(const A a) { a.setX(1); } + +int main(char[][] args) +{ + A a = new A; + foo(a); + //writefln(a.x); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail224.d b/gcc/testsuite/gdc.test/fail_compilation/fail224.d new file mode 100644 index 00000000000..4bde3700482 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail224.d @@ -0,0 +1,36 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail224.d(22): Error: need 'this' of type A to access member x from static function f +--- +*/ + +int gi; + +class A +{ + int x = 42; + + void am() + { + static void f() + { + class B + { + void bm() + { + gi = x; + } + } + + (new B).bm(); + } + + f(); + } +} + +void main() +{ + (new A).am(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail225.d b/gcc/testsuite/gdc.test/fail_compilation/fail225.d new file mode 100644 index 00000000000..6cf59f3556c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail225.d @@ -0,0 +1,10 @@ +struct Struct { + char* chptr; +} + +void main() +{ + char ch = 'd'; + immutable Struct iStruct = {1, &ch}; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail228.d b/gcc/testsuite/gdc.test/fail_compilation/fail228.d new file mode 100644 index 00000000000..a4433bb893d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail228.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail228.d(22): Error: undefined identifier `localVariable` +--- +*/ + +//import core.stdc.stdio : printf; + +int ToTypeString(T : int)() +{ + return 1; +} + +int ToTypeString(T : string)() +{ + return 2; +} + +void main() +{ + auto x = ToTypeString!(typeof(localVariable))(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail229.d b/gcc/testsuite/gdc.test/fail_compilation/fail229.d new file mode 100644 index 00000000000..6cf8676cc99 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail229.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail229.d(11): Error: array index 18446744073709551615 overflow +fail_compilation/fail229.d(11): Error: array dimension overflow +--- +*/ + +// Issue 1936 - Error with no line number (array dimension overflow) + +static int[] x = [-1: 1]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23.d b/gcc/testsuite/gdc.test/fail_compilation/fail23.d new file mode 100644 index 00000000000..29e8ed47f19 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail23.d(14): Error: break is not inside a loop or switch +--- +*/ + +// ICE(s2ir.c) DMD0.100 + +void main() +{ + try + { + break; + } + catch (Throwable) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail231.d b/gcc/testsuite/gdc.test/fail_compilation/fail231.d new file mode 100644 index 00000000000..95f25eea3c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail231.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail231.d(15): Error: class fail231.Derived cannot implicitly generate a default ctor when base class fail231.Base is missing a default ctor +--- +*/ + +// Issue 951 - Missing line number: no constructor provided for a class derived from a class with no default constructor + +class Base +{ + this(int x) {} +} + +class Derived : Base +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail232.d b/gcc/testsuite/gdc.test/fail_compilation/fail232.d new file mode 100644 index 00000000000..ee2f4312097 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail232.d @@ -0,0 +1,7 @@ +void bug1601() { + int i; + + i = i >> 33; + i = i << 33; + i = i >>> 33; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail233.d b/gcc/testsuite/gdc.test/fail_compilation/fail233.d new file mode 100644 index 00000000000..e2274abf172 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail233.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail233.d(11): Error: variable fail233.bug1176.v void[1] does not have a default initializer +--- +*/ + +void bug1176() +{ + void[1] v; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail235.d b/gcc/testsuite/gdc.test/fail_compilation/fail235.d new file mode 100644 index 00000000000..d0d9deb1d4f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail235.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail235.d(12): Error: expression typeid(char) is not a valid template value argument +--- +*/ +template Tuple(TPL...) +{ + alias TPL Tuple; +} + +auto K = Tuple!(typeid(char)); + +/* +TEST_OUTPUT: +--- +fail_compilation/fail235.d(24): Error: expression typeid(char) is not a valid template value argument +--- +*/ +template Alias(alias A) +{ + alias A Alias; +} +auto A = Alias!(typeid(char)); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2350.d b/gcc/testsuite/gdc.test/fail_compilation/fail2350.d new file mode 100644 index 00000000000..deb0ceb6a32 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2350.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail2350.d(8): Error: function fail2350.test2350 naked assembly functions with contracts are not supported +--- +*/ + +void test2350() +in +{ +} +body +{ + asm { naked; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail236.d b/gcc/testsuite/gdc.test/fail_compilation/fail236.d new file mode 100644 index 00000000000..255a88157ef --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail236.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail236.d(14): Error: undefined identifier `x` +fail_compilation/fail236.d(22): Error: template fail236.Templ2 cannot deduce function from argument types !()(int), candidates are: +fail_compilation/fail236.d(12): fail236.Templ2(alias a)(x) +--- +*/ + +// Issue 870 - contradictory error messages for templates + +template Templ2(alias a) +{ + void Templ2(x) + { + } +} + +void main() +{ + int i; + Templ2(i); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d new file mode 100644 index 00000000000..7cc402ee84b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail2361.d(13): Error: cannot modify immutable expression c +--- +*/ + +class C {} + +void main() +{ + immutable c = new immutable(C); + delete c; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail237.d b/gcc/testsuite/gdc.test/fail_compilation/fail237.d new file mode 100644 index 00000000000..09ca94c9a37 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail237.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail237.d(11): Error: undefined identifier `a` in module `fail237` +fail_compilation/fail237.d(11): while evaluating: `static assert(module fail237.a!().b)` +--- +*/ + +// Issue 581 - Error message w/o line number in dot-instantiated template + +static assert(.a!().b); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d new file mode 100644 index 00000000000..cb565ba2d39 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d @@ -0,0 +1,36 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/fail238_m32.d(21): Error: cannot implicitly convert expression `"a"` of type `string` to `uint` +fail_compilation/fail238_m32.d(24): Error: cannot interpret X!() at compile time +fail_compilation/fail238_m32.d(29): Error: template instance fail238_m32.A!"a" error instantiating +fail_compilation/fail238_m32.d(35): instantiated from here: M!(q) +fail_compilation/fail238_m32.d(35): while evaluating pragma(msg, M!(q)) +--- +*/ + +// Issue 581 - Error message w/o line number in dot-instantiated template + +template X(){} + +template D(string str){} + +template A(string str) +{ + static if (D!(str[str])) + {} + else + const string A = .X!(); +} + +template M(alias B) +{ + const string M = A!("a"); +} + +void main() +{ + int q = 3; + pragma(msg, M!(q)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d new file mode 100644 index 00000000000..08837b2a554 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d @@ -0,0 +1,36 @@ +// REQUIRED_ARGS: -m64 +/* +TEST_OUTPUT: +--- +fail_compilation/fail238_m64.d(21): Error: cannot implicitly convert expression `"a"` of type `string` to `ulong` +fail_compilation/fail238_m64.d(24): Error: cannot interpret X!() at compile time +fail_compilation/fail238_m64.d(29): Error: template instance fail238_m64.A!"a" error instantiating +fail_compilation/fail238_m64.d(35): instantiated from here: M!(q) +fail_compilation/fail238_m64.d(35): while evaluating pragma(msg, M!(q)) +--- +*/ + +// Issue 581 - Error message w/o line number in dot-instantiated template + +template X(){} + +template D(string str){} + +template A(string str) +{ + static if (D!(str[str])) + {} + else + const string A = .X!(); +} + +template M(alias B) +{ + const string M = A!("a"); +} + +void main() +{ + int q = 3; + pragma(msg, M!(q)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail239.d b/gcc/testsuite/gdc.test/fail_compilation/fail239.d new file mode 100644 index 00000000000..81fbca2bfd4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail239.d @@ -0,0 +1,2 @@ +class F { int x; } +alias typeof(F).x b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24.d b/gcc/testsuite/gdc.test/fail_compilation/fail24.d new file mode 100644 index 00000000000..84cf8e1814b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail24.d(11): Error: alias fail24.strtype conflicts with alias fail24.strtype at fail_compilation/fail24.d(10) +fail_compilation/fail24.d(12): Error: alias fail24.strtype conflicts with alias fail24.strtype at fail_compilation/fail24.d(11) +fail_compilation/fail24.d(13): Error: alias fail24.strtype conflicts with alias fail24.strtype at fail_compilation/fail24.d(12) +--- +*/ + +alias char[] strtype; +alias char[64] strtype; +alias char[128] strtype; +alias char[256] strtype; + +int main() +{ + printf("%u", strtype.sizeof); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail240.d b/gcc/testsuite/gdc.test/fail_compilation/fail240.d new file mode 100644 index 00000000000..8a06b43401c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail240.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail240.d(9): Error: type F is not an expression +--- +*/ + +class F { int x; } +alias typeof(typeof(F).x) b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail241.d b/gcc/testsuite/gdc.test/fail_compilation/fail241.d new file mode 100644 index 00000000000..97cad211e2b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail241.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail241.d(16): Error: mutable method fail241.Foo.f is not callable using a const object +fail_compilation/fail241.d(17): Error: mutable method fail241.Foo.g is not callable using a const object +--- +*/ + +class Foo +{ + public void f() { } + private void g() { } + + invariant() + { + f(); // error, cannot call public member function from invariant + g(); // ok, g() is not public + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail243.d b/gcc/testsuite/gdc.test/fail_compilation/fail243.d new file mode 100644 index 00000000000..c8970ba915d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail243.d @@ -0,0 +1,28 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/fail243.d(23): Deprecation: class fail243.DepClass is deprecated +fail_compilation/fail243.d(24): Deprecation: struct fail243.DepStruct is deprecated +fail_compilation/fail243.d(25): Deprecation: union fail243.DepUnion is deprecated +fail_compilation/fail243.d(26): Deprecation: enum fail243.DepEnum is deprecated +fail_compilation/fail243.d(27): Deprecation: alias fail243.DepAlias is deprecated +--- +*/ + +deprecated +{ + class DepClass {} + struct DepStruct {} + union DepUnion {} + enum DepEnum { A } + alias int DepAlias; + //typedef int DepTypedef; +} + +void func(DepClass obj) {} +void func(DepStruct obj) {} +void func(DepUnion obj) {} +void func(DepEnum obj) {} +void func(DepAlias obj) {} +//void func(DepTypedef obj) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail244.d b/gcc/testsuite/gdc.test/fail_compilation/fail244.d new file mode 100644 index 00000000000..d688e9ad2d0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail244.d @@ -0,0 +1,39 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/fail244.d(27): Deprecation: variable fail244.StructWithDeps.value is deprecated +fail_compilation/fail244.d(28): Deprecation: variable fail244.StructWithDeps.value is deprecated +fail_compilation/fail244.d(29): Deprecation: variable fail244.StructWithDeps.value is deprecated +fail_compilation/fail244.d(30): Deprecation: variable fail244.StructWithDeps.value is deprecated +fail_compilation/fail244.d(32): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated +fail_compilation/fail244.d(33): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated +fail_compilation/fail244.d(34): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated +fail_compilation/fail244.d(35): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated +fail_compilation/fail244.d(36): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated +fail_compilation/fail244.d(37): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated +--- +*/ + +//import std.stdio; + +struct StructWithDeps +{ + deprecated int value; + deprecated static int staticValue; + + void test(StructWithDeps obj) + { + obj.value = 666; + this.value = 666; + auto n1 = obj.value; + auto n2 = this.value; + + obj.staticValue = 102; + this.staticValue = 103; + StructWithDeps.staticValue = 104; + auto n3 = obj.staticValue; + auto n4 = this.staticValue; + auto n5 = StructWithDeps.staticValue; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail245.d b/gcc/testsuite/gdc.test/fail_compilation/fail245.d new file mode 100644 index 00000000000..79e663dab1e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail245.d @@ -0,0 +1,39 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/fail245.d(27): Deprecation: variable fail245.ClassWithDeps.value is deprecated +fail_compilation/fail245.d(28): Deprecation: variable fail245.ClassWithDeps.value is deprecated +fail_compilation/fail245.d(29): Deprecation: variable fail245.ClassWithDeps.value is deprecated +fail_compilation/fail245.d(30): Deprecation: variable fail245.ClassWithDeps.value is deprecated +fail_compilation/fail245.d(32): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated +fail_compilation/fail245.d(33): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated +fail_compilation/fail245.d(34): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated +fail_compilation/fail245.d(35): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated +fail_compilation/fail245.d(36): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated +fail_compilation/fail245.d(37): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated +--- +*/ + +//import std.stdio; + +class ClassWithDeps +{ + deprecated int value; + deprecated static int staticValue; + + void test(ClassWithDeps obj) + { + obj.value = 666; + this.value = 666; + auto n1 = obj.value; + auto n2 = this.value; + + obj.staticValue = 102; + this.staticValue = 103; + ClassWithDeps.staticValue = 104; + auto n3 = obj.staticValue; + auto n4 = this.staticValue; + auto n5 = ClassWithDeps.staticValue; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail246.d b/gcc/testsuite/gdc.test/fail_compilation/fail246.d new file mode 100644 index 00000000000..c6214ff88dd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail246.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail246.d-mixin-11(11): Error: identifier expected, not `EOF` +fail_compilation/fail246.d-mixin-11(11): Error: `;` expected after mixin +--- +*/ + +void a() +{ + mixin(`mixin`); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail247.d b/gcc/testsuite/gdc.test/fail_compilation/fail247.d new file mode 100644 index 00000000000..1acf1a4105c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail247.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail247.d-mixin-9(9): Error: identifier expected, not `EOF` +fail_compilation/fail247.d-mixin-9(9): Error: `;` expected after mixin +--- +*/ + +mixin(`mixin`); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail248.d b/gcc/testsuite/gdc.test/fail_compilation/fail248.d new file mode 100644 index 00000000000..185de133ec0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail248.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail248.d(9): Error: type int is not an expression +--- +*/ + +alias int foo; +typeof(foo) a; // ok diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail249.d b/gcc/testsuite/gdc.test/fail_compilation/fail249.d new file mode 100644 index 00000000000..79a42891d03 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail249.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail249.d(16): Error: invalid foreach aggregate `bar()` +--- +*/ + +module main; + +public void bar() +{ +} + +void main() +{ + foreach (Object o; bar()) + { + debug Object foo = null; //error + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail25.d b/gcc/testsuite/gdc.test/fail_compilation/fail25.d new file mode 100644 index 00000000000..7393a6c4a67 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail25.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail25.d(14): Error: need 'this' for 'yuiop' of type 'int' +--- +*/ + +class Qwert +{ + int yuiop; + + static int asdfg() + { + return Qwert.yuiop + 105; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail250.d b/gcc/testsuite/gdc.test/fail_compilation/fail250.d new file mode 100644 index 00000000000..c3fd7631aec --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail250.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail250.d(10): Error: constructor fail250.A.this default constructor for structs only allowed with @disable, no body, and no parameters +--- +*/ + +struct A +{ + this() {} +} + +void main() +{ + auto a = A(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail251.d b/gcc/testsuite/gdc.test/fail_compilation/fail251.d new file mode 100644 index 00000000000..083f3a4b9c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail251.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail251.d(12): Error: undefined identifier `xs` +fail_compilation/fail251.d(16): called from here: foo() +fail_compilation/fail251.d(16): while evaluating: `static assert(foo())` +--- +*/ + +bool foo() +{ + foreach (x; xs) {} + return true; +} + +static assert(foo()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail252.d b/gcc/testsuite/gdc.test/fail_compilation/fail252.d new file mode 100644 index 00000000000..3d2db651076 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail252.d @@ -0,0 +1,10 @@ +class Timer { + abstract class Task { + public abstract void run(); + } + private Task IDLE = new class() Task { + int d; + public void run(){ + } + }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail253.d b/gcc/testsuite/gdc.test/fail_compilation/fail253.d new file mode 100644 index 00000000000..14e88581870 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail253.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail253.d(13): Error: variable fail253.main.x inout variables can only be declared inside inout functions +fail_compilation/fail253.d(16): Error: cannot modify inout expression x +--- +*/ + +void main() +{ + foreach (i; 0 .. 2) + { + foreach (inout char x; "hola") + { + //printf("%c", x); + x = '?'; + } + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail254.d b/gcc/testsuite/gdc.test/fail_compilation/fail254.d new file mode 100644 index 00000000000..b29b5907be4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail254.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail254.d(12): Error: integer overflow +fail_compilation/fail254.d(13): Error: integer overflow +fail_compilation/fail254.d(14): Error: integer overflow +fail_compilation/fail254.d(15): Error: integer overflow +fail_compilation/fail254.d(16): Error: integer overflow +--- +*/ + +ulong v1 = 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF; +ulong v2 = 0x1_0000_0000_0000_0000; +ulong v3 = 0x1_FFFF_FFFF_FFFF_FFFF; +ulong v4 = 0x7_FFFF_FFFF_FFFF_FFFF; +ulong v5 = 0x1_0000_FFFF_FFFF_FFFF; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail256.d b/gcc/testsuite/gdc.test/fail_compilation/fail256.d new file mode 100644 index 00000000000..87120e2644f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail256.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail256.d(8): Error: incompatible types for (("foo"d) ~ ("bar"c)): 'dstring' and 'string' +--- +*/ + +auto s = "foo"d ~ "bar"c; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail257.d b/gcc/testsuite/gdc.test/fail_compilation/fail257.d new file mode 100644 index 00000000000..249a5240244 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail257.d @@ -0,0 +1 @@ +pragma(msg, "foo"d == "bar"c ? "A" : "B"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail258.d b/gcc/testsuite/gdc.test/fail_compilation/fail258.d new file mode 100644 index 00000000000..97381a66394 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail258.d @@ -0,0 +1,5 @@ +q" +X + +X" + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail259.d b/gcc/testsuite/gdc.test/fail_compilation/fail259.d new file mode 100644 index 00000000000..802e037ae0c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail259.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail259.d(11): Error: function fail259.C.foo does not override any function +--- +*/ + +class C +{ + final + override void foo(){} +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail261.d b/gcc/testsuite/gdc.test/fail_compilation/fail261.d new file mode 100644 index 00000000000..e25722c1d6d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail261.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail261.d(18): Error: invalid foreach aggregate `range`, define opApply(), range primitives, or use .tupleof +--- +*/ + +//import std.stdio; + +struct MyRange +{ +} + +void main() +{ + MyRange range; + + foreach (r; range) + { + //writefln("%s", r.toString()); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail262.d b/gcc/testsuite/gdc.test/fail_compilation/fail262.d new file mode 100644 index 00000000000..93e6af086ff --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail262.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail262.d(23): Error: function fail262.B.f does not override any function +--- +*/ + +// Issue 1645 - can override base class' const method with non-const method + +import core.stdc.stdio; + +class A +{ + int x; + shared const void f() + { + printf("A\n"); + } +} + +class B : A +{ + override const void f() + { + //x = 2; + printf("B\n"); + } +} + +void main() +{ + A y = new B; + y.f; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail263.d b/gcc/testsuite/gdc.test/fail_compilation/fail263.d new file mode 100644 index 00000000000..f7dfe21e336 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail263.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail263.d(18): Error: function fail263.f (byte* p) is not callable using argument types (const(byte)*) +--- +*/ + +// Issue 2766 - DMD hangs with 0%cpu + +const byte[] A = [ cast(byte)0 ]; + +void f(byte* p) +{ +} + +void func() +{ + f(A.ptr); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail264.d b/gcc/testsuite/gdc.test/fail_compilation/fail264.d new file mode 100644 index 00000000000..ec22d2e0e40 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail264.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail264.d(10): Error: undefined identifier `undef` +--- +*/ + +void main() +{ + foreach (element; undef) + { + fn(element); + } +} + +void fn(int i) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail265.d b/gcc/testsuite/gdc.test/fail_compilation/fail265.d new file mode 100644 index 00000000000..476ff17989e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail265.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail265.d-mixin-10(10): Error: found `EOF` instead of statement +--- +*/ + +void main() +{ + mixin(`for(;;)`); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2656.d b/gcc/testsuite/gdc.test/fail_compilation/fail2656.d new file mode 100644 index 00000000000..ffd38de4502 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2656.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail2656.d(21): Error: octal literals `0123` are no longer supported, use `std.conv.octal!123` instead +fail_compilation/fail2656.d(22): Error: octal literals `01000000000000000000000` are no longer supported, use `std.conv.octal!1000000000000000000000` instead +fail_compilation/fail2656.d(23): Error: octal literals `0100000L` are no longer supported, use `std.conv.octal!100000L` instead +fail_compilation/fail2656.d(24): Error: octal literals `01777777777777777777777u` are no longer supported, use `std.conv.octal!1777777777777777777777u` instead +fail_compilation/fail2656.d(25): Error: octal literals `017777777777uL` are no longer supported, use `std.conv.octal!17777777777uL` instead +fail_compilation/fail2656.d(26): Error: octal literals `0177777` are no longer supported, use `std.conv.octal!177777` instead +fail_compilation/fail2656.d(27): Error: octal literals `020000000000L` are no longer supported, use `std.conv.octal!20000000000L` instead +fail_compilation/fail2656.d(28): Error: octal literals `0200000u` are no longer supported, use `std.conv.octal!200000u` instead +fail_compilation/fail2656.d(29): Error: octal literals `037777777777uL` are no longer supported, use `std.conv.octal!37777777777uL` instead +fail_compilation/fail2656.d(30): Error: octal literals `040000000000` are no longer supported, use `std.conv.octal!40000000000` instead +fail_compilation/fail2656.d(31): Error: octal literals `0777777777777777777777L` are no longer supported, use `std.conv.octal!777777777777777777777L` instead +fail_compilation/fail2656.d(32): Error: octal literals `077777u` are no longer supported, use `std.conv.octal!77777u` instead +fail_compilation/fail2656.d(33): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead +fail_compilation/fail2656.d(34): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead +--- +*/ + +auto a = 0123; +auto b = 01000000000000000000000; +auto c = 0100000L; +auto d = 01777777777777777777777u; +auto e = 017777777777uL; +auto f = 0177777; +auto g = 020000000000L; +auto h = 0200000u; +auto i = 037777777777uL; +auto j = 040000000000; +auto k = 0777777777777777777777L; +auto l = 077777u; +auto m = 077777uL; +auto n = 0_7_7_7_7_7uL; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail267.d b/gcc/testsuite/gdc.test/fail_compilation/fail267.d new file mode 100644 index 00000000000..a6ebfac320b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail267.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail267.d(15): Error: template Bar() does not have property 'foo' +--- +*/ + +class C +{ + template Bar() + { + } +} + +typeof(C.Bar.foo) quux; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail27.d b/gcc/testsuite/gdc.test/fail_compilation/fail27.d new file mode 100644 index 00000000000..9279e0e51f3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail27.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail27.d(15): Error: cannot implicitly convert expression `-32769` of type `int` to `short` +fail_compilation/fail27.d(16): Error: cannot implicitly convert expression `-129` of type `int` to `byte` +fail_compilation/fail27.d(17): Error: cannot implicitly convert expression `-1` of type `int` to `char` +fail_compilation/fail27.d(18): Error: cannot implicitly convert expression `65536` of type `int` to `wchar` +fail_compilation/fail27.d(19): Error: cannot implicitly convert expression `-1` of type `int` to `wchar` +fail_compilation/fail27.d(21): Error: cannot implicitly convert expression `-1` of type `int` to `dchar` +--- +*/ + +void main() +{ + short a = -32769; // short.min-1 + byte b = -129; // byte.min-1 + char c = -1; // char.min-1 + wchar D = 65536; // wchar.max+1 + wchar d = -1; // wchar.min-1 + dchar E = 1114111; // dchar.max+1 + dchar e = -1; // dchar.min-1 +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail270.d b/gcc/testsuite/gdc.test/fail_compilation/fail270.d new file mode 100644 index 00000000000..8f31fd3b2f0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail270.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail270.d(12): Error: string slice `[1 .. 0]` is out of bounds +fail_compilation/fail270.d(12): Error: mixin fail270.Tuple!int.Tuple.Tuple!() error instantiating +fail_compilation/fail270.d(14): Error: mixin fail270.Tuple!int error instantiating +--- +*/ + +struct Tuple(TList...) +{ + mixin .Tuple!((TList[1 .. $])) tail; +} +mixin Tuple!(int); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail272.d b/gcc/testsuite/gdc.test/fail_compilation/fail272.d new file mode 100644 index 00000000000..15325ad187f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail272.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail272.d(9): Error: circular reference to variable 'fail272.Ins!(Ins).Ins' +fail_compilation/fail272.d(10): Error: template instance fail272.Ins!(Ins) error instantiating +--- +*/ + +template Ins(alias x) { const Ins = Ins!(Ins); } +alias Ins!(Ins) x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail273.d b/gcc/testsuite/gdc.test/fail_compilation/fail273.d new file mode 100644 index 00000000000..9393c85df32 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail273.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail273.d(10): Error: alias fail273.b recursive alias declaration +--- +*/ + +// Issue 1054 - regression: circular aliases cause compiler stack overflow + +alias a b; +alias b a; +b x; // ICE #1 +a y; // ICE #2 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail274.d b/gcc/testsuite/gdc.test/fail_compilation/fail274.d new file mode 100644 index 00000000000..5fa55962d18 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail274.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail274.d(10): Error: expression expected not ; +--- +*/ + +void main() +{ + asm { inc [; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2740.d b/gcc/testsuite/gdc.test/fail_compilation/fail2740.d new file mode 100644 index 00000000000..af7334fa71b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2740.d @@ -0,0 +1,15 @@ +interface IFoo +{ + int foo(); +} + +mixin template MFoo(int N) +{ + int foo() { return N; } +} + +class Foo : IFoo +{ + mixin MFoo!(1) t1; + mixin MFoo!(2) t2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail275.d b/gcc/testsuite/gdc.test/fail_compilation/fail275.d new file mode 100644 index 00000000000..df3eca158f0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail275.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail275.d(10): Error: circular reference to variable 'fail275.C.x' +--- +*/ +// REQUIRED_ARGS: -d +struct C +{ + const x = C.x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail276.d b/gcc/testsuite/gdc.test/fail_compilation/fail276.d new file mode 100644 index 00000000000..052558ce0d8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail276.d @@ -0,0 +1,19 @@ + +class C +{ + this() + { + auto i = new class() + { + auto k = new class() + { + void func() + { + this.outer.outer; + } + }; + }; + } + int i; +} +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail278.d b/gcc/testsuite/gdc.test/fail_compilation/fail278.d new file mode 100644 index 00000000000..8437acd6424 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail278.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail278.d(11): Error: template instance NONEXISTENT!() template 'NONEXISTENT' is not defined +fail_compilation/fail278.d(12): Error: template instance fail278.F!() error instantiating +fail_compilation/fail278.d(13): instantiated from here: Bar!(Foo) +--- +*/ + +template Id(xs...) { const Id = xs[0]; } +template Foo() { mixin Id!(NONEXISTENT!()); } +template Bar(alias F) { const int Bar = F!(); } +alias Bar!(Foo) x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail279.d b/gcc/testsuite/gdc.test/fail_compilation/fail279.d new file mode 100644 index 00000000000..22d795e9e0c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail279.d @@ -0,0 +1,8 @@ +// Issue 2920 - recursive templates blow compiler stack +// template_16 + +template Template(int i) +{ + mixin Template!(i + 1); +} +mixin Template!(0); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail280.d b/gcc/testsuite/gdc.test/fail_compilation/fail280.d new file mode 100644 index 00000000000..796d171f716 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail280.d @@ -0,0 +1,12 @@ +// Issue 2920 - recursive templates blow compiler stack +// template_17_A. + +template t(int i) +{ + const int x = t!(i + 1).x; +} + +void main() +{ + int i = t!(0).x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail281.d b/gcc/testsuite/gdc.test/fail_compilation/fail281.d new file mode 100644 index 00000000000..daa9385b69c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail281.d @@ -0,0 +1,18 @@ +// Issue 2920 - recursive templates blow compiler stack +// template_29_B. + +template foo(uint i) +{ + static if (i > 0) + { + const uint bar = foo!(i - 1).bar; + } + else + { + const uint bar = 1; + } +} +int main() +{ + return foo!(uint.max).bar; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail282.d b/gcc/testsuite/gdc.test/fail_compilation/fail282.d new file mode 100644 index 00000000000..0b1391bbd52 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail282.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail282.d(13): Error: template instance fail282.Template!500 recursive expansion +--- +*/ + +// Issue 2920 - recursive templates blow compiler stack +// template_class_09. + +template Template(int i) +{ + class Class : Template!(i + 1).Class + { + } +} + +alias Template!(0).Class Class0; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail284.d b/gcc/testsuite/gdc.test/fail_compilation/fail284.d new file mode 100644 index 00000000000..a33f2c597fb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail284.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail284.d(19): Error: pure function 'fail284.foo' cannot call impure function pointer 'a' +--- +*/ + +static int nasty; + +int impure_evil_function(int x) +{ + nasty++; + return nasty; +} + +pure int foo(int x) +{ + int function(int) a = &impure_evil_function; + return a(x); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail285.d b/gcc/testsuite/gdc.test/fail_compilation/fail285.d new file mode 100644 index 00000000000..82370143bf9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail285.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail285.d(19): Error: with symbol `fail285.S.x` is shadowing local symbol `fail285.main.x` +--- +*/ + +struct S +{ + int x; +} + +void main() +{ + int x; + S s; + with (s) + { + x++; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail287.d b/gcc/testsuite/gdc.test/fail_compilation/fail287.d new file mode 100644 index 00000000000..7ed8f134c97 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail287.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail287.d(14): Error: had 299 cases which is more than 256 cases in case range +--- +*/ + + +void main() +{ + int i = 2; + switch (i) + { + case 1: .. case 300: + i = 5; + break; + } + if (i != 5) + assert(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail288.d b/gcc/testsuite/gdc.test/fail_compilation/fail288.d new file mode 100644 index 00000000000..d6b68c995a4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail288.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail288.d(14): Error: case ranges not allowed in final switch +--- +*/ + +void main() +{ + enum E { a, b } + E i = E.a; + final switch (i) + { + case E.a: .. case E.b: + break; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail289.d b/gcc/testsuite/gdc.test/fail_compilation/fail289.d new file mode 100644 index 00000000000..b1d0882edca --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail289.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail289.d(12): Error: cannot cast from function pointer to delegate +--- +*/ + +alias void delegate() Dg; +void fun() {} +void gun() +{ + Dg d = cast(void delegate())&fun; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail290.d b/gcc/testsuite/gdc.test/fail_compilation/fail290.d new file mode 100644 index 00000000000..2d735815d58 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail290.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail290.d(15): Error: no `this` to create delegate for `foo` +--- +*/ + +struct Foo +{ + void foo(int x) {} +} + +void main() +{ + void delegate (int) a = &Foo.foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail291.d b/gcc/testsuite/gdc.test/fail_compilation/fail291.d new file mode 100644 index 00000000000..79ff2b0bdce --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail291.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail291.d(9): Error: variable fail291.X cannot be declared to be a function +--- +*/ + +auto a() { return 0; } +typeof(a) X; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail296.d b/gcc/testsuite/gdc.test/fail_compilation/fail296.d new file mode 100644 index 00000000000..3f1e5d3f679 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail296.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail296.d(10): Error: can only * a pointer, not a 'int' +--- +*/ + +// Issue 3117 - dmd crash by *1 + +void main(){ *1; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2962.d b/gcc/testsuite/gdc.test/fail_compilation/fail2962.d new file mode 100644 index 00000000000..06caadce3b1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2962.d @@ -0,0 +1,41 @@ +// EXTRA_SOURCES: imports/fail2962a.d + +// comment 6 +/* +TEST_OUTPUT: +--- +fail_compilation/fail2962.d(14): Error: variable y cannot be read at compile time +fail_compilation/fail2962.d(14): while looking for match for baz6!(int, y) +fail_compilation/fail2962.d(22): Error: template instance fail2962.bar6!int error instantiating +--- +*/ +T bar6(T)(T y) +{ + return baz6!(T, y)(); +} +T baz6(T, T z)() +{ + return z * z; +} +void test6() +{ + assert(bar6(4) != 0); +} + +// comment 4 +/* +TEST_OUTPUT: +--- +fail_compilation/fail2962.d(36): Error: variable x cannot be read at compile time +fail_compilation/fail2962.d(36): while looking for match for baz4!(int, x) +fail_compilation/imports/fail2962a.d(6): Error: template instance fail2962.bar4!int error instantiating +--- +*/ +T bar4(T)(T x) +{ + return baz4!(T, x)(); +} +T baz4(T, T x)() +{ + return x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail297.d b/gcc/testsuite/gdc.test/fail_compilation/fail297.d new file mode 100644 index 00000000000..fd2249db2ca --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail297.d @@ -0,0 +1,31 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail297.d(30): Error: incompatible types for ((Bar()) + (baz())): 'Bar' and 'const(Bar)' +--- +*/ + +// Issue 1969 - ICE(cod1.c) using undefined operator with one const operand + +// 1969 ICE or wrong-code. D2 only. Internal error: backend\cod1.c 1673 +/* Root cause: BinExp::typeCombine() is checking for an _exact_ match, but +typeMerge() will return success. + +PATCH: cast.c BinExp::typeCombine(). +Compare the immutable versions of the types, instead of the types themselves. + + if (op == TOKmin || op == TOKadd) + { + if (t1->ito == t2->ito && (t1->ty == Tstruct || t1->ty == Tclass)) + goto Lerror; + } +*/ + +struct Bar {} + +const(Bar) baz() { return Bar(); } + +void foo() +{ + Bar result = Bar() + baz(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail298.d b/gcc/testsuite/gdc.test/fail_compilation/fail298.d new file mode 100644 index 00000000000..aa4f9e84ee7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail298.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail298.d(12): Error: cannot implicitly convert expression `num1 / cast(ulong)num2` of type `ulong` to `int` +--- +*/ + +void main() +{ + ulong num1 = 100; + int num2 = 10; + int result = num1 / num2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail299.d b/gcc/testsuite/gdc.test/fail_compilation/fail299.d new file mode 100644 index 00000000000..1bfdd82a4a2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail299.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail299.d(14): Error: more initializers than fields (0) of Foo +--- +*/ + +struct Foo {} + +void foo (Foo b, void delegate ()) {} + +void main () +{ + foo(Foo(1), (){}); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3.d b/gcc/testsuite/gdc.test/fail_compilation/fail3.d new file mode 100644 index 00000000000..332e561cd0c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3.d @@ -0,0 +1,43 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail3.d(40): Error: incompatible types for ((a) + (b)): 'vec2' and 'vec2' +--- +*/ + +// DMD 0.79 linux: Internal error: ../ztc/cgcod.c 1459 + +template vector(T) +{ + struct vec2 + { + T x, y; + } + + vec2 opAdd(vec2 a, vec2 b) + { + vec2 r; + r.x = a.x + b.x; + r.y = a.y + b.y; + return r; + } + + vec2 make2(T x, T y) + { + vec2 a; + a.x = x; + a.y = y; + return a; + } +} + +alias vector!(float).vec2 vec2f; + +int main() +{ + vec2f a, b; + b.x = 3; + a = a + b; + //printf("%f\n", a.x); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail301.d b/gcc/testsuite/gdc.test/fail_compilation/fail301.d new file mode 100644 index 00000000000..b012fc8c0f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail301.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail301.d(11): Error: need 'this' for 'guard' of type 'int' +fail_compilation/fail301.d(22): Error: template instance fail301.bug3305!0 error instantiating +--- +*/ + +struct bug3305(alias X = 0) +{ + auto guard = bug3305b!(0).guard; +} + +struct bug3305b(alias X = 0) +{ + bug3305!(X) goo; + auto guard = 0; +} + +void test() +{ + bug3305!(0) a; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail302.d b/gcc/testsuite/gdc.test/fail_compilation/fail302.d new file mode 100644 index 00000000000..02c6b242c59 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail302.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail302.d(21): Error: cannot implicitly convert expression `1` of type `int` to `Bar` +--- +*/ + +struct Bar +{ + uint num; + + Bar opAssign(uint otherNum) + { + num = otherNum; + return this; + } +} + +void main() +{ + Bar bar = 1; // disallow because construction is not assignment + auto x = bar.num; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail303.d b/gcc/testsuite/gdc.test/fail_compilation/fail303.d new file mode 100644 index 00000000000..98223fa3b17 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail303.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail303.d(19): Error: double /= cdouble is undefined. Did you mean double /= cdouble.re ? +fail_compilation/fail303.d(20): Error: ireal *= ireal is an undefined operation +fail_compilation/fail303.d(21): Error: ireal *= creal is undefined. Did you mean ireal *= creal.im ? +fail_compilation/fail303.d(22): Error: ireal %= creal is undefined. Did you mean ireal %= creal.im ? +fail_compilation/fail303.d(23): Error: ireal += real is undefined (result is complex) +fail_compilation/fail303.d(24): Error: ireal -= creal is undefined (result is complex) +fail_compilation/fail303.d(25): Error: double -= idouble is undefined (result is complex) +--- +*/ + + +void main() +{ + ireal x = 3.0i; + double y = 3; + y /= 2.0 + 6i; + x *= 7.0i; + x *= 3.0i + 2; + x %= (2 + 6.0i); + x += 2.0; + x -= 1 + 4i; + y -= 3.0i; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail304.d b/gcc/testsuite/gdc.test/fail_compilation/fail304.d new file mode 100644 index 00000000000..29f2c18e312 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail304.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail304.d(15): Error: cannot cast expression `foo()` of type `Small` to `Large` because of different sizes +--- +*/ + +struct Small { uint x; } +struct Large { uint x, y, z; } +Small foo() { return Small(); } +void main() +{ + Large l; + Small s; + l = cast(Large)foo(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail305.d b/gcc/testsuite/gdc.test/fail_compilation/fail305.d new file mode 100644 index 00000000000..3c9dc76854c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail305.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail305.d(10): Error: cannot return non-void from void function +--- +*/ + +void main() +{ + return "a"; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail306.d b/gcc/testsuite/gdc.test/fail_compilation/fail306.d new file mode 100644 index 00000000000..ffe3cf74518 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail306.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail306.d(11): Error: cannot perform array operations on `void[]` arrays +--- +*/ + +void bar() +{ + void [] x; + x[] = -x[]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail307.d b/gcc/testsuite/gdc.test/fail_compilation/fail307.d new file mode 100644 index 00000000000..e871dbff06b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail307.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail307.d(11): Error: cannot implicitly convert expression `cast(int)(cast(double)cast(int)b + 6.1)` of type `int` to `short` +--- +*/ + +void main() +{ + ubyte b = 6; + short c5 = cast(int)(b + 6.1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail308.d b/gcc/testsuite/gdc.test/fail_compilation/fail308.d new file mode 100644 index 00000000000..d283da0e0a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail308.d @@ -0,0 +1,15 @@ +// REQUIRED_ARGS: -unittest + +void main() +{ + MinHeap!(int) foo = new MinHeap!(int)(); +} + +class MinHeap(NodeType) +{ + unittest + { + struct TestType {} + MinHeap!(TestType) foo = new MinHeap!(TestType)(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail309.d b/gcc/testsuite/gdc.test/fail_compilation/fail309.d new file mode 100644 index 00000000000..e1c9bfab889 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail309.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail309.d(10): Error: circular reference to variable 'fail309.S.x' +--- +*/ +// REQUIRED_ARGS: -d +struct S +{ + const x = S.x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail310.d b/gcc/testsuite/gdc.test/fail_compilation/fail310.d new file mode 100644 index 00000000000..1dc3d5b0ee5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail310.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail310.d(10): Error: undefined identifier `Foo`, did you mean function `foo`? +fail_compilation/fail310.d(14): Error: template instance fail310.foo!(1, 2) error instantiating +fail_compilation/fail310.d(14): while evaluating: `static assert(foo!(1, 2)())` +--- +*/ + +Foo foo(A...)() +{ +} + +static assert(foo!(1, 2)()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail311.d b/gcc/testsuite/gdc.test/fail_compilation/fail311.d new file mode 100644 index 00000000000..1713069e5a0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail311.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail311.d(16): Error: undefined identifier `undefined` +fail_compilation/fail311.d(25): Error: template instance fail311.foo!() error instantiating +--- +*/ + +template Tuple(T...) +{ + alias T Tuple; +} + +void foo()() +{ + undefined x; + foreach (i; Tuple!(2)) + { + static assert(true); + } +} + +void main() +{ + foo!()(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail312.d b/gcc/testsuite/gdc.test/fail_compilation/fail312.d new file mode 100644 index 00000000000..3823ee414c5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail312.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail312.d(13): Error: incompatible types for ((a[]) == (b)): 'int[]' and 'short' +fail_compilation/fail312.d(14): Error: incompatible types for ((a[]) <= (b)): 'int[]' and 'short' +--- +*/ + +void main() +{ + int[1] a = 1; + short b = 1; + assert(a[] == b); + assert(a[] <= b); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail313.d b/gcc/testsuite/gdc.test/fail_compilation/fail313.d new file mode 100644 index 00000000000..8f11001721f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail313.d @@ -0,0 +1,31 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/fail313.d(18): Deprecation: module imports.b313 is not accessible here, perhaps add 'static import imports.b313;' +fail_compilation/fail313.d(25): Deprecation: imports.a313.core is not visible from module test313 +fail_compilation/fail313.d(25): Deprecation: package core.stdc is not accessible here +fail_compilation/fail313.d(25): Deprecation: module core.stdc.stdio is not accessible here, perhaps add 'static import core.stdc.stdio;' +fail_compilation/fail313.d(30): Deprecation: package imports.pkg313 is not accessible here, perhaps add 'static import imports.pkg313;' +--- +*/ +module test313; + +import imports.a313; + +void test1() +{ + imports.b313.bug(); + import imports.b313; + imports.b313.bug(); +} + +void test2() +{ + core.stdc.stdio.printf(""); +} + +void test2() +{ + imports.pkg313.bug(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail314.d b/gcc/testsuite/gdc.test/fail_compilation/fail314.d new file mode 100644 index 00000000000..cfbb0308f23 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail314.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail314.d(11): Error: declaration T is already defined +--- +*/ + +struct foo +{ + static if (is(int T == int)) {} + static if (is(int T == int)) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3144.d b/gcc/testsuite/gdc.test/fail_compilation/fail3144.d new file mode 100644 index 00000000000..04e808fc72d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3144.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail3144.d(12): Error: break is not inside a loop or switch +fail_compilation/fail3144.d(15): Error: break is not inside a loop or switch +--- +*/ + +void main() +{ + switch (1) + default: {} break; + + final switch (1) + case 1: {} break; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail315.d b/gcc/testsuite/gdc.test/fail_compilation/fail315.d new file mode 100644 index 00000000000..7ce4a80f031 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail315.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail315.d-mixin-16(16): Error: found `;` when expecting `,` +fail_compilation/fail315.d-mixin-16(16): Error: expression expected, not `}` +fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `,` +fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `]` +fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `;` following return statement +fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `}` following compound statement +fail_compilation/fail315.d(21): Error: template instance fail315.foo!() error instantiating +--- +*/ + +void foo(S...)(S u) +{ + alias typeof(mixin("{ return a[1;}()")) z; +} + +void main() +{ + foo!()(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3150.d b/gcc/testsuite/gdc.test/fail_compilation/fail3150.d new file mode 100644 index 00000000000..3382badb193 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3150.d @@ -0,0 +1,5 @@ +// REQUIRED_ARGS: -de + +void main() { + ulong u = cast(ulong)[1,2]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail316.d b/gcc/testsuite/gdc.test/fail_compilation/fail316.d new file mode 100644 index 00000000000..21788d629d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail316.d @@ -0,0 +1,17 @@ +template BadImpl(T, alias thename) +{ + void a_bad_idea(T t) + { + thename.a_bad_idea(t); + } +} + +class foo +{ + mixin BadImpl!(uint,Mix1) Mix1; +} + +int main() +{ + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail317.d b/gcc/testsuite/gdc.test/fail_compilation/fail317.d new file mode 100644 index 00000000000..05e7edb0598 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail317.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail317.d(10): Error: function fail317.I.f has no function body with return type inference +--- +*/ + +interface I +{ + auto f() + in {} + out {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail318.d b/gcc/testsuite/gdc.test/fail_compilation/fail318.d new file mode 100644 index 00000000000..dd93803eacf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail318.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail318.d(8): Error: function D main must return int or void +--- +*/ + +auto main() { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail319.d b/gcc/testsuite/gdc.test/fail_compilation/fail319.d new file mode 100644 index 00000000000..3c4459a89bd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail319.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail319.d(13): Error: template instance fail319.f!(int, int) does not match template declaration f(T...)() if (T.length > 20) +--- +*/ + +void f(T...)() if (T.length > 20) +{} + +void main() +{ + f!(int, int)(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail320.d b/gcc/testsuite/gdc.test/fail_compilation/fail320.d new file mode 100644 index 00000000000..3a80dd55ce3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail320.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail320.d(10): Error: no overload matches for foo +--- +*/ + +import imports.fail320a; +import imports.fail320b; +void main() { foo(); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail322.d b/gcc/testsuite/gdc.test/fail_compilation/fail322.d new file mode 100644 index 00000000000..0ffa15a4875 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail322.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail322.d(10): Error: function fail322.digestToString2 (ref char[16] digest) is not callable using argument types (string) +--- +*/ + +void main() +{ + digestToString2("1234567890123456"); +} + +void digestToString2(ref char[16] digest) +{ + assert(digest[0] == 0xc3); + assert(digest[15] == 0x3b); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail324.d b/gcc/testsuite/gdc.test/fail_compilation/fail324.d new file mode 100644 index 00000000000..9963c8b3457 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail324.d @@ -0,0 +1,17 @@ +/* +test_output: +--- +fail_compilation/fail324.d(16): Error: template instance doStuff!((i){ return i; }) cannot use local '__lambda1' as parameter to non-global template doStuff(alias fun)() +--- +*/ + +struct Foo +{ + void doStuff(alias fun)() {} +} + +void main() +{ + Foo foo; + foo.doStuff!( (i) { return i; })(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail325.d b/gcc/testsuite/gdc.test/fail_compilation/fail325.d new file mode 100644 index 00000000000..e75a1c1326c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail325.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail325.d(12): Error: template fun(T = int)(int w, int z) has no type +--- +*/ + +void fun(T = int)(int w, int z) {} + +void main() +{ + auto x = cast(void function(int, int))fun; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail327.d b/gcc/testsuite/gdc.test/fail_compilation/fail327.d new file mode 100644 index 00000000000..ab872357bac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail327.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail327.d(10): Error: asm statement is assumed to be @system - mark it with '@trusted' if it is not +--- +*/ + +@safe void foo() +{ + version(GNU) + { + version(X86) asm {"xor %%EAX,%%EAX" : : : ;} + else version(X86_64) asm {"xor %%EAX,%%EAX" : : : ;} + else static assert(false, "ASM code not implemented for this architecture"); + } + else asm { xor EAX,EAX; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail328.d b/gcc/testsuite/gdc.test/fail_compilation/fail328.d new file mode 100644 index 00000000000..7e9791339ac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail328.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail328.d(12): Error: @safe function 'fail328.foo' cannot call @system function 'fail328.bar' +--- +*/ + +void bar(); + +@safe void foo() +{ + bar(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail329.d b/gcc/testsuite/gdc.test/fail_compilation/fail329.d new file mode 100644 index 00000000000..f28304e35da --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail329.d @@ -0,0 +1,63 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail329.d(28): Error: variable fail329.A.foo.__ensure.result cannot modify result 'result' in contract +--- +*/ + +//import core.stdc.stdio; + +/*******************************************/ + +class A +{ + int x = 7; + + int foo(int i) + in + { + //printf("A.foo.in %d\n", i); + assert(i == 2); + assert(x == 7); + //printf("A.foo.in pass\n"); + } + out (result) + { + assert(result & 1); + assert(x == 7); + result++; + } + body + { + return i; + } +} + +class B : A +{ + override int foo(int i) + in + { + float f; + //printf("B.foo.in %d\n", i); + assert(i == 4); + assert(x == 7); + f = f + i; + } + out (result) + { + assert(result < 8); + assert(x == 7); + } + body + { + return i - 1; + } +} + +void test1() +{ + auto b = new B(); + b.foo(2); + b.foo(4); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3290.d b/gcc/testsuite/gdc.test/fail_compilation/fail3290.d new file mode 100644 index 00000000000..f398fc95a7d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3290.d @@ -0,0 +1,9 @@ +// 3290 + +void main() +{ + const(int)[] array; + foreach (ref int i; array) { + //i = 42; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail330.d b/gcc/testsuite/gdc.test/fail_compilation/fail330.d new file mode 100644 index 00000000000..a3409db5d1a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail330.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail330.d(9): Error: variable fail330.fun.result cannot modify result 'result' in contract +--- +*/ + +int fun() +out(result) { result = 2; } +body { return 1; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail331.d b/gcc/testsuite/gdc.test/fail_compilation/fail331.d new file mode 100644 index 00000000000..8b79ea2a2c5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail331.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail331.d(10): Error: cannot use typeof(return) inside function foo with inferred return type +--- +*/ + +auto foo() +{ + typeof(return) result; + return result; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d new file mode 100644 index 00000000000..03f3706d696 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail332.d(14): Error: function fail332.foo (int _param_0, ...) is not callable using argument types () +--- +*/ + +import core.vararg; + +void foo(int, ...) {} + +void bar() +{ + foo(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail333.d b/gcc/testsuite/gdc.test/fail_compilation/fail333.d new file mode 100644 index 00000000000..717de24e608 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail333.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail333.d(8): Error: forward reference to 'test' +--- +*/ + +void test(typeof(test) p) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail334.d b/gcc/testsuite/gdc.test/fail_compilation/fail334.d new file mode 100644 index 00000000000..4cab7d3b56c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail334.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail334.d(10): Error: properties can only have zero, one, or two parameter +--- +*/ + +struct S +{ + @property int foo(int a, int b, int c) { return 1; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail335.d b/gcc/testsuite/gdc.test/fail_compilation/fail335.d new file mode 100644 index 00000000000..1800cd065b7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail335.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail335.d(9): Error: cannot overload both property and non-property functions +--- +*/ + +void foo(); +@property void foo(int); + +void main() +{ + foo(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3354.d b/gcc/testsuite/gdc.test/fail_compilation/fail3354.d new file mode 100644 index 00000000000..bcf6368c421 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3354.d @@ -0,0 +1,12 @@ + +void main() +{ + version(D_InlineAsm_X86) {} + else version(D_InlineAsm_X64) {} + else static assert(0); + + asm { + fldz ST(0), ST(1), ST(2), ST(3); + fld ST(0), ST(1), ST(2), ST(3); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail336.d b/gcc/testsuite/gdc.test/fail_compilation/fail336.d new file mode 100644 index 00000000000..2a6be957052 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail336.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail336.d(16): Error: struct S has constructors, cannot use { initializers }, use S( initializers ) instead +--- +*/ + +// Issue 3476 - C-style initializer for structs must be disallowed for structs with a constructor + +struct S +{ + int a; + this(int) {} +} + +S s = { 1 }; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail337.d b/gcc/testsuite/gdc.test/fail_compilation/fail337.d new file mode 100644 index 00000000000..cc86bd20f28 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail337.d @@ -0,0 +1,42 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail337.d(13): Error: static assert `0` is false +fail_compilation/fail337.d(26): instantiated from here: bar!() +fail_compilation/fail337.d(33): 100 recursive instantiations from here: foo!196 +fail_compilation/fail337.d(41): 253 recursive instantiations from here: baz!300 +--- +*/ + +template bar() +{ + static assert(0); +} + +template foo(int N) +{ + static if (N > 0) + { + static if (N & 1) + alias foo!(N - 3) foo; + else + alias foo!(N - 1) foo; + } + else + alias bar!() foo; +} + +template baz(int M) +{ + static if (M < 50) + { + alias foo!(M * 4) baz; + } + else + alias baz!(M - 1) baz; +} + +void main() +{ + int x = baz!(300); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail34.d b/gcc/testsuite/gdc.test/fail_compilation/fail34.d new file mode 100644 index 00000000000..f910a2d167a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail34.d @@ -0,0 +1,42 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail34.d(31): Error: duplicate `case "123"` in switch statement +--- +*/ + +// $HeadURL$ +// $Date$ +// $Author$ + +// @author@ Thomas Kuehne +// @date@ 2004-11-17 +// @uri@ news:u1gr62-kjv.ln1@kuehne.cn +// @url@ nntp://digitalmars.com/digitalmars.D.bugs/2288 + +// duplicate case "123" in switch statement + +module switch_12; + +int main() +{ + string array = "123"; + switch(array) + { + case "123": + { + assert(0); + break; + } + case "123": + { + assert(1); + break; + } + default: + { + return -1; // dummy + } + } + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail340.d b/gcc/testsuite/gdc.test/fail_compilation/fail340.d new file mode 100644 index 00000000000..57d40a7d8fd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail340.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail340.d(18): Error: variable fail340.w of type struct const(CopyTest) uses this(this), which is not allowed in static initialization +fail_compilation/fail340.d(19): while evaluating: `static assert(w.x == 55.0000)` +--- +*/ + +struct CopyTest +{ + double x; + this(double a) { x = a * 10.0;} + this(this) { x += 2.0; } +} + +const CopyTest z = CopyTest(5.3); + +const CopyTest w = z; +static assert(w.x == 55.0); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail341.d b/gcc/testsuite/gdc.test/fail_compilation/fail341.d new file mode 100644 index 00000000000..af78e8145b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail341.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail341.d(26): Error: struct fail341.S is not copyable because it is annotated with @disable +fail_compilation/fail341.d(27): Error: function fail341.foo is not callable because it is annotated with @disable +--- +*/ + +struct T +{ + @disable this(this) + { + } +} + +struct S +{ + T t; +} + +@disable void foo() { } + +void main() +{ + S s; + auto t = s; + foo(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail343.d b/gcc/testsuite/gdc.test/fail_compilation/fail343.d new file mode 100644 index 00000000000..19601a71fa5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail343.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail343.d(22): Error: function fail343.TimedApp.run cannot override final function I.fail343.Timer.run +fail_compilation/fail343.d(22): Error: function fail343.TimedApp.run cannot override final function Application.fail343.Application.run +--- +*/ + +interface Timer +{ + final void run() { } +} + +interface I : Timer { } +interface Application +{ + final void run() { } +} +class TimedApp : I, Application +{ + // cannot define run() + void run() { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail344.d b/gcc/testsuite/gdc.test/fail_compilation/fail344.d new file mode 100644 index 00000000000..9173740abf2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail344.d @@ -0,0 +1,17 @@ +// 3737 + +int crayon; + +struct SIB(alias junk) +{ + template Alike(V) { + enum bool Alike = Q == V.garbage; + } + void opDispatch(string s)() { + static assert(Alike!(SIB!(crayon))); + } +} + +void main() { + SIB!(SIB!(crayon).E)(3.0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail346.d b/gcc/testsuite/gdc.test/fail_compilation/fail346.d new file mode 100644 index 00000000000..532f0bfd213 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail346.d @@ -0,0 +1,15 @@ + +struct S { + int x; + + template T(int val) { + const P T = { val }; // the P here is an error it should be S + } +} + +template V(R,int val){ + const R V=R.T!(val); +} + +const S x = V!(S,0); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail347.d b/gcc/testsuite/gdc.test/fail_compilation/fail347.d new file mode 100644 index 00000000000..03ae7036d81 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail347.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail347.d(21): Error: undefined identifier `bbr`, did you mean variable `bar`? +fail_compilation/fail347.d(22): Error: no property 'ofo' for type 'S', did you mean 'foo'? +fail_compilation/fail347.d(23): Error: undefined identifier `strlenx`, did you mean function `strlen`? +--- +*/ + +//import core.stdc.string; +import imports.fail347a; + +struct S +{ + int foo; +} + +void main() +{ + S bar; + bbr.foo = 3; + bar.ofo = 4; + auto s = strlenx("hello"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail349.d b/gcc/testsuite/gdc.test/fail_compilation/fail349.d new file mode 100644 index 00000000000..8100ab7fd2b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail349.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail349.d(15): Error: function `fail349.bug6109throwing` is not nothrow +fail_compilation/fail349.d(13): Error: nothrow function `fail349.bug6109noThrow` may throw +--- +*/ + +int bug6109throwing() +{ + throw new Exception("throws"); +} +int bug6109noThrow() nothrow +{ + auto g = [4][0 .. bug6109throwing()]; + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail35.d b/gcc/testsuite/gdc.test/fail_compilation/fail35.d new file mode 100644 index 00000000000..c56f2781d4c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail35.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail35.d(15): Error: variable t cannot be read at compile time +--- +*/ + +// http://www.digitalmars.com/d/archives/digitalmars/D/bugs/2372.html +// allegedly crashes, but cannot reproduce + +void main() +{ + for (int t = 0; t < 33; t++) + { + size_t n = (bool[t]).sizeof; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail351.d b/gcc/testsuite/gdc.test/fail_compilation/fail351.d new file mode 100644 index 00000000000..04f21b2e9be --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail351.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail351.d(14): Error: cast(uint)this.num[index] is not an lvalue +--- +*/ + +// 2780 + +struct Immutable { + immutable uint[2] num; + + ref uint opIndex(size_t index) immutable { + return num[index]; + } +} + +void main() { + immutable Immutable foo; + //foo[0]++; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail352.d b/gcc/testsuite/gdc.test/fail_compilation/fail352.d new file mode 100644 index 00000000000..757dd5e282c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail352.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail352.d(18): Error: cannot infer argument types, expected 1 argument, not 2 +--- +*/ + +struct Range +{ + bool empty; + int front() { return 0; } + void popFront() { empty = true; } +} + +void main() +{ + // no index for range foreach + foreach(i, v; Range()) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail353.d b/gcc/testsuite/gdc.test/fail_compilation/fail353.d new file mode 100644 index 00000000000..56cda779d9f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail353.d @@ -0,0 +1,42 @@ +/* +TEST_OUTPUT: +--- +block displacement of -130 exceeds the maximum offset of -128 to 127. +--- +*/ + +void foo() +{ + enum NOP = 0x9090_9090_9090_9090; + + version(GNU) + { + version(X86) asm { + "L1:" + "dq %0,%0,%0,%0;" + "dq %0,%0,%0,%0;" + "dq %0,%0,%0,%0;" + "dq %0,%0,%0,%0;" + "loop L1;" : "n" (NOP) : : ; + } + else version(X86_64) asm { + "L1:" + "dq %0,%0,%0,%0;" + "dq %0,%0,%0,%0;" + "dq %0,%0,%0,%0;" + "dq %0,%0,%0,%0;" + "loop L1;" : "n" (NOP) : : ; + } + else static assert(false, "ASM code not implemented for this architecture"); + } + else asm + { + L1: + dq NOP,NOP,NOP,NOP; // 32 + dq NOP,NOP,NOP,NOP; // 64 + dq NOP,NOP,NOP,NOP; // 96 + dq NOP,NOP,NOP,NOP; // 128 + // unnoticed signed underflow of rel8 with DMD2.056 + loop L1; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail354.d b/gcc/testsuite/gdc.test/fail_compilation/fail354.d new file mode 100644 index 00000000000..55dbf52953b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail354.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail354.d(11): Error: template instance T!N template 'T' is not defined +fail_compilation/fail354.d(13): Error: template instance fail354.S!1 error instantiating +--- +*/ + +struct S(int N) +{ + this(T!N) { } +} +alias S!1 M; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail355.d b/gcc/testsuite/gdc.test/fail_compilation/fail355.d new file mode 100644 index 00000000000..d342d12df0f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail355.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail355.d(8): Error: module imports.fail355 import 'nonexistent' not found +--- +*/ + +import imports.fail355 : nonexistent; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail356a.d b/gcc/testsuite/gdc.test/fail_compilation/fail356a.d new file mode 100644 index 00000000000..4981f72a9a6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail356a.d @@ -0,0 +1,2 @@ +import imports.fail356; +int imports; // collides with package name diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail356b.d b/gcc/testsuite/gdc.test/fail_compilation/fail356b.d new file mode 100644 index 00000000000..18f60858b4b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail356b.d @@ -0,0 +1,2 @@ +import imports.fail356 : bar; +int bar; // collides with selective import diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail356c.d b/gcc/testsuite/gdc.test/fail_compilation/fail356c.d new file mode 100644 index 00000000000..ab12c904085 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail356c.d @@ -0,0 +1,2 @@ +import foo = imports.fail356; +int foo; // collides with renamed import diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3581a.d b/gcc/testsuite/gdc.test/fail_compilation/fail3581a.d new file mode 100644 index 00000000000..5c448668167 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3581a.d @@ -0,0 +1,5 @@ + +class A { void f() {} } +class B : A { static override void f() {}; } + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3581b.d b/gcc/testsuite/gdc.test/fail_compilation/fail3581b.d new file mode 100644 index 00000000000..38be3225dcc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3581b.d @@ -0,0 +1,5 @@ + +class A { void f() {} } +class B : A { private override void f() {}; } + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail359.d b/gcc/testsuite/gdc.test/fail_compilation/fail359.d new file mode 100644 index 00000000000..aae36c894d7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail359.d @@ -0,0 +1,3 @@ +#line 5 _BOOM +void main() { } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail36.d b/gcc/testsuite/gdc.test/fail_compilation/fail36.d new file mode 100644 index 00000000000..47fb88477ea --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail36.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail36.d(13): Error: template t(int L) does not have property 'a' +fail_compilation/fail36.d(18): Error: mixin fail36.func.t!10 error instantiating +--- +*/ + +template t(int L) +{ + int a; + // void foo(int b = t!(L).a) {} // correct + void foo(int b = t.a) {} // wrong +} + +void func() +{ + mixin t!(10); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3672.d b/gcc/testsuite/gdc.test/fail_compilation/fail3672.d new file mode 100644 index 00000000000..1622bd212e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3672.d @@ -0,0 +1,38 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail3672.d(28): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(*p, 1) instead. +fail_compilation/fail3672.d(32): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(*sfp, 1) instead. +fail_compilation/fail3672.d(32): Error: '*sfp += 1' is not a scalar, it is a shared(SF) +--- +*/ + +struct SF // should fail +{ + void opOpAssign(string op, T)(T rhs) + { + } +} + +struct SK // ok +{ + void opOpAssign(string op, T)(T rhs) shared + { + } +} + +void main() +{ + shared int x; + auto p = &x; + *p += 1; // fail + + shared SF sf; + auto sfp = &sf; + *sfp += 1; // fail + + shared SK sk; + auto skp = &sk; + sk += 1; // ok + *skp += 1; // ok +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3673a.d b/gcc/testsuite/gdc.test/fail_compilation/fail3673a.d new file mode 100644 index 00000000000..92c23f01309 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3673a.d @@ -0,0 +1,2 @@ +class A {} +class B : A if(false) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3673b.d b/gcc/testsuite/gdc.test/fail_compilation/fail3673b.d new file mode 100644 index 00000000000..264b4aed35b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3673b.d @@ -0,0 +1,2 @@ +class A {} +class B : if(false) A { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3703.d b/gcc/testsuite/gdc.test/fail_compilation/fail3703.d new file mode 100644 index 00000000000..0b4e260dccd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3703.d @@ -0,0 +1,27 @@ +// Issue 3703 - static array assignment + +/* +TEST_OUTPUT: +--- +fail_compilation/fail3703.d(18): Error: mismatched array lengths, 2 and 1 +fail_compilation/fail3703.d(20): Error: mismatched array lengths, 2 and 1 +fail_compilation/fail3703.d(22): Error: mismatched array lengths, 3 and 2 +fail_compilation/fail3703.d(23): Error: mismatched array lengths, 2 and 3 +fail_compilation/fail3703.d(25): Error: mismatched array lengths, 3 and 2 +fail_compilation/fail3703.d(26): Error: mismatched array lengths, 2 and 3 +--- +*/ + +void main() +{ + int[1] a = [1]; + int[2] b = a; // should make compile error + + b = a; // should make compile error + + int[3] sa3 = [1,2][]; + int[2] sa2 = sa3[][]; + + sa3 = [1,2][]; + sa2 = sa3[][]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3731.d b/gcc/testsuite/gdc.test/fail_compilation/fail3731.d new file mode 100644 index 00000000000..377fd4919d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3731.d @@ -0,0 +1,8 @@ + +void main() +{ + class C {} + class D : C {} + auto x = new immutable(D); + C y = x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3753.d b/gcc/testsuite/gdc.test/fail_compilation/fail3753.d new file mode 100644 index 00000000000..48559958653 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3753.d @@ -0,0 +1,47 @@ +/* +--- +Error: cannot mix core.std.stdlib.alloca() and exception handling in _Dmain() +--- +*/ + +import core.stdc.stdlib : alloca; +import core.stdc.stdio; + +struct TheStruct +{ + ~this() + { + printf("dtor()\n"); + } +} + +void bar() +{ + printf("bar()\n"); +} + +void main() +{ + auto s = TheStruct(); + bar(); + auto a = alloca(16); + printf("test()\n"); + version (DigitalMars) + { + version (Win32) static assert(0); + version (linux) + { + static assert(0); + } + version (FreeBSD) + { + static assert(0); + } + version (OSX) + { + static assert(0); + } + } + else + static assert(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d new file mode 100644 index 00000000000..996f98fcdf7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/fail37_m32.d(9): Error: 'cast(float)4u / cast(float)8u - cast(float)2147483647' is not of integral type, it is a float +--- +*/ + +ulong[cast(uint)((cast(float)int.sizeof/ulong.sizeof)-int.max>>2)+int.max>>2] hexarray; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d new file mode 100644 index 00000000000..2e979e78c67 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -m64 +/* +TEST_OUTPUT: +--- +fail_compilation/fail37_m64.d(9): Error: 'cast(float)4LU / cast(float)8LU - cast(float)2147483647' is not of integral type, it is a float +--- +*/ + +ulong[cast(uint)((cast(float)int.sizeof/ulong.sizeof)-int.max>>2)+int.max>>2] hexarray; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail38.d b/gcc/testsuite/gdc.test/fail_compilation/fail38.d new file mode 100644 index 00000000000..0f2cd5f3570 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail38.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail38.d(12): Error: 'super' is only allowed in non-static class member functions +--- +*/ + +int x; + +void test() +{ + super.x = 2; +} + +int main() +{ + test(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3882.d b/gcc/testsuite/gdc.test/fail_compilation/fail3882.d new file mode 100644 index 00000000000..b7d8a9789a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3882.d @@ -0,0 +1,48 @@ +// REQUIRED_ARGS: -w +// PERMUTE_ARGS: -debug + +/******************************************/ +// 3882 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail3882.d(23): Warning: calling fail3882.strictlyPure!int.strictlyPure without side effects discards return value of type int, prepend a cast(void) if intentional +fail_compilation/fail3882.d(27): Warning: calling fp without side effects discards return value of type int, prepend a cast(void) if intentional +--- +*/ + +@safe pure nothrow T strictlyPure(T)(T x) +{ + return x*x; +} + +void main() +{ + int x = 3; + strictlyPure(x); + + // 12649 + auto fp = &strictlyPure!int; + fp(x); +} + +/******************************************/ +// bugfix in TypeFunction::purityLevel + +/* +TEST_OUTPUT: +--- +fail_compilation/fail3882.d(46): Warning: calling fail3882.f1 without side effects discards return value of type int, prepend a cast(void) if intentional +fail_compilation/fail3882.d(47): Warning: calling fail3882.f2 without side effects discards return value of type int, prepend a cast(void) if intentional +--- +*/ + +nothrow pure int f1(immutable(int)[] a) { return 0; } +nothrow pure int f2(immutable(int)* p) { return 0; } + +void test_bug() +{ + f1([]); + f2(null); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3895.d b/gcc/testsuite/gdc.test/fail_compilation/fail3895.d new file mode 100644 index 00000000000..9921f2a6b36 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3895.d @@ -0,0 +1,9 @@ +import std.stdio; + +void main() { + double[] stuff = [1.,2.,3.,4.,5.]; + float[] otherStuff; + otherStuff ~= stuff; + writeln(otherStuff); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail39.d b/gcc/testsuite/gdc.test/fail_compilation/fail39.d new file mode 100644 index 00000000000..65472cf614e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail39.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail39.d(11): Error: function fail39.main.__funcliteral2 cannot access frame of function D main +--- +*/ + +void main() +{ + void foo() {} + void function() bar = function void() { foo(); }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3990.d b/gcc/testsuite/gdc.test/fail_compilation/fail3990.d new file mode 100644 index 00000000000..6d17a7dea0e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3990.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail3990.d(12): Error: using * on an array is no longer supported; use *(arr1).ptr instead +fail_compilation/fail3990.d(14): Error: using * on an array is no longer supported; use *(arr2).ptr instead +--- +*/ + +void main() +{ + int[] arr1 = [1, 2, 3]; + assert(*arr1 == 1); + int[3] arr2 = [1, 2, 3]; + assert(*arr2 == 1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail40.d b/gcc/testsuite/gdc.test/fail_compilation/fail40.d new file mode 100644 index 00000000000..aa15db319b1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail40.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail40.d(11): Error: variable yuiop cannot be read at compile time +--- +*/ + +struct Qwert +{ + int[20] yuiop; + int* asdfg = yuiop.ptr; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4082.d b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d new file mode 100644 index 00000000000..fc6ba7874f7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail4082.d(14): Error: destructor `fail4082.Foo.~this` is not nothrow +fail_compilation/fail4082.d(12): Error: nothrow function `fail4082.test1` may throw +--- +*/ +struct Foo +{ + ~this() { throw new Exception(""); } +} +nothrow void test1() +{ + Foo f; + + goto NEXT; +NEXT: + ; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail4082.d(32): Error: destructor `fail4082.Bar.~this` is not nothrow +fail_compilation/fail4082.d(32): Error: nothrow function `fail4082.test2` may throw +--- +*/ +struct Bar +{ + ~this() { throw new Exception(""); } +} +nothrow void test2(Bar t) +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail41.d b/gcc/testsuite/gdc.test/fail_compilation/fail41.d new file mode 100644 index 00000000000..fa0e0c3cdcf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail41.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail41.d(17): Error: cannot return non-void from void function +--- +*/ + +class MyClass +{ +} + +MyClass[char[]] myarray; + +void fn() +{ + foreach (MyClass mc; myarray) + return mc; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail42.d b/gcc/testsuite/gdc.test/fail_compilation/fail42.d new file mode 100644 index 00000000000..5101ca142a2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail42.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail42.d(22): Error: struct fail42.Qwert no size because of forward reference +--- +*/ + +/+ +struct Qwert +{ + Qwert asdfg; +} ++/ + +struct Qwert +{ + Yuiop asdfg; +} + +struct Yuiop +{ + Qwert hjkl; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4206.d b/gcc/testsuite/gdc.test/fail_compilation/fail4206.d new file mode 100644 index 00000000000..409158a400a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4206.d @@ -0,0 +1,5 @@ + +struct s {} +enum var = s; + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d new file mode 100644 index 00000000000..7794c462cc0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d @@ -0,0 +1,7 @@ +enum bool WWW = is(typeof(A.x)); + +interface A { + B blah; + void foo(B b){} +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d new file mode 100644 index 00000000000..2234cb846a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d @@ -0,0 +1,7 @@ +enum bool WWW = is(typeof(A.x)); + +struct A { + B blah; + void foo(B b){} +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d new file mode 100644 index 00000000000..b00ec1be963 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d @@ -0,0 +1,7 @@ +enum bool WWW = is(typeof(A.x)); + +class A { + B blah; + void foo(B b){} +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269d.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269d.d new file mode 100644 index 00000000000..b9d2afc7bee --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269d.d @@ -0,0 +1,5 @@ + +static if(is(typeof(X6.init))) {} +alias Y X6; + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269e.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269e.d new file mode 100644 index 00000000000..d7b2f23308b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269e.d @@ -0,0 +1,5 @@ + +static if(is(typeof(X5.init))) {} +typedef Y X5; + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269f.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269f.d new file mode 100644 index 00000000000..4033447426b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269f.d @@ -0,0 +1,5 @@ + +static if(is(typeof(X16))) {} +alias X16 X16; + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269g.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269g.d new file mode 100644 index 00000000000..9241e481de4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269g.d @@ -0,0 +1,6 @@ + +int[2] d; +static if(is(typeof(Xg.init))) {} +alias d[1] Xg; + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4374.d b/gcc/testsuite/gdc.test/fail_compilation/fail4374.d new file mode 100644 index 00000000000..c1762cbe3e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4374.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail4374.d(11): Error: terminating `;` required after do-while statement +--- +*/ + +void main() +{ + do {} while(0) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375a.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375a.d new file mode 100644 index 00000000000..030b4858b7e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375a.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + if (false) + assert(3); + else + assert(4); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375b.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375b.d new file mode 100644 index 00000000000..6ac5b71b0a7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375b.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + // disallowed + if (true) + foreach (i; 0 .. 5) + if (true) + assert(5); + else + assert(6); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375c.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375c.d new file mode 100644 index 00000000000..697c99f0fc8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375c.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + if (false) { + assert(6.1); + } + else { + assert(6.2); + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d new file mode 100644 index 00000000000..329907eec40 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) +label2: + if (true) + assert(15); + else + assert(16); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375e.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375e.d new file mode 100644 index 00000000000..14b96d72a7f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375e.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + version (A) + if (true) + assert(24); + else + assert(25); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375f.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375f.d new file mode 100644 index 00000000000..c715ee6c7fc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375f.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + version (A) + version (B) + assert(25.1); + else + assert(25.2); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375g.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375g.d new file mode 100644 index 00000000000..f555651c4c8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375g.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + static if (true) + static if (true) + assert(33); + else + assert(34); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375h.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375h.d new file mode 100644 index 00000000000..793e42ba93b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375h.d @@ -0,0 +1,15 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + switch (4) { + default: + if (true) // disallowed + if (false) + assert(48); + else + assert(49); + break; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375i.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375i.d new file mode 100644 index 00000000000..da3e67c93d1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375i.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + switch (1) // o_O + default: + if (false) + assert(115); + else + assert(116); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375j.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375j.d new file mode 100644 index 00000000000..cd289a08fe3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375j.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + final switch (1) // o_O + case 1: + if (false) + assert(119); + else + assert(120); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375k.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375k.d new file mode 100644 index 00000000000..f372406d4a8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375k.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + mixin(q{ + if(true) + if(true) + assert(54); + else + assert(55); + }); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375l.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375l.d new file mode 100644 index 00000000000..fea1d82d0ef --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375l.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + while (false) + if (true) + assert(70); + else + assert(71); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375m.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375m.d new file mode 100644 index 00000000000..fdde1a11b3d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375m.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + do + if (true) + if (true) + assert(76); + else + assert(77); + while (false); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375o.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375o.d new file mode 100644 index 00000000000..6c3d3e15e4e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375o.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + for (; false;) + if (true) + assert(82); + else + assert(83); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375p.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375p.d new file mode 100644 index 00000000000..82f7cabd28b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375p.d @@ -0,0 +1,15 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + while (false) + for (;;) + scope (exit) + synchronized (x) + if (true) + assert(90); + else + assert(89); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d new file mode 100644 index 00000000000..7d11c46f347 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + auto x = 1; + if (true) + with (x) + if (false) + assert(90); + else + assert(91); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375r.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375r.d new file mode 100644 index 00000000000..49b2f8a8a3c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375r.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + try + assert(103); + finally + if (true) + assert(104); + else + assert(105); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375s.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375s.d new file mode 100644 index 00000000000..ed1b7256906 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375s.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +void main() { + if (true) + try + assert(106); + catch(Exception e) + if (true) + assert(107); + else + assert(108); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375t.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375t.d new file mode 100644 index 00000000000..197563654f3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375t.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -w -unittest +// 4375: Dangling else + +unittest { // disallowed + if (true) + if (false) + assert(52); + else + assert(53); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375u.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375u.d new file mode 100644 index 00000000000..cb06823a028 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375u.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +static if (true) + static if (false) + struct G1 {} +else + struct G2 {} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375v.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375v.d new file mode 100644 index 00000000000..1510c8dc935 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375v.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +version (A) + version (B) + struct G3 {} +else + struct G4 {} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375w.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375w.d new file mode 100644 index 00000000000..cd3c3bdf245 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375w.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +static if (true) + version (B) + struct G1 {} +else + struct G2 {} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375x.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375x.d new file mode 100644 index 00000000000..b6ae64fd187 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375x.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +static if (true) +abstract: + static if (false) + class G5 {} +else + class G6 {} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375y.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375y.d new file mode 100644 index 00000000000..b3713e38f12 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375y.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -w +// 4375: Dangling else + +static if (true) + align(1) + extern(C) + pure + static if (false) + void G10(){} +else + void G11(){} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail44.d b/gcc/testsuite/gdc.test/fail_compilation/fail44.d new file mode 100644 index 00000000000..b8916a00991 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail44.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail44.d(18): Error: expression bar[i] is void and has no value +--- +*/ + +void Foo() +{ + void[] bar; + void[] foo; + + bar.length = 50; + foo.length = 50; + + for(size_t i=0; i<50; i++) + { + foo[i] = bar[i]; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4421.d b/gcc/testsuite/gdc.test/fail_compilation/fail4421.d new file mode 100644 index 00000000000..b82d70150ae --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4421.d @@ -0,0 +1,40 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail4421.d(16): Error: function fail4421.U1.__postblit destructors, postblits and invariants are not allowed in union U1 +fail_compilation/fail4421.d(17): Error: destructor fail4421.U1.~this destructors, postblits and invariants are not allowed in union U1 +fail_compilation/fail4421.d(18): Error: function fail4421.U1.__invariant1 destructors, postblits and invariants are not allowed in union U1 +--- + + + + +*/ + +union U1 +{ + this(this); + ~this(); + invariant() { } +} + +struct S1 +{ + this(this); + ~this(); + invariant() { } +} + +union U2 +{ + S1 s1; +} + +struct S2 +{ + union + { + S1 s1; + int j; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4448.d b/gcc/testsuite/gdc.test/fail_compilation/fail4448.d new file mode 100644 index 00000000000..f8b2dbb2871 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4448.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail4448.d(19): Error: label `L1` has no break +fail_compilation/fail4448.d(26): called from here: bug4448() +fail_compilation/fail4448.d(26): while evaluating: `static assert(bug4448() == 3)` +--- +*/ + +int bug4448() +{ + int n=2; + L1:{ switch(n) + { + case 5: + return 7; + default: + n = 5; + break L1; + } + int w = 7; + } + return 3; +} + +static assert(bug4448()==3); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail45.d b/gcc/testsuite/gdc.test/fail_compilation/fail45.d new file mode 100644 index 00000000000..3380fe4fd5d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail45.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail45.d(10): Error: variable fail45.main.O cannot be declared to be a function +--- +*/ + +void main() +{ + typeof(main) O = 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4510.d b/gcc/testsuite/gdc.test/fail_compilation/fail4510.d new file mode 100644 index 00000000000..d10100070e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4510.d @@ -0,0 +1,9 @@ +// 4510 + +void main() +{ + float[] arr = [1.0, 2.5, 4.0]; + foreach (ref double elem; arr) { + //elem /= 2; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4511.d b/gcc/testsuite/gdc.test/fail_compilation/fail4511.d new file mode 100644 index 00000000000..f4d8a1c73e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4511.d @@ -0,0 +1,16 @@ +void test72() +{ + class A {} + class B : A {} + + class X + { + abstract A func(); + } + class Y : X + { + B func() { return new A(); } + } +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4517.d b/gcc/testsuite/gdc.test/fail_compilation/fail4517.d new file mode 100644 index 00000000000..a55b0f5f927 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4517.d @@ -0,0 +1,15 @@ + +enum E : ushort +{ + A, B +} + +void main() +{ + E e; + final switch(e) + { + case E.A: + break; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4559.d b/gcc/testsuite/gdc.test/fail_compilation/fail4559.d new file mode 100644 index 00000000000..0101ae98bf1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4559.d @@ -0,0 +1,22 @@ +/* +REQUIRED_ARGS: -o- -de +TEST_OUTPUT: +--- +fail_compilation/fail4559.d(13): Deprecation: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(19): Deprecation: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(21): Deprecation: use `{ }` for an empty statement, not `;` +--- +*/ + +void foo() +{ + int x;; + enum A + { + a, + b, + c + }; + + void bar() {}; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail46.d b/gcc/testsuite/gdc.test/fail_compilation/fail46.d new file mode 100644 index 00000000000..a62d1631678 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail46.d @@ -0,0 +1,21 @@ +// PERMUTE_ARGS: -inline +/* +TEST_OUTPUT: +--- +fail_compilation/fail46.d(19): Error: need 'this' for 'bug' of type 'int()' +--- +*/ + +struct MyStruct +{ + int bug() + { + return 3; + } +} + +int main() +{ + assert(MyStruct.bug() == 3); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d new file mode 100644 index 00000000000..f1547ba12c5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d @@ -0,0 +1,15 @@ +/* +--- +fail_compilation/fail4611.d(15): Error: Vec[2147483647] size 4 * 2147483647 exceeds 0x7fffffff size limit for static array +--- +*/ + +struct Vec +{ + int x; +} + +void main() +{ + Vec[ptrdiff_t.max] a; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail47.d b/gcc/testsuite/gdc.test/fail_compilation/fail47.d new file mode 100644 index 00000000000..d320fdafc8b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail47.d @@ -0,0 +1,9 @@ +void foo() {} +int _foo; +alias _foo foo; + +void main() +{ + foo = 1; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4958.d b/gcc/testsuite/gdc.test/fail_compilation/fail4958.d new file mode 100644 index 00000000000..b72347662e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4958.d @@ -0,0 +1,2 @@ + +enum FloatEnum : float { A = float.max/2, B, C } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail50.d b/gcc/testsuite/gdc.test/fail_compilation/fail50.d new file mode 100644 index 00000000000..9cd29833877 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail50.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail50.d(12): Error: need 'this' for address of a +fail_compilation/fail50.d(12): Error: variable a cannot be read at compile time +--- +*/ + +struct Marko +{ + int a; + int* m = &a; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail51.d b/gcc/testsuite/gdc.test/fail_compilation/fail51.d new file mode 100644 index 00000000000..41a27ca7a22 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail51.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail51.d(11): Error: interface fail51.B circular inheritance of interface +--- +*/ + +// interface A { void f(); } + +interface A : B { void f(); } +interface B : A { void g(); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail52.d b/gcc/testsuite/gdc.test/fail_compilation/fail52.d new file mode 100644 index 00000000000..9b662de1348 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail52.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail52.d(10): Error: class fail52.C circular inheritance +--- +*/ + +class A : B { void f(); } +class B : C { override void g(); } +class C : A { void g(); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail53.d b/gcc/testsuite/gdc.test/fail_compilation/fail53.d new file mode 100644 index 00000000000..2570dd8939c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail53.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail53.d(25): Error: function object.Object.opEquals (Object o) is not callable using argument types (int) +--- +*/ + +// $HeadURL$ +// $Date$ +// $Author$ + +// @author@ Thomas Kuehne +// @date@ 2005-01-22 +// @uri@ news:csvvet$2g4$1@digitaldaemon.com +// @url@ nntp://news.digitalmars.com/digitalmars.D.bugs/2741 + +// __DSTRESS_ELINE__ 17 + +module dstress.nocompile.bug_mtype_507_A; + +int main() +{ + Object o; + int i; + if (i == o) + { + return -1; + } + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail54.d b/gcc/testsuite/gdc.test/fail_compilation/fail54.d new file mode 100644 index 00000000000..aa95b1d15d6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail54.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail54.d(22): Error: incompatible types for ((0) == (Exception)): cannot use '==' with types +--- +*/ + +// $HeadURL$ +// $Date$ +// $Author$ + +// @author@ zwang +// @date@ 2005-02-03 +// @uri@ news:ctthp6$25b$1@digitaldaemon.com + +// __DSTRESS_ELINE__ 14 + +module dstress.nocompile.bug_mtype_507_C; + +void test() +{ + 0 == Exception; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5435.d b/gcc/testsuite/gdc.test/fail_compilation/fail5435.d new file mode 100644 index 00000000000..2c610a86d66 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5435.d @@ -0,0 +1,13 @@ +// 5435 + +template Tuple5435(E...) { alias E Tuple5435; } +enum Enum5435 { A, B, C }; + +void main() +{ + alias Tuple5435!(Enum5435.A, Enum5435.B, Enum5435.C, "foo", 3.0) tup; + + foreach (Enum5435 foo; tup) pragma(msg, foo); + foreach ( string foo; tup) pragma(msg, foo); + foreach ( int foo; tup) pragma(msg, foo); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail55.d b/gcc/testsuite/gdc.test/fail_compilation/fail55.d new file mode 100644 index 00000000000..57117d86ee4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail55.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail55.d(22): Error: function object.Object.opCmp (Object o) is not callable using argument types (int) +--- +*/ + +// $HeadURL$ +// $Date$ +// $Author$ + +// @author@ zwang +// @date@ 2005-02-03 +// @uri@ news:cttjjg$4i0$2@digitaldaemon.com + +// __DSTRESS_ELINE__ 14 + +module dstress.nocompile.bug_mtype_507_D; + +void test() +{ + 0 < Exception; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail56.d b/gcc/testsuite/gdc.test/fail_compilation/fail56.d new file mode 100644 index 00000000000..579401fb703 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail56.d @@ -0,0 +1,21 @@ +// $HeadURL$ +// $Date$ +// $Author$ + +// @author@ Regan Heath +// @date@ 2005-03-30 +// @uri@ news:opsof4hwgy23k2f5@nrage.netwin.co.nz + +// __DSTRESS_ELINE__ 14 + +module dstress.nocompile.bug_20050330_A; + +template Blah(int a, alias B){ + mixin Blah!(a, B) Foo; +} + +int main(){ + int a; + mixin Blah!(5,a); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5634.d b/gcc/testsuite/gdc.test/fail_compilation/fail5634.d new file mode 100644 index 00000000000..0044adf8df2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5634.d @@ -0,0 +1,3 @@ +void main() { } +void main() { } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail57.d b/gcc/testsuite/gdc.test/fail_compilation/fail57.d new file mode 100644 index 00000000000..ded3a6ea582 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail57.d @@ -0,0 +1,6 @@ + +int main() +{ + int x = 1 / 0; + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5733.d b/gcc/testsuite/gdc.test/fail_compilation/fail5733.d new file mode 100644 index 00000000000..2292716bc9c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5733.d @@ -0,0 +1,6 @@ +struct Test +{ + struct opDispatch(string dummy) + { enum opDispatch = 1; } +} +auto temp = Test().foo!(int); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail58.d b/gcc/testsuite/gdc.test/fail_compilation/fail58.d new file mode 100644 index 00000000000..ad6f8da3e30 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail58.d @@ -0,0 +1,27 @@ +debug(1) import std.stdio; +const int anything = -1000; // Line #2 +dchar[] SomeFunc( dchar[] pText, out int pStopPosn) +{ + if (pText.length == 0) + pStopPosn = 0; + else + pStopPosn = -1; + debug(1) writefln("DEBUG: using '%s' we get %d", pText, pStopPosn); + return pText.dup; +} + +int main(char[][] pArgs) +{ + int sp; + + SomeFunc("123", sp); + debug(1) writefln("DEBUG: got %d", sp); + assert(sp == -1); + + SomeFunc("", sp); +// if (sp != 0){} // Line #22 + debug(1) writefln("DEBUG: got %d", sp); + assert(sp == -1); + return 0; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5851.d b/gcc/testsuite/gdc.test/fail_compilation/fail5851.d new file mode 100644 index 00000000000..c422c1436d1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5851.d @@ -0,0 +1,10 @@ + +class Foo +{ + Object o; + alias o this; +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail59.d b/gcc/testsuite/gdc.test/fail_compilation/fail59.d new file mode 100644 index 00000000000..63fab5e0879 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail59.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail59.d(50): Error: outer class C1 'this' needed to 'new' nested class C2 +--- +*/ + +class C1 +{ + int c1; + + this() + { + c1 = 2; + } + + class C2 + { + class C3 + { + int c3; + + this(int n) + { + c3 = n + c1 + c2; + } + } + + int c2; + + C3 foo() + { + return new C3(8); + } + + this(int k) + { + c2 = k + 7; + } + } + + C2 bar() + { + return new C2(17); + } +} + +void main() +{ + C1.C2 q = new C1.C2(3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5953a1.d b/gcc/testsuite/gdc.test/fail_compilation/fail5953a1.d new file mode 100644 index 00000000000..f977c5822bb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5953a1.d @@ -0,0 +1,4 @@ +void main() +{ + auto a2 = [,]; // invalid, but compiles +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5953a2.d b/gcc/testsuite/gdc.test/fail_compilation/fail5953a2.d new file mode 100644 index 00000000000..a1e6c75cb3a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5953a2.d @@ -0,0 +1,4 @@ +void main() +{ + auto a3 = [,,,]; // invalid, but compiles +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5953s1.d b/gcc/testsuite/gdc.test/fail_compilation/fail5953s1.d new file mode 100644 index 00000000000..c64601b003c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5953s1.d @@ -0,0 +1,5 @@ +void main() +{ + struct S{} + S s2 = {,}; // invalid, but compiles +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5953s2.d b/gcc/testsuite/gdc.test/fail_compilation/fail5953s2.d new file mode 100644 index 00000000000..3f1ac9c42d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail5953s2.d @@ -0,0 +1,5 @@ +void main() +{ + struct S{} + S s3 = {,,,}; // invalid, but compiles +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail60.d b/gcc/testsuite/gdc.test/fail_compilation/fail60.d new file mode 100644 index 00000000000..3d660252be8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail60.d @@ -0,0 +1,10 @@ +class A +{ + class B + { + + } + + B b=new B; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6029.d b/gcc/testsuite/gdc.test/fail_compilation/fail6029.d new file mode 100644 index 00000000000..e5199db6628 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6029.d @@ -0,0 +1,15 @@ +struct A +{ + static A a; + alias a this; +} + +void foo(A a) +{ +} + +void main() +{ +// foo(A); // Error: type A is not an expression + int s = A; // Error: type A has no value + stack overflow +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail61.d b/gcc/testsuite/gdc.test/fail_compilation/fail61.d new file mode 100644 index 00000000000..e9daa6163b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail61.d @@ -0,0 +1,43 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail61.d(22): Error: no property 'B' for type 'fail61.A.B' +fail_compilation/fail61.d(23): Error: no property 'B' for type 'fail61.A.B' +fail_compilation/fail61.d(32): Error: no property 'A2' for type 'fail61.B2' +fail_compilation/fail61.d(41): Error: this for foo needs to be type B3 not type fail61.C3 +--- +*/ + +class A +{ + class B : A + { + static const int C = 5; + } +} + +void main() +{ + int n1 = A.B.C; + int n2 = A.B.B.C; // Line22 + int n3 = A.B.B.B.C; // Line23 +} + +class A2 { void foo(){ assert(0);} } +class B2 : A2 { override void foo(){} } +class C2 : B2 +{ + void bar() + { + B2.A2.foo(); // Line32 + } +} + +class B3 { void foo(){ assert(0); } } +class C3 +{ + void bar() + { + B3.foo(); // Line41 + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6107.d b/gcc/testsuite/gdc.test/fail_compilation/fail6107.d new file mode 100644 index 00000000000..4d79b0c2590 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6107.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail6107.d(10): Error: variable fail6107.Foo.__ctor is not a constructor; identifiers starting with __ are reserved for the implementation +fail_compilation/fail6107.d(14): Error: variable fail6107.Bar.__ctor is not a constructor; identifiers starting with __ are reserved for the implementation +--- +*/ +struct Foo +{ + enum __ctor = 4; +} +class Bar +{ + int __ctor = 4; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail62.d b/gcc/testsuite/gdc.test/fail_compilation/fail62.d new file mode 100644 index 00000000000..caa784300ed --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail62.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail62.d(11): Error: version Foo defined after use +--- +*/ + +version (Foo) + int x; + +version = Foo; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6242.d b/gcc/testsuite/gdc.test/fail_compilation/fail6242.d new file mode 100644 index 00000000000..92df7700563 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6242.d @@ -0,0 +1,3 @@ +class A { void fun(int) {} } + +class B : A { void fun(int x) in { assert(x > 0); } body {} } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail63.d b/gcc/testsuite/gdc.test/fail_compilation/fail63.d new file mode 100644 index 00000000000..4af83ec0a09 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail63.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail63.d(11): Error: debug Foo defined after use +--- +*/ + +debug (Foo) + int x; + +debug = Foo; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6334.d b/gcc/testsuite/gdc.test/fail_compilation/fail6334.d new file mode 100644 index 00000000000..3bb6b771c35 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6334.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail6334.d(12): Error: static assert `0` is false +--- +*/ + +mixin template T1() +{ + mixin T2; //compiles if these lines + mixin T2!(a, bb, ccc, dddd); //are before T2 declaration + mixin template T2() { static assert(0); } +} + +void main() +{ + mixin T1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6451.d b/gcc/testsuite/gdc.test/fail_compilation/fail6451.d new file mode 100644 index 00000000000..54c628ac075 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6451.d @@ -0,0 +1,18 @@ + +version(GNU) +{ + static assert(0); +} +version(Win64) +{ + static assert(0); +} +else version(X86_64) +{ + void error(...){} +} +else +{ + static assert(0); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6453.d b/gcc/testsuite/gdc.test/fail_compilation/fail6453.d new file mode 100644 index 00000000000..e1db9f4d5f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6453.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail6453.d(13): Error: struct fail6453.S6453x mixing invariants with shared/synchronized differene is not supported +fail_compilation/fail6453.d(18): Error: class fail6453.C6453y mixing invariants with shared/synchronized differene is not supported +fail_compilation/fail6453.d(23): Error: class fail6453.C6453z mixing invariants with shared/synchronized differene is not supported +--- +*/ + +struct S6453x +{ + invariant() {} + shared invariant() {} +} +class C6453y +{ + invariant() {} + synchronized invariant() {} +} +class C6453z +{ + shared invariant() {} + synchronized invariant() {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6458.d b/gcc/testsuite/gdc.test/fail_compilation/fail6458.d new file mode 100644 index 00000000000..52b97a3b0d0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6458.d @@ -0,0 +1,5 @@ + +void main() +{ + char d = 'ä'; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6497.d b/gcc/testsuite/gdc.test/fail_compilation/fail6497.d new file mode 100644 index 00000000000..d985cb45553 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6497.d @@ -0,0 +1,6 @@ + +void main() @safe +{ + int n; + auto b = &(0 ? n : n); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6561.d b/gcc/testsuite/gdc.test/fail_compilation/fail6561.d new file mode 100644 index 00000000000..8a9da8ba2e8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6561.d @@ -0,0 +1,8 @@ +struct S +{ + alias x this; // should cause undefined identifier error +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail66.d b/gcc/testsuite/gdc.test/fail_compilation/fail66.d new file mode 100644 index 00000000000..5c352a52093 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail66.d @@ -0,0 +1,91 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail66.d(11): Error: constructor fail66.C1.this missing initializer for const field y +--- +*/ + +class C1 +{ + const int y; + this() {} +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail66.d(28): Error: cannot modify const expression c.y +--- +*/ +class C2 +{ + const int y; + this() { y = 7; } +} +void test2() +{ + C2 c = new C2(); + c.y = 3; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail66.d(43): Error: cannot modify const expression this.y +--- +*/ +class C3 +{ + const int y; + this() { y = 7; } + void foo() + { + y = 6; + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail66.d(59): Error: cannot modify const expression x +--- +*/ +class C4 +{ + static const int x; + static this() { x = 5; } + void foo() + { + x = 4; + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail66.d(73): Error: cannot modify const expression z5 +--- +*/ +const int z5; +static this() { z5 = 3; } +void test5() +{ + z5 = 4; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail66.d(89): Error: cannot modify const expression c.y +--- +*/ +class C6 +{ + const int y; + this() + { + C6 c = this; + y = 7; + c.y = 8; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6611.d b/gcc/testsuite/gdc.test/fail_compilation/fail6611.d new file mode 100644 index 00000000000..781688978d1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6611.d @@ -0,0 +1,6 @@ + +void main() +{ + auto x = new int[](10); + x[]++; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6652.d b/gcc/testsuite/gdc.test/fail_compilation/fail6652.d new file mode 100644 index 00000000000..45a3f5a3fec --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6652.d @@ -0,0 +1,37 @@ +// PERMUTE_ARGS: -w -dw -de -d + +/******************************************/ +// 6652 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail6652.d(20): Error: cannot modify const expression i +fail_compilation/fail6652.d(25): Error: cannot modify const expression i +fail_compilation/fail6652.d(30): Error: cannot modify const expression i +fail_compilation/fail6652.d(35): Error: cannot modify const expression i +--- +*/ + +void main() +{ + foreach (const i; 0..2) + { + ++i; + } + + foreach (ref const i; 0..2) + { + ++i; + } + + foreach (const i, e; [1,2,3,4,5]) + { + ++i; + } + + foreach (ref const i, e; [1,2,3,4,5]) + { + ++i; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6781.d b/gcc/testsuite/gdc.test/fail_compilation/fail6781.d new file mode 100644 index 00000000000..ef1c77f073a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6781.d @@ -0,0 +1,9 @@ +void bug6781(alias xxx)() { + some_error; +} +struct C6781 { + void makeSortedIndices() { + int greater; + bug6781!greater(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d new file mode 100644 index 00000000000..d714f2035a1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d @@ -0,0 +1,34 @@ +// 6795 +/* +TEST_OUTPUT: +--- +fail_compilation/fail6795.d(12): Error: constant 0 is not an lvalue +fail_compilation/fail6795.d(13): Error: constant 0 is not an lvalue +--- +*/ + +void main() { + enum int[] array = [0]; + array[0]++; + array[0] += 3; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail6795.d(31): Error: constant 0 is not an lvalue +fail_compilation/fail6795.d(32): Error: constant 0 is not an lvalue +fail_compilation/fail6795.d(33): Error: constant 0 is not an lvalue +--- +*/ + +void test_wrong_line_num() +{ + enum int[] da = [0]; + enum int[1] sa = [0]; + enum int[int] aa = [0:0]; + + da[0] += 3; + sa[0] += 3; + aa[0] += 3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6889.d b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d new file mode 100644 index 00000000000..4d86256b0bd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d @@ -0,0 +1,130 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail6889.d(16): Error: cannot goto out of `scope(success)` block +fail_compilation/fail6889.d(17): Error: cannot goto in to `scope(success)` block +fail_compilation/fail6889.d(19): Error: return statements cannot be in `scope(success)` bodies +fail_compilation/fail6889.d(23): Error: continue is not inside `scope(success)` bodies +fail_compilation/fail6889.d(24): Error: break is not inside `scope(success)` bodies +fail_compilation/fail6889.d(29): Error: continue is not inside `scope(success)` bodies +fail_compilation/fail6889.d(30): Error: break is not inside `scope(success)` bodies +--- +*/ +void test_success() +{ +L1: + scope(success) { L2: goto L1; } // NG + goto L2; // NG + + scope(success) { return; } // NG (from fail102.d) + + foreach (i; 0..1) + { + scope(success) continue; // NG + scope(success) break; // NG + } + + foreach (i; Aggr()) + { + scope(success) continue; // NG + scope(success) break; // NG + } + /+ + // is equivalent with: + switch ( + Aggr().opApply((int i){ + scope(success) return 0; // NG + scope(success) return 1; // NG + return 0; + })) + { + default: break; + } + +/ +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail6889.d(56): Error: cannot goto in to `scope(failure)` block +--- +*/ +void test_failure() +{ +L1: + scope(failure) { L2: goto L1; } // OK + goto L2; // NG + + scope(failure) { return; } // OK + + foreach (i; 0..1) + { + scope(failure) continue; // OK + scope(failure) break; // OK + } + + foreach (i; Aggr()) + { + scope(failure) continue; // OK + scope(failure) break; // OK + } + /+ + // is equivalent with: + switch ( + Aggr().opApply((int i){ + scope(failure) return 0; // OK + scope(failure) return 1; // OK + return 0; + })) + { + default: break; + } + +/ +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail6889.d(100): Error: cannot goto out of `scope(exit)` block +fail_compilation/fail6889.d(101): Error: cannot goto in to `scope(exit)` block +fail_compilation/fail6889.d(103): Error: return statements cannot be in `scope(exit)` bodies +fail_compilation/fail6889.d(107): Error: continue is not inside `scope(exit)` bodies +fail_compilation/fail6889.d(108): Error: break is not inside `scope(exit)` bodies +fail_compilation/fail6889.d(113): Error: continue is not inside `scope(exit)` bodies +fail_compilation/fail6889.d(114): Error: break is not inside `scope(exit)` bodies +--- +*/ +void test_exit() +{ +L1: + scope(exit) { L2: goto L1; } // NG + goto L2; // NG + + scope(exit) { return; } // NG (from fail102.d) + + foreach (i; 0..1) + { + scope(exit) continue; // NG + scope(exit) break; // NG + } + + foreach (i; Aggr()) + { + scope(exit) continue; // NG + scope(exit) break; // NG + } + /+ + // is equivalent with: + switch ( + Aggr().opApply((int i){ + scope(exit) return 0; // NG + scope(exit) return 1; // NG + return 0; + })) + { + default: break; + } + +/ +} + +struct Aggr { int opApply(int delegate(int) dg) { return dg(0); } } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6968.d b/gcc/testsuite/gdc.test/fail_compilation/fail6968.d new file mode 100644 index 00000000000..69f63b9cbce --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6968.d @@ -0,0 +1,22 @@ +// 6968 + +template Pred(A, B) +{ + static if(is(B == int)) + enum bool Pred = true; + else + enum bool Pred = false; +} + +template PredAny(A, B...) +{ + static if(B.length == 0) + enum bool PredAny = false; + else + enum bool PredAny = Pred(A, B[0]) || PredAny(A, B[1..$]); +} + +void main() +{ + pragma(msg, PredAny!(int, long, float)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7077.d b/gcc/testsuite/gdc.test/fail_compilation/fail7077.d new file mode 100644 index 00000000000..8a3af6f9e69 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7077.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail7077.d(11): Error: undefined identifier `x` +--- +*/ + +void main() +{ + if(0) mixin("auto x = 2;"); + assert(x == 2); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7173.d b/gcc/testsuite/gdc.test/fail_compilation/fail7173.d new file mode 100644 index 00000000000..2f6c748f7c0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7173.d @@ -0,0 +1,18 @@ +struct A{ + + A opBinary(string op)(A a){ A rt; return rt; } + + void fun(){ } +} + +struct B{ + + A _a; + alias _a this; +} + + +void main(){ + + B b1, b2, b3; b3 = (b1 - b2).fun(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7178.d b/gcc/testsuite/gdc.test/fail_compilation/fail7178.d new file mode 100644 index 00000000000..04a1018d8c5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7178.d @@ -0,0 +1,6 @@ +template populate(overloads...) +{ + mixin populate!(.contents); +} +public mixin populate!int; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail72.d b/gcc/testsuite/gdc.test/fail_compilation/fail72.d new file mode 100644 index 00000000000..e6d8b8d7f70 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail72.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail72.d(10): Error: undefined identifier `foo` +--- +*/ + +void main() +{ + synchronized( foo ) + { + + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7234.d b/gcc/testsuite/gdc.test/fail_compilation/fail7234.d new file mode 100644 index 00000000000..e8ddd4e438c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7234.d @@ -0,0 +1,10 @@ + +struct Contract { + void opDispatch()(){} +} + +void foo() +{ + Contract* r; if (r.empty) {} +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail73.d b/gcc/testsuite/gdc.test/fail_compilation/fail73.d new file mode 100644 index 00000000000..dc83e5d3228 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail73.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail73.d(20): Error: case not in switch statement +--- +*/ + +// segfault DMD 0.120 +// http://www.digitalmars.com/d/archives/digitalmars/D/bugs/4634.html + +void main() +{ + int u=2; + + switch(u) + { + case 1: + void j() + { + case 2: + u++; + } + break; + + default: + break; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7369.d b/gcc/testsuite/gdc.test/fail_compilation/fail7369.d new file mode 100644 index 00000000000..b54757d96e3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7369.d @@ -0,0 +1,5 @@ +struct S7369 { + int a; + invariant() { a += 5; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail74.d b/gcc/testsuite/gdc.test/fail_compilation/fail74.d new file mode 100644 index 00000000000..c038b20a5c1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail74.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail74.d(13): Error: cannot append type C[1] to type C[1] +--- +*/ + +class C +{ + C[1] c; + this() + { + c ~= c; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424b.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424b.d new file mode 100644 index 00000000000..d358b60c7db --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424b.d @@ -0,0 +1,5 @@ +struct S7424b +{ + @property int g()() { return 0; } + void test() const { int f = g; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424c.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424c.d new file mode 100644 index 00000000000..c0671786ce5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424c.d @@ -0,0 +1,6 @@ +struct S7424c +{ + @property int g()() { return 0; } + void test() immutable { int f = g; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d new file mode 100644 index 00000000000..a981be6a39c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d @@ -0,0 +1,6 @@ +struct S7424d +{ + @property int g()() immutable { return 0; } + void test() const { int f = g; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d new file mode 100644 index 00000000000..4dfda623e3b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d @@ -0,0 +1,6 @@ +struct S7424e +{ + @property int g()() immutable { return 0; } + void test() { int f = g; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d new file mode 100644 index 00000000000..e72a05b5649 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d @@ -0,0 +1,6 @@ +struct S7424f +{ + @property int g()() shared { return 0; } + void test() { int f = g; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424g.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424g.d new file mode 100644 index 00000000000..059f586a480 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424g.d @@ -0,0 +1,6 @@ +struct S7424g +{ + @property int g()() { return 0; } + void test() shared { int f = g; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424h.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424h.d new file mode 100644 index 00000000000..fd22b2efde0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424h.d @@ -0,0 +1,6 @@ +struct S7424g +{ + @property int g()() { return 0; } + void test() inout { int f = g; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d new file mode 100644 index 00000000000..2871e932140 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d @@ -0,0 +1,6 @@ +struct S7424g +{ + @property int g()() immutable { return 0; } + void test() inout { int f = g; } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail75.d b/gcc/testsuite/gdc.test/fail_compilation/fail75.d new file mode 100644 index 00000000000..1059e36bd62 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail75.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail75.d(13): Error: cannot append type fail75.C to type C[1] +--- +*/ + +class C +{ + C[1] c; + this() + { + c ~= this; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7524a.d b/gcc/testsuite/gdc.test/fail_compilation/fail7524a.d new file mode 100644 index 00000000000..6f1ebefb27f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7524a.d @@ -0,0 +1,4 @@ + +// 7524 + +#line 47 __DATE__ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7524b.d b/gcc/testsuite/gdc.test/fail_compilation/fail7524b.d new file mode 100644 index 00000000000..042baf5d1d6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7524b.d @@ -0,0 +1,3 @@ +// 7524 + +#line 47 __VERSION__ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail76.d b/gcc/testsuite/gdc.test/fail_compilation/fail76.d new file mode 100644 index 00000000000..c2b7e59064f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail76.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail76.d(9): Error: alias fail76.a conflicts with alias fail76.a at fail_compilation/fail76.d(8) +--- +*/ + +alias main a; +alias void a; + +void main() +{ + a; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d new file mode 100644 index 00000000000..e1d28eaf742 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d @@ -0,0 +1 @@ +void test(ref bool val = true) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d new file mode 100644 index 00000000000..5317072296e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d @@ -0,0 +1 @@ +void test(out bool val = true) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d new file mode 100644 index 00000000000..f5f6e18caf2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d @@ -0,0 +1,2 @@ +enum x = 3; +void test(ref int val = x) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail77.d b/gcc/testsuite/gdc.test/fail_compilation/fail77.d new file mode 100644 index 00000000000..79ada7063ea --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail77.d @@ -0,0 +1,8 @@ +void test() +{ + int i; + ubyte[4] ub; + ub[] = cast(ubyte[4]) &i; + //ub[] = (cast(ubyte*) &i)[0..4]; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7702.d b/gcc/testsuite/gdc.test/fail_compilation/fail7702.d new file mode 100644 index 00000000000..8b7ae21cb89 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7702.d @@ -0,0 +1,9 @@ +struct S +{ + template opDispatch (string name) {} +} +void main() +{ + S s; + s.x!int; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7751.d b/gcc/testsuite/gdc.test/fail_compilation/fail7751.d new file mode 100644 index 00000000000..e367d0e3b37 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7751.d @@ -0,0 +1,17 @@ +class Foo(T) +{ + T x; + Foo y; +} +auto foo(T)(T x, Foo!T y=null) +{ + return new Foo!T(x, y); +} +void bar(U)(U foo, U[] spam=[]) +{ + spam ~= []; +} +void main() +{ + bar(foo(0)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail78.d b/gcc/testsuite/gdc.test/fail_compilation/fail78.d new file mode 100644 index 00000000000..1fb24248a5b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail78.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail78.d(9): Error: undefined identifier `inch` +--- +*/ + +auto yd = ft * 3; +auto ft = inch * 12; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7815.d b/gcc/testsuite/gdc.test/fail_compilation/fail7815.d new file mode 100644 index 00000000000..ceb5923edb6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7815.d @@ -0,0 +1,65 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +X: tuple("x") +fail_compilation/fail7815.d(47): Error: no property 'flags' for type 'Move' +--- +*/ + +mixin template Helpers() +{ + static if (is(Flags!Move)) + { + Flags!Move flags; + } + else + { + pragma(msg, "X: ", __traits(derivedMembers, Flags!Move)); + } +} + +template Flags(T) +{ + mixin({ + int defs = 1; + foreach (name; __traits(derivedMembers, Move)) + { + defs++; + } + if (defs) + { + return "struct Flags { bool x; }"; + } + else + { + return ""; + } + }()); +} + +struct Move +{ + int a; + mixin Helpers!(); +} + +enum a7815 = Move.init.flags; + +/+ +This is an invalid case. +When the Move struct member is analyzed: +1. mixin Helpers!() is instantiated. +2. In Helpers!(), static if and its condition is(Flags!Move)) evaluated. +3. In Flags!Move, string mixin evaluates and CTFE lambda. +4. __traits(derivedMembers, Move) tries to see the member of Move. + 4a. mixin Helpers!() member is analyzed. + 4b. `static if (is(Flags!Move))` in Helpers!() is evaluated + 4c. The Flags!Move instantiation is already in progress, so it cannot be resolved. + 4d. `static if` fails because Flags!Move cannot be determined as a type. +5. __traits(derivedMembers, Move) returns a 1-length tuple("a"). +6. The lambda in Flags!Move returns a string "struct Flags {...}", then + Flags!Move is instantiated to a new struct Flags. +7. Finally Move struct does not have flags member, then the `enum a7815` + definition will fail in its initializer. ++/ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d new file mode 100644 index 00000000000..77fcdfa3501 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d @@ -0,0 +1,53 @@ +// REQUIRED_ARGS: -unittest + +/* +TEST_OUTPUT: +--- +fail_compilation/fail7848.d(35): Error: pure function 'fail7848.C.__unittestL33_$n$' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(35): Error: @safe function 'fail7848.C.__unittestL33_$n$' cannot call @system function 'fail7848.func' +fail_compilation/fail7848.d(35): Error: @nogc function 'fail7848.C.__unittestL33_$n$' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(35): Error: function `fail7848.func` is not nothrow +fail_compilation/fail7848.d(33): Error: nothrow function `fail7848.C.__unittestL33_$n$` may throw +fail_compilation/fail7848.d(40): Error: pure function 'fail7848.C.__invariant2' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(40): Error: @safe function 'fail7848.C.__invariant2' cannot call @system function 'fail7848.func' +fail_compilation/fail7848.d(40): Error: @nogc function 'fail7848.C.__invariant2' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(40): Error: function `fail7848.func` is not nothrow +fail_compilation/fail7848.d(38): Error: nothrow function `fail7848.C.__invariant2` may throw +fail_compilation/fail7848.d(45): Error: pure allocator 'fail7848.C.new' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(45): Error: @safe allocator 'fail7848.C.new' cannot call @system function 'fail7848.func' +fail_compilation/fail7848.d(45): Error: @nogc allocator 'fail7848.C.new' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(45): Error: function `fail7848.func` is not nothrow +fail_compilation/fail7848.d(43): Error: nothrow allocator `fail7848.C.new` may throw +fail_compilation/fail7848.d(51): Error: pure deallocator 'fail7848.C.delete' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(51): Error: @safe deallocator 'fail7848.C.delete' cannot call @system function 'fail7848.func' +fail_compilation/fail7848.d(51): Error: @nogc deallocator 'fail7848.C.delete' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(51): Error: function `fail7848.func` is not nothrow +fail_compilation/fail7848.d(49): Error: nothrow deallocator `fail7848.C.delete` may throw +--- +*/ + +void func() {} + +class C +{ + @safe pure nothrow @nogc unittest + { + func(); + } + + @safe pure nothrow @nogc invariant + { + func(); + } + + @safe pure nothrow @nogc new (size_t sz) + { + func(); + return null; + } + + @safe pure nothrow @nogc delete (void* p) + { + func(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7851.d b/gcc/testsuite/gdc.test/fail_compilation/fail7851.d new file mode 100644 index 00000000000..7ede41f3728 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7851.d @@ -0,0 +1,33 @@ +// 7851 + + +template TypeTuple(TList...) +{ + alias TList TypeTuple; +} + +struct Tuple(Specs...) +{ + TypeTuple!(int, long, float) mem; + + alias Identity!(mem[0]) _0; + alias Identity!(mem[1]) _1; + alias Identity!(mem[2]) _2; + + alias mem this; + + enum length = mem.length; +} + +private template Identity(alias T) +{ + alias T Identity; +} + + +void main() { + alias Tuple!(int, long, float) TL; + foreach (i; TL) + { } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7859.d b/gcc/testsuite/gdc.test/fail_compilation/fail7859.d new file mode 100644 index 00000000000..436d3a363b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7859.d @@ -0,0 +1,8 @@ +template A(alias B) {} + +mixin template C(alias B = cast(NonExistent)null) { + alias A!B D; +} + +mixin C!(); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7861.d b/gcc/testsuite/gdc.test/fail_compilation/fail7861.d new file mode 100644 index 00000000000..ce59e8edee2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7861.d @@ -0,0 +1,12 @@ +module test; + +mixin template A() { +import test; +} + +struct B { +mixin A!(); +} + +enum C = B.nonexistent; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7862.d b/gcc/testsuite/gdc.test/fail_compilation/fail7862.d new file mode 100644 index 00000000000..a81bc650b85 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7862.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +A: false +A: false +fail_compilation/fail7862.d(26): Error: template instance nonExistent!() template 'nonExistent' is not defined +fail_compilation/fail7862.d(25): Error: template instance fail7862.B!(A) error instantiating +--- +*/ + +// 7862 + +template B(T) { + mixin( + { + foreach (name; __traits(derivedMembers, T)) {} + return "struct B {}"; + }() + ); +} + +struct A { + pragma(msg, "A: " ~ (__traits(compiles, B!A) ? "true" : "false")); + pragma(msg, "A: " ~ (__traits(compiles, B!A) ? "true" : "false")); + B!A c; + static if (nonExistent!()) {} +} + +auto d = A.init.c; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7886.d b/gcc/testsuite/gdc.test/fail_compilation/fail7886.d new file mode 100644 index 00000000000..b939aad1495 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7886.d @@ -0,0 +1,5 @@ +// 7886 + +struct A { + static if (__traits(derivedMembers, A).length) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail79.d b/gcc/testsuite/gdc.test/fail_compilation/fail79.d new file mode 100644 index 00000000000..46581d9d43c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail79.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail79.d(13): Error: incompatible types for ((& a) + (& b)): 'int*' and 'int*' +--- +*/ + +void main() +{ + int a, b; + int* p; + + p = &a + &b; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7903.d b/gcc/testsuite/gdc.test/fail_compilation/fail7903.d new file mode 100644 index 00000000000..7759f1ada17 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7903.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail7903.d(21): Error: variable fail7903.F1.x Field members of a synchronized class cannot be public +fail_compilation/fail7903.d(22): Error: variable fail7903.F1.y Field members of a synchronized class cannot be export +fail_compilation/fail7903.d(27): Error: variable fail7903.F2.x Field members of a synchronized class cannot be public +--- +*/ +synchronized class K1 +{ + public struct S { } +} + +synchronized class K2 +{ + struct S { } +} + +synchronized class F1 +{ + public int x; + export int y; +} + +synchronized class F2 +{ + int x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d new file mode 100644 index 00000000000..1af7e2c279b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d @@ -0,0 +1,3 @@ +void filter(R)(scope bool delegate(ref BAD!R) func) { } +void main() { filter(r => r); } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8032.d b/gcc/testsuite/gdc.test/fail_compilation/fail8032.d new file mode 100644 index 00000000000..a328181c20a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8032.d @@ -0,0 +1,17 @@ +mixin template T() +{ + void f() { } +} + +class A { + mixin T; + mixin T; +} + +class B : A +{ + override void f() { } + // raises "cannot determine overridden function" error. +} + +void main(){} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d new file mode 100644 index 00000000000..fb2f6fa2b90 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d @@ -0,0 +1,31 @@ +// REQUIRED_ARGS: -m32 +/* +TEST_OUTPUT: +--- +fail_compilation/fail80_m32.d(28): Error: cannot implicitly convert expression `"progress_rem"` of type `string` to `uint` +fail_compilation/fail80_m32.d(29): Error: cannot implicitly convert expression `"redo"` of type `string` to `uint` +--- +*/ + +module paintshop; + +class Image{} + +class ResourceManager +{ + Image getImage(char[] name) { return null; } +} + +class Test +{ + import std.file; + import std.path; + + static Image[] images; + + static void initIcons() + { + images["progress_rem"] = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis + images["redo"] = ResourceManager.getImage("redo.gif"); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d new file mode 100644 index 00000000000..52d23d305fb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d @@ -0,0 +1,31 @@ +// REQUIRED_ARGS: -m64 +/* +TEST_OUTPUT: +--- +fail_compilation/fail80_m64.d(28): Error: cannot implicitly convert expression `"progress_rem"` of type `string` to `ulong` +fail_compilation/fail80_m64.d(29): Error: cannot implicitly convert expression `"redo"` of type `string` to `ulong` +--- +*/ + +module paintshop; + +class Image{} + +class ResourceManager +{ + Image getImage(char[] name) { return null; } +} + +class Test +{ + import std.file; + import std.path; + + static Image[] images; + + static void initIcons() + { + images["progress_rem"] = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis + images["redo"] = ResourceManager.getImage("redo.gif"); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8168.d b/gcc/testsuite/gdc.test/fail_compilation/fail8168.d new file mode 100644 index 00000000000..ed1c307d4bc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8168.d @@ -0,0 +1,6 @@ +void main() { + asm { + unknown; // wrong opcode + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8179b.d b/gcc/testsuite/gdc.test/fail_compilation/fail8179b.d new file mode 100644 index 00000000000..59fd2313894 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8179b.d @@ -0,0 +1,12 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail8179b.d(10): Error: cannot cast expression `[1, 2]` of type `int[]` to `int[2][1]` +--- +*/ +void foo(int[2][1]) {} +void main() { + foo(cast(int[2][1])[1, 2]); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8217.d b/gcc/testsuite/gdc.test/fail_compilation/fail8217.d new file mode 100644 index 00000000000..e74b7c35f2f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8217.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail8217.d(22): Error: this for foo needs to be type D not type fail8217.D.C +--- +*/ + +class D +{ + int x; + template bar() + { + int foo() + { + return x; + } + } + static class C + { + int foo() + { + return bar!().foo(); + } + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8313.d b/gcc/testsuite/gdc.test/fail_compilation/fail8313.d new file mode 100644 index 00000000000..9dec1bdb289 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8313.d @@ -0,0 +1,3 @@ +auto bar()(int x){return x;} +auto bar()(int x = bar()){return x;} +static assert(bar(1)); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8373.d b/gcc/testsuite/gdc.test/fail_compilation/fail8373.d new file mode 100644 index 00000000000..d9217078bd6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8373.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail8373.d(21): Error: fail8373.fun1 called with argument types (int) matches both: +fail_compilation/fail8373.d(15): fail8373.fun1!().fun1!int.fun1(int) +and: +fail_compilation/fail8373.d(16): fail8373.fun1!int.fun1(int) +fail_compilation/fail8373.d(22): Error: fail8373.fun2 called with argument types (int) matches both: +fail_compilation/fail8373.d(18): fail8373.fun2!int.fun2(int) +and: +fail_compilation/fail8373.d(19): fail8373.fun2!().fun2!int.fun2(int) +--- +*/ + +template fun1(a...) { auto fun1(T...)(T args){ return 1; } } + auto fun1(T...)(T args){ return 2; } + + auto fun2(T...)(T args){ return 2; } +template fun2(a...) { auto fun2(T...)(T args){ return 1; } } + +enum x1 = fun1(0); +enum x2 = fun2(0); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail86.d b/gcc/testsuite/gdc.test/fail_compilation/fail86.d new file mode 100644 index 00000000000..a0ccb7c2718 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail86.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail86.d(12): Error: alias Foo recursive alias declaration +--- +*/ + +template Foo(TYPE) {} + +void main() +{ + alias Foo!(int) Foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8631.d b/gcc/testsuite/gdc.test/fail_compilation/fail8631.d new file mode 100644 index 00000000000..3aada74c42a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8631.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail8631.d(14): Error: function fail8631.D.foo does not override any function, did you mean to override 'fail8631.B.foo'? +--- +*/ + +class B { + int foo() immutable { return 2; } + int foo() const { return 2; } +} +class D : B { + override int foo() immutable { return 2; } + override int foo() const shared { return 2; } // doesn't override any + override int foo() const { return 2; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8691.d b/gcc/testsuite/gdc.test/fail_compilation/fail8691.d new file mode 100644 index 00000000000..e1979bb2ce8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8691.d @@ -0,0 +1,4 @@ +struct Foo +{ + Foo[1] f; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8724.d b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d new file mode 100644 index 00000000000..7f9cba2bc4a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -w +/* +TEST_OUTPUT: +--- +fail_compilation/fail8724.d(14): Error: `object.Exception` is thrown but not caught +fail_compilation/fail8724.d(12): Error: nothrow constructor `fail8724.Foo.this` may throw +--- +*/ + +struct Foo +{ + this(int) nothrow + { + throw new Exception("something"); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9.d b/gcc/testsuite/gdc.test/fail_compilation/fail9.d new file mode 100644 index 00000000000..6253774c823 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9.d(23): Error: no property 'Vector' for type 'fail9.Vector!int' +--- +*/ + +template Vector(T) +{ + int x; + + class Vector + { + } +} + +struct Sorter +{ +} + +void Vector_test_int() +{ + alias Vector!(int).Vector vector_t; + vector_t v; + Sorter sorter; + v.sort_with!(int)(sorter); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9063.d b/gcc/testsuite/gdc.test/fail_compilation/fail9063.d new file mode 100644 index 00000000000..962fb04ab2a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9063.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9063.d(9): Error: static assert "msg" +--- +*/ + +@property string bar() { return "msg"; } +static assert(false, bar); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9081.d b/gcc/testsuite/gdc.test/fail_compilation/fail9081.d new file mode 100644 index 00000000000..86c888742ce --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9081.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9081.d(12): Error: package core has no type +fail_compilation/fail9081.d(13): Error: package stdc has no type +fail_compilation/fail9081.d(14): Error: module stdio has no type +--- +*/ + +import core.stdc.stdio; + +typeof(core) a; +typeof(core.stdc) b; +typeof(core.stdc.stdio) c; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail91.d b/gcc/testsuite/gdc.test/fail_compilation/fail91.d new file mode 100644 index 00000000000..59f80fd891d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail91.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail91.d(12): Error: struct fail91.S unknown size +--- +*/ + +struct S; + +void main() +{ + S* s = new S(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9199.d b/gcc/testsuite/gdc.test/fail_compilation/fail9199.d new file mode 100644 index 00000000000..00a87c39907 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9199.d @@ -0,0 +1,40 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/fail9199.d(13): Error: function fail9199.fc without 'this' cannot be const +fail_compilation/fail9199.d(14): Error: function fail9199.fi without 'this' cannot be immutable +fail_compilation/fail9199.d(15): Error: function fail9199.fw without 'this' cannot be inout +fail_compilation/fail9199.d(16): Error: function fail9199.fs without 'this' cannot be shared +fail_compilation/fail9199.d(17): Error: function fail9199.fsc without 'this' cannot be shared const +fail_compilation/fail9199.d(18): Error: function fail9199.fsw without 'this' cannot be shared inout +--- +*/ +void fc() const {} +void fi() immutable {} +void fw() inout {} +void fs() shared {} +void fsc() shared const {} +void fsw() shared inout {} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail9199.d(33): Error: function fail9199.C.fc without 'this' cannot be const +fail_compilation/fail9199.d(34): Error: function fail9199.C.fi without 'this' cannot be immutable +fail_compilation/fail9199.d(35): Error: function fail9199.C.fw without 'this' cannot be inout +fail_compilation/fail9199.d(36): Error: function fail9199.C.fs without 'this' cannot be shared +fail_compilation/fail9199.d(37): Error: function fail9199.C.fsc without 'this' cannot be shared const +fail_compilation/fail9199.d(38): Error: function fail9199.C.fsw without 'this' cannot be shared inout +--- +*/ +class C +{ + static void fc() const {} + static void fi() immutable {} + static void fw() inout {} + static void fs() shared {} + static void fsc() shared const {} + static void fsw() shared inout {} +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail92.d b/gcc/testsuite/gdc.test/fail_compilation/fail92.d new file mode 100644 index 00000000000..8fa69bb4a2c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail92.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail92.d(15): Error: invalid foreach aggregate `t` +fail_compilation/fail92.d(23): Error: template instance fail92.crash!(typeof(null)) error instantiating +--- +*/ + +// [25] + +template crash(T) +{ + void crash(T t) + { + foreach (u; t) + { + } + } +} + +void main() +{ + crash(null); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9279.d b/gcc/testsuite/gdc.test/fail_compilation/fail9279.d new file mode 100644 index 00000000000..102cd05370f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9279.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9279.d(10): Error: escaping reference to stack allocated value returned by `b()` +fail_compilation/fail9279.d(13): Error: escaping reference to stack allocated value returned by `getArr()` +--- +*/ + +char[2] b()() { char[2] ret; return ret; } +string a() { return b(); } + +char[12] getArr() { return "Hello World!"; } +string getString() { return getArr(); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail93.d b/gcc/testsuite/gdc.test/fail_compilation/fail93.d new file mode 100644 index 00000000000..4784038e0c4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail93.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail93.d(13): Error: variable i is shadowing variable fail93.main.i +--- +*/ + +// accepts-valid with DMD0.120. volatile as well as synchronized + +void main() +{ + int i = 1; + synchronized int i = 2; // should fail to compile +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9301.d b/gcc/testsuite/gdc.test/fail_compilation/fail9301.d new file mode 100644 index 00000000000..bd7e95283f4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9301.d @@ -0,0 +1,9 @@ +/* +REQUIRED_ARGS: -o- +PERMUTE_ARGS: +*/ + +void main() +{ + __vector(void[16]) x = 0x0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9346.d b/gcc/testsuite/gdc.test/fail_compilation/fail9346.d new file mode 100644 index 00000000000..d3c7a593db2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9346.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9346.d(26): Error: struct fail9346.S is not copyable because it is annotated with @disable +fail_compilation/fail9346.d(27): Error: struct fail9346.S is not copyable because it is annotated with @disable +--- +*/ + +struct S +{ + @disable this(this); +} +struct SS1 +{ + S s; +} +struct SS2 +{ + S s; + this(this){} +} + +void main() +{ + S s; + SS1 ss1 = SS1(s); + SS2 ss2 = SS2(s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9368.d b/gcc/testsuite/gdc.test/fail_compilation/fail9368.d new file mode 100644 index 00000000000..25e13600ddb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9368.d @@ -0,0 +1,49 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -d +/* +TEST_OUTPUT: +--- +fail_compilation/fail9368.d(20): Error: enum member `b` not represented in final switch +--- +*/ + +enum E +{ + a, + b +} + +void main() +{ + alias E F; + F f; + final switch (f) + { + case F.a: + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail9368.d(41): Error: enum member `B` not represented in final switch +--- +*/ + +enum G +{ + A,B,C +} + +void test286() +{ + G e; + final switch (e) + { + case G.A: +// case G.B: + case G.C: + {} + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail94.d b/gcc/testsuite/gdc.test/fail_compilation/fail94.d new file mode 100644 index 00000000000..23fef9357cb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail94.d @@ -0,0 +1,56 @@ +interface I +{ + int foo(); +} + +class IA : I +{ + int foo() { return 1; } +} + +class A +{ + I i; + + I clone() { return i; } +} + +class B : A +{ + IA ia; + + IA clone() + out (result) + { + printf("B.clone()\n"); + } + body { return ia; } +} + +void main() +{ + IA ia = new IA; + assert(ia.foo() == 1); + + I i = ia; + assert(i.foo() == 1); + + A a = new A; + a.i = i; + assert(a.clone().foo() == 1); + + B b = new B; + b.ia = ia; + assert(b.clone().foo() == 1); + + a = b; + assert(a.clone().foo() == 1); + + bar(&b.clone); +} + + +void bar(IA delegate() dg) +{ +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9413.d b/gcc/testsuite/gdc.test/fail_compilation/fail9413.d new file mode 100644 index 00000000000..617c9950409 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9413.d @@ -0,0 +1,85 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9413.d(45): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(32): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(33): Error: variable fail9413.foo.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9413.d(38): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(39): Error: variable fail9413.foo.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9413.d(40): Error: variable fail9413.foo.bar.s cannot modify result 's' in contract +fail_compilation/fail9413.d(50): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(73): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(74): Error: variable fail9413.foo.r cannot modify result 'r' in contract +fail_compilation/fail9413.d(58): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(59): Error: variable fail9413.foo.r cannot modify result 'r' in contract +fail_compilation/fail9413.d(60): Error: variable fail9413.foo.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9413.d(65): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(66): Error: variable fail9413.foo.r cannot modify result 'r' in contract +fail_compilation/fail9413.d(67): Error: variable fail9413.foo.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9413.d(68): Error: variable fail9413.foo.baz.s cannot modify result 's' in contract +fail_compilation/fail9413.d(79): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9413.d(80): Error: variable fail9413.foo.r cannot modify result 'r' in contract +--- +*/ + +int foo(int x) +in +{ + int a; + int bar(int y) + in + { + x = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err +} +out(r) +{ + int a; + int baz(int y) + in + { + x = 10; // err + r = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + r = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + r = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + r = 10; // err +} +body +{ + return 1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414a.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414a.d new file mode 100644 index 00000000000..4fd98d3cc55 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414a.d @@ -0,0 +1,88 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9414a.d(47): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(34): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(35): Error: variable fail9414a.C.foo.__require.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414a.d(40): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(41): Error: variable fail9414a.C.foo.__require.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414a.d(42): Error: variable fail9414a.C.foo.__require.bar.s cannot modify result 's' in contract +fail_compilation/fail9414a.d(52): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(75): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(76): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract +fail_compilation/fail9414a.d(60): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(61): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract +fail_compilation/fail9414a.d(62): Error: variable fail9414a.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414a.d(67): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(68): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract +fail_compilation/fail9414a.d(69): Error: variable fail9414a.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414a.d(70): Error: variable fail9414a.C.foo.__ensure.baz.s cannot modify result 's' in contract +fail_compilation/fail9414a.d(81): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414a.d(82): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract +--- +*/ + +class C +{ + int foo(int x) + in + { + int a; + int bar(int y) + in + { + x = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + } + out(r) + { + int a; + int baz(int y) + in + { + x = 10; // err + r = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + r = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + r = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + r = 10; // err + } + body + { + return 1; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414b.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414b.d new file mode 100644 index 00000000000..37bd12fc429 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414b.d @@ -0,0 +1,88 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9414b.d(47): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(34): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(35): Error: variable fail9414b.C.foo.__require.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414b.d(40): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(41): Error: variable fail9414b.C.foo.__require.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414b.d(42): Error: variable fail9414b.C.foo.__require.bar.s cannot modify result 's' in contract +fail_compilation/fail9414b.d(52): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(75): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(76): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract +fail_compilation/fail9414b.d(60): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(61): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract +fail_compilation/fail9414b.d(62): Error: variable fail9414b.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414b.d(67): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(68): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract +fail_compilation/fail9414b.d(69): Error: variable fail9414b.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414b.d(70): Error: variable fail9414b.C.foo.__ensure.baz.s cannot modify result 's' in contract +fail_compilation/fail9414b.d(81): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414b.d(82): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract +--- +*/ + +class C +{ + final int foo(int x) + in + { + int a; + int bar(int y) + in + { + x = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + } + out(r) + { + int a; + int baz(int y) + in + { + x = 10; // err + r = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + r = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + r = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + r = 10; // err + } + body + { + return 1; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414c.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414c.d new file mode 100644 index 00000000000..efbff9c42f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414c.d @@ -0,0 +1,88 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9414c.d(47): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(34): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(35): Error: variable fail9414c.C.foo.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414c.d(40): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(41): Error: variable fail9414c.C.foo.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414c.d(42): Error: variable fail9414c.C.foo.bar.s cannot modify result 's' in contract +fail_compilation/fail9414c.d(52): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(75): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(76): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract +fail_compilation/fail9414c.d(60): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(61): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract +fail_compilation/fail9414c.d(62): Error: variable fail9414c.C.foo.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414c.d(67): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(68): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract +fail_compilation/fail9414c.d(69): Error: variable fail9414c.C.foo.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414c.d(70): Error: variable fail9414c.C.foo.baz.s cannot modify result 's' in contract +fail_compilation/fail9414c.d(81): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414c.d(82): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract +--- +*/ + +class C +{ + private int foo(int x) + in + { + int a; + int bar(int y) + in + { + x = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + } + out(r) + { + int a; + int baz(int y) + in + { + x = 10; // err + r = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + r = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + r = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + r = 10; // err + } + body + { + return 1; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414d.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414d.d new file mode 100644 index 00000000000..60b588678f6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414d.d @@ -0,0 +1,88 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9414d.d(47): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(34): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(35): Error: variable fail9414d.C.foo.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414d.d(40): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(41): Error: variable fail9414d.C.foo.bar.y cannot modify parameter 'y' in contract +fail_compilation/fail9414d.d(42): Error: variable fail9414d.C.foo.bar.s cannot modify result 's' in contract +fail_compilation/fail9414d.d(52): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(75): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(76): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract +fail_compilation/fail9414d.d(60): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(61): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract +fail_compilation/fail9414d.d(62): Error: variable fail9414d.C.foo.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414d.d(67): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(68): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract +fail_compilation/fail9414d.d(69): Error: variable fail9414d.C.foo.baz.y cannot modify parameter 'y' in contract +fail_compilation/fail9414d.d(70): Error: variable fail9414d.C.foo.baz.s cannot modify result 's' in contract +fail_compilation/fail9414d.d(81): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract +fail_compilation/fail9414d.d(82): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract +--- +*/ + +class C +{ + static int foo(int x) + in + { + int a; + int bar(int y) + in + { + x = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + } + out(r) + { + int a; + int baz(int y) + in + { + x = 10; // err + r = 10; // err + y = 10; // err + a = 1; // OK + } + out(s) + { + x = 10; // err + r = 10; // err + y = 10; // err + s = 10; // err + a = 1; // OK + } + body + { + x = 10; // err + r = 10; // err + y = 1; // OK + a = 1; // OK + return 2; + } + x = 10; // err + r = 10; // err + } + body + { + return 1; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail95.d b/gcc/testsuite/gdc.test/fail_compilation/fail95.d new file mode 100644 index 00000000000..439e55d8b1f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail95.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail95.d(19): Error: template fail95.A cannot deduce function from argument types !()(int), candidates are: +fail_compilation/fail95.d(11): fail95.A(alias T)(T) +--- +*/ + +// Issue 142 - Assertion failure: '0' on line 610 in file 'template.c' + +template A(alias T) +{ + void A(T) { T = 2; } +} + +void main() +{ + int i; + A(i); + assert(i == 2); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9537.d b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d new file mode 100644 index 00000000000..bf6e4db60b6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9537.d(26): Error: foo(tuple(1, 2)) is not an lvalue +--- +*/ + +struct Tuple(T...) +{ + T field; + alias field this; +} + +Tuple!T tuple(T...)(T args) +{ + return Tuple!T(args); +} + +auto ref foo(T)(auto ref T t) +{ + return t[0]; // t[0] is deduced to non-ref +} + +void main() +{ + int* p = &foo(tuple(1, 2)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9562.d b/gcc/testsuite/gdc.test/fail_compilation/fail9562.d new file mode 100644 index 00000000000..46aafee6094 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9562.d @@ -0,0 +1,22 @@ +/* +REQUIRED_ARGS: -o- +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/fail9562.d(17): Error: int[] is not an expression +fail_compilation/fail9562.d(18): Error: no property 'reverse' for type 'int[]' +fail_compilation/fail9562.d(19): Error: no property 'sort' for type 'int[]' +fail_compilation/fail9562.d(20): Error: no property 'dup' for type 'int[]' +fail_compilation/fail9562.d(21): Error: no property 'idup' for type 'int[]' +--- +*/ + +void main() +{ + alias A = int[]; + auto len = A.length; + auto rev = A.reverse; + auto sort = A.sort; + auto dup = A.dup; + auto idup = A.idup; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9572.d b/gcc/testsuite/gdc.test/fail_compilation/fail9572.d new file mode 100644 index 00000000000..75b42349916 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9572.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9572.d(10): Error: index type `ubyte` cannot cover index range 0..300 +--- +*/ + +void main() { + int[300] data; + foreach (ubyte i, x; data) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail96.d b/gcc/testsuite/gdc.test/fail_compilation/fail96.d new file mode 100644 index 00000000000..1bdc8417b6f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail96.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail96.d(21): Error: template instance foo!long foo is not a template declaration, it is a function alias +--- +*/ + +// 153 + +template bar(T) +{ + void foo() {} +} + +alias bar!(long).foo foo; +alias bar!(char).foo foo; + + +void main() +{ + foo!(long); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9613.d b/gcc/testsuite/gdc.test/fail_compilation/fail9613.d new file mode 100644 index 00000000000..18a18cc3d85 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9613.d @@ -0,0 +1,6 @@ +// PREMUTE_ARGS: + +void main() +{ + auto x = const byte.init; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9665a.d b/gcc/testsuite/gdc.test/fail_compilation/fail9665a.d new file mode 100644 index 00000000000..64602f875c2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9665a.d @@ -0,0 +1,166 @@ +// REQUIRED_ARGS: +// PERMUTE_ARGS: + +/***************************************************/ +// immutable field + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665a.d(19): Error: immutable field 'v' initialized multiple times +--- ++/ +struct S1A +{ + immutable int v; + this(int) + { + v = 1; + v = 2; // multiple initialization + } +} + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665a.d(37): Error: immutable field 'v' initialized multiple times +fail_compilation/fail9665a.d(42): Error: immutable field 'v' initialized multiple times +fail_compilation/fail9665a.d(47): Error: immutable field 'v' initialized multiple times +--- ++/ +struct S1B +{ + immutable int v; + this(int) + { + if (true) v = 1; else v = 2; + v = 3; // multiple initialization + } + this(long) + { + if (true) v = 1; + v = 3; // multiple initialization + } + this(string) + { + if (true) {} else v = 2; + v = 3; // multiple initialization + } +} + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665a.d(65): Error: immutable field 'v' initialized multiple times +fail_compilation/fail9665a.d(70): Error: immutable field 'v' initialized multiple times +fail_compilation/fail9665a.d(75): Error: immutable field 'v' initialized multiple times +--- ++/ +struct S1C +{ + immutable int v; + this(int) + { + true ? (v = 1) : (v = 2); + v = 3; // multiple initialization + } + this(long) + { + auto x = true ? (v = 1) : 2; + v = 3; // multiple initialization + } + this(string) + { + auto x = true ? 1 : (v = 2); + v = 3; // multiple initialization + } +} + +/***************************************************/ +// with control flow + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665a.d(98): Error: immutable field 'v' initialization is not allowed in loops or after labels +fail_compilation/fail9665a.d(103): Error: immutable field 'v' initialization is not allowed in loops or after labels +fail_compilation/fail9665a.d(108): Error: immutable field 'v' initialized multiple times +fail_compilation/fail9665a.d(113): Error: immutable field 'v' initialized multiple times +fail_compilation/fail9665a.d(118): Error: immutable field 'v' initialized multiple times +--- ++/ +struct S2 +{ + immutable int v; + this(int) + { + L: + v = 1; // after labels + } + this(long) + { + foreach (i; 0..1) + v = 1; // in loops + } + this(string) + { + v = 1; // initialization + L: v = 2; // assignment after labels + } + this(wstring) + { + v = 1; // initialization + foreach (i; 0..1) v = 2; // assignment in loops + } + this(dstring) + { + v = 1; return; + v = 2; // multiple initialization + } +} + +/***************************************************/ +// with immutable constructor + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665a.d(139): Error: immutable field 'v' initialized multiple times +fail_compilation/fail9665a.d(143): Error: immutable field 'w' initialized multiple times +--- ++/ +struct S3 +{ + int v; + int w; + this(int) immutable + { + v = 1; + v = 2; // multiple initialization + + if (true) + w = 1; + w = 2; // multiple initialization + } +} + +/***************************************************/ +// in __traits(compiles) + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665a.d(163): Error: static assert `__traits(compiles, this.v = 1)` is false +--- ++/ +struct S4 +{ + immutable int v; + this(int) + { + static assert(__traits(compiles, v = 1)); + v = 1; + static assert(__traits(compiles, v = 1)); // multiple initialization + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9665b.d b/gcc/testsuite/gdc.test/fail_compilation/fail9665b.d new file mode 100644 index 00000000000..8f7d79c705d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9665b.d @@ -0,0 +1,77 @@ +/***************************************************/ +// with disable this() struct + +struct X +{ + @disable this(); + + this(int) {} +} + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665b.d(32): Error: one path skips field x2 +fail_compilation/fail9665b.d(33): Error: one path skips field x3 +fail_compilation/fail9665b.d(35): Error: one path skips field x5 +fail_compilation/fail9665b.d(36): Error: one path skips field x6 +fail_compilation/fail9665b.d(30): Error: field x1 must be initialized in constructor +fail_compilation/fail9665b.d(30): Error: field x4 must be initialized in constructor +--- ++/ +struct S1 +{ + X x1; + X x2; + X x3; + X[2] x4; + X[2] x5; + X[2] x6; + this(int) + { + if (true) x2 = X(1); + auto n = true ? (x3 = X(1)) : X.init; + + if (true) x5 = X(1); + auto m = true ? (x6 = X(1)) : typeof(x6).init; + } +} + +/***************************************************/ +// with nested struct + +/+ +TEST_OUTPUT: +--- +fail_compilation/fail9665b.d(65): Error: one path skips field x2 +fail_compilation/fail9665b.d(66): Error: one path skips field x3 +fail_compilation/fail9665b.d(68): Error: one path skips field x5 +fail_compilation/fail9665b.d(69): Error: one path skips field x6 +fail_compilation/fail9665b.d(63): Error: field x1 must be initialized in constructor, because it is nested struct +fail_compilation/fail9665b.d(63): Error: field x4 must be initialized in constructor, because it is nested struct +fail_compilation/fail9665b.d(76): Error: template instance fail9665b.S2!(X) error instantiating +--- ++/ +struct S2(X) +{ + X x1; + X x2; + X x3; + X[2] x4; + X[2] x5; + X[2] x6; + this(X x) + { + if (true) x2 = x; + auto a = true ? (x3 = x) : X.init; + + if (true) x5 = x; + auto b = true ? (x6 = x) : typeof(x6).init; + } +} +void test2() +{ + struct X { this(int) {} } + static assert(X.tupleof.length == 1); + S2!(X) s = X(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail97.d b/gcc/testsuite/gdc.test/fail_compilation/fail97.d new file mode 100644 index 00000000000..33d0c5fb924 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail97.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail97.d(11): Error: pragma lib pragma is missing closing `;` +--- +*/ + +// 151 + +import std.stdio; +pragma(lib,"ws2_32.lib")//; +class bla{} +void main(){} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9710.d b/gcc/testsuite/gdc.test/fail_compilation/fail9710.d new file mode 100644 index 00000000000..98306b26cac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9710.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9710.d(9): Error: static variable e cannot be read at compile time +--- +*/ + +int* e; +enum v = e[1]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9735.d b/gcc/testsuite/gdc.test/fail_compilation/fail9735.d new file mode 100644 index 00000000000..42dbfdce30f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9735.d @@ -0,0 +1,12 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/fail9735.d(10): Deprecation: casting from void delegate() to void* is deprecated +--- +*/ + +void* dg2ptr(void delegate() dg) { + return cast(void*) dg; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9766.d b/gcc/testsuite/gdc.test/fail_compilation/fail9766.d new file mode 100644 index 00000000000..d75d1bc44e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9766.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9766.d(14): Error: cannot interpret Foo!int at compile time +fail_compilation/fail9766.d(17): Error: alignment must be an integer positive power of 2, not -1 +fail_compilation/fail9766.d(20): Error: alignment must be an integer positive power of 2, not 0 +fail_compilation/fail9766.d(23): Error: alignment must be an integer positive power of 2, not 3 +fail_compilation/fail9766.d(26): Error: alignment must be an integer positive power of 2, not 2147483649u +--- +*/ + +template Foo(T) {} + +align(Foo!int) +struct S9766a {} + +align(-1) +struct S9766b {} + +align(0) +struct S9766c {} + +align(3) +struct S9766d {} + +align((1u << 31) + 1) +struct S9766e {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9773.d b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d new file mode 100644 index 00000000000..18da406beaa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9773.d(7): Error: "" is not an lvalue +--- +*/ +void f(ref string a = "") +{ + a = "crash and burn"; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9790.d b/gcc/testsuite/gdc.test/fail_compilation/fail9790.d new file mode 100644 index 00000000000..0becddd88f4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9790.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9790.d(13): Error: undefined identifier `_Unused_` +fail_compilation/fail9790.d(20): Error: template instance fail9790.foo!() error instantiating +fail_compilation/fail9790.d(18): Error: undefined identifier `_Unused_` +fail_compilation/fail9790.d(21): Error: template instance fail9790.bar!() error instantiating +--- +*/ + +template foo() +{ + enum bool _foo = _Unused_._unused_; + enum bool foo = _foo; +} +template bar() +{ + enum bool bar = _Unused_._unused_; +} +alias Foo = foo!(); +alias Bar = bar!(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail98.d b/gcc/testsuite/gdc.test/fail_compilation/fail98.d new file mode 100644 index 00000000000..ded3624f988 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail98.d @@ -0,0 +1,36 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail98.d(17): Error: cannot implicitly convert expression `256` of type `int` to `E` +--- +*/ + +// 139 + +E foo(int index) +{ + return index + 256; +} + +enum : E +{ + D3DTS_WORLD = 256, + D3DTS_WORLD1, + D3DTS_WORLD2, + D3DTS_WORLD3 +} + +enum E +{ + D3DTS_VIEW = 2, + D3DTS_PROJECTION, + D3DTS_TEXTURE0 = 16, + D3DTS_TEXTURE1, + D3DTS_TEXTURE2, + D3DTS_TEXTURE3, + D3DTS_TEXTURE4, + D3DTS_TEXTURE5, + D3DTS_TEXTURE6, + D3DTS_TEXTURE7, // = 23 + D3DTS_FORCE_DWORD = 0xffffffff +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9891.d b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d new file mode 100644 index 00000000000..99d5f11f019 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9891.d(13): Error: cast(int)i is not an lvalue +fail_compilation/fail9891.d(18): Error: cast(int)i is not an lvalue +fail_compilation/fail9891.d(23): Error: prop() is not an lvalue +--- +*/ + +immutable int i; +int prop() { return 0; } + +void f1(ref int n = i) +{ + ++n; +} + +void f2(out int n = i) +{ + ++n; +} + +void f3(ref int n = prop) +{ + ++n; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9892.d b/gcc/testsuite/gdc.test/fail_compilation/fail9892.d new file mode 100644 index 00000000000..32eef128d20 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9892.d @@ -0,0 +1,13 @@ +// 9892 +/* +TEST_OUTPUT: +--- +fail_compilation/fail9892.d(11): Error: enum member fail9892.a circular reference to enum member +--- +*/ + +enum +{ + a = b, //Segfault! + b +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail99.d b/gcc/testsuite/gdc.test/fail_compilation/fail99.d new file mode 100644 index 00000000000..da87ed66acb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail99.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail99.d(12): Error: delegate dg (int) is not callable using argument types () +--- +*/ + +//import std.stdio; + +void foo(void delegate(int) dg) +{ + dg(); + //writefln("%s", dg(3)); +} + +void main() +{ + foo(delegate(int i) + { + //writefln("i = %d\n", i); + } + ); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9936.d b/gcc/testsuite/gdc.test/fail_compilation/fail9936.d new file mode 100644 index 00000000000..36178f48c21 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9936.d @@ -0,0 +1,31 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9936.d(25): Error: S().opBinary isn't a template +fail_compilation/fail9936.d(26): Error: S().opBinaryRight isn't a template +fail_compilation/fail9936.d(27): Error: S().opOpAssign isn't a template +fail_compilation/fail9936.d(29): Error: S().opIndexUnary isn't a template +fail_compilation/fail9936.d(30): Error: S().opUnary isn't a template +--- +*/ +struct S +{ + auto opBinary(S s) { return 1; } + auto opBinaryRight(int n) { return 1; } + auto opOpAssign(S s) { return 1; } + + auto opIndexUnary(S s) { return 1; } + auto opUnary(S s) { return 1; } +} +void main() +{ + static assert(!is(typeof( S() + S() ))); + static assert(!is(typeof( 100 + S() ))); + static assert(!is(typeof( S() += S() ))); + S() + S(); + 100 + S(); + S() += S(); + + +S()[0]; + +S(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d new file mode 100644 index 00000000000..3498df7cb06 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d @@ -0,0 +1,150 @@ +// REQUIRED_ARGS: -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop1.d(11): Error: invalid array operation `a + a` (possible missing []) +--- +*/ +void test2199(int[] a) // Issue 2199 - Segfault using array operation in function call (from fail266.d) +{ + test2199(a + a); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop1.d(29): Error: invalid array operation `-a` (possible missing []) +--- +*/ +void fail323() // from fail323.d, maybe was a part of issue 3471 fix? +{ + void foo(double[]) {} + + auto a = new double[10], + b = a.dup, + c = a.dup, + d = a.dup; + + foo(-a); + // a[] = -(b[] * (c[] + 4)) + 5 * d[]; // / 3; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop1.d(54): Error: invalid array operation `-a` (possible missing []) +fail_compilation/fail_arrayop1.d(55): Error: invalid array operation `~a` (possible missing []) +fail_compilation/fail_arrayop1.d(56): Error: invalid array operation `a + a` (possible missing []) +fail_compilation/fail_arrayop1.d(57): Error: invalid array operation `a - a` (possible missing []) +fail_compilation/fail_arrayop1.d(58): Error: invalid array operation `a * a` (possible missing []) +fail_compilation/fail_arrayop1.d(59): Error: invalid array operation `a / a` (possible missing []) +fail_compilation/fail_arrayop1.d(60): Error: invalid array operation `a % a` (possible missing []) +fail_compilation/fail_arrayop1.d(61): Error: invalid array operation `a ^^ a` (possible missing []) +fail_compilation/fail_arrayop1.d(62): Error: invalid array operation `a & a` (possible missing []) +fail_compilation/fail_arrayop1.d(63): Error: invalid array operation `a | a` (possible missing []) +fail_compilation/fail_arrayop1.d(64): Error: invalid array operation `a ^ a` (possible missing []) +--- +*/ +void test3903() +{ + int[] a = [1, 2]; + int[] r; + + r = -a; + r = ~a; + r = a + a; + r = a - a; + r = a * a; + r = a / a; + r = a % a; + r = a ^^ a; + r = a & a; + r = a | a; + r = a ^ a; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop1.d(85): Error: invalid array operation `a += a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(86): Error: invalid array operation `a -= a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(87): Error: invalid array operation `a *= a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(88): Error: invalid array operation `a /= a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(89): Error: invalid array operation `a %= a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(90): Error: invalid array operation `a ^= a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(91): Error: invalid array operation `a &= a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(92): Error: invalid array operation `a |= a[]` (possible missing []) +fail_compilation/fail_arrayop1.d(93): Error: invalid array operation `a ^^= a[]` (possible missing []) +--- +*/ +void test9459() +{ + int[] a = [1, 2, 3]; + + a += a[]; + a -= a[]; + a *= a[]; + a /= a[]; + a %= a[]; + a ^= a[]; + a &= a[]; + a |= a[]; + a ^^= a[]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop1.d(111): Error: invalid array operation `x1[] = x2[] * x3[]` because `X` doesn't support necessary arithmetic operations +fail_compilation/fail_arrayop1.d(115): Error: invalid array operation `s2[] += s1[]` because `string` is not a scalar type +fail_compilation/fail_arrayop1.d(119): Error: invalid array operation `pa1[] *= pa2[]` for element type `int*` +--- +*/ +void test11376() +{ + struct X { } + + auto x1 = [X()]; + auto x2 = [X()]; + auto x3 = [X()]; + x1[] = x2[] * x3[]; + + string[] s1; + string[] s2; + s2[] += s1[]; + + int*[] pa1; + int*[] pa2; + pa1[] *= pa2[]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop1.d(131): Error: invalid array operation `a[] <<= 1` (possible missing []) +--- +*/ +void test11566() +{ + int[] a; + a[] <<= 1; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop1.d(147): Error: invalid array operation `a + b` (possible missing []) +fail_compilation/fail_arrayop1.d(148): Error: invalid array operation `x + y` (possible missing []) +fail_compilation/fail_arrayop1.d(149): Error: invalid array operation `"hel" + "lo."` (possible missing []) +--- +*/ +void test14649() +{ + char[] a, b, r; + string x, y; + + r[] = a + b; + r[] = x + y; + r[] = "hel" + "lo."; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d new file mode 100644 index 00000000000..8f654b0ec81 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d @@ -0,0 +1,369 @@ +// REQUIRED_ARGS: -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(12): Error: array operation `[1, 2, 3] - [1, 2, 3]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(15): Error: invalid array operation `"a" - "b"` (possible missing []) +--- +*/ +void test2603() // Issue 2603 - ICE(cgcs.c) on subtracting string literals +{ + auto c1 = [1,2,3] - [1,2,3]; + + // this variation is wrong code on D2, ICE ..\ztc\cgcs.c 358 on D1. + string c2 = "a" - "b"; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(37): Error: array operation `-a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(38): Error: array operation `~a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(40): Error: array operation `a[] + a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(41): Error: array operation `a[] - a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(42): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(43): Error: array operation `a[] / a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(44): Error: array operation `a[] % a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(45): Error: array operation `a[] ^ a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(46): Error: array operation `a[] & a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(47): Error: array operation `a[] | a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(48): Error: array operation `a[] ^^ a[]` without destination memory not allowed (possible missing []) +--- +*/ +void test9459() +{ + int[] a = [1, 2, 3]; + a = -a[]; + a = ~a[]; + + a = a[] + a[]; + a = a[] - a[]; + a = a[] * a[]; + a = a[] / a[]; + a = a[] % a[]; + a = a[] ^ a[]; + a = a[] & a[]; + a = a[] | a[]; + a = a[] ^^ a[]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(74): Error: array operation `a[] + a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(75): Error: array operation `a[] - a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(76): Error: array operation `a[] * a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(77): Error: array operation `a[] / a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(78): Error: array operation `a[] % a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(79): Error: array operation `a[] ^ a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(80): Error: array operation `a[] & a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(81): Error: array operation `a[] | a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(82): Error: array operation `a[] ^^ 10` without destination memory not allowed +fail_compilation/fail_arrayop2.d(83): Error: array operation `-a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(84): Error: array operation `~a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(89): Error: array operation `[1] + a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(90): Error: array operation `[1] + a[]` without destination memory not allowed +--- +*/ +void test12179() +{ + void foo(int[]) {} + int[1] a; + + foo(a[] + a[]); + foo(a[] - a[]); + foo(a[] * a[]); + foo(a[] / a[]); + foo(a[] % a[]); + foo(a[] ^ a[]); + foo(a[] & a[]); + foo(a[] | a[]); + foo(a[] ^^ 10); + foo(-a[]); + foo(~a[]); + + // from issue 11992 + int[] arr1; + int[][] arr2; + arr1 ~= [1] + a[]; // NG + arr2 ~= [1] + a[]; // NG +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(104): Error: array operation `h * y[]` without destination memory not allowed +--- +*/ +void test12381() +{ + double[2] y; + double h; + + double[2] temp1 = cast(double[2])(h * y[]); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(117): Error: array operation `-a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(119): Error: array operation `(-a[])[0..4]` without destination memory not allowed +--- +*/ +float[] test12769(float[] a) +{ + if (a.length < 4) + return -a[]; + else + return (-a[])[0..4]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(136): Error: array operation `a[] - a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(138): Error: array operation `a[] - a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(139): Error: array operation `a[] - a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(142): Error: array operation `a[] - a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(144): Error: array operation `a[] - a[]` without destination memory not allowed +--- +*/ +void test13208() +{ + int[] a; + + auto arr = [a[] - a[]][0]; + + auto aa1 = [1 : a[] - a[]]; + auto aa2 = [a[] - a[] : 1]; + + struct S { int[] a; } + auto s = S(a[] - a[]); + + auto n = int(a[] - a[]); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(159): Error: array operation `a[] * a[]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(160): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed +fail_compilation/fail_arrayop2.d(163): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing []) +fail_compilation/fail_arrayop2.d(164): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed (possible missing []) +--- +*/ +void test13497() +{ + int[1] a; + auto b1 = (a[] * a[])[]; + auto b2 = (a[] * a[])[0..1]; + + int[] c; + c = (a[] * a[])[]; + c = (a[] * a[])[0..1]; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(180): Error: array operation `data[segmentId][28..29] & cast(ubyte)(1 << 0)` without destination memory not allowed +--- +*/ +void test13910() +{ + ubyte[][] data; + size_t segmentId; + + bool isGroup() + { + return !!((data[segmentId][28..29]) & (1 << 0)); + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(194): Error: array operation `a[] + 1` without destination memory not allowed +fail_compilation/fail_arrayop2.d(194): Error: array operation `a[] * 2` without destination memory not allowed +--- +*/ +void test14895() +{ + int[] a; + int[] b = (a[] + 1) ~ a[] * 2; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(245): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(246): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(247): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(252): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(255): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(264): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(267): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(268): Error: array operation `"abc"[] + '\x01'` without destination memory not allowed +fail_compilation/fail_arrayop2.d(271): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(274): Error: ([1] * 6)[0..2] is not an lvalue +fail_compilation/fail_arrayop2.d(277): Error: can only * a pointer, not a 'int[]' +fail_compilation/fail_arrayop2.d(280): Error: [1] * 6 is not an lvalue +fail_compilation/fail_arrayop2.d(283): Error: array operation `da[] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(286): Error: array operation `da[] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(289): Error: [1] * 6 is not an lvalue +fail_compilation/fail_arrayop2.d(290): Error: invalid array operation `[1] * 6 -= 1` for element type `int` +fail_compilation/fail_arrayop2.d(293): Error: [1] * 6 is not an lvalue +fail_compilation/fail_arrayop2.d(294): Error: ([1] * 6)[] is not an lvalue +fail_compilation/fail_arrayop2.d(297): Error: invalid array operation `[1] * 6 += 1` for element type `int` +fail_compilation/fail_arrayop2.d(298): Error: invalid array operation `[1] * 6 *= 2` for element type `int` +fail_compilation/fail_arrayop2.d(299): Error: invalid array operation `[1] * 6 ^^= 3` for element type `int` +fail_compilation/fail_arrayop2.d(302): Error: [1] * 6 is not an lvalue +fail_compilation/fail_arrayop2.d(303): Error: [1] * 6 is not an lvalue +fail_compilation/fail_arrayop2.d(306): Error: '[1] * 6' is not of integral type, it is a int[] +fail_compilation/fail_arrayop2.d(307): Error: '[1] * 6' is not of integral type, it is a int[] +fail_compilation/fail_arrayop2.d(308): Error: '[1] * 6' is not of integral type, it is a int[] +fail_compilation/fail_arrayop2.d(311): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(312): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(315): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(316): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(317): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(320): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(320): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(320): Error: array operation `[1] * 6` without destination memory not allowed +--- +*/ +// Test all expressions, which can take arrays as their operands but cannot be a part of array operation. +void test15407exp() +{ + struct S { int[] a; } + void f(int[] a) {} + + int[] da; + int[6] sa; + + { auto r = [[1] * 6]; } // ArrayLiteralExp + { auto r = [[1] * 6 : + [1] * 6]; } // AssocArrayLiteralExp + + //TupleExp + + // StructLiteralExp.elements <- preFunctionParameters in CallExp + { auto r = S([1] * 6); } + + // NewExp.newargs/arguments <- preFunctionParameters + { auto r = new S([1] * 6); } + + // TODO: TypeidExp + //auto ti = typeid([1] * 6); + //auto foo(T)(T t) {} + //foo(typeid([1] * 6)); + //auto a = [typeid([1] * 6)]; + + // CommaExp.e1 + { auto r = ([1] * 6, 1); } + + // AssertExp + assert([1] * 6, + cast(char)1 + "abc"[]); + + // CallExp.arguments <- preFunctionParameters + f([1] * 6); + + // AddrExp, if a CT-known length slice can become an TypeSarray lvalue in the future. + { auto r = &(([1] * 6)[0..2]); } + + // PtrExp, *([1] * 6).ptr is also invalid -> show better diagnostic + { auto r = *([1] * 6); } + + // DeleteExp - e1 + delete ([1] * 6); + + // TypeDArray.dotExp, cannot check in ArrayLengthExp.semantic() + { auto r = (6 * da[]).length; } + + // IndexExp - e1 + { auto x1 = (da[] * 6)[1]; } + + // Pre, PostExp - e1 + ([1] * 6)++; + --([1] * 6); + + // AssignExp e1 + ([1] * 6) = 10; + ([1] * 6)[] = 10; + + // BinAssignExp e1 + ([1] * 6) += 1; + ([1] * 6)[] *= 2; + ([1] * 6)[] ^^= 3; + + // CatExp e1 + ([1] * 6) ~= 1; + ([1] * 6)[] ~= 2; + + // Shl, Shr, UshrExp - e1, e2 --> checkIntegralBin + { auto r = ([1] * 6) << 1; } + { auto r = ([1] * 6) >> 1; } + { auto r = ([1] * 6) >>> 1; } + + // AndAnd, OrOrExp - e1, e2 + { auto r = sa[0..5] && [1] * 6; } + { auto r = sa[0..5] || [1] * 6; } + + // Cmp, Equal, IdentityExp - e1, e2 + { auto r = sa[0..5] <= [1] * 6; } + { auto r = sa[0..5] == [1] * 6; } + { auto r = sa[0..5] is [1] * 6; } + + // CondExp - econd, e1, e2 + { auto r = [1] * 6 ? [1] * 6 : [1] * 6; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_arrayop2.d(341): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(344): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(347): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(348): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(349): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(352): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(355): Error: array operation `[1] * 6` without destination memory not allowed +fail_compilation/fail_arrayop2.d(358): Error: array operation `"str"[] + cast(immutable(char))1` without destination memory not allowed +fail_compilation/fail_arrayop2.d(366): Error: CTFE internal error: non-constant value "uvt"[] +--- +*/ +// Test all statements, which can take arrays as their operands. +void test15407stmt() +{ + // ExpStatement - exp + [1] * 6; + + // DoStatement - condition + do {} while ([1] * 6); + + // ForStatement - condition, increment + for ([1] * 6; // init == ExpStatement + [1] * 6; + [1] * 6) {} + + // ForeachStatement - aggr -> lowered to ForStatement + foreach (e; [1] * 6) {} + + // IfStatement condition + if ([1] * 6) {} + + // SwitchStatement - condition + switch ("str"[] + 1) + { + case "tus": break; + default: break; + } + // CaseStatement - exp + switch ("tus") + { + case "uvt"[] - 1: break; + default: break; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_casting.d b/gcc/testsuite/gdc.test/fail_compilation/fail_casting.d new file mode 100644 index 00000000000..74337c305de --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_casting.d @@ -0,0 +1,223 @@ +// REQUIRED_ARGS: -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(12): Error: cannot cast expression `x` of type `short[2]` to `int[2]` because of different sizes +--- +*/ +void test3133() +{ + short[2] x = [1, 2]; + auto y = cast(int[2])x; // error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(28): Error: cannot cast expression `null` of type `typeof(null)` to `S1` +fail_compilation/fail_casting.d(29): Error: cannot cast expression `null` of type `typeof(null)` to `S2` +fail_compilation/fail_casting.d(30): Error: cannot cast expression `s1` of type `S1` to `typeof(null)` +fail_compilation/fail_casting.d(31): Error: cannot cast expression `s2` of type `S2` to `typeof(null)` +--- +*/ +void test9904() +{ + static struct S1 { size_t m; } + static struct S2 { size_t m; byte b; } + { auto x = cast(S1)null; } + { auto x = cast(S2)null; } + { S1 s1; auto x = cast(typeof(null))s1; } + { S2 s2; auto x = cast(typeof(null))s2; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(46): Error: cannot cast expression `x` of type `Object[]` to `object.Object` +fail_compilation/fail_casting.d(47): Error: cannot cast expression `x` of type `Object[2]` to `object.Object` +fail_compilation/fail_casting.d(49): Error: cannot cast expression `x` of type `object.Object` to `Object[]` +fail_compilation/fail_casting.d(50): Error: cannot cast expression `x` of type `object.Object` to `Object[2]` +--- +*/ +void test10646() +{ + // T[] or T[n] --> Tclass + { Object[] x; auto y = cast(Object)x; } + { Object[2] x; auto y = cast(Object)x; } + // T[] or T[n] <-- Tclass + { Object x; auto y = cast(Object[] )x; } + { Object x; auto y = cast(Object[2])x; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(69): Error: cannot cast expression `x` of type `int[1]` to `int` +fail_compilation/fail_casting.d(70): Error: cannot cast expression `x` of type `int` to `int[1]` +fail_compilation/fail_casting.d(71): Error: cannot cast expression `x` of type `float[1]` to `int` +fail_compilation/fail_casting.d(72): Error: cannot cast expression `x` of type `int` to `float[1]` +fail_compilation/fail_casting.d(75): Error: cannot cast expression `x` of type `int[]` to `int` +fail_compilation/fail_casting.d(76): Error: cannot cast expression `x` of type `int` to `int[]` +fail_compilation/fail_casting.d(77): Error: cannot cast expression `x` of type `float[]` to `int` +fail_compilation/fail_casting.d(78): Error: cannot cast expression `x` of type `int` to `float[]` +--- +*/ +void test11484() +{ + // Tsarray <--> integer + { int[1] x; auto y = cast(int ) x; } + { int x; auto y = cast(int[1] ) x; } + { float[1] x; auto y = cast(int ) x; } + { int x; auto y = cast(float[1]) x; } + + // Tarray <--> integer + { int[] x; auto y = cast(int ) x; } + { int x; auto y = cast(int[] ) x; } + { float[] x; auto y = cast(int ) x; } + { int x; auto y = cast(float[]) x; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(97): Error: cannot cast expression `x` of type `int` to `fail_casting.test11485.C` +fail_compilation/fail_casting.d(98): Error: cannot cast expression `x` of type `int` to `fail_casting.test11485.I` +fail_compilation/fail_casting.d(101): Error: cannot cast expression `x` of type `fail_casting.test11485.C` to `int` +fail_compilation/fail_casting.d(102): Error: cannot cast expression `x` of type `fail_casting.test11485.I` to `int` +--- +*/ + +void test11485() +{ + class C {} + interface I {} + + // 11485 TypeBasic --> Tclass + { int x; auto y = cast(C)x; } + { int x; auto y = cast(I)x; } + + // 7472 TypeBasic <-- Tclass + { C x; auto y = cast(int)x; } + { I x; auto y = cast(int)x; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(114): Error: cannot cast expression `x` of type `typeof(null)` to `int[2]` +fail_compilation/fail_casting.d(115): Error: cannot cast expression `x` of type `int[2]` to `typeof(null)` +--- +*/ +void test8179() +{ + { typeof(null) x; auto y = cast(int[2])x; } + { int[2] x; auto y = cast(typeof(null))x; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(128): Error: cannot cast expression `x` of type `S` to `int*` +fail_compilation/fail_casting.d(130): Error: cannot cast expression `x` of type `void*` to `S` +--- +*/ +void test13959() +{ + struct S { int* p; } + { S x; auto y = cast(int*)x; } + { int* x; auto y = cast(S)x; } // no error so it's rewritten as: S(x) + { void* x; auto y = cast(S)x; } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(144): Error: cannot cast expression `mi.x` of type `int` to `MyUbyte14154` +--- +*/ +struct MyUbyte14154 { ubyte x; alias x this; } +struct MyInt14154 { int x; alias x this; } +void test14154() +{ + MyInt14154 mi; + ubyte t = cast(MyUbyte14154)mi; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(179): Error: cannot cast expression `__tup$n$.__expand_field_0` of type `int` to `object.Object` +fail_compilation/fail_casting.d(179): Error: cannot cast expression `__tup$n$.__expand_field_1` of type `int` to `object.Object` +--- +*/ +alias TypeTuple14093(T...) = T; +struct Tuple14093(T...) +{ + static if (T.length == 4) + { + alias Types = TypeTuple14093!(T[0], T[2]); + + Types expand; + + @property ref inout(Tuple14093!Types) _Tuple_super() inout @trusted + { + return *cast(typeof(return)*) &(expand[0]); + } + alias _Tuple_super this; + } + else + { + alias Types = T; + Types expand; + alias expand this; + } +} +void test14093() +{ + Tuple14093!(int, "x", int, "y") point; + auto newPoint = cast(Object)(point); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(192): Error: cannot cast expression `p` of type `void*` to `char[]` +fail_compilation/fail_casting.d(193): Error: cannot cast expression `p` of type `void*` to `char[2]` +--- +*/ +void test14596() +{ + void* p = null; + auto arr = cast(char[])p; + char[2] sarr = cast(char[2])p; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting.d(217): Error: cannot cast expression `c` of type `fail_casting.test14629.C` to `typeof(null)` +fail_compilation/fail_casting.d(218): Error: cannot cast expression `p` of type `int*` to `typeof(null)` +fail_compilation/fail_casting.d(219): Error: cannot cast expression `da` of type `int[]` to `typeof(null)` +fail_compilation/fail_casting.d(220): Error: cannot cast expression `aa` of type `int[int]` to `typeof(null)` +fail_compilation/fail_casting.d(221): Error: cannot cast expression `fp` of type `int function()` to `typeof(null)` +fail_compilation/fail_casting.d(222): Error: cannot cast expression `dg` of type `int delegate()` to `typeof(null)` +--- +*/ +void test14629() +{ + alias P = int*; P p; + alias DA = int[]; DA da; + alias AA = int[int]; AA aa; + alias FP = int function(); FP fp; + alias DG = int delegate(); DG dg; + class C {} C c; + alias N = typeof(null); + + { auto x = cast(N)c; } + { auto x = cast(N)p; } + { auto x = cast(N)da; } + { auto x = cast(N)aa; } + { auto x = cast(N)fp; } + { auto x = cast(N)dg; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_casting1.d b/gcc/testsuite/gdc.test/fail_compilation/fail_casting1.d new file mode 100644 index 00000000000..e26f8fdc557 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_casting1.d @@ -0,0 +1,259 @@ +// REQUIRED_SRGS: -o- + + +// references +alias P = int*; P p; +alias FP = int function(); FP fp; +alias DG = int delegate(); DG dg; +alias DA = int[]; DA da; +alias AA = int[int]; AA aa; +class C {} C c; +alias N = typeof(null); N n; + +// values +alias SA = int[1]; SA sa; +struct S {} S s; + int i; + double f; + + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting1.d(39): Error: cannot cast expression `p` of type `int*` to `int[1]` +fail_compilation/fail_casting1.d(40): Error: cannot cast expression `fp` of type `int function()` to `int[1]` +fail_compilation/fail_casting1.d(41): Error: cannot cast expression `dg` of type `int delegate()` to `int[1]` +fail_compilation/fail_casting1.d(42): Error: cannot cast expression `da` of type `int[]` to `int[1]` +fail_compilation/fail_casting1.d(43): Error: cannot cast expression `aa` of type `int[int]` to `int[1]` +fail_compilation/fail_casting1.d(44): Error: cannot cast expression `c` of type `fail_casting1.C` to `int[1]` +fail_compilation/fail_casting1.d(45): Error: cannot cast expression `n` of type `typeof(null)` to `int[1]` +fail_compilation/fail_casting1.d(49): Error: cannot cast expression `sa` of type `int[1]` to `int delegate()` +fail_compilation/fail_casting1.d(51): Error: cannot cast expression `sa` of type `int[1]` to `double[]` since sizes don't line up +fail_compilation/fail_casting1.d(52): Error: cannot cast expression `sa` of type `int[1]` to `int[int]` +fail_compilation/fail_casting1.d(53): Error: cannot cast expression `sa` of type `int[1]` to `fail_casting1.C` +fail_compilation/fail_casting1.d(54): Error: cannot cast expression `sa` of type `int[1]` to `typeof(null)` +--- +*/ +void test1() +{ + { auto x = cast(SA) p; } // Reject (Bugzilla 14596) + { auto x = cast(SA)fp; } // Reject (Bugzilla 14596) (FP is Tpointer) + { auto x = cast(SA)dg; } // Reject (from e2ir) + { auto x = cast(SA)da; } // Reject (from e2ir) + { auto x = cast(SA)aa; } // Reject (from e2ir) + { auto x = cast(SA) c; } // Reject (Bugzilla 10646) + { auto x = cast(SA) n; } // Reject (Bugzilla 8179) + { auto x = cast( P)sa; } // Accept (equivalent with: cast(int*)sa.ptr;) + { auto x = cast(double*)sa; } // Accept (equivalent with: cast(double*)sa.ptr;) + { auto x = cast(FP)sa; } // Accept (equivalent with: cast(FP)sa.ptr;) + { auto x = cast(DG)sa; } // Reject (from e2ir) + { auto x = cast(DA)sa; } // Accept (equivalent with: cast(int[])sa[];) + { auto x = cast(double[])sa; } // Reject (from e2ir) + { auto x = cast(AA)sa; } // Reject (from e2ir) + { auto x = cast( C)sa; } // Reject (Bugzilla 10646) + { auto x = cast( N)sa; } // Reject (Bugzilla 8179) +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting1.d(78): Error: cannot cast expression `p` of type `int*` to `S` +fail_compilation/fail_casting1.d(79): Error: cannot cast expression `fp` of type `int function()` to `S` +fail_compilation/fail_casting1.d(80): Error: cannot cast expression `dg` of type `int delegate()` to `S` +fail_compilation/fail_casting1.d(81): Error: cannot cast expression `da` of type `int[]` to `S` +fail_compilation/fail_casting1.d(82): Error: cannot cast expression `aa` of type `int[int]` to `S` +fail_compilation/fail_casting1.d(83): Error: cannot cast expression `c` of type `fail_casting1.C` to `S` +fail_compilation/fail_casting1.d(84): Error: cannot cast expression `n` of type `typeof(null)` to `S` +fail_compilation/fail_casting1.d(85): Error: cannot cast expression `s` of type `S` to `int*` +fail_compilation/fail_casting1.d(86): Error: cannot cast expression `s` of type `S` to `int function()` +fail_compilation/fail_casting1.d(87): Error: cannot cast expression `s` of type `S` to `int delegate()` +fail_compilation/fail_casting1.d(88): Error: cannot cast expression `s` of type `S` to `int[]` +fail_compilation/fail_casting1.d(89): Error: cannot cast expression `s` of type `S` to `int[int]` +fail_compilation/fail_casting1.d(90): Error: cannot cast expression `s` of type `S` to `fail_casting1.C` +fail_compilation/fail_casting1.d(91): Error: cannot cast expression `s` of type `S` to `typeof(null)` +--- +*/ +void test2() +{ + { auto x = cast( S) p; } // Reject (Bugzilla 13959) + { auto x = cast( S)fp; } // Reject (Bugzilla 13959) (FP is Tpointer) + { auto x = cast( S)dg; } // Reject (from e2ir) + { auto x = cast( S)da; } // Reject (from e2ir) + { auto x = cast( S)aa; } // Reject (from e2ir) + { auto x = cast( S) c; } // Reject (from e2ir) + { auto x = cast( S) n; } // Reject (Bugzilla 9904) + { auto x = cast( P) s; } // Reject (Bugzilla 13959) + { auto x = cast(FP) s; } // Reject (Bugzilla 13959) (FP is Tpointer) + { auto x = cast(DG) s; } // Reject (from e2ir) + { auto x = cast(DA) s; } // Reject (from e2ir) + { auto x = cast(AA) s; } // Reject (from e2ir) + { auto x = cast( C) s; } // Reject (from e2ir) + { auto x = cast( N) s; } // Reject (Bugzilla 9904) +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting1.d(125): Error: cannot cast expression `p` of type `int*` to `int delegate()` +fail_compilation/fail_casting1.d(126): Error: cannot cast expression `p` of type `int*` to `int[]` +fail_compilation/fail_casting1.d(129): Error: cannot cast expression `p` of type `int*` to `typeof(null)` +fail_compilation/fail_casting1.d(133): Error: cannot cast expression `fp` of type `int function()` to `int delegate()` +fail_compilation/fail_casting1.d(134): Error: cannot cast expression `fp` of type `int function()` to `int[]` +fail_compilation/fail_casting1.d(137): Error: cannot cast expression `fp` of type `int function()` to `typeof(null)` +fail_compilation/fail_casting1.d(139): Deprecation: casting from int delegate() to int* is deprecated +fail_compilation/fail_casting1.d(140): Deprecation: casting from int delegate() to int function() is deprecated +fail_compilation/fail_casting1.d(142): Error: cannot cast expression `dg` of type `int delegate()` to `int[]` +fail_compilation/fail_casting1.d(143): Error: cannot cast expression `dg` of type `int delegate()` to `int[int]` +fail_compilation/fail_casting1.d(144): Error: cannot cast expression `dg` of type `int delegate()` to `fail_casting1.C` +fail_compilation/fail_casting1.d(145): Error: cannot cast expression `dg` of type `int delegate()` to `typeof(null)` +fail_compilation/fail_casting1.d(157): Error: cannot cast expression `da` of type `int[]` to `int delegate()` +fail_compilation/fail_casting1.d(159): Error: cannot cast expression `da` of type `int[]` to `int[int]` +fail_compilation/fail_casting1.d(160): Error: cannot cast expression `da` of type `int[]` to `fail_casting1.C` +fail_compilation/fail_casting1.d(161): Error: cannot cast expression `da` of type `int[]` to `typeof(null)` +fail_compilation/fail_casting1.d(165): Error: cannot cast expression `aa` of type `int[int]` to `int delegate()` +fail_compilation/fail_casting1.d(166): Error: cannot cast expression `aa` of type `int[int]` to `int[]` +fail_compilation/fail_casting1.d(169): Error: cannot cast expression `aa` of type `int[int]` to `typeof(null)` +fail_compilation/fail_casting1.d(173): Error: cannot cast expression `c` of type `fail_casting1.C` to `int delegate()` +fail_compilation/fail_casting1.d(174): Error: cannot cast expression `c` of type `fail_casting1.C` to `int[]` +fail_compilation/fail_casting1.d(177): Error: cannot cast expression `c` of type `fail_casting1.C` to `typeof(null)` +--- +*/ +void test3() // between reference types +{ + { auto x = cast( P) p; } // Accept + { auto x = cast(FP) p; } // Accept (FP is Tpointer) + { auto x = cast(DG) p; } // Reject (from e2ir) + { auto x = cast(DA) p; } // Reject (Bugzilla 14596) + { auto x = cast(AA) p; } // Accept (because of size match) + { auto x = cast( C) p; } // Accept (because of size match) + { auto x = cast( N) p; } // Reject (Bugzilla 14629) + + { auto x = cast( P)fp; } // Accept (FP is Tpointer) + { auto x = cast(FP)fp; } // Accept + { auto x = cast(DG)fp; } // Reject (from e2ir) + { auto x = cast(DA)fp; } // Reject (Bugzilla 14596) + { auto x = cast(AA)fp; } // Accept (because of size match) + { auto x = cast( C)fp; } // Accept (because of size match) + { auto x = cast( N)fp; } // Reject (Bugzilla 14629) + + { auto x = cast( P)dg; } // Deprecated (equivalent with: cast( P)dg.ptr;) + { auto x = cast(FP)dg; } // Deprecated (equivalent with: cast(FP)dg.ptr;) + { auto x = cast(DG)dg; } // Accept + { auto x = cast(DA)dg; } // Reject (from e2ir) + { auto x = cast(AA)dg; } // Reject (from e2ir) + { auto x = cast( C)dg; } // Reject (from e2ir) + { auto x = cast( N)dg; } // Reject (Bugzilla 14629) + + { auto x = cast( P) n; } // Accept + { auto x = cast(FP) n; } // Accept + { auto x = cast(DG) n; } // Accept + { auto x = cast(DA) n; } // Accept + { auto x = cast(AA) n; } // Accept + { auto x = cast( C) n; } // Accept + { auto x = cast( N) n; } // Accept + + { auto x = cast( P)da; } // Accept (equivalent with: cast(P)da.ptr;) + { auto x = cast(FP)da; } // Accept (FP is Tpointer) + { auto x = cast(DG)da; } // Reject (from e2ir) + { auto x = cast(DA)da; } // Accept + { auto x = cast(AA)da; } // Reject (from e2ir) + { auto x = cast( C)da; } // Reject (Bugzilla 10646) + { auto x = cast( N)da; } // Reject (Bugzilla 14629) + + { auto x = cast( P)aa; } // Accept (because of size match) + { auto x = cast(FP)aa; } // Accept (FP is Tpointer) + { auto x = cast(DG)aa; } // Reject (from e2ir) + { auto x = cast(DA)aa; } // Reject (from e2ir) + { auto x = cast(AA)aa; } // Accept + { auto x = cast( C)aa; } // Accept (because of size match) + { auto x = cast( N)aa; } // Reject (Bugzilla 14629) + + { auto x = cast( P) c; } // Accept + { auto x = cast(FP) c; } // Accept (FP is Tpointer) + { auto x = cast(DG) c; } // Reject (from e2ir) + { auto x = cast(DA) c; } // Reject (Bugzilla 10646) + { auto x = cast(AA) c; } // Accept (because of size match) + { auto x = cast( C) c; } // Accept + { auto x = cast( N) c; } // Reject (Bugzilla 14629) +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting1.d(206): Error: cannot cast expression `0` of type `int` to `int delegate()` +fail_compilation/fail_casting1.d(207): Error: cannot cast expression `0` of type `int` to `int[]` +fail_compilation/fail_casting1.d(208): Error: cannot cast expression `0` of type `int` to `int[1]` +fail_compilation/fail_casting1.d(209): Error: cannot cast expression `0` of type `int` to `int[int]` +fail_compilation/fail_casting1.d(210): Error: cannot cast expression `0` of type `int` to `fail_casting1.C` +fail_compilation/fail_casting1.d(211): Error: cannot cast expression `0` of type `int` to `typeof(null)` +fail_compilation/fail_casting1.d(215): Error: cannot cast expression `i` of type `int` to `int delegate()` +fail_compilation/fail_casting1.d(216): Error: cannot cast expression `i` of type `int` to `int[]` +fail_compilation/fail_casting1.d(217): Error: cannot cast expression `i` of type `int` to `int[1]` +fail_compilation/fail_casting1.d(218): Error: cannot cast expression `i` of type `int` to `int[int]` +fail_compilation/fail_casting1.d(219): Error: cannot cast expression `i` of type `int` to `fail_casting1.C` +fail_compilation/fail_casting1.d(220): Error: cannot cast expression `i` of type `int` to `typeof(null)` +fail_compilation/fail_casting1.d(224): Error: cannot cast expression `dg` of type `int delegate()` to `int` +fail_compilation/fail_casting1.d(225): Error: cannot cast expression `da` of type `int[]` to `int` +fail_compilation/fail_casting1.d(226): Error: cannot cast expression `sa` of type `int[1]` to `int` +fail_compilation/fail_casting1.d(227): Error: cannot cast expression `aa` of type `int[int]` to `int` +fail_compilation/fail_casting1.d(228): Error: cannot cast expression `c` of type `fail_casting1.C` to `int` +--- +*/ +void test4() +{ + { auto x = cast( P) 0; } // Accept + { auto x = cast(FP) 0; } // Accept + { auto x = cast(DG) 0; } // Reject (from constfold) + { auto x = cast(DA) 0; } // Reject (Bugzilla 11484) + { auto x = cast(SA) 0; } // Reject (Bugzilla 11484) + { auto x = cast(AA) 0; } // Reject (from constfold) + { auto x = cast( C) 0; } // Reject (Bugzilla 11485) + { auto x = cast( N) 0; } // Reject (from constfold) + + { auto x = cast( P) i; } // Accept + { auto x = cast(FP) i; } // Accept + { auto x = cast(DG) i; } // Reject (from e2ir) + { auto x = cast(DA) i; } // Reject (Bugzilla 11484) + { auto x = cast(SA) i; } // Reject (Bugzilla 11484) + { auto x = cast(AA) i; } // Reject (from e2ir) + { auto x = cast( C) i; } // Reject (Bugzilla 11485) + { auto x = cast( N) i; } // Reject (from e2ir) + + { auto x = cast(int) p; } // Accept + { auto x = cast(int)fp; } // Accept + { auto x = cast(int)dg; } // Reject (from e2ir) + { auto x = cast(int)da; } // Reject (Bugzilla 11484) + { auto x = cast(int)sa; } // Reject (Bugzilla 11484) + { auto x = cast(int)aa; } // Reject (from e2ir) + { auto x = cast(int) c; } // Reject (Bugzilla 7472) + { auto x = cast(int) n; } // Accept +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting1.d(249): Error: cannot cast expression `0` of type `int` to `int[1]` +fail_compilation/fail_casting1.d(250): Error: cannot cast expression `0` of type `int` to `S` +fail_compilation/fail_casting1.d(251): Error: cannot cast expression `i` of type `int` to `int[1]` +fail_compilation/fail_casting1.d(252): Error: cannot cast expression `i` of type `int` to `S` +fail_compilation/fail_casting1.d(253): Error: cannot cast expression `f` of type `double` to `int[1]` +fail_compilation/fail_casting1.d(254): Error: cannot cast expression `f` of type `double` to `S` +fail_compilation/fail_casting1.d(255): Error: cannot cast expression `sa` of type `int[1]` to `int` +fail_compilation/fail_casting1.d(256): Error: cannot cast expression `s` of type `S` to `int` +fail_compilation/fail_casting1.d(257): Error: cannot cast expression `sa` of type `int[1]` to `double` +fail_compilation/fail_casting1.d(258): Error: cannot cast expression `s` of type `S` to `double` +--- +*/ +void test5() +{ + { auto x = cast(SA) 0; } // Reject (Bugzilla 14154) + { auto x = cast( S) 0; } // Reject (Bugzilla 14154) + { auto x = cast(SA) i; } // Reject (Bugzilla 14154) + { auto x = cast( S) i; } // Reject (Bugzilla 14154) + { auto x = cast(SA) f; } // Reject (Bugzilla 14154) + { auto x = cast( S) f; } // Reject (Bugzilla 14154) + { auto x = cast(int)sa; } // Reject (Bugzilla 14154) + { auto x = cast(int) s; } // Reject (Bugzilla 14154) + { auto x = cast(double)sa; } // Reject (Bugzilla 14154) + { auto x = cast(double) s; } // Reject (Bugzilla 14154) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d new file mode 100644 index 00000000000..a45d6d30bae --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d @@ -0,0 +1,21 @@ +// REQUIRED_ARGS: -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_casting2.d(15): Error: type int is not an expression +fail_compilation/fail_casting2.d(17): Error: template lambda has no type +fail_compilation/fail_casting2.d(20): Error: template Templ() has no type +--- +*/ + +void test15214() +{ + alias Type = int; + cast(void)(Type); + + cast(void)(x => mixin(x)("mixin(x);")); + + template Templ() {} + cast(void)(Templ); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_circular.d b/gcc/testsuite/gdc.test/fail_compilation/fail_circular.d new file mode 100644 index 00000000000..dd958af5acf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_circular.d @@ -0,0 +1,137 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail_circular.d(16): Error: circular reference to variable 'fail_circular.a1' +fail_compilation/fail_circular.d(17): Error: circular reference to variable 'fail_circular.a2' +fail_compilation/fail_circular.d(19): Error: circular reference to variable 'fail_circular.b1' +fail_compilation/fail_circular.d(20): Error: circular reference to variable 'fail_circular.b2' +fail_compilation/fail_circular.d(22): Error: circular reference to variable 'fail_circular.c1' +fail_compilation/fail_circular.d(23): Error: circular reference to variable 'fail_circular.c2' +fail_compilation/fail_circular.d(25): Error: circular initialization of variable 'fail_circular.d1' +fail_compilation/fail_circular.d(26): Error: circular initialization of variable 'fail_circular.d2' +fail_compilation/fail_circular.d(28): Error: circular initialization of variable 'fail_circular.e1' +fail_compilation/fail_circular.d(29): Error: circular initialization of variable 'fail_circular.e2' +--- +*/ +auto a1 = a1; // semantic error (cannot determine expression type) +auto a2 = .a2; // semantic error + +const b1 = b1; // semantic error +const b2 = .b2; // semantic error + +enum c1 = c1; // semantic error +enum c2 = .c2; // semantic error + +const int d1 = d1; // CTFE error (expression type is determined to int) +const int d2 = .d2; // CTFE error + +enum int e1 = e1; // CTFE error +enum int e2 = .e2; // CTFE error + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_circular.d(47): Error: circular reference to variable 'fail_circular.a1a' +fail_compilation/fail_circular.d(49): Error: circular reference to variable 'fail_circular.a2a' +fail_compilation/fail_circular.d(52): Error: circular reference to variable 'fail_circular.b1a' +fail_compilation/fail_circular.d(54): Error: circular reference to variable 'fail_circular.b2a' +fail_compilation/fail_circular.d(57): Error: circular reference to variable 'fail_circular.c1a' +fail_compilation/fail_circular.d(59): Error: circular reference to variable 'fail_circular.c2a' +fail_compilation/fail_circular.d(62): Error: circular initialization of variable 'fail_circular.d1a' +fail_compilation/fail_circular.d(64): Error: circular initialization of variable 'fail_circular.d2a' +fail_compilation/fail_circular.d(67): Error: circular initialization of variable 'fail_circular.e1a' +fail_compilation/fail_circular.d(69): Error: circular initialization of variable 'fail_circular.e2a' +--- +*/ +auto a1a = a1b; +auto a1b = a1a; // semantic error +auto a2a = a2b; +auto a2b = .a2a; // semantic error + +const b1a = b1b; +const b1b = b1a; // semantic error +const b2a = b2b; +const b2b = .b2a; // semantic error + +enum c1a = c1b; +enum c1b = c1a; // semantic error +enum c2a = c2b; +enum c2b = .c2a; // semantic error + +const int d1a = d1b; +const int d1b = d1a; // CTFE error +const int d2a = d2b; +const int d2b = .d2a; // CTFE error + +enum int e1a = e1b; +enum int e1b = e1a; // CTFE error +enum int e2a = e2b; +enum int e2b = .e2a; // CTFE error + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_circular.d(84): Error: circular reference to variable 'fail_circular.S1.a1' +fail_compilation/fail_circular.d(88): Error: circular reference to variable 'fail_circular.S2.b1' +fail_compilation/fail_circular.d(92): Error: circular reference to variable 'fail_circular.S3.c1' +fail_compilation/fail_circular.d(97): Error: circular reference to variable 'fail_circular.S4.a1a' +fail_compilation/fail_circular.d(102): Error: circular reference to variable 'fail_circular.S5.b1a' +fail_compilation/fail_circular.d(107): Error: circular reference to variable 'fail_circular.S6.c1a' +--- +*/ +struct S1 +{ + static a1 = S1.a1; // semantic error +} +struct S2 +{ + static const b1 = S2.b1; // semantic error +} +struct S3 +{ + enum c1 = S3.c1; // semantic error +} +struct S4 +{ + static a1a = S4.a1b; + static a1b = S4.a1a; // semantic error +} +struct S5 +{ + static const b1a = S5.b1b; + static const b1b = S5.b1a; // semantic error +} +struct S6 +{ + enum c1a = S6.c1b; + enum c1b = S6.c1a; // semantic error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_circular.d(123): Error: circular reference to variable 'fail_circular.C.a1' +fail_compilation/fail_circular.d(125): Error: circular reference to variable 'fail_circular.C.b1' +fail_compilation/fail_circular.d(127): Error: circular reference to variable 'fail_circular.C.c1' +fail_compilation/fail_circular.d(130): Error: circular reference to variable 'fail_circular.C.a1a' +fail_compilation/fail_circular.d(133): Error: circular reference to variable 'fail_circular.C.b1a' +fail_compilation/fail_circular.d(136): Error: circular reference to variable 'fail_circular.C.c1a' +--- +*/ +class C +{ + static a1 = C.a1; // semantic error + + static const b1 = C.b1; // semantic error + + enum c1 = C.c1; // semantic error + + static a1a = C.a1b; + static a1b = C.a1a; // semantic error + + static const b1a = C.b1b; + static const b1b = C.b1a; // semantic error + + enum c1a = C.c1b; + enum c1b = C.c1a; // semantic error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d new file mode 100644 index 00000000000..f04d272563a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail_circular2.d(10): Error: circular initialization of variable 'fail_circular2.S.d1' +fail_compilation/fail_circular2.d(12): Error: circular initialization of variable 'fail_circular2.S.e1' +--- +*/ +struct S +{ + static const int d1 = S.d1; // CTFE error (expression type is determined to int) + + enum int e1 = S.e1; // CTFE error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_circular2.d(24): Error: circular initialization of variable 'fail_circular2.C.d1' +fail_compilation/fail_circular2.d(26): Error: circular initialization of variable 'fail_circular2.C.e1' +--- +*/ +class C +{ + static const int d1 = C.d1; // CTFE error + + enum int e1 = C.e1; // CTFE error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_opover.d b/gcc/testsuite/gdc.test/fail_compilation/fail_opover.d new file mode 100644 index 00000000000..ba930f01a02 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_opover.d @@ -0,0 +1,58 @@ +// REQUIRED_ARGS: -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_opover.d(13): Error: no [] operator overload for type object.Object +fail_compilation/fail_opover.d(17): Error: no [] operator overload for type TestS +--- +*/ +void test1() +{ + Object m; + m[] = error; + + struct TestS {} + TestS s; + s[] = error; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail_opover.d(46): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(47): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(48): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(49): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(50): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(51): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(52): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(53): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(54): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(55): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(56): Error: no [] operator overload for type S +fail_compilation/fail_opover.d(57): Error: no [] operator overload for type S +--- +*/ +void test2() +{ + struct S + { + void func(int) {} + alias func this; + } + S s; + // The errors failing aliasthis access need to be gagged for better error messages. + s[]; // in ArrayExp::op_overload() + s[1]; // ditto + s[1..2]; // ditto + +s[]; // in UnaExp::op_overload() + +s[1]; // ditto + +s[1..2]; // ditto + s[] = 3; // in AssignExp::semantic() + s[1] = 3; // ditto + s[1..2] = 3; // ditto + s[] += 3; // in BinAssignExp::op_overload() + s[1] += 3; // ditto + s[1..2] += 3; // ditto +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d new file mode 100644 index 00000000000..c6342534692 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d @@ -0,0 +1,145 @@ +/* +PERMUTE_ARGS: +REQUIRED_ARGS: -dip25 +TEST_OUTPUT: +--- +fail_compilation/fail_scope.d(45): Error: returning `cast(char[])string` escapes a reference to local variable `string` +fail_compilation/fail_scope.d(63): Error: returning `s.bar()` escapes a reference to local variable `s` +fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a reference to local variable `string` +fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a` +fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a` +fail_compilation/fail_scope.d(108): Error: escaping reference to outer local variable `x` +fail_compilation/fail_scope.d(127): Error: returning `s.bar()` escapes a reference to local variable `s` +fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i` +--- +//fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned +//fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned +//fail_compilation/fail_scope.d(33): Error: scope variable `dg` may not be returned +//fail_compilation/fail_scope.d(35): Error: scope variable `da` may not be returned +//fail_compilation/fail_scope.d(37): Error: scope variable `o` may not be returned +//fail_compilation/fail_scope.d(38): Error: scope variable `dg` may not be returned +//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned +*/ + + + + + +alias int delegate() dg_t; + +int[] checkEscapeScope1(scope int[] da) { return da; } +int[3] checkEscapeScope2(scope int[3] sa) { return sa; } +Object checkEscapeScope3(scope Object o) { return o; } +dg_t checkEscapeScope4(scope dg_t dg) { return dg; } + +int[] checkEscapeScope1() { scope int[] da = []; return da; } +int[3] checkEscapeScope2() { scope int[3] sa = [1,2,3]; return sa; } +Object checkEscapeScope3() { scope Object o = new Object; return o; } // same with fail7294.d +dg_t checkEscapeScope4() { scope dg_t dg = () => 1; return dg; } + +int* test(scope int* p) @safe { return p; } + +char[] foo140() +{ + char[4] string = "abcd"; + return string; +} + +/************/ + +struct S +{ + int x; + + ref int bar() return + { + return x; + } +} + +ref int test() +{ + S s; + return s.bar(); +} + +/************/ + +ref int foo8(ref int x); +ref int foo8(return ref int x); + +void testover() +{ + int x; + foo8(x); +} + +/************/ + +char* fail141() +{ + char[4] string = "abcd"; + return string.ptr; +} + +/************/ + +int[] test1313b() +out{} +body +{ + int[2] a; + return a; +} + +int[] test1313a() +//out{} +body +{ + int[2] a; + return a; +} + +/******************/ +// https://issues.dlang.org/show_bug.cgi?id=15192 + +ref int fun15192(ref int x) @safe +{ + ref int bar(){ return x; } + return bar(); +} + +ref int fun15192_2(return ref int x) @safe +{ + ref int bar(){ return x; } + return bar(); +} + +/**************************/ +// https://issues.dlang.org/show_bug.cgi?id=15193 + +ref int foo15193()@safe{ + struct S{ + int x; + ref int bar() { return x; } + } + S s; + return s.bar(); +} + + +/*****************************/ +// https://issues.dlang.org/show_bug.cgi?id=16226 + +ref int test16226() @safe +{ + int i; + return foo16226(i); +} + + +ref foo16226(ref int bar) @safe +{ + return bar; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/failattr.d b/gcc/testsuite/gdc.test/fail_compilation/failattr.d new file mode 100644 index 00000000000..e0b4562bcad --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failattr.d @@ -0,0 +1,34 @@ +// REQUIRED_ARGS: -o- + +/* +TEST_OUTPUT: +--- +fail_compilation/failattr.d(16): Error: variable failattr.C2901.v1 cannot be synchronized +fail_compilation/failattr.d(17): Error: variable failattr.C2901.v2 cannot be override +fail_compilation/failattr.d(18): Error: variable failattr.C2901.v3 cannot be abstract +fail_compilation/failattr.d(19): Error: variable failattr.C2901.v4 cannot be final, perhaps you meant const? +fail_compilation/failattr.d(31): Error: variable failattr.C2901.v13 cannot be final abstract synchronized override +fail_compilation/failattr.d(33): Error: variable failattr.C2901.v14 cannot be final, perhaps you meant const? +--- +*/ +class C2901 +{ + synchronized int v1; // error + override int v2; // error + abstract int v3; // error + final int v4; // error + + synchronized { int v5; } // no error + override { int v6; } // no error + abstract { int v7; } // no error + final { int v8; } // no error + + synchronized: int v9; // no error + override: int v10; // no error + abstract: int v11; // no error + final: int v12; // no error + + synchronized override abstract final int v13; // one line error + + static final int v14; // error, even if static is applied at the same time +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failcontracts.d b/gcc/testsuite/gdc.test/fail_compilation/failcontracts.d new file mode 100644 index 00000000000..2355aa3d798 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failcontracts.d @@ -0,0 +1,24 @@ +/* TEST_OUTPUT: +--- +fail_compilation/failcontracts.d(18): Error: missing `{ ... }` for function literal +fail_compilation/failcontracts.d(18): Error: semicolon expected following auto declaration, not `bode` +fail_compilation/failcontracts.d(19): Error: function declaration without return type. (Note that constructors are always named `this`) +fail_compilation/failcontracts.d(19): Error: no identifier for declarator `test1()` +fail_compilation/failcontracts.d(19): Error: semicolon expected following function declaration +fail_compilation/failcontracts.d(20): Error: semicolon expected following function declaration +fail_compilation/failcontracts.d(22): Error: unexpected `(` in declarator +fail_compilation/failcontracts.d(22): Error: found `T` when expecting `)` +fail_compilation/failcontracts.d(22): Error: enum declaration is invalid +fail_compilation/failcontracts.d(22): Error: found `)` instead of statement +--- +*/ + +void test() +{ + auto f1 = function() bode; + auto test1() bode; + auto test2()() bode; + + enum : int (int function() bode T); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d new file mode 100644 index 00000000000..f190141aabe --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/faildeleteaa.d(11): Error: cannot delete type int +--- +*/ + +void main() +{ + int[int] aa = [1 : 2]; + delete aa[1]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d b/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d new file mode 100644 index 00000000000..af238f71dcf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/faildottypeinfo.d(11): Error: no property 'typeinfo' for type 'int' +fail_compilation/faildottypeinfo.d(12): Error: no property 'typeinfo' for type 'object.Object' +--- +*/ + +void main() +{ + auto x = 0.typeinfo; + auto y = Object.typeinfo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failescape.d b/gcc/testsuite/gdc.test/fail_compilation/failescape.d new file mode 100644 index 00000000000..8376893e580 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failescape.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/failescape.d(8): Error: character '\' is not a valid token +--- +*/ + +string x = \n; diff --git a/gcc/testsuite/gdc.test/fail_compilation/failinout1.d b/gcc/testsuite/gdc.test/fail_compilation/failinout1.d new file mode 100644 index 00000000000..fc3d7913246 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failinout1.d @@ -0,0 +1,5 @@ +inout(int) foo(inout(int) x) +{ + x = 5; // cannot modify inout + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failinout2.d b/gcc/testsuite/gdc.test/fail_compilation/failinout2.d new file mode 100644 index 00000000000..12a9c44f84a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failinout2.d @@ -0,0 +1 @@ +inout int x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/failinout3748a.d b/gcc/testsuite/gdc.test/fail_compilation/failinout3748a.d new file mode 100644 index 00000000000..bb2cd55aaf5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failinout3748a.d @@ -0,0 +1,4 @@ +struct S3748 +{ + inout(int) err8; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failinout3748b.d b/gcc/testsuite/gdc.test/fail_compilation/failinout3748b.d new file mode 100644 index 00000000000..741e44fa0a5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failinout3748b.d @@ -0,0 +1,4 @@ +void main() +{ + inout(int)* err11; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d b/gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d new file mode 100644 index 00000000000..713c180ec9e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/failmemalloc.d(13): Error: member allocators not supported by CTFE +--- +*/ + +struct S +{ + new(size_t sz) { return null; } +} + +S* s = new S(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/failoffset.d b/gcc/testsuite/gdc.test/fail_compilation/failoffset.d new file mode 100644 index 00000000000..c991d4752ee --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failoffset.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/failoffset.d(12): Error: no property 'offset' for type 'int' +fail_compilation/failoffset.d(12): while evaluating: `static assert(b.offset == 4)` +--- +*/ + +void main() +{ + struct S { int a, b; } + static assert(S.b.offset == 4); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failsafea.d b/gcc/testsuite/gdc.test/fail_compilation/failsafea.d new file mode 100644 index 00000000000..b2a3f227b0d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failsafea.d @@ -0,0 +1,8 @@ + +void systemfunc() @system {} + +@safe +void callingsystem() +{ + systemfunc(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failsafeb.d b/gcc/testsuite/gdc.test/fail_compilation/failsafeb.d new file mode 100644 index 00000000000..c04d9ee5dc7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failsafeb.d @@ -0,0 +1,8 @@ + +void function() @system sysfuncptr; + +@safe +void callingsystem() +{ + sysfuncptr(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/failsafec.d b/gcc/testsuite/gdc.test/fail_compilation/failsafec.d new file mode 100644 index 00000000000..8bcda913720 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/failsafec.d @@ -0,0 +1,9 @@ + +void delegate() @system sysdelegate; + +@safe +void callingsystem() +{ + sysdelegate(); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix350a.d b/gcc/testsuite/gdc.test/fail_compilation/fix350a.d new file mode 100644 index 00000000000..8c3563c2c03 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fix350a.d @@ -0,0 +1,7 @@ +struct S1 +{ + int a, b, c; + + static immutable S1 C1 = { 1 2 3 }; // no commas here, compiles + static immutable S1 C2 = { 1, 2, 3 }; // compiles as well +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix350b.d b/gcc/testsuite/gdc.test/fail_compilation/fix350b.d new file mode 100644 index 00000000000..6c1a0bc949e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fix350b.d @@ -0,0 +1,10 @@ +int foo() { return 3; } + +struct S2 +{ + int a, b, c; + + static immutable S2 C1 = { foo() 2 3 }; // compiles (and works) + static immutable S2 C2 = { foo() 2, 3 }; // compiles (and works) + //static immutable S2 C3 = { 2 foo() 3 }; // does not compile: comma expected separating field initializers +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d new file mode 100644 index 00000000000..3ab4db77867 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -c -o- +/* +TEST_OUTPUT: +--- +fail_compilation/gag4269a.d(12): Error: undefined identifier `B` +--- +*/ + +static if(is(typeof(A4269.sizeof))) {} +class A4269 +{ + void foo(B b); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d new file mode 100644 index 00000000000..718fa942ef2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -c -o- +/* +TEST_OUTPUT: +--- +fail_compilation/gag4269b.d(10): Error: undefined identifier `Y` +--- +*/ + +static if(is(typeof(X2.init))) {} +struct X2 { Y y; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d new file mode 100644 index 00000000000..1a9383148cd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -c -o- +/* +TEST_OUTPUT: +--- +fail_compilation/gag4269c.d(10): Error: undefined identifier `T3`, did you mean function `X3`? +--- +*/ + +static if(is(typeof(X3.init))) {} +void X3(T3) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d new file mode 100644 index 00000000000..bdfabaecc9e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -c -o- +/* +TEST_OUTPUT: +--- +fail_compilation/gag4269d.d(10): Error: undefined identifier `Y4`, did you mean function `X4`? +--- +*/ + +static if(is(typeof(X4.init))) {} +Y4 X4() { return typeof(return).init; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d new file mode 100644 index 00000000000..d6eed626b87 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -c -o- +/* +TEST_OUTPUT: +--- +fail_compilation/gag4269e.d(10): Error: undefined identifier `Y8`, did you mean class `X8`? +--- +*/ + +static if(is(typeof(X8.init))) {} +class X8 : Y8 {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d new file mode 100644 index 00000000000..eaf8593fc1b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d @@ -0,0 +1,11 @@ +// REQUIRED_ARGS: -c -o- +/* +TEST_OUTPUT: +--- +fail_compilation/gag4269f.d(11): Error: undefined identifier `Y9`, did you mean interface `X9`? +fail_compilation/gag4269f.d(11): Error: variable gag4269f.X9.y field not allowed in interface +--- +*/ + +static if(is(typeof(X9.init))) {} +interface X9 { Y9 y; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d new file mode 100644 index 00000000000..348207e0d5e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -c -o- +/* +TEST_OUTPUT: +--- +fail_compilation/gag4269g.d(10): Error: undefined identifier `Y13`, did you mean template `X13(Y13 y)`? +--- +*/ + +static if(is(typeof(X13!(0).init))) {} +template X13(Y13 y) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10016.d b/gcc/testsuite/gdc.test/fail_compilation/ice10016.d new file mode 100644 index 00000000000..ff721318e50 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10016.d @@ -0,0 +1,48 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10016.d(33): Error: undefined identifier `unknownIdentifier` +fail_compilation/ice10016.d(47): Error: template instance ice10016.RefCounted!(S) error instantiating +--- +*/ + +struct RefCounted(T) +{ + struct RefCountedStore + { + struct Impl + { + T _payload; + } + Impl* _store; + } + RefCountedStore _refCounted; + + void opAssign(typeof(this)) { } + void opAssign(T) { } + + @property refCountedPayload() + { + return _refCounted._store._payload; + } + alias refCountedPayload this; +} + +struct S +{ + int i = unknownIdentifier; +} + +class C {} + +class N +{ + this(C) {} + C c() { return null; } +} + +class D : N +{ + this() { super(c); } + RefCounted!S _s; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10076.d b/gcc/testsuite/gdc.test/fail_compilation/ice10076.d new file mode 100644 index 00000000000..8337d7f459e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10076.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10076.d(18): Error: template instance getMembersAndAttributesWhere!() template 'getMembersAndAttributesWhere' is not defined +fail_compilation/ice10076.d(23): Error: template instance ice10076.getValidaterAttrs!string error instantiating +fail_compilation/ice10076.d(13): instantiated from here: validate!string +--- +*/ + +void main() +{ + string s; + validate(s); +} + +template getValidaterAttrs(T) +{ + alias getMembersAndAttributesWhere!().Elements getValidaterAttrs; +} + +void validate(T)(T) +{ + alias getValidaterAttrs!T memberAttrs; + auto x = memberAttrs.length; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10212.d b/gcc/testsuite/gdc.test/fail_compilation/ice10212.d new file mode 100644 index 00000000000..ce4a671f12f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10212.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10212.d(12): Error: mismatched function return type inference of `int function() pure nothrow @nogc @safe` and `int` +--- +*/ + +int delegate() foo() +{ + // returns "int function() pure nothrow @safe function() pure nothrow @safe" + // and it mismatches to "int delegate()" + return () => { + return 1; + }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10259.d b/gcc/testsuite/gdc.test/fail_compilation/ice10259.d new file mode 100644 index 00000000000..e12df7dd5e5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10259.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10259.d(11): Error: circular reference to 'ice10259.D.d' +fail_compilation/ice10259.d(11): called from here: (*function () => x)() +--- +*/ +class D +{ + int x; + D d = { auto x = new D(); return x; }(); +} +enum x = new D; + +/* +TEST_OUTPUT: +--- +fail_compilation/ice10259.d(25): Error: circular reference to 'ice10259.D2.d' +fail_compilation/ice10259.d(25): called from here: (*function () => x)() +--- +*/ +class D2 +{ + int x; + D2 d = function { auto x = new D2(); return x; }(); +} +enum x2 = new D2; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10273.d b/gcc/testsuite/gdc.test/fail_compilation/ice10273.d new file mode 100644 index 00000000000..b7983bbc482 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10273.d @@ -0,0 +1,12 @@ +// 10273 - ICE in CTFE + +struct Bug10273 { + int val = 3.45; +} +int bug10273() +{ + Bug10273 p; + return 1; +} + +static assert(bug10273()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10283.d b/gcc/testsuite/gdc.test/fail_compilation/ice10283.d new file mode 100644 index 00000000000..347ac3557b5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10283.d @@ -0,0 +1,10 @@ +// 10283 + +S10283 blah(S10283 xxx) { return xxx; } +S10283 repy = blah(S10283()); + +struct S10283 +{ + string source = 7; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10341.d b/gcc/testsuite/gdc.test/fail_compilation/ice10341.d new file mode 100644 index 00000000000..ed6b6cbc48c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10341.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10341.d(10): Error: case range not in switch statement +--- +*/ + +void main() +{ + case 1: .. case 2: +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10382.d b/gcc/testsuite/gdc.test/fail_compilation/ice10382.d new file mode 100644 index 00000000000..618a02e8411 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10382.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10382.d(14): Error: can only catch class objects, not `int` +--- +*/ + +void main () +{ + try + { + int b = 3; + } + catch (int a) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10419.d b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d new file mode 100644 index 00000000000..47d1f733548 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10419.d(12): Error: arr().length is not an lvalue +--- +*/ + +int[] arr() { return []; } + +void main() +{ + arr().length = 1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10599.d b/gcc/testsuite/gdc.test/fail_compilation/ice10599.d new file mode 100644 index 00000000000..b8be25ade0f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10599.d @@ -0,0 +1,12 @@ +// 10599 ICE(interpret.c) + +struct Bug { + int val = 3.45; +} +int bug10599() +{ + Bug p = Bug(); + return 1; +} + +static assert(bug10599()); \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10600.d b/gcc/testsuite/gdc.test/fail_compilation/ice10600.d new file mode 100644 index 00000000000..b1ee9067b9b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10600.d @@ -0,0 +1,32 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10600.d(30): Error: template instance to!(int, double) does not match template declaration to(T) +--- +*/ + +import imports.ice10600a; +import imports.ice10600b; + +template Tuple(Specs...) +{ + struct Tuple + { + string toString() + { + Appender!string w; // issue! + return ""; + } + } +} +Tuple!T tuple(T...)(T args) +{ + return typeof(return)(); +} + +void main() +{ + auto a = to!int(""); + auto b = to!(int, double)(""); + tuple(1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10616.d b/gcc/testsuite/gdc.test/fail_compilation/ice10616.d new file mode 100644 index 00000000000..6ccd1c31b60 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10616.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10616.d(8): Error: class ice10616.A is forward referenced when looking for 'B' +--- +*/ + +class A : A.B +{ + interface B {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10624.d b/gcc/testsuite/gdc.test/fail_compilation/ice10624.d new file mode 100644 index 00000000000..883b98ed118 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10624.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10624.d(38): Error: need member function opCmp() for struct Tuple!(Msg) to compare +fail_compilation/ice10624.d(48): Error: template instance ice10624.Variant.handler!(Tuple!(Msg)) error instantiating +fail_compilation/ice10624.d(21): instantiated from here: opAssign!(Tuple!(Msg)) +--- +*/ + +struct Msg {} + +struct Tuple(Specs...) +{ + Specs expand; + alias expand this; +} + +void main() +{ + Variant data; + data = Tuple!Msg(); + +} + +struct Variant +{ + ptrdiff_t function() fptr = &handler!(void); + + static ptrdiff_t handler(A : void)() + { + return 0; + } + static ptrdiff_t handler(A)() + { + A* zis; + A* rhsPA; + { + return *zis < *rhsPA ? -1 : 1; + // Tuple!(Msg) < Tuple!(Msg) + // Tuple!(Msg).expand < Tuple!(Msg).expand + // -> should be error + } + return 0; + } + + Variant opAssign(T)(T rhs) + { + fptr = &handler!(T); + return this; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10651.d b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d new file mode 100644 index 00000000000..51e0a728ca0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10651.d(11): Error: can only throw class objects derived from Throwable, not type `int*` +--- +*/ + +void main() +{ + alias T = int; + throw new T(); // ICE +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10713.d b/gcc/testsuite/gdc.test/fail_compilation/ice10713.d new file mode 100644 index 00000000000..9ef07b34027 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10713.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10713.d(10): Error: no property 'nonExistingField' for type 'S' +--- +*/ + +struct S +{ + void f(typeof(this.nonExistingField) a) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d new file mode 100644 index 00000000000..a7529dc63cd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -c +/* +TEST_OUTPUT: +--- +fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop` +--- +*/ + +import imports.foo10727a; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d new file mode 100644 index 00000000000..958b5069329 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -c +/* +TEST_OUTPUT: +--- +fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop` +--- +*/ + +import imports.foo10727b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10770.d b/gcc/testsuite/gdc.test/fail_compilation/ice10770.d new file mode 100644 index 00000000000..5b0659a6b01 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10770.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10770.d(13): Error: enum ice10770.E2 is forward referenced looking for base type +fail_compilation/ice10770.d(13): while evaluating: `static assert(is(E2 e == enum))` +--- +*/ + +enum E1 : int; +static assert(is(E1 e == enum) && is(e == int)); + +enum E2; +static assert(is(E2 e == enum)); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d new file mode 100644 index 00000000000..1ddad18eba5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10922.d(9): Error: function ice10922.__lambda4 (const(uint) n) is not callable using argument types () +--- +*/ + +auto fib = (in uint n) pure nothrow { + enum self = __traits(parent, {}); + return (n < 2) ? n : self(n - 1) + self(n - 2); +}; + +void main() +{ + auto n = fib(39); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10938.d b/gcc/testsuite/gdc.test/fail_compilation/ice10938.d new file mode 100644 index 00000000000..2b3eab52ea3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10938.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10938.d(12): Error: no property 'opts' for type 'ice10938.C' +--- +*/ + +class C +{ + this() + { + this.opts["opts"] = 1; + } + + auto opDispatch(string field : "opts")() + { + return this.opts; // ICE -> compile time error + } +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10949.d b/gcc/testsuite/gdc.test/fail_compilation/ice10949.d new file mode 100644 index 00000000000..e81cf979549 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10949.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice10949.d(12): Deprecation: Using the result of a comma expression is deprecated +fail_compilation/ice10949.d(12): Error: array index 3 is out of bounds `[5, 5][0 .. 2]` +fail_compilation/ice10949.d(12): Error: array index 17 is out of bounds `[2, 3][0 .. 2]` +fail_compilation/ice10949.d(12): while evaluating: `static assert((((([5, 5][3] + global - global) * global / global % global >> global & global | global) ^ global) == 9 , [2, 3][17]) || [3, 3, 3][9] is 4 && [[1, 2, 3]][4].length)` +--- +*/ + +int global; +static assert((((((([5,5][3] + global - global)*global/global%global)>>global) &global|global)^global) == 9, [2,3][17]) || ([3,3,3][9] is 4) && ([[1,2,3]][4]).length); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11086.d b/gcc/testsuite/gdc.test/fail_compilation/ice11086.d new file mode 100644 index 00000000000..0b2ee3060e3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11086.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11086.d(10): Error: template instance foo!A template 'foo' is not defined +--- +*/ + +struct A +{ + foo!(A) l1,l2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11136.d b/gcc/testsuite/gdc.test/fail_compilation/ice11136.d new file mode 100644 index 00000000000..84defb938e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11136.d @@ -0,0 +1,9 @@ +// EXTRA_SOURCES: imports/bar11136.d +/* +TEST_OUTPUT: +--- +fail_compilation/imports/bar11136.d(1): Error: package name 'ice11136' conflicts with usage as a module name in file fail_compilation/ice11136.d +--- +*/ + +module ice11136; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11153.d b/gcc/testsuite/gdc.test/fail_compilation/ice11153.d new file mode 100644 index 00000000000..6a1b89ba776 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11153.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11153.d(11): Error: function declaration without return type. (Note that constructors are always named `this`) +fail_compilation/ice11153.d(11): Error: no identifier for declarator `foo()` +--- +*/ + +struct S +{ + foo(T)() {} + // Parser creates a TemplateDeclaration object with ident == NULL +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11404.d b/gcc/testsuite/gdc.test/fail_compilation/ice11404.d new file mode 100644 index 00000000000..c3f1ce608bc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11404.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11404.d(10): Error: can't have associative array of (int, int) +--- +*/ +template TypeTuple(TL...) { alias TL TypeTuple; } +void main() +{ + TypeTuple!(int, int)[string] my_map; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice1144.d b/gcc/testsuite/gdc.test/fail_compilation/ice1144.d new file mode 100644 index 00000000000..68563b67127 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice1144.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice1144.d(14): Error: undefined identifier `a` +fail_compilation/ice1144.d(23): Error: template instance ice1144.testHelper!("hello", "world") error instantiating +--- +*/ + +// Issue 1144 - ICE(template.c) template mixin causes DMD crash + +char[] testHelper(A ...)() +{ + char[] result; + foreach (t; a) + { + result ~= "int " ~ t ~ ";\n"; + } + return result; +} + +void main() +{ + mixin(testHelper!("hello", "world")()); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11472.d b/gcc/testsuite/gdc.test/fail_compilation/ice11472.d new file mode 100644 index 00000000000..f5b767f2a25 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11472.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11472.d(13): Error: template instance fun2!fun fun2 is not a template declaration, it is a function +fail_compilation/ice11472.d(18): Error: template instance ice11472.fun1!(fun3) error instantiating +--- +*/ + +void fun3() {} +void fun2(string a) {} +void fun1(alias fun=fun3)() +{ + "a".fun2!fun; +} + +void main() +{ + fun1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11513a.d b/gcc/testsuite/gdc.test/fail_compilation/ice11513a.d new file mode 100644 index 00000000000..576c84550cf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11513a.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/imports/ice11513x.d(1): Error: package name 'ice11513a' conflicts with usage as a module name in file fail_compilation/ice11513a.d +--- +*/ + +module ice11513a; + +import imports.ice11513x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11513b.d b/gcc/testsuite/gdc.test/fail_compilation/ice11513b.d new file mode 100644 index 00000000000..dab09b87e87 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11513b.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/imports/ice11513y.d(1): Error: package name 'ice11513b' conflicts with usage as a module name in file fail_compilation/ice11513b.d +--- +*/ + +module ice11513b; + +import imports.ice11513y; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11518.d b/gcc/testsuite/gdc.test/fail_compilation/ice11518.d new file mode 100644 index 00000000000..cfceb64ed6b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11518.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11518.d(17): Error: class ice11518.B matches more than one template declaration: +fail_compilation/ice11518.d(12): B(T : A!T) +and +fail_compilation/ice11518.d(13): B(T : A!T) +--- +*/ + +class A(T) {} +class B(T : A!T) {} +class B(T : A!T) {} + +void main() +{ + new B!(A!void); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11552.d b/gcc/testsuite/gdc.test/fail_compilation/ice11552.d new file mode 100644 index 00000000000..43fba406133 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11552.d @@ -0,0 +1,17 @@ +/* +REQUIRED_ARGS: -o- +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/ice11552.d(14): Error: label `label` is undefined +fail_compilation/ice11552.d(17): called from here: test11552() +fail_compilation/ice11552.d(17): while evaluating: `static assert(test11552())` +--- +*/ + +int test11552() +{ + goto label; + return 1; +} +static assert(test11552()); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11553.d b/gcc/testsuite/gdc.test/fail_compilation/ice11553.d new file mode 100644 index 00000000000..8fd0975399f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11553.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11553.d(22): Error: recursive template expansion while looking for A!().A() +--- +*/ + + +template A(alias T) +{ + template A() + { + alias A = T!(); + } +} + +template B() +{ + alias B = A!(.B); +} + +static if (A!B) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11626.d b/gcc/testsuite/gdc.test/fail_compilation/ice11626.d new file mode 100644 index 00000000000..5dc5d5c1e66 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11626.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11626.d(8): Error: undefined identifier `Bar` +--- +*/ + +void foo(in ref Bar) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11726.d b/gcc/testsuite/gdc.test/fail_compilation/ice11726.d new file mode 100644 index 00000000000..e9d98c5f095 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11726.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11726.d(16): Error: undefined identifier `x` +--- +*/ + +struct S +{ + auto opDispatch(string fn, Args...)(Args args) + { + } +} + +void main() { + S().reserve(x.foo()); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11755.d b/gcc/testsuite/gdc.test/fail_compilation/ice11755.d new file mode 100644 index 00000000000..86ce6f69979 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11755.d @@ -0,0 +1,30 @@ +// REQUIRED_ARGS: -w +/* +TEST_OUTPUT: +--- +fail_compilation/ice11755.d(20): Error: '!<>=' is not defined for array comparisons +fail_compilation/ice11755.d(21): Error: use '==' for non-floating comparisons rather than floating point operator '!<>' +fail_compilation/ice11755.d(22): Error: use '!=' for non-floating comparisons rather than floating point operator '<>' +fail_compilation/ice11755.d(23): Error: '<>=' is not defined for array comparisons +fail_compilation/ice11755.d(24): Error: use '<=' for non-floating comparisons rather than floating point operator '!>' +fail_compilation/ice11755.d(25): Error: use '<' for non-floating comparisons rather than floating point operator '!>=' +fail_compilation/ice11755.d(26): Error: use '>=' for non-floating comparisons rather than floating point operator '!<' +fail_compilation/ice11755.d(27): Error: use '>' for non-floating comparisons rather than floating point operator '!<=' +fail_compilation/ice11755.d(28): Error: floating point operator '<>=' always returns true for non-floating comparisons +fail_compilation/ice11755.d(29): Error: floating point operator '!<>=' always returns false for non-floating comparisons +--- +*/ +void main() +{ + int[] a, b; + auto r4 = a !<>= b; // TOKunord + auto r2 = a !<> b; // TOKue + auto r1 = a <> b; // TOKlg + auto r3 = a <>= b; // TOKleg + auto r8 = a !> b; // TOKule + auto r7 = a !>= b; // TOKul + auto r6 = a !< b; // TOKuge + auto r5 = a !<= b; // TOKug + assert((5 <>= 3) == 1); + assert((5 !<>= 3) == 0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11790.d b/gcc/testsuite/gdc.test/fail_compilation/ice11790.d new file mode 100644 index 00000000000..34b2002d950 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11790.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11790.d(8): Error: cannot pass type string as a function argument +--- +*/ + +string[string] crash = new string[string]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11793.d b/gcc/testsuite/gdc.test/fail_compilation/ice11793.d new file mode 100644 index 00000000000..e9453a30b44 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11793.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11793.d(11): Error: circular reference to 'ice11793.Outer.outer' +--- +*/ + +class Outer +{ + int foo; + Outer outer = new Outer(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11822.d b/gcc/testsuite/gdc.test/fail_compilation/ice11822.d new file mode 100644 index 00000000000..4ec46c3a2f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11822.d @@ -0,0 +1,33 @@ + + +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/ice11822.d(32): Deprecation: function ice11822.d is deprecated +fail_compilation/ice11822.d(21): instantiated from here: S!(__lambda1) +fail_compilation/ice11822.d(32): instantiated from here: g!((n) => d(i)) +--- +*/ + +struct S(alias pred) +{ + this(int) { pred(1); } + void f() { pred(2); } +} + +auto g(alias pred)() +{ + return S!pred(3); +} + +deprecated bool d(int) +{ + return true; +} + +auto h() +{ + int i; + return g!(n => d(i))(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11849b.d b/gcc/testsuite/gdc.test/fail_compilation/ice11849b.d new file mode 100644 index 00000000000..ef9380f7689 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11849b.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11849b.d(11): Error: circular reference to enum base type `DWORD1` +fail_compilation/ice11849b.d(11): Error: DWORD1 is used as a type +fail_compilation/ice11849b.d(16): Error: circular reference to enum base type `typeof(DWORD2)` +--- +*/ +enum REG_DWORD = 1; + +enum : DWORD1 +{ + DWORD1 = REG_DWORD +} + +enum : typeof(DWORD2) +{ + DWORD2 = REG_DWORD +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11850.d b/gcc/testsuite/gdc.test/fail_compilation/ice11850.d new file mode 100644 index 00000000000..9d1f172a50e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11850.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11850.d(14): Error: incompatible types for ((a) < ([0])): 'uint[]' and 'int[]' +fail_compilation/imports/a11850.d(9): instantiated from here: FilterResult!(__lambda1, uint[][]) +fail_compilation/ice11850.d(14): instantiated from here: filter!(uint[][]) +--- +*/ + +import imports.a11850 : filter; + +void main() +{ + filter!(a => a < [0])([[0u]]); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11919.d b/gcc/testsuite/gdc.test/fail_compilation/ice11919.d new file mode 100644 index 00000000000..700561043d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11919.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11919.d(17): Error: cannot interpret foo at compile time +fail_compilation/imports/a11919.d(4): Error: template instance a11919.doBar!(Foo).doBar.zoo!(t) error instantiating +fail_compilation/imports/a11919.d(11): instantiated from here: doBar!(Foo) +fail_compilation/ice11919.d(25): instantiated from here: doBar!(Bar) +--- +*/ + +import imports.a11919; + +enum foo; + +class Foo +{ + @foo bool _foo; +} + +class Bar : Foo {} + +void main() +{ + auto bar = new Bar(); + bar.doBar; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11922.d b/gcc/testsuite/gdc.test/fail_compilation/ice11922.d new file mode 100644 index 00000000000..0999aeac6b5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11922.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11922.d(11): Error: undefined identifier `a` +fail_compilation/ice11922.d(17): Error: template instance ice11922.S.f!int error instantiating +--- +*/ + +struct S +{ + auto f(B)(B) { return a; } +} + +void main() +{ + S s; + s.f(5); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11926.d b/gcc/testsuite/gdc.test/fail_compilation/ice11926.d new file mode 100644 index 00000000000..97ac4336502 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11926.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11926.d(11): Error: no identifier for declarator `const(a)` +fail_compilation/ice11926.d(12): Error: no identifier for declarator `const(b)` +--- +*/ + +enum +{ + const a = 1, + const b = 2 +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11944.d b/gcc/testsuite/gdc.test/fail_compilation/ice11944.d new file mode 100644 index 00000000000..c72d9f0de5c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11944.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11944.d(12): Error: template instance doCommand!(func) does not match template declaration doCommand(f, T)(f, T arg) +--- +*/ + +void func(int var) {} + +void doCommand(f, T)(f, T arg) {} + +auto var = &doCommand!func; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11963.d b/gcc/testsuite/gdc.test/fail_compilation/ice11963.d new file mode 100644 index 00000000000..9046f093512 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11963.d @@ -0,0 +1 @@ +A("")= diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11965.d b/gcc/testsuite/gdc.test/fail_compilation/ice11965.d new file mode 100644 index 00000000000..8c036ee9690 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11965.d @@ -0,0 +1 @@ +u[{b*A, diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11967.d b/gcc/testsuite/gdc.test/fail_compilation/ice11967.d new file mode 100644 index 00000000000..93b81309020 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11967.d @@ -0,0 +1 @@ +[F(%g{@ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11968.d b/gcc/testsuite/gdc.test/fail_compilation/ice11968.d new file mode 100644 index 00000000000..ce0d9fcf97f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11968.d @@ -0,0 +1 @@ +void main() { delete __FILE__ ; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11969.d b/gcc/testsuite/gdc.test/fail_compilation/ice11969.d new file mode 100644 index 00000000000..918ea4ada85 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11969.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice11969.d(9): Error: undefined identifier `index` +fail_compilation/ice11969.d(10): Error: undefined identifier `cond` +fail_compilation/ice11969.d(11): Error: undefined identifier `msg` +--- +*/ +void test1() { mixin ([index]); } +void test2() { mixin (assert(cond)); } +void test3() { mixin (assert(0, msg)); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11974.d b/gcc/testsuite/gdc.test/fail_compilation/ice11974.d new file mode 100644 index 00000000000..d9f2f3007e0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11974.d @@ -0,0 +1 @@ +void main() { 0 = __LINE__ ^^ [ 0 ] ; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11982.d b/gcc/testsuite/gdc.test/fail_compilation/ice11982.d new file mode 100644 index 00000000000..251dada4bc3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11982.d @@ -0,0 +1 @@ +void main() { new scope ( funk ) function } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12040.d b/gcc/testsuite/gdc.test/fail_compilation/ice12040.d new file mode 100644 index 00000000000..2307e9422aa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12040.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12040.d(8): Error: circular reference to 'ice12040.lol' +--- +*/ + +bool[lol.length] lol; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12158.d b/gcc/testsuite/gdc.test/fail_compilation/ice12158.d new file mode 100644 index 00000000000..7b8d38d4cec --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12158.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12158.d(7): Error: module object import 'nonexisting' not found +--- +*/ +import object : nonexisting; +auto x = nonexisting.init; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12174.d b/gcc/testsuite/gdc.test/fail_compilation/ice12174.d new file mode 100644 index 00000000000..81fef2d7f57 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12174.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12174.d(12): Error: no property 'sum' for type 'int[]' +fail_compilation/ice12174.d(20): Error: CTFE failed because of previous errors in this +fail_compilation/ice12174.d(13): called from here: filter([1, 2, 3]) +--- +*/ + +void main() +{ + enum foo3 = (int n) => [1,2,3].sum; + enum bar3 = [1,2,3].filter!(n => n % foo3(n) == 0); +} + +template filter(alias pred) +{ + auto filter(Range)(Range rs) + { + return FilterResult!(pred, Range)(rs); + } +} + +private struct FilterResult(alias pred, R) +{ + R _input; + + this(R r) + { + _input = r; + while (_input.length && !pred(_input[0])) + { + _input = _input[1..$]; + } + } + + @property bool empty() { return _input.length == 0; } + + @property auto ref front() + { + return _input[0]; + } + + void popFront() + { + do + { + _input = _input[1..$]; + } while (_input.length && !pred(_input[0])); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12235.d b/gcc/testsuite/gdc.test/fail_compilation/ice12235.d new file mode 100644 index 00000000000..1bf55b90ac3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12235.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12235.d(14): Error: forward reference to inferred return type of function '__lambda1' +fail_compilation/ice12235.d(15): Error: forward reference to inferred return type of function '__lambda1' +fail_compilation/ice12235.d(15): while evaluating pragma(msg, __lambda1.mangleof) +--- +*/ + +void main() +{ + (){ + int x; + enum s = __traits(parent, x).mangleof; + pragma(msg, __traits(parent, x).mangleof); + }(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12350.d b/gcc/testsuite/gdc.test/fail_compilation/ice12350.d new file mode 100644 index 00000000000..3ac3751d2c2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12350.d @@ -0,0 +1,31 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12350.d(15): Error: type MyUDC has no value +fail_compilation/ice12350.d(30): Error: template instance ice12350.testAttrs!(MyStruct) error instantiating +--- +*/ + + +enum MyUDC; + +struct MyStruct +{ + int a; + @MyUDC int b; +} + +void testAttrs(T)(const ref T t) +if (is(T == struct)) +{ + foreach (name; __traits(allMembers, T)) + { + auto tr = __traits(getAttributes, __traits(getMember, t, name)); + } +} + +void main() +{ + MyStruct s; + testAttrs(s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12362.d b/gcc/testsuite/gdc.test/fail_compilation/ice12362.d new file mode 100644 index 00000000000..2c662c050d2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12362.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12362.d(12): Error: cannot interpret foo at compile time +--- +*/ + +enum foo; + +void main() +{ + enum bar = foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12397.d b/gcc/testsuite/gdc.test/fail_compilation/ice12397.d new file mode 100644 index 00000000000..015e0230092 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12397.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12397.d(12): Error: undefined identifier `tokenLookup` +--- +*/ + +struct DSplitter +{ + enum Token : int + { + max = tokenLookup.length + } + + immutable string[Token.max] tokenText; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12497.d b/gcc/testsuite/gdc.test/fail_compilation/ice12497.d new file mode 100644 index 00000000000..ab95e81d5b7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12497.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12497.d(15): Error: string expected for argument to mixin, not (foo()) of type void +fail_compilation/ice12497.d(17): Error: string expected for argument to mixin, not (foo()) of type void +--- +*/ + +void foo() {} + +void main() +{ + struct S + { + mixin(foo()); // MixinDeclaration + } + mixin(foo()); // MixinStatement +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12501.d b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d new file mode 100644 index 00000000000..f57980d7bc3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d @@ -0,0 +1,44 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12501.d(29): Error: function ice12501.foo (int value) is not callable using argument types (int, int) +fail_compilation/ice12501.d(29): Error: function ice12501.foo (int value) is not callable using argument types (int, int) +fail_compilation/ice12501.d(43): Error: template instance ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[]) error instantiating +--- +*/ + +struct Tuple(T...) +{ + alias Types = T; + T field; + alias field this; +} +Tuple!A tuple(A...)(A args) { return typeof(return)(args); } + +template reduce(fun...) +{ + auto reduce(Args...)(Args args) + { + alias seed = args[0]; + alias r = args[1]; + Args[0] result = seed; + for (; r.length != 0; r = r[1..$]) + { + foreach (i, Unused; Args[0].Types) + { + result[i] = fun[i](result[i], r[0]); + } + } + return result; + } +} + +int foo(int value) +{ + return value; +} + +void main() +{ + reduce!(foo, foo)(tuple(0, 0), [ 1 ]); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12534.d b/gcc/testsuite/gdc.test/fail_compilation/ice12534.d new file mode 100644 index 00000000000..6820f394a75 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12534.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12534.d(14): Error: static assert `is(exprs[0 .. 0])` is false +--- +*/ + +alias TypeTuple(T...) = T; + +void main() +{ + int x, y; + alias exprs = TypeTuple!(x, y); + static assert(is(exprs[0..0])); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12539.d b/gcc/testsuite/gdc.test/fail_compilation/ice12539.d new file mode 100644 index 00000000000..e1ad9941b1d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12539.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12539.d(15): Error: array index [0] is outside array bounds [0 .. 0] +--- +*/ + +alias TypeTuple(E...) = E; + +void main () +{ + int[string] map; + + alias Foo = TypeTuple!(); + auto a = map[Foo[0]]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12574.d b/gcc/testsuite/gdc.test/fail_compilation/ice12574.d new file mode 100644 index 00000000000..362c359de59 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12574.d @@ -0,0 +1,54 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12574.d(40): Error: tuple index 2 exceeds length 2 +fail_compilation/ice12574.d(53): Error: template instance ice12574.reduce!("a", "a").reduce!(Tuple!(int, int, int)) error instantiating +--- +*/ + +struct Tuple(T...) +{ + alias Types = T; + T field; + alias field this; +} +Tuple!A tuple(A...)(A args) { return typeof(return)(args); } + +template binaryFun(alias fun) +{ + static if (is(typeof(fun) : string)) + { + auto binaryFun(ElementType1, ElementType2)(auto ref ElementType1 __a, auto ref ElementType2 __b) + { + mixin("alias "~"a"~" = __a ;"); + mixin("alias "~"b"~" = __b ;"); + return mixin(fun); + } + } + else + { + alias binaryFun = fun; + } +} + +template reduce(fun...) +{ + auto reduce(Seed)(Seed result) + { + foreach (i, Unused; Seed.Types) + { + result[i] = binaryFun!(fun[i])(1, 1); // here + } + return result; + } +} + +int foo(int value) +{ + return value; +} + +void main() +{ + reduce!("a", "a")(tuple(1, 1, 1)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12581.d b/gcc/testsuite/gdc.test/fail_compilation/ice12581.d new file mode 100644 index 00000000000..d2b0ba3398d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12581.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12581.d(21): Error: undefined identifier `undef` +--- +*/ + +struct S +{ + int[3] a; + alias a this; +} +struct T +{ + S s; + alias s this; +} +void main() +{ + T x; + x[] = (undef = 1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12673.d b/gcc/testsuite/gdc.test/fail_compilation/ice12673.d new file mode 100644 index 00000000000..57f0ec00c25 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12673.d @@ -0,0 +1,4 @@ +void main() +{ + static assert(__traits(compiles, { abcd(); })); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12727.d b/gcc/testsuite/gdc.test/fail_compilation/ice12727.d new file mode 100644 index 00000000000..027894c51e9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12727.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +---- +fail_compilation/ice12727.d(16): Error: alias ice12727.IndexTuple!(1, 0).IndexTuple recursive alias declaration +fail_compilation/ice12727.d(23): Error: template instance ice12727.IndexTuple!(1, 0) error instantiating +fail_compilation/ice12727.d(27): instantiated from here: Matrix!(float, 3) +fail_compilation/ice12727.d(28): instantiated from here: Vector!(float, 3) +---- +*/ + +template IndexTuple(int e, int s = 0, T...) +{ + static if (s == e) + alias IndexTuple = T; + else + alias IndexTuple = IndexTuple!(e); +} + +struct Matrix(T, int N = M) +{ + pure decomposeLUP() + { + foreach (j; IndexTuple!(1)) {} + } +} + +alias Vector(T, int M) = Matrix!(T, M); +alias Vector3 = Vector!(float, 3); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12827.d b/gcc/testsuite/gdc.test/fail_compilation/ice12827.d new file mode 100644 index 00000000000..8270c1fe85b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12827.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12827.d(10): Error: circular initialization of variable 'ice12827.Test.i' +--- +*/ + +struct Test +{ + immutable int i = i; +} + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12836.d b/gcc/testsuite/gdc.test/fail_compilation/ice12836.d new file mode 100644 index 00000000000..39a1c39ec0c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12836.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12836.d(9): Error: undefined identifier `C` +fail_compilation/ice12836.d(9): Error: undefined identifier `K` +--- +*/ + +immutable C L = 1 << K; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12838.d b/gcc/testsuite/gdc.test/fail_compilation/ice12838.d new file mode 100644 index 00000000000..c1edd4f9c7c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12838.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12838.d(27): Error: cannot implicitly convert expression `1` of type `int` to `string` +--- +*/ + +struct Tuple(T...) +{ + T field; + alias field this; +} + +struct Data +{ + string a; +} + +template toTuple(T) +{ + mixin(`alias toTuple = Tuple!(string);`); +} + +void main() +{ + toTuple!Data a; + a[0] = 1; // ICE! +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12841.d b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d new file mode 100644 index 00000000000..564b661babc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12841.d(23): Error: taskPool().amap(Args...)(Args args) is not an lvalue +fail_compilation/ice12841.d(24): Error: amap(Args...)(Args args) is not an lvalue +--- +*/ + +@property TaskPool taskPool() @trusted { return new TaskPool; } + +final class TaskPool +{ + template amap(functions...) + { + auto amap(Args...)(Args args) + { + } + } +} + +void main() +{ + auto dg = &(taskPool.amap!"a.result()"); + auto fp = &(TaskPool.amap!"a.result()"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12850.d b/gcc/testsuite/gdc.test/fail_compilation/ice12850.d new file mode 100644 index 00000000000..2e6a66c851a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12850.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12850.d(12): Error: cannot implicitly convert expression `0` of type `int` to `string` +--- +*/ +alias TypeTuple(TL...) = TL; + +void main() +{ + int[string] arr; + alias staticZip = TypeTuple!(arr[0]); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12902.d b/gcc/testsuite/gdc.test/fail_compilation/ice12902.d new file mode 100644 index 00000000000..e5ada0947de --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12902.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12902.d(20): Error: variable ice12902.main.__dollar type void is inferred from initializer s.opDollar(), and variables cannot be of type void +fail_compilation/ice12902.d(20): Error: expression s.opDollar() is void and has no value +--- +*/ + +struct S +{ + void opDollar() { } + void opIndex() { } + void opIndexAssign() { } + void opSliceAssign() { } +} + +void main() +{ + S s; + s[] = s[$]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12907.d b/gcc/testsuite/gdc.test/fail_compilation/ice12907.d new file mode 100644 index 00000000000..9f758dbaefe --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12907.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice12907.d(10): Error: template lambda has no type +--- +*/ + +auto f(void function() g) +{ + return x => (*g)(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13024.d b/gcc/testsuite/gdc.test/fail_compilation/ice13024.d new file mode 100644 index 00000000000..bf826775b90 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13024.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13024.d(15): Error: cannot implicitly convert expression `t.x` of type `A` to `B` +--- +*/ + +enum A { a } +enum B { b } +struct T { A x; B y; } +void main() +{ + T t; + auto r1 = [cast(int)(t.x), cast(int)(t.y)]; // OK + auto r3 = [t.x, t.y]; // crash +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13027.d b/gcc/testsuite/gdc.test/fail_compilation/ice13027.d new file mode 100644 index 00000000000..04ccdf3e4f7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13027.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13027.d(9): Error: template instance b!"c" template 'b' is not defined +--- +*/ +void main() +{ + scope a = b!"c"; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13081.d b/gcc/testsuite/gdc.test/fail_compilation/ice13081.d new file mode 100644 index 00000000000..126ce9fe5e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13081.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13081.d(17): Error: undefined identifier `node` +fail_compilation/ice13081.d(17): Error: undefined identifier `data` +fail_compilation/ice13081.d(17): Error: undefined identifier `node` +fail_compilation/ice13081.d(28): Error: template instance ice13081.Cube!(SparseDataStore) error instantiating +--- +*/ + +struct Cube(StorageT) +{ + StorageT datastore; + alias datastore this; + auto seed() + { + this[] = node.data ? data : node.data; + } +} + +class SparseDataStore +{ + auto opSlice() {} +} + +void main() +{ + Cube!SparseDataStore c; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13131.d b/gcc/testsuite/gdc.test/fail_compilation/ice13131.d new file mode 100644 index 00000000000..13b5aff9d5b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13131.d @@ -0,0 +1,20 @@ +// EXTRA_SOURCES: imports/a13131parameters.d imports/a13131elec.d +/* +TEST_OUTPUT: +--- ++A ++B +fail_compilation/imports/a13131elec.d(10): Error: template instance elecConnOf!gconn template 'elecConnOf' is not defined +-B +-A +--- +*/ + +void main() +{ + struct Connectivity {} + auto L = Connectivity(); + + import imports.a13131elec; // [1] import + L.initElec; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13220.d b/gcc/testsuite/gdc.test/fail_compilation/ice13220.d new file mode 100644 index 00000000000..3affd54858f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13220.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13220.d(22): Error: template instance test!0 does not match template declaration test(T)() +--- +*/ + +struct Tuple(T...) +{ + T field; + alias field this; +} + +template test(T) +{ + bool test() { return false; }; +} + +void main() +{ + Tuple!bool t; + t[0] = test!0(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13221.d b/gcc/testsuite/gdc.test/fail_compilation/ice13221.d new file mode 100644 index 00000000000..b00169e4098 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13221.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13221.d(20): Error: variable r cannot be read at compile time +--- +*/ + +struct Tuple(T...) +{ + T field; + alias field this; +} + +template test(T) {} + +void main() +{ + foreach (r; 0 .. 0) + { + enum i = r; + test!(Tuple!bool[i]); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13225.d b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d new file mode 100644 index 00000000000..b042431ed70 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13225.d(12): Error: mixin ice13225.S.M!(function (S _param_0) => 0) does not match template declaration M(T) +fail_compilation/ice13225.d(16): Error: undefined identifier `undefined` +--- +*/ +mixin template M(T) {} + +struct S +{ + mixin M!((typeof(this)) => 0); +} +struct T +{ + mixin M!(() => undefined); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13311.d b/gcc/testsuite/gdc.test/fail_compilation/ice13311.d new file mode 100644 index 00000000000..b86681b21f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13311.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/imports/a13311.d(8): Error: undefined identifier `PieceTree` +--- +*/ +module ice13311; + +struct TextPiece +{ + import imports.a13311; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13356.d b/gcc/testsuite/gdc.test/fail_compilation/ice13356.d new file mode 100644 index 00000000000..9225d55147f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13356.d @@ -0,0 +1,41 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13356.d(32): Error: template instance Algebraic!(Tuple!(List)) recursive template expansion +fail_compilation/ice13356.d(15): Error: template instance ice13356.isPrintable!(List) error instantiating +fail_compilation/ice13356.d(33): instantiated from here: Tuple!(List) +--- +*/ + +struct Tuple(Types...) +{ + Types expand; + alias expand this; + + static if (isPrintable!(Types[0])) + { + } +} + +// T == Tuple!List, and accessing its .init will cause unresolved forward reference +enum bool isPrintable(T) = is(typeof({ T t; })); + +struct Algebraic(AllowedTypesX...) +{ + alias AllowedTypes = AllowedTypesX; + + double x; // dummy for the syntax Payload(d) +} + +struct List +{ + alias Payload = Algebraic!( + Tuple!(List) + ); + + Payload payload; + + this(double d) { payload = Payload(d); } +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13382.d b/gcc/testsuite/gdc.test/fail_compilation/ice13382.d new file mode 100644 index 00000000000..e5f1ac0f3f9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13382.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13382.d(18): Error: incompatible types for ((a) == (0)): 'int[]' and 'int' +fail_compilation/ice13382.d(19): Error: incompatible types for ((a) >= (0)): 'int[]' and 'int' +fail_compilation/ice13382.d(20): Error: incompatible types for ((0) == (a)): 'int' and 'int[]' +fail_compilation/ice13382.d(21): Error: incompatible types for ((0) >= (a)): 'int' and 'int[]' +fail_compilation/ice13382.d(22): Error: incompatible types for ((a) is (0)): 'int[]' and 'int' +fail_compilation/ice13382.d(23): Error: incompatible types for ((a) !is (0)): 'int[]' and 'int' +fail_compilation/ice13382.d(24): Error: incompatible types for ((0) is (a)): 'int' and 'int[]' +fail_compilation/ice13382.d(25): Error: incompatible types for ((0) !is (a)): 'int' and 'int[]' +--- +*/ + +void main () +{ + int[] a; + if (a == 0) {} + if (a >= 0) {} + if (0 == a) {} + if (0 >= a) {} + if (a is 0) {} + if (a !is 0) {} + if (0 is a) {} + if (0 !is a) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13385.d b/gcc/testsuite/gdc.test/fail_compilation/ice13385.d new file mode 100644 index 00000000000..b2039b279b8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13385.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13385.d(9): Error: protection attribute 'package(a)' does not bind to one of ancestor packages of module `ice13385` +--- +*/ +module ice13385; + +package(a) void foo() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13459.d b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d new file mode 100644 index 00000000000..35420fdad17 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13459.d(12): Error: undefined identifier `B` +fail_compilation/ice13459.d(18): Error: none of the overloads of 'opSlice' are callable using argument types (int, int), candidates are: +fail_compilation/ice13459.d(11): ice13459.A.opSlice() +--- +*/ +struct A +{ + auto opSlice() {} + auto opSlice() { return B; } +} + +void main() +{ + auto df = A(); + foreach (fi; df[0..0]) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13465a.d b/gcc/testsuite/gdc.test/fail_compilation/ice13465a.d new file mode 100644 index 00000000000..23f73b78ce5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13465a.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -o- +// EXTRA_SOURCES: imports/a13465.d +/* +TEST_OUTPUT: +--- +fail_compilation/imports/a13465.d(10): Error: cannot infer type from template instance isMaskField!() +fail_compilation/ice13465a.d(17): Error: template instance imports.a13465.isMatchingMaskField!() error instantiating +--- +*/ + +module ice13465a; + +import imports.a13465; + +auto createCheckpointMixins() +{ + enum b = isMatchingMaskField!(); +} + +immutable checkpointMixins = createCheckpointMixins; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13465b.d b/gcc/testsuite/gdc.test/fail_compilation/ice13465b.d new file mode 100644 index 00000000000..db0cce1a56a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13465b.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -o- +// EXTRA_SOURCES: imports/b13465.d +/* +TEST_OUTPUT: +--- +fail_compilation/imports/b13465.d(10): Error: cannot infer type from template instance isMaskField!() +fail_compilation/ice13465b.d(17): Error: template instance imports.b13465.isMatchingMaskField!() error instantiating +--- +*/ + +module ice13465b; + +import imports.b13465; + +auto createCheckpointMixins() +{ + enum b = isMatchingMaskField!(); +} + +immutable checkpointMixins = createCheckpointMixins; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13563.d b/gcc/testsuite/gdc.test/fail_compilation/ice13563.d new file mode 100644 index 00000000000..4179007e6d1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13563.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13563.d(23): Error: undefined identifier `z` in module `ice13563` +--- +*/ + +struct Payload +{ + void opIndex(K)(K i) {} + void opIndexAssign(T, N)(T value, N i) {} +} + +struct Value +{ + Payload payload; + alias payload this; +} + +void main() +{ + Value v; + v["name"] = .z(); // ICE + //v["name"] = z(); // OK + //v.opIndex("name") = .z(); // OK + //v.payload["name"] = .z(); // OK +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice1358.d b/gcc/testsuite/gdc.test/fail_compilation/ice1358.d new file mode 100644 index 00000000000..ee71f8cb345 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice1358.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice1358.d(29): Error: invalid UTF character \U80000000 +--- +*/ + +// Issue 1358 - ICE(root.c) on Unicode codepoints greater than 0x7FFFFFFF + +/* 1358. Assertion failure: '0' on line 1548 in file '..\root\root.c' +This one is trivial. +PATCH(lexer.c, Lexer::escapeSequence()). +--- lexer.c (revision 24) ++++ lexer.c (working copy) +@@ -1281,8 +1281,10 @@ + break; + } + } +- if (ndigits != 2 && !utf_isValidDchar(v)) ++ if (ndigits != 2 && !utf_isValidDchar(v)) { + error("invalid UTF character \\U%08x", v); ++ v = 0; // prevent ICE ++ } + c = v; + } + else + +*/ +auto bla = "\U80000000"; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13644.d b/gcc/testsuite/gdc.test/fail_compilation/ice13644.d new file mode 100644 index 00000000000..87e56e428fb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13644.d @@ -0,0 +1,19 @@ + +struct Tuple(T...) +{ + T field; + alias field this; +} + +Tuple!(string, string)[] foo() +{ + Tuple!(string, string)[] res; + return res; +} + +void main() +{ + foreach (string k2, string v2; foo()) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13788.d b/gcc/testsuite/gdc.test/fail_compilation/ice13788.d new file mode 100644 index 00000000000..7d04d9db705 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13788.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13788.d(11): Error: pragma mangle string expected for mangled name +fail_compilation/ice13788.d(12): Error: string expected for mangled name, not (1) of type int +fail_compilation/ice13788.d(13): Error: pragma mangle zero-length string not allowed for mangled name +fail_compilation/ice13788.d(14): Error: pragma mangle mangled name characters can only be of type char +--- +*/ + +pragma(mangle) void f1(); +pragma(mangle, 1) void f2(); +pragma(mangle, "") void f3(); +pragma(mangle, "a"w) void f4(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13816.d b/gcc/testsuite/gdc.test/fail_compilation/ice13816.d new file mode 100644 index 00000000000..6745d7b68e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13816.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13816.d(15): Error: alias ice13816.ItemProperty!().ItemProperty recursive alias declaration +fail_compilation/ice13816.d(20): Error: template instance ice13816.ItemProperty!() error instantiating +--- +*/ + +alias TypeTuple(T...) = T; + +template ItemProperty() +{ + static if (true) + { + alias ItemProperty = TypeTuple!(ItemProperty!()); + } +} +void main() +{ + alias items = ItemProperty!(); + + enum num = items.length; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13835.d b/gcc/testsuite/gdc.test/fail_compilation/ice13835.d new file mode 100644 index 00000000000..6bacdb04e48 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13835.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13835.d(15): Error: value of 'this' is not known at compile time +fail_compilation/ice13835.d(21): Error: template instance ice13835.Foo!int error instantiating +--- +*/ + +class Foo(T) +{ + private T* _data; + + final private void siftUp(int position) nothrow + { + static T crash = *(this._data + position); + } +} + +void main() +{ + auto heap = new Foo!(int); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13921.d b/gcc/testsuite/gdc.test/fail_compilation/ice13921.d new file mode 100644 index 00000000000..8793e5cb10b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13921.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13921.d(13): Error: undefined identifier `undefined_identifier` +fail_compilation/ice13921.d(25): Error: template instance ice13921.S!string error instantiating +--- +*/ + +struct S(N) +{ + void fun() + { + undefined_identifier; + // or anything that makes the instantiation fail + } + +} + +void test(T)(S!T) +{ +} + +void main() +{ + S!string g; + test(g); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13987.d b/gcc/testsuite/gdc.test/fail_compilation/ice13987.d new file mode 100644 index 00000000000..26d3d300a89 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13987.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice13987.d(9): Error: cannot use array to initialize S +--- +*/ + +struct S {} +S s = [{}]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14055.d b/gcc/testsuite/gdc.test/fail_compilation/ice14055.d new file mode 100644 index 00000000000..5e60e88cdf8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14055.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14055.d(16): Error: uninitialized variable 'foo' cannot be returned from CTFE +--- +*/ + +struct S +{ + static returnsFoo() + { + uint[1] foo = void; + return foo; + } + + static enum fooEnum = returnsFoo(); + static uint[1] fooArray = fooEnum[]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14096.d b/gcc/testsuite/gdc.test/fail_compilation/ice14096.d new file mode 100644 index 00000000000..654cfcc7989 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14096.d @@ -0,0 +1,41 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14096.d(29): Error: cannot access frame pointer of ice14096.main.Baz!((i) => i).Baz +fail_compilation/ice14096.d(23): Error: template instance ice14096.foo!(Tuple!(Baz!((i) => i))).foo.bar!(t) error instantiating +fail_compilation/ice14096.d(40): instantiated from here: foo!(Tuple!(Baz!((i) => i))) +--- +*/ + +struct Tuple(Types...) +{ + Types expand; + alias expand this; + alias field = expand; +} +Tuple!T tuple(T...)(T args) +{ + return typeof(return)(args); +} + +auto foo(T)(T t) +{ + bar!t(); +} + +auto bar(alias s)() +{ + // default construction is not possible for: Tuple!(Baz!(i => i)) + typeof(s) p; +} + +struct Baz(alias f) +{ + void g() {} +} + +void main() +{ + auto t = tuple(Baz!(i => i)()); + foo(t); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14116.d b/gcc/testsuite/gdc.test/fail_compilation/ice14116.d new file mode 100644 index 00000000000..52cd8ce5a10 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14116.d @@ -0,0 +1,11 @@ +// EXTRA_SOURCES: imports/a14116.d +/* +TEST_OUTPUT: +--- +fail_compilation/imports/a14116.d(3): Error: module ice14116.ice14116 from file fail_compilation/ice14116.d must be imported with 'import ice14116.ice14116;' +--- +*/ + +module ice14116.ice14116; + +void foo() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d new file mode 100644 index 00000000000..916a7b97a09 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14130.d(10): Error: undefined identifier `Undef` +fail_compilation/ice14130.d(14): Error: template ice14130.foo cannot deduce function from argument types !()(int), candidates are: +fail_compilation/ice14130.d(10): ice14130.foo(R, F = Undef)(R r, F s = 0) +--- +*/ + +F foo(R, F = Undef)(R r, F s = 0) {} + +void main() +{ + 0.foo; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14146.d b/gcc/testsuite/gdc.test/fail_compilation/ice14146.d new file mode 100644 index 00000000000..1e4f9a976e5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14146.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14146.d(15): Error: constructor ice14146.Array.this default constructor for structs only allowed with @disable, no body, and no parameters +--- +*/ + +struct RangeT(A) +{ + A[1] XXXouter; +} + +struct Array +{ + this() + { + } + + alias Range = RangeT!Array; + + bool opEquals(Array) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14177.d b/gcc/testsuite/gdc.test/fail_compilation/ice14177.d new file mode 100644 index 00000000000..b487c2b347e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14177.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +---- +fail_compilation/ice14177.d(8): Error: alias ice14177.Primitive recursive alias declaration +---- +*/ + +alias Primitive = Atom*; +alias Atom = Primitive; + +void main() +{ + Atom atom; + atom; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14185.d b/gcc/testsuite/gdc.test/fail_compilation/ice14185.d new file mode 100644 index 00000000000..9e29cdb5b91 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14185.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14185.d(12): Error: cannot implicitly convert expression `this` of type `Mutexed` to `Mutexed*` +--- +*/ + +struct Mutexed +{ + auto acquire () + { + return Lock (this); + } + alias acquire this; + + struct Lock + { + Mutexed* source; + } +} +void main () +{ + Mutexed x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14272.d b/gcc/testsuite/gdc.test/fail_compilation/ice14272.d new file mode 100644 index 00000000000..d9f642dd3cc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14272.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14272.d(11): Error: circular initialization of variable 'ice14272.A14272!1.A14272.tag' +fail_compilation/ice14272.d(14): Error: template instance ice14272.A14272!1 error instantiating +--- +*/ + +struct A14272(int tag) +{ + enum int tag = tag; +} + +alias a14272 = A14272!1; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14424.d b/gcc/testsuite/gdc.test/fail_compilation/ice14424.d new file mode 100644 index 00000000000..29fe6661201 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14424.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -o- -unittest +/* +TEST_OUTPUT: +--- +fail_compilation/ice14424.d(12): Error: `tuple` has no effect in expression `tuple(__unittestL3_$n$)` +--- +*/ + +void main() +{ + import imports.a14424; + __traits(getUnitTests, imports.a14424); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14446.d b/gcc/testsuite/gdc.test/fail_compilation/ice14446.d new file mode 100644 index 00000000000..ee0bfc450b2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14446.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: +// EXTRA_SOURCES: extra-files/a14446.d + +/* +TEST_OUTPUT: +--- +fail_compilation/extra-files/a14446.d(5): Error: module x14446 from file fail_compilation/ice14446.d must be imported with 'import x14446;' +--- +*/ + +module x14446; + +struct CDB {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14621.d b/gcc/testsuite/gdc.test/fail_compilation/ice14621.d new file mode 100644 index 00000000000..15690b743d6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14621.d @@ -0,0 +1,30 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14621.d(22): Error: static assert `false` is false +fail_compilation/ice14621.d(28): instantiated from here: erroneousTemplateInstantiation!() +--- +*/ + +void main() +{ + S s; + s.foo(); +} + +struct S +{ + float[] array; + alias array this; + + template erroneousTemplateInstantiation() + { + static assert(false); + } + + void foo() + { + S ret; + ret[] = erroneousTemplateInstantiation!(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14642.d b/gcc/testsuite/gdc.test/fail_compilation/ice14642.d new file mode 100644 index 00000000000..07d496311fd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14642.d @@ -0,0 +1,52 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14642.d(47): Error: undefined identifier `errorValue` +fail_compilation/ice14642.d(23): Error: template instance ice14642.X.NA!() error instantiating +--- +*/ + +alias TypeTuple(T...) = T; + +struct X +{ + static struct NA() + { + X x; + + void check() + { + x.func(); + } + } + + alias na = NA!(); + + auto func() + { + Y* p; + p.func(); + } +} + +struct Y +{ + mixin Mix; +} + +template Mix() +{ + void func() + { + auto z = Z(null); + } +} + +struct Type(size_t v) {} + +enum errVal = errorValue; + +struct Z +{ + Type!errVal v; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14844.d b/gcc/testsuite/gdc.test/fail_compilation/ice14844.d new file mode 100644 index 00000000000..d49a1d1dc47 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14844.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14844.d(20): Error: template `opDispatch(string name)` has no members +--- +*/ + +struct Typedef +{ + template opDispatch(string name) + { + static if (true) + { + } + } +} + +void runUnitTestsImpl() +{ + foreach (x; __traits(allMembers, Typedef.opDispatch)) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14923.d b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d new file mode 100644 index 00000000000..86e3b2a2071 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14923.d(21): Error: function ice14923.parse (C a) is not callable using argument types (A) +fail_compilation/ice14923.d(21): instantiated from here: bar!((b) => parse(b)) +--- +*/ + +auto bar(alias fun)() +{ + size_t counter; + scope(exit) counter++; + + Object a2; + if (auto ai = cast(A)a2) return fun(ai); + if (auto ai = cast(B)a2) return fun(ai); +} + +void parse(C a) +{ + bar!(b => parse(b))(); +} + +class A {} + +class C {} + +class B : C {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14929.d b/gcc/testsuite/gdc.test/fail_compilation/ice14929.d new file mode 100644 index 00000000000..01edc0d5e2b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14929.d @@ -0,0 +1,96 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice14929.d(45): Error: cast(Node)(*this.current).items[this.index] is not an lvalue +fail_compilation/ice14929.d(88): Error: template instance ice14929.HashMap!(ulong, int).HashMap.opBinaryRight!"in" error instantiating +fail_compilation/ice14929.d(92): instantiated from here: HashmapComponentStorage!int +fail_compilation/ice14929.d(92): Error: template instance ice14929.isComponentStorage!(HashmapComponentStorage!int, int) error instantiating +fail_compilation/ice14929.d(92): while evaluating: `static assert(isComponentStorage!(HashmapComponentStorage!int, int))` +--- +*/ + +struct HashMap(K, V) +{ + V* opBinaryRight(string op)(K key) const if (op == "in") + { + size_t index; + foreach (ref node; buckets[index].range) + { + return &(node.value); + } + return null; + } + + struct Node + { + K key; + V value; + } + + alias Bucket = UnrolledList!(Node); + Bucket[] buckets; +} + +struct UnrolledList(T) +{ + Range range() const pure + { + return Range(_front); + } + + static struct Range + { + ref T front() const @property + { + return cast(T) current.items[index]; + } + void popFront() pure + { + } + bool empty() const pure @property + { + return true; + } + const(Node)* current; + size_t index; + } + + Node* _front; + + static struct Node + { + ContainerStorageType!T[10] items; + } +} + +template ContainerStorageType(T) +{ + alias ContainerStorageType = T; +} + +template isComponentStorage(CS, C) +{ + enum bool isComponentStorage = is(typeof( + (inout int = 0) + { + CS cs = CS.init; + ulong eid; + cs.add(eid, c); + })); +} + +struct HashmapComponentStorage(ComponentType) +{ + private HashMap!(ulong, ComponentType) components; + + void add(ulong eid, ComponentType component) + { + assert(eid !in components); + } +} + +static assert(isComponentStorage!(HashmapComponentStorage!int, int)); + +void main() +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15002.d b/gcc/testsuite/gdc.test/fail_compilation/ice15002.d new file mode 100644 index 00000000000..50d13dd9bd4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15002.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15002.d(10): Error: array index 5 is out of bounds `x[0 .. 3]` +fail_compilation/ice15002.d(10): Error: array index 5 is out of bounds `x[0 .. 3]` +--- +*/ + +int[][3] x = []; +int* p = &x[5][0]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15092.d b/gcc/testsuite/gdc.test/fail_compilation/ice15092.d new file mode 100644 index 00000000000..0064ae37d97 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15092.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15092.d(13): Error: struct ice15092.A.S conflicts with struct ice15092.A.S at fail_compilation/ice15092.d(12) +fail_compilation/ice15092.d(16): Error: class ice15092.A.C conflicts with class ice15092.A.C at fail_compilation/ice15092.d(15) +fail_compilation/ice15092.d(19): Error: interface ice15092.A.I conflicts with interface ice15092.A.I at fail_compilation/ice15092.d(18) +--- +*/ + +class A +{ + struct S {} + struct S {} + + class C {} + class C {} + + interface I {} + interface I {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15127.d b/gcc/testsuite/gdc.test/fail_compilation/ice15127.d new file mode 100644 index 00000000000..afc6419725f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15127.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15127.d(17): Error: basic type expected, not `struct` +fail_compilation/ice15127.d(17): Error: identifier expected for template value parameter +fail_compilation/ice15127.d(17): Error: found `struct` when expecting `)` +fail_compilation/ice15127.d(17): Error: found `ExampleStruct` when expecting `=` +fail_compilation/ice15127.d(17): Error: semicolon expected following auto declaration, not `)` +fail_compilation/ice15127.d(17): Error: declaration expected, not `)` +--- +*/ + +struct ExampleStruct(S) { } + +template ExampleTemplate(K) +{ + enum ExampleTemplate(struct ExampleStruct(K)) = K; +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15172.d b/gcc/testsuite/gdc.test/fail_compilation/ice15172.d new file mode 100644 index 00000000000..dc8ae9444fa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15172.d @@ -0,0 +1,33 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15172.d(14): Error: constructor ice15172.ThreadError.this no match for implicit super() call in constructor +--- +*/ + +// 1. ClassDeclaration.semantic +class ThreadError : Error +{ + // 2. FuncDeclaration.semantic + // 4. FuncDeclaration.semantic3 + // --> error happens + this(string) + { + } +} + +// 3. FuncDeclaration.semantic +// 5. FuncDeclaration.semantic3 +void onThreadError() +{ + // 6. NewExp.semantic + // --> cd.members.errors == false, cd.members.semantic3Errors == true + // BUT, The ThreadError class constructor is not a template function, so + // the errors inside its function body won't be associated with the validness of this NewExp. + // Therefore, converting the semantic3Error to ErrorExp is not correct. + // 7. ctfeInterpret + // Finally, FuncDeclaration::interpret may encounter a function which is semantic3Errors == true. So + // 7a. functionSemantic3() should return false if semantic3Errors is true. + // 7b. the function body errors may not happen during ctfeInterpret call and global.errors could be unincremented. + __gshared auto ThreadError = new ThreadError(null); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15239.d b/gcc/testsuite/gdc.test/fail_compilation/ice15239.d new file mode 100644 index 00000000000..6512d858c17 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15239.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15239.d(21): Error: cannot interpret opDispatch!"foo" at compile time +fail_compilation/ice15239.d(21): Error: bad type/size of operands '__error' +--- +*/ + +struct T +{ + template opDispatch(string Name, P...) + { + static void opDispatch(P) {} + } +} + +void main() +{ + asm + { + call T.foo; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15317.d b/gcc/testsuite/gdc.test/fail_compilation/ice15317.d new file mode 100644 index 00000000000..2ab3ef9344c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15317.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/ice15317.d(11): Error: undefined identifier `fun` +--- +*/ + +void main() +{ + alias f = fun; + auto x1 = &f; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15332.d b/gcc/testsuite/gdc.test/fail_compilation/ice15332.d new file mode 100644 index 00000000000..41411782bf4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15332.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15332.d(16): Error: need 'this' for 'fun' of type 'int()' +fail_compilation/ice15332.d(17): Error: need 'this' for 'var' of type 'int' +--- +*/ + +class C +{ + int fun() { return 5; } + int var; + + void test() + { + int a1 = function() { return fun; }(); + int a2 = function() { return var; }(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15441.d b/gcc/testsuite/gdc.test/fail_compilation/ice15441.d new file mode 100644 index 00000000000..ef4369bac17 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15441.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15441.d(24): Error: variable ice15441.main.__front$n$ type void is inferred from initializer __r$n$.front(), and variables cannot be of type void +fail_compilation/ice15441.d(24): Error: expression __r$n$.front() is void and has no value +fail_compilation/ice15441.d(24): Error: `s1.front` is void and has no value +fail_compilation/ice15441.d(27): Error: cannot infer argument types, expected 1 argument, not 2 +--- +*/ + +struct S1 +{ + auto front()() {} +} + +struct S2 +{ + auto front()() { return 1; } +} + +void main() +{ + S1 s1; + foreach (p, e; s1) {} + + S2 s2; + foreach (p, e; s2) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15688.d b/gcc/testsuite/gdc.test/fail_compilation/ice15688.d new file mode 100644 index 00000000000..92810e68888 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15688.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +--- +fail_compilation/ice15688.d(12): Error: undefined identifier `mappings` +fail_compilation/ice15688.d(12): Error: function expected before (), not 0 of type int +--- +*/ + +void main() +{ + (mappings, 0)(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15788.d b/gcc/testsuite/gdc.test/fail_compilation/ice15788.d new file mode 100644 index 00000000000..e81f25bd8b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15788.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15788.d(17): Error: none of the overloads of 'iota' are callable using argument types !()(S, S) +--- +*/ + +import imports.range15788 : iota; + +void iota() {} + +struct S {} + +void main() +{ + S s; + iota(s, s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15816.d b/gcc/testsuite/gdc.test/fail_compilation/ice15816.d new file mode 100644 index 00000000000..b9e1e475b69 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15816.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/imports/a15816.d(3): Error: anonymous classes not allowed +--- +*/ + +class A +{ + import imports.a15816; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15855.d b/gcc/testsuite/gdc.test/fail_compilation/ice15855.d new file mode 100644 index 00000000000..407288b17f0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15855.d @@ -0,0 +1,3 @@ +// REQUIRED_ARGS: -o- + +a[{for diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15922.d b/gcc/testsuite/gdc.test/fail_compilation/ice15922.d new file mode 100644 index 00000000000..c9739a178e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice15922.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice15922.d(23): Error: function ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false.correctedInsert has no return statement, but is expected to return a value of type int +fail_compilation/ice15922.d(21): Error: template instance ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false error instantiating +fail_compilation/ice15922.d(26): instantiated from here: ValidSparseDataStore!int +fail_compilation/ice15922.d(14): Error: need 'this' for 'insert' of type 'pure @nogc @safe int()' +fail_compilation/ice15922.d(26): Error: template instance ice15922.StorageAttributes!(ValidSparseDataStore!int) error instantiating +--- +*/ + +template StorageAttributes(Store) +{ + enum hasInsertMethod = Store.insert; + enum hasFullSlice = Store.init[]; +} +struct ValidSparseDataStore(DataT) +{ + DataT insert() + { + correctedInsert!(false); + } + DataT correctedInsert(bool CorrectParents)() {} + auto opSlice() inout {} +} +alias BasicCubeT = StorageAttributes!(ValidSparseDataStore!int); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice16035.d b/gcc/testsuite/gdc.test/fail_compilation/ice16035.d new file mode 100644 index 00000000000..9ad1a4e8535 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice16035.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice16035.d(18): Error: forward reference to inferred return type of function call 'this.a[0].toString()' +fail_compilation/ice16035.d(13): Error: template instance ice16035.Value.get!string error instantiating +--- +*/ + +struct Value +{ + auto toString() inout + { + get!string; + } + + T get(T)() + { + a[0].toString(); + } + + const(Value)* a; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice17074.d b/gcc/testsuite/gdc.test/fail_compilation/ice17074.d new file mode 100644 index 00000000000..b41b25abb0b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice17074.d @@ -0,0 +1,39 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice17074.d(9): Error: identifier expected for C++ namespace +fail_compilation/ice17074.d(9): Error: found `cast` when expecting `)` +fail_compilation/ice17074.d(9): Error: declaration expected, not `)` +--- +*/ +extern(C++, cast) void ice_keyword(); + +/* +TEST_OUTPUT: +--- +fail_compilation/ice17074.d(19): Error: identifier expected for C++ namespace +fail_compilation/ice17074.d(19): Error: found `__overloadset` when expecting `)` +fail_compilation/ice17074.d(19): Error: declaration expected, not `)` +--- +*/ +extern(C++, std.__overloadset) void ice_std_keyword(); + +/* +TEST_OUTPUT: +--- +fail_compilation/ice17074.d(29): Error: identifier expected for C++ namespace +fail_compilation/ice17074.d(29): Error: found `...` when expecting `)` +fail_compilation/ice17074.d(29): Error: declaration expected, not `)` +--- +*/ +extern(C++, ...) void ice_token(); + +/* +TEST_OUTPUT: +--- +fail_compilation/ice17074.d(39): Error: identifier expected for C++ namespace +fail_compilation/ice17074.d(39): Error: found `*` when expecting `)` +fail_compilation/ice17074.d(39): Error: declaration expected, not `)` +--- +*/ +extern(C++, std.*) void ice_std_token(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice17690.d b/gcc/testsuite/gdc.test/fail_compilation/ice17690.d new file mode 100644 index 00000000000..853b7952a79 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice17690.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice17690.d(9): Error: undefined identifier `x` +--- +*/ +void main(){ + scope(exit) int x=3; + assert(x==3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice17831.d b/gcc/testsuite/gdc.test/fail_compilation/ice17831.d new file mode 100644 index 00000000000..15b8502172b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice17831.d @@ -0,0 +1,78 @@ +// REQUIRED_ARGS: -d +/* +TEST_OUTPUT: +--- +fail_compilation/ice17831.d(19): Error: case variable `i` declared at fail_compilation/ice17831.d(17) cannot be declared in switch body +fail_compilation/ice17831.d(33): Error: case variable `i` declared at fail_compilation/ice17831.d(31) cannot be declared in switch body +fail_compilation/ice17831.d(48): Error: case variable `i` declared at fail_compilation/ice17831.d(45) cannot be declared in switch body +fail_compilation/ice17831.d(61): Error: case variable `i` declared at fail_compilation/ice17831.d(60) cannot be declared in switch body +fail_compilation/ice17831.d(73): Error: case variable `i` declared at fail_compilation/ice17831.d(72) cannot be declared in switch body +--- + */ + +void test17831a() +{ + switch (0) + { + foreach (i; 0 .. 5) + { + case i: + break; + } + default: + break; + } +} + +void test17831b() +{ + switch (0) + { + for (int i = 0; i < 5; i++) + { + case i: + break; + } + default: + break; + } +} + +void test17831c() +{ + switch (0) + { + int i = 0; + while (i++ < 5) + { + case i: + break; + } + default: + break; + } +} + +void test17831d() +{ + switch (0) + { + int i = 0; + case i: + break; + default: + break; + } +} + +void test17831e() +{ + switch (0) + { + static int i = 0; + case i: + break; + default: + break; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice2843.d b/gcc/testsuite/gdc.test/fail_compilation/ice2843.d new file mode 100644 index 00000000000..c0c379767e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice2843.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice2843.d(22): Error: incompatible types for ((1) is (typeid(int))): 'int' and 'object.TypeInfo' +--- +*/ + +// Issue 2843 - ICE(constfold.c) with is-expression with invalid dot-expression in is-expression involving typeid expression + +/* 2843 Assertion failure: '0' on line 863 in file 'constfold.c' +PATCH: constfold.c, line 861: +OLD: + }else + assert(0); +NEW: + }else if (e1->isConst() && e2->isConst()) { + // Comparing a SymExp with a literal, eg typeid(int) is 7.1; + cmp=0; // An error has already occurred. Prevent an ICE. + }else + assert(0); +*/ +bool b = 1 is typeid(int); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice4094.d b/gcc/testsuite/gdc.test/fail_compilation/ice4094.d new file mode 100644 index 00000000000..cd41e651121 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice4094.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice4094.d(11): Error: circular reference to variable 'ice4094.Zug!0.Zug.bahn' +fail_compilation/ice4094.d(19): Error: template instance ice4094.Zug!0 error instantiating +--- +*/ +// REQUIRED_ARGS: -d +struct Zug(int Z) +{ + const bahn = Bug4094!(0).hof.bahn; +} + +struct Bug4094(int Q) +{ + Zug!(0) hof; +} + +const a = Zug!(0).bahn; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice4983.d b/gcc/testsuite/gdc.test/fail_compilation/ice4983.d new file mode 100644 index 00000000000..1925c174dd9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice4983.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice4983.d(14): Error: circular reference to 'ice4983.Foo.dg' +--- +*/ + +struct Foo +{ + void bar() + { + } + + void delegate() dg = &Foo.init.bar; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice5996.d b/gcc/testsuite/gdc.test/fail_compilation/ice5996.d new file mode 100644 index 00000000000..eb2b53e8652 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice5996.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice5996.d(8): Error: undefined identifier `anyOldGarbage` +--- +*/ +auto bug5996() { + if (anyOldGarbage) {} + return 2; +} +enum uint h5996 = bug5996(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d new file mode 100644 index 00000000000..dad6491c5e9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d @@ -0,0 +1,30 @@ + + +/**************************************/ +// 9361 + +/* +TEST_OUTPUT: +--- +fail_compilation/ice6538.d(23): Error: expression super is not a valid template value argument +fail_compilation/ice6538.d(28): Error: template ice6538.D.foo cannot deduce function from argument types !()(), candidates are: +fail_compilation/ice6538.d(23): ice6538.D.foo()() if (Sym!(super)) +--- +*/ + +template Sym(alias A) +{ + enum Sym = true; +} + +class C {} +class D : C +{ + void foo()() if (Sym!(super)) {} +} +void test9361b() +{ + auto d = new D(); + d.foo(); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice7645.d b/gcc/testsuite/gdc.test/fail_compilation/ice7645.d new file mode 100644 index 00000000000..1aa3fad67a0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice7645.d @@ -0,0 +1,32 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice7645.d(28): Error: need 'this' for 't' of type 'char' +fail_compilation/ice7645.d(31): Error: need 'this' for 'fn' of type 'pure nothrow @nogc @safe void()' +--- +*/ + +class C +{ + class C2() + { + char t; + } +} + +struct S +{ + struct S2(T) + { + void fn() {} + } +} + +void main() +{ + C c; + auto v = c.C2!().t; + + S s; + s.S2!int.fn(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice7782.d b/gcc/testsuite/gdc.test/fail_compilation/ice7782.d new file mode 100644 index 00000000000..161995abb79 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice7782.d @@ -0,0 +1,4 @@ +import imports.ice7782algorithm; +import imports.ice7782range. imports.ice7782math; + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8100.d b/gcc/testsuite/gdc.test/fail_compilation/ice8100.d new file mode 100644 index 00000000000..1e7d56ba94f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8100.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8100.d(10): Error: no property 'Q' for type 'ice8100.Bar!bool' +fail_compilation/ice8100.d(11): Error: template instance ice8100.Foo!(Bar!bool) error instantiating +fail_compilation/ice8100.d(12): instantiated from here: Bar!bool +--- +*/ + +class Foo(T1) { T1.Q r; } +class Bar(T2) : Foo!(Bar!T2) {} +Bar!bool b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8255.d b/gcc/testsuite/gdc.test/fail_compilation/ice8255.d new file mode 100644 index 00000000000..d98e38ad9a4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8255.d @@ -0,0 +1,10 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8255.d(10): Error: function ice8255.F!(G).F.f (ref G _param_0) is not callable using argument types (G) +fail_compilation/ice8255.d(10): while evaluating pragma(msg, F().f(G())) +--- +*/ +struct G {} +struct F(T) { void f(ref T) {} } +pragma(msg, F!G().f(G.init)); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8309.d b/gcc/testsuite/gdc.test/fail_compilation/ice8309.d new file mode 100644 index 00000000000..5d5bb83298d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8309.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8309.d(10): Error: incompatible types for ((__lambda1) : (__lambda2)): 'double function() pure nothrow @nogc @safe' and 'int function() pure nothrow @nogc @safe' +--- +*/ + +void main() +{ + auto x = [()=>1.0, ()=>1]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8499.d b/gcc/testsuite/gdc.test/fail_compilation/ice8499.d new file mode 100644 index 00000000000..318883dc624 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8499.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8499.d(18): Error: undefined identifier `i` +--- +*/ + +struct Variant +{ + @property T get(T)() + { + struct X {} // necessary + } +} + +void main() +{ + (Variant()).get!(typeof(() => i)); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8511.d b/gcc/testsuite/gdc.test/fail_compilation/ice8511.d new file mode 100644 index 00000000000..873f8965ec2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8511.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8511.d(11): Error: enum ice8511.hypot.SQRTMAX is forward referenced looking for base type +fail_compilation/ice8511.d(12): Error: incompatible types for ((SQRTMAX) / (2)): cannot use '/' with types +--- +*/ + +real hypot() +{ + enum SQRTMAX; + SQRTMAX/2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8604.d b/gcc/testsuite/gdc.test/fail_compilation/ice8604.d new file mode 100644 index 00000000000..a734c2f24e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8604.d @@ -0,0 +1,7 @@ +struct StructFoo +{ + static if(i) { } + else enum z = ""; +} + +void main() { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8630.d b/gcc/testsuite/gdc.test/fail_compilation/ice8630.d new file mode 100644 index 00000000000..ef733dc864f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8630.d @@ -0,0 +1,3 @@ +auto map(alias func, R)(R r) { return r; } +typeof(v) foo(R)(R v) { return map!(p=>p)(v); } +void main() { foo([1]); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8711.d b/gcc/testsuite/gdc.test/fail_compilation/ice8711.d new file mode 100644 index 00000000000..c1439297f09 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8711.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8711.d(8): Error: cannot use array to initialize int function(int) +--- +*/ + +int function(int) foos = [x => 0]; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8742.d b/gcc/testsuite/gdc.test/fail_compilation/ice8742.d new file mode 100644 index 00000000000..480a2d7357a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8742.d @@ -0,0 +1,11 @@ +// PERMUTE_ARGS: +class C +{ + class D { } +} + +void main ( ) +{ + auto c = new C; + auto d = c.new class C.D { }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8795.d b/gcc/testsuite/gdc.test/fail_compilation/ice8795.d new file mode 100644 index 00000000000..29eabbfff46 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8795.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8795.d-mixin-14(14): Error: found `EOF` when expecting `(` +fail_compilation/ice8795.d-mixin-14(14): Error: expression expected, not `EOF` +fail_compilation/ice8795.d-mixin-14(14): Error: found `EOF` when expecting `)` +fail_compilation/ice8795.d-mixin-14(14): Error: found `EOF` instead of statement +fail_compilation/ice8795.d-mixin-15(15): Error: { } expected following `interface` declaration +fail_compilation/ice8795.d-mixin-15(15): Error: anonymous interfaces not allowed +--- +*/ +void main() +{ + mixin("switch"); + mixin("interface;"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8795b.d b/gcc/testsuite/gdc.test/fail_compilation/ice8795b.d new file mode 100644 index 00000000000..23004f457d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice8795b.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice8795b.d-mixin-8(8): Error: { } expected following `interface` declaration +fail_compilation/ice8795b.d-mixin-8(8): Error: anonymous interfaces not allowed +--- +*/ +mixin("interface;"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9013.d b/gcc/testsuite/gdc.test/fail_compilation/ice9013.d new file mode 100644 index 00000000000..116729fa55f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9013.d @@ -0,0 +1,5 @@ +void main() +{ + foreach (i; 0 .. missing) + int[] foo = cast(int[])[i]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9254a.d b/gcc/testsuite/gdc.test/fail_compilation/ice9254a.d new file mode 100644 index 00000000000..594b5ce54fa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9254a.d @@ -0,0 +1,12 @@ + +void main() +{ + foreach (divisor; !(2, 3, 4, 8, 7, 9)) + { + // ice in ForeachRangeStatement::blockExit() + foreach (v; 0..uint.max) {} + + // ice in WhileStatement::blockExit() + while (1) {} + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9254b.d b/gcc/testsuite/gdc.test/fail_compilation/ice9254b.d new file mode 100644 index 00000000000..c5a9944adb3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9254b.d @@ -0,0 +1,15 @@ + +class C +{ + synchronized void foo() + { + foreach(divisor; !(2, 3, 4, 8, 7, 9)) + { + // ice in ForeachRangeStatement::usesEH() + foreach (v; 0..uint.max) {} + + // ice in WhileStatement::usesEH() + while (1) {} + } + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9254c.d b/gcc/testsuite/gdc.test/fail_compilation/ice9254c.d new file mode 100644 index 00000000000..d816bbfc117 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9254c.d @@ -0,0 +1,14 @@ + +void main() +{ + foreach(divisor; !(2, 3, 4, 8, 7, 9)) + { + assert(0); + + // ice in ForeachRangeStatement::comeFrom() + foreach (v; 0..uint.max) {} + + // ice in WhileStatement::comeFrom() + while (1) {} + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9273a.d b/gcc/testsuite/gdc.test/fail_compilation/ice9273a.d new file mode 100644 index 00000000000..91f22d42f35 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9273a.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9273a.d(19): Error: constructor ice9273a.C.__ctor!().this no match for implicit super() call in constructor +fail_compilation/ice9273a.d(23): Error: template instance ice9273a.C.__ctor!() error instantiating +--- +*/ + +template CtorMixin() +{ + this(T)() {} +} +class B +{ + mixin CtorMixin!(); +} +class C : B +{ + this()() {} +} +void main() +{ + auto c = new C(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9273b.d b/gcc/testsuite/gdc.test/fail_compilation/ice9273b.d new file mode 100644 index 00000000000..1a779facbbf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9273b.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9273b.d(14): Error: constructor ice9273b.B.this no match for implicit super() call in constructor +--- +*/ + +class A +{ + this(T)() {} +} +class B : A +{ + this() {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d new file mode 100644 index 00000000000..0c95bd87257 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9284.d(14): Error: template ice9284.C.__ctor cannot deduce function from argument types !()(int), candidates are: +fail_compilation/ice9284.d(12): ice9284.C.__ctor()(string) +fail_compilation/ice9284.d(20): Error: template instance ice9284.C.__ctor!() error instantiating +--- +*/ + +class C +{ + this()(string) + { + this(10); + // delegating to a constructor which not exists. + } +} +void main() +{ + new C("hello"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9291.d b/gcc/testsuite/gdc.test/fail_compilation/ice9291.d new file mode 100644 index 00000000000..a662eaf21bb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9291.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9291.d(10): Error: undefined identifier `F` +--- +*/ + +void main() nothrow +{ + throw new F(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9338.d b/gcc/testsuite/gdc.test/fail_compilation/ice9338.d new file mode 100644 index 00000000000..292c05964fd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9338.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9338.d(13): Error: value of 'this' is not known at compile time +fail_compilation/ice9338.d(14): Error: value of 'this' is not known at compile time +--- +*/ + +class Foo +{ + void test() + { + enum members1 = makeArray(); + enum members2 = this.makeArray(); + } + + string[] makeArray() + { + return ["a"]; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9406.d b/gcc/testsuite/gdc.test/fail_compilation/ice9406.d new file mode 100644 index 00000000000..d8c0837699a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9406.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9406.d(21): Error: expression has no value +--- +*/ + +mixin template Mixin() { } + +struct S +{ + template t1() + { + mixin Mixin t1; + } +} + +void main() +{ + S s1; + s1.t1!(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9439.d b/gcc/testsuite/gdc.test/fail_compilation/ice9439.d new file mode 100644 index 00000000000..51b84e82d71 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9439.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9439.d(12): Error: this for foo needs to be type Derived not type ice9439.Base +fail_compilation/ice9439.d(12): while evaluating: `static assert((__error).foo())` +fail_compilation/ice9439.d(19): Error: template instance ice9439.Base.boo!(foo) error instantiating +--- +*/ + +class Base { + void boo(alias F)() { + static assert(F()); + } +} + +class Derived : Base { + int foo() { return 1; } + void bug() { + boo!(foo)(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9494.d b/gcc/testsuite/gdc.test/fail_compilation/ice9494.d new file mode 100644 index 00000000000..b2743e5a3d9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9494.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9494.d(10): Error: circular reference to variable 'ice9494.test' +fail_compilation/ice9494.d(14): Error: circular reference to variable 'ice9494.Foo.test' +fail_compilation/ice9494.d(19): Error: circular reference to variable 'ice9494.Bar.test' +--- +*/ + +int[test] test; // stack overflow + +class Foo +{ + int[this.test] test; // stack overflow +} + +struct Bar +{ + int[this.test] test; // stack overflow +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d new file mode 100644 index 00000000000..d6c9cdae0f3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d @@ -0,0 +1,37 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9540.d(34): Error: function ice9540.A.test.AddFront!(this, f).AddFront.dg (int _param_0) is not callable using argument types () +fail_compilation/ice9540.d(25): Error: template instance ice9540.A.test.AddFront!(this, f) error instantiating +--- +*/ + +template Tuple(E...) { alias E Tuple; } +alias Tuple!(int) Args; + +void main() { + (new A).test (); +} + +void test1 (int delegate (int) f) { f (-2); } + +class A +{ + int f (int a) { + return a; + } + + void test () { + test1 (&AddFront!(this, f)); + } +} + +template AddFront (alias ctx, alias fun) { + auto AddFront(Args args) { + auto dg (Args dgArgs) { + return fun (dgArgs); + } + dg.ptr = ctx; + return dg(args); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9545.d b/gcc/testsuite/gdc.test/fail_compilation/ice9545.d new file mode 100644 index 00000000000..846975afd3b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9545.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -o- +/* +TEST_OUTPUT: +---- +fail_compilation/ice9545.d(13): Error: type int has no value +---- +*/ + +struct S { template T(X) { alias T = X; } } + +void main() +{ + auto x1 = S.init.T!int; // ICE +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9759.d b/gcc/testsuite/gdc.test/fail_compilation/ice9759.d new file mode 100644 index 00000000000..300540cfeed --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9759.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9759.d(24): Error: mutable method ice9759.Json.opAssign is not callable using a const object +--- +*/ + +struct Json +{ + union + { + Json[] m_array; + Json[string] m_object; + } + + void opAssign(Json v) + { + } +} + +void bug() +{ + const(Json) r; + r = r.init; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9806.d b/gcc/testsuite/gdc.test/fail_compilation/ice9806.d new file mode 100644 index 00000000000..5f00fccf597 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9806.d @@ -0,0 +1,49 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9806.d(12): Error: undefined identifier `undefined_expr` +fail_compilation/ice9806.d(17): Error: template instance ice9806.S1!() error instantiating +fail_compilation/ice9806.d(13): Error: undefined identifier `undefined_expr` +fail_compilation/ice9806.d(19): Error: template instance ice9806.C1!() error instantiating +fail_compilation/ice9806.d(14): Error: undefined identifier `undefined_expr` +fail_compilation/ice9806.d(21): Error: template instance ice9806.I1!() error instantiating +--- +*/ +struct S1() { enum x = undefined_expr; } +class C1() { enum x = undefined_expr; } +class I1() { enum x = undefined_expr; } +void test1() { + static assert(!is(typeof(S1!().x))); + auto sx = S1!().x; + static assert(!is(typeof(C1!().x))); + auto cx = C1!().x; + static assert(!is(typeof(I1!().x))); + auto ix = I1!().x; +} + +// -------- +/* +TEST_OUTPUT: +--- +fail_compilation/ice9806.d(36): Error: undefined identifier `undefined_expr` +fail_compilation/ice9806.d(44): Error: template instance ice9806.S2!() error instantiating +fail_compilation/ice9806.d(37): Error: undefined identifier `undefined_expr` +fail_compilation/ice9806.d(46): Error: template instance ice9806.C2!() error instantiating +fail_compilation/ice9806.d(38): Error: undefined identifier `undefined_expr` +fail_compilation/ice9806.d(48): Error: template instance ice9806.I2!() error instantiating +--- +*/ +int foo2()() { return undefined_expr; } +int bar2()() { return undefined_expr; } +int baz2()() { return undefined_expr; } +struct S2() { enum x = foo2(); } +class C2() { enum x = bar2(); } +class I2() { enum x = baz2(); } +void test2() { + static assert(!is(typeof(S2!().x))); + auto sx = S2!().x; + static assert(!is(typeof(C2!().x))); + auto cx = C2!().x; + static assert(!is(typeof(I2!().x))); + auto ix = I2!().x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9865.d b/gcc/testsuite/gdc.test/fail_compilation/ice9865.d new file mode 100644 index 00000000000..846ba2e5914 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9865.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/ice9865.d(8): Error: alias ice9865.Baz recursive alias declaration +--- +*/ + +public import imports.ice9865b : Baz; +struct Foo { Baz f; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imphint.d b/gcc/testsuite/gdc.test/fail_compilation/imphint.d new file mode 100644 index 00000000000..1e1387cbae5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imphint.d @@ -0,0 +1,20 @@ +/* PERMUTE_ARGS: +--- +fail_compilation/imphint.d(14): Error: 'printf' is not defined, perhaps you need to import core.stdc.stdio; ? +fail_compilation/imphint.d(15): Error: 'writeln' is not defined, perhaps you need to import std.stdio; ? +fail_compilation/imphint.d(16): Error: 'sin' is not defined, perhaps you need to import std.math; ? +fail_compilation/imphint.d(17): Error: 'cos' is not defined, perhaps you need to import std.math; ? +fail_compilation/imphint.d(18): Error: 'sqrt' is not defined, perhaps you need to import std.math; ? +fail_compilation/imphint.d(19): Error: 'fabs' is not defined, perhaps you need to import std.math; ? +--- +*/ + +void foo() +{ + printf("hello world\n"); + writeln("hello world\n"); + sin(3.6); + cos(1.2); + sqrt(2.0); + fabs(-3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a10169.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a10169.d new file mode 100644 index 00000000000..91ec888fe06 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a10169.d @@ -0,0 +1,6 @@ +module imports.a10169; + +struct B +{ + private int x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a10528.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a10528.d new file mode 100644 index 00000000000..8d2e1dbaa77 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a10528.d @@ -0,0 +1,6 @@ +private enum string a = "asdfgh"; +private enum { b = "asdfgh" } + +struct S { private enum string c = "qwerty"; } +class C { private enum string d = "qwerty"; } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a11850.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a11850.d new file mode 100644 index 00000000000..c9a76821c83 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a11850.d @@ -0,0 +1,51 @@ +//import std.array, std.range; +module imports.a11850; + + +template filter(alias pred) +{ + auto filter(Range)(Range rs) + { + return FilterResult!(pred, Range)(rs); + } +} + + +private struct FilterResult(alias pred, Range) +{ + alias Range R; + R _input; + + + this(R r) + { + _input = r; + while (_input.length != 0 && !pred(_input[0])) + { + _input = _input[1..$]; + } + } + + + auto opSlice() { return this; } + + + @property bool empty() { return _input.length == 0; } + + + void popFront() + { + do + { + _input = _input[1..$]; + } while (_input.length != 0 && !pred(_input[0])); + } + + + @property auto ref front() + { + return _input[0]; + } +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a11919.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a11919.d new file mode 100644 index 00000000000..983147dee6d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a11919.d @@ -0,0 +1,17 @@ +void doBar(T)(T t) +{ + static if (t.tupleof.length) + if (zoo!t.length == 0) {} + static if (is(T B == super) + && is(B[0] == class) + && is(B[]) + ) + { + B[0] b = t; + doBar(b); + } +} +template zoo(alias t) +{ + enum zoo = __traits(getAttributes, t.tupleof); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a13131checkpoint.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a13131checkpoint.d new file mode 100644 index 00000000000..7c9a2b0ecda --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a13131checkpoint.d @@ -0,0 +1,18 @@ +module imports.a13131checkpoint; + +mixin(createGlobalsMixins); // [3] mixin + +auto createGlobalsMixins() // [4] semantic3 +{ + pragma(msg, "+A"); + enum fullModuleName = "imports.a13131parameters"; // necessary + mixin("import "~fullModuleName~";"); + foreach (e ; __traits(derivedMembers, mixin(fullModuleName))) + { + // [5] see imports.parameters (it's listed in command line) + static if ( __traits(compiles, mixin(`__traits(getAttributes, `~fullModuleName~`.`~e~`)`))) {} + } + pragma(msg, "-A"); + + return ""; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a13131elec.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a13131elec.d new file mode 100644 index 00000000000..658dbb531bd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a13131elec.d @@ -0,0 +1,10 @@ +module imports.a13131elec; + +import imports.a13131checkpoint; // [2] import + +void initElec(T)(T L) +{ + immutable cv = econn.velocities; // econn is invalid so generates ErrorExp +} + +alias econn = elecConnOf!gconn; // invalid declaration diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a13131parameters.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a13131parameters.d new file mode 100644 index 00000000000..4508d2fad14 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a13131parameters.d @@ -0,0 +1,14 @@ +module imports.a13131parameters; + +auto createParameterMixins() // auto is necessary to invoke semantic3 to calculate full signature +{ + pragma(msg, "+B"); + enum fullModuleName = "imports.a13131elec"; // necessary + mixin("import "~fullModuleName~";"); + foreach (e ; __traits(derivedMembers, mixin(fullModuleName))) + { + // will access yet-not semantic analyzed invalid symbol 'econn' in imports.elec + static if ( __traits(compiles, mixin(`__traits(getAttributes, `~fullModuleName~`.`~e~`)`))) {} + } + pragma(msg, "-B"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a13311.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a13311.d new file mode 100644 index 00000000000..b4f78a0a699 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a13311.d @@ -0,0 +1,9 @@ +module imports.a13311; + +import ice13311; + +class Z +{ + TextPiece piece; + this(PieceTree owner) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a13465.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a13465.d new file mode 100644 index 00000000000..684c3e11c99 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a13465.d @@ -0,0 +1,22 @@ +module imports.a13465; + +template isMaskField() +{ + import imports.a13465; +} + +template isMatchingMaskField() +{ + enum isMatchingMaskField = isMaskField!(); + + /* Semantic analysis journey came from isMatchingMaskField!() + * + * TemplateInstance('isMaskField!T')->semantic() + * TemplateInstance('isMaskField!T')->semantic2() <--- + * TemplateInstance::semantic() will run its semantic2() always. + * Import('import imports.ice1365a;')->semantic2() + * Module('imports.ice1365a')->semantic2() + * VarDeclaration('imports.ice1365a.isMatchingMaskField!().isMatchingMaskField')->semantic2() <--- + * The type field is yet NULL during type inference, then ICE happens. + */ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a14116.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a14116.d new file mode 100644 index 00000000000..42fc89d3fcc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a14116.d @@ -0,0 +1,5 @@ +module ice14116.a14116; + +import ice14116; + +void main() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a14235.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a14235.d new file mode 100644 index 00000000000..d2b6cb9fd1b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a14235.d @@ -0,0 +1,7 @@ +module imports.a14235; + +struct SomeThing(T...) +{ +} + +class SomeClass {} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d new file mode 100644 index 00000000000..d906bc74404 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d @@ -0,0 +1,19 @@ +module imports.a14407; + +deprecated class C +{ + private deprecated new (size_t, string) + { + return null; + } + private this(int) {} +} + +deprecated struct S +{ + private deprecated new (size_t, string) + { + return null; + } + private this(int) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a14424.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a14424.d new file mode 100644 index 00000000000..57312136d75 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a14424.d @@ -0,0 +1,3 @@ +module imports.a14424; + +unittest { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a15667.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a15667.d new file mode 100644 index 00000000000..bec79b65817 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a15667.d @@ -0,0 +1,18 @@ +module imports.a15667; + +template staticIndexOf(T) +{ + enum staticIndexOf = genericIndexOf!T; +} + +template genericIndexOf(args...) +{ + alias e = args; + alias tuple = args; + alias tail = tuple; + enum next = genericIndexOf!(e, tail); +} + +alias X = ; + +static if (staticIndexOf!X) diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a15816.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a15816.d new file mode 100644 index 00000000000..49316e21df2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a15816.d @@ -0,0 +1,5 @@ +module imports.a15816; + +class +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a313.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a313.d new file mode 100644 index 00000000000..d739afa75a8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a313.d @@ -0,0 +1,9 @@ +module imports.a313; + +private import imports.b313; +private static import imports.b313; +private static import b313 = imports.b313; + +private import imports.pkg313; + +private import core.stdc.stdio; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a314.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a314.d new file mode 100644 index 00000000000..fcf3157e9ad --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a314.d @@ -0,0 +1,5 @@ +module imports.a314; + +static import imports.c314; +import renamed = imports.c314; +import imports.c314 : bug; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/b13465.d b/gcc/testsuite/gdc.test/fail_compilation/imports/b13465.d new file mode 100644 index 00000000000..9700a9eac91 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/b13465.d @@ -0,0 +1,22 @@ +module imports.b13465; + +template isMaskField() +{ + import imports.b13465; +} + +template isMatchingMaskField() +{ + enum isMatchingMaskField = { enum n = isMaskField!(); return n; }(); + + /* Semantic analysis journey came from isMatchingMaskField!() + * + * TemplateInstance('isMaskField!T')->semantic() + * TemplateInstance('isMaskField!T')->semantic2() <--- + * TemplateInstance::semantic() should run its semantic2() in function body. + * Import('import imports.ice1365a;')->semantic2() + * Module('imports.ice1365a')->semantic2() + * VarDeclaration('imports.ice1365a.isMatchingMaskField!().isMatchingMaskField')->semantic2() <--- + * Cannot avoid this visiting, so we need to add a fix in VarDeclaration::semantic2(). + */ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/b313.d b/gcc/testsuite/gdc.test/fail_compilation/imports/b313.d new file mode 100644 index 00000000000..1834c997229 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/b313.d @@ -0,0 +1,4 @@ +module imports.b313; + +void bug() +{} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/b314.d b/gcc/testsuite/gdc.test/fail_compilation/imports/b314.d new file mode 100644 index 00000000000..89b62c3e983 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/b314.d @@ -0,0 +1,4 @@ +module imports.b314; + +package import renamedpkg = imports.c314; +package import imports.c314 : bugpkg=bug; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/bar11136.d b/gcc/testsuite/gdc.test/fail_compilation/imports/bar11136.d new file mode 100644 index 00000000000..1cb541bfedc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/bar11136.d @@ -0,0 +1 @@ +module ice11136.bar11136; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/c314.d b/gcc/testsuite/gdc.test/fail_compilation/imports/c314.d new file mode 100644 index 00000000000..5c43c8608e4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/c314.d @@ -0,0 +1,4 @@ +module imports.c314; + +void bug(string s) +{} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3a.d new file mode 100644 index 00000000000..85e6cd8c390 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3a.d @@ -0,0 +1 @@ +void foo() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3b.d new file mode 100644 index 00000000000..37ea7ae0387 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3b.d @@ -0,0 +1 @@ +private void foo(int) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3c.d b/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3c.d new file mode 100644 index 00000000000..93b4ac5fe12 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/checkimports3c.d @@ -0,0 +1 @@ +void foo(string) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag10089a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10089a.d new file mode 100644 index 00000000000..857c5ed8000 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10089a.d @@ -0,0 +1,8 @@ +module imports.diag10089a; + +struct chunks +{ + this(size_t size) + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag10089b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10089b.d new file mode 100644 index 00000000000..0e3c2ea5964 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10089b.d @@ -0,0 +1,5 @@ +module imports.diag10089b; + +void chunks(Source)(Source source, size_t chunkSize) +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag10141a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10141a.d new file mode 100644 index 00000000000..df775858ca4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10141a.d @@ -0,0 +1,26 @@ +module imports.diag10141a; + +import imports.diag10141b; + +string format() +{ + auto w = Appender!string(); + char[] digits = ['0']; + put(w, digits); + return null; +} + +template Tuple(Specs...) +{ + struct Tuple + { + Specs expand; + + enum x = format(); // in injectNameFields() + } +} + +private template Identity(alias T) +{ + alias T Identity; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag10141b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10141b.d new file mode 100644 index 00000000000..72ebce73196 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag10141b.d @@ -0,0 +1,55 @@ +module imports.diag10141b; + +template isSomeChar(T) { + enum isSomeChar = + is(immutable T == immutable char) || + is(immutable T == immutable wchar) || + is(immutable T == immutable dchar); +} + +struct Appender(A : T[], T) +{ + private template canPutItem(U) + { + enum bool canPutItem = + //isImplicitlyConvertible!(U, T) || + isSomeChar!T && isSomeChar!U; + } + private template canPutRange(Range) + { + enum bool canPutRange = + //isInputRange!Range && + is(typeof(Appender.init.put("a"d[0]))); + } + + /** + * Appends one item to the managed array. + */ + void put(U)(U item) if (canPutItem!U) + { + char[T.sizeof == 1 ? 4 : 2] encoded; + auto len = 1; + put(encoded[0 .. len]); // ! + } + + /** + * Appends an entire range to the managed array. + */ + void put(Range)(Range items) if (canPutRange!Range) + { + } +} + +void put(R, E)(ref R r, E e) +{ + static if (is(typeof(r.put(e)))) + { + r.put(e); + } + else + { + static assert(false, + "Cannot put a "~E.stringof~" into a "~R.stringof); + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag12598a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag12598a.d new file mode 100644 index 00000000000..dee00545254 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag12598a.d @@ -0,0 +1,3 @@ +module imports.diag12598a; + +struct lines { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210b.d new file mode 100644 index 00000000000..f83d122d844 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210b.d @@ -0,0 +1,6 @@ +module imports.diag9210b; + +import imports.diag9210c; +import imports.diag9210stdcomplex; + +interface B : A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210c.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210c.d new file mode 100644 index 00000000000..9c3f78956fe --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210c.d @@ -0,0 +1,4 @@ +module imports.diag9210c; + +import diag9210a; +interface C : A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d new file mode 100644 index 00000000000..58aa99a740f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d @@ -0,0 +1,17 @@ +module imports.diag9210stdcomplex; + +import imports.diag9210stdtraits; + +struct Complex(T) if (isFloatingPoint!T) +{ + T re; + T im; +} + +// Bugzilla 9210: Complex!real instantiation is incomplete in here, +// because its completion is deferred by an "undefined identifier" error in imports.diag9210b. +Complex!real expi(real y) +{ + return Complex!real(0, 0); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdtraits.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdtraits.d new file mode 100644 index 00000000000..f978047765f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdtraits.d @@ -0,0 +1,33 @@ +module imports.diag9210stdtraits; + +template FloatingPointTypeOf(T)// if (!is(T == enum)) +{ + inout( float) idx( inout( float) ); + inout(double) idx( inout(double) ); + inout( real) idx( inout( real) ); + shared(inout float) idx( shared(inout float) ); + shared(inout double) idx( shared(inout double) ); + shared(inout real) idx( shared(inout real) ); + + immutable( float) idy( immutable( float) ); + immutable(double) idy( immutable(double) ); + immutable( real) idy( immutable( real) ); + + static if (is(typeof(idx(T.init)) X)) + { + alias X FloatingPointTypeOf; + } + else static if (is(typeof(idy(T.init)) X)) + { + alias X FloatingPointTypeOf; + } + else + { + static assert(0, T.stringof~" is not a floating point type"); + } +} + +template isFloatingPoint(T) +{ + enum bool isFloatingPoint = is(FloatingPointTypeOf!T); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/dip22a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22a.d new file mode 100644 index 00000000000..53a24e975c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22a.d @@ -0,0 +1,20 @@ +module imports.dip22a; + +class Klass +{ + private void bar() {} +} + +struct Struct +{ + private void bar() {} +} + +private void bar() {} + +template Template(T) +{ + private void bar() {} +} + +private void bar(int) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/dip22b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22b.d new file mode 100644 index 00000000000..1e0e526ca88 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22b.d @@ -0,0 +1,3 @@ +module imports.dip22b; +// this public import only exports symbols that are visible within this module +public import imports.dip22c; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/dip22c.d b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22c.d new file mode 100644 index 00000000000..c735543f917 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22c.d @@ -0,0 +1,3 @@ +module pkg.dip22c; + +package(pkg) struct Foo {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/dip22d.d b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22d.d new file mode 100644 index 00000000000..9f80442e4b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22d.d @@ -0,0 +1,5 @@ +module imports.dip22d; + +private struct Foo {} +private void foo() {} +private void bar() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/dip22e.d b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22e.d new file mode 100644 index 00000000000..3464e605d5d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/dip22e.d @@ -0,0 +1,4 @@ +module imports.dip22e; + +public struct Foo {} +public void bar(int) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail10277.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail10277.d new file mode 100644 index 00000000000..b15461bc5d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail10277.d @@ -0,0 +1,23 @@ +module imports.fail10277; + +class TypeInfo { } +class TypeInfo_Class { } +class TypeInfo_Interface { } +class TypeInfo_Struct { } +class TypeInfo_Typedef { } +class TypeInfo_Pointer { } +class TypeInfo_Array { } +class TypeInfo_AssociativeArray { } +class TypeInfo_Enum { } +class TypeInfo_Function { } +class TypeInfo_Delegate { } +class TypeInfo_Tuple { } +class TypeInfo_Const { } +class TypeInfo_Invariant { } +class TypeInfo_Shared { } +class TypeInfo_Inout { } +class TypeInfo_Vector { } +class Object { } +class Throwable { } +class Exception { } +class Error { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail17646.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail17646.d new file mode 100644 index 00000000000..f6466923731 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail17646.d @@ -0,0 +1,10 @@ +module imports.fail17646; + +struct TestData +{ +} + +const(TestData)[] allTestData(MOD_STRINGS...)() +{ + foreach (i; MOD_STRINGS) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail1900a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail1900a.d new file mode 100644 index 00000000000..9ae04eed00a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail1900a.d @@ -0,0 +1,2 @@ +module imports.fail1900a; +template Bar(int n) { enum Bar = n; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail1900b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail1900b.d new file mode 100644 index 00000000000..b36fc87f964 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail1900b.d @@ -0,0 +1,2 @@ +module imports.fail1900b; +template Bar(short n) { enum Bar = n; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail2962a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail2962a.d new file mode 100644 index 00000000000..bd6e2bf22fb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail2962a.d @@ -0,0 +1,7 @@ +import fail2962; + +// comment 4 +int foo4() +{ + return bar4(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail320a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail320a.d new file mode 100644 index 00000000000..91972ed6546 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail320a.d @@ -0,0 +1 @@ +void foo(int) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail320b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail320b.d new file mode 100644 index 00000000000..9efc51c420c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail320b.d @@ -0,0 +1 @@ +void foo(T)(){} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail347a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail347a.d new file mode 100644 index 00000000000..2c2b1f6d6b1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail347a.d @@ -0,0 +1,3 @@ +module imports.fail347a; + +pure size_t strlen(in char* s); diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail355.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail355.d new file mode 100644 index 00000000000..9c1fd8ddb57 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail355.d @@ -0,0 +1 @@ +module imports.fail355; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail356.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail356.d new file mode 100644 index 00000000000..875cdeef325 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail356.d @@ -0,0 +1,2 @@ +module imports.fail356; +int bar; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail4479.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail4479.d new file mode 100644 index 00000000000..236de1d243a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail4479.d @@ -0,0 +1 @@ +module imports.fail4479mod; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail5385.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail5385.d new file mode 100644 index 00000000000..a07411ac7d2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail5385.d @@ -0,0 +1,17 @@ +module imports.fail5385; + +class C +{ + static private int privX; + static package int packX; + __gshared private int privX2; + __gshared package int packX2; +} + +struct S +{ + static private int privX; + static package int packX; + __gshared private int privX2; + __gshared package int packX2; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/foo10727a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/foo10727a.d new file mode 100644 index 00000000000..af0f1006cc8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/foo10727a.d @@ -0,0 +1,34 @@ +struct CirBuff(T) +{ + import imports.stdtraits10727 : isArray; + CirBuff!T opAssign(R)(R) if (isArray!R) + {} + + struct Range(U, S) + { + Range!(U, S) save() { return U; } + } + + T[] toArray() + { + T[] ret = new T[this.length]; + return ret; + } + + alias toArray this; + + Range!(T, T) range() {} + +} + +class Bar(T = int) +{ + CirBuff!T _bar; +} + +class Once +{ + Bar!Foo _foobar; +} + +class Foo : Frop {} // Frop is not defined diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/foo10727b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/foo10727b.d new file mode 100644 index 00000000000..4c51cac7b94 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/foo10727b.d @@ -0,0 +1,25 @@ +struct CirBuff(T) +{ + import imports.stdtraits10727 : isArray; + CirBuff!T opAssign(R)(R) if (isArray!R) + {} + + T[] toArray() + { + T[] ret = new T[this.length]; + return ret; + } + alias toArray this; +} + +class Bar(T = int) +{ + CirBuff!T _bar; +} + +class Once +{ + Bar!Foo _foobar; +} + +class Foo : Frop {} // Frop is not defined diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/ice10600a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/ice10600a.d new file mode 100644 index 00000000000..9488afddf79 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/ice10600a.d @@ -0,0 +1,11 @@ +module imports.ice10600a; + +struct Appender(A : T[], T) +{ + this(T[]) {} +} + +Appender!(E[]) appender(A : E[], E)() +{ + return Appender!(E[])(null); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/ice10600b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/ice10600b.d new file mode 100644 index 00000000000..f8a788dd729 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/ice10600b.d @@ -0,0 +1,36 @@ +module imports.ice10600b; + +import imports.ice10600a; + +template to(T) +{ + T to(A...)(A args) + { + return toImpl!T(args); + } +} + + +T toImpl(T, S)(S value) +if (is(S : T)) +{ + return value; +} + + +T toImpl(T, S)(S value) +if (!is(S : T) && + is(T == string)) +{ + auto w = appender!T(); + //Appender!T w; + return null; +} + +T toImpl(T, S)(S value) +if ( is(S == string) && + !is(T == string) && is(typeof(to!string(value[0]))) + ) +{ + return T.init; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/ice11513x.d b/gcc/testsuite/gdc.test/fail_compilation/imports/ice11513x.d new file mode 100644 index 00000000000..c24df566db4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/ice11513x.d @@ -0,0 +1 @@ +module ice11513a.imports; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/ice11513y.d b/gcc/testsuite/gdc.test/fail_compilation/imports/ice11513y.d new file mode 100644 index 00000000000..73d6feef69f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/ice11513y.d @@ -0,0 +1 @@ +module ice11513b.imports.ice11513y; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/ice7782algorithm.d b/gcc/testsuite/gdc.test/fail_compilation/imports/ice7782algorithm.d new file mode 100644 index 00000000000..4c14a2114f1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/ice7782algorithm.d @@ -0,0 +1,3 @@ +module imports.ice7782algorithm; + +import imports.ice7782range; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/ice7782range.d b/gcc/testsuite/gdc.test/fail_compilation/imports/ice7782range.d new file mode 100644 index 00000000000..b9b5ca6a520 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/ice7782range.d @@ -0,0 +1,3 @@ +module imports.ice7782range; + +import imports.ice7782algorithm; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/ice9865b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/ice9865b.d new file mode 100644 index 00000000000..2d30dd1f23f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/ice9865b.d @@ -0,0 +1,2 @@ +public import ice9865; +class Bar { Foo foo; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp1.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp1.d new file mode 100644 index 00000000000..9db9b45f7ba --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp1.d @@ -0,0 +1,5 @@ +module imports.imp1; + +enum X = 1; +enum Y = 1; +enum Z = 1; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp2.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp2.d new file mode 100644 index 00000000000..9dd5ff6bdd5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp2.d @@ -0,0 +1,5 @@ +module imports.imp2; + +enum X = 2; +enum Y = 2; +enum Z = 2; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/pkg313/package.d b/gcc/testsuite/gdc.test/fail_compilation/imports/pkg313/package.d new file mode 100644 index 00000000000..369a5aac753 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/pkg313/package.d @@ -0,0 +1,4 @@ +module imports.pkg313; + +void bug() +{} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/range15788.d b/gcc/testsuite/gdc.test/fail_compilation/imports/range15788.d new file mode 100644 index 00000000000..86026e9c450 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/range15788.d @@ -0,0 +1,5 @@ +module imports.range15788; + +auto iota(B, E, S)(B, E, S) +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/spell9644a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/spell9644a.d new file mode 100644 index 00000000000..b148ff71895 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/spell9644a.d @@ -0,0 +1,7 @@ +module imports.spell9644a; + +public import imports.spell9644b; + +int cora; +int pub; +private int priv; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/spell9644b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/spell9644b.d new file mode 100644 index 00000000000..aa6ff76da88 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/spell9644b.d @@ -0,0 +1,3 @@ +module imports.spell9644b; + +private int prib; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/stdtraits10727.d b/gcc/testsuite/gdc.test/fail_compilation/imports/stdtraits10727.d new file mode 100644 index 00000000000..7c56120fc1a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/stdtraits10727.d @@ -0,0 +1,46 @@ +template StaticArrayTypeOf(T) +{ + inout(U[n]) idx(U, size_t n)( inout(U[n]) ); + + /+static if (is(T == enum)) + alias .StaticArrayTypeOf!(OriginalType!T) StaticArrayTypeOf; + else +/static if (is(typeof(idx(T.init/+defaultInit!T+/)) X)) + alias X StaticArrayTypeOf; + else + static assert(0, T.stringof~" is not a static array type"); +} + +template DynamicArrayTypeOf(T) +{ + inout(U[]) idx(U)( inout(U[]) ); + + /+static if (is(T == enum)) + alias .DynamicArrayTypeOf!(OriginalType!T) DynamicArrayTypeOf; + else +/static if (!is(StaticArrayTypeOf!T) && + is(typeof(idx(T.init/+defaultInit!T+/)) X)) + { + alias typeof(T.init[0]/+defaultInit!T[0]+/) E; + + E[] idy( E[] ); + const(E[]) idy( const(E[]) ); + inout(E[]) idy( inout(E[]) ); + shared( E[]) idy( shared( E[]) ); + shared(const E[]) idy( shared(const E[]) ); + shared(inout E[]) idy( shared(inout E[]) ); + immutable(E[]) idy( immutable(E[]) ); + + alias typeof(idy(T.init/+defaultInit!T+/)) DynamicArrayTypeOf; + } + else + static assert(0, T.stringof~" is not a dynamic array"); +} + +template isDynamicArray(T) +{ + enum isDynamicArray = is(DynamicArrayTypeOf!T)/+ && !isAggregateType!T+/; +} + +template isArray(T) +{ + enum bool isArray = /+isStaticArray!T || +/isDynamicArray!T; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test10327/empty.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test10327/empty.d new file mode 100644 index 00000000000..ba3877b9c18 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test10327/empty.d @@ -0,0 +1 @@ +module empty; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152a.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152a.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152b.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152b.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152c.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152c.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152c.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152d.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152d.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152d.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152e.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152e.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152e.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152f.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152f.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152f.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152g.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152g.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152g.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152h.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152h.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152h.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152i.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152i.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152i.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152j.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152j.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152j.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152k.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152k.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152k.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152l.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152l.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152l.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152m.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152m.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152m.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152n.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152n.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152n.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152o.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152o.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152o.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152p.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152p.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152p.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152q.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152q.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152q.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152r.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152r.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152r.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152s.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152s.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152s.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152t.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152t.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152t.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152u.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152u.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152u.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152v.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152v.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152v.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152w.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152w.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152w.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152x.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152x.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152x.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152y.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152y.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152y.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test13152z.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152z.d new file mode 100644 index 00000000000..a91ff0df785 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test13152z.d @@ -0,0 +1,26 @@ +public import imports.test13152a; +public import imports.test13152b; +public import imports.test13152c; +public import imports.test13152d; +public import imports.test13152e; +public import imports.test13152f; +public import imports.test13152g; +public import imports.test13152h; +public import imports.test13152i; +public import imports.test13152j; +public import imports.test13152k; +public import imports.test13152l; +public import imports.test13152m; +public import imports.test13152n; +public import imports.test13152o; +public import imports.test13152p; +public import imports.test13152q; +public import imports.test13152r; +public import imports.test13152s; +public import imports.test13152t; +public import imports.test13152u; +public import imports.test13152v; +public import imports.test13152w; +public import imports.test13152x; +public import imports.test13152y; +public import imports.test13152z; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test143.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test143.d new file mode 100644 index 00000000000..2dbae1a93bf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test143.d @@ -0,0 +1,3 @@ +module imports.test143; + +package int x = 5; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test15785.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test15785.d new file mode 100644 index 00000000000..a97b0884276 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test15785.d @@ -0,0 +1,13 @@ +module imports.test15785; + +class Base +{ + private void foo() {} + private void bar() {} + private alias T = int; +} + +interface IBase2 +{ + private alias T = int; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test15897.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test15897.d new file mode 100644 index 00000000000..2583ad973cd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test15897.d @@ -0,0 +1,6 @@ +module imports.test15897; +import test15897; + +class Cat : Animal +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test5412a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test5412a.d new file mode 100644 index 00000000000..a0270239978 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test5412a.d @@ -0,0 +1 @@ +module imports.test5412a; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test5412b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test5412b.d new file mode 100644 index 00000000000..176b3880b1f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test5412b.d @@ -0,0 +1 @@ +module imports.test5412b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test64a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test64a.d new file mode 100644 index 00000000000..cb87b953325 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test64a.d @@ -0,0 +1,4 @@ +module imports; + +const char[] file1 = "File1"; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue3827.d b/gcc/testsuite/gdc.test/fail_compilation/issue3827.d new file mode 100644 index 00000000000..76d90ed7141 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/issue3827.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/issue3827.d(12): Deprecation: Implicit string concatenation is deprecated, use "Hello" ~ "World" instead +fail_compilation/issue3827.d(13): Deprecation: Implicit string concatenation is deprecated, use "A" ~ "B" instead +--- +*/ + +void main () +{ + string[] arr = [ "Hello" "World" ]; + auto foo = "A" "B"; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d new file mode 100644 index 00000000000..31246ce6173 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d @@ -0,0 +1,52 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/lexer1.d(30): Error: declaration expected, not `x"01 02 03"w` +fail_compilation/lexer1.d(31): Error: declaration expected, not `2147483649U` +fail_compilation/lexer1.d(32): Error: declaration expected, not `0.1` +fail_compilation/lexer1.d(33): Error: declaration expected, not `0.1f` +fail_compilation/lexer1.d(34): Error: declaration expected, not `0.1L` +fail_compilation/lexer1.d(35): Error: declaration expected, not `0.1i` +fail_compilation/lexer1.d(36): Error: declaration expected, not `0.1fi` +fail_compilation/lexer1.d(37): Error: declaration expected, not `0.1Li` +fail_compilation/lexer1.d(38): Error: declaration expected, not `32U` +fail_compilation/lexer1.d(39): Error: declaration expected, not `55295U` +fail_compilation/lexer1.d(40): Error: declaration expected, not `65536U` +fail_compilation/lexer1.d(41): Error: declaration expected, not `"ab\\c\"\u1234a\U00011100a"d` +fail_compilation/lexer1.d(43): Error: declaration expected, not `module` +fail_compilation/lexer1.d(45): Error: escape hex sequence has 1 hex digits instead of 2 +fail_compilation/lexer1.d(46): Error: undefined escape hex sequence \G +fail_compilation/lexer1.d(47): Error: unnamed character entity &unnamedentity; +fail_compilation/lexer1.d(48): Error: unterminated named entity &1; +fail_compilation/lexer1.d(49): Error: unterminated named entity &*; +fail_compilation/lexer1.d(50): Error: unterminated named entity &s1"; +fail_compilation/lexer1.d(51): Error: unterminated named entity &2; +fail_compilation/lexer1.d(52): Error: escape octal sequence \400 is larger than \377 +--- +*/ + +// https://dlang.dawg.eu/coverage/src/lexer.c.gcov.html + +x"01 02 03"w; +0x80000001; +0.1; +0.1f; +0.1L; +0.1i; +0.1fi; +0.1Li; +' '; +'\uD7FF'; +'\U00010000'; +"ab\\c\"\u1234a\U00011100a\000ab"d; + +module x; + +static s1 = "\x1G"; +static s2 = "\xGG"; +static s3 = "\&unnamedentity;"; +static s4 = "\&1"; +static s5 = "\&*"; +static s6 = "\&s1"; +static s7 = "\&2;"; +static s7 = "\400;"; diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer2.d b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d new file mode 100644 index 00000000000..d574b07d9b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/lexer2.d(14): Error: odd number (3) of hex characters in hex string +fail_compilation/lexer2.d(15): Error: non-hex character 'G' in hex string +fail_compilation/lexer2.d(16): Error: heredoc rest of line should be blank +fail_compilation/lexer2.d(18): Error: unterminated delimited string constant starting at fail_compilation/lexer2.d(18) +fail_compilation/lexer2.d(20): Error: semicolon expected following auto declaration, not `EOF` +--- +*/ + +// https://dlang.dawg.eu/coverage/src/lexer.c.gcov.html + +static s1 = x"123"; +static s2 = x"123G"; +static s4 = q"here notblank +here"; +static s5 = q"here +"; diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer3.d b/gcc/testsuite/gdc.test/fail_compilation/lexer3.d new file mode 100644 index 00000000000..f2bcda4ba8a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/lexer3.d @@ -0,0 +1,9 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/lexer3.d(9): Error: unterminated token string constant starting at fail_compilation/lexer3.d(9) +fail_compilation/lexer3.d(10): Error: semicolon expected following auto declaration, not `EOF` +--- +*/ + +static s1 = q{ asef; diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer4.d b/gcc/testsuite/gdc.test/fail_compilation/lexer4.d new file mode 100644 index 00000000000..374f69d5a13 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/lexer4.d @@ -0,0 +1,43 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/lexer4.d(22): Error: unterminated character constant +fail_compilation/lexer4.d(24): Error: unterminated character constant +fail_compilation/lexer4.d(25): Error: unterminated character constant +fail_compilation/lexer4.d(26): Error: binary digit expected +fail_compilation/lexer4.d(27): Error: radix 8 digit expected, not `8` +fail_compilation/lexer4.d(27): Error: octal literals `0130` are no longer supported, use `std.conv.octal!130` instead +fail_compilation/lexer4.d(28): Error: radix 10 digit expected, not `a` +fail_compilation/lexer4.d(29): Error: unrecognized token +fail_compilation/lexer4.d(30): Error: exponent required for hex float +fail_compilation/lexer4.d(31): Error: lower case integer suffix 'l' is not allowed. Please use 'L' instead +fail_compilation/lexer4.d(32): Error: use 'i' suffix instead of 'I' +fail_compilation/lexer4.d(34): Error: line number `1234567891234567879` out of range +fail_compilation/lexer4.d(36): Error: #line integer ["filespec"]\n expected +fail_compilation/lexer4.d(19): Error: #line integer ["filespec"]\n expected +fail_compilation/lexer4.d(19): Error: declaration expected, not `"file"` +--- +*/ + +static c1 = ' +; +static c2 = ''; +static c3 = 'a; +int i = 0b12; +int j = 0128; +int k = 12a; +int l = 12UU; +int f = 0x1234.0; +int m = 12l; +static n = 12.1I; + +#line 1234567891234567879 + +#line whatever + +#line 18 __FILE__ + +#line 20 "file" "file" + +/** asdf *//** asdf2 */ +int o; diff --git a/gcc/testsuite/gdc.test/fail_compilation/lookup.d b/gcc/testsuite/gdc.test/fail_compilation/lookup.d new file mode 100644 index 00000000000..0bb53859310 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/lookup.d @@ -0,0 +1,28 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/lookup.d(23): Error: no property 'X' for type 'lookup.B' +fail_compilation/lookup.d(23): while evaluating: `static assert((B).X == 0)` +fail_compilation/lookup.d(24): Error: no property 'Y' for type 'lookup.B' +fail_compilation/lookup.d(24): while evaluating: `static assert((B).Y == 2)` +--- +*/ + +import imports.imp1; + +enum X = 0; + +class B +{ + import imports.imp2; + static assert(X == 0); + static assert(Y == 2); +} +class C : B +{ + static assert(B.X == 0); + static assert(B.Y == 2); + + static assert(X == 0); + static assert(Y == 1); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/mangle1.d b/gcc/testsuite/gdc.test/fail_compilation/mangle1.d new file mode 100644 index 00000000000..bc2bc3dda89 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/mangle1.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/mangle1.d(8): Error: pragma mangle can only apply to a single declaration +--- +*/ + +pragma(mangle, "_stuff_") __gshared { int x, y; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/mangle2.d b/gcc/testsuite/gdc.test/fail_compilation/mangle2.d new file mode 100644 index 00000000000..e68c92acebb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/mangle2.d @@ -0,0 +1,42 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/mangle2.d(20): Error: pragma mangle char 0x20 not allowed in mangled name +fail_compilation/mangle2.d(21): Error: pragma mangle char 0x20 not allowed in mangled name +fail_compilation/mangle2.d(24): Error: pragma mangle char 0x0a not allowed in mangled name +fail_compilation/mangle2.d(25): Error: pragma mangle char 0x0a not allowed in mangled name +fail_compilation/mangle2.d(28): Error: pragma mangle char 0x07 not allowed in mangled name +fail_compilation/mangle2.d(29): Error: pragma mangle char 0x07 not allowed in mangled name +fail_compilation/mangle2.d(32): Error: pragma mangle char 0x01 not allowed in mangled name +fail_compilation/mangle2.d(33): Error: pragma mangle char 0x01 not allowed in mangled name +fail_compilation/mangle2.d(36): Error: pragma mangle char 0x00 not allowed in mangled name +fail_compilation/mangle2.d(37): Error: pragma mangle char 0x00 not allowed in mangled name +fail_compilation/mangle2.d(40): Error: pragma mangle Outside Unicode code space +fail_compilation/mangle2.d(41): Error: pragma mangle Outside Unicode code space +--- +*/ + +//spaces +__gshared pragma(mangle, "test 9") ubyte test9_1; +__gshared extern pragma(mangle, "test 9") ubyte test9_1_e; + +//\n chars +__gshared pragma(mangle, "test\n9") ubyte test9_2; +__gshared extern pragma(mangle, "test\n9") ubyte test9_2_e; + +//\a chars +__gshared pragma(mangle, "test\a9") ubyte test9_3; +__gshared extern pragma(mangle, "test\a9") ubyte test9_3_e; + +//\x01 chars +__gshared pragma(mangle, "test\x019") ubyte test9_4; +__gshared extern pragma(mangle, "test\x019") ubyte test9_4_e; + +//\0 chars +__gshared pragma(mangle, "test\09") ubyte test9_5; +__gshared extern pragma(mangle, "test\09") ubyte test9_5_e; + +//\xff chars +__gshared pragma(mangle, "test\xff9") ubyte test9_6; +__gshared extern pragma(mangle, "test\xff9") ubyte test9_6_e; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/moduleundefuda.d b/gcc/testsuite/gdc.test/fail_compilation/moduleundefuda.d new file mode 100644 index 00000000000..6e69aa130a6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/moduleundefuda.d @@ -0,0 +1,7 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/moduleundefuda.d(7): Error: undefined identifier `undef` +--- +*/ +@undef module moduleundefuda; diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc1.d b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d new file mode 100644 index 00000000000..8a66ac3e0ba --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d @@ -0,0 +1,85 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +/***************** NewExp *******************/ + +struct S1 { } +struct S2 { this(int); } +struct S3 { this(int) @nogc; } +struct S4 { new(size_t); } +struct S5 { @nogc new(size_t); } + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc1.d(27): Error: cannot use 'new' in @nogc function 'nogc1.testNew' +fail_compilation/nogc1.d(29): Error: cannot use 'new' in @nogc function 'nogc1.testNew' +fail_compilation/nogc1.d(30): Error: cannot use 'new' in @nogc function 'nogc1.testNew' +fail_compilation/nogc1.d(32): Error: cannot use 'new' in @nogc function 'nogc1.testNew' +fail_compilation/nogc1.d(33): Error: @nogc function 'nogc1.testNew' cannot call non-@nogc constructor 'nogc1.S2.this' +fail_compilation/nogc1.d(34): Error: cannot use 'new' in @nogc function 'nogc1.testNew' +fail_compilation/nogc1.d(35): Error: @nogc function 'nogc1.testNew' cannot call non-@nogc allocator 'nogc1.S4.new' +fail_compilation/nogc1.d(38): Error: cannot use 'new' in @nogc function 'nogc1.testNew' +--- +*/ +@nogc void testNew() +{ + int* p1 = new int; + + int[] a1 = new int[3]; + int[][] a2 = new int[][](2, 3); + + S1* ps1 = new S1(); + S2* ps2 = new S2(1); + S3* ps3 = new S3(1); + S4* ps4 = new S4; + S5* ps5 = new S5; // no error + + Object o1 = new Object(); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc1.d(55): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope' +fail_compilation/nogc1.d(57): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope' +fail_compilation/nogc1.d(58): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope' +fail_compilation/nogc1.d(60): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope' +fail_compilation/nogc1.d(61): Error: @nogc function 'nogc1.testNewScope' cannot call non-@nogc constructor 'nogc1.S2.this' +fail_compilation/nogc1.d(62): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope' +fail_compilation/nogc1.d(63): Error: @nogc function 'nogc1.testNewScope' cannot call non-@nogc allocator 'nogc1.S4.new' +--- +*/ +@nogc void testNewScope() +{ + scope int* p1 = new int; + + scope int[] a1 = new int[3]; + scope int[][] a2 = new int[][](2, 3); + + scope S1* ps1 = new S1(); + scope S2* ps2 = new S2(1); + scope S3* ps3 = new S3(1); + scope S4* ps4 = new S4; + scope S5* ps5 = new S5; // no error + + scope Object o1 = new Object(); // no error + scope o2 = new Object(); // no error +} + +/***************** DeleteExp *******************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc1.d(82): Error: cannot use 'delete' in @nogc function 'nogc1.testDelete' +fail_compilation/nogc1.d(83): Error: cannot use 'delete' in @nogc function 'nogc1.testDelete' +fail_compilation/nogc1.d(84): Error: cannot use 'delete' in @nogc function 'nogc1.testDelete' +--- +*/ +@nogc void testDelete(int* p, Object o, S1* s) +{ + delete p; + delete o; + delete s; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc2.d b/gcc/testsuite/gdc.test/fail_compilation/nogc2.d new file mode 100644 index 00000000000..1af413ac98c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/nogc2.d @@ -0,0 +1,104 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +/***************** CatExp *******************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc2.d(21): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +fail_compilation/nogc2.d(22): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +fail_compilation/nogc2.d(23): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +fail_compilation/nogc2.d(25): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +fail_compilation/nogc2.d(26): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +fail_compilation/nogc2.d(27): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +fail_compilation/nogc2.d(28): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +fail_compilation/nogc2.d(29): Error: cannot use operator ~ in @nogc function 'nogc2.testCat' +--- +*/ +@nogc void testCat(int[] a, string s) +{ + int[] a1 = a ~ a; + int[] a2 = a ~ 1; + int[] a3 = 1 ~ a; + + string s1 = s ~ s; + string s2 = s ~ "a"; + string s3 = "a" ~ s; + string s4 = s ~ 'c'; + string s5 = 'c' ~ s; + + string s6 = "a" ~ "b"; // no error + string s7 = "a" ~ 'c'; // no error + string s8 = 'c' ~ "b"; // no error +} + +/***************** CatAssignExp *******************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc2.d(48): Error: cannot use operator ~= in @nogc function 'nogc2.testCatAssign' +fail_compilation/nogc2.d(50): Error: cannot use operator ~= in @nogc function 'nogc2.testCatAssign' +fail_compilation/nogc2.d(51): Error: cannot use operator ~= in @nogc function 'nogc2.testCatAssign' +--- +*/ +@nogc void testCatAssign(int[] a, string s) +{ + a ~= 1; + + s ~= "a"; + s ~= 'c'; +} + +/***************** ArrayLiteralExp *******************/ + +@nogc int* barA(); + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc2.d(70): Error: array literal in @nogc function 'nogc2.testArray' may cause GC allocation +fail_compilation/nogc2.d(71): Error: array literal in @nogc function 'nogc2.testArray' may cause GC allocation +--- +*/ +@nogc void testArray() +{ + enum arrLiteral = [null, null]; + + int* p; + auto a = [p, p, barA()]; + a = arrLiteral; +} + +/***************** AssocArrayLiteralExp *******************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc2.d(87): Error: associative array literal in @nogc function 'nogc2.testAssocArray' may cause GC allocation +fail_compilation/nogc2.d(88): Error: associative array literal in @nogc function 'nogc2.testAssocArray' may cause GC allocation +--- +*/ +@nogc void testAssocArray() +{ + enum aaLiteral = [10: 100]; + + auto aa = [1:1, 2:3, 4:5]; + aa = aaLiteral; +} + +/***************** IndexExp *******************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc2.d(102): Error: indexing an associative array in @nogc function 'nogc2.testIndex' may cause GC allocation +fail_compilation/nogc2.d(103): Error: indexing an associative array in @nogc function 'nogc2.testIndex' may cause GC allocation +--- +*/ +@nogc void testIndex(int[int] aa) +{ + aa[1] = 0; + int n = aa[1]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc3.d b/gcc/testsuite/gdc.test/fail_compilation/nogc3.d new file mode 100644 index 00000000000..7c9e6d2219e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/nogc3.d @@ -0,0 +1,95 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +/***************** AssignExp *******************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc3.d(16): Error: setting 'length' in @nogc function 'nogc3.testArrayLength' may cause GC allocation +fail_compilation/nogc3.d(17): Error: setting 'length' in @nogc function 'nogc3.testArrayLength' may cause GC allocation +fail_compilation/nogc3.d(18): Error: setting 'length' in @nogc function 'nogc3.testArrayLength' may cause GC allocation +--- +*/ +@nogc void testArrayLength(int[] a) +{ + a.length = 3; + a.length += 1; + a.length -= 1; +} + +/***************** CallExp *******************/ + +void barCall(); + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc3.d(35): Error: @nogc function 'nogc3.testCall' cannot call non-@nogc function pointer 'fp' +fail_compilation/nogc3.d(36): Error: @nogc function 'nogc3.testCall' cannot call non-@nogc function 'nogc3.barCall' +--- +*/ +@nogc void testCall() +{ + auto fp = &barCall; + (*fp)(); + barCall(); +} + +/****************** Closure ***********************/ + +@nogc void takeDelegate2(scope int delegate() dg) {} +@nogc void takeDelegate3( int delegate() dg) {} + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc3.d(53): Error: function nogc3.testClosure1 is @nogc yet allocates closures with the GC +fail_compilation/nogc3.d(56): nogc3.testClosure1.bar closes over variable x at fail_compilation/nogc3.d(55) +fail_compilation/nogc3.d(65): Error: function nogc3.testClosure3 is @nogc yet allocates closures with the GC +fail_compilation/nogc3.d(68): nogc3.testClosure3.bar closes over variable x at fail_compilation/nogc3.d(67) +--- +*/ +@nogc auto testClosure1() +{ + int x; + int bar() { return x; } + return &bar; +} +@nogc void testClosure2() +{ + int x; + int bar() { return x; } + takeDelegate2(&bar); // no error +} +@nogc void testClosure3() +{ + int x; + int bar() { return x; } + takeDelegate3(&bar); +} + +/****************** ErrorExp ***********************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/nogc3.d(86): Error: array literal in @nogc function 'nogc3.foo13702' may cause GC allocation +fail_compilation/nogc3.d(87): Error: array literal in @nogc function 'nogc3.foo13702' may cause GC allocation +fail_compilation/nogc3.d(93): Error: array literal in @nogc function 'nogc3.bar13702' may cause GC allocation +fail_compilation/nogc3.d(92): Error: array literal in @nogc function 'nogc3.bar13702' may cause GC allocation +--- +*/ +int[] foo13702(bool b) @nogc +{ + if (b) + return [1]; // error + return 1 ~ [2]; // error +} +int[] bar13702(bool b) @nogc +{ + if (b) + return [1]; // error <- no error report + auto aux = 1 ~ [2]; // error + return aux; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse12924.d b/gcc/testsuite/gdc.test/fail_compilation/parse12924.d new file mode 100644 index 00000000000..c98167b4409 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parse12924.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parse12924.d(14): Error: declaration expected following attribute, not `;` +fail_compilation/parse12924.d(15): Error: declaration expected following attribute, not `;` +fail_compilation/parse12924.d(16): Error: declaration expected following attribute, not `;` +fail_compilation/parse12924.d(17): Error: declaration expected following attribute, not `;` +fail_compilation/parse12924.d(18): Error: declaration expected following attribute, not `;` +fail_compilation/parse12924.d(19): Error: declaration expected following attribute, not `;` +fail_compilation/parse12924.d(20): Error: declaration expected following attribute, not `;` +--- +*/ + +static; void f1() {} +deprecated; void f2() {} +deprecated(""); void f3() {} +extern(C); void f4() {} +public; void f5() {} +align(1); void f6() {} +@(1); void f7() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse12967a.d b/gcc/testsuite/gdc.test/fail_compilation/parse12967a.d new file mode 100644 index 00000000000..90bccb783ac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parse12967a.d @@ -0,0 +1,43 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parse12967a.d(14): Error: function parse12967a.pre_i1 without 'this' cannot be immutable +fail_compilation/parse12967a.d(15): Error: function parse12967a.pre_i2 without 'this' cannot be immutable +fail_compilation/parse12967a.d(16): Error: function parse12967a.pre_c1 without 'this' cannot be const +fail_compilation/parse12967a.d(17): Error: function parse12967a.pre_c2 without 'this' cannot be const +fail_compilation/parse12967a.d(18): Error: function parse12967a.pre_w1 without 'this' cannot be inout +fail_compilation/parse12967a.d(19): Error: function parse12967a.pre_w2 without 'this' cannot be inout +fail_compilation/parse12967a.d(20): Error: function parse12967a.pre_s1 without 'this' cannot be shared +fail_compilation/parse12967a.d(21): Error: function parse12967a.pre_s2 without 'this' cannot be shared +--- +*/ +immutable pre_i1() {} +immutable void pre_i2() {} +const pre_c1() {} +const void pre_c2() {} +inout pre_w1() {} +inout void pre_w2() {} +shared pre_s1() {} +shared void pre_s2() {} + +/* +TEST_OUTPUT: +--- +fail_compilation/parse12967a.d(36): Error: function parse12967a.post_i1 without 'this' cannot be immutable +fail_compilation/parse12967a.d(37): Error: function parse12967a.post_i2 without 'this' cannot be immutable +fail_compilation/parse12967a.d(38): Error: function parse12967a.post_c1 without 'this' cannot be const +fail_compilation/parse12967a.d(39): Error: function parse12967a.post_c2 without 'this' cannot be const +fail_compilation/parse12967a.d(40): Error: function parse12967a.post_w1 without 'this' cannot be inout +fail_compilation/parse12967a.d(41): Error: function parse12967a.post_w2 without 'this' cannot be inout +fail_compilation/parse12967a.d(42): Error: function parse12967a.post_s1 without 'this' cannot be shared +fail_compilation/parse12967a.d(43): Error: function parse12967a.post_s2 without 'this' cannot be shared +--- +*/ +auto post_i1() immutable {} +void post_i2() immutable {} +auto post_c1() const {} +void post_c2() const {} +auto post_w1() inout {} +void post_w2() inout {} +auto post_s1() shared {} +void post_s2() shared {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse12967b.d b/gcc/testsuite/gdc.test/fail_compilation/parse12967b.d new file mode 100644 index 00000000000..60d9d09948b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parse12967b.d @@ -0,0 +1,41 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parse12967b.d(24): Error: function parse12967b.C.pre_c without 'this' cannot be const +fail_compilation/parse12967b.d(25): Error: function parse12967b.C.pre_c without 'this' cannot be const +fail_compilation/parse12967b.d(26): Error: function parse12967b.C.pre_i without 'this' cannot be immutable +fail_compilation/parse12967b.d(27): Error: function parse12967b.C.pre_i without 'this' cannot be immutable +fail_compilation/parse12967b.d(28): Error: function parse12967b.C.pre_w without 'this' cannot be inout +fail_compilation/parse12967b.d(29): Error: function parse12967b.C.pre_w without 'this' cannot be inout +fail_compilation/parse12967b.d(30): Error: function parse12967b.C.pre_s without 'this' cannot be shared +fail_compilation/parse12967b.d(31): Error: function parse12967b.C.pre_s without 'this' cannot be shared +fail_compilation/parse12967b.d(33): Error: function parse12967b.C.post_c without 'this' cannot be const +fail_compilation/parse12967b.d(34): Error: function parse12967b.C.post_c without 'this' cannot be const +fail_compilation/parse12967b.d(35): Error: function parse12967b.C.post_i without 'this' cannot be immutable +fail_compilation/parse12967b.d(36): Error: function parse12967b.C.post_i without 'this' cannot be immutable +fail_compilation/parse12967b.d(37): Error: function parse12967b.C.post_w without 'this' cannot be inout +fail_compilation/parse12967b.d(38): Error: function parse12967b.C.post_w without 'this' cannot be inout +fail_compilation/parse12967b.d(39): Error: function parse12967b.C.post_s without 'this' cannot be shared +fail_compilation/parse12967b.d(40): Error: function parse12967b.C.post_s without 'this' cannot be shared +--- +*/ +class C +{ + const static pre_c() {} + const static void pre_c() {} + immutable static pre_i() {} + immutable static void pre_i() {} + inout static pre_w() {} + inout static void pre_w() {} + shared static pre_s() {} + shared static void pre_s() {} + + static post_c() const {} + static void post_c() const {} + static post_i() immutable {} + static void post_i() immutable {} + static post_w() inout {} + static void post_w() inout {} + static post_s() shared {} + static void post_s() shared {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse13361.d b/gcc/testsuite/gdc.test/fail_compilation/parse13361.d new file mode 100644 index 00000000000..f05ee8e5138 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parse13361.d @@ -0,0 +1,16 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parse13361.d(11): Error: empty attribute list is not allowed +fail_compilation/parse13361.d(14): Error: empty attribute list is not allowed +fail_compilation/parse13361.d(14): Error: use `@(attributes)` instead of `[attributes]` +--- +*/ +struct A +{ + @() + int b; + + [] // deprecated style + int c; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse14285.d b/gcc/testsuite/gdc.test/fail_compilation/parse14285.d new file mode 100644 index 00000000000..c9aa70aa793 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parse14285.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parse14285.d(10): Error: no identifier for declarator `this` +--- +*/ + +struct S +{ + alias this; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse14745.d b/gcc/testsuite/gdc.test/fail_compilation/parse14745.d new file mode 100644 index 00000000000..fa462e042b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parse14745.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parse14745.d(11): Error: function literal cannot be `immutable` +fail_compilation/parse14745.d(12): Error: function literal cannot be `const` +--- +*/ + +void test14745() +{ + auto fp1 = function () pure immutable { return 0; }; + auto fp2 = function () pure const { return 0; }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc.d new file mode 100644 index 00000000000..e0ce2c321b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc.d @@ -0,0 +1,38 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc.d(11): Error: found `;` when expecting `)` +fail_compilation/parseStc.d(11): Error: found `)` when expecting `;` following statement +fail_compilation/parseStc.d(12): Error: redundant attribute `const` +--- +*/ +void test1() +{ + if (x; 1) {} + if (const const auto x = 1) {} +} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc.d(25): Error: redundant attribute `const` +fail_compilation/parseStc.d(26): Error: redundant attribute `const` +fail_compilation/parseStc.d(27): Error: conflicting attribute `immutable` +--- +*/ +void test2() +{ + const const x = 1; + foreach (const const x; [1,2,3]) {} + foreach (const immutable x; [1,2,3]) {} +} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc.d(37): Error: redundant attribute `const` +fail_compilation/parseStc.d(38): Error: redundant attribute `const` +--- +*/ +struct S3 { const const test3() {} } +void test4(const const int x) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d new file mode 100644 index 00000000000..5e9c4461626 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d @@ -0,0 +1,77 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc2.d(11): Error: conflicting attribute `const` +fail_compilation/parseStc2.d(12): Error: conflicting attribute `@system` +fail_compilation/parseStc2.d(13): Error: conflicting attribute `@safe` +fail_compilation/parseStc2.d(14): Error: conflicting attribute `@trusted` +fail_compilation/parseStc2.d(15): Error: conflicting attribute `__gshared` +--- +*/ +immutable const void f4() {} +@safe @system void f4() {} +@trusted @safe void f4() {} +@system @trusted void f4() {} +shared __gshared f4() {} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc2.d(26): Error: redundant attribute `static` +fail_compilation/parseStc2.d(27): Error: redundant attribute `pure` +fail_compilation/parseStc2.d(28): Error: redundant attribute `@property` +fail_compilation/parseStc2.d(29): Error: redundant attribute `@safe` +--- +*/ +static static void f1() {} +pure nothrow pure void f2() {} +@property extern(C) @property void f3() {} +deprecated("") @safe @safe void f4() {} +@(1) @(1) void f5() {} // OK + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc2.d(39): Error: redundant linkage `extern (C)` +fail_compilation/parseStc2.d(40): Error: conflicting linkage `extern (C)` and `extern (C++)` +--- +*/ +extern(C) extern(C) void f6() {} +extern(C) extern(C++) void f7() {} +extern(C++, foo) extern(C++, bar) void f8() {} // OK + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc2.d(50): Error: redundant protection attribute `public` +fail_compilation/parseStc2.d(51): Error: conflicting protection attribute `public` and `private` +--- +*/ +public public void f9() {} +public private void f10() {} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc2.d(63): Error: redundant alignment attribute `align` +fail_compilation/parseStc2.d(64): Error: redundant alignment attribute `align(1)` +fail_compilation/parseStc2.d(65): Error: redundant alignment attribute `align(1)` +fail_compilation/parseStc2.d(66): Error: redundant alignment attribute `align` +fail_compilation/parseStc2.d(67): Error: redundant alignment attribute `align(2)` +--- +*/ +align align void f11() {} +align(1) align(1) void f12() {} +align align(1) void f13() {} +align(1) align void f14() {} +align(1) align(2) void f15() {} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc2.d(76): Error: redundant linkage `extern (System)` +fail_compilation/parseStc2.d(77): Error: conflicting linkage `extern (System)` and `extern (C++)` +--- +*/ +extern(System) extern(System) void f16() {} +extern(System) extern(C++) void f17() {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc3.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc3.d new file mode 100644 index 00000000000..1417f9432d2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc3.d @@ -0,0 +1,62 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc3.d(10): Deprecation: redundant attribute `pure` +fail_compilation/parseStc3.d(11): Deprecation: redundant attribute `nothrow` +fail_compilation/parseStc3.d(12): Deprecation: redundant attribute `@nogc` +fail_compilation/parseStc3.d(13): Deprecation: redundant attribute `@property` +--- +*/ +pure void f1() pure {} +nothrow void f2() nothrow {} +@nogc void f3() @nogc {} +@property void f4() @property {} +//ref int f5() ref { static int g; return g; } + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc3.d(24): Deprecation: redundant attribute `@safe` +fail_compilation/parseStc3.d(25): Deprecation: redundant attribute `@system` +fail_compilation/parseStc3.d(26): Deprecation: redundant attribute `@trusted` +--- +*/ +@safe void f6() @safe {} +@system void f7() @system {} +@trusted void f8() @trusted {} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc3.d(39): Error: conflicting attribute `@system` +fail_compilation/parseStc3.d(40): Error: conflicting attribute `@trusted` +fail_compilation/parseStc3.d(41): Error: conflicting attribute `@safe` +fail_compilation/parseStc3.d(42): Error: conflicting attribute `@trusted` +fail_compilation/parseStc3.d(43): Error: conflicting attribute `@safe` +fail_compilation/parseStc3.d(44): Error: conflicting attribute `@system` +--- +*/ +@safe void f9() @system {} +@safe void f10() @trusted {} +@system void f11() @safe {} +@system void f12() @trusted {} +@trusted void f13() @safe {} +@trusted void f14() @system {} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc3.d(59): Error: conflicting attribute `@system` +fail_compilation/parseStc3.d(59): Error: conflicting attribute `@trusted` +fail_compilation/parseStc3.d(60): Error: conflicting attribute `@system` +fail_compilation/parseStc3.d(60): Deprecation: redundant attribute `@system` +fail_compilation/parseStc3.d(61): Error: conflicting attribute `@safe` +fail_compilation/parseStc3.d(61): Deprecation: redundant attribute `@system` +fail_compilation/parseStc3.d(62): Error: conflicting attribute `@safe` +fail_compilation/parseStc3.d(62): Deprecation: redundant attribute `@trusted` +--- +*/ +@safe @system void f15() @trusted {} +@safe @system void f16() @system {} +@system @safe void f17() @system {} +@trusted @safe void f18() @trusted {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc4.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc4.d new file mode 100644 index 00000000000..fee3e085cdb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc4.d @@ -0,0 +1,42 @@ + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `pure` +fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `nothrow` +fail_compilation/parseStc4.d(14): Error: conflicting attribute `@system` +fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `@nogc` +fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `@property` +--- +*/ +pure nothrow @safe @nogc @property +int foo() +pure nothrow @system @nogc @property +{ + return 0; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc4.d(34): Deprecation: redundant attribute `const` +fail_compilation/parseStc4.d(35): Deprecation: redundant attribute `const` +fail_compilation/parseStc4.d(36): Deprecation: redundant attribute `const` +fail_compilation/parseStc4.d(38): Deprecation: redundant attribute `pure` +fail_compilation/parseStc4.d(39): Deprecation: redundant attribute `@safe` +fail_compilation/parseStc4.d(40): Deprecation: redundant attribute `nothrow` +fail_compilation/parseStc4.d(41): Error: conflicting attribute `@trusted` +--- +*/ + +struct S +{ + const this(int) const {} + const this(this) const {} + const ~this() const {} + + pure static this() pure {} + @safe static ~this() @safe {} + nothrow shared static this() nothrow {} + @system shared static ~this() @trusted {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc5.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc5.d new file mode 100644 index 00000000000..a274c6e3bbc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc5.d @@ -0,0 +1,88 @@ +// REQUIRED_ARGS: +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc5.d(11): Error: constructor cannot be static +fail_compilation/parseStc5.d(12): Error: postblit cannot be static +--- +*/ +class C1 +{ + static pure this(int) {} // `static pure` + `this(int)` + static pure this(this) {} // `static pure` + `this(this)` +} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc5.d(28): Error: use `shared static this()` to declare a shared static constructor +fail_compilation/parseStc5.d(29): Error: use `shared static this()` to declare a shared static constructor +fail_compilation/parseStc5.d(31): Error: use `shared static this()` to declare a shared static constructor +fail_compilation/parseStc5.d(33): Error: use `shared static ~this()` to declare a shared static destructor +fail_compilation/parseStc5.d(34): Error: use `shared static ~this()` to declare a shared static destructor +fail_compilation/parseStc5.d(36): Error: use `shared static ~this()` to declare a shared static destructor +--- +*/ +class C2 // wrong combinations of `shared`, `static`, and `~?this()` +{ + shared pure static this() {} // `shared pure` + `static this()` + shared static pure this() {} // `shared static pure` + `this()` + + static this() shared {} // `shared pure` + `static this()` + + shared pure static ~this() {} // `shared pure` + `static ~this()` + shared static pure ~this() {} // `shared static pure` + `~this()` + + static ~this() shared {} // `shared` + `static ~this()` +} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc5.d(48): Error: use `static this()` to declare a static constructor +fail_compilation/parseStc5.d(49): Error: use `static ~this()` to declare a static destructor +--- +*/ +class C3 // wrong combinations of `static` and `~?this()` +{ + static pure this() {} // `static pure` + `this()` + static pure ~this() {} // `static pure` + `~this()` +} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc5.d(64): Error: redundant attribute `shared` +fail_compilation/parseStc5.d(65): Error: redundant attribute `shared` +fail_compilation/parseStc5.d(67): Error: redundant attribute `static` +fail_compilation/parseStc5.d(69): Error: redundant attribute `static shared` +fail_compilation/parseStc5.d(70): Error: redundant attribute `static shared` +--- +*/ +class C4 // redundancy of `shared` and/or `static` +{ + shared shared static this() {} // `shared` + `shared static this()` + shared static this() shared {} // `shared` + `shared static this()` + + static static this() {} // `static` + `shared static this()` + + shared static shared static this() {} // shared static + `shared static this()` + shared static shared static this() shared {} // shared shared static + `shared static this()` +} + +/* +TEST_OUTPUT: +--- +fail_compilation/parseStc5.d(84): Error: static constructor cannot be `const` +fail_compilation/parseStc5.d(85): Error: static destructor cannot be `const` +fail_compilation/parseStc5.d(86): Error: shared static constructor cannot be `const` +fail_compilation/parseStc5.d(87): Error: shared static destructor cannot be `const` +--- +*/ +class C5 // wrong MemberFunctionAttributes on `shared? static (con|de)structor` +{ + static this() const {} + static ~this() const {} + shared static this() const {} + shared static ~this() const {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/pragmainline.d b/gcc/testsuite/gdc.test/fail_compilation/pragmainline.d new file mode 100644 index 00000000000..030f19a39a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/pragmainline.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/pragmainline.d(9): Error: pragma inline one boolean expression expected for `pragma(inline)`, not 3 +fail_compilation/pragmainline.d(10): Error: pragma inline pragma(`inline`, `true` or `false`) expected, not `"string"` +--- +*/ + +pragma(inline, 1,2,3) void bar(); +pragma(inline, "string") void baz(); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d new file mode 100644 index 00000000000..33a89218172 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d @@ -0,0 +1,40 @@ +/* +REQUIRED_ARGS: +PERMUTE_ARGS: +*/ + +/************************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/pragmas.d(103): Error: boolean expression expected for pragma(inline) +fail_compilation/pragmas.d(108): Error: boolean expression expected for pragma(inline) +fail_compilation/pragmas.d(113): Error: pragma(inline, true or false) expected, not `"string"` +fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)` +--- +*/ + +#line 100 +void test1() +{ + pragma(inline); + pragma(inline, true, false); +} + +void test2() +{ + pragma(inline, true, false); +} + +void test3() +{ + pragma(inline, "string"); +} + +void test4() +{ + pragma(unrecognized, "string"); +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/protattr1.d b/gcc/testsuite/gdc.test/fail_compilation/protattr1.d new file mode 100644 index 00000000000..dbd2efa43a2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/protattr1.d @@ -0,0 +1,7 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/protection/subpkg/test1.d(3): Error: protection attribute 'package(undefined)' does not bind to one of ancestor packages of module `protection.subpkg.test1` +--- +*/ +import protection.subpkg.test1; diff --git a/gcc/testsuite/gdc.test/fail_compilation/protattr2.d b/gcc/testsuite/gdc.test/fail_compilation/protattr2.d new file mode 100644 index 00000000000..cc36cc00afb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/protattr2.d @@ -0,0 +1,7 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/protection/subpkg/test2.d(3): Error: protection attribute 'package(protection.subpkg2)' does not bind to one of ancestor packages of module `protection.subpkg.test2` +--- +*/ +import protection.subpkg.test2; diff --git a/gcc/testsuite/gdc.test/fail_compilation/protattr3.d b/gcc/testsuite/gdc.test/fail_compilation/protattr3.d new file mode 100644 index 00000000000..8f40b2e2c0e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/protattr3.d @@ -0,0 +1,7 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/protection/subpkg/test3.d(3): Error: `protection package` expected as dot-separated identifiers, got `123` +--- +*/ +import protection.subpkg.test3; diff --git a/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test1.d b/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test1.d new file mode 100644 index 00000000000..35abb80cbe1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test1.d @@ -0,0 +1,3 @@ +module protection.subpkg.test1; + +package(undefined) void foo1(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test2.d b/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test2.d new file mode 100644 index 00000000000..32aedff0b81 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test2.d @@ -0,0 +1,3 @@ +module protection.subpkg.test2; + +package(protection.subpkg2) void foo2(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test3.d b/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test3.d new file mode 100644 index 00000000000..13cc08034ec --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/protection/subpkg/test3.d @@ -0,0 +1,3 @@ +module protection.subpkg.test3; + +package(123) void foo3(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d new file mode 100644 index 00000000000..de23c461e4a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d @@ -0,0 +1,298 @@ +// REQUIRED_ARGS: -verrors=0 +/* +TEST_OUTPUT: +--- +fail_compilation/reserved_version.d(105): Error: version identifier `MSP430` is reserved and cannot be set +fail_compilation/reserved_version.d(106): Error: version identifier `D_P16` is reserved and cannot be set +fail_compilation/reserved_version.d(107): Error: version identifier `DigitalMars` is reserved and cannot be set +fail_compilation/reserved_version.d(108): Error: version identifier `GNU` is reserved and cannot be set +fail_compilation/reserved_version.d(109): Error: version identifier `LDC` is reserved and cannot be set +fail_compilation/reserved_version.d(110): Error: version identifier `SDC` is reserved and cannot be set +fail_compilation/reserved_version.d(111): Error: version identifier `Windows` is reserved and cannot be set +fail_compilation/reserved_version.d(112): Error: version identifier `Win32` is reserved and cannot be set +fail_compilation/reserved_version.d(113): Error: version identifier `Win64` is reserved and cannot be set +fail_compilation/reserved_version.d(114): Error: version identifier `linux` is reserved and cannot be set +fail_compilation/reserved_version.d(115): Error: version identifier `OSX` is reserved and cannot be set +fail_compilation/reserved_version.d(116): Error: version identifier `FreeBSD` is reserved and cannot be set +fail_compilation/reserved_version.d(117): Error: version identifier `OpenBSD` is reserved and cannot be set +fail_compilation/reserved_version.d(118): Error: version identifier `NetBSD` is reserved and cannot be set +fail_compilation/reserved_version.d(119): Error: version identifier `DragonFlyBSD` is reserved and cannot be set +fail_compilation/reserved_version.d(120): Error: version identifier `BSD` is reserved and cannot be set +fail_compilation/reserved_version.d(121): Error: version identifier `Solaris` is reserved and cannot be set +fail_compilation/reserved_version.d(122): Error: version identifier `Posix` is reserved and cannot be set +fail_compilation/reserved_version.d(123): Error: version identifier `AIX` is reserved and cannot be set +fail_compilation/reserved_version.d(124): Error: version identifier `Haiku` is reserved and cannot be set +fail_compilation/reserved_version.d(125): Error: version identifier `SkyOS` is reserved and cannot be set +fail_compilation/reserved_version.d(126): Error: version identifier `SysV3` is reserved and cannot be set +fail_compilation/reserved_version.d(127): Error: version identifier `SysV4` is reserved and cannot be set +fail_compilation/reserved_version.d(128): Error: version identifier `Hurd` is reserved and cannot be set +fail_compilation/reserved_version.d(129): Error: version identifier `Android` is reserved and cannot be set +fail_compilation/reserved_version.d(130): Error: version identifier `PlayStation` is reserved and cannot be set +fail_compilation/reserved_version.d(131): Error: version identifier `PlayStation4` is reserved and cannot be set +fail_compilation/reserved_version.d(132): Error: version identifier `Cygwin` is reserved and cannot be set +fail_compilation/reserved_version.d(133): Error: version identifier `MinGW` is reserved and cannot be set +fail_compilation/reserved_version.d(134): Error: version identifier `FreeStanding` is reserved and cannot be set +fail_compilation/reserved_version.d(135): Error: version identifier `X86` is reserved and cannot be set +fail_compilation/reserved_version.d(136): Error: version identifier `X86_64` is reserved and cannot be set +fail_compilation/reserved_version.d(137): Error: version identifier `ARM` is reserved and cannot be set +fail_compilation/reserved_version.d(138): Error: version identifier `ARM_Thumb` is reserved and cannot be set +fail_compilation/reserved_version.d(139): Error: version identifier `ARM_SoftFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(140): Error: version identifier `ARM_SoftFP` is reserved and cannot be set +fail_compilation/reserved_version.d(141): Error: version identifier `ARM_HardFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(142): Error: version identifier `AArch64` is reserved and cannot be set +fail_compilation/reserved_version.d(143): Error: version identifier `Epiphany` is reserved and cannot be set +fail_compilation/reserved_version.d(144): Error: version identifier `PPC` is reserved and cannot be set +fail_compilation/reserved_version.d(145): Error: version identifier `PPC_SoftFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(146): Error: version identifier `PPC_HardFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(147): Error: version identifier `PPC64` is reserved and cannot be set +fail_compilation/reserved_version.d(148): Error: version identifier `IA64` is reserved and cannot be set +fail_compilation/reserved_version.d(149): Error: version identifier `MIPS32` is reserved and cannot be set +fail_compilation/reserved_version.d(150): Error: version identifier `MIPS64` is reserved and cannot be set +fail_compilation/reserved_version.d(151): Error: version identifier `MIPS_O32` is reserved and cannot be set +fail_compilation/reserved_version.d(152): Error: version identifier `MIPS_N32` is reserved and cannot be set +fail_compilation/reserved_version.d(153): Error: version identifier `MIPS_O64` is reserved and cannot be set +fail_compilation/reserved_version.d(154): Error: version identifier `MIPS_N64` is reserved and cannot be set +fail_compilation/reserved_version.d(155): Error: version identifier `MIPS_EABI` is reserved and cannot be set +fail_compilation/reserved_version.d(156): Error: version identifier `MIPS_SoftFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(157): Error: version identifier `MIPS_HardFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(158): Error: version identifier `NVPTX` is reserved and cannot be set +fail_compilation/reserved_version.d(159): Error: version identifier `NVPTX64` is reserved and cannot be set +fail_compilation/reserved_version.d(160): Error: version identifier `RISCV32` is reserved and cannot be set +fail_compilation/reserved_version.d(161): Error: version identifier `RISCV64` is reserved and cannot be set +fail_compilation/reserved_version.d(162): Error: version identifier `SPARC` is reserved and cannot be set +fail_compilation/reserved_version.d(163): Error: version identifier `SPARC_V8Plus` is reserved and cannot be set +fail_compilation/reserved_version.d(164): Error: version identifier `SPARC_SoftFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(165): Error: version identifier `SPARC_HardFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(166): Error: version identifier `SPARC64` is reserved and cannot be set +fail_compilation/reserved_version.d(167): Error: version identifier `S390` is reserved and cannot be set +fail_compilation/reserved_version.d(168): Error: version identifier `S390X` is reserved and cannot be set +fail_compilation/reserved_version.d(169): Error: version identifier `SystemZ` is reserved and cannot be set +fail_compilation/reserved_version.d(170): Error: version identifier `HPPA` is reserved and cannot be set +fail_compilation/reserved_version.d(171): Error: version identifier `HPPA64` is reserved and cannot be set +fail_compilation/reserved_version.d(172): Error: version identifier `SH` is reserved and cannot be set +fail_compilation/reserved_version.d(173): Error: version identifier `Alpha` is reserved and cannot be set +fail_compilation/reserved_version.d(174): Error: version identifier `Alpha_SoftFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(175): Error: version identifier `Alpha_HardFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(176): Error: version identifier `LittleEndian` is reserved and cannot be set +fail_compilation/reserved_version.d(177): Error: version identifier `BigEndian` is reserved and cannot be set +fail_compilation/reserved_version.d(178): Error: version identifier `ELFv1` is reserved and cannot be set +fail_compilation/reserved_version.d(179): Error: version identifier `ELFv2` is reserved and cannot be set +fail_compilation/reserved_version.d(180): Error: version identifier `CRuntime_Bionic` is reserved and cannot be set +fail_compilation/reserved_version.d(181): Error: version identifier `CRuntime_DigitalMars` is reserved and cannot be set +fail_compilation/reserved_version.d(182): Error: version identifier `CRuntime_Glibc` is reserved and cannot be set +fail_compilation/reserved_version.d(183): Error: version identifier `CRuntime_Microsoft` is reserved and cannot be set +fail_compilation/reserved_version.d(184): Error: version identifier `CRuntime_Musl` is reserved and cannot be set +fail_compilation/reserved_version.d(185): Error: version identifier `CRuntime_UClibc` is reserved and cannot be set +fail_compilation/reserved_version.d(186): Error: version identifier `D_Coverage` is reserved and cannot be set +fail_compilation/reserved_version.d(187): Error: version identifier `D_Ddoc` is reserved and cannot be set +fail_compilation/reserved_version.d(188): Error: version identifier `D_InlineAsm_X86` is reserved and cannot be set +fail_compilation/reserved_version.d(189): Error: version identifier `D_InlineAsm_X86_64` is reserved and cannot be set +fail_compilation/reserved_version.d(190): Error: version identifier `D_LP64` is reserved and cannot be set +fail_compilation/reserved_version.d(191): Error: version identifier `D_X32` is reserved and cannot be set +fail_compilation/reserved_version.d(192): Error: version identifier `D_HardFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(193): Error: version identifier `D_SoftFloat` is reserved and cannot be set +fail_compilation/reserved_version.d(194): Error: version identifier `D_PIC` is reserved and cannot be set +fail_compilation/reserved_version.d(195): Error: version identifier `D_SIMD` is reserved and cannot be set +fail_compilation/reserved_version.d(196): Error: version identifier `D_Version2` is reserved and cannot be set +fail_compilation/reserved_version.d(197): Error: version identifier `D_NoBoundsChecks` is reserved and cannot be set +fail_compilation/reserved_version.d(200): Error: version identifier `all` is reserved and cannot be set +fail_compilation/reserved_version.d(201): Error: version identifier `none` is reserved and cannot be set +--- +*/ + +// Some extra empty lines to help fixup the manual line numbering after adding new version identifiers + +version = MSP430; +version = D_P16; +version = DigitalMars; +version = GNU; +version = LDC; +version = SDC; +version = Windows; +version = Win32; +version = Win64; +version = linux; +version = OSX; +version = FreeBSD; +version = OpenBSD; +version = NetBSD; +version = DragonFlyBSD; +version = BSD; +version = Solaris; +version = Posix; +version = AIX; +version = Haiku; +version = SkyOS; +version = SysV3; +version = SysV4; +version = Hurd; +version = Android; +version = PlayStation; +version = PlayStation4; +version = Cygwin; +version = MinGW; +version = FreeStanding; +version = X86; +version = X86_64; +version = ARM; +version = ARM_Thumb; +version = ARM_SoftFloat; +version = ARM_SoftFP; +version = ARM_HardFloat; +version = AArch64; +version = Epiphany; +version = PPC; +version = PPC_SoftFloat; +version = PPC_HardFloat; +version = PPC64; +version = IA64; +version = MIPS32; +version = MIPS64; +version = MIPS_O32; +version = MIPS_N32; +version = MIPS_O64; +version = MIPS_N64; +version = MIPS_EABI; +version = MIPS_SoftFloat; +version = MIPS_HardFloat; +version = NVPTX; +version = NVPTX64; +version = RISCV32; +version = RISCV64; +version = SPARC; +version = SPARC_V8Plus; +version = SPARC_SoftFloat; +version = SPARC_HardFloat; +version = SPARC64; +version = S390; +version = S390X; +version = SystemZ; +version = HPPA; +version = HPPA64; +version = SH; +version = Alpha; +version = Alpha_SoftFloat; +version = Alpha_HardFloat; +version = LittleEndian; +version = BigEndian; +version = ELFv1; +version = ELFv2; +version = CRuntime_Bionic; +version = CRuntime_DigitalMars; +version = CRuntime_Glibc; +version = CRuntime_Microsoft; +version = CRuntime_Musl; +version = CRuntime_UClibc; +version = D_Coverage; +version = D_Ddoc; +version = D_InlineAsm_X86; +version = D_InlineAsm_X86_64; +version = D_LP64; +version = D_X32; +version = D_HardFloat; +version = D_SoftFloat; +version = D_PIC; +version = D_SIMD; +version = D_Version2; +version = D_NoBoundsChecks; +//version = unittest; +//version = assert; +version = all; +version = none; + +// This should work though +debug = DigitalMars; +debug = GNU; +debug = LDC; +debug = SDC; +debug = Windows; +debug = Win32; +debug = Win64; +debug = linux; +debug = OSX; +debug = FreeBSD; +debug = OpenBSD; +debug = NetBSD; +debug = DragonFlyBSD; +debug = BSD; +debug = Solaris; +debug = Posix; +debug = AIX; +debug = Haiku; +debug = SkyOS; +debug = SysV3; +debug = SysV4; +debug = Hurd; +debug = Android; +debug = Cygwin; +debug = MinGW; +debug = FreeStanding; +debug = X86; +debug = X86_64; +debug = ARM; +debug = ARM_Thumb; +debug = ARM_SoftFloat; +debug = ARM_SoftFP; +debug = ARM_HardFloat; +debug = AArch64; +debug = Epiphany; +debug = PPC; +debug = PPC_SoftFloat; +debug = PPC_HardFloat; +debug = PPC64; +debug = IA64; +debug = MIPS32; +debug = MIPS64; +debug = MIPS_O32; +debug = MIPS_N32; +debug = MIPS_O64; +debug = MIPS_N64; +debug = MIPS_EABI; +debug = MIPS_SoftFloat; +debug = MIPS_HardFloat; +debug = NVPTX; +debug = NVPTX64; +debug = RISCV32; +debug = RISCV64; +debug = SPARC; +debug = SPARC_V8Plus; +debug = SPARC_SoftFloat; +debug = SPARC_HardFloat; +debug = SPARC64; +debug = S390; +debug = S390X; +debug = SystemZ; +debug = HPPA; +debug = HPPA64; +debug = SH; +debug = Alpha; +debug = Alpha_SoftFloat; +debug = Alpha_HardFloat; +debug = LittleEndian; +debug = BigEndian; +debug = ELFv1; +debug = ELFv2; +debug = CRuntime_Bionic; +debug = CRuntime_DigitalMars; +debug = CRuntime_Glibc; +debug = CRuntime_Microsoft; +debug = CRuntime_Musl; +debug = CRuntime_UClibc; +debug = D_Coverage; +debug = D_Ddoc; +debug = D_InlineAsm_X86; +debug = D_InlineAsm_X86_64; +debug = D_LP64; +debug = D_X32; +debug = D_HardFloat; +debug = D_SoftFloat; +debug = D_PIC; +debug = D_SIMD; +debug = D_Version2; +debug = D_NoBoundsChecks; +//debug = unittest; +//debug = assert; +debug = all; +debug = none; +debug = D_P16; +debug = MSP430; diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d new file mode 100644 index 00000000000..eb794d2ac42 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d @@ -0,0 +1,284 @@ +// REQUIRED_ARGS: -verrors=0 + +// REQUIRED_ARGS: -version=DigitalMars +// REQUIRED_ARGS: -version=GNU +// REQUIRED_ARGS: -version=LDC +// REQUIRED_ARGS: -version=SDC +// REQUIRED_ARGS: -version=Windows +// REQUIRED_ARGS: -version=Win32 +// REQUIRED_ARGS: -version=Win64 +// REQUIRED_ARGS: -version=linux +// REQUIRED_ARGS: -version=OSX +// REQUIRED_ARGS: -version=FreeBSD +// REQUIRED_ARGS: -version=OpenBSD +// REQUIRED_ARGS: -version=NetBSD +// REQUIRED_ARGS: -version=DragonFlyBSD +// REQUIRED_ARGS: -version=BSD +// REQUIRED_ARGS: -version=Solaris +// REQUIRED_ARGS: -version=Posix +// REQUIRED_ARGS: -version=AIX +// REQUIRED_ARGS: -version=Haiku +// REQUIRED_ARGS: -version=SkyOS +// REQUIRED_ARGS: -version=SysV3 +// REQUIRED_ARGS: -version=SysV4 +// REQUIRED_ARGS: -version=Hurd +// REQUIRED_ARGS: -version=Android +// REQUIRED_ARGS: -version=Cygwin +// REQUIRED_ARGS: -version=MinGW +// REQUIRED_ARGS: -version=FreeStanding +// REQUIRED_ARGS: -version=X86 +// REQUIRED_ARGS: -version=X86_64 +// REQUIRED_ARGS: -version=ARM +// REQUIRED_ARGS: -version=ARM_Thumb +// REQUIRED_ARGS: -version=ARM_SoftFloat +// REQUIRED_ARGS: -version=ARM_SoftFP +// REQUIRED_ARGS: -version=ARM_HardFloat +// REQUIRED_ARGS: -version=AArch64 +// REQUIRED_ARGS: -version=Epiphany +// REQUIRED_ARGS: -version=PPC +// REQUIRED_ARGS: -version=PPC_SoftFloat +// REQUIRED_ARGS: -version=PPC_HardFloat +// REQUIRED_ARGS: -version=PPC64 +// REQUIRED_ARGS: -version=IA64 +// REQUIRED_ARGS: -version=MIPS32 +// REQUIRED_ARGS: -version=MIPS64 +// REQUIRED_ARGS: -version=MIPS_O32 +// REQUIRED_ARGS: -version=MIPS_N32 +// REQUIRED_ARGS: -version=MIPS_O64 +// REQUIRED_ARGS: -version=MIPS_N64 +// REQUIRED_ARGS: -version=MIPS_EABI +// REQUIRED_ARGS: -version=MIPS_SoftFloat +// REQUIRED_ARGS: -version=MIPS_HardFloat +// REQUIRED_ARGS: -version=NVPTX +// REQUIRED_ARGS: -version=NVPTX64 +// REQUIRED_ARGS: -version=RISCV32 +// REQUIRED_ARGS: -version=RISCV64 +// REQUIRED_ARGS: -version=SPARC +// REQUIRED_ARGS: -version=SPARC_V8Plus +// REQUIRED_ARGS: -version=SPARC_SoftFloat +// REQUIRED_ARGS: -version=SPARC_HardFloat +// REQUIRED_ARGS: -version=SPARC64 +// REQUIRED_ARGS: -version=S390 +// REQUIRED_ARGS: -version=S390X +// REQUIRED_ARGS: -version=SystemZ +// REQUIRED_ARGS: -version=HPPA +// REQUIRED_ARGS: -version=HPPA64 +// REQUIRED_ARGS: -version=SH +// REQUIRED_ARGS: -version=Alpha +// REQUIRED_ARGS: -version=Alpha_SoftFloat +// REQUIRED_ARGS: -version=Alpha_HardFloat +// REQUIRED_ARGS: -version=LittleEndian +// REQUIRED_ARGS: -version=BigEndian +// REQUIRED_ARGS: -version=ELFv1 +// REQUIRED_ARGS: -version=ELFv2 +// REQUIRED_ARGS: -version=CRuntime_Bionic +// REQUIRED_ARGS: -version=CRuntime_DigitalMars +// REQUIRED_ARGS: -version=CRuntime_Glibc +// REQUIRED_ARGS: -version=CRuntime_Microsoft +// REQUIRED_ARGS: -version=CRuntime_Musl +// REQUIRED_ARGS: -version=CRuntime_UClibc +// REQUIRED_ARGS: -version=D_Coverage +// REQUIRED_ARGS: -version=D_Ddoc +// REQUIRED_ARGS: -version=D_InlineAsm_X86 +// REQUIRED_ARGS: -version=D_InlineAsm_X86_64 +// REQUIRED_ARGS: -version=D_LP64 +// REQUIRED_ARGS: -version=D_X32 +// REQUIRED_ARGS: -version=D_HardFloat +// REQUIRED_ARGS: -version=D_SoftFloat +// REQUIRED_ARGS: -version=D_PIC +// REQUIRED_ARGS: -version=D_SIMD +// REQUIRED_ARGS: -version=D_Version2 +// REQUIRED_ARGS: -version=D_NoBoundsChecks +// REQUIRED_ARGS: -version=unittest +// REQUIRED_ARGS: -version=assert +// REQUIRED_ARGS: -version=all +// REQUIRED_ARGS: -version=none +// REQUIRED_ARGS: -debug=DigitalMars +// REQUIRED_ARGS: -debug=GNU +// REQUIRED_ARGS: -debug=LDC +// REQUIRED_ARGS: -debug=SDC +// REQUIRED_ARGS: -debug=Windows +// REQUIRED_ARGS: -debug=Win32 +// REQUIRED_ARGS: -debug=Win64 +// REQUIRED_ARGS: -debug=linux +// REQUIRED_ARGS: -debug=OSX +// REQUIRED_ARGS: -debug=FreeBSD +// REQUIRED_ARGS: -debug=OpenBSD +// REQUIRED_ARGS: -debug=NetBSD +// REQUIRED_ARGS: -debug=DragonFlyBSD +// REQUIRED_ARGS: -debug=BSD +// REQUIRED_ARGS: -debug=Solaris +// REQUIRED_ARGS: -debug=Posix +// REQUIRED_ARGS: -debug=AIX +// REQUIRED_ARGS: -debug=Haiku +// REQUIRED_ARGS: -debug=SkyOS +// REQUIRED_ARGS: -debug=SysV3 +// REQUIRED_ARGS: -debug=SysV4 +// REQUIRED_ARGS: -debug=Hurd +// REQUIRED_ARGS: -debug=Android +// REQUIRED_ARGS: -debug=Cygwin +// REQUIRED_ARGS: -debug=MinGW +// REQUIRED_ARGS: -debug=FreeStanding +// REQUIRED_ARGS: -debug=X86 +// REQUIRED_ARGS: -debug=X86_64 +// REQUIRED_ARGS: -debug=ARM +// REQUIRED_ARGS: -debug=ARM_Thumb +// REQUIRED_ARGS: -debug=ARM_SoftFloat +// REQUIRED_ARGS: -debug=ARM_SoftFP +// REQUIRED_ARGS: -debug=ARM_HardFloat +// REQUIRED_ARGS: -debug=AArch64 +// REQUIRED_ARGS: -debug=Epiphany +// REQUIRED_ARGS: -debug=PPC +// REQUIRED_ARGS: -debug=PPC_SoftFloat +// REQUIRED_ARGS: -debug=PPC_HardFloat +// REQUIRED_ARGS: -debug=PPC64 +// REQUIRED_ARGS: -debug=IA64 +// REQUIRED_ARGS: -debug=MIPS32 +// REQUIRED_ARGS: -debug=MIPS64 +// REQUIRED_ARGS: -debug=MIPS_O32 +// REQUIRED_ARGS: -debug=MIPS_N32 +// REQUIRED_ARGS: -debug=MIPS_O64 +// REQUIRED_ARGS: -debug=MIPS_N64 +// REQUIRED_ARGS: -debug=MIPS_EABI +// REQUIRED_ARGS: -debug=MIPS_SoftFloat +// REQUIRED_ARGS: -debug=MIPS_HardFloat +// REQUIRED_ARGS: -debug=NVPTX +// REQUIRED_ARGS: -debug=NVPTX64 +// REQUIRED_ARGS: -debug=SPARC +// REQUIRED_ARGS: -debug=SPARC_V8Plus +// REQUIRED_ARGS: -debug=SPARC_SoftFloat +// REQUIRED_ARGS: -debug=SPARC_HardFloat +// REQUIRED_ARGS: -debug=SPARC64 +// REQUIRED_ARGS: -debug=S390 +// REQUIRED_ARGS: -debug=S390X +// REQUIRED_ARGS: -debug=SystemZ +// REQUIRED_ARGS: -debug=HPPA +// REQUIRED_ARGS: -debug=HPPA64 +// REQUIRED_ARGS: -debug=SH +// REQUIRED_ARGS: -debug=Alpha +// REQUIRED_ARGS: -debug=Alpha_SoftFloat +// REQUIRED_ARGS: -debug=Alpha_HardFloat +// REQUIRED_ARGS: -debug=LittleEndian +// REQUIRED_ARGS: -debug=BigEndian +// REQUIRED_ARGS: -debug=ELFv1 +// REQUIRED_ARGS: -debug=ELFv2 +// REQUIRED_ARGS: -debug=CRuntime_Bionic +// REQUIRED_ARGS: -debug=CRuntime_DigitalMars +// REQUIRED_ARGS: -debug=CRuntime_Glibc +// REQUIRED_ARGS: -debug=CRuntime_Microsoft +// REQUIRED_ARGS: -debug=CRuntime_Musl +// REQUIRED_ARGS: -debug=CRuntime_UClibc +// REQUIRED_ARGS: -debug=D_Coverage +// REQUIRED_ARGS: -debug=D_Ddoc +// REQUIRED_ARGS: -debug=D_InlineAsm_X86 +// REQUIRED_ARGS: -debug=D_InlineAsm_X86_64 +// REQUIRED_ARGS: -debug=D_LP64 +// REQUIRED_ARGS: -debug=D_X32 +// REQUIRED_ARGS: -debug=D_HardFloat +// REQUIRED_ARGS: -debug=D_SoftFloat +// REQUIRED_ARGS: -debug=D_PIC +// REQUIRED_ARGS: -debug=D_SIMD +// REQUIRED_ARGS: -debug=D_Version2 +// REQUIRED_ARGS: -debug=D_NoBoundsChecks +// REQUIRED_ARGS: -debug=unittest +// REQUIRED_ARGS: -debug=assert +// REQUIRED_ARGS: -debug=all +// REQUIRED_ARGS: -debug=none +/* +TEST_OUTPUT: +--- +Error: version identifier `DigitalMars` is reserved and cannot be set +Error: version identifier `GNU` is reserved and cannot be set +Error: version identifier `LDC` is reserved and cannot be set +Error: version identifier `SDC` is reserved and cannot be set +Error: version identifier `Windows` is reserved and cannot be set +Error: version identifier `Win32` is reserved and cannot be set +Error: version identifier `Win64` is reserved and cannot be set +Error: version identifier `linux` is reserved and cannot be set +Error: version identifier `OSX` is reserved and cannot be set +Error: version identifier `FreeBSD` is reserved and cannot be set +Error: version identifier `OpenBSD` is reserved and cannot be set +Error: version identifier `NetBSD` is reserved and cannot be set +Error: version identifier `DragonFlyBSD` is reserved and cannot be set +Error: version identifier `BSD` is reserved and cannot be set +Error: version identifier `Solaris` is reserved and cannot be set +Error: version identifier `Posix` is reserved and cannot be set +Error: version identifier `AIX` is reserved and cannot be set +Error: version identifier `Haiku` is reserved and cannot be set +Error: version identifier `SkyOS` is reserved and cannot be set +Error: version identifier `SysV3` is reserved and cannot be set +Error: version identifier `SysV4` is reserved and cannot be set +Error: version identifier `Hurd` is reserved and cannot be set +Error: version identifier `Android` is reserved and cannot be set +Error: version identifier `Cygwin` is reserved and cannot be set +Error: version identifier `MinGW` is reserved and cannot be set +Error: version identifier `FreeStanding` is reserved and cannot be set +Error: version identifier `X86` is reserved and cannot be set +Error: version identifier `X86_64` is reserved and cannot be set +Error: version identifier `ARM` is reserved and cannot be set +Error: version identifier `ARM_Thumb` is reserved and cannot be set +Error: version identifier `ARM_SoftFloat` is reserved and cannot be set +Error: version identifier `ARM_SoftFP` is reserved and cannot be set +Error: version identifier `ARM_HardFloat` is reserved and cannot be set +Error: version identifier `AArch64` is reserved and cannot be set +Error: version identifier `Epiphany` is reserved and cannot be set +Error: version identifier `PPC` is reserved and cannot be set +Error: version identifier `PPC_SoftFloat` is reserved and cannot be set +Error: version identifier `PPC_HardFloat` is reserved and cannot be set +Error: version identifier `PPC64` is reserved and cannot be set +Error: version identifier `IA64` is reserved and cannot be set +Error: version identifier `MIPS32` is reserved and cannot be set +Error: version identifier `MIPS64` is reserved and cannot be set +Error: version identifier `MIPS_O32` is reserved and cannot be set +Error: version identifier `MIPS_N32` is reserved and cannot be set +Error: version identifier `MIPS_O64` is reserved and cannot be set +Error: version identifier `MIPS_N64` is reserved and cannot be set +Error: version identifier `MIPS_EABI` is reserved and cannot be set +Error: version identifier `MIPS_SoftFloat` is reserved and cannot be set +Error: version identifier `MIPS_HardFloat` is reserved and cannot be set +Error: version identifier `NVPTX` is reserved and cannot be set +Error: version identifier `NVPTX64` is reserved and cannot be set +Error: version identifier `RISCV32` is reserved and cannot be set +Error: version identifier `RISCV64` is reserved and cannot be set +Error: version identifier `SPARC` is reserved and cannot be set +Error: version identifier `SPARC_V8Plus` is reserved and cannot be set +Error: version identifier `SPARC_SoftFloat` is reserved and cannot be set +Error: version identifier `SPARC_HardFloat` is reserved and cannot be set +Error: version identifier `SPARC64` is reserved and cannot be set +Error: version identifier `S390` is reserved and cannot be set +Error: version identifier `S390X` is reserved and cannot be set +Error: version identifier `SystemZ` is reserved and cannot be set +Error: version identifier `HPPA` is reserved and cannot be set +Error: version identifier `HPPA64` is reserved and cannot be set +Error: version identifier `SH` is reserved and cannot be set +Error: version identifier `Alpha` is reserved and cannot be set +Error: version identifier `Alpha_SoftFloat` is reserved and cannot be set +Error: version identifier `Alpha_HardFloat` is reserved and cannot be set +Error: version identifier `LittleEndian` is reserved and cannot be set +Error: version identifier `BigEndian` is reserved and cannot be set +Error: version identifier `ELFv1` is reserved and cannot be set +Error: version identifier `ELFv2` is reserved and cannot be set +Error: version identifier `CRuntime_Bionic` is reserved and cannot be set +Error: version identifier `CRuntime_DigitalMars` is reserved and cannot be set +Error: version identifier `CRuntime_Glibc` is reserved and cannot be set +Error: version identifier `CRuntime_Microsoft` is reserved and cannot be set +Error: version identifier `CRuntime_Musl` is reserved and cannot be set +Error: version identifier `CRuntime_UClibc` is reserved and cannot be set +Error: version identifier `D_Coverage` is reserved and cannot be set +Error: version identifier `D_Ddoc` is reserved and cannot be set +Error: version identifier `D_InlineAsm_X86` is reserved and cannot be set +Error: version identifier `D_InlineAsm_X86_64` is reserved and cannot be set +Error: version identifier `D_LP64` is reserved and cannot be set +Error: version identifier `D_X32` is reserved and cannot be set +Error: version identifier `D_HardFloat` is reserved and cannot be set +Error: version identifier `D_SoftFloat` is reserved and cannot be set +Error: version identifier `D_PIC` is reserved and cannot be set +Error: version identifier `D_SIMD` is reserved and cannot be set +Error: version identifier `D_Version2` is reserved and cannot be set +Error: version identifier `D_NoBoundsChecks` is reserved and cannot be set +Error: version identifier `unittest` is reserved and cannot be set +Error: version identifier `assert` is reserved and cannot be set +Error: version identifier `all` is reserved and cannot be set +Error: version identifier `none` is reserved and cannot be set +--- +*/ diff --git a/gcc/testsuite/gdc.test/fail_compilation/retref2.d b/gcc/testsuite/gdc.test/fail_compilation/retref2.d new file mode 100644 index 00000000000..037c258539b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/retref2.d @@ -0,0 +1,23 @@ + +// REQUIRED_ARGS: -dip25 + +/* +TEST_OUTPUT: +--- +fail_compilation/retref2.d(21): Error: function retref2.D.foo does not override any function, did you mean to override 'retref2.C.foo'? +fail_compilation/retref2.d(22): Error: function retref2.D.bar does not override any function, did you mean to override 'retref2.C.bar'? +--- +*/ + + +class C +{ + ref int foo(ref int); + ref int bar(); +} + +class D : C +{ + override ref int foo(return ref int); + override ref int bar() return; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d new file mode 100644 index 00000000000..35efda38ac3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d @@ -0,0 +1,662 @@ +/* +REQUIRED_ARGS: -dip1000 +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/retscope.d(23): Error: scope variable `p` may not be returned +fail_compilation/retscope.d(33): Error: returning `b ? nested1(& i) : nested2(& j)` escapes a reference to local variable `j` +fail_compilation/retscope.d(46): Error: scope variable `p` assigned to non-scope `q` +fail_compilation/retscope.d(48): Error: address of variable `i` assigned to `q` with longer lifetime +fail_compilation/retscope.d(49): Error: variadic variable `a` assigned to non-scope `b` +fail_compilation/retscope.d(50): Error: reference to stack allocated value returned by `(*fp2)()` assigned to non-scope `q` +--- +*/ + + + + +int* foo1(return scope int* p) { return p; } // ok + +int* foo2()(scope int* p) { return p; } // ok, 'return' is inferred +alias foo2a = foo2!(); + +int* foo3(scope int* p) { return p; } // error + +int* foo4(bool b) +{ + int i; + int j; + + int* nested1(scope int* p) { return null; } + int* nested2(return scope int* p) { return p; } + + return b ? nested1(&i) : nested2(&j); +} + +/************************************************/ + +struct S2 { int a,b,c,d; } + +@safe S2 function() fp2; + +void test2(scope int* p, int[] a ...) @safe +{ + static int* q; + static int[] b; + q = p; + int i; + q = &i; + b = a; + q = &fp2().d; +} + +/**************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(76): Error: function retscope.HTTP.Impl.onReceive is @nogc yet allocates closures with the GC +fail_compilation/retscope.d(78): retscope.HTTP.Impl.onReceive.__lambda1 closes over variable this at fail_compilation/retscope.d(76) +--- +*/ + + +struct Curl +{ + int delegate() dg; +} + +struct HTTP +{ + struct Impl + { + Curl curl; + int x; + + @nogc void onReceive() + { + auto dg = ( ) { return x; }; + curl.dg = dg; + } + } +} + +/***********************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(97): Error: reference to local variable `sa` assigned to non-scope parameter `a` calling retscope.bar8 +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=8838 + +int[] foo8() @safe +{ + int[5] sa; + return bar8(sa); +} + +int[] bar8(int[] a) @safe +{ + return a; +} + + +/*************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(124): Error: returning `foo9(cast(char[])tmp)` escapes a reference to local variable `tmp` +--- +*/ + +char[] foo9(return char[] a) @safe pure nothrow @nogc +{ + return a; +} + +char[] bar9() @safe +{ + char[20] tmp; + foo9(tmp); // ok + return foo9(tmp); // error +} + +/*************************************************/ + +/* +// +// +//fail_compilation/retscope.d(143): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope' +// +*/ + +struct S10 +{ + static int opApply(int delegate(S10*) dg); +} + +S10* test10() +{ + foreach (S10* m; S10) + return m; + return null; +} + +/************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(159): Error: scope variable `this` may not be returned +--- +*/ + +class C11 +{ + @safe C11 foo() scope { return this; } +} + + +/****************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(178): Error: address of variable `i` assigned to `p` with longer lifetime +--- +*/ + + + +void foo11() @safe +{ + int[] p; + int[3] i; + p = i[]; +} + +/************************************************/ +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(198): Error: scope variable `e` may not be returned +--- +*/ + +struct Escaper +{ + void* DG; +} + +void* escapeDg1(scope void* d) @safe +{ + Escaper e; + e.DG = d; + return e.DG; +} + +/*************************************************/ +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(213): Error: scope variable `p` assigned to non-scope `e` +--- +*/ +struct Escaper3 { void* e; } + +void* escape3 (scope void* p) @safe { + Escaper3 e; + scope dg = () { return e.e; }; + e.e = p; + return dg(); +} + +/**************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(230): Error: scope variable `ptr` may not be returned +--- +*/ + +alias dg_t = void* delegate () return scope @safe; + +void* funretscope(scope dg_t ptr) @safe +{ + return ptr(); +} + +/*****************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda1` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` +fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda1` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` +fail_compilation/retscope.d(250): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` +fail_compilation/retscope.d(250): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe` +--- +*/ + +void escape4() @safe +{ + alias FunDG = void* delegate () @safe; + int x = 42; + scope FunDG f = () return { return &x; }; + scope FunDG g = () { return &x; }; +} + +/**************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(267): Error: cannot take address of scope local p in @safe function escape5 +--- +*/ + +void escape5() @safe +{ + int* q; + scope int* p; + scope int** pp = &q; // ok + pp = &p; // error +} + +/***********************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(287): Error: returning `foo6(& b)` escapes a reference to local variable `b` +--- +*/ + +@safe int* foo6()(int* arg) +{ + return arg; +} + +int* escape6() @safe +{ + int b; + return foo6(&b); +} + +/***************************************************/ + +struct S7 +{ + int[10] a; + int[3] abc(int i) @safe + { + return a[0 .. 3]; // should not error + } +} + +/***************************************************/ + +int[3] escape8(scope int[] p) @safe { return p[0 .. 3]; } // should not error +char*[3] escape9(scope char*[] p) @safe { return p[0 .. 3]; } + +/***************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(320): Error: reference to local variable `i` assigned to non-scope `f` +--- +*/ + +int* escape10() @safe +{ + int i; + int* f; + scope int** x = &f; + f = &i; + + return bar10(x); +} + +int* bar10( scope int** ptr ) @safe +{ + return *ptr; +} + +/******************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(343): Error: cannot take address of scope local aa in @safe function escape11 +--- +*/ + +int* escape11() @safe +{ + int i; + int*[3] aa = [ &i, null, null ]; + return bar11(&aa[0]); +} + +int* bar11(scope int** x) @safe +{ + return foo11(*x); +} + +int* foo11(int* x) @safe { return x; } + +/******************************************/ + +void escape15() @safe +{ + int arg; + const(void)*[1] argsAddresses; + argsAddresses[0] = // MUST be an array assignment + (ref arg)@trusted{ return cast(const void*) &arg; }(arg); +} + +/******************************************/ +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1003): Error: returning `f.foo()` escapes a reference to local variable `f` +--- +*/ + +#line 1000 +int* escape12() @safe +{ + Foo12 f; + return f.foo; +} + +struct Foo12 +{ + int* foo() return @safe; +} + +/******************************************/ +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1103): Error: scope variable `f` may not be returned +--- +*/ + +#line 1100 +int* escape13() @safe +{ + scope Foo13 f; + return f.foo; +} + +class Foo13 +{ + int* foo() return @safe; +} + +/******************************************/ +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1205): Error: scope variable `f14` assigned to non-scope parameter `this` calling retscope.Foo14.foo +--- +*/ + +#line 1200 +int* escape14() @safe +{ + int i; + Foo14 f14; + f14.v = &i; + return f14.foo; +} + +struct Foo14 +{ + int* v; + int* foo () @safe { return this.v; } +} + +/******************************************/ +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1311): Error: scope variable `u2` assigned to `ek` with longer lifetime +--- +*/ + +#line 1300 +@safe struct U13 { + int* k; + int* get() return scope { return k; } + static int* sget(return scope ref U13 u) { return u.k; } +} + +@safe void foo13() { + int* ek; + + int i; + auto u2 = U13(&i); + ek = U13.sget(u2); // Error: scope variable u2 assigned to ek with longer lifetime + + auto u1 = U13(new int); + ek = u1.get(); // ok + ek = U13.sget(u1); // ok +} + +/************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assigned to non-scope parameter `unnamed` calling retscope.myprintf +--- +*/ + +#line 1400 +@trusted extern(C) int myprintf(const(char)*, ...); + +@safe void foo14() +{ + char[4] buf = [ 'h', 'i', '\n', 0 ]; + myprintf(&buf[0]); +} + +/************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1509): Error: reference to stack allocated value returned by `(*fp15)()` assigned to non-scope parameter `unnamed` +--- +*/ + +#line 1500 + +@safe void bar15(int*); + +struct S15 { int a,b,c,d; } + +@safe S15 function() fp15; + +void test15() @safe +{ + bar15(&fp15().d); +} + + +/*************************************************/ + +void foo16() @nogc nothrow +{ + alias dg_t = string delegate(string) @nogc nothrow; + + dg_t dg = (string s) => s; +} + +/*************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1701): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(scope int* p)` +fail_compilation/retscope.d(1702): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(return scope int* p)` +fail_compilation/retscope.d(1703): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(return scope int* p)` +fail_compilation/retscope.d(1711): Error: cannot implicitly convert expression `& funcr` of type `int* function(return scope int* p)` to `int* function(scope int* p)` +fail_compilation/retscope.d(1716): Error: cannot implicitly convert expression `& funcrs` of type `int* function(return scope int* p)` to `int* function(scope int* p)` +--- +*/ + +int* func(int* p); +int* funcs(scope int* p); +int* funcr(return int* p); +int* funcrs(return scope int* p); + +void foo17() +{ +#line 1700 + typeof(func) *fp1 = &func; + typeof(funcs) *fp2 = &func; // error + typeof(funcr) *fp3 = &func; // error + typeof(funcrs) *fp4 = &func; // error + + typeof(func) *fq1 = &funcs; + typeof(funcs) *fq2 = &funcs; + typeof(funcr) *fq3 = &funcs; + typeof(funcrs) *fq4 = &funcs; + + typeof(func) *fr1 = &funcr; + typeof(funcs) *fr2 = &funcr; // error + typeof(funcr) *fr3 = &funcr; + typeof(funcrs) *fr4 = &funcr; + + typeof(func) *fs1 = &funcrs; + typeof(funcs) *fs2 = &funcrs; // error + typeof(funcr) *fs3 = &funcrs; + typeof(funcrs) *fs4 = &funcrs; +} + +/*************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope.d(1801): Error: cannot implicitly convert expression `&c.func` of type `int* delegate()` to `int* delegate() scope` +fail_compilation/retscope.d(1802): Error: cannot implicitly convert expression `&c.func` of type `int* delegate()` to `int* delegate() return scope` +fail_compilation/retscope.d(1803): Error: cannot implicitly convert expression `&c.func` of type `int* delegate()` to `int* delegate() return scope` +fail_compilation/retscope.d(1811): Error: cannot implicitly convert expression `&c.funcr` of type `int* delegate() return scope` to `int* delegate() scope` +fail_compilation/retscope.d(1816): Error: cannot implicitly convert expression `&c.funcrs` of type `int* delegate() return scope` to `int* delegate() scope` +--- +*/ + +class C18 +{ + int* func(); + int* funcs() scope; + int* funcr() return; + int* funcrs() return scope; +} + +void foo18() +{ + C18 c; + +#line 1800 + typeof(&c.func) fp1 = &c.func; + typeof(&c.funcs) fp2 = &c.func; // error + typeof(&c.funcr) fp3 = &c.func; // error + typeof(&c.funcrs) fp4 = &c.func; // error + + typeof(&c.func) fq1 = &c.funcs; + typeof(&c.funcs) fq2 = &c.funcs; + typeof(&c.funcr) fq3 = &c.funcs; + typeof(&c.funcrs) fq4 = &c.funcs; + + typeof(&c.func) fr1 = &c.funcr; + typeof(&c.funcs) fr2 = &c.funcr; // error + typeof(&c.funcr) fr3 = &c.funcr; + typeof(&c.funcrs) fr4 = &c.funcr; + + typeof(&c.func) fs1 = &c.funcrs; + typeof(&c.funcs) fs2 = &c.funcrs; // error + typeof(&c.funcr) fs3 = &c.funcrs; + typeof(&c.funcrs) fs4 = &c.funcrs; +} + +/*********************************************/ + +@safe void foo19(C)(ref C[] str) // infer 'scope' for 'str' +{ + str = str; + str = str[1 .. str.length]; +} + +@safe void test19() +{ + char[10] s; + char[] t = s[]; + foo19(t); +} + +/********************************************/ + + +bool foo20(const string a) @safe pure nothrow @nogc +{ + return !a.length; +} + +struct Result(R) +{ + R source; + + bool empty() // infer 'scope' for 'this' + { return foo20(source); } +} + +@safe void test20() +{ + scope n = Result!string("abc"); + n.empty(); +} + +/************************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=17117 + +ref int foo21(return ref int s) +{ + return s; +} + +int fail21() +{ + int s; + return foo21(s); // Error: escaping reference to local variable s +} + +int test21() +{ + int s; + s = foo21(s); + return s; +} + +/**********************************************/ + +@safe void foo22()(ref char[] s) +{ + char[] a = s; +} + +@safe void test22(scope char[] s) +{ + foo22(s); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d new file mode 100644 index 00000000000..a565008a792 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d @@ -0,0 +1,295 @@ +/* +REQUIRED_ARGS: -dip1000 +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(102): Error: scope variable `s` assigned to `p` with longer lifetime +fail_compilation/retscope2.d(107): Error: address of variable `s` assigned to `p` with longer lifetime +--- +*/ + +#line 100 +@safe foo1(ref char[] p, scope char[] s) +{ + p = s; +} + +@safe bar1(ref char* p, char s) +{ + p = &s; +} + +/**********************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=17123 + +void test200() +{ + char[256] buffer; + + char[] delegate() read = () { + return buffer[]; + }; +} + +/**********************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(302): Error: scope variable `a` assigned to return scope `b` +--- +*/ + +#line 300 +@safe int* test300(scope int* a, return scope int* b) +{ + b = a; + return b; +} + +/**********************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(403): Error: scope variable `a` assigned to return scope `c` +--- +*/ + +#line 400 +@safe int* test400(scope int* a, return scope int* b) +{ + auto c = b; // infers 'return scope' for 'c' + c = a; + return c; +} + +/**********************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(504): Error: scope variable `c` may not be returned +--- +*/ + +#line 500 +@safe int* test500(scope int* a, return scope int* b) +{ + scope c = b; // does not infer 'return' for 'c' + c = a; + return c; +} + +/**********************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope parameter `unnamed` calling retscope2.foo600 +fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope parameter `unnamed` calling retscope2.foo600 +fail_compilation/retscope2.d(614): Error: template instance retscope2.test600!(int*, int*) error instantiating +--- +*/ + +#line 600 +@safe test600(A...)(scope A args) +{ + foreach (i, Arg; A) + { + foo600(args[i]); + } +} + +@safe void foo600(int*); + +@safe bar600() +{ + scope int* p; + scope int* q; + test600(p, q); +} + +/*************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(719): Error: returning `get2(s)` escapes a reference to local variable `s` +fail_compilation/retscope2.d(721): Error: returning `s.get1()` escapes a reference to local variable `s` +--- +*/ + +#line 700 +// https://issues.dlang.org/show_bug.cgi?id=17049 + +@safe S700* get2(return ref scope S700 _this) +{ + return &_this; +} + +struct S700 +{ + @safe S700* get1() return scope + { + return &this; + } +} + +S700* escape700(int i) @safe +{ + S700 s; + if (i) + return s.get2(); // 719 + else + return s.get1(); // 721 +} + +/*************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(804): Error: scope variable `e` may not be thrown +--- +*/ + +#line 800 + +void foo800() +{ + scope Exception e; + throw e; +} + +/*************************************************/ +/+ +/* +XEST_OUTPUT: + +fail_compilation/retscope2.d(907): Error: address of variable `this` assigned to `p17568` with longer lifetime + +*/ + +#line 900 + +int* p17568; +struct T17568 +{ + int a; + void escape() @safe scope + { + p17568 = &a; + } +} ++/ +/*************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(1005): Error: scope variable `p` assigned to `this` with longer lifetime +fail_compilation/retscope2.d(1024): Error: scope variable `p` assigned to `d` with longer lifetime +--- +*/ + +#line 1000 + +class C17428 +{ + void set(scope int* p) @safe + { + _p = p; + } + + int* _p; +} + +class C17428b +{ + int* _p; +} + +void test17428() @safe +{ + int x; + int* p = &x; + scope C17428b c; + c._p = p; // ok + + C17428b d; + d._p = p; // bad +} + + + +/*************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(1107): Error: scope variable `dg` may not be returned +--- +*/ + +#line 1100 + +struct S17430 { void foo() {} } + +void delegate() test17430() @safe +{ + S17430 s; + auto dg = &s.foo; // infer dg as scope + return dg; +} + +/****************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/retscope2.d(1216): Error: returning `s.foo()` escapes a reference to local variable `s` +fail_compilation/retscope2.d(1233): Error: returning `t.foo()` escapes a reference to local variable `t` +--- +*/ + +#line 1200 +// https://issues.dlang.org/show_bug.cgi?id=17388 + +struct S17388 +{ + //int* + auto + foo() return @safe + { + return &x; + } + int x; +} + +@safe int* f17388() +{ + S17388 s; + return s.foo(); +} + +struct T17388 +{ + //int[] + auto + foo() return @safe + { + return x[]; + } + int[4] x; +} + +@safe int[] g17388() +{ + T17388 t; + return t.foo(); +} + + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/skip.d b/gcc/testsuite/gdc.test/fail_compilation/skip.d new file mode 100644 index 00000000000..c870e7e945a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/skip.d @@ -0,0 +1,52 @@ +/* + * REQUIRED_ARGS: -de + * TEST_OUTPUT: +--- +fail_compilation/skip.d(21): Deprecation: 'switch' skips declaration of 'with' temporary at fail_compilation/skip.d(26) +fail_compilation/skip.d(43): Deprecation: 'switch' skips declaration of variable skip.test14532.n at fail_compilation/skip.d(45) +--- + */ +// https://issues.dlang.org/show_bug.cgi?id=10524 + +struct S +{ + int field; +} + +void test10524() +{ + int a = 1; + S struct_with_long_name; + + switch( a ) + { + case 0: + struct_with_long_name.field = 444; // ok + break; + with( struct_with_long_name ) + { + case 1: + field = 555; // segfault + break; + } + + default: + break; + } +} + +// https://issues.dlang.org/show_bug.cgi?id=14532 + +void test14532() +{ + char ch = '!'; + switch (ch) + { + int n = 42; + case '!': + assert(n == 42); + break; + + default: + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/spell9644.d b/gcc/testsuite/gdc.test/fail_compilation/spell9644.d new file mode 100644 index 00000000000..383ec677586 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/spell9644.d @@ -0,0 +1,36 @@ +// REQUIRED_ARGS: -o- +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/spell9644.d(27): Error: undefined identifier `b` +fail_compilation/spell9644.d(28): Error: undefined identifier `xx` +fail_compilation/spell9644.d(29): Error: undefined identifier `cb`, did you mean variable `ab`? +fail_compilation/spell9644.d(30): Error: undefined identifier `bc`, did you mean variable `abc`? +fail_compilation/spell9644.d(31): Error: undefined identifier `ccc` +fail_compilation/spell9644.d(33): Error: undefined identifier `cor2`, did you mean variable `cor1`? +fail_compilation/spell9644.d(34): Error: undefined identifier `pua`, did you mean variable `pub`? +fail_compilation/spell9644.d(35): Error: undefined identifier `priw` +--- +*/ + +import imports.spell9644a; + +int a; +int ab; +int abc; +int cor1; + +int main() +{ + cast(void)b; // max distance 0, no match + cast(void)xx; // max distance 1, no match + cast(void)cb; // max distance 1, match + cast(void)bc; // max distance 1, match + cast(void)ccc; // max distance 2, match + + cast(void)cor2; // max distance 1, match "cor1", but not cora from import (bug 13736) + cast(void)pua; // max distance 1, match "pub" from import + cast(void)priw; // max distance 1, match "priv" from import, but do not report (bug 5839) +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d new file mode 100644 index 00000000000..8743bf1993e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d @@ -0,0 +1,23 @@ +/* +REQUIRED_ARGS: -m64 +PERMUTE_ARGS: +--- +fail_compilation/staticarrayoverflow.d(21): Error: static array S[1879048192] size overflowed to 7516192768000 +fail_compilation/staticarrayoverflow.d(21): Error: variable staticarrayoverflow.y size overflow +fail_compilation/staticarrayoverflow.d(22): Error: variable staticarrayoverflow.z size of x1000ae0 exceeds max allowed size 0x100_0000 +fail_compilation/staticarrayoverflow.d(23): Error: static array S[8070450532247928832] size overflowed to 0 +fail_compilation/staticarrayoverflow.d(23): Error: variable staticarrayoverflow.a size overflow +--- +*/ + + + +struct S +{ + int[1000] x; +} + +S[0x7000_0000] y; +S[0x100_0000/(4*1000 - 1)] z; +S[0x7000_0000_0000_0000] a; + diff --git a/gcc/testsuite/gdc.test/fail_compilation/switches.d b/gcc/testsuite/gdc.test/fail_compilation/switches.d new file mode 100644 index 00000000000..c96ddb27288 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/switches.d @@ -0,0 +1,74 @@ +/* +REQUIRED_ARGS: +PERMUTE_ARGS: +*/ + +/************************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/switches.d(105): Error: `case 2` not found +--- +*/ + +#line 100 +void test1(int i) +{ + switch (i) + { + case 1: + goto case 2; + defaut: + break; + } +} + +/************************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/switches.d(205): Error: no case statement following goto case; +--- +*/ + +#line 200 +void test2(int i) +{ + switch (i) + { + case 1: + goto case; + defaut: + break; + } +} + +/************************************************************/ + +/* +TEST_OUTPUT: +--- +fail_compilation/switches.d(302): Deprecation: 'switch' skips declaration of variable switches.test3.j at fail_compilation/switches.d(306) +--- +*/ + +#line 300 +void test3(int i) +{ + switch (i) + { + case 1: + { + int j; + case 2: + ++j; + break; + } + default: + break; + } +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test1.d b/gcc/testsuite/gdc.test/fail_compilation/test1.d new file mode 100644 index 00000000000..9dae856c349 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test1.d @@ -0,0 +1 @@ +fail diff --git a/gcc/testsuite/gdc.test/fail_compilation/test11047.d b/gcc/testsuite/gdc.test/fail_compilation/test11047.d new file mode 100644 index 00000000000..ef8007d434b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test11047.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test11047.d(11): Error: value of x is not known at compile time +fail_compilation/test11047.d(11): Error: value of x is not known at compile time +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=11047 + +int x; +@(++x, ++x) void foo(){} + +@safe pure void test() +{ + __traits(getAttributes, foo); + __traits(getAttributes, foo)[0]; +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test11176.d b/gcc/testsuite/gdc.test/fail_compilation/test11176.d new file mode 100644 index 00000000000..242119e71db --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test11176.d @@ -0,0 +1,18 @@ +/* +REQUIRED_ARGS: -de +--- +fail_compilation/test11176.d(12): Deprecation: b.ptr cannot be used in @safe code, use &b[0] instead +fail_compilation/test11176.d(16): Deprecation: b.ptr cannot be used in @safe code, use &b[0] instead +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=11176 + +@safe ubyte oops(ubyte[] b) { + return *b.ptr; +} + +@safe ubyte oops(ubyte[3] b) { + return *b.ptr; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test12822.d b/gcc/testsuite/gdc.test/fail_compilation/test12822.d new file mode 100644 index 00000000000..fe710981fe3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test12822.d @@ -0,0 +1,17 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test12822.d(13): Error: cannot modify delegate pointer in @safe code dg.ptr +fail_compilation/test12822.d(14): Error: dg.funcptr cannot be used in @safe code +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=12822 +void test2(int delegate() dg) @safe +{ + static int i; + dg.ptr = &i; + dg.funcptr = &func; +} + +int func(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test12979.d b/gcc/testsuite/gdc.test/fail_compilation/test12979.d new file mode 100644 index 00000000000..95cd3aae1e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test12979.d @@ -0,0 +1,16 @@ +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/test12979.d(13): Error: const/immutable/shared/inout attributes are not allowed on `asm` blocks +--- +*/ + +void foo() +{ + asm const shared + { + ret; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13152.d b/gcc/testsuite/gdc.test/fail_compilation/test13152.d new file mode 100644 index 00000000000..814dcb7d3f0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test13152.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test13152.d(11): Error: undefined identifier `x` +--- +*/ +import imports.test13152a; + +void main() +{ + auto y = x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13536.d b/gcc/testsuite/gdc.test/fail_compilation/test13536.d new file mode 100644 index 00000000000..800757dcf6c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test13536.d @@ -0,0 +1,27 @@ +/* +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test13536.d(24): Error: field U.sysDg cannot access pointers in @safe code that overlap other fields +fail_compilation/test13536.d(24): Error: address of variable `s` assigned to `u` with longer lifetime +fail_compilation/test13536.d(25): Error: field U.safeDg cannot access pointers in @safe code that overlap other fields +--- +*/ + + +// https://issues.dlang.org/show_bug.cgi?id=13536 + +struct S { + void sysMethod() @system {} +} +void fun() @safe { + union U { + void delegate() @system sysDg; + void delegate() @safe safeDg; + } + U u; + S s; + u.sysDg = &s.sysMethod; + u.safeDg(); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13537.d b/gcc/testsuite/gdc.test/fail_compilation/test13537.d new file mode 100644 index 00000000000..0e087dd5640 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test13537.d @@ -0,0 +1,61 @@ +/* +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test13537.d(32): Error: field U.y cannot modify fields in @safe code that overlap fields with other storage classes +fail_compilation/test13537.d(33): Error: field U.y cannot modify fields in @safe code that overlap fields with other storage classes +fail_compilation/test13537.d(34): Error: field U.z cannot access pointers in @safe code that overlap other fields +fail_compilation/test13537.d(35): Error: field U.y cannot modify fields in @safe code that overlap fields with other storage classes +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=13537 + +union U +{ + immutable int x; + int y; + int* z; +} + +union V +{ + immutable int x; + const int y; +} + +void fun() @safe +{ + U u; + + // errors + u.y = 1; + int* p = &u.y; + int** q = &u.z; + abc(u.y); + + // read access is allowed + int a = u.x; + a = u.y; + def(u.y); + + // Overlapping const/immutable is allowed + auto v = V(1); + assert(v.y == 1); +} + +void gun() @system +{ + U u; + + // allowed because system code + u.y = 1; + int* p = &u.y; + int** q = &u.z; + abc(u.y); +} + +@safe: +void abc(ref int x) { } +void def(const ref int x) { } + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13786.d b/gcc/testsuite/gdc.test/fail_compilation/test13786.d new file mode 100644 index 00000000000..3b05dcc40dc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test13786.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test13786.d(14): Error: debug 123 level declaration must be at module level +fail_compilation/test13786.d(15): Error: debug abc declaration must be at module level +fail_compilation/test13786.d(16): Error: version 123 level declaration must be at module level +fail_compilation/test13786.d(17): Error: version abc declaration must be at module level +fail_compilation/test13786.d(20): Error: template instance test13786.T!() error instantiating +--- +*/ + +template T() +{ + debug = 123; + debug = abc; + version = 123; + version = abc; +} + +alias X = T!(); diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13867.d b/gcc/testsuite/gdc.test/fail_compilation/test13867.d new file mode 100644 index 00000000000..aebab2badf9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test13867.d @@ -0,0 +1,40 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test13867.d(12): Error: function test13867.X.blah does not override any function, did you mean to override 'extern (C++) test13867.Base.blah'? +fail_compilation/test13867.d(19): Error: function test13867.Z.blah does not override any function, did you mean to override 'extern (C++) test13867.Base.blah'? +--- +*/ +extern (C++) class Base { + void blah() {} +} +class X : Base { + override void blah();//Error +} +extern (C++) class Y : Base { + override void blah(){} +} +class Z : Base { + alias blah = super.blah; + override void blah(){}//Error +} +class O : Base { + extern (C++) override void blah(){} +} +extern (C++) class OK : Base { + alias blah = super.blah; + override void blah(){} +} + +void main() { + scope b = new Base(); + b.blah(); + scope x = new X(); + x.blah(); + scope y = new Y(); + y.blah(); + scope o = new O(); + o.blah(); + scope z = new Z(); + z.blah(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14238.d b/gcc/testsuite/gdc.test/fail_compilation/test14238.d new file mode 100644 index 00000000000..2d5f58630b2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test14238.d @@ -0,0 +1,30 @@ +/* REQUIRED_ARGS: -dip1000 + PERMUTE_ARGS: + TEST_OUTPUT: +--- +fail_compilation/test14238.d(21): Error: scope variable `fn` may not be returned +fail_compilation/test14238.d(29): Error: escaping reference to stack allocated value returned by `&baz` +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=14238 + +@safe: + +alias Fn = ref int delegate() return; + +ref int foo(return scope Fn fn) +{ + return fn(); // Ok +} + +ref int foo2(scope Fn fn) { + return fn(); // Error +} + +ref int bar() { + int x; + ref int baz() { + return x; + } + return foo(&baz); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test143.d b/gcc/testsuite/gdc.test/fail_compilation/test143.d new file mode 100644 index 00000000000..94f614a9126 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test143.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -de +module test143; // Bugzilla 143 + +import imports.test143; + +void bar(int) +{ +} + +void foo() +{ + bar(x); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14496.d b/gcc/testsuite/gdc.test/fail_compilation/test14496.d new file mode 100644 index 00000000000..8575e7276ef --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test14496.d @@ -0,0 +1,53 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test14496.d(21): Error: variable test14496.foo.f void initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(24): Error: variable test14496.foo.Bar.foo void initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(28): Error: variable test14496.foo.Baz.x void initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(48): Error: variable test14496.sinister.bar void initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(49): Error: variable test14496.sinister.baz void initializers for pointers not allowed in safe functions +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=14496 + +@safe void foo() +{ + struct Foo { + int* indirection1; + Object indirection2; + string[] indirection3; + } + + Foo f = void; + + struct Bar { + Foo foo = void; + } + + struct Baz { + int* x = void; + } +} + + +struct Foo { + int* indirection1; + Object indirection2; + string[] indirection3; +} + +struct Bar { + Foo foo = void; +} + +struct Baz { + int* x = void; +} + +@safe void sinister() { + Bar bar; + Baz baz; +} + + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14538.d b/gcc/testsuite/gdc.test/fail_compilation/test14538.d new file mode 100644 index 00000000000..b0b76a7f505 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test14538.d @@ -0,0 +1,20 @@ +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/test14538.d(19): Error: cannot implicitly convert expression `x ? cast(uint)this.fCells[x].code : 32u` of type `uint` to `Cell` +--- +*/ + +struct Cell +{ + dchar code; + alias code this; +} + +struct Row +{ + Cell[] fCells; + Cell opIndex(size_t x) { return x ? fCells[x] : ' '; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d new file mode 100644 index 00000000000..55b09b799f2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d @@ -0,0 +1,18 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test15191.d(17): Error: cannot take address of ref return of foo() in @safe function bar +--- +*/ + + +// https://issues.dlang.org/show_bug.cgi?id=15191 + +ref int foo(return ref int s)@safe +{ + return s; +} + +int* bar(return ref int s) @safe +{ + return &foo(s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15306.d b/gcc/testsuite/gdc.test/fail_compilation/test15306.d new file mode 100644 index 00000000000..ad51371b2bd --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15306.d @@ -0,0 +1,29 @@ +/* +REQUIRED_ARGS: +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test15306.d(17): Error: immutable delegate 'test15306.main.__dgliteral1' cannot access mutable data 'i' +fail_compilation/test15306.d(21): Error: shared delegate 'test15306.main.__dgliteral2' cannot access non-shared data 'p' +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=15306 + +void main() +{ + // immutable cannot access mutable + int i = 42; + auto dg1 = delegate void() immutable { auto inner = i; }; + + // shared cannot access unshared + int* p = &i; + auto dg2 = delegate int() shared { return *p; }; + assert(dg2() == i); + + // unshared can access shared + shared j = 43; + shared int* q = &j; + auto dg3 = delegate int() { return *q; }; + assert(dg2() == j); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15399.d b/gcc/testsuite/gdc.test/fail_compilation/test15399.d new file mode 100644 index 00000000000..8aecfdee6dc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15399.d @@ -0,0 +1,46 @@ +/* https://issues.dlang.org/show_bug.cgi?id=15399 +--- +fail_compilation/test15399.d(31): Error: writing to misaligned pointer in field S1.ptr is not @safe +fail_compilation/test15399.d(32): Error: writing to misaligned pointer in field S2.ptr is not @safe +fail_compilation/test15399.d(33): Error: taking address of misaligned pointer in field S1.ptr is not @safe +fail_compilation/test15399.d(34): Error: taking address of misaligned pointer in field S2.ptr is not @safe +fail_compilation/test15399.d(35): Error: 'ref' of misaligned pointer in field S1.ptr is not @safe +fail_compilation/test15399.d(36): Error: 'ref' of misaligned pointer in field S2.ptr is not @safe +fail_compilation/test15399.d(37): Error: 'out' of misaligned pointer in field S1.ptr is not @safe +fail_compilation/test15399.d(38): Error: 'out' of misaligned pointer in field S2.ptr is not @safe +--- +*/ + +struct S1 +{ + char c; + align (1) + int* ptr; +} + +align (1) +struct S2 +{ + int* ptr; +} + +@safe void test(S1* s1, S2* s2) +{ + int* p = s1.ptr; + p = s2.ptr; + s1.ptr = null; + s2.ptr = null; + int** pp = &s1.ptr; + pp = &s2.ptr; + bar(s1.ptr); + bar(s2.ptr); + sinister(s1.ptr); + sinister(s2.ptr); + cbar(s1.ptr); + cbar(s2.ptr); +} + +@safe void bar(ref int*); +@safe void cbar(ref const int*); +@safe void sinister(out int*); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15544.d b/gcc/testsuite/gdc.test/fail_compilation/test15544.d new file mode 100644 index 00000000000..9757dbf3dd7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15544.d @@ -0,0 +1,51 @@ +/* +REQUIRED_ARGS: -dip1000 +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test15544.d(21): Error: reference to local `this` assigned to non-scope `_del` in @safe code +fail_compilation/test15544.d(23): Error: reference to local `this` assigned to non-scope `_del` in @safe code +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=15544 + +void delegate() @safe _del; + +struct S { + int x = 42; + + @safe void test() + { + void foo() { assert(x == 42); } + _del = &foo; + + _del = { assert(x == 42); }; + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/test15544.d(47): Error: reference to local `y` assigned to non-scope `dg` in @safe code +--- +*/ + +int delegate() dg; + +void testClosure1() +{ + int* x; + int bar() { return *x; } + dg = &bar; +} + +@safe void testClosure2() +{ + scope int* y; + int bar() { return *y; } + dg = &bar; // Error + auto dg2 = &bar; +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15672.d b/gcc/testsuite/gdc.test/fail_compilation/test15672.d new file mode 100644 index 00000000000..19b5bf1c2d1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15672.d @@ -0,0 +1,38 @@ +/* + * TEST_OUTPUT: +--- +fail_compilation/test15672.d(15): Error: cast from void[] to byte[] not allowed in safe code +fail_compilation/test15672.d(25): Error: cast from void* to byte* not allowed in safe code +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=15672 + +alias byte T; +alias const(byte) CT; + +@safe T[] test1(void[] a) +{ + return cast(T[])a; +} + +@safe CT[] test2(void[] a) +{ + return cast(CT[])a; +} + +@safe T* test3(void* a) +{ + return cast(T*)a; +} + +@safe CT* test4(void* a) +{ + return cast(CT*)a; +} + +@safe T[] test5() +{ + return cast(T[])[]; +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15703.d b/gcc/testsuite/gdc.test/fail_compilation/test15703.d new file mode 100644 index 00000000000..cf24c3b4481 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15703.d @@ -0,0 +1,32 @@ +/* +REQUIRED_ARGS: -m32 +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test15703.d(17): Error: cast from Object[] to uint[] not allowed in safe code +fail_compilation/test15703.d(19): Error: cast from object.Object to const(uint)* not allowed in safe code +fail_compilation/test15703.d(22): Error: cast from uint[] to Object[] not allowed in safe code +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=15703 + +void test() @safe +{ + auto objs = [ new Object() ]; + auto longs = cast(size_t[]) objs; // error + auto longc = cast(const(size_t)[]) objs; // ok + auto longp = cast(const(size_t)*) objs[0]; // error + + size_t[] al; + objs = cast(Object[]) al; // error + + auto am = cast(int[])[]; +} + +void test2() @safe +{ + const(ubyte)[] a; + auto b = cast(const(uint[])) a; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15704.d b/gcc/testsuite/gdc.test/fail_compilation/test15704.d new file mode 100644 index 00000000000..6b4190611c7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15704.d @@ -0,0 +1,17 @@ +/* + * TEST_OUTPUT: +--- +fail_compilation/test15704.d(15): Error: cannot copy void[] to void[] in @safe code +--- + */ + +// https://issues.dlang.org/show_bug.cgi?id=15704 + +void main() @safe { + Object[] objs = [ new Object() ]; + void[] arr1 = objs; + void[] arr2 = [ 123, 345, 567 ]; + + arr1[] = arr2[]; // overwrites pointers with arbitrary ints +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15785.d b/gcc/testsuite/gdc.test/fail_compilation/test15785.d new file mode 100644 index 00000000000..b35e5105436 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15785.d @@ -0,0 +1,20 @@ +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +fail_compilation/test15785.d(17): Deprecation: imports.test15785.Base.foo is not visible from module test15785 +fail_compilation/test15785.d(17): Error: class test15785.Derived member `foo` is not accessible +fail_compilation/test15785.d(18): Deprecation: imports.test15785.Base.bar is not visible from module test15785 +fail_compilation/test15785.d(18): Error: class test15785.Derived member `bar` is not accessible +--- +*/ +import imports.test15785; + +class Derived : Base +{ + void test() + { + super.foo(); + bar(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15785b.d b/gcc/testsuite/gdc.test/fail_compilation/test15785b.d new file mode 100644 index 00000000000..1613617bcd0 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15785b.d @@ -0,0 +1,18 @@ +// REQUIRED_ARGS: -de +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +fail_compilation/test15785b.d(15): Deprecation: imports.test15785.Base.T is not visible from module test15785b +fail_compilation/test15785b.d(16): Deprecation: imports.test15785.Base.T is not visible from module test15785b +fail_compilation/test15785b.d(17): Deprecation: imports.test15785.IBase2.T is not visible from module test15785b +--- +*/ +import imports.test15785; + +class Derived : Base, IBase2 +{ + super.T t; + Base.T t2; + IBase2.T t3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15897.d b/gcc/testsuite/gdc.test/fail_compilation/test15897.d new file mode 100644 index 00000000000..19c65b46419 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15897.d @@ -0,0 +1,19 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/test15897.d(18): Deprecation: test15897.Animal.create is not visible from class Cat +--- +*/ +module test15897; +import imports.test15897; + +class Animal +{ + private void create() {} +} + +void foo(Cat cat) +{ + cat.create(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15989.d b/gcc/testsuite/gdc.test/fail_compilation/test15989.d new file mode 100644 index 00000000000..29eab9c38cb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15989.d @@ -0,0 +1,52 @@ +/* +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test15989.d(40): Error: variable test15989.main.ctRegex : Unable to initialize enum with class or pointer to struct. Use static const variable instead. +fail_compilation/test15989.d(49): Error: variable test15989.test.c : Unable to initialize enum with class or pointer to struct. Use static const variable instead. +fail_compilation/test15989.d(50): Error: cannot use non-constant CTFE pointer in an initializer '&[3][0]' +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=15989 + +import core.stdc.stdio; + +interface Kickstart{ + bool foo( int ); +} + +class ShiftOr : Kickstart +{ + bool foo( int i ) + { + printf("i = %d\n", i); + return false; + } +} + +struct Regex +{ + Kickstart kickstart; +} + +Regex regex() +{ + return Regex(new ShiftOr()); +} + +void main() +{ + enum ctRegex = regex(); + Regex r = ctRegex; + r.kickstart.foo(7); +} + +class C { } + +void test() +{ + enum c = new C(); + enum pi = new int(3); +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16095.d b/gcc/testsuite/gdc.test/fail_compilation/test16095.d new file mode 100644 index 00000000000..cb164f5edae --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16095.d @@ -0,0 +1,44 @@ +/* +REQUIRED_ARGS: +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test16095.d(20): Error: shared method test16095.C.ping is not callable using a non-shared a +fail_compilation/test16095.d(30): Error: shared method test16095.S.ping is not callable using a non-shared *a +fail_compilation/test16095.d(43): Error: mutable method test16095.Foo.flip is not callable using a immutable foo +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=16095 + +class C +{ + void ping() shared; +} + +void test1(C a) +{ + (&a.ping)(); // error +} + +struct S +{ + void ping() shared; +} + +void test2(S* a) +{ + (&a.ping)(); // error +} + +struct Foo { + bool flag; + void flip() { + flag = true; + } +} + +void test3() +{ + immutable Foo foo; + (&foo.flip)(); // error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16116.d b/gcc/testsuite/gdc.test/fail_compilation/test16116.d new file mode 100644 index 00000000000..be6e7868960 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16116.d @@ -0,0 +1,16 @@ +/* +REQUIRED_ARGS: -m64 +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test16116.d(15): Error: incompatible types for ((v) * (i)): '__vector(short[8])' and 'int' +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=16116 + +void foo() { + __vector(short[8]) v; + int i; + v = v * i; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16188.d b/gcc/testsuite/gdc.test/fail_compilation/test16188.d new file mode 100644 index 00000000000..ffdb41ac467 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16188.d @@ -0,0 +1,25 @@ +/* PERMUTE_ARGS: + */ + +// https://issues.dlang.org/show_bug.cgi?id=16188 + +/* This produces the message: + * Error: no property 'name' for type 'Where' + * when the actual error is 'getMember is undefined'. + * This happens because errors are gagged when opDispatch() is compiled, + * I don't understand why. + */ + +void where() { Where().name; } + +struct Where +{ + void opDispatch(string name)() + { + alias FieldType = typeof(getMember); + WhereField!FieldType; + } +} + +struct WhereField(FieldType) {} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16193.d b/gcc/testsuite/gdc.test/fail_compilation/test16193.d new file mode 100644 index 00000000000..de65e8a871c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16193.d @@ -0,0 +1,45 @@ +/* +REQUIRED_ARGS: -dip1000 +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test16193.d(39): Error: function test16193.abc is @nogc yet allocates closures with the GC +fail_compilation/test16193.d(41): test16193.abc.__foreachbody1 closes over variable x at fail_compilation/test16193.d(40) +--- +*/ +//fail_compilation/test16193.d(22): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope' +//fail_compilation/test16193.d(34): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope' +//fail_compilation/test16193.d(41): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope' + +// https://issues.dlang.org/show_bug.cgi?id=16193 + +struct S { + int opApply(int delegate(int) dg) @nogc; +} + +void foo() { + int x = 0; + foreach(i; S.init) { + x++; + } +} + +struct T { + int opApply(scope int delegate(int) dg) @nogc; +} + + +void bar() @nogc { + int x = 0; + foreach(i; T.init) { + x++; + } +} + +void abc() @nogc { + int x = 0; + foreach(i; S.init) { + x++; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16195.d b/gcc/testsuite/gdc.test/fail_compilation/test16195.d new file mode 100644 index 00000000000..704974ca30a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16195.d @@ -0,0 +1,14 @@ +/* + * TEST_OUTPUT: +--- +fail_compilation/test16195.d(13): Error: delete p is not @safe but is used in @safe function test +--- + */ + + +// https://issues.dlang.org/show_bug.cgi?id=16195 + +@safe pure nothrow @nogc void test(int* p) +{ + delete p; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16228.d b/gcc/testsuite/gdc.test/fail_compilation/test16228.d new file mode 100644 index 00000000000..6aa79a2db42 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16228.d @@ -0,0 +1,24 @@ +/* REQUIRED_ARGS: -dip25 + TEST_OUTPUT: +--- +fail_compilation/test16228.d(22): Error: function type 'return int()' has 'return' but does not return any indirections +fail_compilation/test16228.d(23): Error: function test16228.S.foo static member has no 'this' to which 'return' can apply +--- +*/ + + + +// https://issues.dlang.org/show_bug.cgi?id=16228 + +int* wrap ( return ref int input ) +{ + return &input; +} + +struct S +{ + int x; + + int foo() return { return 3; } + static ref int foo() return { return x; } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16365.d b/gcc/testsuite/gdc.test/fail_compilation/test16365.d new file mode 100644 index 00000000000..067361b6428 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16365.d @@ -0,0 +1,30 @@ +/* REQUIRED_ARGS: + PERMUTE_ARGS: + TEST_OUTPUT: +--- +fail_compilation/test16365.d(22): Error: 'this' reference necessary to take address of member f1 in @safe function main +fail_compilation/test16365.d(24): Error: cannot implicitly convert expression `&f2` of type `void delegate() pure nothrow @nogc @safe` to `void function() @safe` +fail_compilation/test16365.d(28): Error: address of variable `s` assigned to `dg` with longer lifetime +fail_compilation/test16365.d(29): Error: dg.funcptr cannot be used in @safe code +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=16365 + +struct S +{ + void f1() @safe { } +} + +void main() @safe +{ + void function() @safe f; + f = &S.f1; + void f2() @safe { } + f = &f2; + + void delegate() @safe dg; + S s; + dg = &s.f1; + f = dg.funcptr; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16381.d b/gcc/testsuite/gdc.test/fail_compilation/test16381.d new file mode 100644 index 00000000000..ed591bd31dc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16381.d @@ -0,0 +1,18 @@ +/* +REQUIRED_ARGS: -m64 +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/test16381.d(16): Error: foo() is not an lvalue +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=16381 + +__vector(float[4]) foo(); + +void bar() +{ + float g = foo().ptr[0]; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16523.d b/gcc/testsuite/gdc.test/fail_compilation/test16523.d new file mode 100644 index 00000000000..e5de7c19cb1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16523.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -de +/* +TEST_OUTPUT: +--- +fail_compilation/test16523.d(13): Deprecation: case variables have to be const or immutable +--- +*/ + +void test(int a, int b) +{ + switch (a) + { + case b: return; + default: assert(0); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16589.d b/gcc/testsuite/gdc.test/fail_compilation/test16589.d new file mode 100644 index 00000000000..205347b7603 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test16589.d @@ -0,0 +1,65 @@ +/* PERMUTE_ARGS: +REQUIRED_ARGS: -dip1000 +TEST_OUTPUT: +--- +fail_compilation/test16589.d(26): Error: returning `&this.data` escapes a reference to parameter `this`, perhaps annotate with `return` +fail_compilation/test16589.d(31): Error: returning `&this` escapes a reference to parameter `this`, perhaps annotate with `return` +fail_compilation/test16589.d(37): Error: returning `&s.data` escapes a reference to parameter `s`, perhaps annotate with `return` +fail_compilation/test16589.d(42): Error: returning `&s` escapes a reference to parameter `s`, perhaps annotate with `return` +fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to parameter `s`, perhaps annotate with `return` +fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to parameter `s`, perhaps annotate with `return` +--- +*/ + + + + + +// https://issues.dlang.org/show_bug.cgi?id=16589 + +struct S +{ + int data; + + @safe int* access1() + { + return &data; + } + + @safe S* access2() + { + return &this; + } +} + +@safe int* access3(ref S s) +{ + return &s.data; +} + +@safe S* access4(ref S s) +{ + return &s; +} + +@safe int* access5(S s) +{ + return &s.data; +} + +@safe S* access6(S s) +{ + return &s; +} + +class C +{ + int data; + + @safe int* access7() + { + return &data; + } +} + + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17380.d b/gcc/testsuite/gdc.test/fail_compilation/test17380.d new file mode 100644 index 00000000000..22e3c315336 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17380.d @@ -0,0 +1,21 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test17380.d(12): Error: undefined identifier `ThisTypeDoesNotExistsAndCrahesTheCompiler` +--- + * https://issues.dlang.org/show_bug.cgi?id=17380 + */ + +struct Int128 +{ + Uint128 opCast() + { + return ThisTypeDoesNotExistsAndCrahesTheCompiler; + } + alias opCast this; +} + +struct Uint128 +{ + Int128 opCast() { return Int128.init; } + alias opCast this; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17422.d b/gcc/testsuite/gdc.test/fail_compilation/test17422.d new file mode 100644 index 00000000000..4d203cbdb5b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17422.d @@ -0,0 +1,24 @@ +/* +REQUIRED_ARGS: -dip1000 +TEST_OUTPUT: +--- +fail_compilation/test17422.d(23): Error: scope variable `p` may not be returned +--- +*/ +struct RC +{ + Object get() return scope @trusted + { + return cast(Object) &store[0]; + } + +private: + ubyte[__traits(classInstanceSize, Object)] store; +} + +Object test() @safe +{ + RC rc; + auto p = rc.get; // p must be inferred as scope variable, works for int* + return p; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17425.d b/gcc/testsuite/gdc.test/fail_compilation/test17425.d new file mode 100644 index 00000000000..f7628b83e22 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17425.d @@ -0,0 +1,32 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test17425.d(24): Error: parameter index must be in range 0..4 not 4 +fail_compilation/test17425.d(27): Error: first argument to `__traits(getParameterStorageClasses, i, 4)` is not a function +fail_compilation/test17425.d(29): Error: expression expected as second argument of `__traits(getParameterStorageClasses, foo, int)` +fail_compilation/test17425.d(31): Error: expected 2 arguments for `getParameterStorageClasses` but had 3 +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17425 + +ref int foo(return ref const int* p, scope int* a, out int b, lazy int c); + +//pragma(msg, __traits(getParameterStorageClasses, foo, 0)); + +static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return"); +static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref"); + +//pragma(msg, __traits(getParameterStorageClasses, foo, 1)); +static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope"); +static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out"); +static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"); + +enum a1 = __traits(getParameterStorageClasses, foo, 4); + +int i; +enum a2 = __traits(getParameterStorageClasses, i, 4); + +enum a3 = __traits(getParameterStorageClasses, foo, int); + +enum a4 = __traits(getParameterStorageClasses, foo, 0, 1); + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17450.d b/gcc/testsuite/gdc.test/fail_compilation/test17450.d new file mode 100644 index 00000000000..58a5c7dafc5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17450.d @@ -0,0 +1,58 @@ +/* +REQUIRED_ARGS: -dip1000 -dip25 +TEST_OUTPUT: +--- +fail_compilation/test17450.d(15): Error: returning `&s.bar` escapes a reference to parameter `s`, perhaps annotate with `return` +fail_compilation/test17450.d(18): Error: returning `&this.bar` escapes a reference to parameter `this`, perhaps annotate with `return` +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=17450 + +alias dg_t = void delegate(); + +struct S { + @safe dg_t foo1(ref S s) { + return &s.bar; + } + @safe dg_t foo2() { + return &bar; + } + + @safe dg_t foo3(return ref S s) { + return &s.bar; + } + @safe dg_t foo4() return { + return &bar; + } + + @safe void bar(); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/test17450.d(103): Error: scope variable `c` may not be returned +fail_compilation/test17450.d(106): Error: scope variable `this` may not be returned +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=17450 + +#line 100 + +class C { + @safe dg_t foo1(scope C c) { + return &c.bar; + } + @safe dg_t foo2() scope { + return &bar; + } + + @safe dg_t foo3(return scope C c) { + return &c.bar; + } + @safe dg_t foo4() return scope { + return &bar; + } + + @safe void bar(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17451.d b/gcc/testsuite/gdc.test/fail_compilation/test17451.d new file mode 100644 index 00000000000..fc2f2d22c76 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17451.d @@ -0,0 +1,45 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test17451.d(22): Error: undefined identifier `allocator` +fail_compilation/test17451.d(23): Error: `long` has no effect in expression `false` +fail_compilation/test17451.d(30): Error: variable test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v size of type ThreadSlot is invalid +fail_compilation/test17451.d(44): Error: template instance test17451.HashMap!(ThreadSlot) error instantiating +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=17451 + +interface ManualEvent {} + +interface EventDriver { + ManualEvent createManualEvent() ; +} + +struct ArraySet(Key) +{ + ~this() + { + try allocator; + catch false; // should never happen + } +} + +struct HashMap(TValue) +{ + alias Value = TValue; + static if ({ Value v; }) {} +} + +struct Task {} + +class Libevent2Driver : EventDriver { + Libevent2ManualEvent createManualEvent() {} +} + +struct ThreadSlot { + ArraySet!Task tasks; +} + +class Libevent2ManualEvent { + HashMap!ThreadSlot m_waiters; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test314.d b/gcc/testsuite/gdc.test/fail_compilation/test314.d new file mode 100644 index 00000000000..3dea03fa6b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test314.d @@ -0,0 +1,24 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/test314.d(19): Deprecation: imports.a314.renamed is not visible from module test314 +fail_compilation/test314.d(20): Deprecation: imports.a314.bug is not visible from module test314 +fail_compilation/test314.d(22): Deprecation: imports.b314.renamedpkg is not visible from module test314 +fail_compilation/test314.d(23): Deprecation: imports.b314.bugpkg is not visible from module test314 +--- +*/ + +module test314; + +import imports.a314; +import imports.b314; + +void main() +{ + renamed.bug("This should not work.\n"); + bug("This should not work.\n"); + + renamedpkg.bug("This should not work.\n"); + bugpkg("This should not work.\n"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test4682.d b/gcc/testsuite/gdc.test/fail_compilation/test4682.d new file mode 100644 index 00000000000..18d2108957f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test4682.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +---- +fail_compilation/test4682.d(10): Error: integer overflow: `int.min / -1` +fail_compilation/test4682.d(11): Error: integer overflow: `long.min / -1L` +fail_compilation/test4682.d(12): Error: integer overflow: `int.min % -1` +fail_compilation/test4682.d(13): Error: integer overflow: `long.min % -1L` +---- +*/ +auto a = int.min / -1; +auto b = long.min / -1; +auto c = int.min % -1; +auto d = long.min % -1; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test4682a.d b/gcc/testsuite/gdc.test/fail_compilation/test4682a.d new file mode 100644 index 00000000000..40446869bd9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test4682a.d @@ -0,0 +1,13 @@ +/* +TEST_OUTPUT: +---- +fail_compilation/test4682a.d(10): Error: divide by 0 +fail_compilation/test4682a.d(11): Error: divide by 0 +fail_compilation/test4682a.d(12): Error: divide by 0 +fail_compilation/test4682a.d(13): Error: divide by 0 +---- +*/ +auto a = int.min / 0; +auto b = long.min / 0; +auto c = int.min % 0; +auto d = long.min % 0; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test4838.d b/gcc/testsuite/gdc.test/fail_compilation/test4838.d new file mode 100644 index 00000000000..0bf075737e5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test4838.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test4838.d(13): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions +fail_compilation/test4838.d(14): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions +fail_compilation/test4838.d(15): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions +fail_compilation/test4838.d(16): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions +fail_compilation/test4838.d(17): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions +fail_compilation/test4838.d(18): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions +--- +*/ + +void function() const fpc; +void function() immutable fpi; +void function() shared fps; +void function() shared const fpsc; +void function() inout fpw; +void function() shared inout fpsw; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test5412a.d b/gcc/testsuite/gdc.test/fail_compilation/test5412a.d new file mode 100644 index 00000000000..412cb214d6c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test5412a.d @@ -0,0 +1,4 @@ +module test5412a; + +import A = imports.test5412a; +import A = imports.test5412b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test5412b.d b/gcc/testsuite/gdc.test/fail_compilation/test5412b.d new file mode 100644 index 00000000000..846fdd3f00e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test5412b.d @@ -0,0 +1,4 @@ +module test5412b; + +import A = imports.test5412a; +static import A = imports.test5412b; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test5412c.d b/gcc/testsuite/gdc.test/fail_compilation/test5412c.d new file mode 100644 index 00000000000..88290f66d49 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test5412c.d @@ -0,0 +1,4 @@ +module test5412c; + +import test5412c2 = imports.test5412a; +import test5412c2; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test64.d b/gcc/testsuite/gdc.test/fail_compilation/test64.d new file mode 100644 index 00000000000..bfc63f29f12 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test64.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/imports/test64a.d(1): Error: module imports from file fail_compilation/imports/test64a.d conflicts with package name imports +--- +*/ + +// PERMUTE_ARGS: + +//import std.stdio; + +import imports.test64a; + +int main(string[] args) +{ + //writefln(file1); + return 0; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/test6883.d b/gcc/testsuite/gdc.test/fail_compilation/test6883.d new file mode 100644 index 00000000000..b379f1b6a62 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test6883.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test6883.d(15): Error: array index 5 is out of bounds `x[0 .. 5]` +fail_compilation/test6883.d(17): Error: array index 7 is out of bounds `x[0 .. 5]` +fail_compilation/test6883.d(21): Error: array index 5 is out of bounds `x[0 .. 5]` +fail_compilation/test6883.d(23): Error: array index 7 is out of bounds `x[0 .. 5]` +--- +*/ + +void main() +{ + { + int[5] x; + x[x.length] = 1; + enum size_t n = 2; + x[x.length + n] = 2; + } + { + int[5] x; + x[$] = 1; + enum size_t n = 2; + x[$ + n] = 2; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test8509.d b/gcc/testsuite/gdc.test/fail_compilation/test8509.d new file mode 100644 index 00000000000..121ae9e2814 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test8509.d @@ -0,0 +1,8 @@ +module test8509; +enum E : string { a = "hello", b = "world" } + +void main() +{ + E e1 = E.a ~ " world"; + E e2 = "hello " ~ E.b; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test8556.d b/gcc/testsuite/gdc.test/fail_compilation/test8556.d new file mode 100644 index 00000000000..34900412e5b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test8556.d @@ -0,0 +1,56 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test8556.d(21): Error: template instance test8556.Grab!(Circle!(uint[])) does not match template declaration Grab(Range) if (!isSliceable!Range) +fail_compilation/test8556.d(52): Error: template instance test8556.grab!(Circle!(uint[])) error instantiating +--- +*/ + +extern(C) int printf(const char*, ...); + +template isSliceable(R) +{ + enum bool isSliceable = is(typeof( R.init[1 .. 2] )); +} + +struct Grab(Range) if (!isSliceable!Range) +{ + public Range source; +} + +Grab!R grab(R)(R input) +{ + return Grab!R(input); +} + +// 3. evaluate isSliceable in template constraint +auto grabExactly(R)(R range) if (!isSliceable!R) { return 0; } +auto grabExactly(R)(R range) if ( isSliceable!R) { return 0; } + +struct Circle(Range) +{ + // 2. auto return opSlice + auto opSlice(size_t i, size_t j) + { + //pragma(msg, typeof(opSlice)); // prints "fwdref err" with B, but doesn't with A + + printf("%d %d\n", i, j); + assert(j >= i); + + // 1. grabExactly curcular refers this opSlice. + return grabExactly(typeof(this)()); // broken execution with A + } +} + +Circle!R circle(R)() +{ + return Circle!R(); +} + +void main() +{ + auto t = grab(circle!(uint[])()); + + auto cx = circle!(uint[])(); + auto slice = cx[23 .. 33]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test8751.d b/gcc/testsuite/gdc.test/fail_compilation/test8751.d new file mode 100644 index 00000000000..f739a5a9c1f --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test8751.d @@ -0,0 +1,3 @@ +Bar foo3(ref const int x) pure { + return y => x > y; // error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test9150.d b/gcc/testsuite/gdc.test/fail_compilation/test9150.d new file mode 100644 index 00000000000..650bcd48bfc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test9150.d @@ -0,0 +1,21 @@ +// Issue 9150 - Mismatching static array length should be detected in foreach + +/* +TEST_OUTPUT: +--- +fail_compilation/test9150.d(14): Error: mismatched array lengths, 5 and 3 +--- +*/ + +void main() +{ + int[3][2] matrix = [ [1,11,111], [2,22,222] ]; + + foreach (int[5] row; matrix) //if int[3], there is no error. + { + foreach (x; row) + {}//write(x, " "); + + //writeln(); + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test9176.d b/gcc/testsuite/gdc.test/fail_compilation/test9176.d new file mode 100644 index 00000000000..357d54f610c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test9176.d @@ -0,0 +1,18 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test9176.d(14): Error: forward reference to inferred return type of function call 'get()' +fail_compilation/test9176.d(10): while evaluating: `static assert(!false)` +--- +*/ + +void foo(int x) {} +static assert(!is(typeof(foo(S())))); + +struct S +{ + auto get() { return get(); } + alias get this; +} + +void main(){} diff --git a/gcc/testsuite/gdc.test/fail_compilation/testCols.d b/gcc/testsuite/gdc.test/fail_compilation/testCols.d new file mode 100644 index 00000000000..d072b3c8d02 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/testCols.d @@ -0,0 +1,14 @@ +// REQUIRED_ARGS: -vcolumns +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/testCols.d(13,5): Error: undefined identifier `nonexistent` +--- +*/ + +void test() +{ + nonexistent(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/testInference.d b/gcc/testsuite/gdc.test/fail_compilation/testInference.d new file mode 100644 index 00000000000..3a49c58a029 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/testInference.d @@ -0,0 +1,226 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(24): Error: cannot implicitly convert expression `this.a` of type `inout(A8998)` to `immutable(A8998)` +--- +*/ + +class A8998 +{ + int i; +} +class C8998 +{ + A8998 a; + + this() + { + a = new A8998(); + } + + // WRONG: Returns immutable(A8998) + immutable(A8998) get() inout pure + { + return a; // should be error + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(39): Error: cannot implicitly convert expression `s` of type `const(char[])` to `string` +fail_compilation/testInference.d(44): Error: cannot implicitly convert expression `a` of type `int[]` to `immutable(int[])` +fail_compilation/testInference.d(49): Error: cannot implicitly convert expression `a` of type `int[]` to `immutable(int[])` +fail_compilation/testInference.d(54): Error: cannot implicitly convert expression `a` of type `int[]` to `immutable(int[])` +--- +*/ +string foo(in char[] s) pure +{ + return s; // +} +immutable(int[]) x1() /*pure*/ +{ + int[] a = new int[](10); + return a; // +} +immutable(int[]) x2(int len) /*pure*/ +{ + int[] a = new int[](len); + return a; +} +immutable(int[]) x3(immutable(int[]) org) /*pure*/ +{ + int[] a = new int[](org.length); + return a; // +} + + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(94): Error: cannot implicitly convert expression `c` of type `testInference.C1` to `immutable(C1)` +fail_compilation/testInference.d(95): Error: cannot implicitly convert expression `c` of type `testInference.C1` to `immutable(C1)` +fail_compilation/testInference.d(96): Error: cannot implicitly convert expression `c` of type `testInference.C3` to `immutable(C3)` +fail_compilation/testInference.d(97): Error: cannot implicitly convert expression `c` of type `testInference.C3` to `immutable(C3)` +fail_compilation/testInference.d(100): Error: undefined identifier `X1`, did you mean function `x1`? +fail_compilation/testInference.d(106): Error: cannot implicitly convert expression `s` of type `S1` to `immutable(S1)` +fail_compilation/testInference.d(109): Error: cannot implicitly convert expression `a` of type `int*[]` to `immutable(int*[])` +fail_compilation/testInference.d(110): Error: cannot implicitly convert expression `a` of type `const(int)*[]` to `immutable(int*[])` +fail_compilation/testInference.d(114): Error: cannot implicitly convert expression `s` of type `S2` to `immutable(S2)` +fail_compilation/testInference.d(115): Error: cannot implicitly convert expression `s` of type `S2` to `immutable(S2)` +fail_compilation/testInference.d(116): Error: cannot implicitly convert expression `s` of type `S2` to `immutable(S2)` +fail_compilation/testInference.d(118): Error: cannot implicitly convert expression `a` of type `const(int)*[]` to `immutable(int*[])` +--- +*/ +immutable(Object) get(inout int*) pure +{ + auto o = new Object; + return o; // should be ok +} +immutable(Object) get(immutable Object) pure +{ + auto o = new Object; + return o; // should be ok +} +inout(Object) get(inout Object) pure +{ + auto o = new Object; + return o; // should be ok (, but cannot in current conservative rule) +} + +class C1 { C2 c2; } +class C2 { C3 c3; } +class C3 { C1 c1; } +immutable(C1) recursive1(C3 pc) pure { auto c = new C1(); return c; } // should be error, because pc.c1 == C1 +immutable(C1) recursive2(C2 pc) pure { auto c = new C1(); return c; } // should be error, because pc.c3.c1 == C1 +immutable(C3) recursive3(C1 pc) pure { auto c = new C3(); return c; } // should be error, c.c1 may be pc +immutable(C3) recursive4(C2 pc) pure { auto c = new C3(); return c; } // should be error, c.c1.c2 may be pc +immutable(C1) recursive5(shared C2 pc) pure { auto c = new C1(); return c; } +immutable(C1) recursive6(immutable C2 pc) pure { auto c = new C1(); return c; } +immutable(C1) recursiveE(immutable C2 pc) pure { auto c = new X1(); return c; } + +class C4 { C4[] arr; } +immutable(C4)[] recursive7(int[] arr) pure { auto a = new C4[](1); return a; } + +struct S1 { int* ptr; } +immutable(S1) foo1a( int*[] prm) pure { S1 s; return s; } // NG +immutable(S1) foo1b( const int*[] prm) pure { S1 s; return s; } // OK +immutable(S1) foo1c(immutable int*[] prm) pure { S1 s; return s; } // OK +immutable(int*[]) bar1a( S1 prm) pure { int *[] a; return a; } // NG +immutable(int*[]) bar1b( S1 prm) pure { const(int)*[] a; return a; } // NG +immutable(int*[]) bar1c( S1 prm) pure { immutable(int)*[] a; return a; } // OK + +struct S2 { const(int)* ptr; } +immutable(S2) foo2a( int*[] prm) pure { S2 s; return s; } // OK +immutable(S2) foo2b( const int*[] prm) pure { S2 s; return s; } // NG +immutable(S2) foo2c(immutable int*[] prm) pure { S2 s; return s; } // NG +immutable(int*[]) bar2a( S2 prm) pure { int *[] a; return a; } // OK +immutable(int*[]) bar2b( S2 prm) pure { const(int)*[] a; return a; } // NG +immutable(int*[]) bar2c( S2 prm) pure { immutable(int)*[] a; return a; } // OK + + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(134): Error: cannot implicitly convert expression `f10063(cast(inout(void*))p)` of type `inout(void)*` to `immutable(void)*` +--- +*/ +inout(void)* f10063(inout void* p) pure +{ + return p; +} +immutable(void)* g10063(inout int* p) pure +{ + return f10063(p); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(154): Error: pure function 'testInference.bar14049' cannot call impure function 'testInference.foo14049!int.foo14049' +--- +*/ +auto impure14049() { static int i = 1; return i; } + +void foo14049(T)(T val) +{ + auto n = () @trusted { + return impure14049(); + }(); +} + +void bar14049() pure +{ + foo14049(1); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(166): Error: pure function 'testInference.f14160' cannot access mutable static data 'g14160' +--- +*/ +int g14160; +int* f14160() pure +{ + return &g14160; // should be rejected +} + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(180): Error: pure function 'testInference.test12422' cannot call impure function 'testInference.test12422.bar12422!().bar12422' +--- +*/ +int g12422; +void foo12422() { ++g12422; } +void test12422() pure +{ + void bar12422()() { foo12422(); } + bar12422(); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(196): Error: pure function 'testInference.test13729a' cannot access mutable static data 'g13729' +fail_compilation/testInference.d(206): Error: pure function 'testInference.test13729b' cannot call impure function 'testInference.test13729b.foo!().foo' +--- +*/ +int g13729; + +void test13729a() pure +{ + static void foo() // typed as impure + { + g13729++; // disallowed + } + foo(); +} +void test13729b() pure +{ + static void foo()() // inferred to impure + { + g13729++; + } + foo(); // cannot call impure function +} + +/* +TEST_OUTPUT: +--- +fail_compilation/testInference.d(225): Error: testInference.test17086 called with argument types (bool) matches both: +fail_compilation/testInference.d(219): testInference.test17086!(bool, false).test17086(bool x) +and: +fail_compilation/testInference.d(220): testInference.test17086!(bool, false).test17086(bool y) +--- +*/ + +void test17086 (T, T V = T.init) (T x) { assert(x.foo); } +void test17086 (T, T V = T.init) (T y) { assert(y.bar); } + +void test17086_call () +{ + bool f; + test17086(f); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/testpull1810.d b/gcc/testsuite/gdc.test/fail_compilation/testpull1810.d new file mode 100644 index 00000000000..141c9d2ff95 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/testpull1810.d @@ -0,0 +1,21 @@ +// REQUIRED_ARGS: -c -w +/* +TEST_OUTPUT: +--- +fail_compilation/testpull1810.d(19): Warning: statement is not reachable +--- +*/ + +uint foo(uint i) +{ + try + { + ++i; + return 3; + } + catch (Exception e) + { + } + return 4; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d b/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d new file mode 100644 index 00000000000..310e9fef472 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d @@ -0,0 +1,24 @@ + +/* TEST_OUTPUT: +--- +fail_compilation/testscopestatic.d(15): Error: variable testscopestatic.foo.p cannot be 'scope' and 'static' +fail_compilation/testscopestatic.d(16): Error: variable testscopestatic.foo.b cannot be 'scope' and 'extern' +fail_compilation/testscopestatic.d(17): Error: variable testscopestatic.foo.c cannot be 'scope' and '__gshared' +fail_compilation/testscopestatic.d(21): Error: variable testscopestatic.foo.S.x field cannot be 'scope' +--- +*/ + + +void foo() +{ + scope int a; + static scope int* p; + extern scope int b; + scope __gshared int c; + + struct S + { + scope int x; + } +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d new file mode 100644 index 00000000000..ba80fdc1bdf --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d @@ -0,0 +1,58 @@ +/* +PERMUTE_ARGS: +TEST_OUTPUT: +--- +fail_compilation/typeerrors.d(36): Error: tuple index 4 exceeds 4 +fail_compilation/typeerrors.d(38): Error: variable x cannot be read at compile time +fail_compilation/typeerrors.d(39): Error: can't have array of void() +fail_compilation/typeerrors.d(40): Error: cannot have array of scope typeerrors.C +fail_compilation/typeerrors.d(41): Error: cannot have array of scope typeerrors.C +fail_compilation/typeerrors.d(44): Error: int[5] is not an expression +fail_compilation/typeerrors.d(46): Error: x is used as a type +fail_compilation/typeerrors.d(47): Error: can't have associative array key of void() +fail_compilation/typeerrors.d(48): Error: can't have associative array key of void +fail_compilation/typeerrors.d(49): Error: cannot have array of scope typeerrors.C +fail_compilation/typeerrors.d(50): Error: can't have associative array of void +fail_compilation/typeerrors.d(51): Error: can't have associative array of void() +fail_compilation/typeerrors.d(53): Error: cannot have parameter of type void +fail_compilation/typeerrors.d(55): Error: slice [1..5] is out of range of [0..4] +fail_compilation/typeerrors.d(56): Error: slice [2..1] is out of range of [0..4] +--- +*/ + + + + + +template tuple(T...) { alias T tuple; } + +void bar(); + +scope class C { } + +void foo() +{ + alias T = tuple!(1,2,int,7); + T[4] a; + int x; + T[x] b; + typeof(bar)[5] c; + C[6] d; + C[] e; + + alias int[5] AI; + auto f = AI.ptr; + + int[x*] g; + int[typeof(bar)] h; + int[void] i; + C[int] j; + void[int] k; + typeof(bar)[int] l; + + void abc(void) { } + + alias T2 = T[1 .. 5]; + alias T3 = T[2 .. 1]; +} + diff --git a/gcc/testsuite/gdc.test/fail_compilation/verrors0.d b/gcc/testsuite/gdc.test/fail_compilation/verrors0.d new file mode 100644 index 00000000000..23cd7acb234 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/verrors0.d @@ -0,0 +1,60 @@ +// REQUIRED_ARGS: -verrors=0 + +void main() +{ + { T a; } // 1 + { T a; } // 2 + { T a; } // 3 + { T a; } // 4 + { T a; } // 5 + { T a; } // 6 + { T a; } // 7 + { T a; } // 8 + { T a; } // 9 + { T a; } // 10 + { T a; } // 11 + { T a; } // 12 + { T a; } // 13 + { T a; } // 14 + { T a; } // 15 + { T a; } // 16 + { T a; } // 17 + { T a; } // 18 + { T a; } // 19 + { T a; } // 20 (default limit) + { T a; } // 21 + { T a; } // 22 + { T a; } // 23 + { T a; } // 24 + { T a; } // 25 +} +/* +TEST_OUTPUT: +--- +fail_compilation/verrors0.d(5): Error: undefined identifier `T` +fail_compilation/verrors0.d(6): Error: undefined identifier `T` +fail_compilation/verrors0.d(7): Error: undefined identifier `T` +fail_compilation/verrors0.d(8): Error: undefined identifier `T` +fail_compilation/verrors0.d(9): Error: undefined identifier `T` +fail_compilation/verrors0.d(10): Error: undefined identifier `T` +fail_compilation/verrors0.d(11): Error: undefined identifier `T` +fail_compilation/verrors0.d(12): Error: undefined identifier `T` +fail_compilation/verrors0.d(13): Error: undefined identifier `T` +fail_compilation/verrors0.d(14): Error: undefined identifier `T` +fail_compilation/verrors0.d(15): Error: undefined identifier `T` +fail_compilation/verrors0.d(16): Error: undefined identifier `T` +fail_compilation/verrors0.d(17): Error: undefined identifier `T` +fail_compilation/verrors0.d(18): Error: undefined identifier `T` +fail_compilation/verrors0.d(19): Error: undefined identifier `T` +fail_compilation/verrors0.d(20): Error: undefined identifier `T` +fail_compilation/verrors0.d(21): Error: undefined identifier `T` +fail_compilation/verrors0.d(22): Error: undefined identifier `T` +fail_compilation/verrors0.d(23): Error: undefined identifier `T` +fail_compilation/verrors0.d(24): Error: undefined identifier `T` +fail_compilation/verrors0.d(25): Error: undefined identifier `T` +fail_compilation/verrors0.d(26): Error: undefined identifier `T` +fail_compilation/verrors0.d(27): Error: undefined identifier `T` +fail_compilation/verrors0.d(28): Error: undefined identifier `T` +fail_compilation/verrors0.d(29): Error: undefined identifier `T` +--- +*/ diff --git a/gcc/testsuite/gdc.test/fail_compilation/verrors5.d b/gcc/testsuite/gdc.test/fail_compilation/verrors5.d new file mode 100644 index 00000000000..424d4f7622d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/verrors5.d @@ -0,0 +1,40 @@ +// REQUIRED_ARGS: -verrors=5 + +void main() +{ + { T a; } // 1 + { T a; } // 2 + { T a; } // 3 + { T a; } // 4 + { T a; } // 5 + { T a; } // 6 + { T a; } // 7 + { T a; } // 8 + { T a; } // 9 + { T a; } // 10 + { T a; } // 11 + { T a; } // 12 + { T a; } // 13 + { T a; } // 14 + { T a; } // 15 + { T a; } // 16 + { T a; } // 17 + { T a; } // 18 + { T a; } // 19 + { T a; } // 20 (default limit) + { T a; } // 21 + { T a; } // 22 + { T a; } // 23 + { T a; } // 24 + { T a; } // 25 +} +/* +TEST_OUTPUT: +--- +fail_compilation/verrors5.d(5): Error: undefined identifier `T` +fail_compilation/verrors5.d(6): Error: undefined identifier `T` +fail_compilation/verrors5.d(7): Error: undefined identifier `T` +fail_compilation/verrors5.d(8): Error: undefined identifier `T` +fail_compilation/verrors5.d(9): Error: undefined identifier `T` +--- +*/ diff --git a/gcc/testsuite/gdc.test/fail_compilation/warn12809.d b/gcc/testsuite/gdc.test/fail_compilation/warn12809.d new file mode 100644 index 00000000000..100f0fb9f33 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/warn12809.d @@ -0,0 +1,34 @@ +// REQUIRED_ARGS: -o- -w + +/* +TEST_OUTPUT: +--- +fail_compilation/warn12809.d(25): Warning: statement is not reachable +fail_compilation/warn12809.d(33): Warning: statement is not reachable +--- +*/ + +//void test_unrachable1() +//{ +// try assert(0); +// finally +// { +// int x = 1; // unreachable +// } +//} + +void test_unrachable2() +{ + try assert(0); + finally {} + + int x = 1; // unreachable +} + +void test_unrachable3() +{ + try {} + finally assert(0); + + int x = 1; // unreachable +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/warn13679.d b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d new file mode 100644 index 00000000000..0a92b766788 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d @@ -0,0 +1,15 @@ +// REQUIRED_ARGS: -w +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/warn13679.d(14): Warning: cannot use foreach_reverse with an associative array +--- +*/ + +void main() +{ + int[int] aa; + foreach_reverse(k, v; aa) {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/warn7444.d b/gcc/testsuite/gdc.test/fail_compilation/warn7444.d new file mode 100644 index 00000000000..ec7d49c150b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/warn7444.d @@ -0,0 +1,83 @@ +// REQUIRED_ARGS: -w +// PERMUTE_ARGS: + +/* +TEST_OUTPUT: +--- +fail_compilation/warn7444.d(23): Error: cannot implicitly convert expression `e` of type `int` to `int[]` +--- +*/ + +void test7444() +{ + int[2] sa; + int[] da; + int e; + + { + // X: Changed accepts-invalid to rejects-invalid by this issue + // a: slice assignment + // b: element-wise assignment + sa = e; // X + sa[] = e; // b + da = e; + da[] = e; // b + + // lhs is static array + sa = sa; // b == identity assign + sa = sa[]; // X + sa[] = sa; // X + sa[] = sa[]; // b + + sa = da; // X + sa = da[]; // X + sa[] = da; // X + sa[] = da[]; // b + + // lhs is dynamic array + da = sa; // X + da = sa[]; // a + da[] = sa; // X + da[] = sa[]; // b + + da = da; // a == identity assign + da = da[]; // a + da[] = da; // X + da[] = da[]; // b + } +} + +/* +TEST_OUTPUT: +--- +No warning +--- +*/ + +void test10214() +{ + bool[1] arr; + arr = 0; + pragma(msg, "No warning"); +} + +/* +TEST_OUTPUT: +--- +No warning +--- +*/ + +struct S11228 +{ + int[2] ii; + alias ii this; +} +void test11228() +{ + S11228 s; + int[2] ii; + ii = s.ii; // OK + ii = s; // OK <- Warning + pragma(msg, "No warning"); +} diff --git a/gcc/testsuite/gdc.test/gdc-test.exp b/gcc/testsuite/gdc.test/gdc-test.exp new file mode 100644 index 00000000000..246ac850a20 --- /dev/null +++ b/gcc/testsuite/gdc.test/gdc-test.exp @@ -0,0 +1,416 @@ +# Copyright (C) 2012-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 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Test using the DMD testsuite. +# Load support procs. +load_lib gdc-dg.exp + +# +# Convert DMD arguments to GDC equivalent +# + +proc gdc-convert-args { args } { + set out "" + + foreach arg [split [lindex $args 0] " "] { + # List of switches kept in ASCII collated order. + if { [regexp -- {^-I([\w+/-]+)} $arg pattern path] } { + lappend out "-I$path" + + } elseif { [regexp -- {^-J([\w+/-]+)} $arg pattern path] } { + lappend out "-J$path" + + } elseif [string match "-allinst" $arg] { + lappend out "-fall-instantiations" + + } elseif { [string match "-boundscheck" $arg] + || [string match "-boundscheck=on" $arg] } { + lappend out "-fbounds-check" + + } elseif { [string match "-boundscheck=off" $arg] + || [string match "-noboundscheck" $arg] } { + lappend out "-fno-bounds-check" + + } elseif [string match "-boundscheck=safeonly" $arg] { + lappend out "-fbounds-check=safeonly" + + } elseif [string match "-c" $arg] { + lappend out "-c" + + } elseif [string match "-d" $arg] { + lappend out "-Wno-deprecated" + + } elseif [string match "-de" $arg] { + lappend out "-Wdeprecated" + lappend out "-Werror" + + } elseif [string match "-debug" $arg] { + lappend out "-fdebug" + + } elseif [regexp -- {^-debug=(\w+)} $arg pattern value] { + lappend out "-fdebug=$value" + + } elseif [string match "-dip1000" $arg] { + lappend out "-ftransition=dip1000" + + } elseif [string match "-dip25" $arg] { + lappend out "-ftransition=dip25" + + } elseif [string match "-dw" $arg] { + lappend out "-Wdeprecated" + lappend out "-Wno-error" + + } elseif [string match "-fPIC" $arg] { + lappend out "-fPIC" + + } elseif { [string match "-g" $arg] + || [string match "-gc" $arg] } { + lappend out "-g" + + } elseif [string match "-inline" $arg] { + lappend out "-finline-functions" + + } elseif [string match "-main" $arg] { + lappend out "-fmain" + + } elseif [regexp -- {^-mv=([\w+=./-]+)} $arg pattern value] { + lappend out "-fmodule-file=$value" + + } elseif [string match "-O" $arg] { + lappend out "-O2" + + } elseif [string match "-release" $arg] { + lappend out "-frelease" + + } elseif [regexp -- {^-transition=(\w+)} $arg pattern value] { + lappend out "-ftransition=$value" + + } elseif [string match "-unittest" $arg] { + lappend out "-funittest" + + } elseif [string match "-verrors=spec" $arg] { + lappend out "-Wspeculative" + + } elseif [regexp -- {^-verrors=(\d+)} $arg pattern num] { + lappend out "-fmax-errors=$num" + + } elseif [regexp -- {^-version=(\w+)} $arg pattern value] { + lappend out "-fversion=$value" + + } elseif [string match "-vtls" $arg] { + lappend out "-ftransition=tls" + + } elseif [string match "-w" $arg] { + lappend out "-Wall" + lappend out "-Werror" + + } elseif [string match "-wi" $arg] { + lappend out "-Wall" + lappend out "-Wno-error" + + } else { + # print "Unhandled Argument: $arg" + } + } + + return $out +} + +proc gdc-copy-extra { base extra } { + # Split base, folder/file. + set type [file dirname $extra] + + # print "Filename: $base - $extra" + + set fdin [open $base/$extra r] + fconfigure $fdin -encoding binary + + file mkdir $type + set fdout [open $extra w] + fconfigure $fdout -encoding binary + + while { [gets $fdin copy_line] >= 0 } { + set out_line $copy_line + puts $fdout $out_line + } + + close $fdin + close $fdout + + return $extra +} + +# +# Translate DMD test directives to dejagnu equivalent. +# +# COMPILE_SEPARATELY: Not handled. +# EXECUTE_ARGS: Parameters to add to the execution of the test. +# COMPILED_IMPORTS: List of modules files that are imported by the main +# source file that should be included in compilation. +# Currently handled the same as EXTRA_SOURCES. +# EXTRA_SOURCES: List of extra sources to build and link along with +# the test. +# EXTRA_FILES: List of extra files to copy for the test runs. +# PERMUTE_ARGS: The set of arguments to permute in multiple compiler +# invocations. An empty set means only one permutation +# with no arguments. +# TEST_OUTPUT: The output expected from the compilation. +# POST_SCRIPT: Not handled. +# REQUIRED_ARGS: Arguments to add to the compiler command line. +# DISABLED: Not handled. +# + +proc dmd2dg { base test } { + global DEFAULT_DFLAGS + global PERMUTE_ARGS + global GDC_EXECUTE_ARGS + + set PERMUTE_ARGS $DEFAULT_DFLAGS + set GDC_EXECUTE_ARGS "" + + # Split base, folder/file. + set type [file dirname $test] + + # print "Filename: $base - $test" + + set fdin [open $base/$test r] + #fconfigure $fdin -encoding binary + + file mkdir $type + set fdout [open $test w] + #fconfigure $fdout -encoding binary + + while { [gets $fdin copy_line] >= 0 } { + set out_line $copy_line + + if [regexp -- {COMPILE_SEPARATELY} $copy_line] { + # COMPILE_SEPARATELY is not handled. + regsub -- {COMPILE_SEPARATELY.*$} $copy_line "" out_line + + } elseif [regexp -- {DISABLED} $copy_line] { + # DISABLED is not handled. + regsub -- {DISABLED.*$} $copy_line "" out_line + + } elseif [regexp -- {POST_SCRIPT} $copy_line] { + # POST_SCRIPT is not handled + regsub -- {POST_SCRIPT.*$} $copy_line "" out_line + + } elseif [regexp -- {PERMUTE_ARGS\s*:\s*(.*)} $copy_line match args] { + # PERMUTE_ARGS is handled by gdc-do-test. + set PERMUTE_ARGS [gdc-convert-args $args] + regsub -- {PERMUTE_ARGS.*$} $copy_line "" out_line + + } elseif [regexp -- {EXECUTE_ARGS\s*:\s*(.*)} $copy_line match args] { + # EXECUTE_ARGS is handled by gdc_load. + foreach arg $args { + lappend GDC_EXECUTE_ARGS $arg + } + regsub -- {EXECUTE_ARGS.*$} $copy_line "" out_line + + } elseif [regexp -- {REQUIRED_ARGS\s*:\s*(.*)} $copy_line match args] { + # Convert all listed arguments to from dmd to gdc-style. + set new_option "{ dg-additional-options \"[gdc-convert-args $args]\" }" + regsub -- {REQUIRED_ARGS.*$} $copy_line $new_option out_line + + } elseif [regexp -- {EXTRA_SOURCES\s*:\s*(.*)} $copy_line match sources] { + # Copy all sources to the testsuite build directory. + foreach import $sources { + # print "Import: $base $type/$import" + gdc-copy-extra $base "$type/$import" + } + set new_option "{ dg-additional-sources \"$sources\" }" + regsub -- {EXTRA_SOURCES.*$} $copy_line $new_option out_line + + } elseif [regexp -- {EXTRA_CPP_SOURCES\s*:\s*(.*)} $copy_line match sources] { + # Copy all sources to the testsuite build directory. + foreach import $sources { + # print "Import: $base $type/$import" + gdc-copy-extra $base "$type/$import" + } + set new_option "{ dg-additional-sources \"$sources\" }" + regsub -- {EXTRA_CPP_SOURCES.*$} $copy_line $new_option out_line + + } elseif [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] { + # Copy all files to the testsuite build directory. + foreach import $files { + # print "Import: $base $type/$import" + gdc-copy-extra $base "$type/$import" + } + set new_option "{ dg-additional-files \"$files\" }" + regsub -- {EXTRA_FILES.*$} $copy_line $new_option out_line + + } elseif [regexp -- {COMPILED_IMPORTS\s*:\s*(.*)} $copy_line match sources] { + # Copy all sources to the testsuite build directory. + foreach import $sources { + # print "Import: $base $type/$import" + gdc-copy-extra $base "$type/$import" + } + set new_option "{ dg-additional-sources \"$sources\" }" + regsub -- {COMPILED_IMPORTS.*$} $copy_line $new_option out_line + + } + + puts $fdout $out_line + } + + # Add specific options for test type + + # DMD's testsuite is extremely verbose, compiler messages from constructs + # such as pragma(msg, ...) would otherwise cause tests to fail. + set out_line "// { dg-prune-output .* }" + puts $fdout $out_line + + # Since GCC 6-20160131 blank lines are not allowed in the output by default. + dg-allow-blank-lines-in-output { 1 } + + # Compilable files are successful if an output is generated. + # Fail compilable are successful if an output is not generated. + # Runnable must compile, link, and return 0 to be successful by default. + switch [file dirname $test] { + runnable { + if ![isnative] { + set out_line "// { dg-final { output-exists } }" + puts $fdout $out_line + } + } + + compilable { + set out_line "// { dg-final { output-exists } }" + puts $fdout $out_line + } + + fail_compilation { + set out_line "// { dg-final { output-exists-not } }" + puts $fdout $out_line + } + } + + close $fdin + close $fdout + + return $test +} + +proc gdc-permute-options { options } { + set result { } + set n [expr 1<<[llength $options]] + for { set i 0 } { $i<$n } { incr i } { + set option "" + for { set j 0 } { $j<[llength $options] } { incr j } { + if [expr $i & 1 << $j] { + append option [lindex $options $j] + append option " " + } + } + lappend result $option + + } + return $result +} + + +proc gdc-do-test { } { + global srcdir subdir + global dg-do-what-default + global verbose + + # If a testcase doesn't have special options, use these. + global DEFAULT_DFLAGS + if ![info exists DEFAULT_DFLAGS] then { + set DEFAULT_DFLAGS "-g -O2 -frelease" + #set DEFAULT_DFLAGS "-O2" + } + + # These are special options to use on testcase, and override DEFAULT_DFLAGS + global PERMUTE_ARGS + + # Set if an extra option should be passed to link to shared druntime. + global SHARED_OPTION + + # Additional arguments for gdc_load + global GDC_EXECUTE_ARGS + + # Initialize `dg'. + dg-init + + # Main loop. + + # set verbose 1 + # set dg-final-code "" + # Find all tests and pass to routine. + foreach test [lsort [find $srcdir/$subdir *]] { + regexp -- "(.*)/(.+)/(.+)\.(.+)$" $test match base dir name ext + + # Skip invalid test directory + if { [lsearch "runnable compilable fail_compilation" $dir] == -1 } { + continue + } + + # Skip invalid test extensions + if { [lsearch "d" $ext] == -1 } { + continue + } + + # Convert to DG test. + set imports [format "-I%s/%s" $base $dir] + set filename [dmd2dg $base $dir/$name.$ext] + + if { $dir == "runnable" } { + append PERMUTE_ARGS " $SHARED_OPTION" + } + set options [gdc-permute-options $PERMUTE_ARGS] + + switch $dir { + runnable { + for { set i 0 } { $i<[llength $options] } { incr i } { + set flags [lindex $options $i] + if [isnative] { + set dg-do-what-default "run" + } else { + set dg-do-what-default "link" + } + gdc-dg-runtest $filename $flags $imports + } + } + + compilable { + for { set i 0 } { $i<[llength $options] } { incr i } { + set flags [lindex $options $i] + #set dg-do-what-default "compile" + set dg-do-what-default "assemble" + gdc-dg-runtest $filename $flags $imports + } + } + + fail_compilation { + for { set i 0 } { $i<[llength $options] } { incr i } { + set flags [lindex $options $i] + set dg-do-what-default "assemble" + gdc-dg-runtest $filename $flags $imports + } + } + } + + # Cleanup + #file delete $filename + } + + # All done. + dg-finish +} + +gdc-do-test + diff --git a/gcc/testsuite/gdc.test/runnable/A16.d b/gcc/testsuite/gdc.test/runnable/A16.d new file mode 100644 index 00000000000..f65335393b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/A16.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: imports/A16a.d + +import std.stdio; + +class AA16 +{ + protected: + this() + { + printf("class AA16\n"); + } +} diff --git a/gcc/testsuite/gdc.test/runnable/Same.d b/gcc/testsuite/gdc.test/runnable/Same.d new file mode 100644 index 00000000000..85025e77c4e --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/Same.d @@ -0,0 +1,12 @@ +// EXTRA_SOURCES: imports/Other.d +// PERMUTE_ARGS: + +module Same; // makes no difference if removed +import core.stdc.stdio; +class Same +{ +this() +{ +printf("Same\n"); +} +} diff --git a/gcc/testsuite/gdc.test/runnable/a17.d b/gcc/testsuite/gdc.test/runnable/a17.d new file mode 100644 index 00000000000..79eeecfeb14 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/a17.d @@ -0,0 +1,21 @@ +// EXTRA_SOURCES: imports/a17a.d + +module a17; + +import std.stdio; + +private import imports.a17a; + +class barx { + this() { printf("barx\n"); } +} + + +int main() +{ + foo2x f = new foo2x(); +// f = new foo2x(); +// f.x++; + + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/a18.d b/gcc/testsuite/gdc.test/runnable/a18.d new file mode 100644 index 00000000000..4d8b000a138 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/a18.d @@ -0,0 +1,16 @@ +// COMPILE_SEPARATELY +// EXTRA_SOURCES: imports/a18a.d +// PERMUTE_ARGS: + +import imports.a18a; + +extern(C) int printf(const char*, ...); + +alias IContainer!(int) icontainer_t; + +int main() +{ + printf("Test enumerator\n"); + + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/a19.d b/gcc/testsuite/gdc.test/runnable/a19.d new file mode 100644 index 00000000000..574f95cae8f --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/a19.d @@ -0,0 +1,12 @@ +// COMPILE_SEPARATELY +// EXTRA_SOURCES: imports/a19a.d +// PERMUTE_ARGS: + +import imports.a19a; + +int main(char[][] args) +{ + TemplatedStruct!(Dummy) e; + + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/a21.d b/gcc/testsuite/gdc.test/runnable/a21.d new file mode 100644 index 00000000000..6b3be9d814c --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/a21.d @@ -0,0 +1,29 @@ +// EXTRA_SOURCES: imports/a21a.d +// PERMUTE_ARGS: + +import std.stdio; +import imports.a21a; + + +template BadMixin() +{ + int badFunc() + { + printf("badFunc\n"); + return 2; + } +} + + +int main() +{ + int i; + auto x = new SomeClass; + i = x.goodFunc(); + assert(i == 1); + i = x.badFunc(); + assert(i == 2); + + return 0; +} + diff --git a/gcc/testsuite/gdc.test/runnable/aliasthis.d b/gcc/testsuite/gdc.test/runnable/aliasthis.d new file mode 100644 index 00000000000..8cd00517692 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/aliasthis.d @@ -0,0 +1,2034 @@ + +extern (C) int printf(const(char*) fmt, ...); +import core.vararg; + +struct Tup(T...) +{ + T field; + alias field this; + + bool opEquals(const Tup rhs) const + { + foreach (i, _; T) + if (field[i] != rhs.field[i]) + return false; + return true; + } +} + +Tup!T tup(T...)(T fields) +{ + return typeof(return)(fields); +} + +template Seq(T...) +{ + alias T Seq; +} + +/**********************************************/ + +struct S +{ + int x; + alias x this; +} + +int foo(int i) +{ + return i * 2; +} + +void test1() +{ + S s; + s.x = 7; + int i = -s; + assert(i == -7); + + i = s + 8; + assert(i == 15); + + i = s + s; + assert(i == 14); + + i = 9 + s; + assert(i == 16); + + i = foo(s); + assert(i == 14); +} + +/**********************************************/ + +class C +{ + int x; + alias x this; +} + +void test2() +{ + C s = new C(); + s.x = 7; + int i = -s; + assert(i == -7); + + i = s + 8; + assert(i == 15); + + i = s + s; + assert(i == 14); + + i = 9 + s; + assert(i == 16); + + i = foo(s); + assert(i == 14); +} + +/**********************************************/ + +void test3() +{ + Tup!(int, double) t; + t[0] = 1; + t[1] = 1.1; + assert(t[0] == 1); + assert(t[1] == 1.1); + printf("%d %g\n", t[0], t[1]); +} + +/**********************************************/ + +struct Iter +{ + bool empty() { return true; } + void popFront() { } + ref Tup!(int, int) front() { return *new Tup!(int, int); } + ref Iter opSlice() { return this; } +} + +void test4() +{ + foreach (a; Iter()) { } +} + +/**********************************************/ + +void test5() +{ + static struct Double1 { + double val = 1; + alias val this; + } + static Double1 x() { return Double1(); } + x()++; +} + +/**********************************************/ +// 4617 + +struct S4617 +{ + struct F + { + int square(int n) { return n*n; } + real square(real n) { return n*n; } + } + F forward; + + alias forward this; + + alias forward.square sqr; // okay + + int field; + void mfunc(); + template Templ(){} + void tfunc()(){} +} + +template Id4617(alias k) { alias k Id4617; } + +void test4617a() +{ + alias Id4617!(S4617.square) test1; //NG + alias Id4617!(S4617.forward.square) test2; //OK + + alias Id4617!(S4617.sqr) test3; //okay + + static assert(__traits(isSame, S4617.square, S4617.forward.square)); +} + +void test4617b() +{ + static struct Sub(T) + { + T value; + @property ref inout(T) payload() inout { return value; } + alias payload this; + } + + alias Id4617!(S4617.field) S_field; + alias Id4617!(S4617.mfunc) S_mfunc; + alias Id4617!(S4617.Templ) S_Templ; + alias Id4617!(S4617.tfunc) S_tfunc; + + alias Sub!S4617 T4617; + alias Id4617!(T4617.field) R_field; + alias Id4617!(T4617.mfunc) R_mfunc; + alias Id4617!(T4617.Templ) R_Templ; + alias Id4617!(T4617.tfunc) R_tfunc; + static assert(__traits(isSame, R_field, S_field)); + static assert(__traits(isSame, R_mfunc, S_mfunc)); + static assert(__traits(isSame, R_Templ, S_Templ)); + static assert(__traits(isSame, R_tfunc, S_tfunc)); + + alias Id4617!(T4617.square) R_sqr; + static assert(__traits(isSame, R_sqr, S4617.forward.square)); +} + +/**********************************************/ +// 4773 + +void test4773() +{ + struct Rebindable + { + Object obj; + @property const(Object) get(){ return obj; } + alias get this; + } + + Rebindable r; + if (r) assert(0); + r.obj = new Object; + if (!r) assert(0); +} + +/**********************************************/ +// 5188 + +void test5188() +{ + struct S + { + int v = 10; + alias v this; + } + + S s; + assert(s <= 20); + assert(s != 14); +} + +/***********************************************/ + +struct Foo { + void opIndexAssign(int x, size_t i) { + val = x; + } + void opSliceAssign(int x, size_t a, size_t b) { + val = x; + } + int val; +} + +struct Bar { + Foo foo; + alias foo this; +} + +void test6() { + Bar b; + b[0] = 1; + assert(b.val == 1); + b[0 .. 1] = 2; + assert(b.val == 2); +} + +/**********************************************/ +// recursive alias this detection + +class C0 {} + +class C1 { C2 c; alias c this; } +class C2 { C1 c; alias c this; } + +class C3 { C2 c; alias c this; } + +struct S0 {} + +struct S1 { S2* ps; @property ref get(){return *ps;} alias get this; } +struct S2 { S1* ps; @property ref get(){return *ps;} alias get this; } + +struct S3 { S2* ps; @property ref get(){return *ps;} alias get this; } + +struct S4 { S5* ps; @property ref get(){return *ps;} alias get this; } +struct S5 { S4* ps; @property ref get(){return *ps;} alias get this; } + +struct S6 { S5* ps; @property ref get(){return *ps;} alias get this; } + +void test7() +{ + // Able to check a type is implicitly convertible within a finite time. + static assert(!is(C1 : C0)); + static assert( is(C2 : C1)); + static assert( is(C1 : C2)); + static assert(!is(C3 : C0)); + static assert( is(C3 : C1)); + static assert( is(C3 : C2)); + + static assert(!is(S1 : S0)); + static assert( is(S2 : S1)); + static assert( is(S1 : S2)); + static assert(!is(S3 : S0)); + static assert( is(S3 : S1)); + static assert( is(S3 : S2)); + + C0 c0; C1 c1; C3 c3; + S0 s0; S1 s1; S3 s3; S4 s4; S6 s6; + + // Allow merging types that contains alias this recursion. + static assert( __traits(compiles, c0 is c1)); // typeMerge(c || c) e2->implicitConvTo(t1); + static assert( __traits(compiles, c0 is c3)); // typeMerge(c || c) e2->implicitConvTo(t1); + static assert( __traits(compiles, c1 is c0)); // typeMerge(c || c) e1->implicitConvTo(t2); + static assert( __traits(compiles, c3 is c0)); // typeMerge(c || c) e1->implicitConvTo(t2); + static assert(!__traits(compiles, s1 is c0)); // typeMerge(c || c) e1 + static assert(!__traits(compiles, s3 is c0)); // typeMerge(c || c) e1 + static assert(!__traits(compiles, c0 is s1)); // typeMerge(c || c) e2 + static assert(!__traits(compiles, c0 is s3)); // typeMerge(c || c) e2 + + static assert(!__traits(compiles, s1 is s0)); // typeMerge(s && s) e1 + static assert(!__traits(compiles, s3 is s0)); // typeMerge(s && s) e1 + static assert(!__traits(compiles, s0 is s1)); // typeMerge(s && s) e2 + static assert(!__traits(compiles, s0 is s3)); // typeMerge(s && s) e2 + static assert(!__traits(compiles, s1 is s4)); // typeMerge(s && s) e1 + e2 + static assert(!__traits(compiles, s3 is s6)); // typeMerge(s && s) e1 + e2 + + static assert(!__traits(compiles, s1 is 10)); // typeMerge(s || s) e1 + static assert(!__traits(compiles, s3 is 10)); // typeMerge(s || s) e1 + static assert(!__traits(compiles, 10 is s1)); // typeMerge(s || s) e2 + static assert(!__traits(compiles, 10 is s3)); // typeMerge(s || s) e2 + + // SliceExp::semantic + static assert(!__traits(compiles, c1[])); + static assert(!__traits(compiles, c3[])); + static assert(!__traits(compiles, s1[])); + static assert(!__traits(compiles, s3[])); + + // CallExp::semantic +// static assert(!__traits(compiles, c1())); +// static assert(!__traits(compiles, c3())); + static assert(!__traits(compiles, s1())); + static assert(!__traits(compiles, s3())); + + // AssignExp::semantic + static assert(!__traits(compiles, { c1[1] = 0; })); + static assert(!__traits(compiles, { c3[1] = 0; })); + static assert(!__traits(compiles, { s1[1] = 0; })); + static assert(!__traits(compiles, { s3[1] = 0; })); + static assert(!__traits(compiles, { c1[ ] = 0; })); + static assert(!__traits(compiles, { c3[ ] = 0; })); + static assert(!__traits(compiles, { s1[ ] = 0; })); + static assert(!__traits(compiles, { s3[ ] = 0; })); + + // UnaExp::op_overload + static assert(!__traits(compiles, +c1[1])); + static assert(!__traits(compiles, +c3[1])); + static assert(!__traits(compiles, +s1[1])); + static assert(!__traits(compiles, +s3[1])); + static assert(!__traits(compiles, +c1[ ])); + static assert(!__traits(compiles, +c3[ ])); + static assert(!__traits(compiles, +s1[ ])); + static assert(!__traits(compiles, +s3[ ])); + static assert(!__traits(compiles, +c1)); + static assert(!__traits(compiles, +c3)); + static assert(!__traits(compiles, +s1)); + static assert(!__traits(compiles, +s3)); + + // ArrayExp::op_overload + static assert(!__traits(compiles, c1[1])); + static assert(!__traits(compiles, c3[1])); + static assert(!__traits(compiles, s1[1])); + static assert(!__traits(compiles, s3[1])); + + // BinExp::op_overload + static assert(!__traits(compiles, c1 + 10)); // e1 + static assert(!__traits(compiles, c3 + 10)); // e1 + static assert(!__traits(compiles, 10 + c1)); // e2 + static assert(!__traits(compiles, 10 + c3)); // e2 + static assert(!__traits(compiles, s1 + 10)); // e1 + static assert(!__traits(compiles, s3 + 10)); // e1 + static assert(!__traits(compiles, 10 + s1)); // e2 + static assert(!__traits(compiles, 10 + s3)); // e2 + + // BinExp::compare_overload + static assert(!__traits(compiles, c1 < 10)); // (Object.opCmp(int) is invalid) + static assert(!__traits(compiles, c3 < 10)); // (Object.opCmp(int) is invalid) + static assert(!__traits(compiles, 10 < c1)); // (Object.opCmp(int) is invalid) + static assert(!__traits(compiles, 10 < c3)); // (Object.opCmp(int) is invalid) + static assert(!__traits(compiles, s1 < 10)); // e1 + static assert(!__traits(compiles, s3 < 10)); // e1 + static assert(!__traits(compiles, 10 < s1)); // e2 + static assert(!__traits(compiles, 10 < s3)); // e2 + + // BinAssignExp::op_overload + static assert(!__traits(compiles, c1[1] += 1)); + static assert(!__traits(compiles, c3[1] += 1)); + static assert(!__traits(compiles, s1[1] += 1)); + static assert(!__traits(compiles, s3[1] += 1)); + static assert(!__traits(compiles, c1[ ] += 1)); + static assert(!__traits(compiles, c3[ ] += 1)); + static assert(!__traits(compiles, s1[ ] += 1)); + static assert(!__traits(compiles, s3[ ] += 1)); + static assert(!__traits(compiles, c1 += c0)); // e1 + static assert(!__traits(compiles, c3 += c0)); // e1 + static assert(!__traits(compiles, s1 += s0)); // e1 + static assert(!__traits(compiles, s3 += s0)); // e1 + static assert(!__traits(compiles, c0 += c1)); // e2 + static assert(!__traits(compiles, c0 += c3)); // e2 + static assert(!__traits(compiles, s0 += s1)); // e2 + static assert(!__traits(compiles, s0 += s3)); // e2 + static assert(!__traits(compiles, c1 += s1)); // e1 + e2 + static assert(!__traits(compiles, c3 += s3)); // e1 + e2 + + // ForeachStatement::inferAggregate + static assert(!__traits(compiles, { foreach (e; s1){} })); + static assert(!__traits(compiles, { foreach (e; s3){} })); + static assert(!__traits(compiles, { foreach (e; c1){} })); + static assert(!__traits(compiles, { foreach (e; c3){} })); + + // Expression::checkToBoolean + static assert(!__traits(compiles, { if (s1){} })); + static assert(!__traits(compiles, { if (s3){} })); + + // SwitchStatement::semantic + static assert(!__traits(compiles, { switch (c0) { default: } })); + static assert(!__traits(compiles, { switch (c1) { default: } })); + static assert(!__traits(compiles, { switch (c3) { default: } })); + + // Bugzilla 12537: function arguments with IFTI + void eq12537()(Object lhs) {} + const C0 cc0; + const C1 cc1; + const C3 cc3; + static assert(!__traits(compiles, eq12537(cc0))); + static assert(!__traits(compiles, eq12537(cc1))); + static assert(!__traits(compiles, eq12537(cc3))); +} + +/***************************************************/ +// 11875 - endless recursion in Type::deduceType + +struct T11875x(C) +{ + C c; +} +class D11875a { D11875b c; alias c this; } +class D11875b { D11875a c; alias c this; } +static assert(!is(D11875a == D11875b)); +static assert( is(T11875x!D11875a == T11875x!D, D) && is(D == D11875a)); +static assert(!is(D11875a == T11875x!D, D)); // this used to freeze dmd + +// test that types in recursion are still detected +struct T11875y(C) +{ + C c; + alias c this; +} +class D11875c { T11875y!D11875b c; alias c this; } +static assert(is(D11875c : T11875y!D, D) && is(D == D11875b)); + +/***************************************************/ +// 11930 + +class BarObj11930 {} + +struct Bar11930 +{ + BarObj11930 _obj; + alias _obj this; +} + +BarObj11930 getBarObj11930(T)(T t) +{ + static if (is(T unused : BarObj11930)) + return t; + else + static assert(false, "Can not get BarObj from " ~ T.stringof); +} + +void test11930() +{ + Bar11930 b; + getBarObj11930(b); +} + +/***************************************************/ +// 2781 + +struct Tuple2781a(T...) { + T data; + alias data this; +} + +struct Tuple2781b(T) { + T data; + alias data this; +} + +void test2781() +{ + Tuple2781a!(uint, float) foo; + foreach(elem; foo) {} + + { + Tuple2781b!(int[]) bar1; + foreach(elem; bar1) {} + + Tuple2781b!(int[int]) bar2; + foreach(key, elem; bar2) {} + + Tuple2781b!(string) bar3; + foreach(dchar elem; bar3) {} + } + + { + Tuple2781b!(int[]) bar1; + foreach(elem; bar1) goto L1; + L1: + ; + + Tuple2781b!(int[int]) bar2; + foreach(key, elem; bar2) goto L2; + L2: + ; + + Tuple2781b!(string) bar3; + foreach(dchar elem; bar3) goto L3; + L3: + ; + } + + + int eval; + + auto t1 = tup(10, "str"); + auto i1 = 0; + foreach (e; t1) + { + pragma(msg, "[] = ", typeof(e)); + static if (is(typeof(e) == int )) assert(i1 == 0 && e == 10); + static if (is(typeof(e) == string)) assert(i1 == 1 && e == "str"); + ++i1; + } + + auto t2 = tup(10, "str"); + foreach (i2, e; t2) + { + pragma(msg, "[", cast(int)i2, "] = ", typeof(e)); + static if (is(typeof(e) == int )) { static assert(i2 == 0); assert(e == 10); } + static if (is(typeof(e) == string)) { static assert(i2 == 1); assert(e == "str"); } + } + + auto t3 = tup(10, "str"); + auto i3 = 2; + foreach_reverse (e; t3) + { + --i3; + pragma(msg, "[] = ", typeof(e)); + static if (is(typeof(e) == int )) assert(i3 == 0 && e == 10); + static if (is(typeof(e) == string)) assert(i3 == 1 && e == "str"); + } + + auto t4 = tup(10, "str"); + foreach_reverse (i4, e; t4) + { + pragma(msg, "[", cast(int)i4, "] = ", typeof(e)); + static if (is(typeof(e) == int )) { static assert(i4 == 0); assert(e == 10); } + static if (is(typeof(e) == string)) { static assert(i4 == 1); assert(e == "str"); } + } + + eval = 0; + foreach (i, e; tup(tup((eval++, 10), 3.14), tup("str", [1,2]))) + { + static if (i == 0) assert(e == tup(10, 3.14)); + static if (i == 1) assert(e == tup("str", [1,2])); + } + assert(eval == 1); + + eval = 0; + foreach (i, e; tup((eval++,10), tup(3.14, tup("str", tup([1,2]))))) + { + static if (i == 0) assert(e == 10); + static if (i == 1) assert(e == tup(3.14, tup("str", tup([1,2])))); + } + assert(eval == 1); +} + +/**********************************************/ +// 6546 + +void test6546() +{ + class C {} + class D : C {} + + struct S { C c; alias c this; } // S : C + struct T { S s; alias s this; } // T : S + struct U { T t; alias t this; } // U : T + + C c; + D d; + S s; + T t; + U u; + + assert(c is c); // OK + assert(c is d); // OK + assert(c is s); // OK + assert(c is t); // OK + assert(c is u); // OK + + assert(d is c); // OK + assert(d is d); // OK + assert(d is s); // doesn't work + assert(d is t); // doesn't work + assert(d is u); // doesn't work + + assert(s is c); // OK + assert(s is d); // doesn't work + assert(s is s); // OK + assert(s is t); // doesn't work + assert(s is u); // doesn't work + + assert(t is c); // OK + assert(t is d); // doesn't work + assert(t is s); // doesn't work + assert(t is t); // OK + assert(t is u); // doesn't work + + assert(u is c); // OK + assert(u is d); // doesn't work + assert(u is s); // doesn't work + assert(u is t); // doesn't work + assert(u is u); // OK +} + +/**********************************************/ +// 6736 + +void test6736() +{ + static struct S1 + { + struct S2 // must be 8 bytes in size + { + uint a, b; + } + S2 s2; + alias s2 this; + } + S1 c; + static assert(!is(typeof(c + c))); +} + +/**********************************************/ +// 2777 + +struct ArrayWrapper(T) { + T[] array; + alias array this; +} + +// alias array this +void test2777a() +{ + ArrayWrapper!(uint) foo; + foo.length = 5; // Works + foo[0] = 1; // Works + auto e0 = foo[0]; // Works + auto e4 = foo[$ - 1]; // Error: undefined identifier __dollar + auto s01 = foo[0..2]; // Error: ArrayWrapper!(uint) cannot be sliced with[] +} + +// alias tuple this +void test2777b() +{ + auto t = tup(10, 3.14, "str", [1,2]); + + assert(t[$ - 1] == [1,2]); + + auto f1 = t[]; + assert(f1[0] == 10); + assert(f1[1] == 3.14); + assert(f1[2] == "str"); + assert(f1[3] == [1,2]); + + auto f2 = t[1..3]; + assert(f2[0] == 3.14); + assert(f2[1] == "str"); +} + +/****************************************/ +// 2787 + +struct Base2787 +{ + int x; + void foo() { auto _ = x; } +} + +struct Derived2787 +{ + Base2787 _base; + alias _base this; + int y; + void bar() { auto _ = x; } +} + +/***********************************/ +// 5679 + +void test5679() +{ + class Foo {} + + class Base + { + @property Foo getFoo() { return null; } + } + class Derived : Base + { + alias getFoo this; + } + + Derived[] dl; + Derived d = new Derived(); + dl ~= d; // Error: cannot append type alias_test.Base to type Derived[] +} + +/***********************************/ +// 6508 + +void test6508() +{ + int x, y; + Seq!(x, y) = tup(10, 20); + assert(x == 10); + assert(y == 20); +} + +void test6508x() +{ + static int ctor, cpctor, dtor; + + static struct Tuple(T...) + { + T field; + alias field this; + + this(int) { ++ctor; printf("ctor\n"); } + this(this) { ++cpctor; printf("cpctor\n"); } + ~this() { ++dtor; printf("dtor\n"); } + } + + { + alias Tup = Tuple!(int, string); + auto tup = Tup(1); + assert(ctor==1 && cpctor==0 && dtor==0); + + auto getVal() { return tup; } + ref getRef(ref Tup s = tup) { return s; } + + { + auto n1 = tup[0]; + assert(ctor==1 && cpctor==0 && dtor==0); + + auto n2 = getRef()[0]; + assert(ctor==1 && cpctor==0 && dtor==0); + + auto n3 = getVal()[0]; + assert(ctor==1 && cpctor==1 && dtor==1); + } + + // bug in DotVarExp::semantic + { + typeof(tup.field) vars; + vars = getVal(); + assert(ctor==1 && cpctor==2 && dtor==2); + } + } + assert(ctor==1 && cpctor==2 && dtor==3); + assert(ctor + cpctor == dtor); +} + +/***********************************/ +// 6369 + +void test6369a() +{ + alias Seq!(int, string) Field; + + auto t1 = Tup!(int, string)(10, "str"); + Field field1 = t1; // NG -> OK + assert(field1[0] == 10); + assert(field1[1] == "str"); + + auto t2 = Tup!(int, string)(10, "str"); + Field field2 = t2.field; // NG -> OK + assert(field2[0] == 10); + assert(field2[1] == "str"); + + auto t3 = Tup!(int, string)(10, "str"); + Field field3; + field3 = t3.field; + assert(field3[0] == 10); + assert(field3[1] == "str"); +} + +void test6369b() +{ + auto t = Tup!(Tup!(int, double), string)(tup(10, 3.14), "str"); + + Seq!(int, double, string) fs1 = t; + assert(fs1[0] == 10); + assert(fs1[1] == 3.14); + assert(fs1[2] == "str"); + + Seq!(Tup!(int, double), string) fs2 = t; + assert(fs2[0][0] == 10); + assert(fs2[0][1] == 3.14); + assert(fs2[0] == tup(10, 3.14)); + assert(fs2[1] == "str"); + + Tup!(Tup!(int, double), string) fs3 = t; + assert(fs3[0][0] == 10); + assert(fs3[0][1] == 3.14); + assert(fs3[0] == tup(10, 3.14)); + assert(fs3[1] == "str"); +} + +void test6369c() +{ + auto t = Tup!(Tup!(int, double), Tup!(string, int[]))(tup(10, 3.14), tup("str", [1,2])); + + Seq!(int, double, string, int[]) fs1 = t; + assert(fs1[0] == 10); + assert(fs1[1] == 3.14); + assert(fs1[2] == "str"); + assert(fs1[3] == [1,2]); + + Seq!(int, double, Tup!(string, int[])) fs2 = t; + assert(fs2[0] == 10); + assert(fs2[1] == 3.14); + assert(fs2[2] == tup("str", [1,2])); + + Seq!(Tup!(int, double), string, int[]) fs3 = t; + assert(fs3[0] == tup(10, 3.14)); + assert(fs3[0][0] == 10); + assert(fs3[0][1] == 3.14); + assert(fs3[1] == "str"); + assert(fs3[2] == [1,2]); +} + +void test6369d() +{ + int eval = 0; + Seq!(int, string) t = tup((++eval, 10), "str"); + assert(eval == 1); + assert(t[0] == 10); + assert(t[1] == "str"); +} + +/**********************************************/ +// 6434 + +struct Variant6434{} + +struct A6434 +{ + Variant6434 i; + alias i this; + + void opDispatch(string name)() + { + } +} + +void test6434() +{ + A6434 a; + a.weird; // no property 'weird' for type 'VariantN!(maxSize)' +} + +/**************************************/ +// 6366 + +void test6366() +{ + struct Zip + { + string str; + size_t i; + this(string s) + { + str = s; + } + @property const bool empty() + { + return i == str.length; + } + @property Tup!(size_t, char) front() + { + return typeof(return)(i, str[i]); + } + void popFront() + { + ++i; + } + } + + foreach (i, c; Zip("hello")) + { + switch (i) + { + case 0: assert(c == 'h'); break; + case 1: assert(c == 'e'); break; + case 2: assert(c == 'l'); break; + case 3: assert(c == 'l'); break; + case 4: assert(c == 'o'); break; + default:assert(0); + } + } + + auto range(F...)(F field) + { + static struct Range { + F field; + bool empty = false; + Tup!F front() { return typeof(return)(field); } + void popFront(){ empty = true; } + } + return Range(field); + } + + foreach (i, t; range(10, tup("str", [1,2]))){ + static assert(is(typeof(i) == int)); + static assert(is(typeof(t) == Tup!(string, int[]))); + assert(i == 10); + assert(t == tup("str", [1,2])); + } + auto r1 = range(10, "str", [1,2]); + auto r2 = range(tup(10, "str"), [1,2]); + auto r3 = range(10, tup("str", [1,2])); + auto r4 = range(tup(10, "str", [1,2])); + alias Seq!(r1, r2, r3, r4) ranges; + foreach (n, _; ranges) + { + foreach (i, s, a; ranges[n]){ + static assert(is(typeof(i) == int)); + static assert(is(typeof(s) == string)); + static assert(is(typeof(a) == int[])); + assert(i == 10); + assert(s == "str"); + assert(a == [1,2]); + } + } +} + +/***************************************************/ +// 6711 + +void test6711() +{ + struct A { int i; } + struct B { A a; alias a this; } + struct C { B b; alias b this; } + + B b; + with (b) + { + i = 42; + } + assert(b.i == 42); + + C c; + with (c) + { + i = 42; + } + assert(c.i == 42); +} + +/**********************************************/ +// 12161 + +class A12161 +{ + void m() {} +} + +class B12161 +{ + A12161 a; + alias a this; +} + +void test12161() +{ + B12161 b = new B12161(); + b.a = new A12161(); + with (b) + m(); +} + +/**********************************************/ +// 6759 + +struct Range +{ + size_t front() { return 0; } + void popFront() { empty = true; } + bool empty; +} + +struct ARange +{ + Range range; + alias range this; +} + +void test6759() +{ + ARange arange; + assert(arange.front == 0); + foreach(e; arange) + { + assert(e == 0); + } +} + +/**********************************************/ +// 6479 + +struct Memory6479 +{ + mixin Wrapper6479!(); +} +struct Image6479 +{ + Memory6479 sup; + alias sup this; +} +mixin template Wrapper6479() +{ +} + +/**********************************************/ +// 6832 + +void test6832() +{ + static class Foo { } + static struct Bar { Foo foo; alias foo this; } + Bar bar; + bar = new Foo; // ok + assert(bar !is null); // ng + + struct Int { int n; alias n this; } + Int a; + int b; + auto c = (true ? a : b); // TODO + assert(c == a); +} + +/**********************************************/ +// 6928 + +void test6928() +{ + struct T { int* p; } // p is necessary. + T tx; + + struct S { + T get() const { return tx; } + alias get this; + } + + immutable(S) s; + immutable(T) t; + static assert(is(typeof(1? s:t))); // ok. + static assert(is(typeof(1? t:s))); // ok. + static assert(is(typeof(1? s:t)==typeof(1? t:s))); // fail. + + auto x = 1? t:s; // ok. + auto y = 1? s:t; // compile error. +} + +/**********************************************/ +// 6929 + +struct S6929 +{ + T6929 get() const { return T6929.init; } + alias get this; +} +struct T6929 +{ + S6929 get() const { return S6929.init; } + alias get this; +} +void test6929() +{ + T6929 t; + S6929 s; + static assert(!is(typeof(1? t:s))); +} + +/***************************************************/ +// 7136 + +void test7136() +{ + struct X + { + Object get() immutable { return null; } + alias get this; + } + immutable(X) x; + Object y; + static assert( is(typeof(1?x:y) == Object)); // fails + static assert(!is(typeof(1?x:y) == const(Object))); // fails + + struct A + { + int[] get() immutable { return null; } + alias get this; + } + immutable(A) a; + int[] b; + static assert( is(typeof(1?a:b) == int[])); // fails + static assert(!is(typeof(1?a:b) == const(int[]))); // fails +} + +/***************************************************/ +// 7731 + +struct A7731 +{ + int a; +} +template Inherit7731(alias X) +{ + X __super; + alias __super this; +} +struct B7731 +{ + mixin Inherit7731!A7731; + int b; +} + +struct PolyPtr7731(X) +{ + X* _payload; + static if (is(typeof(X.init.__super))) + { + alias typeof(X.init.__super) Super; + @property auto getSuper(){ return PolyPtr7731!Super(&_payload.__super); } + alias getSuper this; + } +} +template create7731(X) +{ + PolyPtr7731!X create7731(T...)(T args){ + return PolyPtr7731!X(args); + } +} + +void f7731a(PolyPtr7731!A7731 a) {/*...*/} +void f7731b(PolyPtr7731!B7731 b) {f7731a(b);/*...*/} + +void test7731() +{ + auto b = create7731!B7731(); +} + +/***************************************************/ +// 7808 + +struct Nullable7808(T) +{ + private T _value; + + this()(T value) + { + _value = value; + } + + @property ref inout(T) get() inout pure @safe + { + return _value; + } + alias get this; +} + +class C7808 {} +struct S7808 { C7808 c; } + +void func7808(S7808 s) {} + +void test7808() +{ + auto s = Nullable7808!S7808(S7808(new C7808)); + func7808(s); +} + +/***************************************************/ +// 7945 + +struct S7945 +{ + int v; + alias v this; +} +void foo7945(ref int n){} + +void test7945() +{ + auto s = S7945(1); + foo7945(s); // 1.NG -> OK + s.foo7945(); // 2.OK, ufcs + foo7945(s.v); // 3.OK + s.v.foo7945(); // 4.OK, ufcs +} + +/***************************************************/ +// 15674 - alias this on out parameter, consistent with 7945 case + +struct S15674 +{ + int v; + alias v this; +} +void foo15674(out int i){ i = 42; } + +void test15674() +{ + S15674 s; + s.v = 1; foo15674(s); assert(s.v == 42); + s.v = 1; foo15674(s.v); assert(s.v == 42); + s.v = 1; s.foo15674(); assert(s.v == 42); + s.v = 1; s.v.foo15674(); assert(s.v == 42); +} + +/***************************************************/ +// 7979 + +void test7979() +{ + static struct N + { + int val; + alias val this; + } + N n = N(1); + + switch (n) + { + case 0: + assert(0); + case 1: + break; + default: + assert(0); + } + + static struct S + { + string val; + alias val this; + } + S s = S("b"); + + switch (s) + { + case "a": + assert(0); + case "b": + break; + default: + assert(0); + } +} + +/***************************************************/ +// 7992 + +struct S7992 +{ + int[] arr; + alias arr this; +} +S7992 func7992(...) +{ + S7992 ret; + ret.arr.length = _arguments.length; + return ret; +} +void test7992() +{ + int[] arr; + assert(arr.length == 0); + arr ~= func7992(1, 2); //NG + //arr = func7992(1, 2); //OK + assert(arr.length == 2); +} + +/***************************************************/ +// 8169 + +void test8169() +{ + static struct ValueImpl + { + static immutable(int) getValue() + { + return 42; + } + } + + static struct ValueUser + { + ValueImpl m_valueImpl; + alias m_valueImpl this; + } + + static assert(ValueImpl.getValue() == 42); // #0, OK + static assert(ValueUser.getValue() == 42); // #1, NG -> OK + static assert( ValueUser.m_valueImpl .getValue() == 42); // #2, NG -> OK + static assert(typeof(ValueUser.m_valueImpl).getValue() == 42); // #3, OK +} + +/***************************************************/ +// 8735 + +struct S8735(alias Arg) +{ + alias Arg Val; + alias Val this; +} + +struct Tuple9709(T...) +{ + alias T expand; + alias expand this; +} + +void test8735() +{ + alias S8735!1 S; + S s; + int n = s; + assert(n == 1); + + // 11502 case + static void f(int i); + S8735!f sf; + + // 9709 case + alias A = Tuple9709!(1,int,"foo"); + A a; + //static assert(A[0] == 1); + static assert(a[0] == 1); + //static assert(is(A[1] == int)); + //static assert(is(a[1] == int)); + //static assert(A[2] == "foo"); + static assert(a[2] == "foo"); +} + +/***************************************************/ +// 9174 + +void test9174() +{ + static struct Foo + { + char x; + alias x this; + } + static assert(is(typeof(true ? 'A' : Foo()) == char)); + static assert(is(typeof(true ? Foo() : 100) == int)); +} + +/***************************************************/ +// 9177 + +struct S9177 +{ + int foo(int){ return 0; } + alias foo this; +} +pragma(msg, is(S9177 : int)); + +/***************************************************/ +// 9858 + +struct S9858() +{ + @property int get() const + { + return 42; + } + alias get this; + void opAssign(int) {} +} +void test9858() +{ + const S9858!() s; + int i = s; +} + +/***************************************************/ +// 9873 + +void test9873() +{ + struct Tup(T...) { T field; alias field this; } + + auto seq1 = Seq!(1, "hi"); + assert(Seq!(1, "hi") == Seq!(1, "hi")); + assert(seq1 == Seq!(1, "hi")); + assert(Seq!(1, "hi") == seq1); + assert(seq1 == seq1); + + auto seq2 = Seq!(2, "hi"); + assert(Seq!(1, "hi") != Seq!(2, "hi")); + assert(seq2 != Seq!(1, "hi")); + assert(Seq!(1, "hi") != seq2); + assert(seq2 != seq1); + + auto tup1 = Tup!(int, string)(1, "hi"); + assert(Seq!(1, "hi") == tup1); + assert(seq1 == tup1); + assert(tup1 == Seq!(1, "hi")); + assert(tup1 == seq1); + + auto tup2 = Tup!(int, string)(2, "hi"); + assert(Seq!(1, "hi") != tup2); + assert(seq1 != tup2); + assert(tup2 != Seq!(1, "hi")); + assert(tup2 != seq1); + + static assert(!__traits(compiles, seq1 == Seq!(1, "hi", [1,2]))); + static assert(!__traits(compiles, tup1 == Seq!(1, "hi", [1,2]))); +} + +/***************************************************/ +// 10178 + +void test10178() +{ + struct S { static int count; } + S s; + assert((s.tupleof == s.tupleof) == true); + assert((s.tupleof != s.tupleof) == false); + + S getS() + { + S s; + ++S.count; + return s; + } + assert(getS().tupleof == getS().tupleof); + assert(S.count == 2); +} + +/***************************************************/ +// 10179 + +void test10179() +{ + struct S { static int count; } + S s; + static assert(s.tupleof.length == 0); + s.tupleof = s.tupleof; // error -> OK + + S getS() + { + S s; + ++S.count; + return s; + } + getS().tupleof = getS().tupleof; + assert(S.count == 2); +} + +/***************************************************/ +// 9890 + +void test9890() +{ + struct RefCounted(T) + { + T _payload; + + ref T refCountedPayload() + { + return _payload; + } + + alias refCountedPayload this; + } + + struct S(int x_) + { + alias x_ x; + } + + alias RefCounted!(S!1) Rs; + static assert(Rs.x == 1); +} + +/***************************************************/ +// 10004 + +void test10004() +{ + static int count = 0; + + static S make(S)() + { + ++count; // necessary to make this function impure + S s; + return s; + } + + struct SX(T...) { + T field; alias field this; + } + alias S = SX!(int, long); + assert(make!S.field == make!S.field); + assert(count == 2); +} + +/***************************************************/ +// 10180 + +template TypeTuple10180(TL...) { alias TypeTuple10180 = TL; } + +template Identity10180(alias T) { alias Identity10180 = T; } + +struct Tuple10180(Specs...) +{ + static if (is(Specs)) + { + alias Types = Specs; + Types expand; + alias expand this; + } + else + { + alias Types = TypeTuple10180!(Specs[0]); + Types expand; + mixin("alias Identity10180!(expand[0]) "~Specs[1]~";"); + + @property + ref Tuple10180!(Specs[0]) _Tuple_super() + { + return *cast(typeof(return)*) (&expand[0]); + } + alias _Tuple_super this; + } +} + +void test10180() +{ + Tuple10180!(int, "a") x; + auto o1 = x.a.offsetof; // OK + auto o2 = x[0].offsetof; // NG: no property 'offsetof' for type 'int' + auto o3 = x._Tuple_super[0].offsetof; // same as above + assert(o2 == o3); +} + +/***************************************************/ +// 10456 + +void test10456() +{ + S10456 s1, s2; + auto x = s1 == s2; +} + +struct S10456 +{ + enum E { e }; + alias E this; + int[] x; +} + +/***************************************************/ +// 11261 + +template Tuple11261(Specs...) +{ + struct Tuple11261 + { + static if (Specs.length != 4) // anonymous field version + { + alias Specs Types; + Types expand; + alias expand this; + } + else + { + alias Seq!(Specs[0], Specs[2]) Types; + Types expand; + ref inout(Tuple11261!Types) _Tuple_super() inout @trusted + { + return *cast(typeof(return)*) &(expand[0]); + } + // This is mostly to make t[n] work. + alias _Tuple_super this; + } + + this()(Types values) + { + expand[] = values[]; + } + } +} + +interface InputRange11261(E) +{ + @property bool empty(); + @property E front(); + void popFront(); + + int opApply(int delegate(E)); + int opApply(int delegate(size_t, E)); + +} +template InputRangeObject11261(R) +{ + alias typeof(R.init.front()) E; + + class InputRangeObject11261 : InputRange11261!E + { + private R _range; + + this(R range) { this._range = range; } + + @property bool empty() { return _range.empty; } + @property E front() { return _range.front; } + void popFront() { _range.popFront(); } + + int opApply(int delegate(E) dg) { return 0; } + int opApply(int delegate(size_t, E) dg) { return 0; } + } +} + +// ------ + +class Container11261 +{ + alias Tuple11261!(string, "key", string, "value") Key; + + InputRange11261!Key opSlice() + { + Range r; + return new InputRangeObject11261!Range(r); + } + private struct Range + { + enum empty = false; + auto popFront() {} + auto front() { return Key("myKey", "myValue"); } + } +} + +void test11261() +{ + auto container = new Container11261(); + foreach (k, v; container) // map the tuple of container[].front to (k, v) + { + static assert(is(typeof(k) == string) && is(typeof(v) == string)); + break; + } +} + +/***************************************************/ +// 11333 + +alias id11333(a...) = a; + +struct Unit11333 +{ + enum value = Unit11333.init.tupleof; + alias value this; +} + +void test11333() +{ + void foo() {} + + id11333!() unit; + unit = unit; // ok + foo(unit); // ok + + unit = Unit11333.value; // ok + foo(Unit11333.value); // ok + + Unit11333 unit2; + unit = unit2; // ok <- segfault +} + +/***************************************************/ +// 11800 + +struct A11800 +{ + B11800 b; + alias b this; +} + +struct B11800 +{ + static struct Value {} + Value value; + alias value this; + + void foo(ref const B11800 rhs) + { + } +} + +void test11800() +{ + A11800 a; + B11800 b; + b.foo(a); +} + +/***************************************************/ +// 12008 + +struct RefCounted12008(T) +{ + struct RefCountedStore + { + private struct Impl + { + T _payload; + } + + private void initialize(A...)(auto ref A args) + { + import core.memory; + } + + void ensureInitialized() + { + initialize(); + } + + } + RefCountedStore _refCounted; + + void opAssign(T rhs) + { + } + + int refCountedPayload() + { + _refCounted.ensureInitialized(); + return 0; + } + + int refCountedPayload() inout + { + return 0; + } + + alias refCountedPayload this; +} + +struct SharedInput12008 +{ + Group12008 unused; +} + +struct Group12008 +{ + RefCounted12008!SharedInput12008 _allGroups; +} + +/***************************************************/ +// 12038 + +bool f12038(void* p) { return true; } + +struct S12038 +{ + @property p() { f12038(&this); } + alias p this; +} + +/***************************************************/ +// 13490 + +struct S13490 +{ + int i; + alias i this; +} + +struct T13490 +{ + S13490[] a1, a2; +} + +void test13490() +{ + T13490 t; + + (true ? t.a1 : t.a2) ~= S13490(1); + assert(t.a1 == [S13490(1)]); + assert(t.a2 == []); + + (false ? t.a1 : t.a2) ~= S13490(2); + assert(t.a1 == [S13490(1)]); + assert(t.a2 == [S13490(2)]); +} + +/***************************************************/ +// 11355 + +struct A11355 +{ + static int postblit; + this(this) { ++postblit; } +} + +struct B11355 +{ + A11355 a; + alias a this; +} + +B11355 make11355() +{ + return B11355(); +} +void test11355() +{ + A11355 a1 = make11355(); + assert(A11355.postblit == 1); +} + +/***************************************************/ +// 13009 + +struct T13009 +{ + void put(char c) {} +} + +struct S13009(bool rev) +{ + T13009 t; + + static if (!rev) + { + @property T13009 getT() { return t; } + @property inout(T13009) getT() inout { return t; } + } + else + { + @property inout(T13009) getT() inout { return t; } + @property T13009 getT() { return t; } + } + + alias getT this; +} + +void test13009() +{ + foreach (bool rev; Seq!(false, true)) + { + alias S = S13009!rev; + + alias MS = S; + alias CS = const(S); + alias WS = inout( S); + alias WCS = inout(const S); + alias SMS = shared( S); + alias SCS = shared( const S); + alias SWS = shared(inout S); + alias SWCS = shared(inout const S); + alias IS = immutable(S); + + alias MSput = MS .put; + alias CSput = CS .put; + alias WSput = WS .put; + alias WCSput = WCS.put; + static assert(!__traits(compiles, { alias SMSput = SMS .put; })); + static assert(!__traits(compiles, { alias SCSput = SCS .put; })); + static assert(!__traits(compiles, { alias SWSput = SWS .put; })); + static assert(!__traits(compiles, { alias SWCSput = SWCS.put; })); + alias ISput = IS .put; + } +} + +/***************************************************/ +// 14806 + +struct Nullable14806 +{ + float get() { return float.nan; } + alias get this; +} + +struct Foo14806(T) +{ + T bar; + Nullable14806 baz; +} + +void test14806() +{ + Foo14806!int a, b; + assert(a != b); + // ==> a.tupleof != b.tupleof + // ==> a.bar != b.bar || a.baz.get() != b.baz.get() + + Foo14806!string c, d; + assert(c != d); + // ==> c.tupleof != d.tupleof + // ==> c.bar != d.bar || c.baz.get() != d.baz.get() +} + +/***************************************************/ +// 14948 + +struct RefCounted14948(T) +{ + struct Impl + { + T data; + } + Impl* impl; + + @property ref T payload() { return impl.data; } + + alias payload this; +} + +struct HTTP14948 +{ + struct Impl + { + } + + RefCounted14948!Impl p; +} + +void test14948() +{ + int[HTTP14948] aa; +} + +/***************************************************/ +// 15292 + +struct NullableRef15292(T) +{ + inout(T) get() inout + { + assert(false); + } + + alias get this; +} + +struct S15292 +{ + NullableRef15292!S15292 n; // -> no segfault + + /* The field 'n' contains alias this, so to use it for the equality, + * following helper function is automatically generated in buildXopEquals(). + * + * static bool __xopEquals(ref const S15292 p, ref const S15292 q) + * { + * return p == q; + * } + * + * In its definition, const(S15292) equality is analyzed. It fails, then + * the error is gagged. + */ +} + +/***************************************************/ + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test4617a(); + test4617b(); + test4773(); + test5188(); + test6(); + test7(); + test2781(); + test6546(); + test6736(); + test2777a(); + test2777b(); + test5679(); + test6508(); + test6508x(); + test6369a(); + test6369b(); + test6369c(); + test6369d(); + test6434(); + test6366(); + test6711(); + test12161(); + test6759(); + test6832(); + test6928(); + test6929(); + test7136(); + test7731(); + test7808(); + test7945(); + test15674(); + test7979(); + test7992(); + test8169(); + test8735(); + test9174(); + test9858(); + test9873(); + test10178(); + test10179(); + test9890(); + test10004(); + test10180(); + test10456(); + test11333(); + test11800(); + test13490(); + test11355(); + test14806(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/argufilem.d b/gcc/testsuite/gdc.test/runnable/argufilem.d new file mode 100644 index 00000000000..44d627005cc --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/argufilem.d @@ -0,0 +1,22 @@ +// EXTRA_SOURCES: imports/argufile.d + +// NOTE: The bug only works when main.d and argufile.d are put in +// separate files and compiled like 'dmd main.d argufile.d' +// Also, I'm sure writefln is causing the crash cause when I +// use printf(), it doesn't crash. + +// main.d ------------------------------------------------------- + +import argufile; + +int main(string[] args) +{ + string message = arguments("bob is ", 7, " years old"); + + writefln(message); + + argufile.useargs(); // will crash here + + return 0; +} + diff --git a/gcc/testsuite/gdc.test/runnable/arrayop.d b/gcc/testsuite/gdc.test/runnable/arrayop.d new file mode 100644 index 00000000000..99bf800f610 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/arrayop.d @@ -0,0 +1,956 @@ +import std.math; + +extern(C) int printf(const char*, ...); + +string abc; + +template Floating(T) +{ + T[3] a; + T[3] b; + T[3] c; + + T[] A() + { + printf("A\n"); + abc ~= "A"; + return a; + } + + T[] B() + { + printf("B\n"); + abc ~= "B"; + return b; + } + + T[] C() + { + printf("C\n"); + abc ~= "C"; + return c; + } + + T D() + { + printf("D\n"); + abc ~= "D"; + return 4; + } + + + void testx() + { + a = [11, 22, 33]; + b = [1, 2, 3]; + c = [4, 5, 6]; + + abc = null; + A()[] = B()[] + C()[]; + assert(abc == "BCA"); + assert(a[0] == 5); + assert(a[1] == 7); + assert(a[2] == 9); + + abc = null; + A()[] = B()[] + 4; + assert(abc == "BA"); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 7); + + abc = null; + A()[] = 4 + B()[]; + assert(abc == "BA"); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 7); + + abc = null; + A()[] = D() + B()[]; + assert(abc == "DBA"); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 7); + + a = [11, 22, 33]; + abc = null; + A()[] += B()[]; + assert(abc == "BA"); + assert(a[0] == 12); + assert(a[1] == 24); + assert(a[2] == 36); + + a = [11, 22, 33]; + A()[] += 4; + assert(a[0] == 15); + assert(a[1] == 26); + assert(a[2] == 37); + + a = [11, 22, 33]; + A()[] -= 4; + assert(a[0] == 7); + assert(a[1] == 18); + assert(a[2] == 29); + + a = [11, 22, 33]; + A()[] *= 4; + assert(a[0] == 44); + assert(a[1] == 88); + assert(a[2] == 132); + + a = [4, 8, 32]; + A()[] /= 4; + assert(a[0] == 1); + assert(a[1] == 2); + assert(a[2] == 8); + + a = [4, 8, 33]; + A()[] %= 4; + assert(a[0] == 0); + assert(a[1] == 0); + assert(a[2] == 1); + + a = [11, 22, 33]; + abc = null; + A()[] += 4 + B()[]; + assert(abc == "BA"); + assert(a[0] == 16); + assert(a[1] == 28); + assert(a[2] == 40); + + abc = null; + A()[] = B()[] - C()[]; + assert(abc == "BCA"); + printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); + assert(a[0] == -3); + assert(a[1] == -3); + assert(a[2] == -3); + + abc = null; + A()[] = -B()[] - C()[]; + assert(abc == "BCA"); + printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); + assert(a[0] == -5); + assert(a[1] == -7); + assert(a[2] == -9); + + abc = null; + A()[] = B()[] + C()[] * 4; + assert(abc == "BCA"); + printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); + assert(a[0] == 17); + assert(a[1] == 22); + assert(a[2] == 27); + + abc = null; + A()[] = B()[] + C()[] * B()[]; + assert(abc == "BCBA"); + printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); + assert(a[0] == 5); + assert(a[1] == 12); + assert(a[2] == 21); + + abc = null; + A()[] = B()[] + C()[] / 2; + assert(abc == "BCA"); + printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); + assert(a[0] == 3); + assert(a[1] == 4.5); + assert(a[2] == 6); + + abc = null; + A()[] = B()[] + C()[] % 2; + assert(abc == "BCA"); + printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]); + assert(a[0] == 1); + assert(a[1] == 3); + assert(a[2] == 3); + } +} + +mixin Floating!(float) Ffloat; +mixin Floating!(double) Fdouble; +mixin Floating!(real) Freal; + +void test1() +{ + Ffloat.testx(); + Fdouble.testx(); + Freal.testx(); +} + +/************************************************************************/ + +template Integral(T) +{ + T[3] a; + T[3] b; + T[3] c; + + T[] A() + { + printf("A\n"); + abc ~= "A"; + return a; + } + + T[] B() + { + printf("B\n"); + abc ~= "B"; + return b; + } + + T[] C() + { + printf("C\n"); + abc ~= "C"; + return c; + } + + T D() + { + printf("D\n"); + abc ~= "D"; + return 4; + } + + + void testx() + { + a = [11, 22, 33]; + b = [1, 2, 3]; + c = [4, 5, 6]; + + abc = null; + A()[] = B()[] + C()[]; + assert(abc == "BCA"); + assert(a[0] == 5); + assert(a[1] == 7); + assert(a[2] == 9); + + abc = null; + A()[] = B()[] + 4; + assert(abc == "BA"); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 7); + + abc = null; + A()[] = 4 + B()[]; + assert(abc == "BA"); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 7); + + abc = null; + A()[] = D() + B()[]; + assert(abc == "DBA"); + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 7); + + a = [11, 22, 33]; + abc = null; + A()[] += B()[]; + assert(abc == "BA"); + assert(a[0] == 12); + assert(a[1] == 24); + assert(a[2] == 36); + + a = [11, 22, 33]; + A()[] += 4; + assert(a[0] == 15); + assert(a[1] == 26); + assert(a[2] == 37); + + a = [11, 22, 33]; + A()[] -= 4; + assert(a[0] == 7); + assert(a[1] == 18); + assert(a[2] == 29); + + a = [11, 22, 27]; + A()[] *= 4; + assert(a[0] == 44); + assert(a[1] == 88); + assert(a[2] == 108); + + a = [11, 22, 33]; + A()[] /= 4; + assert(a[0] == 2); + assert(a[1] == 5); + assert(a[2] == 8); + + a = [11, 22, 33]; + A()[] %= 4; + assert(a[0] == 3); + assert(a[1] == 2); + assert(a[2] == 1); + + a = [1, 2, 7]; + A()[] &= 4; + assert(a[0] == 0); + assert(a[1] == 0); + assert(a[2] == 4); + + a = [1, 2, 7]; + A()[] |= 4; + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 7); + + a = [1, 2, 7]; + A()[] ^= 4; + assert(a[0] == 5); + assert(a[1] == 6); + assert(a[2] == 3); + + a = [11, 22, 33]; + abc = null; + A()[] += 4 + B()[]; + assert(abc == "BA"); + assert(a[0] == 16); + assert(a[1] == 28); + assert(a[2] == 40); + + abc = null; + A()[] = B()[] - C()[]; + assert(abc == "BCA"); + printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); + assert(a[0] == -3); + assert(a[1] == -3); + assert(a[2] == -3); + + abc = null; + A()[] = -B()[] - C()[]; + assert(abc == "BCA"); + printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); + assert(a[0] == -5); + assert(a[1] == -7); + assert(a[2] == -9); + + abc = null; + A()[] = B()[] + C()[] * 4; + assert(abc == "BCA"); + printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); + assert(a[0] == 17); + assert(a[1] == 22); + assert(a[2] == 27); + + abc = null; + A()[] = B()[] + C()[] * B()[]; + assert(abc == "BCBA"); + printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); + assert(a[0] == 5); + assert(a[1] == 12); + assert(a[2] == 21); + + abc = null; + A()[] = B()[] + C()[] / 2; + assert(abc == "BCA"); + printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); + assert(a[0] == 3); + assert(a[1] == 4); + assert(a[2] == 6); + + abc = null; + A()[] = B()[] + C()[] % 2; + assert(abc == "BCA"); + printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]); + assert(a[0] == 1); + assert(a[1] == 3); + assert(a[2] == 3); + + abc = null; + A()[] = ~B()[]; + assert(abc == "BA"); + assert(a[0] == ~cast(T)1); + assert(a[1] == ~cast(T)2); + assert(a[2] == ~cast(T)3); + + abc = null; + A()[] = B()[] & 2; + assert(abc == "BA"); + assert(a[0] == 0); + assert(a[1] == 2); + assert(a[2] == 2); + + abc = null; + A()[] = B()[] | 2; + assert(abc == "BA"); + assert(a[0] == 3); + assert(a[1] == 2); + assert(a[2] == 3); + + abc = null; + A()[] = B()[] ^ 2; + assert(abc == "BA"); + assert(a[0] == 3); + assert(a[1] == 0); + assert(a[2] == 1); + } +} + +/************************************************************************/ + +mixin Integral!(byte) Fbyte; +mixin Integral!(short) Fshort; +mixin Integral!(int) Fint; +mixin Integral!(long) Flong; + +void test2() +{ + Fbyte.testx(); + Fshort.testx(); + Fint.testx(); + Flong.testx(); +} + +/************************************************************************/ + +void test3() +{ + auto a = new double[10], b = a.dup, c = a.dup, d = a.dup; + a[] = -(b[] * (c[] + 4)) + 5 * d[] / 3.0; +} + +/************************************************************************/ + +void test4() +{ + int[] a, b; + if (a && b) {} +} + +/***************************************************/ + +void test4662() +{ + immutable double[] nums = [1.0, 2.0]; + + static assert(!is(typeof({ nums[] += nums[]; }))); + static assert(!is(typeof({ nums[] -= nums[]; }))); + static assert(!is(typeof({ nums[] /= nums[]; }))); + static assert(!is(typeof({ nums[] += 4; }))); + static assert(!is(typeof({ nums[] /= 7; }))); +} + +/***************************************************/ +// 5284 + +void bug5284_1() +{ + class C { int v; } + + C [] mda; + immutable(C)[] ida; + static assert(!__traits(compiles, (mda[] = ida[]))); + + C [1] msa; + immutable(C)[1] isa; + static assert(!__traits(compiles, (msa[] = isa[]))); + + C m; + immutable(C) i; + static assert(!__traits(compiles, m = i)); +} +void bug5284_2a() +{ + struct S { int v; } + + S [] mda; + immutable(S)[] ida; + mda[] = ida[]; + + S [1] msa; + immutable(S)[1] isa; + msa[] = isa[]; + + S m = S(); + immutable(S) i = immutable(S)(); + m = i; +} +void bug5284_2b() +{ + struct S { int v; int[] arr; } + + S [] mda; + immutable(S)[] ida; + static assert(!__traits(compiles, (mda[] = ida[]))); + + S [1] msa; + immutable(S)[1] isa; + static assert(!__traits(compiles, (msa[] = isa[]))); + + S m; + immutable(S) i; + static assert(!__traits(compiles, m = i)); +} +void bug5284_3() +{ + int [] ma; + immutable(int)[] ia; + ma[] = ia[]; + + int m; + immutable(int) i; + m = i; +} + +void test5() +{ + bug5284_1(); + bug5284_2a(); + bug5284_2b(); + bug5284_3(); +} + +/************************************************************************/ + +void test6() +{ + int[10] a = [1,2,3,4,5,6,7,8,9,10]; + int[10] b; + + b = a[] ^^ 2; + assert(b[0] == 1); + assert(b[1] == 4); + assert(b[2] == 9); + assert(b[3] == 16); + assert(b[4] == 25); + assert(b[5] == 36); + assert(b[6] == 49); + assert(b[7] == 64); + assert(b[8] == 81); + assert(b[9] == 100); + + int[10] c = 3; + b = a[] ^^ c[]; + assert(b[0] == 1); + assert(b[1] == 8); + assert(b[2] == 27); + assert(b[3] == 64); + assert(b[4] == 125); + assert(b[5] == 216); + assert(b[6] == 343); + assert(b[7] == 512); + assert(b[8] == 729); + assert(b[9] == 1000); +} + +/************************************************************************/ + +void test8390() { + const int[] a = new int[5]; + int[] b = new int[5]; + b[] += a[]; +} + +/************************************************************************/ +// 8651 + +void test8651() +{ + void test(T)() @safe pure nothrow + { + T[3] a = [11, 22, 33]; + T[3] b = [1, 2, 3]; + T[3] c = [4, 5, 6]; + T d = 4; + + // Arithmetic array ops + { + a[] = b[] + c[]; + a[] = b[] + 4; + a[] = 4 + b[]; + a[] = d + b[]; + a[] += b[]; + a[] += 4; + a[] -= 4; + a[] *= 4; + a[] /= 4; + a[] %= 4; + a[] += 4 + b[]; + a[] = b[] - c[]; + a[] = -b[] - c[]; + a[] = b[] + c[] * 4; + a[] = b[] + c[] * b[]; + a[] = b[] + c[] / 2; + a[] = b[] + c[] % 2; + } + // Bitwise array ops + static if (is(typeof(T.init & T.init))) + { + a[] &= 4; + a[] |= 4; + a[] ^= 4; + a[] = ~b[]; + a[] = b[] & 2; + a[] = b[] | 2; + a[] = b[] ^ 2; + } + } + + test!float(); + test!double(); + test!real(); + + test!byte(); + test!short(); + test!int(); + test!long(); +} + +/************************************************************************/ +// 9656 + +void test9656() +{ + static class C {} + static struct S + { + immutable int[] narr1; + immutable int[] narr2; + immutable C[] carr1; + immutable C[] carr2; + this(int n) { + narr1 = new int[](3); // OK, expected + narr2 = [1,2,3].dup; // NG -> OK + carr1 = [new C].dup; // NG -> OK + + C c = new C; + static assert(!__traits(compiles, carr2 = [c])); + } + } + + { + int[] ma = [1,2,3]; + immutable ia = ma.dup; + } + + + { + static struct V { int val; } + V[] ma = [V(1), V(2)]; + immutable ia = ma.dup; + } + + { + static struct R { int* ptr; } + R[] ma = [R(new int), R(null)]; + static assert(!__traits(compiles, { immutable ia = rarr.dup; })); + } + + { + C[] ma = [new C(), new C()]; + static assert(!__traits(compiles, { immutable ia = carr.dup; })); + } +} + +/************************************************************************/ +// 10282 + +void test10282() +{ + int[3] a1 = [1, 3, 6]; + int[3] a2 = [1, 3, 6] * 3; // OK + const int[3] a3 = a1[] * 3; // OK <- Error + const int[3] a4 = [1, 3, 6] * 3; // OK <- Error + immutable int[3] a5 = [1, 3, 6] * 3; // OK <- Error + + assert(a1[0] == 1 && a1[1] == 3 && a1[2] == 6); + assert(a2[0] == 3 && a2[1] == 9 && a2[2] == 18); + assert(a3[0] == 3 && a3[1] == 9 && a3[2] == 18); + assert(a4[0] == 3 && a4[1] == 9 && a4[2] == 18); + assert(a5[0] == 3 && a5[1] == 9 && a5[2] == 18); +} + +/************************************************************************/ +// 10433 + +void test10433() +{ + void foo(T)(in int[] v1, in T v2) + { + int[2] r; + r[] = v1[] + v2[]; + } + + immutable int[] v = [10, 20]; + foo(v, v); +} + +/************************************************************************/ +// 10684 + +void test10684a() +{ + int[] a = [0, 0]; + a[] += [10, 20][]; +} + +void test10684b() +{ + int[] a = [1, 2, 3]; + int[] b = [4, 5, 6]; + + // Allow array literal as the operand of array oeration + a[] += [1, 2, 3]; + assert(a == [2, 4, 6]); + + a[] *= b[] + [1, 1, 1]; + assert(a == [2*(4+1), 4*(5+1), 6*(6+1)]); + + a[] = [9, 8, 7] - [1, 2, 3]; + assert(a == [8, 6, 4]); + + a[] = [2, 4, 6] / 2; + assert(a == [1,2,3]); + + // Disallow: [1,2,3] is not an lvalue + static assert(!__traits(compiles, { [1,2,3] = a[] * 2; })); + static assert(!__traits(compiles, { [1,2,3] += a[] * b[]; })); +} + +/************************************************************************/ +// 11376 + +template TL11376(T...) +{ + alias TL11376 = T; +} + +auto sumArrs11376(T0, T1)(T0[] a, T1[] b) +{ + a[] += b[]; //no ICE without this line + return a; +} + +static assert(!__traits(compiles, sumArrs11376(TL11376!(string[], string).init))); + +/************************************************************************/ +// 11525 + +void test11525() +{ + static struct Complex(T) + { + T re, im; + + ref opOpAssign(string op : "*")(Complex z) + { + auto temp = re*z.re - im*z.im; + im = im*z.re + re*z.im; + re = temp; + return this; + } + } + + auto a = [Complex!double(2, 2)]; + assert(a.length == 1 && a[0].re == 2 && a[0].im == 2); + a[] *= a[]; + assert(a.length == 1 && a[0].re == 0 && a[0].im == 8); +} + +/************************************************************************/ +// 12250 + +void f12250(inout int[] p, inout int[] q, int[] r) +{ + r[] = p[] + q[]; + assert(r == [5,7,9]); + r[] -= p[] - q[]; + assert(r == [8,10,12]); +} + +void test12250() +{ + immutable int[3] x = [1,2,3], y = [4,5,6]; + int[3] z; + f12250(x[], y[], z[]); +} + +/************************************************************************/ +// 12179 + +void test12179() +{ + void foo(int[]) {} + int[1] a; + + foo(a[] = a[]); + foo(a[] += a[]); + foo(a[] -= a[]); + foo(a[] *= a[]); + foo(a[] /= a[]); + foo(a[] %= a[]); + foo(a[] ^= a[]); + foo(a[] &= a[]); + foo(a[] |= a[]); + foo(a[] ^^= a[]); + + // from issue 11992 + int[] arr1; + int[][] arr2; + arr1 ~= (a[] = [1] + a[]); // OK + arr2 ~= (a[] = [1] + a[]); // OK +} + +/************************************************************************/ +// 12780 + +void test12780() +{ + int ival = 2; + int[] iarr = [1, 2, 3]; + double dval = 2.0; + double[] darr = [4, 5, 6]; + + double[] oarr = [0, 0, 0]; + + // multiply array operations + oarr[] = dval * iarr[]; + assert(oarr == [dval * iarr[0], + dval * iarr[1], + dval * iarr[2]]); + + oarr[] = iarr[] / dval; + assert(oarr == [iarr[0] / dval, + iarr[1] / dval, + iarr[2] / dval]); + + oarr[] = dval * (ival + iarr[]); + assert(oarr == [dval * (ival + iarr[0]), + dval * (ival + iarr[1]), + dval * (ival + iarr[2])]); + + oarr[] = (iarr[] & ival) / dval; + assert(oarr == [(iarr[0] & ival) / dval, + (iarr[1] & ival) / dval, + (iarr[2] & ival) / dval]); + + oarr[] = darr[] + iarr[]; + assert(oarr == [darr[0] + iarr[0], + darr[1] + iarr[1], + darr[2] + iarr[2]]); + + oarr[] = iarr[] - darr[]; + assert(oarr == [iarr[0] - darr[0], + iarr[1] - darr[1], + iarr[2] - darr[2]]); + + oarr[] = darr[] * (ival & iarr[]); + assert(oarr == [darr[0] * (ival & iarr[0]), + darr[1] * (ival & iarr[1]), + darr[2] * (ival & iarr[2])]); + + oarr[] = (iarr[] ^ ival) / darr[]; + assert(oarr == [(iarr[0] ^ ival) / darr[0], + (iarr[1] ^ ival) / darr[1], + (iarr[2] ^ ival) / darr[2]]); +} + +/************************************************************************/ +// 13497 + +void test13497() +{ + int[1] a = [2], b = [3]; + int[1] c1 = a[] * b[]; + int[1] c2 = (a[] * b[])[]; + assert(c1 == [6]); + assert(c2 == [6]); +} + +/************************************************************************/ +// 14649 + +void test14649() +{ + char[] a = "abc".dup; + char[] b = [char(1), char(2), char(3)]; + string x = "abc"; + string y = [char(1), char(2), char(3)]; + char[] r = new char[](3); + + r[] = a[] + b[]; + assert(r == "bdf"); + + r[] = x[] + y[]; + assert(r == "bdf"); + + r[] = "hel"[] + "lo."[]; + assert(r == [('h'+'l'), ('e'+'o'), ('l'+'.')]); + + enum s = "abc"; + r[] = s[0..3] + "def"[0..3]; + assert(r == [('a'+'d'), ('b'+'e'), ('c'+'f')]); +} + +/************************************************************************/ +// 14851 + +void test14851() +{ + int[8] a, b, c; + + c = a[] | b[]; // OK <- NG from 2.068.0-b2 + c = a[] ^ b[]; // OK <- NG from 2.068.0-b2 + + c[] = a[] | b[]; // OK + c[] = a[] ^ b[]; // OK +} + +/************************************************************************/ + +int main() +{ + version(X86) + { + test1(); + test2(); + } + else version(X86_64) + { + test1(); + test2(); + } + else + { + pragma(msg, "arrayop.d:test1 Test skipped because arrayop evaluation" + " order is ill-defined. See GDC issue #8"); + } + test3(); + test4(); + test5(); + test6(); + test8390(); + test8651(); + test9656(); + test10282(); + test10433(); + test10684a(); + test10684b(); + test11525(); + test12250(); + test12780(); + test13497(); + test14649(); + test14851(); + + printf("Success\n"); + return 0; +} + + +version (none) +{ +extern (C) T[] _arraySliceSliceAddSliceAssignd(T[] a, T[] c, T[] b) +{ + foreach (i; 0 .. a.length) + a[i] = b[i] + c[i]; + return a; +} +} diff --git a/gcc/testsuite/gdc.test/runnable/auto1.d b/gcc/testsuite/gdc.test/runnable/auto1.d new file mode 100644 index 00000000000..e68b06380ef --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/auto1.d @@ -0,0 +1,125 @@ + +import core.stdc.stdio; + +/******************************************/ + +scope class Foo +{ + static int x; + + ~this() + { + printf("Foo.~this()\n"); + x++; + } +} + +int test1x() +{ + scope Foo f = new Foo(); + return 6; +} + + +void test1() +{ + { + scope Foo f = new Foo(); + } + int c; + + assert(Foo.x == 1); + c = test1x(); + assert(c == 6); + assert(Foo.x == 2); + + if (c != 6) + scope Foo h = new Foo(); + assert(Foo.x == 2); + + if (c == 6) + scope Foo j = new Foo(); + assert(Foo.x == 3); + + { + scope Foo g = null, k = new Foo(); + assert(Foo.x == 3); + } + assert(Foo.x == 4); +} + +/******************************************/ + +int ax; + +scope class A2 +{ + this() + { + printf("A2.this()\n"); + ax += 1; + } + + ~this() + { + printf("A2.~this()\n"); + ax += 1000; + } +}; + + +void test2() +{ + { + scope A2 a = new A2(); + printf("Hello world.\n"); + } + assert(ax == 1001); +} + + + +/******************************************/ + +int status3; + +scope class Parent3 +{ +} + +scope class Child3 : Parent3 +{ + this(){ + assert(status3==0); + status3=1; + } + + ~this(){ + assert(status3==1); + status3=2; + } +} + +void foo3() +{ + scope Parent3 o = new Child3(); + assert(status3==1); +} + +void test3() +{ + foo3(); + assert(status3==2); +} + +/******************************************/ + +int main() +{ + test1(); + test2(); + test3(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/b17073.d b/gcc/testsuite/gdc.test/runnable/b17073.d new file mode 100644 index 00000000000..82df219254d --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/b17073.d @@ -0,0 +1,13 @@ +struct S0 +{ + int x = void; +} +struct S1 +{ + S0 x = S0(42); +} +void main() +{ + S1 x; + assert(x.x.x == 42); +} diff --git a/gcc/testsuite/gdc.test/runnable/b26.d b/gcc/testsuite/gdc.test/runnable/b26.d new file mode 100644 index 00000000000..e32533b2b48 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/b26.d @@ -0,0 +1,14 @@ +// COMPILE_SEPARATELY +// EXTRA_SOURCES: imports/b26a.d +// PERMUTE_ARGS: + +// 382 + +struct List(T) { + interface A {} +} + +int main(char[][] args) { + List!(char) list; + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/bench1.d b/gcc/testsuite/gdc.test/runnable/bench1.d new file mode 100644 index 00000000000..74b24a4c6c1 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bench1.d @@ -0,0 +1,30 @@ +// REQUIRED_ARGS: +// EXECUTE_ARGS: 10000 + +extern(C) int printf(const char *, ...); +extern(C) int atoi(const char *); + + int main (string[] argv) + { + string s = ""; + int count, loop; + + count = atoi((argv[1] ~ '\0').ptr); + if (count == 0) + count = 1; + printf("count = %u\n", count); + + for (loop = 0; loop < count; loop ++) + s ~= "hello\n"; + for (loop = 0; loop < count; loop ++) + s ~= "h"; + printf ("%d\n", s.length); + //printf("%.*s\n", s[0..100]); + assert(s.length == count * (6 + 1)); + s.length = 3; + s.length = 10; + s.length = 0; + s.length = 1000; + return 0; + } + diff --git a/gcc/testsuite/gdc.test/runnable/bitops.d b/gcc/testsuite/gdc.test/runnable/bitops.d new file mode 100644 index 00000000000..eb51f0f475f --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bitops.d @@ -0,0 +1,148 @@ +// PERMUTE_ARGS: + +import core.stdc.stdio; +import core.bitop; + +/*****************************************************/ + +void test1() +{ + size_t array[2]; + uint x; +version (D_LP64) + size_t bitToUse = 67; +else + size_t bitToUse = 35; + + array[0] = 2; + array[1] = 0x100; + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + x = btc(array.ptr, bitToUse); + printf("btc(array, %d) = %d\n", bitToUse, x); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + assert(x == 0); + assert(array[0] == 0x2 && array[1] == 0x108); + + x = btc(array.ptr, bitToUse); + printf("btc(array, %d) = %d\n", bitToUse, x); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + assert(x != 0); + assert(array[0] == 2 && array[1] == 0x100); + + x = bts(array.ptr, bitToUse); + printf("bts(array, %d) = %d\n", bitToUse, x); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + assert(x == 0); + assert(array[0] == 2 && array[1] == 0x108); + + x = btr(array.ptr, bitToUse); + printf("btr(array, %d) = %d\n", bitToUse, x); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + assert(x != 0); + assert(array[0] == 2 && array[1] == 0x100); + + x = bt(array.ptr, 1); + printf("bt(array, 1) = %d\n", x); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + assert(x != 0); + assert(array[0] == 2 && array[1] == 0x100); +} + +/*****************************************************/ + +void test2() +{ + uint v; + int x; + + v = 0x21; + x = bsf(v); + printf("bsf(x%x) = %d\n", v, x); + assert(x == 0); + + x = bsr(v); + printf("bsr(x%x) = %d\n", v, x); + assert(x == 5); +} + +/*****************************************************/ + +version (DigitalMars) +void test3() +{ uint v; + int b; + + b = inp(b); + b = inpw(b); + b = inpl(b); + + b = outp(v, cast(ubyte)b); + b = outpw(v, cast(ushort)b); + b = outpl(v, b); +} + +/*****************************************************/ + +void test4() +{ + uint i = 0x12_34_56_78; + i = bswap(i); + assert(i == 0x78_56_34_12); +} + +/*****************************************************/ + +void test5() +{ + size_t array[2]; + + array[0] = 2; + array[1] = 0x100; + + printf("btc(array, 35) = %d\n", btc(array.ptr, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btc(array, 35) = %d\n", btc(array.ptr, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bts(array, 35) = %d\n", bts(array.ptr, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("btr(array, 35) = %d\n", btr(array.ptr, 35)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); + + printf("bt(array, 1) = %d\n", bt(array.ptr, 1)); + printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]); +} + + +/*****************************************************/ + +class Node { + uint leaf = 0; + + int m() { + return leaf ? 0 : bsf(leaf); + } +} + +void test6() +{ + Node n = new Node(); +} + +/*****************************************************/ + +int main() +{ + test1(); + test2(); + //test3(); + test4(); + test5(); + test6(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/bug11155.d b/gcc/testsuite/gdc.test/runnable/bug11155.d new file mode 100644 index 00000000000..afe4208ebaf --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bug11155.d @@ -0,0 +1,19 @@ +// PERMUTE_ARGS: + +version(D_SIMD) +{ + alias float4 = __vector(float[4]); + + void foo(float4* ptr, float4 val) + { + assert((cast(ulong) &val & 0xf) == 0); + } + + void main() + { + float4 v; + foo(&v, v); + } +} +else + void main(){} diff --git a/gcc/testsuite/gdc.test/runnable/bug12928.d b/gcc/testsuite/gdc.test/runnable/bug12928.d new file mode 100644 index 00000000000..92ce78eeda7 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bug12928.d @@ -0,0 +1,13 @@ +// PERMUTE_ARGS: -inline -g -O +import core.exception : RangeError; +void main(string[] args) +{ + int[2] a; + try + { + foreach(const i; 0..3) + a[i] = i; + assert(0); + } + catch(RangeError){} +} diff --git a/gcc/testsuite/gdc.test/runnable/bug16146.d b/gcc/testsuite/gdc.test/runnable/bug16146.d new file mode 100644 index 00000000000..dfe7861a6cb --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bug16146.d @@ -0,0 +1,26 @@ +struct X { + int* rc; + this (int n) { auto x = new int[](1); rc = x.ptr; *rc = n; } + this (this) { ++*rc; } + ~this () { --*rc; } + @disable void opAssign (X src); +} + +struct Y { + X x; +} + +void frob(X x) +{ + Y y = { x: x }; + // The 'rc' counter starts from 1 and gets bumped when: + // - 'f0' is passed to 'frob' + // - 'y' is initialized with 'x' + assert(*y.x.rc == 3); +} + +void main () +{ + auto f0 = X(1); + frob(f0); +} diff --git a/gcc/testsuite/gdc.test/runnable/bug5.d b/gcc/testsuite/gdc.test/runnable/bug5.d new file mode 100644 index 00000000000..cbb4dcfee40 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bug5.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -w + +class F { } + +int test1() { + scope F f = new F(); // comment out and warning goes away + return 0; +} + +int test2() { // no return at end of function + try { + return 0; + } finally { } +} + +void main() +{ + test1(); + test2(); +} diff --git a/gcc/testsuite/gdc.test/runnable/bug7068.d b/gcc/testsuite/gdc.test/runnable/bug7068.d new file mode 100644 index 00000000000..70e351e8154 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bug7068.d @@ -0,0 +1,11 @@ +// PERMUTE_ARGS: -inline -g -O -d +void main() +{ + auto darray1 = new int*[](10); + foreach(ref v; darray1) + v = new int; + auto darray2 = new int*[](10); + darray2[] = darray1[]; // calls memset instead of memcpy + foreach(i; 0 .. 10) + assert(darray1[i] == darray2[i]); +} diff --git a/gcc/testsuite/gdc.test/runnable/bug846.d b/gcc/testsuite/gdc.test/runnable/bug846.d new file mode 100644 index 00000000000..71beb8562af --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bug846.d @@ -0,0 +1,11 @@ +// see also: bug 8 +// EXTRA_SOURCES: imports/bug846.d + +import imports.bug846; + +void main() +{ + auto num = removeIf( "abcdef".dup, ( char c ) { return c == 'c'; } ); + assert(num == 5); +} + diff --git a/gcc/testsuite/gdc.test/runnable/builtin.d b/gcc/testsuite/gdc.test/runnable/builtin.d new file mode 100644 index 00000000000..205e792879d --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/builtin.d @@ -0,0 +1,118 @@ + +import std.stdio; +import std.math; +import core.bitop; + +version (DigitalMars) +{ + version (X86_64) + version = AnyX86; + else version (X86) + version = AnyX86; +} + +/*******************************************/ + +void test1() +{ + writefln("%a", sin(6.8L)); + auto f = 6.8L; + writefln("%a", sin(f)); + assert(sin(f) == sin(6.8L)); + static assert(approxEqual(sin(6.8L), 0x1.f9f8d9aea10fdf1cp-2)); + + writefln("%a", cos(6.8L)); + f = 6.8L; + writefln("%a", cos(f)); + assert(cos(f) == cos(6.8L)); + static assert(approxEqual(cos(6.8L), 0x1.bd21aaf88dcfa13ap-1)); + + writefln("%a", tan(6.8L)); + f = 6.8L; + writefln("%a", tan(f)); + version (Win64) + { } + else + assert(tan(f) == tan(6.8L)); + static assert(approxEqual(tan(6.8L), 0x1.22fd752af75cd08cp-1)); +} + +/*******************************************/ + +void test2() +{ + float i = 3; + i = i ^^ 2; + assert(i == 9); + + int j = 2; + j = j ^^ 1; + assert(j == 2); + + i = 4; + i = i ^^ .5; + assert(i == 2); +} + +/**** Bug 5703 *****************************/ + +static assert({ + int a = 0x80; + int f = bsf(a); + int r = bsr(a); + a = 0x22; + assert(bsf(a)==1); + assert(bsr(a)==5); + a = 0x8000000; + assert(bsf(a)==27); + assert(bsr(a)==27); + a = 0x13f562c0; + assert(bsf(a) == 6); + assert(bsr(a) == 28); + assert(bswap(0xAABBCCDD) == 0xDDCCBBAA); + return true; +}()); + +/*******************************************/ + +void test3() +{ + version (AnyX86) + { + static assert( _popcnt( cast(ushort)0 ) == 0 ); + static assert( _popcnt( cast(ushort)7 ) == 3 ); + static assert( _popcnt( cast(ushort)0xAA )== 4); + static assert( _popcnt( cast(ushort)0xFFFF ) == 16 ); + static assert( _popcnt( cast(ushort)0xCCCC ) == 8 ); + static assert( _popcnt( cast(ushort)0x7777 ) == 12 ); + static assert( _popcnt( cast(uint)0 ) == 0 ); + static assert( _popcnt( cast(uint)7 ) == 3 ); + static assert( _popcnt( cast(uint)0xAA )== 4); + static assert( _popcnt( cast(uint)0x8421_1248 ) == 8 ); + static assert( _popcnt( cast(uint)0xFFFF_FFFF ) == 32 ); + static assert( _popcnt( cast(uint)0xCCCC_CCCC ) == 16 ); + static assert( _popcnt( cast(uint)0x7777_7777 ) == 24 ); + version (X86_64) + { + static assert( _popcnt( cast(ulong)0 ) == 0 ); + static assert( _popcnt( cast(ulong)7 ) == 3 ); + static assert( _popcnt( cast(ulong)0xAA )== 4); + static assert( _popcnt( cast(ulong)0x8421_1248 ) == 8 ); + static assert( _popcnt( cast(ulong)0xFFFF_FFFF_FFFF_FFFF ) == 64 ); + static assert( _popcnt( cast(ulong)0xCCCC_CCCC_CCCC_CCCC ) == 32 ); + static assert( _popcnt( cast(ulong)0x7777_7777_7777_7777 ) == 48 ); + } + } +} + +/*******************************************/ + +int main() +{ + test1(); + test2(); + test3(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/c22.d b/gcc/testsuite/gdc.test/runnable/c22.d new file mode 100644 index 00000000000..8af091b4dce --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/c22.d @@ -0,0 +1,15 @@ +// EXTRA_SOURCES: imports/c22a.d imports/c22b.d +// PERMUTE_ARGS: + +module main; + +import imports.c22a; +import imports.c22b; + +int main() +{ + afn1(); + afn2(); + bfn1(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/cabi1.d b/gcc/testsuite/gdc.test/runnable/cabi1.d new file mode 100644 index 00000000000..b58e25ca5dc --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/cabi1.d @@ -0,0 +1,262 @@ + +// EXTRA_CPP_SOURCES: extra-files/cabi2.cpp + +import core.stdc.stdio; +import core.stdc.config; + +struct Foo1 { char c; } +struct Foo2 { short s; } +struct Foo3 { char c; short s; } +struct Foo4 { int i; } +struct Foo5 { int i, j; } +struct Foo6 { int i, j, k; } +struct S7 { float a, b; } + +extern (C) Foo1 ctest1(); +extern (C) Foo2 ctest2(); +extern (C) Foo3 ctest3(); +extern (C) Foo4 ctest4(); +extern (C) Foo5 ctest5(); +extern (C) Foo6 ctest6(); +extern (C) S7 ctest10(); + +version(Windows) + version = Windows_or_32bit; +else version(X86) + version = Windows_or_32bit; + + +void test1() +{ + Foo1 f1 = ctest1(); + assert(f1.c == 3); + + Foo2 f2 = ctest2(); + assert(f2.s == 0x1234); + + Foo3 f3 = ctest3(); + assert(f3.s == 0x5678); + + Foo4 f4 = ctest4(); + assert(f4.i == 0x12345678); + + Foo5 f5 = ctest5(); + assert(f5.i == 0x12345678); + assert(f5.j == 0x21436587); + +version(Windows_or_32bit) +{ + Foo6 f6 = ctest6(); + assert(f6.i == 0x12345678); + assert(f6.j == 0x21463587); + assert(f6.k == 0x24163857); +} + + S7 s7 = ctest10(); + assert(s7.a == 2.5); + assert(s7.b == 1.5); +} + +/*******************************************/ + +extern (C) +{ + char ctest7(char); + ubyte ctest8(ubyte); + byte ctest9(byte); +} + +void test2() +{ + assert(ctest7('a') == 'b'); + assert(ctest8(7) == 8); + assert(ctest9(3) == 4); +} + +/******************************************/ + +extern (C) +{ + void ctestrir(int x1, int x2, int x3, int x4, int x5, int x6, c_long_double a, int b, c_long_double c); +} + +void test3() +{ + ctestrir(1,2,3,4,5,6, c_long_double(100.0), 67, c_long_double(200.0)); +} + +/******************************************/ + +extern (C) void dtestrir(int x1, int x2, int x3, int x4, int x5, int x6, c_long_double a, int b, c_long_double c) +{ + assert(a == 300.0); + assert(b == 68); + assert(c == 401.0); +} + +extern (C) void test4(); + +/******************************************/ + +struct S11 { ubyte a, b, c; } + +extern (C) S11 ctest11(ubyte x, S11, ubyte y); + +void test11() +{ + version (X86) + { + S11 t; + assert(S11.sizeof == 3); + t.a = 2; + t.b = 3; + t.c = 4; + auto s = ctest11(1, t, 5); + assert(s.a == 2); + assert(s.b == 3); + assert(s.c == 4); + } +} + +/******************************************/ + +struct S12 { char a,d; char b,e; ubyte c; } + +extern (C) S12 ctest12(ubyte x, S12, ubyte y); + +void test12() +{ + version (X86) + { + S12 t; + printf("D sz = %d\n", cast(int)S12.sizeof); +// assert(S12.sizeof == 5); + t.a = 2; + t.b = 3; + t.c = 4; + auto s = ctest12(1, t, 5); + assert(s.a == 2); + assert(s.b == 3); + assert(s.c == 4); + } +} + +/******************************************/ + +struct S13 { ushort a, b, c; } + +extern (C) S13 ctest13(ubyte x, S13, ubyte y); + +void test13() +{ + version (X86) + { + S13 t; + assert(S13.sizeof == 6); + t.a = 2; + t.b = 3; + t.c = 4; + auto s = ctest13(1, t, 5); + assert(s.a == 2); + assert(s.b == 3); + assert(s.c == 4); + } +} + +/******************************************/ + +struct S14 { char a,d,e,f; char b,g; ubyte c; } + +extern (C) S14 ctest14(ubyte x, S14, ubyte y); + +void test14() +{ + version (X86) + { + S14 t; + assert(S14.sizeof == 7); + t.a = 2; + t.b = 3; + t.c = 4; + auto s = ctest14(1, t, 5); + assert(s.a == 2); + assert(s.b == 3); + assert(s.c == 4); + } +} + +/******************************************/ + +struct S15 { char a,d,e,f; char b,g,h,i; ubyte c; } + +extern (C) S15 ctest15(ubyte x, S15, ubyte y); + +void test15() +{ + version (X86) + { + S15 t; + assert(S15.sizeof == 9); + t.a = 2; + t.b = 3; + t.c = 4; + auto s = ctest15(1, t, 5); + assert(s.a == 2); + assert(s.b == 3); + assert(s.c == 4); + } +} + +/******************************************/ + +// see https://issues.dlang.org/show_bug.cgi?id=17277 +struct S16 { + char[5] a; + struct { + char b; + align(1) int c; + } +} + +extern (C) S16 ctest16(ubyte x, S16, ubyte y); + +void test16() +{ + version (X86) // misaligned field + { + S16 t; + assert(S16.sizeof == 10); + assert(S16.alignof == 1); + t.a = "hello"; + t.b = 3; + t.c = 0x11223344; + auto s = ctest16(1, t, 5); + assert(s.a == "hello"); + assert(s.b == 3); + assert(s.c == 0x11223344); + } +} + +/******************************************/ + +int main() +{ + test1(); + test2(); + test3(); +version (Win64) +{ +} +else +{ + test4(); +} + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); + + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/cassert.d b/gcc/testsuite/gdc.test/runnable/cassert.d new file mode 100644 index 00000000000..8c767508495 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/cassert.d @@ -0,0 +1,17 @@ +/* REQUIRED_ARGS: -betterC + PERMUTE_ARGS: + */ + + +void test(int ij) +{ + assert(ij); +#line 100 "anotherfile" + assert(ij,"it is not zero"); +} + +extern (C) int main() +{ + test(1); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/casting.d b/gcc/testsuite/gdc.test/runnable/casting.d new file mode 100644 index 00000000000..233cc94f634 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/casting.d @@ -0,0 +1,248 @@ +extern(C) int printf(const char*, ...); + +template Seq(T...) { alias T Seq; } + +/***************************************************/ +// 3133 + +void test3133() +{ + short[2] x = [1, 2]; + auto y = cast(int[1])x; // no error +} + +/***************************************************/ +// 7504 + +void test7504() pure nothrow @safe +{ + auto n = null; + char[] k = n; + assert(k.ptr == null); + assert(k.length == 0); + + double[] l; + l = n; + assert(l.ptr == null); + assert(l.length == 0); + + immutable(int[]) m = n; + assert(m.ptr == null); + assert(m.length == 0); + + const(float)[] o; + o = n; + assert(o.ptr == null); + assert(o.length == 0); + + auto c = create7504(null, null); + assert(c.k.ptr == null); + assert(c.k.length == 0); + assert(c.l.ptr == null); + assert(c.l.length == 0); +} + +class C7504 +{ + int[] k; + string l; +} + +C7504 create7504(T...)(T input) +{ + auto obj = new C7504; + obj.tupleof = input; + return obj; +} + +/***************************************************/ +// 8119 + +struct S8119; + +void test8119() +{ + void* v; + auto sp1 = cast(S8119*)v; + + int* i; + auto sp2 = cast(S8119*)i; + + S8119* s; + auto ip = cast(int*)s; +} + +/***************************************************/ +// 8645 + +template TypeTuple8645(TL...) +{ + alias TL TypeTuple8645; +} + +void test8645() +{ + alias TypeTuple8645!(int) Foo; + int bar; + static assert(!is(typeof( cast(Foo)bar ))); +} + +/***************************************************/ +// 10497 + +struct S10497; + +void test10497(S10497** s) +{ + void* ptr; + *s = cast(S10497*)ptr; +} + +/***************************************************/ +// 10793 + +struct RealFoo10793 +{ + int i; +} + +struct Foo10793; + +void test10793() +{ + auto rf = RealFoo10793(10); + void* prf = cast(void*)&rf; + Foo10793* f = cast(Foo10793*)prf; +} + +/***************************************************/ +// 10834 + +void test10834() +{ + struct S { int i; } + S s; + cast(void)s; + + class C { int i; } + C c; + cast(void)c; + + enum E { a, b } + E e; + cast(void)e; + + int[] ia; + cast(void)ia; +} + +/***************************************************/ +// 10842 + +template Test10842(F, T) +{ + bool res; + F from() + { + res = true; + return F.init; + } + T to() + { + // The cast operand had incorrectly been eliminated + return cast(T)from(); + } + bool test() + { + res = false; + to(); + return res; + } +} + +void test10842() +{ + foreach (From; Seq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) + { + foreach (To; Seq!(ifloat, idouble, ireal)) + { + if (!Test10842!(From, To).test()) + assert(0); + } + } + + foreach (From; Seq!(ifloat, idouble, ireal)) + { + foreach (To; Seq!(/*bool*, */byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) + { + if (!Test10842!(From, To).test()) + assert(0); + } + } + + if (!Test10842!(typeof(null), string).test()) // 10842 + assert(0); +} + +/***************************************************/ +// 11722 + +class C11722 +{ + T opCast(T)() { assert(0); } +} + +void test11722() +{ + C11722 c = new C11722(); + shared C11722 sc = cast(shared)c; +} + +/***************************************************/ +// 14218 + +void test14218() +{ + foreach (To; Seq!( byte, short, int, long, + ubyte, ushort, uint, ulong, + char, wchar, dchar, bool)) + { + auto x = cast(To)null; + assert(x == 0); // false, '0x00' + } + + version (DigitalMars) + { + // Questionable but currently accepted by DMD (but not GDC). + foreach (To; Seq!( float, double, real, + ifloat, idouble, ireal)) + { + auto x = cast(To)null; + assert(x == 0); // 0i + } + + // Internal error: backend/el.c in el_long() + //foreach (To; Seq!(cfloat, cdouble, creal)) + //{ + // static assert(!__traits(compiles, { auto x = cast(To)null; })); + //} + } +} + +/***************************************************/ + +int main() +{ + test3133(); + test7504(); + test8119(); + test8645(); + test10793(); + test10834(); + test10842(); + test11722(); + test14218(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/circular.d b/gcc/testsuite/gdc.test/runnable/circular.d new file mode 100644 index 00000000000..8fdc8aa7d49 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/circular.d @@ -0,0 +1,25 @@ +// REQUIRED_ARGS: -d +// PERMUTE_ARGS: -dw +// EXTRA_SOURCES: imports/circularA.d +// This bug is typedef-specific. + +// Bugzilla 4543 + +import core.stdc.stdio; +import imports.circularA; + +class bclass {}; +alias bclass Tclass; + +struct bstruct {} +alias bstruct Tstruct; + + +/************************************/ + +int main() +{ + printf("Success\n"); + return 0; +} + diff --git a/gcc/testsuite/gdc.test/runnable/closure.d b/gcc/testsuite/gdc.test/runnable/closure.d new file mode 100644 index 00000000000..1ed10e2c031 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/closure.d @@ -0,0 +1,988 @@ + +import core.stdc.stdio; + +struct S { int a,b,c,d; } + +alias int delegate() dg_t; +alias int delegate(int) dg1_t; + +void fill() +{ + int[100] x; +} + +/************************************/ + +dg_t foo() +{ + int x = 7; + + int bar() + { + return x + 3; + } + + return &bar; +} + +void test1() +{ + dg_t dg = foo(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +dg_t foo2() +{ + dg_t abc() + { + int x = 7; + + int bar() + { + return x + 3; + } + + return &bar; + } + + return abc(); +} + +void test2() +{ + dg_t dg = foo2(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +dg_t foo3() +{ + dg_t abc(int x) + { + int bar() + { + return x + 3; + } + + return &bar; + } + + return abc(7); +} + +void test3() +{ + dg_t dg = foo3(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +dg_t foo4() +{ + S s; + + s = S(4,5,6,7); + + dg_t abc(S t) + { + int bar() + { + return t.d + 3; + } + + return &bar; + } + + return abc(s); +} + +void test4() +{ + dg_t dg = foo4(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +void test5() +{ + int x = 7; + + dg_t abc(ref int y) + { + int bar() + { + y += 4; + return y + 3; + } + + return &bar; + } + + dg_t dg = abc(x); + fill(); + assert(x == 7); + auto i = dg(); + assert(x == 11); + assert(i == 14); + + x = 8; + i = dg(); + assert(x == 12); + assert(i == 15); +} + +/************************************/ + +void test6() +{ + int x = 7; + + dg_t abc(out int y) + { + int bar() + { + y += 4; + return y + 3; + } + + return &bar; + } + + dg_t dg = abc(x); + fill(); + + assert(x == 0); + auto i = dg(); + assert(x == 4); + assert(i == 7); + + x = 8; + i = dg(); + assert(x == 12); + assert(i == 15); +} + +/************************************/ + +void test7() +{ + int[3] a = [10,11,12]; + + dg_t abc(int[3] y) + { + int bar() + { + y[2] += 4; + return y[2] + 3; + } + + return &bar; + } + + dg_t dg = abc(a); + fill(); + + assert(a[2] == 12); + auto i = dg(); + assert(a[2] == 12); + assert(i == 19); +} + +/************************************/ + +void test8() +{ + S s = S(7,8,9,10); + + dg_t abc(ref S t) + { + int bar() + { + t.d += 4; + return t.c + 3; + } + + return &bar; + } + + dg_t dg = abc(s); + fill(); + + assert(s.d == 10); + auto i = dg(); + assert(s.d == 14); + assert(i == 12); +} + +/************************************/ + +S foo9(out dg_t dg) +{ + S s1 = S(7,8,9,10); + + dg_t abc() + { + int bar() + { + s1.d += 4; + return s1.c + 3; + } + + return &bar; + } + + dg = abc(); + return s1; +} + +void test9() +{ + dg_t dg; + + S s = foo9(dg); + fill(); + assert(s.a == 7); + assert(s.b == 8); + assert(s.c == 9); + assert(s.d == 10); + + auto i = dg(); + assert(s.d == 10); + assert(i == 12); +} + +/************************************/ + +dg_t foo10() +{ + dg_t abc() + { + int x = 7; + + int bar() + { + int def() + { + return x + 3; + } + return def(); + } + + return &bar; + } + + return abc(); +} + +void test10() +{ + dg_t dg = foo10(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + + +/************************************/ + +dg_t foo11() +{ + int x = 7; + + class T + { + int bar() + { + return x + 3; + } + } + + T t = new T; + + return &t.bar; +} + +void test11() +{ + dg_t dg = foo11(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +dg_t foo12() +{ + int x = 7; + + class T + { + int bar() + { + return x + 3; + } + + int xyz() + { + return bar(); + } + } + + T t = new T; + + return &t.xyz; +} + +void test12() +{ + dg_t dg = foo12(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +dg_t foo13() +{ + int x = 7; + + class T + { + int xyz() + { + int bar() + { + return x + 3; + } + + return bar(); + } + } + + T t = new T; + + return &t.xyz; +} + +void test13() +{ + dg_t dg = foo13(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + + +/************************************/ + +dg_t foo14() +{ + class T + { + int xyz() + { + int x = 7; + + int bar() + { + return x + 3; + } + + return bar(); + } + } + + T t = new T; + + return &t.xyz; +} + +void test14() +{ + dg_t dg = foo14(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +dg_t foo15() +{ + class T + { + int x = 7; + + int xyz() + { + int bar() + { + return x + 3; + } + + return bar(); + } + } + + T t = new T; + + return &t.xyz; +} + +void test15() +{ + dg_t dg = foo15(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 10); +} + +/************************************/ + +dg_t foo16() +{ + int a = 5; + + class T + { + int x = 7; + + int xyz() + { + int y = 8; + int bar() + { + return a + x + y + 3; + } + + return bar(); + } + } + + T t = new T; + + return &t.xyz; +} + +void test16() +{ + dg_t dg = foo16(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 23); +} + +/************************************/ + +dg_t foo17() +{ + int a = 5; + + class T + { + int x = 7; + + dg_t xyz() + { + int y = 8; + + int bar() + { + return a + x + y + 3; + } + + return &bar; + } + } + + T t = new T; + + return t.xyz(); +} + +void test17() +{ + dg_t dg = foo17(); + fill(); + printf("bar = %d\n", dg()); + assert(dg() == 23); +} + +/************************************/ + +dg_t dg18; + +void bar18() +{ + int a = 7; + int foo() { return a + 3; } + + dg18 = &foo; + int i = dg18(); + assert(i == 10); +} + +void test18() +{ + bar18(); + fill(); + int i = dg18(); + assert(i == 10); +} + +/************************************/ + +void abc19(void delegate() dg) +{ + dg(); + dg(); + dg(); +} + +struct S19 +{ + static S19 call(int v) + { + S19 result; + + result.v = v; + void nest() + { + result.v += 1; + } + abc19(&nest); + return result; + } + int a; + int v; + int x,y,z; +} + +int foo19() +{ + auto s = S19.call(5); + return s.v; +} + +void test19() +{ + int i = foo19(); + printf("%d\n", i); + assert(i == 8); +} + +/************************************/ + +void enforce20(lazy int msg) +{ +} + + +void test20() +{ + int x; + foreach (j; 0 .. 10) + { + printf("%d\n", j); + assert(j == x); + x++; + enforce20(j); + } +} + +/************************************/ + +void thrash21() { char[128] x = '\xfe'; } + +void delegate() dg21; +int g_input = 11, g_output; + +void f21() +{ + int i = g_input + 2; + + class X + { + // both 'private' and 'final' to make non-virtual + private final void actual() + { + g_output = i; + } + + void go() + { + actual(); + } + } + + dg21 = & (new X).go; +} + +void test21() +{ + f21(); + thrash21(); + dg21(); + assert(g_output == 13); +} + +/************************************/ + +void thrash22() { char[128] x = '\xfe'; } +int gi22; +void delegate() dg22; + +class A22 +{ + int x = 42; + + void am() + { + int j; /* Making f access this variable causes f's chain to be am's + frame. Otherwise, f's chain would be the A instance. */ + void f() + { + int k = j; + + void g() + { + class B + { + void bm() + { + gi22 = x; /* No checkedNestedReference for A.am.this, + so it is never placed in a closure. */ + } + } + + (new B).bm(); + } + + dg22 = &g; + } + + f(); + } +} + +void test22() +{ + (new A22).am(); + thrash22(); + dg22(); + assert(gi22 == 42); +} + +/************************************/ +// 1759 + +void test1759() +{ + struct S { int a, b, c; } + struct SS { S obj; } + + static int delegate() makeSum1(S s) + { + with (s) return { return a + b + c; }; + } + static int delegate() makeSum2(S[1] sa) + { + with (sa[0]) return { return a + b + c; }; + } + static int delegate() makeSum3(SS ss) + { + with (ss.obj) return { return a + b + c; }; + } + static int delegate() makeSum4(SS[1] ssa) + { + with (ssa[0].obj) return { return a + b + c; }; + } + + S s = {15, 30, 45}; + SS ss = {s}; + int delegate() sum; + + sum = makeSum1(s); assert(sum() == 90); + sum = makeSum2([s]); assert(sum() == 90); + sum = makeSum3(ss); assert(sum() == 90); + sum = makeSum4([ss]); assert(sum() == 90); +} + +/************************************/ +// 1841 + +int delegate() foo1841() +{ + int stack; + int heap = 3; + + int nested_func() + { + ++heap; + return heap; + } + return delegate int() { return nested_func(); }; +} + +int delegate() foo1841b() +{ + int stack; + int heap = 7; + + int nested_func() + { + ++heap; + return heap; + } + int more_nested() { return nested_func(); } + return delegate int() { return more_nested(); }; +} + +void test1841() +{ + auto z = foo1841(); + auto p = foo1841(); + assert(z() == 4); + p(); + assert(z() == 5); + z = foo1841b(); + p = foo1841b(); + assert(z() == 8); + p(); + assert(z() == 9); +} + +/************************************/ +// 5911 + +void writeln5911(const(char)[] str) {} + +void logout5911(lazy const(char)[] msg) { writeln5911(msg); } + +void test5911() +{ + string str = "hello world"; + logout5911((){ return str; }()); // closure 1 + + try + { + throw new Exception("exception!!"); + } + catch (Exception e) + { + assert(e !is null); + logout5911(e.toString()); // closure2 SEGV : e is null. + } +} + +/************************************/ +// 9685 + +auto get9685a(alias fun)() +{ + int x = 10; + struct Foo + { + size_t data; + + @property clone() + { + return Foo(15); + } + } + return Foo(5); +} +void test9685a() +{ + uint a = 42; + auto bar = get9685a!(() => a)(); + auto qux = bar.clone; + //printf("bar context pointer : %p\n", bar.tupleof[$-1]); + //printf("qux context pointer : %p\n", qux.tupleof[$-1]); + assert(bar.tupleof[$-1] == qux.tupleof[$-1]); + assert(qux.data == 15); +} + +auto get9685b(alias fun)() +{ + int x = 10; + struct Foo + { + size_t data; + + @property clone() + { + return Foo(data + x); + } + } + return Foo(5); +} +void test9685b() +{ + uint a = 42; + auto bar = get9685b!(() => a)(); + auto qux = bar.clone; + //printf("bar context pointer : %p\n", bar.tupleof[$-1]); + //printf("qux context pointer : %p\n", qux.tupleof[$-1]); + assert(bar.tupleof[$-1] == qux.tupleof[$-1]); + assert(qux.data == 15); +} + +/************************************/ +// 12406 + +auto createDg12406() +{ + static struct Dg + { + Dg delegate() action; + } + + static void fn(void delegate()) { } + + int x; fn({ x++; }); // required + + Dg dg; + + Dg createDg2() + { + int x; void unusedFun() { x++; } // required + + return Dg(() => dg); // lambda returns garbage instead of dg + } + + return dg = Dg(&createDg2); +} + +void test12406() +{ + auto dgs = [createDg12406()]; + //printf("dgs[%2d].action = %p:%p\n", 0, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); + foreach (i; 1 .. 10+1) + { + dgs ~= dgs[i-1].action(); + //printf("dgs[%2d].action = %p:%p\n", i, dgs[$-1].action.ptr, dgs[$-1].action.funcptr); + } + + foreach (i, dgx; dgs) + { + if (i % 2 == 0) + { + // All closures are equal with dgs[0]. + assert(dgx.action.ptr is dgs[0].action.ptr); + assert(dgx.action.funcptr is dgs[0].action.funcptr); // is: createDg2 + } + else + { + // Each closures has unique context. + for (size_t j = i + 2; j < dgs.length; j += 2) + assert(dgx.action.ptr !is dgs[j].action.ptr); + assert(dgx.action.funcptr is dgs[1].action.funcptr); // is: lambda () => dg + } + } +} + +/************************************/ +// 14730 + +void test14730() +{ + static auto makeS(int x) + { + struct S + { + int n; + int get() { return x; } // x will be a closure variable + } + return S(x); + } + auto s = makeS(1); + assert(s.get() == 1); + // By inlining get() function call, it's rewritten to: + // assert(*(s.tupleof[$-1] + x.offset) == 1); + // --> In DotVarExp::toElem(), x->offset should be already nonzero. +} + +// ---- + +// This is questionable case. Currently it works without any errors, +// but not sure it's really intentional + +struct S14730x(alias f) +{ + auto foo()() { return f(0); } + + void dummy() {} +} + +auto makeS14730x() //@nogc +{ + int x = 10; + S14730x!(a => x) s; + //assert(s.foo() == 10); + return s; +} + +void test14730x() +{ + auto s = makeS14730x(); + assert(s.tupleof[$-1] !is null); + + // instantiationg foo outside of makeS will place the variable x in closure + // *after* the semantic3 completion of makeS() function. + assert(s.foo() == 10); +} + +/************************************/ + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); + test17(); + test18(); + test19(); + test20(); + test21(); + test22(); + test1759(); + test1841(); + test5911(); + test9685a(); + test9685b(); + test12406(); + test14730(); + test14730x(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/complex.d b/gcc/testsuite/gdc.test/runnable/complex.d new file mode 100644 index 00000000000..e9c79cb7d21 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/complex.d @@ -0,0 +1,462 @@ +// PERMUTE_ARGS: + +import std.stdio; +import std.math; +import core.stdc.stdio; + +/***************************************/ + +void test1() +{ + creal c = 3.0 + 4.0i; + c = sqrt(c); + printf("re = %Lg, im = %Lg\n", c.re, c.im); + assert(c.re == 2.0); + assert(c.im == 1.0); + + float f = sqrt(25.0f); + assert(f == 5.0); + double d = sqrt(4.0); + assert(d == 2.0); + real r = sqrt(9.0L); + assert(r == 3.0); +} + +/***************************************/ + +ireal f2() { return 1i; } + +void test2() +{ + creal v = 0+0i; + + v += f2(); + assert(v == 0 + 1i); + + v = v + f2(); + assert(v == 0 + 2i); +} + +/***************************************/ + +cdouble[1] a3; +cdouble[1] b3; + +cdouble[] concat3() { + return a3~b3; +} + +void test3() +{ + a3[]=0.5+1.0i; + b3[]=0.5+3.0i; + + cdouble[] arr=concat3(); + + assert(arr.length==2); + assert(arr[0]==0.5+1.0i); + assert(arr[1]==0.5+3.0i); +} + +/***************************************/ + +creal[1] a4; +creal[1] b4; + +creal[] concat4() { + return a4~b4; +} + +void test4() +{ + a4[]=0.5+1.0i; + b4[]=0.5+3.0i; + + creal[] arr=concat4(); + + assert(arr.length==2); + assert(arr[0]==0.5+1.0i); + assert(arr[1]==0.5+3.0i); +} + +/***************************************/ + +void test5() +{ + ifloat i=1.0fi; +// i += 2.2; +// assert(i == 1i); +} + +/***************************************/ + +void test6() +{ + float i=1.0f; +// i /= 2.2fi; +// assert(i == 0); +} + +/***************************************/ + +void test7() +{ + creal x=1.0i+2.0; + creal[] arr; + + arr = arr ~ x; + assert(arr.length==1); + assert(arr[0]==1.0i+2.0); + + x=0.0i+5.0; + assert(arr[0]==1.0i+2.0); +} + +/****************************************/ + +creal[1] a8; +creal[1] b8; + +creal[] concat8() { + return a8 ~ b8; +} + +void test8() +{ + a8[]=0.5L+1.0Li; + b8[]=0.5L+3.0Li; + + creal[] arr=concat8(); + + assert(arr.length==2); + assert(arr[0]==0.5L+1.0Li); + assert(arr[1]==0.5L+3.0Li); +} + +/***************************************/ + +creal[1] a9; +creal[1] b9; + +creal[] concat9() { + return a9~b9; +} + +void test9() +{ + a9[]=0.5L+1.0Li; + b9[]=0.5L+3.0Li; + + creal[] arr=concat9(); + + assert(arr.length==2); + assert(arr[0]==0.5L+1.0Li); + assert(arr[1]==0.5L+3.0Li); +} + + +/***************************************/ + +void test10() +{ + ifloat a = 1.0i; + assert(a.im == 1.0); + + const ifloat b = 2.0i; + static assert(b.im == 2.0); // FAIL + +} + +/***************************************/ + +void test11() +{ + real r = real.nan; + assert( r!=0 ); + if (r==0) assert(0); + + ireal ir = ireal.nan; + assert( ir!=0 ); + assert( ir!=0i ); + if (ir==0) assert(0); + if (ir==0i) assert(0); + + creal cr = creal.nan; + assert( cr!=0 ); + assert( cr!=0i ); + if (cr==0) assert(0); + if (cr==0i) assert(0); + + double d = double.nan; + assert( d!=0 ); + if (d==0) assert(0); + + idouble id = idouble.nan; + assert( id!=0 ); + assert( id!=0i ); + if (id==0) assert(0); + if (id==0i) assert(0); + + cdouble cd = cdouble.nan; + assert( cd!=0 ); + assert( cd!=0i ); + if (cd==0) assert(0); + if (cd==0i) assert(0); + + float f = float.nan; + assert( f!=0 ); + if (f==0) assert(0); + + ifloat ifx = ifloat.nan; + assert( ifx!=0 ); + assert( ifx!=0i ); + if (ifx==0) assert(0); + if (ifx==0i) assert(0); + + cfloat cf = cfloat.nan; + assert( cf!=0 ); + assert( cf!=0i ); + if (cf==0) assert(0); + if (cf==0i) assert(0); +} + +/***************************************/ + +void test12() +{ + real x = 3; + creal a = (2 + 4i) % 3; + writeln(a); + assert(a == 2 + 1i); + + creal b = (2 + 4i) % x; + writeln(b); + assert(b == a); +} + +/***************************************/ + +void test13() +{ + ireal a = 5i; + ireal b = a % 2; + writeln(b); + assert(b == 1i); +} + +/***************************************/ + +cdouble inv( cdouble expr ) +{ + return (1.0 + 0.0i) / expr; +} + +/***************************************/ + +void test14() +{ + cfloat c; + cfloat d; + assert(c != d); + + cdouble e; + cdouble f; + assert(e != f); + + creal g; + creal h; + assert(g != h); +} + +/***************************************/ + +void test7581() +{ + cfloat a() { return cfloat.nan; } + assert(a() != 0); +} + +/***************************************/ + +float f() { return 1.0f; } +ifloat i() { return 1.0fi; } + +void test7594() +{ + assert(f() + i() == 1.0f + 1.0fi); +} + +/***************************************/ + +cdouble conv(cfloat a) +{ + return a; +} + +void test7593() +{ + assert(conv(1.0f+1.0fi) == 1.0+1.0i); +} + +/***************************************/ + +cfloat get() { return cfloat.nan; } + +void test7591() +{ + assert(!(get() == 0)); +} + +/***************************************/ + +void foo8966(cfloat x) +{ + assert(x.re == 3.0f); +} + +__gshared cfloat[] a8966; + +void test8966() +{ + a8966 = new cfloat[2]; + a8966[0] = 3.0f + 1.0fi; + foo8966(a8966[0]); +} + +/***************************************/ + +void formatTest2(cfloat s, double re, double im) +{ + assert(s.re == re); + assert(s.im == im); +} + +cfloat getcf() +{ + return 2 + 1i; +} + +void test10677() +{ + formatTest2( getcf(), 2, 1 ); +} + +/***************************************/ + +void test7806() +{ + for (idouble i = -2i; i <= 2i; i += .125i) + for (double r = -2; r <= 2; r += .0625) + { + cdouble c = r + i; + printf("%g %gi\n", c.re, c.im); + } +} + +/***************************************/ + +void test7976() { + creal[] a = new creal[2]; + auto b = a[0] = a[1]; +} + +/***************************************/ + +cfloat foo15f(ifloat re, float im) +{ + return re + im; +} + +cfloat bar15f(float re, ifloat im) +{ + return re + im; +} + +cdouble foo15(idouble re, double im) +{ + return re + im; +} + +cdouble bar15(double re, idouble im) +{ + return re + im; +} + +creal foo15r(ireal re, real im) +{ + return re + im; +} + +creal bar15r(real re, ireal im) +{ + return re + im; +} + +void test15() +{ + assert(foo15f(1.0fi, 2.0f) == 2.0f + 1.0fi); + assert(bar15f(1.0f, 2.0fi) == 1.0f + 2.0fi); + + assert(foo15(1.0i, 2.0) == 2.0 + 1.0i); + assert(bar15(1.0, 2.0i) == 1.0 + 2.0i); + + assert(foo15r(1.0Li, 2.0L) == 2.0L + 1.0Li); + assert(bar15r(1.0L, 2.0Li) == 1.0L + 2.0Li); +} + +/***************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17087 + +cfloat toComplex(int x) { return cast(cfloat)x; } + +void test17087() +{ + assert (toComplex(1) == 1.0); +} + +/***************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17677 + +void test17677() +{ + cfloat v2 = 0.0f + 0.0fi; + ulong v1 = 1; + auto z = v2 + v1; + assert(z == 1.0f); +} + +/***************************************/ + +int main(char[][] args) +{ + + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); + test14(); + test7581(); + test7594(); + test7593(); + test7591(); + test8966(); + test10677(); + test7806(); + test7976(); + test15(); + test17087(); + test17677(); + + printf("Success!\n"); + return 0; +} + diff --git a/gcc/testsuite/gdc.test/runnable/constfold.d b/gcc/testsuite/gdc.test/runnable/constfold.d new file mode 100644 index 00000000000..57da8b75ba2 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/constfold.d @@ -0,0 +1,674 @@ +#! blah + +static assert(__LINE__ == 3); // fails as __LINE__ is 2 + +import std.stdio; +import std.math : signbit, sqrt; + + +/************************************/ + +static assert(-(1) == -1); +static assert(-(6i) == -6i); +static assert(-(1 + 6i) == -1 - 6i); + +static assert(!27 == 0); +static assert(!0 == 1); +static assert(!6.2 == 0); +static assert(!0.0 == 1); +static assert(!3.7i == 0); +static assert(!0.0i == 1); +static assert(!(2+3.7i) == 0); +static assert(!(0+3.7i) == 0); +static assert(!(2+0.0i) == 0); +static assert(!(0+0.0i) == 1); + +static assert(-6i + 2i == -4i); +static assert(6i - 1i == 5i); + +static assert((3.6 + 7.2i) / (1 + 0i) == 3.6 + 7.2i); +static assert((3.6 + 7.2i) / (0.0 + 1i) == 7.2 - 3.6i); + +static assert((6 % 4) == 2); +static assert((6u % 4u) == 2u); + +static assert((cast(byte)0x109 >> 1) == 4); +static assert((cast(byte)-1 >> 1) == -1); +static assert((cast(ubyte)0x109 >> 1) == 4); + +static assert((cast(short)0x10009 >> 1) == 4); +static assert((cast(short)-1 >> 1) == -1); +static assert((cast(ushort)0x10009 >> 1) == 4); + +static assert((cast(long)0x1_0000_0000_0009 >> 1) == 0x8000_0000_0004); +static assert((cast(long)-1L >> 1) == -1); +static assert((cast(ulong)0x10009 >> 1) == 0x8004); + +static assert((cast(byte)0x109 >>> 1) == 4); +static assert((cast(byte)-1 >>> 1) == int.max); +static assert((cast(ubyte)0x109 >>> 1) == 4); + +static assert((cast(short)0x10009 >>> 1) == 4); +static assert((cast(short)-1 >>> 1) == int.max); +static assert((cast(ushort)0x10009 >>> 1) == 4); + +static assert((cast(long)0x1_0000_0000_0009 >>> 1) == 0x8000_0000_0004); +static assert((cast(long)-1L >>> 1) == long.max); +static assert((cast(ulong)0x10009 >>> 1) == 0x8004); + +static assert((3 ^ 5) == 6); + +static assert((0 && 0) == 0); +static assert((0 && 5) == 0); +static assert((10 && 0) == 0); +static assert((58 && 10000) == 1); + +static assert((0.0 && 0.0) == 0); +static assert((0.0 && 5.1) == 0); +static assert((10.0 && 0.0) == 0); +static assert((58.6 && 10000.7) == 1); + +static assert((0 || 0) == 0); +static assert((0 || 5) == 1); +static assert((10 || 0) == 1); +static assert((58 || 10000) == 1); + +static assert((0.0 || 0.0) == 0); +static assert((0.0 || 5.1) == 1); +static assert((10.0 || 0.0) == 1); +static assert((58.6 || 10000.7) == 1); + +static assert((5 < 3) == 0); +static assert((5 < 5) == 0); +static assert((5 < 6) == 1); +static assert((5 <= 3) == 0); +static assert((5 <= 5) == 1); +static assert((5 <= 6) == 1); +static assert((5 > 3) == 1); +static assert((5 > 5) == 0); +static assert((5 > 6) == 0); +static assert((5 >= 3) == 1); +static assert((5 >= 5) == 1); +static assert((5 >= 6) == 0); + +static assert((-5 < -3) == 1); +static assert((-5 < -5) == 0); +static assert((-5 < -6) == 0); +static assert((-5 <= -3) == 1); +static assert((-5 <= -5) == 1); +static assert((-5 <= -6) == 0); +static assert((-5 > -3) == 0); +static assert((-5 > -5) == 0); +static assert((-5 > -6) == 1); +static assert((-5 >= -3) == 0); +static assert((-5 >= -5) == 1); +static assert((-5 >= -6) == 1); + +static assert((5u < 3u) == 0); +static assert((5u < 5u) == 0); +static assert((5u < 6u) == 1); +static assert((5u <= 3u) == 0); +static assert((5u <= 5u) == 1); +static assert((5u <= 6u) == 1); +static assert((5u > 3u) == 1); +static assert((5u > 5u) == 0); +static assert((5u > 6u) == 0); +static assert((5u >= 3u) == 1); +static assert((5u >= 5u) == 1); +static assert((5u >= 6u) == 0); + +static assert((-5u < 3) == 0); +static assert((-5u <= 3) == 0); +static assert((-5u > 3) == 1); +static assert((-5u >= 3) == 1); + +static assert((-5 < 3u) == 0); +static assert((-5 <= 3u) == 0); +static assert((-5 > 3u) == 1); +static assert((-5 >= 3u) == 1); + +static assert((5.2 < double.nan) == 0); +static assert((5.2 <= double.nan) == 0); +static assert((5.2 > double.nan) == 0); +static assert((5.2 >= double.nan) == 0); + +static assert((double.nan < 6.2) == 0); +static assert((double.nan <= 6.2) == 0); +static assert((double.nan > 6.2) == 0); +static assert((double.nan >= 6.2) == 0); + +static assert((double.nan < double.nan) == 0); +static assert((double.nan <= double.nan) == 0); +static assert((double.nan > double.nan) == 0); +static assert((double.nan >= double.nan) == 0); + +static assert((5.2 < 6.2) == 1); +static assert((5.2 <= 6.2) == 1); +static assert((5.2 > 6.2) == 0); +static assert((5.2 >= 6.2) == 0); + +static assert((5.2 < 5.2) == 0); +static assert((5.2 <= 5.2) == 1); +static assert((5.2 > 5.2) == 0); +static assert((5.2 >= 5.2) == 1); + +static assert((7.2 < 6.2) == 0); +static assert((7.2 <= 6.2) == 0); +static assert((7.2 > 6.2) == 1); +static assert((7.2 >= 6.2) == 1); + +static assert((7.2i < 6.2i) == 0); + + +static assert((7.2i == 6.2i) == 0); +static assert((7.2i != 6.2i) == 1); +static assert((7.2 == 6.2) == 0); +static assert((7.2 != 6.2) == 1); + +static assert((7.2i == 7.2i) == 1); +static assert((7.2i != 7.2i) == 0); +static assert((7.2 == 7.2) == 1); +static assert((7.2 != 7.2) == 0); + +static assert((7.2 == double.nan) == 0); +static assert((7.2 != double.nan) == 1); +static assert((double.nan == double.nan) == 0); +static assert((double.nan != double.nan) == 1); +static assert((double.nan == 7.2) == 0); +static assert((double.nan != 7.2) == 1); + +static assert((5 is 5) == 1); +static assert((5 is 4) == 0); +static assert((5 !is 5) == 0); +static assert((5 !is 4) == 1); + +static assert((5.1 is 5.1) == 1); +static assert((5.1 is 4.1) == 0); +static assert((5.1 !is 5.1) == 0); +static assert((5.1 !is 4.1) == 1); + +static assert((5.1 is 5.1i) == 0); +static assert((5.1 !is 5.1i) == 1); + +static assert((5 ? 2 : 3) == 2); +static assert((0 ? 2 : 3) == 3); +static assert((5.0 ? 2 : 3) == 2); +static assert((0.0 ? 2 : 3) == 3); + +static assert("abc" == "abc"); + +//static assert("abc"w.sizeof == 6); +//static assert("\U00010000bc"w.sizeof == 8); + +static assert([1,2,3][1] == 2); +static assert([1,2,3] ~ [4] == [1,2,3,4]); +static assert([1,2,3][1..3] == [2,3]); + +static assert(['a','b','c','d'] == "abcd"); +static assert("efgh" == ['e','f','g','h']); +static assert("efgi" != ['e','f','g','h']); + +static assert((2 ^^ 8) == 256); +static assert((3 ^^ 8.0) == 6561); +static assert((4.0 ^^ 8) == 65536); +static assert((5.0 ^^ 8.0) == 390625); + +static assert((0.5 ^^ 3) == 0.125); +static assert((1.5 ^^ 3.0) == 3.375); +static assert((2.5 ^^ 3) == 15.625); +static assert((3.5 ^^ 3.0) == 42.875); + +static assert(((-2) ^^ -5.0) == -0.031250); +static assert(((-2.0) ^^ -6) == 0.015625); +static assert(((-2.0) ^^ -7.0) == -0.0078125); + +static assert((144 ^^ 0.5) == 12); +static assert((1089 ^^ 0.5) == 33); +static assert((1764 ^^ 0.5) == 42); +static assert((650.25 ^^ 0.5) == 25.5); + + +void test1() +{ + int x; + int y; + int* p; + + p = &x + cast(size_t)&y; + p = &x + 2; + p = 4 + &y; + p = &x - 1; + + assert((&x is &x) == 1); + assert((&x is &y) == 0); + assert((&x !is &x) == 0); + assert((&x !is &y) == 1); +} + +/************************************/ + +void test2() +{ + // This test only tests undefined, architecture-dependant behavior. + // E.g. the result of converting a float whose value doesn't fit into the integer + // leads to an undefined result. + version(GNU) + return; + + float f = float.infinity; + int i = cast(int) f; + writeln(i); + writeln(cast(int)float.max); + assert(i == cast(int)float.max); + assert(i == 0x80000000); +} + +/************************************/ + +void test3() +{ + real n = -0.0; + const real m = -0.0; + + creal c = -0.0 + 3i; + creal d = n + 3i; + creal e = m + 3i; + + // should print "11111" + writeln(signbit(n), signbit(m), + signbit(c.re), signbit(d.re), signbit(e.re)); + + assert(signbit(n) == 1); + assert(signbit(m) == 1); + assert(signbit(c.re) == 1); + assert(signbit(d.re) == 1); + assert(signbit(e.re) == 1); +} + +/************************************/ + +struct A4 { char [] a; } +struct B4 { long x; } +struct C4 { int a; + static C4 opCall(int b) { C4 q; q.a=b; return q; } +} +static assert(!is(typeof( (){ A4 s; B4 q = s; }))); +static assert(!is(typeof( (){ B4 x =1L; }))); +static assert(is(typeof( (){ C4 g = 7; }))); +static assert(is(typeof( (){ C4 g = 7; C4 h = g;}))); + +/************************************/ + +alias uint DWORD; +MY_API_FUNCTION lpStartAddress; +extern (Windows) alias DWORD function(void*) MY_API_FUNCTION; +pragma(msg, MY_API_FUNCTION.stringof); +static assert(MY_API_FUNCTION.stringof == "extern (Windows) uint function(void*)"); + +/************************************/ + +enum bug6 = cast(void*)0xFEFEFEFE; +static assert(bug6 is bug6); + +/************************************/ + +struct S7{ + double z; +} + +int bug7(int x) { return x; } + +S7 s7; +double e7 = 4; +const double d7 = 4; + +static assert(!is(typeof(bug7(cast(long)e7)))); +static assert(!is(typeof(bug7(cast(long)s7)))); +version (LDC) {} else // cast in LDC undefined result w/ x > long.max +static assert(!is(typeof(bug7(cast(long)3.256679e30)))); + +static assert(is(typeof(bug7(cast(long)d7)))); +static assert(is(typeof(bug7(cast(long)3.256679e4)))); + +/************************************/ + +class C8 { + int x; +} +alias C8.x F8; +static assert(is(typeof(F8) == int)); +static assert(is(typeof(C8.x) == int)); + +/************************************/ + +int foo9() { + int u = cast(int)(0x1_0000_0000L); + while (u) { + if (u) { + assert(u!=0); + } + assert(u!=0); + } + return 2; +} + +static assert(foo9()==2); + +/************************************/ +// Bugzilla 6077 + +void test6077() { + static string scat(string s1, string s2) + { + return s1 ~ s2; + } + + static string scatass(string s1, string s2) + { + s1 ~= s2; + return s1; + } + + static string[] arycats(string[] ary, string s) + { + return ary ~ s; + } + + static string[] scatary(string s, string[] ary) + { + return s ~ ary; + } + + static string[] arycatasss(string[] ary, string s) + { + ary ~= s; + return ary; + } + + static assert(scat(null, null) is null); + static assert(scatass(null, null) is null); + static assert(arycats(null, null) == cast(string[])[null]); + static assert(scatary(null, null) == cast(string[])[null]); + static assert(arycatasss(null, null) == cast(string[])[null]); +} + +/************************************/ + +int test4() +{ + int i; + + dchar d; + d >>= 1; + d >>>= 1; + d <<= 1; + d = d >> 1; + d = d >>> 1; + d = d << 1; + wchar w; + w >>= 1; + w >>>= 1; + w <<= 1; + w = w >> 1; + w = w >>> 1; + i = w << 1; // promoted to int + char c; + c >>= 1; + c >>>= 1; + c <<= 1; + c = c >> 1; + c = c >>> 1; + i = c << 1; // promoted to int + return d + w + c + i; +} + +static assert(test4() == 24666); + +/************************************/ +// 8400 + +void test8400() +{ + immutable a = [1,2]; + int[a.length+0] b; // ok + int[a.length ] c; // error +} + +/************************************/ +// 8939 + +void foo8939(T)(ref T) { } // same for `auto ref` +void bar8939(ref const int) { } +void bar8939(ref const S8939) { } + +static struct S8939 { int n; } + +const gn8939 = 1; // or `immutable` +const gs8939 = S8939(3); +static assert(__traits(compiles, foo8939(gn8939), bar8939(gn8939))); +static assert(__traits(compiles, foo8939(gs8939), bar8939(gs8939))); + +void test8939() +{ + foo8939(gn8939), bar8939(gn8939); + foo8939(gs8939), bar8939(gs8939); + + const ln8939 = 1; + const ls8939 = S8939(3); + foo8939(ln8939), bar8939(ln8939); + foo8939(ls8939), bar8939(ls8939); +} + +class C8939regression +{ + const int n1 = 0; + const int n2 = 0; + const int n3 = 0; + const int n4 = 1; + + int refValue(V)(ref V var) + { + return 0; + } + + void foo() + { + string[2] str; + refValue(str[n1]); + + int[] da; + refValue(da[n2]); + + int n; int* p = &n; + refValue(*cast(int*)(p + n3)); + + refValue([1,2,n4].ptr[0]); + } +} + +/************************************/ +// 9058 + +template TypeTuple9058(TL...) { alias TypeTuple9058 = TL; } +template EnumMembers9058(T) +{ + alias EnumMembers9058 = TypeTuple9058!(Foo9058.A, Foo9058.B); +} +enum Foo9058 { A, B } +size_t bar9058(size_t n) +{ + return 0; +} +void test9058() +{ + Foo9058 x = [EnumMembers9058!Foo9058][bar9058($)]; +} + +/************************************/ +// 11159 + +void test11159() +{ + import std.math : pow; + enum ulong + e_2_pow_64 = 2uL^^64, + e_10_pow_19 = 10uL^^19, + e_10_pow_20 = 10uL^^20; + assert(e_2_pow_64 == pow(2uL, 64)); + assert(e_10_pow_19 == pow(10uL, 19)); + assert(e_10_pow_20 == pow(10uL, 20)); +} + +/************************************/ +// 12306 + +void test12306() +{ + struct Point3D { ubyte x, y, z; } + + enum Point3D pt1 = {x:1, y:1, z:1}; + const Point3D pt2 = {x:1, y:1, z:1}; + immutable Point3D pt3 = {x:1, y:1, z:1}; + + int[pt1.z][pt1.y][pt1.x] a1; + int[pt2.z][pt2.y][pt2.x] a2; + int[pt3.z][pt3.y][pt3.x] a3; + + ubyte a = 1; + const Point3D ptx = {x:a, y:1, z:1}; + + static assert(!__traits(compiles, { int[ptx.z][ptx.y][ptx.x] ax; })); +} + +/************************************/ +// 13977 + +void test13977() +{ + bool cond(bool b) { return b; } + int x = 0; + void check(int n = 1) { x = n; } + + cond(true) && check(); + assert(x == 1); x = 0; + + cond(false) && check(); + assert(x == 0); x = 0; + + true && check(); + assert(x == 1); x = 0; + + false && check(); + assert(x == 0); x = 0; + (int[]).init && check(); + assert(x == 0); x = 0; + Object.init && check(); + assert(x == 0); + + (check(2), false) && check(); + assert(x == 2); x = 0; +} + +/************************************/ +// 13978 + +void test13978() +{ + bool cond(bool b) { return b; } + int x = 0; + void check(int n = 1) { x = n; } + + cond(true) || check(); + assert(x == 0); x = 0; + + cond(false) || check(); + assert(x == 1); x = 0; + + true || check(); + assert(x == 0); x = 0; + + false || check(); + assert(x == 1); x = 0; + (int[]).init || check(); + assert(x == 1); x = 0; + Object.init || check(); + assert(x == 1); x = 0; + + (check(2), true) || check(); + assert(x == 2); x = 0; +} + +/************************************/ +// Pull Request 3697 + +void test3697and() +{ + enum x = 0; + auto y = x && 1 / x; +} + +void test3697or() +{ + enum x = 0; + enum y = 1; + auto z = y || 1 / x; +} + +/************************************/ +// 14459 + +void test14459() +{ + const char* s0 = "hi0"; + const(char)* p0 = s0; + assert(p0 == s0); + + const char* s1 = "hi1"; + const char* s2 = "hi2"; + const char* s3 = "hi3"; + const char* s4 = "hi4"; + const char* s5 = "hi5"; + const char* s6 = "hi6"; + const char* s7 = "hi7"; + const char* s8 = "hi8"; + const char* s9 = "hi9"; + const char* s10 = "hi10"; + const char* s11 = "hi11"; + const char* s12 = "hi12"; + const char* s13 = "hi13"; + const char* s14 = "hi14"; + const char* s15 = "hi15"; + assert(p0 == s0); // ok + const char* s16 = "hi16"; + assert(p0 == s0); // ok <- fails +} + +/************************************/ +// https://issues.dlang.org/show_bug.cgi?id=15607 + +static immutable char[2][4] code_base = [ "??", 12 ]; +static assert(code_base[0] == "??"); +static assert(code_base[1] == [12, 12]); +static assert(code_base[2] == typeof(code_base[2]).init); + +/************************************/ + +int main() +{ + test1(); + test2(); + test3(); + test3697and(); + test3697or(); + test6077(); + test8400(); + test8939(); + test9058(); + test11159(); + test13977(); + test13978(); + test14459(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/cpp_abi_tests.d b/gcc/testsuite/gdc.test/runnable/cpp_abi_tests.d new file mode 100644 index 00000000000..f0c0c097904 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/cpp_abi_tests.d @@ -0,0 +1,157 @@ +// EXTRA_CPP_SOURCES: extra-files/cpp_abi_tests.cpp + +extern(C++) { + +struct S +{ + float a = 1; +} + +bool passthrough(bool value); +byte passthrough(byte value); +ubyte passthrough(ubyte value); +char passthrough(char value); +dchar passthrough(dchar value); +short passthrough(short value); +ushort passthrough(ushort value); +int passthrough(int value); +uint passthrough(uint value); +long passthrough(long value); +ulong passthrough(ulong value); +float passthrough(float value); +double passthrough(double value); +S passthrough(S value); + +bool passthrough_ptr(bool *value); +byte passthrough_ptr(byte *value); +ubyte passthrough_ptr(ubyte *value); +char passthrough_ptr(char *value); +dchar passthrough_ptr(dchar *value); +short passthrough_ptr(short *value); +ushort passthrough_ptr(ushort *value); +int passthrough_ptr(int *value); +uint passthrough_ptr(uint *value); +long passthrough_ptr(long *value); +ulong passthrough_ptr(ulong *value); +float passthrough_ptr(float *value); +double passthrough_ptr(double *value); +S passthrough_ptr(S *value); + +bool passthrough_ref(ref bool value); +byte passthrough_ref(ref byte value); +ubyte passthrough_ref(ref ubyte value); +char passthrough_ref(ref char value); +dchar passthrough_ref(ref dchar value); +short passthrough_ref(ref short value); +ushort passthrough_ref(ref ushort value); +int passthrough_ref(ref int value); +uint passthrough_ref(ref uint value); +long passthrough_ref(ref long value); +ulong passthrough_ref(ref ulong value); +float passthrough_ref(ref float value); +double passthrough_ref(ref double value); +S passthrough_ref(ref S value); +} + +template IsSigned(T) +{ + enum IsSigned = is(T==byte) || + is(T==short) || + is(T==int) || + is(T==long); +} + +template IsUnsigned(T) +{ + enum IsUnsigned = is(T==ubyte) || + is(T==ushort) || + is(T==uint) || + is(T==ulong); +} + +template IsIntegral(T) +{ + enum IsIntegral = IsSigned!T || IsUnsigned!T; +} + +template IsFloatingPoint(T) +{ + enum IsFloatingPoint = is(T==float) || is(T==double) || is(T==real); +} + +template IsBoolean(T) +{ + enum IsBoolean = is(T==bool); +} + +template IsSomeChar(T) +{ + enum IsSomeChar = is(T==char) || is(T==dchar); +} + +void check(T)(T actual, T expected) +{ + assert(actual is expected); +} + +void check(T)(T value) +{ + check(passthrough(value), value); + check(passthrough_ptr(&value), value); + check(passthrough_ref(value), value); +} + +T[] values(T)() +{ + T[] values; + static if(IsBoolean!T) + { + values ~= true; + values ~= false; + } + else static if(IsSomeChar!T) + { + values ~= T.init; + values ~= T('a'); + values ~= T('z'); + } + else + { + values ~= T(0); + values ~= T(1); + static if(IsIntegral!T) + { + static if(IsSigned!T) values ~= T.min; + values ~= T.max; + } + else static if(IsFloatingPoint!T) + { + values ~= T.nan; + values ~= T.min_normal; + values ~= T.max; + } + else + { + assert(0); + } + } + return values; +} + +void main() +{ + foreach(bool val; values!bool()) check(val); + foreach(byte val; values!byte()) check(val); + foreach(ubyte val; values!ubyte()) check(val); + foreach(char val; values!char()) check(val); + foreach(dchar val; values!dchar()) check(val); + foreach(short val; values!short()) check(val); + foreach(ushort val; values!ushort()) check(val); + foreach(int val; values!int()) check(val); + foreach(uint val; values!uint()) check(val); + foreach(long val; values!long()) check(val); + foreach(ulong val; values!ulong()) check(val); + foreach(float val; values!float()) check(val); + foreach(double val; values!double()) check(val); + check(S()); +} diff --git a/gcc/testsuite/gdc.test/runnable/cppa.d b/gcc/testsuite/gdc.test/runnable/cppa.d new file mode 100644 index 00000000000..3b283427951 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/cppa.d @@ -0,0 +1,1258 @@ +// PERMUTE_ARGS: -g +// EXTRA_CPP_SOURCES: extra-files/cppb.cpp + +import core.stdc.stdio; +import core.stdc.stdarg; +import core.stdc.config; + +extern (C++) + int foob(int i, int j, int k); + +class C +{ + extern (C++) int bar(int i, int j, int k) + { + printf("this = %p\n", this); + printf("i = %d\n", i); + printf("j = %d\n", j); + printf("k = %d\n", k); + return 1; + } +} + + +extern (C++) + int foo(int i, int j, int k) +{ + printf("i = %d\n", i); + printf("j = %d\n", j); + printf("k = %d\n", k); + assert(i == 1); + assert(j == 2); + assert(k == 3); + return 1; +} + +void test1() +{ + foo(1, 2, 3); + + auto i = foob(1, 2, 3); + assert(i == 7); + + C c = new C(); + c.bar(4, 5, 6); +} + +/****************************************/ + +extern (C++) interface D +{ + int bar(int i, int j, int k); +} + +extern (C++) D getD(); + +void test2() +{ + D d = getD(); + int i = d.bar(9,10,11); + assert(i == 8); +} + +/****************************************/ + +extern (C++) int callE(E); + +extern (C++) interface E +{ + int bar(int i, int j, int k); +} + +class F : E +{ + extern (C++) int bar(int i, int j, int k) + { + printf("F.bar: i = %d\n", i); + printf("F.bar: j = %d\n", j); + printf("F.bar: k = %d\n", k); + assert(i == 11); + assert(j == 12); + assert(k == 13); + return 8; + } +} + +void test3() +{ + F f = new F(); + int i = callE(f); + assert(i == 8); +} + +/****************************************/ + +extern (C++) void foo4(char* p); + +void test4() +{ + foo4(null); +} + +/****************************************/ + +extern(C++) +{ + struct foo5 { int i; int j; void* p; } + + interface bar5{ + foo5 getFoo(int i); + } + + bar5 newBar(); +} + +void test5() +{ + bar5 b = newBar(); + foo5 f = b.getFoo(4); + printf("f.p = %p, b = %p\n", f.p, cast(void*)b); + assert(f.p == cast(void*)b); +} + + +/****************************************/ + +extern(C++) +{ + struct S6 + { + int i; + double d; + } + + union S6_2 + { + int i; + double d; + } + + enum S6_3 + { + A, B + } + + S6 foo6(); + S6_2 foo6_2(); + S6_3 foo6_3(); +} + +extern (C) int foosize6(); + +void test6() +{ + S6 f = foo6(); + printf("%d %d\n", foosize6(), S6.sizeof); + assert(foosize6() == S6.sizeof); +version (X86) +{ + assert(f.i == 42); + printf("f.d = %g\n", f.d); + assert(f.d == 2.5); + assert(foo6_2().i == 42); + assert(foo6_3() == S6_3.A); +} +} + +/****************************************/ + +extern (C) int foo7(); + +struct S +{ + int i; + long l; +} + +void test7() +{ + printf("%d %d\n", foo7(), S.sizeof); + assert(foo7() == S.sizeof); +} + +/****************************************/ + +extern (C++) void foo8(const(char)*); + +void test8() +{ + char c; + foo8(&c); +} + +/****************************************/ +// 4059 + +struct elem9 { } + +extern(C++) void foobar9(elem9*, elem9*); + +void test9() +{ + elem9 *a; + foobar9(a, a); +} + +/****************************************/ + + +struct A11802; +struct B11802; + +extern(C++) class C11802 +{ + int x; + void fun(A11802*) { x += 2; } + void fun(B11802*) { x *= 2; } +} + +extern(C++) class D11802 : C11802 +{ + override void fun(A11802*) { x += 3; } + override void fun(B11802*) { x *= 3; } +} + +extern(C++) void test11802x(D11802); + +void test11802() +{ + auto x = new D11802(); + x.x = 0; + test11802x(x); + assert(x.x == 9); +} + + +/****************************************/ + +struct S13956 +{ +} + +extern(C++) void func13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); + +extern(C++) void check13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) +{ + assert(arg0 == S13956()); + assert(arg1 == 1); + assert(arg2 == 2); + assert(arg3 == 3); + assert(arg4 == 4); + assert(arg5 == 5); + version (OSX) + { + version (D_LP64) + assert(arg6 == 6); + // fails on OSX 32-bit + } + else + assert(arg6 == 6); +} + +void test13956() +{ + func13956(S13956(), 1, 2, 3, 4, 5, 6); +} + +/****************************************/ +// 5148 + +extern (C++) +{ + void foo10(const(char)*, const(char)*); + void foo10(const int, const int); + void foo10(const char, const char); + void foo10(bool, bool); + + struct MyStructType { } + void foo10(const MyStructType s, const MyStructType t); + + enum MyEnumType { onemember } + void foo10(const MyEnumType s, const MyEnumType t); +} + +void test10() +{ + char* p; + foo10(p, p); + foo10(1,2); + foo10('c','d'); + MyStructType s; + foo10(s,s); + MyEnumType e; + foo10(e,e); +} + +/****************************************/ + +extern (C++, N11.M) { void bar11(); } + +extern (C++, A11.B) { extern (C++, C) { void bar(); }} + +void test11() +{ + bar11(); + A11.B.C.bar(); +} +/****************************************/ + +struct Struct10071 +{ + void *p; + c_long_double r; +} + +extern(C++) size_t offset10071(); +void test10071() +{ + assert(offset10071() == Struct10071.r.offsetof); +} + +/****************************************/ + +char[100] valistbuffer; + +extern(C++) void myvprintfx(const(char)* format, va_list va) +{ + vsprintf(valistbuffer.ptr, format, va); +} +extern(C++) void myvprintf(const(char)*, va_list); +extern(C++) void myprintf(const(char)* format, ...) +{ + va_list ap; + va_start(ap, format); + myvprintf(format, ap); + va_end(ap); +} + +void testvalist() +{ + myprintf("hello %d", 999); + assert(valistbuffer[0..9] == "hello 999"); +} + +/****************************************/ +// 12825 + +extern(C++) class C12825 +{ + uint a = 0x12345678; +} + +void test12825() +{ + auto c = new C12825(); +} + +/****************************************/ + +struct S13955a +{ + float a; + double b; +} + +struct S13955b +{ + double a; + float b; +} + +struct S13955c +{ + float a; + float b; +} + +struct S13955d +{ + double a; + double b; +} + +extern(C++) void check13955(S13955a a, S13955b b, S13955c c, S13955d d) +{ + assert(a.a == 2); + assert(a.b == 4); + assert(b.a == 8); + assert(b.b == 16); + assert(c.a == 32); + assert(c.b == 64); + assert(d.a == 128); + assert(d.b == 256); +} + +extern(C++) void func13955(S13955a a, S13955b b, S13955c c, S13955d d); + +void test13955() +{ + func13955(S13955a(2, 4), S13955b(8, 16), S13955c(32, 64), S13955d(128, 256)); +} + +/****************************************/ + +extern(C++) class C13161 +{ + void dummyfunc(); + long val_5; + uint val_9; +} + +extern(C++) class Test : C13161 +{ + uint val_0; + long val_1; +} + +extern(C++) size_t getoffset13161(); + +extern(C++) class C13161a +{ + void dummyfunc(); + c_long_double val_5; + uint val_9; +} + +extern(C++) class Testa : C13161a +{ + bool val_0; +} + +extern(C++) size_t getoffset13161a(); + +void test13161() +{ + assert(getoffset13161() == Test.val_0.offsetof); + assert(getoffset13161a() == Testa.val_0.offsetof); +} + +/****************************************/ + +version (linux) +{ + extern(C++, __gnu_cxx) + { + struct new_allocator(T) + { + alias size_type = size_t; + static if (is(T : char)) + void deallocate(T*, size_type) { } + else + void deallocate(T*, size_type); + } + } +} + +extern (C++, std) +{ + struct allocator(T) + { + version (linux) + { + alias size_type = size_t; + void deallocate(T* p, size_type sz) + { (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); } + } + } + + version (linux) + { + class vector(T, A = allocator!T) + { + final void push_back(ref const T); + } + + struct char_traits(T) + { + } + + // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html + version (none) + { + extern (C++, __cxx11) + { + struct basic_string(T, C = char_traits!T, A = allocator!T) + { + } + } + } + else + { + struct basic_string(T, C = char_traits!T, A = allocator!T) + { + } + } + + struct basic_istream(T, C = char_traits!T) + { + } + + struct basic_ostream(T, C = char_traits!T) + { + } + + struct basic_iostream(T, C = char_traits!T) + { + } + } + + class exception { } + + // 14956 + extern(C++, N14956) + { + struct S14956 { } + } +} + +extern (C++) +{ + version (linux) + { + void foo14(std.vector!(int) p); + void foo14a(std.basic_string!(char) *p); + void foo14b(std.basic_string!(int) *p); + void foo14c(std.basic_istream!(char) *p); + void foo14d(std.basic_ostream!(char) *p); + void foo14e(std.basic_iostream!(char) *p); + + void foo14f(std.char_traits!char* x, std.basic_string!char* p, std.basic_string!char* q); + } +} + +void test14() +{ + version (linux) + { + std.vector!int p; + foo14(p); + + foo14a(null); + foo14b(null); + foo14c(null); + foo14d(null); + foo14e(null); + foo14f(null, null, null); + } +} + +version (linux) +{ + void test14a(std.allocator!int * pa) + { + pa.deallocate(null, 0); + } + + void gun(std.vector!int pa) + { + int x = 42; + pa.push_back(x); + } +} + +void test13289() +{ + assert(f13289_cpp_wchar_t('a') == 'A'); + assert(f13289_cpp_wchar_t('B') == 'B'); + assert(f13289_d_wchar('c') == 'C'); + assert(f13289_d_wchar('D') == 'D'); + assert(f13289_d_dchar('e') == 'E'); + assert(f13289_d_dchar('F') == 'F'); + assert(f13289_cpp_test()); +} + +extern(C++) +{ + bool f13289_cpp_test(); + + version(Posix) + { + dchar f13289_cpp_wchar_t(dchar); + } + else version(Windows) + { + wchar f13289_cpp_wchar_t(wchar); + } + + wchar f13289_d_wchar(wchar ch) + { + if (ch <= 'z' && ch >= 'a') + { + return cast(wchar)(ch - ('a' - 'A')); + } + else + { + return ch; + } + } + dchar f13289_d_dchar(dchar ch) + { + if (ch <= 'z' && ch >= 'a') + { + return ch - ('a' - 'A'); + } + else + { + return ch; + } + } +} + +/****************************************/ + +version (CRuntime_Microsoft) +{ + struct __c_long_double + { + this(double d) { ld = d; } + double ld; + alias ld this; + } + + alias __c_long_double myld; +} +else + alias c_long_double myld; + +extern (C++) myld testld(myld); + + +void test15() +{ + myld ld = 5.0; + ld = testld(ld); + assert(ld == 6.0); +} + +/****************************************/ + +version( Windows ) +{ + alias int x_long; + alias uint x_ulong; +} +else +{ + static if( (void*).sizeof > int.sizeof ) + { + alias long x_long; + alias ulong x_ulong; + } + else + { + alias int x_long; + alias uint x_ulong; + } +} + +struct __c_long +{ + this(x_long d) { ld = d; } + x_long ld; + alias ld this; +} + +struct __c_ulong +{ + this(x_ulong d) { ld = d; } + x_ulong ld; + alias ld this; +} + +alias __c_long mylong; +alias __c_ulong myulong; + +extern (C++) mylong testl(mylong); +extern (C++) myulong testul(myulong); + + +void test16() +{ + { + mylong ld = 5; + ld = testl(ld); + assert(ld == 5 + mylong.sizeof); + } + { + myulong ld = 5; + ld = testul(ld); + assert(ld == 5 + myulong.sizeof); + } +} + +/****************************************/ + +struct S13707 +{ + void* a; + void* b; + this(void* a, void* b) + { + this.a = a; + this.b = b; + } +} + +extern(C++) S13707 func13707(); + +void test13707() +{ + auto p = func13707(); + assert(p.a == null); + assert(p.b == null); +} + +/****************************************/ + +struct S13932(int x) +{ + int member; +} + +extern(C++) void func13932(S13932!(-1) s); + +/****************************************/ + +extern(C++, N13337.M13337) +{ + struct S13337{} + void foo13337(S13337 s); +} + +/****************************************/ +// 14195 + +struct Delegate1(T) {} +struct Delegate2(T1, T2) {} + +template Signature(T) +{ + alias Signature = typeof(*(T.init)); +} + +extern(C++) +{ + alias del1_t = Delegate1!(Signature!(void function())); + alias del2_t = Delegate2!(Signature!(int function(float, double)), Signature!(int function(float, double))); + void test14195a(del1_t); + void test14195b(del2_t); +} + +void test14195() +{ + test14195a(del1_t()); + test14195b(del2_t()); +} + + +/****************************************/ +// 14200 + +template Tuple14200(T...) +{ + alias Tuple14200 = T; +} + +extern(C++) void test14200a(Tuple14200!(int)); +extern(C++) void test14200b(float, Tuple14200!(int, double)); + +void test14200() +{ + test14200a(1); + test14200b(1.0f, 1, 1.0); +} + +/****************************************/ +// 14956 + +extern(C++) void test14956(S14956 s); + +/****************************************/ +// check order of overloads in vtable + +extern (C++) class Statement {} +extern (C++) class ErrorStatement {} +extern (C++) class PeelStatement {} +extern (C++) class ExpStatement {} +extern (C++) class DtorExpStatement {} + +extern (C++) class Visitor +{ +public: + int visit(Statement) { return 1; } + int visit(ErrorStatement) { return 2; } + int visit(PeelStatement) { return 3; } +} + +extern (C++) class Visitor2 : Visitor +{ + int visit2(ExpStatement) { return 4; } + int visit2(DtorExpStatement) { return 5; } +} + +extern(C++) bool testVtableCpp(Visitor2 sv); +extern(C++) Visitor2 getVisitor2(); + +bool testVtableD(Visitor2 sv) +{ + Statement s1; + ErrorStatement s2; + PeelStatement s3; + ExpStatement s4; + DtorExpStatement s5; + + if (sv.visit(s1) != 1) return false; + if (sv.visit(s2) != 2) return false; + if (sv.visit(s3) != 3) return false; + if (sv.visit2(s4) != 4) return false; + if (sv.visit2(s5) != 5) return false; + return true; +} + +void testVtable() +{ + Visitor2 dinst = new Visitor2; + if (!testVtableCpp(dinst)) + assert(0); + + Visitor2 cppinst = getVisitor2(); + if (!testVtableD(cppinst)) + assert(0); +} + +/****************************************/ +/* problems detected by fuzzer */ +extern(C++) void fuzz1_cppvararg(long arg10, long arg11, bool arg12); +extern(C++) void fuzz1_dvararg(long arg10, long arg11, bool arg12) +{ + fuzz1_checkValues(arg10, arg11, arg12); +} + +extern(C++) void fuzz1_checkValues(long arg10, long arg11, bool arg12) +{ + assert(arg10 == 103); + assert(arg11 == 104); + assert(arg12 == false); +} + +void fuzz1() +{ + long arg10 = 103; + long arg11 = 104; + bool arg12 = false; + fuzz1_dvararg(arg10, arg11, arg12); + fuzz1_cppvararg(arg10, arg11, arg12); +} + +//////// +extern(C++) void fuzz2_cppvararg(ulong arg10, ulong arg11, bool arg12); +extern(C++) void fuzz2_dvararg(ulong arg10, ulong arg11, bool arg12) +{ + fuzz2_checkValues(arg10, arg11, arg12); +} + +extern(C++) void fuzz2_checkValues(ulong arg10, ulong arg11, bool arg12) +{ + assert(arg10 == 103); + assert(arg11 == 104); + assert(arg12 == false); +} + +void fuzz2() +{ + ulong arg10 = 103; + ulong arg11 = 104; + bool arg12 = false; + fuzz2_dvararg(arg10, arg11, arg12); + fuzz2_cppvararg(arg10, arg11, arg12); +} + +//////// +extern(C++) void fuzz3_cppvararg(wchar arg10, wchar arg11, bool arg12); +extern(C++) void fuzz3_dvararg(wchar arg10, wchar arg11, bool arg12) +{ + fuzz2_checkValues(arg10, arg11, arg12); +} + +extern(C++) void fuzz3_checkValues(wchar arg10, wchar arg11, bool arg12) +{ + assert(arg10 == 103); + assert(arg11 == 104); + assert(arg12 == false); +} + +void fuzz3() +{ + wchar arg10 = 103; + wchar arg11 = 104; + bool arg12 = false; + fuzz3_dvararg(arg10, arg11, arg12); + fuzz3_cppvararg(arg10, arg11, arg12); +} + +void fuzz() +{ + fuzz1(); + fuzz2(); + fuzz3(); +} + +/****************************************/ + +extern (C++) +{ + void throwit(); +} + +void testeh() +{ + printf("testeh()\n"); + version (linux) + { + version (X86_64) + { + bool caught; + try + { + throwit(); + } + catch (std.exception e) + { + caught = true; + } + assert(caught); + } + } +} + +/****************************************/ + +version (linux) +{ + version (X86_64) + { + bool raii_works = false; + struct RAIITest + { + ~this() + { + raii_works = true; + } + } + + void dFunction() + { + RAIITest rt; + throwit(); + } + + void testeh2() + { + printf("testeh2()\n"); + try + { + dFunction(); + } + catch(std.exception e) + { + assert(raii_works); + } + } + } + else + void testeh2() { } +} +else + void testeh2() { } + +/****************************************/ + +extern (C++) { void throwle(); void throwpe(); } + +void testeh3() +{ + printf("testeh3()\n"); + version (linux) + { + version (X86_64) + { + bool caught = false; + try + { + throwle(); + } + catch (std.exception e) //polymorphism test. + { + caught = true; + } + assert(caught); + } + } +} + +/****************************************/ +// 15576 + +extern (C++, ns15576) +{ + extern __gshared int global15576; + + extern (C++, ns) + { + extern __gshared int n_global15576; + } +} + +void test15576() +{ + global15576 = n_global15576 = 123; +} + +/****************************************/ +// 15579 + +extern (C++) +{ + class Base + { + //~this() {} + void based() { } + ubyte x = 4; + } + + interface Interface + { + int MethodCPP(); + int MethodD(); + } + + class Derived : Base, Interface + { + short y = 5; + int MethodCPP(); + int MethodD() { + printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y); + Derived p = this; + //p = cast(Derived)(cast(void*)p - 16); + assert(p.x == 4 || p.x == 7); + assert(p.y == 5 || p.y == 8); + return 3; + } + int Method() { return 6; } + } + + Derived cppfoo(Derived); + Interface cppfooi(Interface); +} + +void test15579() +{ + Derived d = new Derived(); + printf("d = %p\n", d); + assert(d.x == 4); + assert(d.y == 5); + assert((cast(Interface)d).MethodCPP() == 30); + assert((cast(Interface)d).MethodD() == 3); + assert(d.MethodCPP() == 30); + assert(d.MethodD() == 3); + assert(d.Method() == 6); + + d = cppfoo(d); + assert(d.x == 7); + assert(d.y == 8); + + printf("d2 = %p\n", d); + + /* Casting to an interface involves thunks in the vtbl[]. + * g++ puts the thunks for MethodD in the same COMDAT as MethodD. + * But D doesn't, so when the linker "picks one" of the D generated MethodD + * or the g++ generated MethodD, it may wind up with a messed up thunk, + * resulting in a seg fault. The solution is to not expect objects of the same + * type to be constructed on both sides of the D/C++ divide if the same member + * function (in this case, MethodD) is also defined on both sides. + */ + version (Windows) + { + assert((cast(Interface)d).MethodD() == 3); + } + assert((cast(Interface)d).MethodCPP() == 30); + + assert(d.Method() == 6); + + printf("d = %p, i = %p\n", d, cast(Interface)d); + version (Windows) + { + Interface i = cppfooi(d); + printf("i2: %p\n", i); + assert(i.MethodD() == 3); + assert(i.MethodCPP() == 30); + } + printf("test15579() done\n"); +} + +/****************************************/ +// 15610 + +extern(C++) class Base2 +{ + int i; + void baser() { } +} + +extern(C++) interface Interface2 { abstract void f(); } + +extern(C++) class Derived2 : Base2, Interface2 +{ + final + override void f(); +} + + +void test15610() +{ + auto c = new Derived2(); + printf("test15610(): c = %p\n", c); + c.i = 3; + c.f(); +} + +/******************************************/ +// 15455 + +struct X6 +{ + ushort a; + ushort b; + ubyte c; + ubyte d; +} + +static assert(X6.sizeof == 6); + +struct X8 +{ + ushort a; + X6 b; +} + +static assert(X8.sizeof == 8); + +void test15455a(X8 s) +{ + assert(s.a == 1); + assert(s.b.a == 2); + assert(s.b.b == 3); + assert(s.b.c == 4); + assert(s.b.d == 5); +} + +extern (C++) void test15455b(X8 s); + +void test15455() +{ + X8 s; + + s.a = 1; + s.b.a = 2; + s.b.b = 3; + s.b.c = 4; + s.b.d = 5; + test15455a(s); + test15455b(s); +} + +/****************************************/ +// 15372 + +extern(C++) int foo15372(T)(T v); + +void test15372() +{ + version(Windows){} + else + assert(foo15372!int(1) == 1); +} + +/****************************************/ +// 15802 + +extern(C++) { + template Foo15802(T) { + static int boo(T v); + } +} + +void test15802() +{ + version(Windows){} + else + assert(Foo15802!(int).boo(1) == 1); +} + +/****************************************/ +// 16536 - mangling mismatch on OSX + +version(OSX) extern(C++) ulong pass16536(ulong); + +void test16536() +{ + version(OSX) assert(pass16536(123) == 123); +} + +/****************************************/ + +void main() +{ + test1(); + test2(); + test3(); + test4(); + test13956(); + test5(); + test6(); + test10071(); + test7(); + test8(); + test11802(); + test9(); + test10(); + test13955(); + test11(); + testvalist(); + test12825(); + test13161(); + test14(); + test13289(); + test15(); + test16(); + func13707(); + func13932(S13932!(-1)(0)); + foo13337(S13337()); + test14195(); + test14200(); + test14956(S14956()); + testVtable(); + fuzz(); + testeh(); + testeh2(); + testeh3(); + test15576(); + test15579(); + test15610(); + test15455(); + test15372(); + test15802(); + test16536(); + + printf("Success\n"); +} diff --git a/gcc/testsuite/gdc.test/runnable/ctorpowtests.d b/gcc/testsuite/gdc.test/runnable/ctorpowtests.d new file mode 100644 index 00000000000..2fb458e44f1 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/ctorpowtests.d @@ -0,0 +1,248 @@ +// PERMUTE_ARGS: + +int magicVariable() +{ + if (__ctfe) + return 3; + + version(GNU) + { + version(X86) + asm { "nop"; } + else version(X86_64) + asm { "nop"; } + else + static assert(""); + } + else + asm { nop; } + return 2; +} + +static assert(magicVariable()==3); + +void main() +{ + assert(!__ctfe); + assert(magicVariable()==2); +} + +// bug 991 -- invalid. +// bug 3500 -- is this related to 2127? + +// Tests for ^^ +// TODO: These tests should not require import std.math. + +import std.math; +// Test float ^^ int +static assert( 27.0 ^^ 5 == 27.0 * 27.0 * 27.0 * 27.0 * 27.0); +static assert( 2.0 ^^ 3 == 8.0); + +static assert( 2.0 ^^ 4 == 16.0); +static assert( 2 ^^ 4 == 16); + +// Check the typing rules. +static assert( is (typeof(2.0^^7) == double)); +static assert( is (typeof(7^^3) == int)); + +static assert( is (typeof(7L^^3) == long)); +static assert( is (typeof(7^^3L) == long)); +enum short POW_SHORT_1 = 3; +enum short POW_SHORT_3 = 7; +static assert( is (typeof(POW_SHORT_1 * POW_SHORT_1) == +typeof(POW_SHORT_1*POW_SHORT_1))); + +static assert( is (typeof(7.0^^3) == double)); +static assert( is (typeof(7.0L^^3) == real)); +static assert( is (typeof(7.0f^^3) == float)); +static assert( is (typeof(POW_SHORT_1^^3.1) == double)); +static assert( is (typeof(POW_SHORT_1^^3.1f) == float)); +static assert( is (typeof(2.1f ^^ POW_SHORT_1) == float)); +static assert( is (typeof(7.0f^^3.1) == double)); +static assert( is (typeof(7.0^^3.1f) == double)); +static assert( is (typeof(7.0f^^3.1f) == float)); +static assert( is (typeof(7.0f^^3.1L) == real)); +static assert( is (typeof(7.0L^^3.1f) == real)); +// Check typing for special cases +static assert( is (typeof(7.0f^^2) == float)); +static assert( is (typeof(7.0f^^2.0) == double)); +static assert( is (typeof(7.0f^^8.0) == double)); +static assert( is (typeof(1^^0.5f) == float)); +static assert( is (typeof(7^^0.5f) == float)); +static assert( is (typeof(3L^^0.5) == double)); +static assert( is (typeof(123^^17.0f) == float)); + +static assert(POW_SHORT_1 ^^ 2 == 9); +static assert(4.0 ^^ POW_SHORT_1 == 4.0*4.0*4.0); +static assert(4.0 ^^ 7.0 == 4.0*4.0*4.0*4.0*4.0*4.0*4.0); + +// ^^ has higher precedence than multiply +static assert( 2 * 2 ^^ 3 + 1 == 17); +static assert( 2 ^^ 3 * 2 + 1 == 17); +// ^^ has higher precedence than negate +static assert( -2 ^^ 3 * 2 - 1 == -17); + +// ^^ is right associative +static assert( 2 ^^ 3 ^^ 2 == 2 ^^ 9); +static assert( 2.0 ^^ -3 ^^ 2 == 2.0 ^^ -9); + +// 1 ^^ n is always 1, even if n is negative +static assert( 1 ^^ -5 == 1); + +// -1 ^^ n gets transformed into n & 1 ? -1 : 1 +// even if n is negative +static assert( (-1) ^^ -5 == -1); +static assert( (-1) ^^ -4 == 1); +static assert( (-1) ^^ 0 == 1); + +// n ^^ 0 is always 1 +static assert( (-5) ^^ 0 == 1); + +// n ^^ 1 is always n +static assert( 6.0 ^^ 1 == 6.0); + +// n ^^ -1.0 gets transformed into 1.0 / n, even if n is negative +static assert( (-4) ^^ -1.0 == 1.0 / -4); +static assert( 9 ^^ -1.0 == 1.0 / 9); + +// Other integers raised to negative powers create an error +static assert( !is(typeof(2 ^^ -5))); +static assert( !is(typeof((-2) ^^ -4))); + +// Bug 3535 +struct StructWithCtor +{ + this(int _n) { + n = _n; x = 5; + } + this(int _n, float _x) { + n = _n; x = _x; + } + int n; + float x; +} + +int containsAsm() { + version(GNU) + { + version(X86) + asm { "nop"; } + else version(X86_64) + asm { "nop"; } + else + static assert(""); + } + else + asm { nop; } + return 0; + } + +enum A = StructWithCtor(1); +enum B = StructWithCtor(7, 2.3); + +static assert(A.n == 1); +static assert(A.x == 5.0); +static assert(B.n == 7); +static assert(B.x == 2.3); + +int bazra(int x) +{ + StructWithCtor p = StructWithCtor(4); + return p.n ^^ 3; + +} + +static assert(bazra(14)==64); + +void moreCommaTests() +{ + auto k = (containsAsm(), containsAsm()); + for (int i=0; i< k^^2; i+=StructWithCtor(1).n) {} +} + +// Test copy constructors +struct CopyTest { + double x; + this(double a) { x = a * 10.0;} + this(this) { x+=2.0;} +} + +struct CopyTest2 +{ + int x; int x1; int x2; int x3; + this(int a) { x = a * 2; x1 = 3;} + this(this) { x1+=17;} +} + + +const CopyTest z = CopyTest(5.3); +/+ +// TODO: This is not yet supported. But it +// generates an error message instead of wrong-code. +const CopyTest w = z; +static assert(z.x==55.0); ++/ + +int copytest1() +{ + CopyTest z = CopyTest(3.4); + CopyTest w = z; + assert(w.x == 36.0); + CopyTest2 q = CopyTest2(7); + CopyTest2 q2 = q; + CopyTest2 q3 = q2; + assert(q3.x1 == 37); + + return 123; +} +static assert(copytest1()==123); + +// This must not cause a segfault +alias int FILTH; +struct Filth +{ + struct Impl + { + FILTH * handle = null; + this(FILTH* h, uint r, string n) + { + handle = h; + } + } + Impl * p; + + this(string name, in char[] stdioOpenmode = "rb") + { + } + + ~this() + { + if (!p) return; + } + + this(this) + { + if (!p) return; + } + } + struct InputByChar + { + private Filth _f; + + this(Filth f) + { + _f = f; + } +} + + +static int nastyForCtfe=4; + +// Can't use a global variable +static assert(!is(typeof( (){ static assert(0!=nastyForCtfe^^2); }))); + +int anotherPowTest() +{ + double x = 5.0; + return x^^4 > 2.0 ? 3: 2; +} diff --git a/gcc/testsuite/gdc.test/runnable/declaration.d b/gcc/testsuite/gdc.test/runnable/declaration.d new file mode 100644 index 00000000000..0b6c6b530db --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/declaration.d @@ -0,0 +1,412 @@ + +extern(C) int printf(const char*, ...); + +/***************************************************/ +// 6475 + +class Foo6475(Value) +{ + template T1(size_t n){ alias int T1; } +} + +void test6475() +{ + alias Foo6475!(int) C1; + alias C1.T1!0 X1; + static assert(is(X1 == int)); + + alias const(Foo6475!(int)) C2; + alias C2.T1!0 X2; + static assert(is(X2 == int)); +} + +/***************************************************/ +// 6905 + +void test6905() +{ + auto foo1() { static int n; return n; } + auto foo2() { int n; return n; } + auto foo3() { return 1; } + static assert(typeof(&foo1).stringof == "int delegate() nothrow @nogc @safe"); + static assert(typeof(&foo2).stringof == "int delegate() pure nothrow @nogc @safe"); + static assert(typeof(&foo3).stringof == "int delegate() pure nothrow @nogc @safe"); + + ref bar1() { static int n; return n; } + static assert(!__traits(compiles, { + ref bar2() { int n; return n; } + })); + static assert(!__traits(compiles, { + ref bar3() { return 1; } + })); + + auto ref baz1() { static int n; return n; } + auto ref baz2() { int n; return n; } + auto ref baz3() { return 1; } + static assert(typeof(&baz1).stringof == "int delegate() nothrow @nogc ref @safe"); + static assert(typeof(&baz2).stringof == "int delegate() pure nothrow @nogc @safe"); + static assert(typeof(&baz3).stringof == "int delegate() pure nothrow @nogc @safe"); +} + +/***************************************************/ +// 7019 + +struct S7019 +{ + int store; + this(int n) + { + store = n << 3; + } +} + +S7019 rt_gs = 2; +enum S7019 ct_gs = 2; +pragma(msg, ct_gs, ", ", ct_gs.store); + +void test7019() +{ + S7019 rt_ls = 3; // this compiles fine + enum S7019 ct_ls = 3; + pragma(msg, ct_ls, ", ", ct_ls.store); + + static class C + { + S7019 rt_fs = 4; + enum S7019 ct_fs = 4; + pragma(msg, ct_fs, ", ", ct_fs.store); + } + + auto c = new C; + assert(rt_gs == S7019(2) && rt_gs.store == 16); + assert(rt_ls == S7019(3) && rt_ls.store == 24); + assert(c.rt_fs == S7019(4) && c.rt_fs.store == 32); + static assert(ct_gs == S7019(2) && ct_gs.store == 16); + static assert(ct_ls == S7019(3) && ct_ls.store == 24); + static assert(C.ct_fs == S7019(4) && C.ct_fs.store == 32); + + void foo(S7019 s = 5) // fixing bug 7152 + { + assert(s.store == 5 << 3); + } + foo(); +} + +/***************************************************/ +// 7239 + +struct vec7239 +{ + float x, y, z, w; + alias x r; //! for color access + alias y g; //! ditto + alias z b; //! ditto + alias w a; //! ditto +} + +void test7239() +{ + vec7239 a = {x: 0, g: 0, b: 0, a: 1}; + assert(a.r == 0); + assert(a.g == 0); + assert(a.b == 0); + assert(a.a == 1); +} + +/***************************************************/ +struct S10635 +{ + string str; + + this(string[] v) { str = v[0]; } + this(string[string] v) { str = v.keys[0]; } +} + +S10635 s10635a = ["getnonce"]; +S10635 s10635b = ["getnonce" : "str"]; + +void test10635() +{ + S10635 sa = ["getnonce"]; + S10635 sb = ["getnonce" : "str"]; +} + +/***************************************************/ +// 8123 + +void test8123() +{ + struct S { } + + struct AS + { + alias S Alias; + } + + struct Wrapper + { + AS as; + } + + Wrapper w; + static assert(is(typeof(w.as).Alias == S)); // fail + static assert(is(AS.Alias == S)); // ok + static assert(is(typeof(w.as) == AS)); // ok + static assert(is(typeof(w.as).Alias == AS.Alias)); // fail +} + +/***************************************************/ +// 8147 + +enum A8147 { a, b, c } + +@property ref T front8147(T)(T[] a) +if (!is(T[] == void[])) +{ + return a[0]; +} + +template ElementType8147(R) +{ + static if (is(typeof({ R r = void; return r.front8147; }()) T)) + alias T ElementType8147; + else + alias void ElementType8147; +} + +void test8147() +{ + auto arr = [A8147.a]; + alias typeof(arr) R; + auto e = ElementType8147!R.init; +} + +/***************************************************/ +// 8410 + +void test8410() +{ + struct Foo { int[15] x; string s; } + + Foo[5] a1 = Foo([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "hello"); // OK + Foo f = { s: "hello" }; // OK (not static) + Foo[5] a2 = { s: "hello" }; // error +} + +/***************************************************/ +// 8942 + +alias const int A8942_0; +static assert(is(A8942_0 == const int)); // passes + +void test8942() +{ + alias const int A8942_1; + static assert(is(A8942_1 == const int)); // passes + + static struct S { int i; } + foreach (Unused; typeof(S.tupleof)) + { + alias const(int) A8942_2; + static assert(is(A8942_2 == const int)); // also passes + + alias const int A8942_3; + static assert(is(A8942_3 == const int)); // fails + // Error: static assert (is(int == const(int))) is false + } +} + +/***************************************************/ +// 10144 + +final class TNFA10144(char_t) +{ + enum Act { don } + const Act[] action_lookup1 = [ Act.don, ]; +} +alias X10144 = TNFA10144!char; + +class C10144 +{ + enum Act { don } + synchronized { enum x1 = [Act.don]; } + override { enum x2 = [Act.don]; } + abstract { enum x3 = [Act.don]; } + final { enum x4 = [Act.don]; } + synchronized { static s1 = [Act.don]; } + override { static s2 = [Act.don]; } + abstract { static s3 = [Act.don]; } + final { static s4 = [Act.don]; } + synchronized { __gshared gs1 = [Act.don]; } + override { __gshared gs2 = [Act.don]; } + abstract { __gshared gs3 = [Act.don]; } + final { __gshared gs4 = [Act.don]; } +} + +/***************************************************/ + +// 10142 + +class File10142 +{ + enum Access : ubyte { Read = 0x01 } + enum Open : ubyte { Exists = 0 } + enum Share : ubyte { None = 0 } + enum Cache : ubyte { None = 0x00 } + + struct Style + { + Access access; + Open open; + Share share; + Cache cache; + } + enum Style ReadExisting = { Access.Read, Open.Exists }; + + this (const(char[]) path, Style style = ReadExisting) + { + assert(style.access == Access.Read); + assert(style.open == Open .Exists); + assert(style.share == Share .None); + assert(style.cache == Cache .None); + } +} + +void test10142() +{ + auto f = new File10142("dummy"); +} + +/***************************************************/ +// 11421 + +void test11421() +{ + // AAs in array + const a1 = [[1:2], [3:4]]; // ok <- error + const int[int][] a2 = [[1:2], [3:4]]; // ok + static assert(is(typeof(a1) == typeof(a2))); + + // AAs in AA + auto aa = [1:["a":1.0], 2:["b":2.0]]; + static assert(is(typeof(aa) == double[string][int])); + assert(aa[1]["a"] == 1.0); + assert(aa[2]["b"] == 2.0); +} + +/***************************************************/ +// 13776 + +enum a13776(T) = __traits(compiles, { T; }); + +enum b13776(A...) = 1; + +template x13776s() +{ + struct S; + alias x13776s = b13776!(a13776!S); +} +template y13776s() +{ + struct S; + alias x2 = b13776!(a13776!S); + alias y13776s = x2; +} +template z13776s() +{ + struct S; + alias x1 = a13776!S; + alias x2 = b13776!(x1); + alias z13776s = x2; +} + +template x13776c() +{ + class C; + alias x13776c = b13776!(a13776!C); +} +template y13776c() +{ + class C; + alias x2 = b13776!(a13776!C); + alias y13776c = x2; +} +template z13776c() +{ + class C; + alias x1 = a13776!C; + alias x2 = b13776!(x1); + alias z13776c = x2; +} + +void test13776() +{ + alias xs = x13776s!(); // ok <- ng + alias ys = y13776s!(); // ok <- ng + alias zs = z13776s!(); // ok + + alias xc = x13776c!(); // ok <- ng + alias yc = y13776c!(); // ok <- ng + alias zc = z13776c!(); // ok +} + +/***************************************************/ +// 14090 + +template Packed14090(Args...) +{ + enum x = __traits(compiles, { Args[0] v; }); + // Args[0] is an opaque struct Empty, so the variable declaration fails to compile. + // The error message creation calls TypeStruct('_Empty')->toChars(), and + // it wrongly calls TemplateInstance('RoundRobin!()')->toAlias(). + // Finally it will cause incorrect "recursive template instantiation" error. +} + +template Map14090(A...) +{ + alias Map14090 = A[0]; +} + +template RoundRobin14090() +{ + struct Empty; + alias RoundRobin14090 = Map14090!(Packed14090!(Empty)); +} + +alias roundRobin14090 = RoundRobin14090!(); + +/***************************************************/ +// 13950 + +template Tuple13950(T...) { alias T Tuple13950; } + +void f13950(int x = 0, Tuple13950!() xs = Tuple13950!()) +{ + assert(x == 0); + assert(xs.length == 0); +} + +void test13950() +{ + f13950(); +} + +/***************************************************/ + +int main() +{ + test6475(); + test6905(); + test7019(); + test7239(); + test8123(); + test8147(); + test8410(); + test8942(); + test10142(); + test11421(); + test13950(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/delegate.d b/gcc/testsuite/gdc.test/runnable/delegate.d new file mode 100644 index 00000000000..a371e1cee3d --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/delegate.d @@ -0,0 +1,357 @@ +// REQUIRED_ARGS: + +import core.stdc.stdio; + +/********************************************************/ + +//int delegate(int, char[]) *p; + +class Foo +{ + int bar(int i, char[] s) { return 4; } +} + +class Bar : Foo +{ + override int bar(int i, char[] s) { return 5; } +} + +void test1() +{ + int delegate(int, char[]) dg; + Foo f = new Foo(); + Bar b = new Bar(); + int x; + + dg = &f.bar; + x = dg(3, null); + assert(x == 4); + + f = b; + dg = &f.bar; + x = dg(3, null); + assert(x == 5); +} + +/********************************************************/ + +int foo2() +{ + return 3; +} + +void test2() +{ + int function () fp; + + fp = &foo2; + assert(fp() == 3); +} + +/********************************************************/ + +class Foo3 +{ + int bar(int i, char[] s) { return 47; } + + void test() + { + int delegate(int, char[]) dg; + + dg = &bar; + printf("%d %d\n", dg(3, null), result()); + assert(dg(3, null) == result()); + + dg = &this.bar; + printf("%d %d\n", dg(3, null), result()); + assert(dg(3, null) == result()); + } + + int result() { return 47; } +} + +class Bar3 : Foo3 +{ + override int bar(int i, char[] s) { return 48; } + + override int result() { return 48; } + + void test2() + { + int delegate(int, char[]) dg; + + dg = &super.bar; + assert(dg(3, null) == 47); + } + +} + +void test3() +{ + Foo3 f = new Foo3(); + f.test(); + + Bar3 b = new Bar3(); + b.test(); + b.test2(); +} + +/********************************************************/ + + +int foo4(int x) { return 1; } +int foo4(char x) { return 2; } +int foo4(int x, int y) { return 3; } + +void test4() +{ + int function (char) fp; + + fp = &foo4; + assert(fp(0) == 2); +} + +/********************************************************/ + +class Abc +{ + int foo1(int x) { return 1; } + int foo1(char x) { return 2; } + int foo1(int x, int y) { return 3; } +} + +void test5() +{ + int delegate(char) dg; + Abc a = new Abc(); + + dg = &a.foo1; + assert(dg(0) == 2); +} + +/********************************************************/ + +int delegate(int) bar6; + +int[int delegate(int)] aa6; + +void test6() +{ + aa6[bar6] = 0; +} + +/********************************************************/ + +void foo7(void delegate(int) dg) +{ + dg(1); + //writefln("%s", dg(3)); +} + +void test7() +{ + foo7(delegate(int i) + { + printf("i = %d\n", i); + } + ); +} + +/********************************************************/ + +void foo8(int delegate(int) dg) +{ + printf("%d\n", dg(3)); + assert(dg(3) == 6); +} + +void test8() +{ + foo8(delegate(int i) + { + return i * 2; + } + ); +} + +/********************************************************/ + +void foo9(int delegate(int) dg) +{ + assert(dg(3) == 6); +} + +void test9() +{ + foo9( (int i) { return i * 2; } ); +} + +/********************************************************/ +// 8257 + +struct S8257 { + static int g() { + return 6; + } +} + +void test8257() +{ + S8257 s; + int w = 2; + S8257 func() { ++w; return s; } + auto k = &(func()).g; + // check that the call to func() still happened + assert(w == 3); + assert( k() == 6); +} + +auto f8257(string m)() { return &__traits(getMember, S8257.init, m); } +static assert (__traits(compiles, f8257!"g"())); + +/********************************************************/ + +void foo10(int delegate() dg) +{ + assert(dg() == 6); +} + +void test10() +{ int i = 3; + + foo10( { return i * 2; } ); +} + +/********************************************************/ + +class A12 +{ +public: + int delegate(int, int) dgs[4]; + int function(int, int) fps[4]; + int delegate(int, int) dg; + int function(int, int) fp; + int f(int x, int y) { + printf("here "); + int res = x + y; + printf("%d\n", res); + return res; + } + + void bug_1() { +// fp = &f; +// fp(1,2); + dg = &f; + dg(1,2); +// fps[] = [&f, &f, &f, &(f)]; // bug 1: this line shouldn't compile +// this.fps[0](1, 2); // seg-faults here! + + dgs[] = [&(f), &(f), &(f), &(f)]; // bug 1: why this line can't compile? + this.dgs[0](1, 2); + + dgs[] = [&(this.f), &(this.f), &(this.f), &(this.f)]; + this.dgs[0](1, 2); + } + +} + +void test12() +{ + A12 a = new A12(); + + a.bug_1(); +} + +/********************************************************/ +// 1570 + +class A13 +{ + int f() + { + return 1; + } +} + +class B13 : A13 +{ + override int f() + { + return 2; + } +} + +void test13() +{ + B13 b = new B13; + assert(b.f() == 2); + assert(b.A13.f() == 1); + assert((&b.f)() == 2); + assert((&b.A13.f)() == 1); +} + +/********************************************************/ +// 2472 + +class A2472 +{ + void foo() {} +} + +void test2472() +{ + auto a = new A2472; + auto fp1 = (&a.foo).funcptr; + auto dg = &a.foo; + auto fp2 = dg.funcptr; + assert(fp1 == fp2); +} + +/********************************************************/ + +void testAssign() +{ + static class C + { + int a; + this(int a) { this.a = a; } + int funca() { return a; } + int funcb() { return a + 1; } + } + + auto x = new C(5); + auto y = new C(7); + + auto dg = &x.funca; + assert(dg() == 5); + dg.funcptr = &C.funcb; + assert(dg() == 6); + dg.ptr = cast(void*)y; + assert(dg() == 8); + dg.funcptr = &C.funca; + assert(dg() == 7); +} + +/********************************************************/ + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test12(); + test13(); + test2472(); + test8257(); + testAssign(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/dhry.d b/gcc/testsuite/gdc.test/runnable/dhry.d new file mode 100644 index 00000000000..40f9ccff093 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/dhry.d @@ -0,0 +1,927 @@ +// PERMUTE_ARGS: +// REQUIRED_ARGS: -release -O -g -inline +// DISABLED: freebsd + +/* + ************************************************************************* + * + * "DHRYSTONE" Benchmark Program + * ----------------------------- + * + * Version: C, Version 2.1 + * + * File: dhry.h (part 1 of 3) + * + * Date: May 25, 1988 + * + * Author: Reinhold P. Weicker + * Siemens Nixdorf Inf. Syst. + * STM OS 32 + * Otto-Hahn-Ring 6 + * W-8000 Muenchen 83 + * Germany + * Phone: [+49]-89-636-42436 + * (8-17 Central European Time) + * UUCP: weicker@ztivax.uucp@unido.uucp + * Internet: weicker@ztivax.siemens.com + * + * Original Version (in Ada) published in + * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), + * pp. 1013 - 1030, together with the statistics + * on which the distribution of statements etc. is based. + * + * In this C version, the following C library functions are + * used: + * - strcpy, strcmp (inside the measurement loop) + * - printf, scanf (outside the measurement loop) + * + * Collection of Results: + * Reinhold Weicker (address see above) and + * + * Rick Richardson + * PC Research. Inc. + * 94 Apple Orchard Drive + * Tinton Falls, NJ 07724 + * Phone: (201) 834-1378 (9-17 EST) + * UUCP: ...!uunet!pcrat!rick + * + * Please send results to Rick Richardson and/or Reinhold Weicker. + * Complete information should be given on hardware and software + * used. Hardware information includes: Machine type, CPU, type and + * size of caches; for microprocessors: clock frequency, memory speed + * (number of wait states). Software information includes: Compiler + * (and runtime library) manufacturer and version, compilation + * switches, OS version. The Operating System version may give an + * indication about the compiler; Dhrystone itself performs no OS + * calls in the measurement loop. + * + * The complete output generated by the program should be mailed + * such that at least some checks for correctness can be made. + * + ************************************************************************* + * + * History: This version C/2.1 has been made for two reasons: + * + * 1) There is an obvious need for a common C version of + * Dhrystone, since C is at present the most popular system + * programming language for the class of processors + * (microcomputers, minicomputers) where Dhrystone is used + * most. There should be, as far as possible, only one C + * version of Dhrystone such that results can be compared + * without restrictions. In the past, the C versions + * distributed by Rick Richardson (Version 1.1) and by + * Reinhold Weicker had small (though not significant) + * differences. + * + * 2) As far as it is possible without changes to the + * Dhrystone statistics, optimizing compilers should be + * prevented from removing significant statements. + * + * This C version has been developed in cooperation with + * Rick Richardson (Tinton Falls, NJ), it incorporates many + * ideas from the "Version 1.1" distributed previously by + * him over the UNIX network Usenet. + * I also thank Chaim Benedelac (National Semiconductor), + * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), + * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) + * for their help with comments on earlier versions of the + * benchmark. + * + * Changes: In the initialization part, this version follows mostly + * Rick Richardson's version distributed via Usenet, not the + * version distributed earlier via floppy disk by Reinhold + * Weicker. As a concession to older compilers, names have + * been made unique within the first 8 characters. Inside the + * measurement loop, this version follows the version + * previously distributed by Reinhold Weicker. + * + * At several places in the benchmark, code has been added, + * but within the measurement loop only in branches that + * are not executed. The intention is that optimizing + * compilers should be prevented from moving code out of the + * measurement loop, or from removing code altogether. Since + * the statements that are executed within the measurement + * loop have NOT been changed, the numbers defining the + * "Dhrystone distribution" (distribution of statements, + * operand types and locality) still hold. Except for + * sophisticated optimizing compilers, execution times for + * this version should be the same as for previous versions. + * + * Since it has proven difficult to subtract the time for the + * measurement loop overhead in a correct way, the loop check + * has been made a part of the benchmark. This does have + * an impact - though a very minor one - on the distribution + * statistics which have been updated for this version. + * + * All changes within the measurement loop are described + * and discussed in the companion paper "Rationale for + * Dhrystone version 2". + * + * Because of the self-imposed limitation that the order and + * distribution of the executed statements should not be + * changed, there are still cases where optimizing compilers + * may not generate code for some statements. To a certain + * degree, this is unavoidable for small synthetic + * benchmarks. Users of the benchmark are advised to check + * code listings whether code is generated for all statements + * of Dhrystone. + * + * Version 2.1 is identical to version 2.0 distributed via + * the UNIX network Usenet in March 1988 except that it + * corrects some minor deficiencies that were found by users + * of version 2.0. The only change within the measurement + * loop is that a non-executed "else" part was added to the + * "if" statement in Func_3, and a non-executed "else" part + * removed from Proc_3. + * + ************************************************************************* + * + * Defines: The following "Defines" are possible: + * -DROPT (default: Not defined) + * As an approximation to what an average C + * programmer might do, the "register" storage class + * is applied (if enabled by -DROPT) + * - for local variables, if they are used + * (dynamically) five or more times + * - for parameters if they are used (dynamically) + * six or more times + * Note that an optimal "register" strategy is + * compiler-dependent, and that "register" + * declarations do not necessarily lead to faster + * execution. + * -DNOSTRUCTASSIGN (default: Not defined) + * Define if the C compiler does not support + * assignment of structures. + * -DNOENUMS (default: Not defined) + * Define if the C compiler does not support + * enumeration types. + * + ************************************************************************* + * + * Compilation model and measurement (IMPORTANT): + * + * This C version of Dhrystone consists of three files: + * - dhry.h (this file, containing global definitions and comments) + * - dhry_1.c (containing the code corresponding to Ada package Pack_1) + * - dhry_2.c (containing the code corresponding to Ada package Pack_2) + * + * The following "ground rules" apply for measurements: + * - Separate compilation + * - No procedure merging + * - Otherwise, compiler optimizations are allowed but should be + * indicated + * - Default results are those without register declarations + * See the companion paper "Rationale for Dhrystone Version 2" for a more + * detailed discussion of these ground rules. + * + * For 16-Bit processors (e.g. 80186, 80286), times for all compilation + * models ("small", "medium", "large" etc.) should be given if possible, + * together with a definition of these models for the compiler system + * used. + * + ************************************************************************* + * + * Dhrystone (C version) statistics: + * + * [Comment from the first distribution, updated for version 2. + * Note that because of language differences, the numbers are slightly + * different from the Ada version.] + * + * The following program contains statements of a high level programming + * language (here: C) in a distribution considered representative: + * + * assignments 52 (51.0 %) + * control statements 33 (32.4 %) + * procedure, function calls 17 (16.7 %) + * + * 103 statements are dynamically executed. The program is balanced with + * respect to the three aspects: + * + * - statement type + * - operand type + * - operand locality + * operand global, local, parameter, or constant. + * + * The combination of these three aspects is balanced only approximately. + * + * 1. Statement Type: + * ----------------- number + * + * V1 = V2 9 + * (incl. V1 = F(..) + * V = Constant 12 + * Assignment, 7 + * with array element + * Assignment, 6 + * with record component + * -- + * 34 34 + * + * X = Y +|-|"&&"|"|" Z 5 + * X = Y +|-|"==" Constant 6 + * X = X +|- 1 3 + * X = Y *|/ Z 2 + * X = Expression, 1 + * two operators + * X = Expression, 1 + * three operators + * -- + * 18 18 + * + * if .... 14 + * with "else" 7 + * without "else" 7 + * executed 3 + * not executed 4 + * for ... 7 | counted every time + * while ... 4 | the loop condition + * do ... while 1 | is evaluated + * switch ... 1 + * break 1 + * declaration with 1 + * initialization + * -- + * 34 34 + * + * P (...) procedure call 11 + * user procedure 10 + * library procedure 1 + * X = F (...) + * function call 6 + * user function 5 + * library function 1 + * -- + * 17 17 + * --- + * 103 + * + * The average number of parameters in procedure or function calls + * is 1.82 (not counting the function values as implicit parameters). + * + * + * 2. Operators + * ------------ + * number approximate + * percentage + * + * Arithmetic 32 50.8 + * + * + 21 33.3 + * - 7 11.1 + * * 3 4.8 + * / (int div) 1 1.6 + * + * Comparison 27 42.8 + * + * == 9 14.3 + * /= 4 6.3 + * > 1 1.6 + * < 3 4.8 + * >= 1 1.6 + * <= 9 14.3 + * + * Logic 4 6.3 + * + * && (AND-THEN) 1 1.6 + * | (OR) 1 1.6 + * ! (NOT) 2 3.2 + * + * -- ----- + * 63 100.1 + * + * + * 3. Operand Type (counted once per operand reference): + * --------------- + * number approximate + * percentage + * + * Integer 175 72.3 % + * Character 45 18.6 % + * Pointer 12 5.0 % + * String30 6 2.5 % + * Array 2 0.8 % + * Record 2 0.8 % + * --- ------- + * 242 100.0 % + * + * When there is an access path leading to the final operand (e.g. a + * record component), only the final data type on the access path is + * counted. + * + * + * 4. Operand Locality: + * ------------------- + * number approximate + * percentage + * + * local variable 114 47.1 % + * global variable 22 9.1 % + * parameter 45 18.6 % + * value 23 9.5 % + * reference 22 9.1 % + * function result 6 2.5 % + * constant 55 22.7 % + * --- ------- + * 242 100.0 % + * + * + * The program does not compute anything meaningful, but it is + * syntactically and semantically correct. All variables have a value + * assigned to them before they are used as a source operand. + * + * There has been no explicit effort to account for the effects of a + * cache, or to balance the use of long or short displacements for code + * or data. + * + ************************************************************************* + */ + +import core.stdc.stdio; +import core.stdc.string; +import core.stdc.stdlib; +import std.string; + + +/* Compiler and system dependent definitions: */ + +const double Mic_secs_Per_Second = 1000000.0; + /* Berkeley UNIX C returns process times in seconds/HZ */ + +enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} +alias int Enumeration; + /* for boolean and enumeration types in Ada, Pascal */ + +/* General definitions: */ + +const int StrLen = 30; + +alias int One_Thirty; +alias int One_Fifty; +alias char Capital_Letter; +alias bool Boolean; +alias char Str_30 [StrLen]; +alias int Arr_1_Dim [50]; +alias int Arr_2_Dim [50] [50]; + +struct record +{ + record *Ptr_Comp; + Enumeration Discr; + union V { + struct V1 { + Enumeration Enum_Comp; + int Int_Comp; + char Str_Comp [StrLen]; + } + V1 var_1; + struct V2 { + Enumeration E_Comp_2; + char Str_2_Comp [StrLen]; + } + V2 var_2; + struct V3 { + char Ch_1_Comp; + char Ch_2_Comp; + } + V3 var_3; + } + V variant; +} + +alias record Rec_Type; +alias record *Rec_Pointer; + + +/* Global Variables: */ + +Rec_Pointer Ptr_Glob, + Next_Ptr_Glob; +int Int_Glob; +Boolean Bool_Glob; +char Ch_1_Glob, + Ch_2_Glob; +int Arr_1_Glob [50]; +int Arr_2_Glob [50] [50]; + +char[StrLen] Reg_Define = "Register option selected."; + +/* variables for time measurement: */ + +const int Too_Small_Time = 2; + /* Measurements should last at least 2 seconds */ + +double Begin_Time, + End_Time, + User_Time; + +double Microseconds, + Dhrystones_Per_Second, + Vax_Mips; + +/* end of variables for time measurement */ + + +void main () +/*****/ + + /* main program, corresponds to procedures */ + /* Main and Proc_0 in the Ada version */ +{ + One_Fifty Int_1_Loc; + One_Fifty Int_2_Loc; + One_Fifty Int_3_Loc; + char Ch_Index; + Enumeration Enum_Loc; + Str_30 Str_1_Loc; + Str_30 Str_2_Loc; + int Run_Index; + int Number_Of_Runs; + +/+ + FILE *Ap; + + /* Initializations */ + + if ((Ap = fopen("dhry.res","a+")) == null) + { + printf("Can not open dhry.res\n\n"); + exit(1); + } ++/ + + Next_Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); + Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); + + Ptr_Glob.Ptr_Comp = Next_Ptr_Glob; + Ptr_Glob.Discr = Ident_1; + Ptr_Glob.variant.var_1.Enum_Comp = Ident_3; + Ptr_Glob.variant.var_1.Int_Comp = 40; +// strcpy (Ptr_Glob.variant.var_1.Str_Comp, +// "DHRYSTONE PROGRAM, SOME STRING"); +// strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); + Ptr_Glob.variant.var_1.Str_Comp[] = "DHRYSTONE PROGRAM, SOME STRING"; + Str_1_Loc[] = "DHRYSTONE PROGRAM, 1'ST STRING"; + + Arr_2_Glob [8][7] = 10; + /* Was missing in published program. Without this statement, */ + /* Arr_2_Glob [8][7] would have an undefined value. */ + /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ + /* overflow may occur for this array element. */ + + printf ("\n"); + printf ("Dhrystone Benchmark, Version 2.1 (Language: D)\n"); + printf ("\n"); + printf ("Please give the number of runs through the benchmark: "); + { + int n; + //scanf ("%d", &n); + n = 10000000; + Number_Of_Runs = n; + } + printf ("\n"); + + printf ("Execution starts, %d runs through Dhrystone\n",Number_Of_Runs); + + /***************/ + /* Start timer */ + /***************/ + + Begin_Time = dtime(); + + for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) + { + + Proc_5(); + Proc_4(); + /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ + Int_1_Loc = 2; + Int_2_Loc = 3; + //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); + Str_2_Loc[] = "DHRYSTONE PROGRAM, 2'ND STRING"; + Enum_Loc = Ident_2; + Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); + /* Bool_Glob == 1 */ + while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ + { + Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; + /* Int_3_Loc == 7 */ + Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); + /* Int_3_Loc == 7 */ + Int_1_Loc += 1; + } /* while */ + /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ + Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); + /* Int_Glob == 5 */ + Proc_1 (Ptr_Glob); + for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) + /* loop body executed twice */ + { + if (Enum_Loc == Func_1 (Ch_Index, 'C')) + /* then, not executed */ + { + Proc_6 (Ident_1, &Enum_Loc); + //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); + Str_2_Loc[] = "DHRYSTONE PROGRAM, 3'RD STRING"; + Int_2_Loc = Run_Index; + Int_Glob = Run_Index; + } + } + /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ + Int_2_Loc = Int_2_Loc * Int_1_Loc; + Int_1_Loc = Int_2_Loc / Int_3_Loc; + Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; + /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ + Proc_2 (&Int_1_Loc); + /* Int_1_Loc == 5 */ + + } /* loop "for Run_Index" */ + + /**************/ + /* Stop timer */ + /**************/ + + End_Time = dtime(); + + printf ("Execution ends\n"); + printf ("\n"); + printf ("Final values of the variables used in the benchmark:\n"); + printf ("\n"); + printf ("Int_Glob: %d\n", Int_Glob); + printf (" should be: %d\n", 5); + printf ("Bool_Glob: %d\n", Bool_Glob); + printf (" should be: %d\n", 1); + printf ("Ch_1_Glob: %c\n", Ch_1_Glob); + printf (" should be: %c\n", cast(int)'A'); + printf ("Ch_2_Glob: %c\n", Ch_2_Glob); + printf (" should be: %c\n", cast(int)'B'); + printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); + printf (" should be: %d\n", 7); + printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); + printf (" should be: Number_Of_Runs + 10\n"); + printf ("Ptr_Glob.\n"); + printf (" Ptr_Comp: %d\n", cast(int) Ptr_Glob.Ptr_Comp); + printf (" should be: (implementation-dependent)\n"); + printf (" Discr: %d\n", Ptr_Glob.Discr); + printf (" should be: %d\n", 0); + printf (" Enum_Comp: %d\n", Ptr_Glob.variant.var_1.Enum_Comp); + printf (" should be: %d\n", 2); + printf (" Int_Comp: %d\n", Ptr_Glob.variant.var_1.Int_Comp); + printf (" should be: %d\n", 17); + printf (" Str_Comp: %.*s\n", Ptr_Glob.variant.var_1.Str_Comp.length, Ptr_Glob.variant.var_1.Str_Comp.ptr); + printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); + printf ("Next_Ptr_Glob.\n"); + printf (" Ptr_Comp: %d\n", cast(int) Next_Ptr_Glob.Ptr_Comp); + printf (" should be: (implementation-dependent), same as above\n"); + printf (" Discr: %d\n", Next_Ptr_Glob.Discr); + printf (" should be: %d\n", 0); + printf (" Enum_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Enum_Comp); + printf (" should be: %d\n", 1); + printf (" Int_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Int_Comp); + printf (" should be: %d\n", 18); + printf (" Str_Comp: %.*s\n", Next_Ptr_Glob.variant.var_1.Str_Comp.length, Next_Ptr_Glob.variant.var_1.Str_Comp.ptr); + printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); + printf ("Int_1_Loc: %d\n", Int_1_Loc); + printf (" should be: %d\n", 5); + printf ("Int_2_Loc: %d\n", Int_2_Loc); + printf (" should be: %d\n", 13); + printf ("Int_3_Loc: %d\n", Int_3_Loc); + printf (" should be: %d\n", 7); + printf ("Enum_Loc: %d\n", Enum_Loc); + printf (" should be: %d\n", 1); + printf ("Str_1_Loc: %.*s\n", Str_1_Loc.length, Str_1_Loc.ptr); + printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); + printf ("Str_2_Loc: %.*s\n", Str_2_Loc.length, Str_2_Loc.ptr); + printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); + printf ("\n"); + + User_Time = End_Time - Begin_Time; + + if (User_Time < Too_Small_Time) + { + printf ("Measured time too small to obtain meaningful results\n"); + printf ("Please increase number of runs\n"); + printf ("\n"); + } + else + { + Microseconds = User_Time * Mic_secs_Per_Second + / cast(double) Number_Of_Runs; + Dhrystones_Per_Second = cast(double) Number_Of_Runs / User_Time; + Vax_Mips = Dhrystones_Per_Second / 1757.0; + + printf ("Register option selected? NO\n"); + strcpy(Reg_Define.ptr, "Register option not selected."); + printf ("Microseconds for one run through Dhrystone: "); + printf ("%7.1lf \n", Microseconds); + printf ("Dhrystones per Second: "); + printf ("%10.1lf \n", Dhrystones_Per_Second); + printf ("VAX MIPS rating = %10.3lf \n",Vax_Mips); + printf ("\n"); + + /+ + fprintf(Ap,"\n"); + fprintf(Ap,"Dhrystone Benchmark, Version 2.1 (Language: D)\n"); + fprintf(Ap,"%.*s\n",Reg_Define.length, Reg_Define.ptr); + fprintf(Ap,"Microseconds for one loop: %7.1lf\n",Microseconds); + fprintf(Ap,"Dhrystones per second: %10.1lf\n",Dhrystones_Per_Second); + fprintf(Ap,"VAX MIPS rating: %10.3lf\n",Vax_Mips); + fclose(Ap); + +/ + + } + +} + +void Proc_1 (Rec_Pointer Ptr_Val_Par) +/******************/ + + /* executed once */ +{ + Rec_Pointer Next_Record = Ptr_Val_Par.Ptr_Comp; + /* == Ptr_Glob_Next */ + /* Local variable, initialized with Ptr_Val_Par.Ptr_Comp, */ + /* corresponds to "rename" in Ada, "with" in Pascal */ + + *Ptr_Val_Par.Ptr_Comp = *Ptr_Glob; + Ptr_Val_Par.variant.var_1.Int_Comp = 5; + Next_Record.variant.var_1.Int_Comp + = Ptr_Val_Par.variant.var_1.Int_Comp; + Next_Record.Ptr_Comp = Ptr_Val_Par.Ptr_Comp; + Proc_3 (&Next_Record.Ptr_Comp); + /* Ptr_Val_Par.Ptr_Comp.Ptr_Comp + == Ptr_Glob.Ptr_Comp */ + if (Next_Record.Discr == Ident_1) + /* then, executed */ + { + Next_Record.variant.var_1.Int_Comp = 6; + Proc_6 (Ptr_Val_Par.variant.var_1.Enum_Comp, + &Next_Record.variant.var_1.Enum_Comp); + Next_Record.Ptr_Comp = Ptr_Glob.Ptr_Comp; + Proc_7 (Next_Record.variant.var_1.Int_Comp, 10, + &Next_Record.variant.var_1.Int_Comp); + } + else /* not executed */ + *Ptr_Val_Par = *Ptr_Val_Par.Ptr_Comp; +} /* Proc_1 */ + +void Proc_2 (One_Fifty *Int_Par_Ref) +/******************/ + /* executed once */ + /* *Int_Par_Ref == 1, becomes 4 */ +{ + One_Fifty Int_Loc; + Enumeration Enum_Loc; + + Int_Loc = *Int_Par_Ref + 10; + do /* executed once */ + if (Ch_1_Glob == 'A') + /* then, executed */ + { + Int_Loc -= 1; + *Int_Par_Ref = Int_Loc - Int_Glob; + Enum_Loc = Ident_1; + } /* if */ + while (Enum_Loc != Ident_1); /* true */ +} /* Proc_2 */ + + +void Proc_3 (Rec_Pointer *Ptr_Ref_Par) +/******************/ + /* executed once */ + /* Ptr_Ref_Par becomes Ptr_Glob */ + +{ + if (Ptr_Glob != null) + /* then, executed */ + *Ptr_Ref_Par = Ptr_Glob.Ptr_Comp; + Proc_7 (10, Int_Glob, &Ptr_Glob.variant.var_1.Int_Comp); +} /* Proc_3 */ + +void Proc_4 () /* without parameters */ +/*******/ + /* executed once */ +{ + Boolean Bool_Loc; + + Bool_Loc = Ch_1_Glob == 'A'; + Bool_Glob = Bool_Loc | Bool_Glob; + Ch_2_Glob = 'B'; +} /* Proc_4 */ + + +void Proc_5 () /* without parameters */ +/*******/ + /* executed once */ +{ + Ch_1_Glob = 'A'; + Bool_Glob = false; +} /* Proc_5 */ + + +void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par) +/*********************************/ + /* executed once */ + /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ +{ + *Enum_Ref_Par = Enum_Val_Par; + if (! Func_3 (Enum_Val_Par)) + /* then, not executed */ + *Enum_Ref_Par = Ident_4; + final switch (Enum_Val_Par) + { + case Ident_1: + *Enum_Ref_Par = Ident_1; + break; + case Ident_2: + if (Int_Glob > 100) + /* then */ + *Enum_Ref_Par = Ident_1; + else *Enum_Ref_Par = Ident_4; + break; + case Ident_3: /* executed */ + *Enum_Ref_Par = Ident_2; + break; + case Ident_4: break; + case Ident_5: + *Enum_Ref_Par = Ident_3; + break; + } /* switch */ +} /* Proc_6 */ + + +void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref) +/**********************************************/ + /* executed three times */ + /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ + /* Int_Par_Ref becomes 7 */ + /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ + /* Int_Par_Ref becomes 17 */ + /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ + /* Int_Par_Ref becomes 18 */ +{ + One_Fifty Int_Loc; + + Int_Loc = Int_1_Par_Val + 2; + *Int_Par_Ref = Int_2_Par_Val + Int_Loc; +} /* Proc_7 */ + + +void Proc_8 (ref Arr_1_Dim Arr_1_Par_Ref, ref Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val) +/*********************************************************************/ + /* executed once */ + /* Int_Par_Val_1 == 3 */ + /* Int_Par_Val_2 == 7 */ +{ + One_Fifty Int_Index; + One_Fifty Int_Loc; + + Int_Loc = Int_1_Par_Val + 5; + Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; + Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; + Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; + for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) + Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; + Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; + Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; + Int_Glob = 5; +} /* Proc_8 */ + + +Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val) +/*************************************************/ + /* executed three times */ + /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ + /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ + /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ +{ + Capital_Letter Ch_1_Loc; + Capital_Letter Ch_2_Loc; + + Ch_1_Loc = Ch_1_Par_Val; + Ch_2_Loc = Ch_1_Loc; + if (Ch_2_Loc != Ch_2_Par_Val) + /* then, executed */ + return (Ident_1); + else /* not executed */ + { + Ch_1_Glob = Ch_1_Loc; + return (Ident_2); + } +} /* Func_1 */ + + +Boolean Func_2 (Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref) +/*************************************************/ + /* executed once */ + /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ + /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ +{ + One_Thirty Int_Loc; + Capital_Letter Ch_Loc; + + Int_Loc = 2; + while (Int_Loc <= 2) /* loop body executed once */ + if (Func_1 (Str_1_Par_Ref[Int_Loc], + Str_2_Par_Ref[Int_Loc+1]) == Ident_1) + /* then, executed */ + { + Ch_Loc = 'A'; + Int_Loc += 1; + } /* if, while */ + if (Ch_Loc >= 'W' && Ch_Loc < 'Z') + /* then, not executed */ + Int_Loc = 7; + if (Ch_Loc == 'R') + /* then, not executed */ + return (true); + else /* executed */ + { + //if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) + //if (memcmp (Str_1_Par_Ref, Str_2_Par_Ref, 30) > 0) + if (Str_1_Par_Ref > Str_2_Par_Ref) + /* then, not executed */ + { + Int_Loc += 7; + Int_Glob = Int_Loc; + return (true); + } + else /* executed */ + return (false); + } /* if Ch_Loc */ +} /* Func_2 */ + + +Boolean Func_3 (Enumeration Enum_Par_Val) +/***************************/ + /* executed once */ + /* Enum_Par_Val == Ident_3 */ +{ + Enumeration Enum_Loc; + + Enum_Loc = Enum_Par_Val; + if (Enum_Loc == Ident_3) + /* then, executed */ + return (true); + else /* not executed */ + return (false); +} /* Func_3 */ + +version (Windows) +{ + import core.sys.windows.windows; + + double dtime() + { + double q; + + q = cast(double)GetTickCount() * 1.0e-03; + + return q; + } +} + +version (linux) +{ + import core.stdc.time; + + double dtime() + { + double q; + + q = cast(double)time(null); + + return q; + } +} + +version (OSX) // supplied by Anders F Bjorklund +{ + import core.sys.posix.sys.time; + + double dtime() + { + double q; + timeval tv; + + gettimeofday(&tv,null); + q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6; + + return q; + } +} + +version (NetBSD) +{ + import core.sys.posix.sys.time; + + double dtime() + { + double q; + timeval tv; + + gettimeofday(&tv,null); + q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6; + + return q; + } +} diff --git a/gcc/testsuite/gdc.test/runnable/eh.d b/gcc/testsuite/gdc.test/runnable/eh.d new file mode 100644 index 00000000000..b3077a2e96f --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/eh.d @@ -0,0 +1,866 @@ +// PERMUTE_ARGS: -O -fPIC + +extern(C) int printf(const char*, ...); + +/****************************************************/ + +class Abc : Exception +{ + this() + { + super(""); + } + int i; +} + +int y; + +alias int boo; + +void foo(int x) +{ + y = cast(boo)1; +L6: + try + { + printf("try 1\n"); + y += 4; + if (y == 5) + goto L6; + y += 3; + } + finally + { + y += 5; + printf("finally 1\n"); + } + try + { + printf("try 2\n"); + y = 1; + if (y == 4) + goto L6; + y++; + } + catch (Abc c) + { + printf("catch 2\n"); + y = 2 + c.i; + } + y++; + printf("done\n"); +} + +/****************************************************/ + + +class IntException : Exception +{ + this(int i) + { + m_i = i; + super(""); + } + + int getValue() + { + return m_i; + } + + int m_i; +} + + +void test2() +{ + int cIterations = 10; + + int i; + long total_x = 0; + long total_nox = 0; + + for(int WARMUPS = 2; WARMUPS-- > 0; ) + { + for(total_x = 0, i = 0; i < cIterations; ++i) + { + total_nox += fn2_nox(); + } +printf("foo\n"); + + for(total_nox = 0, i = 0; i < cIterations; ++i) + { +printf("i = %d\n", i); + try + { + int z = 1; + + throw new IntException(z); + } + catch(IntException x) + { +printf("catch, i = %d\n", i); + total_x += x.getValue(); + } + } + } + + printf("iterations %d totals: %ld, %ld\n", cIterations, total_x, total_nox); +} + +int fn2_nox() +{ + return 47; +} + + +/****************************************************/ + +void test3() +{ + static int x; + try + { + } + finally + { + printf("a\n"); + assert(x == 0); + x++; + } + printf("--\n"); + assert(x == 1); + try + { + printf("tb\n"); + assert(x == 1); + } + finally + { + printf("b\n"); + assert(x == 1); + x++; + } + assert(x == 2); +} + +/****************************************************/ + +class Tester +{ + this(void delegate() dg_) { dg = dg_; } + void delegate() dg; + void stuff() { dg(); } +} + +void test4() +{ + printf("Starting test\n"); + + int a = 0; + int b = 0; + int c = 0; + int d = 0; + + try + { + a++; + throw new Exception("test1"); + a++; + } + catch(Exception e) + { + auto es = e.toString(); + printf("%.*s\n", es.length, es.ptr); + b++; + } + finally + { + c++; + } + + printf("initial test.\n"); + + assert(a == 1); + assert(b == 1); + assert(c == 1); + + printf("pass\n"); + + Tester t = new Tester( + delegate void() + { + try + { + a++; + throw new Exception("test2"); + a++; + } + catch(Exception e) + { + b++; + throw e; + b++; + } + }); + + try + { + c++; + t.stuff(); + c++; + } + catch(Exception e) + { + d++; + string es = e.toString; + printf("%.*s\n", es.length, es.ptr); + } + + assert(a == 2); + assert(b == 2); + assert(c == 2); + assert(d == 1); + + + int q0 = 0; + int q1 = 0; + int q2 = 0; + int q3 = 0; + + Tester t2 = new Tester( + delegate void() + { + try + { + q0++; + throw new Exception("test3"); + q0++; + } + catch(Exception e) + { + printf("Never called.\n"); + q1++; + throw e; + q1++; + } + }); + + try + { + q2++; + t2.stuff(); + q2++; + } + catch(Exception e) + { + q3++; + string es = e.toString; + printf("%.*s\n", es.length, es.ptr); + } + + assert(q0 == 1); + assert(q1 == 1); + assert(q2 == 1); + assert(q3 == 1); + + printf("Passed!\n"); +} + +/****************************************************/ + +void test5() +{ + char[] result; + int i = 3; + while(i--) + { + try + { + printf("i: %d\n", i); + result ~= 't'; + if (i == 1) + continue; + } + finally + { + printf("finally\n"); + result ~= cast(char)('a' + i); + } + } + printf("--- %.*s", result.length, result.ptr); + if (result != "tctbta") + assert(0); +} + +/****************************************************/ + +void test6() +{ + char[] result; + + while (true) + { + try + { + printf("one\n"); + result ~= 'a'; + break; + } + finally + { + printf("two\n"); + result ~= 'b'; + } + } + printf("three\n"); + result ~= 'c'; + if (result != "abc") + assert(0); +} + +/****************************************************/ + +string a7; + +void doScan(int i) +{ + a7 ~= "a"; + try + { + try + { + a7 ~= "b"; + return; + } + finally + { + a7 ~= "c"; + } + } + finally + { + a7 ~= "d"; + } +} + +void test7() +{ + doScan(0); + assert(a7 == "abcd"); +} + + +/**************************************************** + * Exception chaining tests. See also test4.d + ****************************************************/ +int result1513; + +void bug1513a() +{ + throw new Exception("d"); +} + +void bug1513b() +{ + try + { + try + { + bug1513a(); + } + finally + { + result1513 |=4; + throw new Exception("f"); + } + } + catch(Exception e) + { + assert(e.msg == "d"); + assert(e.next.msg == "f"); + assert(!e.next.next); + } +} + +void bug1513c() +{ + try + { + try + { + throw new Exception("a"); + } + finally + { + result1513 |= 1; + throw new Exception("b"); + } + } + finally + { + bug1513b(); + result1513 |= 2; + throw new Exception("c"); + } +} + +void bug1513() +{ + result1513 = 0; + try + { + bug1513c(); + } + catch(Exception e) + { + assert(result1513 == 7); + assert(e.msg == "a"); + assert(e.next.msg == "b"); + assert(e.next.next.msg == "c"); + } +} + +void collideone() +{ + try + { + throw new Exception("x"); + } + finally + { + throw new Exception("y"); + } +} + +void doublecollide() +{ + try + { + try + { + try + { + throw new Exception("p"); + } + finally + { + throw new Exception("q"); + } + } + finally + { + collideone(); + } + } + catch(Exception e) + { + assert(e.msg == "p"); + assert(e.next.msg == "q"); + assert(e.next.next.msg == "x"); + assert(e.next.next.next.msg == "y"); + assert(!e.next.next.next.next); + } +} + +void collidetwo() +{ + try + { + try + { + throw new Exception("p2"); + } + finally + { + throw new Exception("q2"); + } + } + finally + { + collideone(); + } +} + +void collideMixed() +{ + int works = 6; + try + { + try + { + try + { + throw new Exception("e"); + } + finally + { + throw new Error("t"); + } + } + catch(Exception f) + { // Doesn't catch, because Error is chained to it. + works += 2; + } + } + catch(Error z) + { + works += 4; + assert(z.msg=="t"); // Error comes first + assert(z.next is null); + assert(z.bypassedException.msg == "e"); + } + assert(works == 10); +} + +class AnotherException : Exception +{ + this(string s) + { + super(s); + } +} + +void multicollide() +{ + try + { + try + { + try + { + try + { + throw new Exception("m2"); + } + finally + { + throw new AnotherException("n2"); + } + } + catch(AnotherException s) + { // Not caught -- we needed to catch the root cause "m2", not + // just the collateral "n2" (which would leave m2 uncaught). + assert(0); + } + } + finally + { + collidetwo(); + } + } + catch(Exception f) + { + assert(f.msg == "m2"); + assert(f.next.msg == "n2"); + Throwable e = f.next.next; + assert(e.msg == "p2"); + assert(e.next.msg == "q2"); + assert(e.next.next.msg == "x"); + assert(e.next.next.next.msg == "y"); + assert(!e.next.next.next.next); + } +} + +/****************************************************/ + +void use9568(char [] x, char [] y) {} + +int bug9568() +{ + try + return 7; + finally + use9568(null,null); +} + +void test9568() +{ + assert( bug9568() == 7 ); +} + +/****************************************************/ + +version (DigitalMars) +{ +void test8a() +{ + int a; + goto L2; // L2 is not addressable. + + try { + a += 2; + } + catch (Exception) { + a += 3; +L2: ; + a += 100; + } + assert(a == 100); +} + +void test8b() +{ + int a; + goto L2; // L2 is not addressable. + + try { + } + catch (Exception) { + a += 3; +L2: ; + a += 100; + } + assert(a == 100); +} + +void test8c() +{ + int a; + goto L2; // L2 is not addressable. + + try + static assert(true); + catch (Exception) { + a += 3; +L2: ; + a += 100; + } + assert(a == 100); +} + +void test8() +{ + test8a(); + test8b(); + test8c(); +} +} + +/****************************************************/ + +uint foo9(uint i) +{ + try + { + ++i; + return 3; + } + catch (Exception e) + { + debug printf("Exception happened\n"); + } + return 4; +} + +void test9() +{ + assert(foo9(7) == 3); +} + +/****************************************************/ +// 10964 + +void test10964() +{ + static struct S + { + this(this) + { + throw new Exception("BOOM!"); + } + } + + S ss; + S[1] sa; + int result; + + result = 0; + try + { + ss = ss; + } + catch (Exception e) result = 1; + catch (Error e) result = 2; + catch (Throwable e) result = 3; + assert(result == 1); + + try + { + sa = ss; + } + catch (Exception e) result = 1; + catch (Error e) result = 2; + catch (Throwable e) result = 3; + assert(result == 1); + + try + { + sa = sa; + } + catch (Exception e) result = 1; + catch (Error e) result = 2; + catch (Throwable e) result = 3; + assert(result == 1); +} + +/****************************************************/ + +alias Action = void delegate(); + +class A10 +{ + invariant() + { + } + + public Action foo(Action a) + { + synchronized + { + B10 elements = new B10; + Action[] actions = [a]; + + elements.bar(actions); + + if (actions.length > 1) + elements.bar(actions); + return actions[0]; + } + return null; + } +} + +class B10 +{ + public bool bar(ref Action[]) + { + return false; + } +} + +class D10 +{ + void baz() + { + } +} + +void test12989() +{ + auto a = new A10; + auto d = new D10; + + assert(a.foo(&d.baz) == &d.baz); +} + +/****************************************************/ + +int bar10(int c) +{ + if (c <= 0xFFFF) + { + L3: + return 3; + } + throw new Exception("msg"); + goto L3; +} + +void test10() +{ + int x; + try + { + bar10(0x110000); + } + catch (Exception e) + { + printf("caught\n"); + x = 1; + } + assert(x == 1); + printf("test10 success\n"); +} + +/****************************************************/ + +class ParseException : Exception +{ + @safe pure nothrow this( string msg ) + { + super( msg ); + } +} + +class OverflowException : Exception +{ + @safe pure nothrow this( string msg ) + { + super( msg ); + } +} + +void test11() +{ + int x; + try + { + printf("test11()\n"); + throw new ParseException("msg"); + } + catch( OverflowException e ) + { + printf( "catch OverflowException\n" ); + } + catch( ParseException e ) + { + printf( "catch ParseException: %.*s\n", cast(int) e.msg.length, e.msg.ptr ); + x = 1; + } + assert(x == 1); +} + +/****************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=17481 + +class C17481 +{ + synchronized void trigger(){ new ubyte[1]; } +} + +void test17481() +{ + auto k = new shared C17481; + k.trigger; +} + +/****************************************************/ + +int main() +{ + printf("start\n"); + foo(3); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + + bug1513(); + doublecollide(); + collideMixed(); + multicollide(); + test9568(); + + version(DigitalMars) test8(); + test9(); + test10964(); + test12989(); + test10(); + test11(); + test17481(); + + printf("finish\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/eh2.d b/gcc/testsuite/gdc.test/runnable/eh2.d new file mode 100644 index 00000000000..dc285a5dfab --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/eh2.d @@ -0,0 +1,85 @@ +// PERMUTE_ARGS: -fPIC + +extern(C) int printf(const char*, ...); + +class Abc : Throwable +{ + this() pure + { + super(""); + } + static int x; + int a,b,c; + + synchronized void test() + { + printf("test 1\n"); + x |= 1; + foo(); + printf("test 2\n"); + x |= 2; + } + + shared void foo() + { + printf("foo 1\n"); + x |= 4; + throw this; + printf("foo 2\n"); + x |= 8; + } +} + +struct RefCounted +{ + void *p; + ~this() + { + p = null; + } +} + +struct S +{ + RefCounted _data; + + int get() @property + { + throw new Exception(""); + } +} + +void b9438() +{ + try + { + S s; + S().get; + } + catch (Exception e){ } +} + +int main() +{ + printf("hello world\n"); + auto a = new shared(Abc)(); + printf("hello 2\n"); + Abc.x |= 0x10; + + try + { + Abc.x |= 0x20; + a.test(); + Abc.x |= 0x40; + } + catch (shared(Abc) b) + { + Abc.x |= 0x80; + printf("Caught %p, x = x%x\n", b, Abc.x); + assert(a is b); + assert(Abc.x == 0xB5); + } + printf("Success!\n"); + b9438(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/entity1.d b/gcc/testsuite/gdc.test/runnable/entity1.d new file mode 100644 index 00000000000..39211934110 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/entity1.d @@ -0,0 +1,144 @@ +// $HeadURL$ +// $Date$ +// $Author$ + +module dstress.run.named_entity_02; + +// "-//W3C//ENTITIES Symbolic//EN//HTML" + +int main(){ + assert('\ƒ'==402); + assert('\Α'==913); + assert('\Β'==914); + assert('\Γ'==915); + assert('\Δ'==916); + assert('\Ε'==917); + assert('\Ζ'==918); + assert('\Η'==919); + assert('\Θ'==920); + assert('\Ι'==921); + assert('\Κ'==922); + assert('\Λ'==923); + assert('\Μ'==924); + assert('\Ν'==925); + assert('\Ξ'==926); + assert('\Ο'==927); + assert('\Π'==928); + assert('\Ρ'==929); + assert('\Σ'==931); + assert('\Τ'==932); + assert('\Υ'==933); + assert('\Φ'==934); + assert('\Χ'==935); + assert('\Ψ'==936); + assert('\Ω'==937); + assert('\α'==945); + assert('\β'==946); + assert('\γ'==947); + assert('\δ'==948); + assert('\ε'==949); + assert('\ζ'==950); + assert('\η'==951); + assert('\θ'==952); + assert('\ι'==953); + assert('\κ'==954); + assert('\λ'==955); + assert('\μ'==956); + assert('\ν'==957); + assert('\ξ'==958); + assert('\ο'==959); + assert('\π'==960); + assert('\ρ'==961); + assert('\ς'==962); + assert('\σ'==963); + assert('\τ'==964); + assert('\υ'==965); + assert('\φ'==966); + assert('\χ'==967); + assert('\ψ'==968); + assert('\ω'==969); + assert('\ϑ'==977); + assert('\ϒ'==978); + assert('\ϖ'==982); + assert('\•'==8226); + assert('\…'==8230); + assert('\′'==8242); + assert('\″'==8243); + assert('\‾'==8254); + assert('\⁄'==8260); + assert('\℘'==8472); + assert('\ℑ'==8465); + assert('\ℜ'==8476); + assert('\™'==8482); + assert('\ℵ'==8501); + assert('\←'==8592); + assert('\↑'==8593); + assert('\→'==8594); + assert('\↓'==8595); + assert('\↔'==8596); + assert('\↵'==8629); + assert('\⇐'==8656); + assert('\⇑'==8657); + assert('\⇒'==8658); + assert('\⇓'==8659); + assert('\⇔'==8660); + assert('\∀'==8704); + assert('\∂'==8706); + assert('\∃'==8707); + assert('\∅'==8709); + assert('\∇'==8711); + assert('\∈'==8712); + assert('\∉'==8713); + assert('\∋'==8715); + assert('\∏'==8719); + assert('\∑'==8721); + assert('\−'==8722); + assert('\∗'==8727); + assert('\√'==8730); + assert('\∝'==8733); + assert('\∞'==8734); + assert('\∠'==8736); + assert('\∧'==8743); + assert('\∨'==8744); + assert('\∩'==8745); + assert('\∪'==8746); + assert('\∫'==8747); + assert('\∴'==8756); + assert('\∼'==8764); + assert('\≅'==8773); + assert('\≈'==8776); + assert('\≠'==8800); + assert('\≡'==8801); + assert('\≤'==8804); + assert('\≥'==8805); + assert('\⊂'==8834); + assert('\⊃'==8835); + assert('\⊄'==8836); + assert('\⊆'==8838); + assert('\⊇'==8839); + assert('\⊕'==8853); + assert('\⊗'==8855); + assert('\⊥'==8869); + assert('\⋅'==8901); + assert('\⌈'==8968); + assert('\⌉'==8969); + assert('\⌊'==8970); + assert('\⌋'==8971); + //assert('\⟨'==9001); // U+2329 valid for HTML 4.01; changed in HTML5 + //assert('\⟩'==9002); // U+232A valid for HTML 4.01; changed in HTML5 + assert('\⟨'==0x27E8); // valid for HTML 5 and later. The character was introduced in HTML 3.2 + assert('\⟩'==0x27E9); // valid for HTML 5 and later. The character was introduced in HTML 3.2 + assert('\◊'==9674); + assert('\♠'==9824); + assert('\♣'==9827); + assert('\♥'==9829); + assert('\♦'==9830); + return 0; +} + +// Bug 5221 +static assert('\✓'==10003); +static assert('\≲'==8818); +static assert('\№'==8470); +static assert('\⌝'==8989); +static assert('\Ż'==379); diff --git a/gcc/testsuite/gdc.test/runnable/evalorder.d b/gcc/testsuite/gdc.test/runnable/evalorder.d new file mode 100644 index 00000000000..8b56cc7af59 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/evalorder.d @@ -0,0 +1,164 @@ +extern(C) int printf(const char*, ...); + +void test14040() +{ + uint[] values = [0, 1, 2, 3, 4, 5, 6, 7]; + uint offset = 0; + + auto a1 = values[offset .. offset += 2]; + if (a1 != [0, 1] || offset != 2) + assert(0); + + uint[] fun() + { + offset += 2; + return values; + } + auto a2 = fun()[offset .. offset += 2]; + if (a2 != [4, 5] || offset != 6) + assert(0); + + // Also test an offset of type size_t such that it is used + // directly without any implicit conversion in the slice expression. + size_t offset_szt = 0; + auto a3 = values[offset_szt .. offset_szt += 2]; + if (a3 != [0, 1] || offset_szt != 2) + assert(0); +} + +/******************************************/ + +int add8ret3(T)(ref T s) +{ + s += 8; + return 3; +} + +int mul11ret3(T)(ref T s) +{ + s *= 11; + return 3; +} + +void add() +{ + static int test1(int val) { val += add8ret3(val); return val; } + assert(test1(1) == (1 + 8 + 3)); + static assert(test1(1) == (1 + 8 + 3)); + + static int test2(int val) { val = val + add8ret3(val); return val; } + // FIXME: assert(test2(1) == (1 + 3)); + static assert(test2(1) == (1 + 3)); + + static int test3(int val) { (val += 7) += mul11ret3(val); return val; } + assert(test3(2) == (((2+7)*11) + 3)); + static assert(test3(2) == (((2+7)*11) + 3)); +} + +void min() +{ + static int test1(int val) { val -= add8ret3(val); return val; } + assert(test1(1) == (1 + 8 - 3)); + static assert(test1(1) == (1 + 8 - 3)); + + static int test2(int val) { val = val - add8ret3(val); return val; } + // FIXME: assert(test2(1) == (1 - 3)); + static assert(test2(1) == (1 - 3)); + + static int test3(int val) { (val -= 7) -= mul11ret3(val); return val; } + assert(test3(2) == (((2-7)*11) - 3)); + static assert(test3(2) == (((2-7)*11) - 3)); +} + +void mul() +{ + static int test1(int val) { val *= add8ret3(val); return val; } + assert(test1(7) == ((7 + 8) * 3)); + static assert(test1(7) == ((7 + 8) * 3)); + + static int test2(int val) { val = val * add8ret3(val); return val; } + // FIXME: assert(test2(7) == (7 * 3)); + static assert(test2(7) == (7 * 3)); + + static int test3(int val) { (val *= 7) *= add8ret3(val); return val; } + assert(test3(2) == (((2*7)+8) * 3)); + static assert(test3(2) == (((2*7)+8) * 3)); +} + +void xor() +{ + static int test1(int val) { val ^= add8ret3(val); return val; } + assert(test1(1) == ((1 + 8) ^ 3)); + static assert(test1(1) == ((1 + 8) ^ 3)); + + static int test2(int val) { val = val ^ add8ret3(val); return val; } + // FIXME: assert(test2(1) == (1 ^ 3)); + static assert(test2(1) == (1 ^ 3)); + + static int test3(int val) { (val ^= 7) ^= add8ret3(val); return val; } + assert(test3(2) == (((2^7)+8) ^ 3)); + static assert(test3(2) == (((2^7)+8) ^ 3)); +} + +void addptr() +{ + static int* test1(int* val) { val += add8ret3(val); return val; } + assert(test1(cast(int*)4) == ((cast(int*)4) + 8 + 3)); + + static int* test2(int* val) { val = val + add8ret3(val); return val; } + // FIXME: assert(test2(cast(int*)4) == ((cast(int*)4) + 3)); + + static int* test3(int* val) { (val += 7) += add8ret3(val); return val; } + assert(test3(cast(int*)16) == ((cast(int*)16) + 7 + 8 + 3)); +} + +void lhsCast() +{ + static byte test(byte val) + { + // lhs type `byte`, rhs type `int` => + // rewritten to `cast(int)(cast(int)val += 10) -= mul11ret3(val)` + (val += 10) -= mul11ret3(val); + return val; + } + + assert(test(1) == ((1 + 10) * 11 - 3)); + static assert(test(1) == ((1 + 10) * 11 - 3)); +} + +void shr() +{ + static ubyte test(ubyte val) + { + // lhs type `ubyte`, rhs type `int` => + // rewritten to `cast(int)val >>= 1` + // we still want a logical (unsigned) right-shift though + val >>= 1; + return val; + } + + assert(test(0x80) == 0x40); + static assert(test(0x80) == 0x40); +} + +void ldc_github_1617() +{ + add(); + min(); + mul(); + xor(); + addptr(); + lhsCast(); + shr(); +} + +/******************************************/ + +int main() +{ + test14040(); + ldc_github_1617(); + + printf("Success\n"); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/extern1.d b/gcc/testsuite/gdc.test/runnable/extern1.d new file mode 100644 index 00000000000..ad53e4e2d28 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extern1.d @@ -0,0 +1,14 @@ +// note: not actually imported, just built and linked against +// EXTRA_SOURCES: imports/extern1a.d +// PERMUTE_ARGS: + +extern (C) +{ + extern int x; +} + +int main() +{ + assert(x == 3); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/externmangle.d b/gcc/testsuite/gdc.test/runnable/externmangle.d new file mode 100644 index 00000000000..bf80adafe02 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/externmangle.d @@ -0,0 +1,314 @@ +// EXTRA_CPP_SOURCES: extra-files/externmangle.cpp + +extern(C++): + +struct Foo(X) +{ + X* v; +} + + +struct Boo(X) +{ + X* v; +} + + +void test1(Foo!int arg1); +void test2(int* arg2, Boo!(int*) arg1); + + +struct Test3(int X, int Y) +{ +} + +void test3(Test3!(3,3) arg1); + +void test4(Foo!(int*) arg1, Boo!(int*) arg2, Boo!(int*) arg3, int*, Foo!(double)); + +void test5(Foo!(int*) arg1, Boo!(int*) arg2, Boo!(int*) arg3); + + +struct Goo +{ + struct Foo(X) + { + X* v; + } + + struct Boo(X) + { + struct Xoo(Y) + { + Y* v; + }; + X* v; + } + + + void test6(Foo!(Boo!(Foo!(void))) arg1); + void test7(Boo!(void).Xoo!(int) arg1); +} + +struct P1 +{ + struct Mem(T) + { + } +} + +struct P2 +{ + struct Mem(T) + { + } +} + +void test8(P1.Mem!int, P2.Mem!int); +void test9(Foo!(int**), Foo!(int*), int**, int*); + + +interface Test10 +{ + private final void test10(); + public final void test11(); + protected final void test12(); + public final void test13() const; + + private void test14(); + public void test15(); + protected void test16(); + + private static void test17(); + public static void test18(); + protected static void test19(); +}; + +Test10 Test10Ctor(); +void Test10Dtor(ref Test10 ptr); + +struct Test20 +{ + __gshared: + private extern int test20; + protected extern int test21; + public extern int test22; +}; + + +int test23(Test10*, Test10, Test10**, const(Test10)); +int test23b(const Test10*, const Test10, Test10); + +void test24(int function(int,int)); + +void test25(int[291][6][5]* arr); +int test26(int[291][6]* arr); + +void test27(int, ...); +void test28(int); + +void test29(float); +void test30(const float); + +struct Array(T) +{ + int dim; +} + + +interface Module +{ + public static void imports(Module); + public static int dim(Array!Module*); +}; + +ulong testlongmangle(int a, uint b, long c, ulong d); + +__gshared extern int[2][2][2] test31; +__gshared extern int* test32; + + +alias int function(Expression , void* ) apply_fp_t; + +interface Expression +{ + public final int apply(apply_fp_t fp, apply_fp_t fp2, void* param); + public final int getType(); + public static Expression create(int); + public static void dispose(ref Expression); +} + +//int test34(int[0][0]*); +version(CRuntime_Microsoft){} +else +{ + int test35(real arg); +} + +const(char)* test36(const(char)*); + +final class Test37 +{ + static Test37 create() + { + return new Test37; + } + + bool test() + { + return true; + } +} + +bool test37(); + +interface Test38 +{ + final int test(int, ...); + public static Test38 create(); + public static void dispose(ref Test38); +} + +extern(C++) int test39cpp(C2!char, S2!(int)*); + +extern(C++, class) +struct S1 +{ + private int val; + static S1* init(int); + int value(); +} + +extern(C++, class) +struct S2(T) +{ + private T val; + static S2!T* init(int); + T value(); +} + +extern(C++, struct) +class C1 +{ + const(char)* data; + + static C1 init(const(char)* p); + const(char)* getDataCPP(); + extern(C++) const(char)* getDataD() + { + return data; + } +} + +extern(C++, struct) +class C2(T) +{ + const(T)* data; + + static C2!T init(const(T)* p); + const(T)* getData(); +} + +void test39() +{ + S1* s1 = S1.init(42); + assert(s1.value == 42); + assert(S2!int.init(43).value == 43); + const(char)* ptr = "test".ptr; + C1 c1 = C1.init(ptr); + assert(c1.getDataCPP() == ptr); + assert(c1.getDataD() == ptr); + C2!char c2 = C2!char.init(ptr); + assert(c2.getData() == ptr); + auto result = test39cpp(c2, S2!int.init(43)); + assert(result == 0); +} + + +void main() +{ + test1(Foo!int()); + test2(null, Boo!(int*)()); + test3(Test3!(3,3)()); + test4(Foo!(int*)(), Boo!(int*)(), Boo!(int*)(), null, Foo!(double)()); + test5(Foo!(int*)(), Boo!(int*)(), Boo!(int*)()); + Goo goo; + goo.test6(Goo.Foo!(Goo.Boo!(Goo.Foo!(void)))()); + goo.test7(Goo.Boo!(void).Xoo!(int)()); + + test8(P1.Mem!int(), P2.Mem!int()); + test9(Foo!(int**)(), Foo!(int*)(), null, null); + + auto t10 = Test10Ctor(); + scope(exit) Test10Dtor(t10); + + t10.test10(); + t10.test11(); + t10.test12(); + t10.test13(); + t10.test14(); + t10.test15(); + t10.test16(); + t10.test17(); + t10.test18(); + t10.test19(); + + assert(Test20.test20 == 20); + assert(Test20.test21 == 21); + assert(Test20.test22 == 22); + + assert(test23(null, null, null, null) == 1); + assert(test23b(null, null, null) == 1); + + extern(C++) static int cb(int a, int b){return a+b;} + + test24(&cb); + int[291][6][5] arr; + arr[1][1][1] = 42; + test25(&arr); + assert(test26(&arr[0]) == 42); + + test27(3,4,5); + test28(3); + + test29(3.14f); + test30(3.14f); + + auto t32 = &Module.imports; + Array!Module arr2; + arr2.dim = 20; + assert(Module.dim(&arr2) == 20); + + assert(testlongmangle(1, 2, 3, 4) == 10); + assert(test31 == [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]); + assert(test32 == null); + + auto ee = Expression.create(42); + extern(C++) static int efun(Expression e, void* p) + { + return cast(int)(cast(size_t)p ^ e.getType()); + } + + extern(C++) static int efun2(Expression e, void* p) + { + return cast(int)(cast(size_t)p * e.getType()); + } + + auto test33 = ee.apply(&efun, &efun2, cast(void*)&Expression.create); + assert(test33 == cast(int)(cast(size_t)cast(void*)&Expression.create ^ 42) * cast(int)(cast(size_t)cast(void*)&Expression.create * 42)); + Expression.dispose(ee); + assert(ee is null); + //assert(test34(null) == 0); + version(CRuntime_Microsoft){} + else + { + assert(test35(3.14L) == 3); + } + const char* hello = "hello"; + assert(test36(hello) == hello); + assert(test37()); + auto t38 = Test38.create(); + assert(t38.test(1, 2, 3) == 1); + Test38.dispose(t38); + test39(); +} diff --git a/gcc/testsuite/gdc.test/runnable/externmangle2.d b/gcc/testsuite/gdc.test/runnable/externmangle2.d new file mode 100644 index 00000000000..7d87fbd67f3 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/externmangle2.d @@ -0,0 +1,164 @@ +// EXTRA_CPP_SOURCES: extra-files/externmangle2.cpp + +version(Windows) +{ + void main() + { + } +} +else +{ + extern(C++): + + struct Test32NS1 + { + struct Foo(X) + { + X *v; + } + + + struct Bar(X) + { + X *v; + } + + }; + + struct Test32NS2 + { + struct Foo(X) + { + X *v; + } + }; + + struct Test32(alias Y, alias Z) + { + Y!(int)* field; + }; + + + void test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo) arg); + void test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar) arg); + void test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg); + void test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg1, Test32!(Test32NS2.Foo, Test32NS1.Foo) arg2); + + interface XXX + { + } + + void test33a(XXX, XXX*); + + + struct Test33(alias A, alias B) + { + } + + /* + void test33(XXX, Test33!(test33a, test33a) arg, XXX); + + + struct Test34(alias A) + { + }; + + struct Test34A + { + static void foo(int); + }; + + + void test34(Test34!(Test34A.foo) arg); + */ + + __gshared extern int test36; + + /* + struct Test37(alias A) + { + }; + + struct Test37A + { + __gshared extern int t38; + }; + + void test37(Test37!(test36) arg); + void test38(Test37!(Test37A.t38) arg); + */ + + struct Test39 + { + struct T39A(X) + { + } + } + + struct T39A + { + } + + void test39(Test39.T39A!(.T39A)); + + version(none) + { + version(Posix) //Only for g++ with -std=c++0x and Visual Studio 2013+ + { + + struct Test40(T, V...) + { + + } + + void test40(Test40!(int, double, void)) + { + } + } + else version(Win64) //Only for g++ with -std=c++0x and Visual Studio 2013+ + { + + struct Test40(T, V...) + { + + } + + void test40(Test40!(int, double, void)) + { + } + } + } + + + __gshared extern const XXX test41; + struct Test42 + { + __gshared extern const XXX test42; + } + __gshared extern int[4] test43; + const(XXX) test44(); + + void main() + { + test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo)()); + test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar)()); + test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo)()); + test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo)(), Test32!(Test32NS2.Foo, Test32NS1.Foo)()); + + //test33a(null, null); + //test33(null, Test33!(test33a, test33a)(), null); + + //test34(Test34!(Test34A.foo)()); + + assert(test36 == 36); + + //test37(Test37!(test36)()); + //test38(Test37!(Test37A.t38)()); + test39(Test39.T39A!(.T39A)()); + + assert(test41 is null); + assert(Test42.test42 is null); + assert(test43 == [1, 2, 3, 4]); + auto ptr = &test44; + } +} diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/alice30.txt b/gcc/testsuite/gdc.test/runnable/extra-files/alice30.txt new file mode 100644 index 00000000000..62c11310587 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extra-files/alice30.txt @@ -0,0 +1,3603 @@ + + + + + ALICE'S ADVENTURES IN WONDERLAND + + Lewis Carroll + + THE MILLENNIUM FULCRUM EDITION 3.0 + + + + + CHAPTER I + + Down the Rabbit-Hole + + + Alice was beginning to get very tired of sitting by her sister +on the bank, and of having nothing to do: once or twice she had +peeped into the book her sister was reading, but it had no +pictures or conversations in it, `and what is the use of a book,' +thought Alice `without pictures or conversation?' + + So she was considering in her own mind (as well as she could, +for the hot day made her feel very sleepy and stupid), whether +the pleasure of making a daisy-chain would be worth the trouble +of getting up and picking the daisies, when suddenly a White +Rabbit with pink eyes ran close by her. + + There was nothing so VERY remarkable in that; nor did Alice +think it so VERY much out of the way to hear the Rabbit say to +itself, `Oh dear! Oh dear! I shall be late!' (when she thought +it over afterwards, it occurred to her that she ought to have +wondered at this, but at the time it all seemed quite natural); +but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT- +POCKET, and looked at it, and then hurried on, Alice started to +her feet, for it flashed across her mind that she had never +before seen a rabbit with either a waistcoat-pocket, or a watch to +take out of it, and burning with curiosity, she ran across the +field after it, and fortunately was just in time to see it pop +down a large rabbit-hole under the hedge. + + In another moment down went Alice after it, never once +considering how in the world she was to get out again. + + The rabbit-hole went straight on like a tunnel for some way, +and then dipped suddenly down, so suddenly that Alice had not a +moment to think about stopping herself before she found herself +falling down a very deep well. + + Either the well was very deep, or she fell very slowly, for she +had plenty of time as she went down to look about her and to +wonder what was going to happen next. First, she tried to look +down and make out what she was coming to, but it was too dark to +see anything; then she looked at the sides of the well, and +noticed that they were filled with cupboards and book-shelves; +here and there she saw maps and pictures hung upon pegs. She +took down a jar from one of the shelves as she passed; it was +labelled `ORANGE MARMALADE', but to her great disappointment it +was empty: she did not like to drop the jar for fear of killing +somebody, so managed to put it into one of the cupboards as she +fell past it. + + `Well!' thought Alice to herself, `after such a fall as this, I +shall think nothing of tumbling down stairs! How brave they'll +all think me at home! Why, I wouldn't say anything about it, +even if I fell off the top of the house!' (Which was very likely +true.) + + Down, down, down. Would the fall NEVER come to an end! `I +wonder how many miles I've fallen by this time?' she said aloud. +`I must be getting somewhere near the centre of the earth. Let +me see: that would be four thousand miles down, I think--' (for, +you see, Alice had learnt several things of this sort in her +lessons in the schoolroom, and though this was not a VERY good +opportunity for showing off her knowledge, as there was no one to +listen to her, still it was good practice to say it over) `--yes, +that's about the right distance--but then I wonder what Latitude +or Longitude I've got to?' (Alice had no idea what Latitude was, +or Longitude either, but thought they were nice grand words to +say.) + + Presently she began again. `I wonder if I shall fall right +THROUGH the earth! How funny it'll seem to come out among the +people that walk with their heads downward! The Antipathies, I +think--' (she was rather glad there WAS no one listening, this +time, as it didn't sound at all the right word) `--but I shall +have to ask them what the name of the country is, you know. +Please, Ma'am, is this New Zealand or Australia?' (and she tried +to curtsey as she spoke--fancy CURTSEYING as you're falling +through the air! Do you think you could manage it?) `And what +an ignorant little girl she'll think me for asking! No, it'll +never do to ask: perhaps I shall see it written up somewhere.' + + Down, down, down. There was nothing else to do, so Alice soon +began talking again. `Dinah'll miss me very much to-night, I +should think!' (Dinah was the cat.) `I hope they'll remember +her saucer of milk at tea-time. Dinah my dear! I wish you were +down here with me! There are no mice in the air, I'm afraid, but +you might catch a bat, and that's very like a mouse, you know. +But do cats eat bats, I wonder?' And here Alice began to get +rather sleepy, and went on saying to herself, in a dreamy sort of +way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do +bats eat cats?' for, you see, as she couldn't answer either +question, it didn't much matter which way she put it. She felt +that she was dozing off, and had just begun to dream that she +was walking hand in hand with Dinah, and saying to her very +earnestly, `Now, Dinah, tell me the truth: did you ever eat a +bat?' when suddenly, thump! thump! down she came upon a heap of +sticks and dry leaves, and the fall was over. + + Alice was not a bit hurt, and she jumped up on to her feet in a +moment: she looked up, but it was all dark overhead; before her +was another long passage, and the White Rabbit was still in +sight, hurrying down it. There was not a moment to be lost: +away went Alice like the wind, and was just in time to hear it +say, as it turned a corner, `Oh my ears and whiskers, how late +it's getting!' She was close behind it when she turned the +corner, but the Rabbit was no longer to be seen: she found +herself in a long, low hall, which was lit up by a row of lamps +hanging from the roof. + + There were doors all round the hall, but they were all locked; +and when Alice had been all the way down one side and up the +other, trying every door, she walked sadly down the middle, +wondering how she was ever to get out again. + + Suddenly she came upon a little three-legged table, all made of +solid glass; there was nothing on it except a tiny golden key, +and Alice's first thought was that it might belong to one of the +doors of the hall; but, alas! either the locks were too large, or +the key was too small, but at any rate it would not open any of +them. However, on the second time round, she came upon a low +curtain she had not noticed before, and behind it was a little +door about fifteen inches high: she tried the little golden key +in the lock, and to her great delight it fitted! + + Alice opened the door and found that it led into a small +passage, not much larger than a rat-hole: she knelt down and +looked along the passage into the loveliest garden you ever saw. +How she longed to get out of that dark hall, and wander about +among those beds of bright flowers and those cool fountains, but +she could not even get her head though the doorway; `and even if +my head would go through,' thought poor Alice, `it would be of +very little use without my shoulders. Oh, how I wish +I could shut up like a telescope! I think I could, if I only +know how to begin.' For, you see, so many out-of-the-way things +had happened lately, that Alice had begun to think that very few +things indeed were really impossible. + + There seemed to be no use in waiting by the little door, so she +went back to the table, half hoping she might find another key on +it, or at any rate a book of rules for shutting people up like +telescopes: this time she found a little bottle on it, (`which +certainly was not here before,' said Alice,) and round the neck +of the bottle was a paper label, with the words `DRINK ME' +beautifully printed on it in large letters. + + It was all very well to say `Drink me,' but the wise little +Alice was not going to do THAT in a hurry. `No, I'll look +first,' she said, `and see whether it's marked "poison" or not'; +for she had read several nice little histories about children who +had got burnt, and eaten up by wild beasts and other unpleasant +things, all because they WOULD not remember the simple rules +their friends had taught them: such as, that a red-hot poker +will burn you if you hold it too long; and that if you cut your +finger VERY deeply with a knife, it usually bleeds; and she had +never forgotten that, if you drink much from a bottle marked +`poison,' it is almost certain to disagree with you, sooner or +later. + + However, this bottle was NOT marked `poison,' so Alice ventured +to taste it, and finding it very nice, (it had, in fact, a sort +of mixed flavour of cherry-tart, custard, pine-apple, roast +turkey, toffee, and hot buttered toast,) she very soon finished +it off. + + * * * * * * * + + * * * * * * + + * * * * * * * + + `What a curious feeling!' said Alice; `I must be shutting up +like a telescope.' + + And so it was indeed: she was now only ten inches high, and +her face brightened up at the thought that she was now the right +size for going through the little door into that lovely garden. +First, however, she waited for a few minutes to see if she was +going to shrink any further: she felt a little nervous about +this; `for it might end, you know,' said Alice to herself, `in my +going out altogether, like a candle. I wonder what I should be +like then?' And she tried to fancy what the flame of a candle is +like after the candle is blown out, for she could not remember +ever having seen such a thing. + + After a while, finding that nothing more happened, she decided +on going into the garden at once; but, alas for poor Alice! +when she got to the door, she found she had forgotten the +little golden key, and when she went back to the table for it, +she found she could not possibly reach it: she could see it +quite plainly through the glass, and she tried her best to climb +up one of the legs of the table, but it was too slippery; +and when she had tired herself out with trying, +the poor little thing sat down and cried. + + `Come, there's no use in crying like that!' said Alice to +herself, rather sharply; `I advise you to leave off this minute!' +She generally gave herself very good advice, (though she very +seldom followed it), and sometimes she scolded herself so +severely as to bring tears into her eyes; and once she remembered +trying to box her own ears for having cheated herself in a game +of croquet she was playing against herself, for this curious +child was very fond of pretending to be two people. `But it's no +use now,' thought poor Alice, `to pretend to be two people! Why, +there's hardly enough of me left to make ONE respectable +person!' + + Soon her eye fell on a little glass box that was lying under +the table: she opened it, and found in it a very small cake, on +which the words `EAT ME' were beautifully marked in currants. +`Well, I'll eat it,' said Alice, `and if it makes me grow larger, +I can reach the key; and if it makes me grow smaller, I can creep +under the door; so either way I'll get into the garden, and I +don't care which happens!' + + She ate a little bit, and said anxiously to herself, `Which +way? Which way?', holding her hand on the top of her head to +feel which way it was growing, and she was quite surprised to +find that she remained the same size: to be sure, this generally +happens when one eats cake, but Alice had got so much into the +way of expecting nothing but out-of-the-way things to happen, +that it seemed quite dull and stupid for life to go on in the +common way. + + So she set to work, and very soon finished off the cake. + + * * * * * * * + + * * * * * * + + * * * * * * * + + + + + CHAPTER II + + The Pool of Tears + + + `Curiouser and curiouser!' cried Alice (she was so much +surprised, that for the moment she quite forgot how to speak good +English); `now I'm opening out like the largest telescope that +ever was! Good-bye, feet!' (for when she looked down at her +feet, they seemed to be almost out of sight, they were getting so +far off). `Oh, my poor little feet, I wonder who will put on +your shoes and stockings for you now, dears? I'm sure _I_ shan't +be able! I shall be a great deal too far off to trouble myself +about you: you must manage the best way you can; --but I must be +kind to them,' thought Alice, `or perhaps they won't walk the +way I want to go! Let me see: I'll give them a new pair of +boots every Christmas.' + + And she went on planning to herself how she would manage it. +`They must go by the carrier,' she thought; `and how funny it'll +seem, sending presents to one's own feet! And how odd the +directions will look! + + ALICE'S RIGHT FOOT, ESQ. + HEARTHRUG, + NEAR THE FENDER, + (WITH ALICE'S LOVE). + +Oh dear, what nonsense I'm talking!' + + Just then her head struck against the roof of the hall: in +fact she was now more than nine feet high, and she at once took +up the little golden key and hurried off to the garden door. + + Poor Alice! It was as much as she could do, lying down on one +side, to look through into the garden with one eye; but to get +through was more hopeless than ever: she sat down and began to +cry again. + + `You ought to be ashamed of yourself,' said Alice, `a great +girl like you,' (she might well say this), `to go on crying in +this way! Stop this moment, I tell you!' But she went on all +the same, shedding gallons of tears, until there was a large pool +all round her, about four inches deep and reaching half down the +hall. + + After a time she heard a little pattering of feet in the +distance, and she hastily dried her eyes to see what was coming. +It was the White Rabbit returning, splendidly dressed, with a +pair of white kid gloves in one hand and a large fan in the +other: he came trotting along in a great hurry, muttering to +himself as he came, `Oh! the Duchess, the Duchess! Oh! won't she +be savage if I've kept her waiting!' Alice felt so desperate +that she was ready to ask help of any one; so, when the Rabbit +came near her, she began, in a low, timid voice, `If you please, +sir--' The Rabbit started violently, dropped the white kid +gloves and the fan, and skurried away into the darkness as hard +as he could go. + + Alice took up the fan and gloves, and, as the hall was very +hot, she kept fanning herself all the time she went on talking: +`Dear, dear! How queer everything is to-day! And yesterday +things went on just as usual. I wonder if I've been changed in +the night? Let me think: was I the same when I got up this +morning? I almost think I can remember feeling a little +different. But if I'm not the same, the next question is, Who in +the world am I? Ah, THAT'S the great puzzle!' And she began +thinking over all the children she knew that were of the same age +as herself, to see if she could have been changed for any of +them. + + `I'm sure I'm not Ada,' she said, `for her hair goes in such +long ringlets, and mine doesn't go in ringlets at all; and I'm +sure I can't be Mabel, for I know all sorts of things, and she, +oh! she knows such a very little! Besides, SHE'S she, and I'm I, +and--oh dear, how puzzling it all is! I'll try if I know all the +things I used to know. Let me see: four times five is twelve, +and four times six is thirteen, and four times seven is--oh dear! +I shall never get to twenty at that rate! However, the +Multiplication Table doesn't signify: let's try Geography. +London is the capital of Paris, and Paris is the capital of Rome, +and Rome--no, THAT'S all wrong, I'm certain! I must have been +changed for Mabel! I'll try and say "How doth the little--"' +and she crossed her hands on her lap as if she were saying lessons, +and began to repeat it, but her voice sounded hoarse and +strange, and the words did not come the same as they used to do:-- + + `How doth the little crocodile + Improve his shining tail, + And pour the waters of the Nile + On every golden scale! + + `How cheerfully he seems to grin, + How neatly spread his claws, + And welcome little fishes in + With gently smiling jaws!' + + `I'm sure those are not the right words,' said poor Alice, and +her eyes filled with tears again as she went on, `I must be Mabel +after all, and I shall have to go and live in that poky little +house, and have next to no toys to play with, and oh! ever so +many lessons to learn! No, I've made up my mind about it; if I'm +Mabel, I'll stay down here! It'll be no use their putting their +heads down and saying "Come up again, dear!" I shall only look +up and say "Who am I then? Tell me that first, and then, if I +like being that person, I'll come up: if not, I'll stay down +here till I'm somebody else"--but, oh dear!' cried Alice, with a +sudden burst of tears, `I do wish they WOULD put their heads +down! I am so VERY tired of being all alone here!' + + As she said this she looked down at her hands, and was +surprised to see that she had put on one of the Rabbit's little +white kid gloves while she was talking. `How CAN I have done +that?' she thought. `I must be growing small again.' She got up +and went to the table to measure herself by it, and found that, +as nearly as she could guess, she was now about two feet high, +and was going on shrinking rapidly: she soon found out that the +cause of this was the fan she was holding, and she dropped it +hastily, just in time to avoid shrinking away altogether. + +`That WAS a narrow escape!' said Alice, a good deal frightened at +the sudden change, but very glad to find herself still in +existence; `and now for the garden!' and she ran with all speed +back to the little door: but, alas! the little door was shut +again, and the little golden key was lying on the glass table as +before, `and things are worse than ever,' thought the poor child, +`for I never was so small as this before, never! And I declare +it's too bad, that it is!' + + As she said these words her foot slipped, and in another +moment, splash! she was up to her chin in salt water. Her first +idea was that she had somehow fallen into the sea, `and in that +case I can go back by railway,' she said to herself. (Alice had +been to the seaside once in her life, and had come to the general +conclusion, that wherever you go to on the English coast you find +a number of bathing machines in the sea, some children digging in +the sand with wooden spades, then a row of lodging houses, and +behind them a railway station.) However, she soon made out that +she was in the pool of tears which she had wept when she was nine +feet high. + + `I wish I hadn't cried so much!' said Alice, as she swam about, +trying to find her way out. `I shall be punished for it now, I +suppose, by being drowned in my own tears! That WILL be a queer +thing, to be sure! However, everything is queer to-day.' + + Just then she heard something splashing about in the pool a +little way off, and she swam nearer to make out what it was: at +first she thought it must be a walrus or hippopotamus, but then +she remembered how small she was now, and she soon made out that +it was only a mouse that had slipped in like herself. + + `Would it be of any use, now,' thought Alice, `to speak to this +mouse? Everything is so out-of-the-way down here, that I should +think very likely it can talk: at any rate, there's no harm in +trying.' So she began: `O Mouse, do you know the way out of +this pool? I am very tired of swimming about here, O Mouse!' +(Alice thought this must be the right way of speaking to a mouse: +she had never done such a thing before, but she remembered having +seen in her brother's Latin Grammar, `A mouse--of a mouse--to a +mouse--a mouse--O mouse!' The Mouse looked at her rather +inquisitively, and seemed to her to wink with one of its little +eyes, but it said nothing. + + `Perhaps it doesn't understand English,' thought Alice; `I +daresay it's a French mouse, come over with William the +Conqueror.' (For, with all her knowledge of history, Alice had +no very clear notion how long ago anything had happened.) So she +began again: `Ou est ma chatte?' which was the first sentence in +her French lesson-book. The Mouse gave a sudden leap out of the +water, and seemed to quiver all over with fright. `Oh, I beg +your pardon!' cried Alice hastily, afraid that she had hurt the +poor animal's feelings. `I quite forgot you didn't like cats.' + + `Not like cats!' cried the Mouse, in a shrill, passionate +voice. `Would YOU like cats if you were me?' + + `Well, perhaps not,' said Alice in a soothing tone: `don't be +angry about it. And yet I wish I could show you our cat Dinah: +I think you'd take a fancy to cats if you could only see her. +She is such a dear quiet thing,' Alice went on, half to herself, +as she swam lazily about in the pool, `and she sits purring so +nicely by the fire, licking her paws and washing her face--and +she is such a nice soft thing to nurse--and she's such a capital +one for catching mice--oh, I beg your pardon!' cried Alice again, +for this time the Mouse was bristling all over, and she felt +certain it must be really offended. `We won't talk about her any +more if you'd rather not.' + + `We indeed!' cried the Mouse, who was trembling down to the end +of his tail. `As if I would talk on such a subject! Our family +always HATED cats: nasty, low, vulgar things! Don't let me hear +the name again!' + + `I won't indeed!' said Alice, in a great hurry to change the +subject of conversation. `Are you--are you fond--of--of dogs?' +The Mouse did not answer, so Alice went on eagerly: `There is +such a nice little dog near our house I should like to show you! +A little bright-eyed terrier, you know, with oh, such long curly +brown hair! And it'll fetch things when you throw them, and +it'll sit up and beg for its dinner, and all sorts of things--I +can't remember half of them--and it belongs to a farmer, you +know, and he says it's so useful, it's worth a hundred pounds! +He says it kills all the rats and--oh dear!' cried Alice in a +sorrowful tone, `I'm afraid I've offended it again!' For the +Mouse was swimming away from her as hard as it could go, and +making quite a commotion in the pool as it went. + + So she called softly after it, `Mouse dear! Do come back +again, and we won't talk about cats or dogs either, if you don't +like them!' When the Mouse heard this, it turned round and swam +slowly back to her: its face was quite pale (with passion, Alice +thought), and it said in a low trembling voice, `Let us get to +the shore, and then I'll tell you my history, and you'll +understand why it is I hate cats and dogs.' + + It was high time to go, for the pool was getting quite crowded +with the birds and animals that had fallen into it: there were a +Duck and a Dodo, a Lory and an Eaglet, and several other curious +creatures. Alice led the way, and the whole party swam to the +shore. + + + + CHAPTER III + + A Caucus-Race and a Long Tale + + + They were indeed a queer-looking party that assembled on the +bank--the birds with draggled feathers, the animals with their +fur clinging close to them, and all dripping wet, cross, and +uncomfortable. + + The first question of course was, how to get dry again: they +had a consultation about this, and after a few minutes it seemed +quite natural to Alice to find herself talking familiarly with +them, as if she had known them all her life. Indeed, she had +quite a long argument with the Lory, who at last turned sulky, +and would only say, `I am older than you, and must know better'; +and this Alice would not allow without knowing how old it was, +and, as the Lory positively refused to tell its age, there was no +more to be said. + + At last the Mouse, who seemed to be a person of authority among +them, called out, `Sit down, all of you, and listen to me! I'LL +soon make you dry enough!' They all sat down at once, in a large +ring, with the Mouse in the middle. Alice kept her eyes +anxiously fixed on it, for she felt sure she would catch a bad +cold if she did not get dry very soon. + + `Ahem!' said the Mouse with an important air, `are you all ready? +This is the driest thing I know. Silence all round, if you please! +"William the Conqueror, whose cause was favoured by the pope, was +soon submitted to by the English, who wanted leaders, and had been +of late much accustomed to usurpation and conquest. Edwin and +Morcar, the earls of Mercia and Northumbria--"' + + `Ugh!' said the Lory, with a shiver. + + `I beg your pardon!' said the Mouse, frowning, but very +politely: `Did you speak?' + + `Not I!' said the Lory hastily. + + `I thought you did,' said the Mouse. `--I proceed. "Edwin and +Morcar, the earls of Mercia and Northumbria, declared for him: +and even Stigand, the patriotic archbishop of Canterbury, found +it advisable--"' + + `Found WHAT?' said the Duck. + + `Found IT,' the Mouse replied rather crossly: `of course you +know what "it" means.' + + `I know what "it" means well enough, when I find a thing,' said +the Duck: `it's generally a frog or a worm. The question is, +what did the archbishop find?' + + The Mouse did not notice this question, but hurriedly went on, +`"--found it advisable to go with Edgar Atheling to meet William +and offer him the crown. William's conduct at first was +moderate. But the insolence of his Normans--" How are you +getting on now, my dear?' it continued, turning to Alice as it +spoke. + + `As wet as ever,' said Alice in a melancholy tone: `it doesn't +seem to dry me at all.' + + `In that case,' said the Dodo solemnly, rising to its feet, `I +move that the meeting adjourn, for the immediate adoption of more +energetic remedies--' + + `Speak English!' said the Eaglet. `I don't know the meaning of +half those long words, and, what's more, I don't believe you do +either!' And the Eaglet bent down its head to hide a smile: +some of the other birds tittered audibly. + + `What I was going to say,' said the Dodo in an offended tone, +`was, that the best thing to get us dry would be a Caucus-race.' + + `What IS a Caucus-race?' said Alice; not that she wanted much +to know, but the Dodo had paused as if it thought that SOMEBODY +ought to speak, and no one else seemed inclined to say anything. + + `Why,' said the Dodo, `the best way to explain it is to do it.' +(And, as you might like to try the thing yourself, some winter +day, I will tell you how the Dodo managed it.) + + First it marked out a race-course, in a sort of circle, (`the +exact shape doesn't matter,' it said,) and then all the party +were placed along the course, here and there. There was no `One, +two, three, and away,' but they began running when they liked, +and left off when they liked, so that it was not easy to know +when the race was over. However, when they had been running half +an hour or so, and were quite dry again, the Dodo suddenly called +out `The race is over!' and they all crowded round it, panting, +and asking, `But who has won?' + + This question the Dodo could not answer without a great deal of +thought, and it sat for a long time with one finger pressed upon +its forehead (the position in which you usually see Shakespeare, +in the pictures of him), while the rest waited in silence. At +last the Dodo said, `EVERYBODY has won, and all must have +prizes.' + + `But who is to give the prizes?' quite a chorus of voices +asked. + + `Why, SHE, of course,' said the Dodo, pointing to Alice with +one finger; and the whole party at once crowded round her, +calling out in a confused way, `Prizes! Prizes!' + + Alice had no idea what to do, and in despair she put her hand +in her pocket, and pulled out a box of comfits, (luckily the salt +water had not got into it), and handed them round as prizes. +There was exactly one a-piece all round. + + `But she must have a prize herself, you know,' said the Mouse. + + `Of course,' the Dodo replied very gravely. `What else have +you got in your pocket?' he went on, turning to Alice. + + `Only a thimble,' said Alice sadly. + + `Hand it over here,' said the Dodo. + + Then they all crowded round her once more, while the Dodo +solemnly presented the thimble, saying `We beg your acceptance of +this elegant thimble'; and, when it had finished this short +speech, they all cheered. + + Alice thought the whole thing very absurd, but they all looked +so grave that she did not dare to laugh; and, as she could not +think of anything to say, she simply bowed, and took the thimble, +looking as solemn as she could. + + The next thing was to eat the comfits: this caused some noise +and confusion, as the large birds complained that they could not +taste theirs, and the small ones choked and had to be patted on +the back. However, it was over at last, and they sat down again +in a ring, and begged the Mouse to tell them something more. + + `You promised to tell me your history, you know,' said Alice, +`and why it is you hate--C and D,' she added in a whisper, half +afraid that it would be offended again. + + `Mine is a long and a sad tale!' said the Mouse, turning to +Alice, and sighing. + + `It IS a long tail, certainly,' said Alice, looking down with +wonder at the Mouse's tail; `but why do you call it sad?' And +she kept on puzzling about it while the Mouse was speaking, so +that her idea of the tale was something like this:-- + + `Fury said to a + mouse, That he + met in the + house, + "Let us + both go to + law: I will + prosecute + YOU. --Come, + I'll take no + denial; We + must have a + trial: For + really this + morning I've + nothing + to do." + Said the + mouse to the + cur, "Such + a trial, + dear Sir, + With + no jury + or judge, + would be + wasting + our + breath." + "I'll be + judge, I'll + be jury," + Said + cunning + old Fury: + "I'll + try the + whole + cause, + and + condemn + you + to + death."' + + + `You are not attending!' said the Mouse to Alice severely. +`What are you thinking of?' + + `I beg your pardon,' said Alice very humbly: `you had got to +the fifth bend, I think?' + + `I had NOT!' cried the Mouse, sharply and very angrily. + + `A knot!' said Alice, always ready to make herself useful, and +looking anxiously about her. `Oh, do let me help to undo it!' + + `I shall do nothing of the sort,' said the Mouse, getting up +and walking away. `You insult me by talking such nonsense!' + + `I didn't mean it!' pleaded poor Alice. `But you're so easily +offended, you know!' + + The Mouse only growled in reply. + + `Please come back and finish your story!' Alice called after +it; and the others all joined in chorus, `Yes, please do!' but +the Mouse only shook its head impatiently, and walked a little +quicker. + + `What a pity it wouldn't stay!' sighed the Lory, as soon as it +was quite out of sight; and an old Crab took the opportunity of +saying to her daughter `Ah, my dear! Let this be a lesson to you +never to lose YOUR temper!' `Hold your tongue, Ma!' said the +young Crab, a little snappishly. `You're enough to try the +patience of an oyster!' + + `I wish I had our Dinah here, I know I do!' said Alice aloud, +addressing nobody in particular. `She'd soon fetch it back!' + + `And who is Dinah, if I might venture to ask the question?' +said the Lory. + + Alice replied eagerly, for she was always ready to talk about +her pet: `Dinah's our cat. And she's such a capital one for +catching mice you can't think! And oh, I wish you could see her +after the birds! Why, she'll eat a little bird as soon as look +at it!' + + This speech caused a remarkable sensation among the party. +Some of the birds hurried off at once: one old Magpie began +wrapping itself up very carefully, remarking, `I really must be +getting home; the night-air doesn't suit my throat!' and a Canary +called out in a trembling voice to its children, `Come away, my +dears! It's high time you were all in bed!' On various pretexts +they all moved off, and Alice was soon left alone. + + `I wish I hadn't mentioned Dinah!' she said to herself in a +melancholy tone. `Nobody seems to like her, down here, and I'm +sure she's the best cat in the world! Oh, my dear Dinah! I +wonder if I shall ever see you any more!' And here poor Alice +began to cry again, for she felt very lonely and low-spirited. +In a little while, however, she again heard a little pattering of +footsteps in the distance, and she looked up eagerly, half hoping +that the Mouse had changed his mind, and was coming back to +finish his story. + + + + CHAPTER IV + + The Rabbit Sends in a Little Bill + + + It was the White Rabbit, trotting slowly back again, and +looking anxiously about as it went, as if it had lost something; +and she heard it muttering to itself `The Duchess! The Duchess! +Oh my dear paws! Oh my fur and whiskers! She'll get me +executed, as sure as ferrets are ferrets! Where CAN I have +dropped them, I wonder?' Alice guessed in a moment that it was +looking for the fan and the pair of white kid gloves, and she +very good-naturedly began hunting about for them, but they were +nowhere to be seen--everything seemed to have changed since her +swim in the pool, and the great hall, with the glass table and +the little door, had vanished completely. + + Very soon the Rabbit noticed Alice, as she went hunting about, +and called out to her in an angry tone, `Why, Mary Ann, what ARE +you doing out here? Run home this moment, and fetch me a pair of +gloves and a fan! Quick, now!' And Alice was so much frightened +that she ran off at once in the direction it pointed to, without +trying to explain the mistake it had made. + + `He took me for his housemaid,' she said to herself as she ran. +`How surprised he'll be when he finds out who I am! But I'd +better take him his fan and gloves--that is, if I can find them.' +As she said this, she came upon a neat little house, on the door +of which was a bright brass plate with the name `W. RABBIT' +engraved upon it. She went in without knocking, and hurried +upstairs, in great fear lest she should meet the real Mary Ann, +and be turned out of the house before she had found the fan and +gloves. + + `How queer it seems,' Alice said to herself, `to be going +messages for a rabbit! I suppose Dinah'll be sending me on +messages next!' And she began fancying the sort of thing that +would happen: `"Miss Alice! Come here directly, and get ready +for your walk!" "Coming in a minute, nurse! But I've got to see +that the mouse doesn't get out." Only I don't think,' Alice went +on, `that they'd let Dinah stop in the house if it began ordering +people about like that!' + + By this time she had found her way into a tidy little room with +a table in the window, and on it (as she had hoped) a fan and two +or three pairs of tiny white kid gloves: she took up the fan and +a pair of the gloves, and was just going to leave the room, when +her eye fell upon a little bottle that stood near the looking- +glass. There was no label this time with the words `DRINK ME,' +but nevertheless she uncorked it and put it to her lips. `I know +SOMETHING interesting is sure to happen,' she said to herself, +`whenever I eat or drink anything; so I'll just see what this +bottle does. I do hope it'll make me grow large again, for +really I'm quite tired of being such a tiny little thing!' + + It did so indeed, and much sooner than she had expected: +before she had drunk half the bottle, she found her head pressing +against the ceiling, and had to stoop to save her neck from being +broken. She hastily put down the bottle, saying to herself +`That's quite enough--I hope I shan't grow any more--As it is, I +can't get out at the door--I do wish I hadn't drunk quite so +much!' + + Alas! it was too late to wish that! She went on growing, and +growing, and very soon had to kneel down on the floor: in +another minute there was not even room for this, and she tried +the effect of lying down with one elbow against the door, and the +other arm curled round her head. Still she went on growing, and, +as a last resource, she put one arm out of the window, and one +foot up the chimney, and said to herself `Now I can do no more, +whatever happens. What WILL become of me?' + + Luckily for Alice, the little magic bottle had now had its full +effect, and she grew no larger: still it was very uncomfortable, +and, as there seemed to be no sort of chance of her ever getting +out of the room again, no wonder she felt unhappy. + + `It was much pleasanter at home,' thought poor Alice, `when one +wasn't always growing larger and smaller, and being ordered about +by mice and rabbits. I almost wish I hadn't gone down that +rabbit-hole--and yet--and yet--it's rather curious, you know, +this sort of life! I do wonder what CAN have happened to me! +When I used to read fairy-tales, I fancied that kind of thing +never happened, and now here I am in the middle of one! There +ought to be a book written about me, that there ought! And when +I grow up, I'll write one--but I'm grown up now,' she added in a +sorrowful tone; `at least there's no room to grow up any more +HERE.' + + `But then,' thought Alice, `shall I NEVER get any older than I +am now? That'll be a comfort, one way--never to be an old woman-- +but then--always to have lessons to learn! Oh, I shouldn't like THAT!' + + `Oh, you foolish Alice!' she answered herself. `How can you +learn lessons in here? Why, there's hardly room for YOU, and no +room at all for any lesson-books!' + + And so she went on, taking first one side and then the other, +and making quite a conversation of it altogether; but after a few +minutes she heard a voice outside, and stopped to listen. + + `Mary Ann! Mary Ann!' said the voice. `Fetch me my gloves +this moment!' Then came a little pattering of feet on the +stairs. Alice knew it was the Rabbit coming to look for her, and +she trembled till she shook the house, quite forgetting that she +was now about a thousand times as large as the Rabbit, and had no +reason to be afraid of it. + + Presently the Rabbit came up to the door, and tried to open it; +but, as the door opened inwards, and Alice's elbow was pressed +hard against it, that attempt proved a failure. Alice heard it +say to itself `Then I'll go round and get in at the window.' + + `THAT you won't' thought Alice, and, after waiting till she +fancied she heard the Rabbit just under the window, she suddenly +spread out her hand, and made a snatch in the air. She did not +get hold of anything, but she heard a little shriek and a fall, +and a crash of broken glass, from which she concluded that it was +just possible it had fallen into a cucumber-frame, or something +of the sort. + + Next came an angry voice--the Rabbit's--`Pat! Pat! Where are +you?' And then a voice she had never heard before, `Sure then +I'm here! Digging for apples, yer honour!' + + `Digging for apples, indeed!' said the Rabbit angrily. `Here! +Come and help me out of THIS!' (Sounds of more broken glass.) + + `Now tell me, Pat, what's that in the window?' + + `Sure, it's an arm, yer honour!' (He pronounced it `arrum.') + + `An arm, you goose! Who ever saw one that size? Why, it +fills the whole window!' + + `Sure, it does, yer honour: but it's an arm for all that.' + + `Well, it's got no business there, at any rate: go and take it +away!' + + There was a long silence after this, and Alice could only hear +whispers now and then; such as, `Sure, I don't like it, yer +honour, at all, at all!' `Do as I tell you, you coward!' and at +last she spread out her hand again, and made another snatch in +the air. This time there were TWO little shrieks, and more +sounds of broken glass. `What a number of cucumber-frames there +must be!' thought Alice. `I wonder what they'll do next! As for +pulling me out of the window, I only wish they COULD! I'm sure I +don't want to stay in here any longer!' + + She waited for some time without hearing anything more: at +last came a rumbling of little cartwheels, and the sound of a +good many voices all talking together: she made out the words: +`Where's the other ladder?--Why, I hadn't to bring but one; +Bill's got the other--Bill! fetch it here, lad!--Here, put 'em up +at this corner--No, tie 'em together first--they don't reach half +high enough yet--Oh! they'll do well enough; don't be particular-- +Here, Bill! catch hold of this rope--Will the roof bear?--Mind +that loose slate--Oh, it's coming down! Heads below!' (a loud +crash)--`Now, who did that?--It was Bill, I fancy--Who's to go +down the chimney?--Nay, I shan't! YOU do it!--That I won't, +then!--Bill's to go down--Here, Bill! the master says you're to +go down the chimney!' + + `Oh! So Bill's got to come down the chimney, has he?' said +Alice to herself. `Shy, they seem to put everything upon Bill! +I wouldn't be in Bill's place for a good deal: this fireplace is +narrow, to be sure; but I THINK I can kick a little!' + + She drew her foot as far down the chimney as she could, and +waited till she heard a little animal (she couldn't guess of what +sort it was) scratching and scrambling about in the chimney close +above her: then, saying to herself `This is Bill,' she gave one +sharp kick, and waited to see what would happen next. + + The first thing she heard was a general chorus of `There goes +Bill!' then the Rabbit's voice along--`Catch him, you by the +hedge!' then silence, and then another confusion of voices--`Hold +up his head--Brandy now--Don't choke him--How was it, old fellow? +What happened to you? Tell us all about it!' + + Last came a little feeble, squeaking voice, (`That's Bill,' +thought Alice,) `Well, I hardly know--No more, thank ye; I'm +better now--but I'm a deal too flustered to tell you--all I know +is, something comes at me like a Jack-in-the-box, and up I goes +like a sky-rocket!' + + `So you did, old fellow!' said the others. + + `We must burn the house down!' said the Rabbit's voice; and +Alice called out as loud as she could, `If you do. I'll set +Dinah at you!' + + There was a dead silence instantly, and Alice thought to +herself, `I wonder what they WILL do next! If they had any +sense, they'd take the roof off.' After a minute or two, they +began moving about again, and Alice heard the Rabbit say, `A +barrowful will do, to begin with.' + + `A barrowful of WHAT?' thought Alice; but she had not long to +doubt, for the next moment a shower of little pebbles came +rattling in at the window, and some of them hit her in the face. +`I'll put a stop to this,' she said to herself, and shouted out, +`You'd better not do that again!' which produced another dead +silence. + + Alice noticed with some surprise that the pebbles were all +turning into little cakes as they lay on the floor, and a bright +idea came into her head. `If I eat one of these cakes,' she +thought, `it's sure to make SOME change in my size; and as it +can't possibly make me larger, it must make me smaller, I +suppose.' + + So she swallowed one of the cakes, and was delighted to find +that she began shrinking directly. As soon as she was small +enough to get through the door, she ran out of the house, and +found quite a crowd of little animals and birds waiting outside. +The poor little Lizard, Bill, was in the middle, being held up by +two guinea-pigs, who were giving it something out of a bottle. +They all made a rush at Alice the moment she appeared; but she +ran off as hard as she could, and soon found herself safe in a +thick wood. + + `The first thing I've got to do,' said Alice to herself, as she +wandered about in the wood, `is to grow to my right size again; +and the second thing is to find my way into that lovely garden. +I think that will be the best plan.' + + It sounded an excellent plan, no doubt, and very neatly and +simply arranged; the only difficulty was, that she had not the +smallest idea how to set about it; and while she was peering +about anxiously among the trees, a little sharp bark just over +her head made her look up in a great hurry. + + An enormous puppy was looking down at her with large round +eyes, and feebly stretching out one paw, trying to touch her. +`Poor little thing!' said Alice, in a coaxing tone, and she tried +hard to whistle to it; but she was terribly frightened all the +time at the thought that it might be hungry, in which case it +would be very likely to eat her up in spite of all her coaxing. + + Hardly knowing what she did, she picked up a little bit of +stick, and held it out to the puppy; whereupon the puppy jumped +into the air off all its feet at once, with a yelp of delight, +and rushed at the stick, and made believe to worry it; then Alice +dodged behind a great thistle, to keep herself from being run +over; and the moment she appeared on the other side, the puppy +made another rush at the stick, and tumbled head over heels in +its hurry to get hold of it; then Alice, thinking it was very +like having a game of play with a cart-horse, and expecting every +moment to be trampled under its feet, ran round the thistle +again; then the puppy began a series of short charges at the +stick, running a very little way forwards each time and a long +way back, and barking hoarsely all the while, till at last it sat +down a good way off, panting, with its tongue hanging out of its +mouth, and its great eyes half shut. + + This seemed to Alice a good opportunity for making her escape; +so she set off at once, and ran till she was quite tired and out +of breath, and till the puppy's bark sounded quite faint in the +distance. + + `And yet what a dear little puppy it was!' said Alice, as she +leant against a buttercup to rest herself, and fanned herself +with one of the leaves: `I should have liked teaching it tricks +very much, if--if I'd only been the right size to do it! Oh +dear! I'd nearly forgotten that I've got to grow up again! Let +me see--how IS it to be managed? I suppose I ought to eat or +drink something or other; but the great question is, what?' + + The great question certainly was, what? Alice looked all round +her at the flowers and the blades of grass, but she did not see +anything that looked like the right thing to eat or drink under +the circumstances. There was a large mushroom growing near her, +about the same height as herself; and when she had looked under +it, and on both sides of it, and behind it, it occurred to her +that she might as well look and see what was on the top of it. + + She stretched herself up on tiptoe, and peeped over the edge of +the mushroom, and her eyes immediately met those of a large +caterpillar, that was sitting on the top with its arms folded, +quietly smoking a long hookah, and taking not the smallest notice +of her or of anything else. + + + + CHAPTER V + + Advice from a Caterpillar + + + The Caterpillar and Alice looked at each other for some time in +silence: at last the Caterpillar took the hookah out of its +mouth, and addressed her in a languid, sleepy voice. + + `Who are YOU?' said the Caterpillar. + + This was not an encouraging opening for a conversation. Alice +replied, rather shyly, `I--I hardly know, sir, just at present-- +at least I know who I WAS when I got up this morning, but I think +I must have been changed several times since then.' + + `What do you mean by that?' said the Caterpillar sternly. +`Explain yourself!' + + `I can't explain MYSELF, I'm afraid, sir' said Alice, `because +I'm not myself, you see.' + + `I don't see,' said the Caterpillar. + + `I'm afraid I can't put it more clearly,' Alice replied very +politely, `for I can't understand it myself to begin with; and +being so many different sizes in a day is very confusing.' + + `It isn't,' said the Caterpillar. + + `Well, perhaps you haven't found it so yet,' said Alice; `but +when you have to turn into a chrysalis--you will some day, you +know--and then after that into a butterfly, I should think you'll +feel it a little queer, won't you?' + + `Not a bit,' said the Caterpillar. + + `Well, perhaps your feelings may be different,' said Alice; +`all I know is, it would feel very queer to ME.' + + `You!' said the Caterpillar contemptuously. `Who are YOU?' + + Which brought them back again to the beginning of the +conversation. Alice felt a little irritated at the Caterpillar's +making such VERY short remarks, and she drew herself up and said, +very gravely, `I think, you ought to tell me who YOU are, first.' + + `Why?' said the Caterpillar. + + Here was another puzzling question; and as Alice could not +think of any good reason, and as the Caterpillar seemed to be in +a VERY unpleasant state of mind, she turned away. + + `Come back!' the Caterpillar called after her. `I've something +important to say!' + + This sounded promising, certainly: Alice turned and came back +again. + + `Keep your temper,' said the Caterpillar. + + `Is that all?' said Alice, swallowing down her anger as well as +she could. + + `No,' said the Caterpillar. + + Alice thought she might as well wait, as she had nothing else +to do, and perhaps after all it might tell her something worth +hearing. For some minutes it puffed away without speaking, but +at last it unfolded its arms, took the hookah out of its mouth +again, and said, `So you think you're changed, do you?' + + `I'm afraid I am, sir,' said Alice; `I can't remember things as +I used--and I don't keep the same size for ten minutes together!' + + `Can't remember WHAT things?' said the Caterpillar. + + `Well, I've tried to say "HOW DOTH THE LITTLE BUSY BEE," but it +all came different!' Alice replied in a very melancholy voice. + + `Repeat, "YOU ARE OLD, FATHER WILLIAM,"' said the Caterpillar. + + Alice folded her hands, and began:-- + + `You are old, Father William,' the young man said, + `And your hair has become very white; + And yet you incessantly stand on your head-- + Do you think, at your age, it is right?' + + `In my youth,' Father William replied to his son, + `I feared it might injure the brain; + But, now that I'm perfectly sure I have none, + Why, I do it again and again.' + + `You are old,' said the youth, `as I mentioned before, + And have grown most uncommonly fat; + Yet you turned a back-somersault in at the door-- + Pray, what is the reason of that?' + + `In my youth,' said the sage, as he shook his grey locks, + `I kept all my limbs very supple + By the use of this ointment--one shilling the box-- + Allow me to sell you a couple?' + + `You are old,' said the youth, `and your jaws are too weak + For anything tougher than suet; + Yet you finished the goose, with the bones and the beak-- + Pray how did you manage to do it?' + + `In my youth,' said his father, `I took to the law, + And argued each case with my wife; + And the muscular strength, which it gave to my jaw, + Has lasted the rest of my life.' + + `You are old,' said the youth, `one would hardly suppose + That your eye was as steady as ever; + Yet you balanced an eel on the end of your nose-- + What made you so awfully clever?' + + `I have answered three questions, and that is enough,' + Said his father; `don't give yourself airs! + Do you think I can listen all day to such stuff? + Be off, or I'll kick you down stairs!' + + + `That is not said right,' said the Caterpillar. + + `Not QUITE right, I'm afraid,' said Alice, timidly; `some of the +words have got altered.' + + `It is wrong from beginning to end,' said the Caterpillar +decidedly, and there was silence for some minutes. + + The Caterpillar was the first to speak. + + `What size do you want to be?' it asked. + + `Oh, I'm not particular as to size,' Alice hastily replied; +`only one doesn't like changing so often, you know.' + + `I DON'T know,' said the Caterpillar. + + Alice said nothing: she had never been so much contradicted in +her life before, and she felt that she was losing her temper. + + `Are you content now?' said the Caterpillar. + + `Well, I should like to be a LITTLE larger, sir, if you +wouldn't mind,' said Alice: `three inches is such a wretched +height to be.' + + `It is a very good height indeed!' said the Caterpillar +angrily, rearing itself upright as it spoke (it was exactly three +inches high). + + `But I'm not used to it!' pleaded poor Alice in a piteous tone. +And she thought of herself, `I wish the creatures wouldn't be so +easily offended!' + + `You'll get used to it in time,' said the Caterpillar; and it +put the hookah into its mouth and began smoking again. + + This time Alice waited patiently until it chose to speak again. +In a minute or two the Caterpillar took the hookah out of its +mouth and yawned once or twice, and shook itself. Then it got +down off the mushroom, and crawled away in the grass, merely +remarking as it went, `One side will make you grow taller, and +the other side will make you grow shorter.' + + `One side of WHAT? The other side of WHAT?' thought Alice to +herself. + + `Of the mushroom,' said the Caterpillar, just as if she had +asked it aloud; and in another moment it was out of sight. + + Alice remained looking thoughtfully at the mushroom for a +minute, trying to make out which were the two sides of it; and as +it was perfectly round, she found this a very difficult question. +However, at last she stretched her arms round it as far as they +would go, and broke off a bit of the edge with each hand. + + `And now which is which?' she said to herself, and nibbled a +little of the right-hand bit to try the effect: the next moment +she felt a violent blow underneath her chin: it had struck her +foot! + + She was a good deal frightened by this very sudden change, but +she felt that there was no time to be lost, as she was shrinking +rapidly; so she set to work at once to eat some of the other bit. +Her chin was pressed so closely against her foot, that there was +hardly room to open her mouth; but she did it at last, and +managed to swallow a morsel of the lefthand bit. + + + * * * * * * * + + * * * * * * + + * * * * * * * + + `Come, my head's free at last!' said Alice in a tone of +delight, which changed into alarm in another moment, when she +found that her shoulders were nowhere to be found: all she could +see, when she looked down, was an immense length of neck, which +seemed to rise like a stalk out of a sea of green leaves that lay +far below her. + + `What CAN all that green stuff be?' said Alice. `And where +HAVE my shoulders got to? And oh, my poor hands, how is it I +can't see you?' She was moving them about as she spoke, but no +result seemed to follow, except a little shaking among the +distant green leaves. + + As there seemed to be no chance of getting her hands up to her +head, she tried to get her head down to them, and was delighted +to find that her neck would bend about easily in any direction, +like a serpent. She had just succeeded in curving it down into a +graceful zigzag, and was going to dive in among the leaves, which +she found to be nothing but the tops of the trees under which she +had been wandering, when a sharp hiss made her draw back in a +hurry: a large pigeon had flown into her face, and was beating +her violently with its wings. + + `Serpent!' screamed the Pigeon. + + `I'm NOT a serpent!' said Alice indignantly. `Let me alone!' + + `Serpent, I say again!' repeated the Pigeon, but in a more +subdued tone, and added with a kind of sob, `I've tried every +way, and nothing seems to suit them!' + + `I haven't the least idea what you're talking about,' said +Alice. + + `I've tried the roots of trees, and I've tried banks, and I've +tried hedges,' the Pigeon went on, without attending to her; `but +those serpents! There's no pleasing them!' + + Alice was more and more puzzled, but she thought there was no +use in saying anything more till the Pigeon had finished. + + `As if it wasn't trouble enough hatching the eggs,' said the +Pigeon; `but I must be on the look-out for serpents night and +day! Why, I haven't had a wink of sleep these three weeks!' + + `I'm very sorry you've been annoyed,' said Alice, who was +beginning to see its meaning. + + `And just as I'd taken the highest tree in the wood,' continued +the Pigeon, raising its voice to a shriek, `and just as I was +thinking I should be free of them at last, they must needs come +wriggling down from the sky! Ugh, Serpent!' + + `But I'm NOT a serpent, I tell you!' said Alice. `I'm a--I'm +a--' + + `Well! WHAT are you?' said the Pigeon. `I can see you're +trying to invent something!' + + `I--I'm a little girl,' said Alice, rather doubtfully, as she +remembered the number of changes she had gone through that day. + + `A likely story indeed!' said the Pigeon in a tone of the +deepest contempt. `I've seen a good many little girls in my +time, but never ONE with such a neck as that! No, no! You're a +serpent; and there's no use denying it. I suppose you'll be +telling me next that you never tasted an egg!' + + `I HAVE tasted eggs, certainly,' said Alice, who was a very +truthful child; `but little girls eat eggs quite as much as +serpents do, you know.' + + `I don't believe it,' said the Pigeon; `but if they do, why +then they're a kind of serpent, that's all I can say.' + + This was such a new idea to Alice, that she was quite silent +for a minute or two, which gave the Pigeon the opportunity of +adding, `You're looking for eggs, I know THAT well enough; and +what does it matter to me whether you're a little girl or a +serpent?' + + `It matters a good deal to ME,' said Alice hastily; `but I'm +not looking for eggs, as it happens; and if I was, I shouldn't +want YOURS: I don't like them raw.' + + `Well, be off, then!' said the Pigeon in a sulky tone, as it +settled down again into its nest. Alice crouched down among the +trees as well as she could, for her neck kept getting entangled +among the branches, and every now and then she had to stop and +untwist it. After a while she remembered that she still held the +pieces of mushroom in her hands, and she set to work very +carefully, nibbling first at one and then at the other, and +growing sometimes taller and sometimes shorter, until she had +succeeded in bringing herself down to her usual height. + + It was so long since she had been anything near the right size, +that it felt quite strange at first; but she got used to it in a +few minutes, and began talking to herself, as usual. `Come, +there's half my plan done now! How puzzling all these changes +are! I'm never sure what I'm going to be, from one minute to +another! However, I've got back to my right size: the next +thing is, to get into that beautiful garden--how IS that to be +done, I wonder?' As she said this, she came suddenly upon an +open place, with a little house in it about four feet high. +`Whoever lives there,' thought Alice, `it'll never do to come +upon them THIS size: why, I should frighten them out of their +wits!' So she began nibbling at the righthand bit again, and did +not venture to go near the house till she had brought herself +down to nine inches high. + + + + CHAPTER VI + + Pig and Pepper + + + For a minute or two she stood looking at the house, and +wondering what to do next, when suddenly a footman in livery came +running out of the wood--(she considered him to be a footman +because he was in livery: otherwise, judging by his face only, +she would have called him a fish)--and rapped loudly at the door +with his knuckles. It was opened by another footman in livery, +with a round face, and large eyes like a frog; and both footmen, +Alice noticed, had powdered hair that curled all over their +heads. She felt very curious to know what it was all about, and +crept a little way out of the wood to listen. + + The Fish-Footman began by producing from under his arm a great +letter, nearly as large as himself, and this he handed over to +the other, saying, in a solemn tone, `For the Duchess. An +invitation from the Queen to play croquet.' The Frog-Footman +repeated, in the same solemn tone, only changing the order of the +words a little, `From the Queen. An invitation for the Duchess +to play croquet.' + + Then they both bowed low, and their curls got entangled +together. + + Alice laughed so much at this, that she had to run back into +the wood for fear of their hearing her; and when she next peeped +out the Fish-Footman was gone, and the other was sitting on the +ground near the door, staring stupidly up into the sky. + + Alice went timidly up to the door, and knocked. + + `There's no sort of use in knocking,' said the Footman, `and +that for two reasons. First, because I'm on the same side of the +door as you are; secondly, because they're making such a noise +inside, no one could possibly hear you.' And certainly there was +a most extraordinary noise going on within--a constant howling +and sneezing, and every now and then a great crash, as if a dish +or kettle had been broken to pieces. + + `Please, then,' said Alice, `how am I to get in?' + + `There might be some sense in your knocking,' the Footman went +on without attending to her, `if we had the door between us. For +instance, if you were INSIDE, you might knock, and I could let +you out, you know.' He was looking up into the sky all the time +he was speaking, and this Alice thought decidedly uncivil. `But +perhaps he can't help it,' she said to herself; `his eyes are so +VERY nearly at the top of his head. But at any rate he might +answer questions.--How am I to get in?' she repeated, aloud. + + `I shall sit here,' the Footman remarked, `till tomorrow--' + + At this moment the door of the house opened, and a large plate +came skimming out, straight at the Footman's head: it just +grazed his nose, and broke to pieces against one of the trees +behind him. + + `--or next day, maybe,' the Footman continued in the same tone, +exactly as if nothing had happened. + + `How am I to get in?' asked Alice again, in a louder tone. + + `ARE you to get in at all?' said the Footman. `That's the +first question, you know.' + + It was, no doubt: only Alice did not like to be told so. +`It's really dreadful,' she muttered to herself, `the way all the +creatures argue. It's enough to drive one crazy!' + + The Footman seemed to think this a good opportunity for +repeating his remark, with variations. `I shall sit here,' he +said, `on and off, for days and days.' + + `But what am I to do?' said Alice. + + `Anything you like,' said the Footman, and began whistling. + + `Oh, there's no use in talking to him,' said Alice desperately: +`he's perfectly idiotic!' And she opened the door and went in. + + The door led right into a large kitchen, which was full of +smoke from one end to the other: the Duchess was sitting on a +three-legged stool in the middle, nursing a baby; the cook was +leaning over the fire, stirring a large cauldron which seemed to +be full of soup. + + `There's certainly too much pepper in that soup!' Alice said to +herself, as well as she could for sneezing. + + There was certainly too much of it in the air. Even the +Duchess sneezed occasionally; and as for the baby, it was +sneezing and howling alternately without a moment's pause. The +only things in the kitchen that did not sneeze, were the cook, +and a large cat which was sitting on the hearth and grinning from +ear to ear. + + `Please would you tell me,' said Alice, a little timidly, for +she was not quite sure whether it was good manners for her to +speak first, `why your cat grins like that?' + + `It's a Cheshire cat,' said the Duchess, `and that's why. Pig!' + + She said the last word with such sudden violence that Alice +quite jumped; but she saw in another moment that it was addressed +to the baby, and not to her, so she took courage, and went on +again:-- + + `I didn't know that Cheshire cats always grinned; in fact, I +didn't know that cats COULD grin.' + + `They all can,' said the Duchess; `and most of 'em do.' + + `I don't know of any that do,' Alice said very politely, +feeling quite pleased to have got into a conversation. + + `You don't know much,' said the Duchess; `and that's a fact.' + + Alice did not at all like the tone of this remark, and thought +it would be as well to introduce some other subject of +conversation. While she was trying to fix on one, the cook took +the cauldron of soup off the fire, and at once set to work +throwing everything within her reach at the Duchess and the baby +--the fire-irons came first; then followed a shower of saucepans, +plates, and dishes. The Duchess took no notice of them even when +they hit her; and the baby was howling so much already, that it +was quite impossible to say whether the blows hurt it or not. + + `Oh, PLEASE mind what you're doing!' cried Alice, jumping up +and down in an agony of terror. `Oh, there goes his PRECIOUS +nose'; as an unusually large saucepan flew close by it, and very +nearly carried it off. + + `If everybody minded their own business,' the Duchess said in a +hoarse growl, `the world would go round a deal faster than it +does.' + + `Which would NOT be an advantage,' said Alice, who felt very +glad to get an opportunity of showing off a little of her +knowledge. `Just think of what work it would make with the day +and night! You see the earth takes twenty-four hours to turn +round on its axis--' + + `Talking of axes,' said the Duchess, `chop off her head!' + + Alice glanced rather anxiously at the cook, to see if she meant +to take the hint; but the cook was busily stirring the soup, and +seemed not to be listening, so she went on again: `Twenty-four +hours, I THINK; or is it twelve? I--' + + `Oh, don't bother ME,' said the Duchess; `I never could abide +figures!' And with that she began nursing her child again, +singing a sort of lullaby to it as she did so, and giving it a +violent shake at the end of every line: + + `Speak roughly to your little boy, + And beat him when he sneezes: + He only does it to annoy, + Because he knows it teases.' + + CHORUS. + + (In which the cook and the baby joined):-- + + `Wow! wow! wow!' + + While the Duchess sang the second verse of the song, she kept +tossing the baby violently up and down, and the poor little thing +howled so, that Alice could hardly hear the words:-- + + `I speak severely to my boy, + I beat him when he sneezes; + For he can thoroughly enjoy + The pepper when he pleases!' + + CHORUS. + + `Wow! wow! wow!' + + `Here! you may nurse it a bit, if you like!' the Duchess said +to Alice, flinging the baby at her as she spoke. `I must go and +get ready to play croquet with the Queen,' and she hurried out of +the room. The cook threw a frying-pan after her as she went out, +but it just missed her. + + Alice caught the baby with some difficulty, as it was a queer- +shaped little creature, and held out its arms and legs in all +directions, `just like a star-fish,' thought Alice. The poor +little thing was snorting like a steam-engine when she caught it, +and kept doubling itself up and straightening itself out again, +so that altogether, for the first minute or two, it was as much +as she could do to hold it. + + As soon as she had made out the proper way of nursing it, +(which was to twist it up into a sort of knot, and then keep +tight hold of its right ear and left foot, so as to prevent its +undoing itself,) she carried it out into the open air. `IF I +don't take this child away with me,' thought Alice, `they're sure +to kill it in a day or two: wouldn't it be murder to leave it +behind?' She said the last words out loud, and the little thing +grunted in reply (it had left off sneezing by this time). `Don't +grunt,' said Alice; `that's not at all a proper way of expressing +yourself.' + + The baby grunted again, and Alice looked very anxiously into +its face to see what was the matter with it. There could be no +doubt that it had a VERY turn-up nose, much more like a snout +than a real nose; also its eyes were getting extremely small for +a baby: altogether Alice did not like the look of the thing at +all. `But perhaps it was only sobbing,' she thought, and looked +into its eyes again, to see if there were any tears. + + No, there were no tears. `If you're going to turn into a pig, +my dear,' said Alice, seriously, `I'll have nothing more to do +with you. Mind now!' The poor little thing sobbed again (or +grunted, it was impossible to say which), and they went on for +some while in silence. + + Alice was just beginning to think to herself, `Now, what am I +to do with this creature when I get it home?' when it grunted +again, so violently, that she looked down into its face in some +alarm. This time there could be NO mistake about it: it was +neither more nor less than a pig, and she felt that it would be +quite absurd for her to carry it further. + + So she set the little creature down, and felt quite relieved to +see it trot away quietly into the wood. `If it had grown up,' +she said to herself, `it would have made a dreadfully ugly child: +but it makes rather a handsome pig, I think.' And she began +thinking over other children she knew, who might do very well as +pigs, and was just saying to herself, `if one only knew the right +way to change them--' when she was a little startled by seeing +the Cheshire Cat sitting on a bough of a tree a few yards off. + + The Cat only grinned when it saw Alice. It looked good- +natured, she thought: still it had VERY long claws and a great +many teeth, so she felt that it ought to be treated with respect. + + `Cheshire Puss,' she began, rather timidly, as she did not at +all know whether it would like the name: however, it only +grinned a little wider. `Come, it's pleased so far,' thought +Alice, and she went on. `Would you tell me, please, which way I +ought to go from here?' + + `That depends a good deal on where you want to get to,' said +the Cat. + + `I don't much care where--' said Alice. + + `Then it doesn't matter which way you go,' said the Cat. + + `--so long as I get SOMEWHERE,' Alice added as an explanation. + + `Oh, you're sure to do that,' said the Cat, `if you only walk +long enough.' + + Alice felt that this could not be denied, so she tried another +question. `What sort of people live about here?' + + `In THAT direction,' the Cat said, waving its right paw round, +`lives a Hatter: and in THAT direction,' waving the other paw, +`lives a March Hare. Visit either you like: they're both mad.' + + `But I don't want to go among mad people,' Alice remarked. + + `Oh, you can't help that,' said the Cat: `we're all mad here. +I'm mad. You're mad.' + + `How do you know I'm mad?' said Alice. + + `You must be,' said the Cat, `or you wouldn't have come here.' + + Alice didn't think that proved it at all; however, she went on +`And how do you know that you're mad?' + + `To begin with,' said the Cat, `a dog's not mad. You grant +that?' + + `I suppose so,' said Alice. + + `Well, then,' the Cat went on, `you see, a dog growls when it's +angry, and wags its tail when it's pleased. Now I growl when I'm +pleased, and wag my tail when I'm angry. Therefore I'm mad.' + + `I call it purring, not growling,' said Alice. + + `Call it what you like,' said the Cat. `Do you play croquet +with the Queen to-day?' + + `I should like it very much,' said Alice, `but I haven't been +invited yet.' + + `You'll see me there,' said the Cat, and vanished. + + Alice was not much surprised at this, she was getting so used +to queer things happening. While she was looking at the place +where it had been, it suddenly appeared again. + + `By-the-bye, what became of the baby?' said the Cat. `I'd +nearly forgotten to ask.' + + `It turned into a pig,' Alice quietly said, just as if it had +come back in a natural way. + + `I thought it would,' said the Cat, and vanished again. + + Alice waited a little, half expecting to see it again, but it +did not appear, and after a minute or two she walked on in the +direction in which the March Hare was said to live. `I've seen +hatters before,' she said to herself; `the March Hare will be +much the most interesting, and perhaps as this is May it won't be +raving mad--at least not so mad as it was in March.' As she said +this, she looked up, and there was the Cat again, sitting on a +branch of a tree. + + `Did you say pig, or fig?' said the Cat. + + `I said pig,' replied Alice; `and I wish you wouldn't keep +appearing and vanishing so suddenly: you make one quite giddy.' + + `All right,' said the Cat; and this time it vanished quite slowly, +beginning with the end of the tail, and ending with the grin, +which remained some time after the rest of it had gone. + + `Well! I've often seen a cat without a grin,' thought Alice; +`but a grin without a cat! It's the most curious thing I ever +saw in my life!' + + She had not gone much farther before she came in sight of the +house of the March Hare: she thought it must be the right house, +because the chimneys were shaped like ears and the roof was +thatched with fur. It was so large a house, that she did not +like to go nearer till she had nibbled some more of the lefthand +bit of mushroom, and raised herself to about two feet high: even +then she walked up towards it rather timidly, saying to herself +`Suppose it should be raving mad after all! I almost wish I'd +gone to see the Hatter instead!' + + + + CHAPTER VII + + A Mad Tea-Party + + + There was a table set out under a tree in front of the house, +and the March Hare and the Hatter were having tea at it: a +Dormouse was sitting between them, fast asleep, and the other two +were using it as a cushion, resting their elbows on it, and talking +over its head. `Very uncomfortable for the Dormouse,' thought Alice; +`only, as it's asleep, I suppose it doesn't mind.' + + The table was a large one, but the three were all crowded +together at one corner of it: `No room! No room!' they cried +out when they saw Alice coming. `There's PLENTY of room!' said +Alice indignantly, and she sat down in a large arm-chair at one +end of the table. + + `Have some wine,' the March Hare said in an encouraging tone. + + Alice looked all round the table, but there was nothing on it +but tea. `I don't see any wine,' she remarked. + + `There isn't any,' said the March Hare. + + `Then it wasn't very civil of you to offer it,' said Alice +angrily. + + `It wasn't very civil of you to sit down without being +invited,' said the March Hare. + + `I didn't know it was YOUR table,' said Alice; `it's laid for a +great many more than three.' + + `Your hair wants cutting,' said the Hatter. He had been +looking at Alice for some time with great curiosity, and this was +his first speech. + + `You should learn not to make personal remarks,' Alice said +with some severity; `it's very rude.' + + The Hatter opened his eyes very wide on hearing this; but all +he SAID was, `Why is a raven like a writing-desk?' + + `Come, we shall have some fun now!' thought Alice. `I'm glad +they've begun asking riddles.--I believe I can guess that,' she +added aloud. + + `Do you mean that you think you can find out the answer to it?' +said the March Hare. + + `Exactly so,' said Alice. + + `Then you should say what you mean,' the March Hare went on. + + `I do,' Alice hastily replied; `at least--at least I mean what +I say--that's the same thing, you know.' + + `Not the same thing a bit!' said the Hatter. `You might just +as well say that "I see what I eat" is the same thing as "I eat +what I see"!' + + `You might just as well say,' added the March Hare, `that "I +like what I get" is the same thing as "I get what I like"!' + + `You might just as well say,' added the Dormouse, who seemed to +be talking in his sleep, `that "I breathe when I sleep" is the +same thing as "I sleep when I breathe"!' + + `It IS the same thing with you,' said the Hatter, and here the +conversation dropped, and the party sat silent for a minute, +while Alice thought over all she could remember about ravens and +writing-desks, which wasn't much. + + The Hatter was the first to break the silence. `What day of +the month is it?' he said, turning to Alice: he had taken his +watch out of his pocket, and was looking at it uneasily, shaking +it every now and then, and holding it to his ear. + + Alice considered a little, and then said `The fourth.' + + `Two days wrong!' sighed the Hatter. `I told you butter +wouldn't suit the works!' he added looking angrily at the March +Hare. + + `It was the BEST butter,' the March Hare meekly replied. + + `Yes, but some crumbs must have got in as well,' the Hatter +grumbled: `you shouldn't have put it in with the bread-knife.' + + The March Hare took the watch and looked at it gloomily: then +he dipped it into his cup of tea, and looked at it again: but he +could think of nothing better to say than his first remark, `It +was the BEST butter, you know.' + + Alice had been looking over his shoulder with some curiosity. +`What a funny watch!' she remarked. `It tells the day of the +month, and doesn't tell what o'clock it is!' + + `Why should it?' muttered the Hatter. `Does YOUR watch tell +you what year it is?' + + `Of course not,' Alice replied very readily: `but that's +because it stays the same year for such a long time together.' + + `Which is just the case with MINE,' said the Hatter. + + Alice felt dreadfully puzzled. The Hatter's remark seemed to +have no sort of meaning in it, and yet it was certainly English. +`I don't quite understand you,' she said, as politely as she +could. + + `The Dormouse is asleep again,' said the Hatter, and he poured +a little hot tea upon its nose. + + The Dormouse shook its head impatiently, and said, without +opening its eyes, `Of course, of course; just what I was going to +remark myself.' + + `Have you guessed the riddle yet?' the Hatter said, turning to +Alice again. + + `No, I give it up,' Alice replied: `what's the answer?' + + `I haven't the slightest idea,' said the Hatter. + + `Nor I,' said the March Hare. + + Alice sighed wearily. `I think you might do something better +with the time,' she said, `than waste it in asking riddles that +have no answers.' + + `If you knew Time as well as I do,' said the Hatter, `you +wouldn't talk about wasting IT. It's HIM.' + + `I don't know what you mean,' said Alice. + + `Of course you don't!' the Hatter said, tossing his head +contemptuously. `I dare say you never even spoke to Time!' + + `Perhaps not,' Alice cautiously replied: `but I know I have to +beat time when I learn music.' + + `Ah! that accounts for it,' said the Hatter. `He won't stand +beating. Now, if you only kept on good terms with him, he'd do +almost anything you liked with the clock. For instance, suppose +it were nine o'clock in the morning, just time to begin lessons: +you'd only have to whisper a hint to Time, and round goes the +clock in a twinkling! Half-past one, time for dinner!' + + (`I only wish it was,' the March Hare said to itself in a +whisper.) + + `That would be grand, certainly,' said Alice thoughtfully: +`but then--I shouldn't be hungry for it, you know.' + + `Not at first, perhaps,' said the Hatter: `but you could keep +it to half-past one as long as you liked.' + + `Is that the way YOU manage?' Alice asked. + + The Hatter shook his head mournfully. `Not I!' he replied. +`We quarrelled last March--just before HE went mad, you know--' +(pointing with his tea spoon at the March Hare,) `--it was at the +great concert given by the Queen of Hearts, and I had to sing + + "Twinkle, twinkle, little bat! + How I wonder what you're at!" + +You know the song, perhaps?' + + `I've heard something like it,' said Alice. + + `It goes on, you know,' the Hatter continued, `in this way:-- + + "Up above the world you fly, + Like a tea-tray in the sky. + Twinkle, twinkle--"' + +Here the Dormouse shook itself, and began singing in its sleep +`Twinkle, twinkle, twinkle, twinkle--' and went on so long that +they had to pinch it to make it stop. + + `Well, I'd hardly finished the first verse,' said the Hatter, +`when the Queen jumped up and bawled out, "He's murdering the +time! Off with his head!"' + + `How dreadfully savage!' exclaimed Alice. + + `And ever since that,' the Hatter went on in a mournful tone, +`he won't do a thing I ask! It's always six o'clock now.' + + A bright idea came into Alice's head. `Is that the reason so +many tea-things are put out here?' she asked. + + `Yes, that's it,' said the Hatter with a sigh: `it's always +tea-time, and we've no time to wash the things between whiles.' + + `Then you keep moving round, I suppose?' said Alice. + + `Exactly so,' said the Hatter: `as the things get used up.' + + `But what happens when you come to the beginning again?' Alice +ventured to ask. + + `Suppose we change the subject,' the March Hare interrupted, +yawning. `I'm getting tired of this. I vote the young lady +tells us a story.' + + `I'm afraid I don't know one,' said Alice, rather alarmed at +the proposal. + + `Then the Dormouse shall!' they both cried. `Wake up, +Dormouse!' And they pinched it on both sides at once. + + The Dormouse slowly opened his eyes. `I wasn't asleep,' he +said in a hoarse, feeble voice: `I heard every word you fellows +were saying.' + + `Tell us a story!' said the March Hare. + + `Yes, please do!' pleaded Alice. + + `And be quick about it,' added the Hatter, `or you'll be asleep +again before it's done.' + + `Once upon a time there were three little sisters,' the +Dormouse began in a great hurry; `and their names were Elsie, +Lacie, and Tillie; and they lived at the bottom of a well--' + + `What did they live on?' said Alice, who always took a great +interest in questions of eating and drinking. + + `They lived on treacle,' said the Dormouse, after thinking a +minute or two. + + `They couldn't have done that, you know,' Alice gently +remarked; `they'd have been ill.' + + `So they were,' said the Dormouse; `VERY ill.' + + Alice tried to fancy to herself what such an extraordinary ways +of living would be like, but it puzzled her too much, so she went +on: `But why did they live at the bottom of a well?' + + `Take some more tea,' the March Hare said to Alice, very +earnestly. + + `I've had nothing yet,' Alice replied in an offended tone, `so +I can't take more.' + + `You mean you can't take LESS,' said the Hatter: `it's very +easy to take MORE than nothing.' + + `Nobody asked YOUR opinion,' said Alice. + + `Who's making personal remarks now?' the Hatter asked +triumphantly. + + Alice did not quite know what to say to this: so she helped +herself to some tea and bread-and-butter, and then turned to the +Dormouse, and repeated her question. `Why did they live at the +bottom of a well?' + + The Dormouse again took a minute or two to think about it, and +then said, `It was a treacle-well.' + + `There's no such thing!' Alice was beginning very angrily, but +the Hatter and the March Hare went `Sh! sh!' and the Dormouse +sulkily remarked, `If you can't be civil, you'd better finish the +story for yourself.' + + `No, please go on!' Alice said very humbly; `I won't interrupt +again. I dare say there may be ONE.' + + `One, indeed!' said the Dormouse indignantly. However, he +consented to go on. `And so these three little sisters--they +were learning to draw, you know--' + + `What did they draw?' said Alice, quite forgetting her promise. + + `Treacle,' said the Dormouse, without considering at all this +time. + + `I want a clean cup,' interrupted the Hatter: `let's all move +one place on.' + + He moved on as he spoke, and the Dormouse followed him: the +March Hare moved into the Dormouse's place, and Alice rather +unwillingly took the place of the March Hare. The Hatter was the +only one who got any advantage from the change: and Alice was a +good deal worse off than before, as the March Hare had just upset +the milk-jug into his plate. + + Alice did not wish to offend the Dormouse again, so she began +very cautiously: `But I don't understand. Where did they draw +the treacle from?' + + `You can draw water out of a water-well,' said the Hatter; `so +I should think you could draw treacle out of a treacle-well--eh, +stupid?' + + `But they were IN the well,' Alice said to the Dormouse, not +choosing to notice this last remark. + + `Of course they were', said the Dormouse; `--well in.' + + This answer so confused poor Alice, that she let the Dormouse +go on for some time without interrupting it. + + `They were learning to draw,' the Dormouse went on, yawning and +rubbing its eyes, for it was getting very sleepy; `and they drew +all manner of things--everything that begins with an M--' + + `Why with an M?' said Alice. + + `Why not?' said the March Hare. + + Alice was silent. + + The Dormouse had closed its eyes by this time, and was going +off into a doze; but, on being pinched by the Hatter, it woke up +again with a little shriek, and went on: `--that begins with an +M, such as mouse-traps, and the moon, and memory, and muchness-- +you know you say things are "much of a muchness"--did you ever +see such a thing as a drawing of a muchness?' + + `Really, now you ask me,' said Alice, very much confused, `I +don't think--' + + `Then you shouldn't talk,' said the Hatter. + + This piece of rudeness was more than Alice could bear: she got +up in great disgust, and walked off; the Dormouse fell asleep +instantly, and neither of the others took the least notice of her +going, though she looked back once or twice, half hoping that +they would call after her: the last time she saw them, they were +trying to put the Dormouse into the teapot. + + `At any rate I'll never go THERE again!' said Alice as she +picked her way through the wood. `It's the stupidest tea-party I +ever was at in all my life!' + + Just as she said this, she noticed that one of the trees had a +door leading right into it. `That's very curious!' she thought. +`But everything's curious today. I think I may as well go in at once.' +And in she went. + + Once more she found herself in the long hall, and close to the +little glass table. `Now, I'll manage better this time,' +she said to herself, and began by taking the little golden key, +and unlocking the door that led into the garden. Then she went +to work nibbling at the mushroom (she had kept a piece of it +in her pocket) till she was about a foot high: then she walked down +the little passage: and THEN--she found herself at last in the +beautiful garden, among the bright flower-beds and the cool fountains. + + + + CHAPTER VIII + + The Queen's Croquet-Ground + + + A large rose-tree stood near the entrance of the garden: the +roses growing on it were white, but there were three gardeners at +it, busily painting them red. Alice thought this a very curious +thing, and she went nearer to watch them, and just as she came up +to them she heard one of them say, `Look out now, Five! Don't go +splashing paint over me like that!' + + `I couldn't help it,' said Five, in a sulky tone; `Seven jogged +my elbow.' + + On which Seven looked up and said, `That's right, Five! Always +lay the blame on others!' + + `YOU'D better not talk!' said Five. `I heard the Queen say only +yesterday you deserved to be beheaded!' + + `What for?' said the one who had spoken first. + + `That's none of YOUR business, Two!' said Seven. + + `Yes, it IS his business!' said Five, `and I'll tell him--it +was for bringing the cook tulip-roots instead of onions.' + + Seven flung down his brush, and had just begun `Well, of all +the unjust things--' when his eye chanced to fall upon Alice, as +she stood watching them, and he checked himself suddenly: the +others looked round also, and all of them bowed low. + + `Would you tell me,' said Alice, a little timidly, `why you are +painting those roses?' + + Five and Seven said nothing, but looked at Two. Two began in a +low voice, `Why the fact is, you see, Miss, this here ought to +have been a RED rose-tree, and we put a white one in by mistake; +and if the Queen was to find it out, we should all have our heads +cut off, you know. So you see, Miss, we're doing our best, afore +she comes, to--' At this moment Five, who had been anxiously +looking across the garden, called out `The Queen! The Queen!' +and the three gardeners instantly threw themselves flat upon +their faces. There was a sound of many footsteps, and Alice +looked round, eager to see the Queen. + + First came ten soldiers carrying clubs; these were all shaped +like the three gardeners, oblong and flat, with their hands and +feet at the corners: next the ten courtiers; these were +ornamented all over with diamonds, and walked two and two, as the +soldiers did. After these came the royal children; there were +ten of them, and the little dears came jumping merrily along hand +in hand, in couples: they were all ornamented with hearts. Next +came the guests, mostly Kings and Queens, and among them Alice +recognised the White Rabbit: it was talking in a hurried nervous +manner, smiling at everything that was said, and went by without +noticing her. Then followed the Knave of Hearts, carrying the +King's crown on a crimson velvet cushion; and, last of all this +grand procession, came THE KING AND QUEEN OF HEARTS. + + Alice was rather doubtful whether she ought not to lie down on +her face like the three gardeners, but she could not remember +ever having heard of such a rule at processions; `and besides, +what would be the use of a procession,' thought she, `if people +had all to lie down upon their faces, so that they couldn't see it?' +So she stood still where she was, and waited. + + When the procession came opposite to Alice, they all stopped +and looked at her, and the Queen said severely `Who is this?' +She said it to the Knave of Hearts, who only bowed and smiled in reply. + + `Idiot!' said the Queen, tossing her head impatiently; and, +turning to Alice, she went on, `What's your name, child?' + + `My name is Alice, so please your Majesty,' said Alice very +politely; but she added, to herself, `Why, they're only a pack of +cards, after all. I needn't be afraid of them!' + + `And who are THESE?' said the Queen, pointing to the three +gardeners who were lying round the rosetree; for, you see, as +they were lying on their faces, and the pattern on their backs +was the same as the rest of the pack, she could not tell whether +they were gardeners, or soldiers, or courtiers, or three of her +own children. + + `How should I know?' said Alice, surprised at her own courage. +`It's no business of MINE.' + + The Queen turned crimson with fury, and, after glaring at her +for a moment like a wild beast, screamed `Off with her head! +Off--' + + `Nonsense!' said Alice, very loudly and decidedly, and the +Queen was silent. + + The King laid his hand upon her arm, and timidly said +`Consider, my dear: she is only a child!' + + The Queen turned angrily away from him, and said to the Knave +`Turn them over!' + + The Knave did so, very carefully, with one foot. + + `Get up!' said the Queen, in a shrill, loud voice, and the +three gardeners instantly jumped up, and began bowing to the +King, the Queen, the royal children, and everybody else. + + `Leave off that!' screamed the Queen. `You make me giddy.' +And then, turning to the rose-tree, she went on, `What HAVE you +been doing here?' + + `May it please your Majesty,' said Two, in a very humble tone, +going down on one knee as he spoke, `we were trying--' + + `I see!' said the Queen, who had meanwhile been examining the +roses. `Off with their heads!' and the procession moved on, +three of the soldiers remaining behind to execute the unfortunate +gardeners, who ran to Alice for protection. + + `You shan't be beheaded!' said Alice, and she put them into a +large flower-pot that stood near. The three soldiers wandered +about for a minute or two, looking for them, and then quietly +marched off after the others. + + `Are their heads off?' shouted the Queen. + + `Their heads are gone, if it please your Majesty!' the soldiers +shouted in reply. + + `That's right!' shouted the Queen. `Can you play croquet?' + + The soldiers were silent, and looked at Alice, as the question +was evidently meant for her. + + `Yes!' shouted Alice. + + `Come on, then!' roared the Queen, and Alice joined the +procession, wondering very much what would happen next. + + `It's--it's a very fine day!' said a timid voice at her side. +She was walking by the White Rabbit, who was peeping anxiously +into her face. + + `Very,' said Alice: `--where's the Duchess?' + + `Hush! Hush!' said the Rabbit in a low, hurried tone. He +looked anxiously over his shoulder as he spoke, and then raised +himself upon tiptoe, put his mouth close to her ear, and +whispered `She's under sentence of execution.' + + `What for?' said Alice. + + `Did you say "What a pity!"?' the Rabbit asked. + + `No, I didn't,' said Alice: `I don't think it's at all a pity. +I said "What for?"' + + `She boxed the Queen's ears--' the Rabbit began. Alice gave a +little scream of laughter. `Oh, hush!' the Rabbit whispered in a +frightened tone. `The Queen will hear you! You see, she came +rather late, and the Queen said--' + + `Get to your places!' shouted the Queen in a voice of thunder, +and people began running about in all directions, tumbling up +against each other; however, they got settled down in a minute or +two, and the game began. Alice thought she had never seen such a +curious croquet-ground in her life; it was all ridges and +furrows; the balls were live hedgehogs, the mallets live +flamingoes, and the soldiers had to double themselves up and to +stand on their hands and feet, to make the arches. + + The chief difficulty Alice found at first was in managing her +flamingo: she succeeded in getting its body tucked away, +comfortably enough, under her arm, with its legs hanging down, +but generally, just as she had got its neck nicely straightened +out, and was going to give the hedgehog a blow with its head, it +WOULD twist itself round and look up in her face, with such a +puzzled expression that she could not help bursting out laughing: +and when she had got its head down, and was going to begin again, +it was very provoking to find that the hedgehog had unrolled +itself, and was in the act of crawling away: besides all this, +there was generally a ridge or furrow in the way wherever she +wanted to send the hedgehog to, and, as the doubled-up soldiers +were always getting up and walking off to other parts of the +ground, Alice soon came to the conclusion that it was a very +difficult game indeed. + + The players all played at once without waiting for turns, +quarrelling all the while, and fighting for the hedgehogs; and in +a very short time the Queen was in a furious passion, and went +stamping about, and shouting `Off with his head!' or `Off with +her head!' about once in a minute. + + Alice began to feel very uneasy: to be sure, she had not as +yet had any dispute with the Queen, but she knew that it might +happen any minute, `and then,' thought she, `what would become of +me? They're dreadfully fond of beheading people here; the great +wonder is, that there's any one left alive!' + + She was looking about for some way of escape, and wondering +whether she could get away without being seen, when she noticed a +curious appearance in the air: it puzzled her very much at +first, but, after watching it a minute or two, she made it out to +be a grin, and she said to herself `It's the Cheshire Cat: now I +shall have somebody to talk to.' + + `How are you getting on?' said the Cat, as soon as there was +mouth enough for it to speak with. + + Alice waited till the eyes appeared, and then nodded. `It's no +use speaking to it,' she thought, `till its ears have come, or at +least one of them.' In another minute the whole head appeared, +and then Alice put down her flamingo, and began an account of the +game, feeling very glad she had someone to listen to her. The +Cat seemed to think that there was enough of it now in sight, and +no more of it appeared. + + `I don't think they play at all fairly,' Alice began, in rather +a complaining tone, `and they all quarrel so dreadfully one can't +hear oneself speak--and they don't seem to have any rules in +particular; at least, if there are, nobody attends to them--and +you've no idea how confusing it is all the things being alive; +for instance, there's the arch I've got to go through next +walking about at the other end of the ground--and I should have +croqueted the Queen's hedgehog just now, only it ran away when it +saw mine coming!' + + `How do you like the Queen?' said the Cat in a low voice. + + `Not at all,' said Alice: `she's so extremely--' Just then +she noticed that the Queen was close behind her, listening: so +she went on, `--likely to win, that it's hardly worth while +finishing the game.' + + The Queen smiled and passed on. + + `Who ARE you talking to?' said the King, going up to Alice, and +looking at the Cat's head with great curiosity. + + `It's a friend of mine--a Cheshire Cat,' said Alice: `allow me +to introduce it.' + + `I don't like the look of it at all,' said the King: +`however, it may kiss my hand if it likes.' + + `I'd rather not,' the Cat remarked. + + `Don't be impertinent,' said the King, `and don't look at me +like that!' He got behind Alice as he spoke. + + `A cat may look at a king,' said Alice. `I've read that in +some book, but I don't remember where.' + + `Well, it must be removed,' said the King very decidedly, and +he called the Queen, who was passing at the moment, `My dear! I +wish you would have this cat removed!' + + The Queen had only one way of settling all difficulties, great +or small. `Off with his head!' she said, without even looking +round. + + `I'll fetch the executioner myself,' said the King eagerly, and +he hurried off. + + Alice thought she might as well go back, and see how the game +was going on, as she heard the Queen's voice in the distance, +screaming with passion. She had already heard her sentence three +of the players to be executed for having missed their turns, and +she did not like the look of things at all, as the game was in +such confusion that she never knew whether it was her turn or +not. So she went in search of her hedgehog. + + The hedgehog was engaged in a fight with another hedgehog, +which seemed to Alice an excellent opportunity for croqueting one +of them with the other: the only difficulty was, that her +flamingo was gone across to the other side of the garden, where +Alice could see it trying in a helpless sort of way to fly up +into a tree. + + By the time she had caught the flamingo and brought it back, +the fight was over, and both the hedgehogs were out of sight: +`but it doesn't matter much,' thought Alice, `as all the arches +are gone from this side of the ground.' So she tucked it away +under her arm, that it might not escape again, and went back for +a little more conversation with her friend. + + When she got back to the Cheshire Cat, she was surprised to +find quite a large crowd collected round it: there was a dispute +going on between the executioner, the King, and the Queen, who +were all talking at once, while all the rest were quite silent, +and looked very uncomfortable. + + The moment Alice appeared, she was appealed to by all three to +settle the question, and they repeated their arguments to her, +though, as they all spoke at once, she found it very hard indeed +to make out exactly what they said. + + The executioner's argument was, that you couldn't cut off a +head unless there was a body to cut it off from: that he had +never had to do such a thing before, and he wasn't going to begin +at HIS time of life. + + The King's argument was, that anything that had a head could be +beheaded, and that you weren't to talk nonsense. + + The Queen's argument was, that if something wasn't done about +it in less than no time she'd have everybody executed, all round. +(It was this last remark that had made the whole party look so +grave and anxious.) + + Alice could think of nothing else to say but `It belongs to the +Duchess: you'd better ask HER about it.' + + `She's in prison,' the Queen said to the executioner: `fetch +her here.' And the executioner went off like an arrow. + + The Cat's head began fading away the moment he was gone, and, +by the time he had come back with the Dutchess, it had entirely +disappeared; so the King and the executioner ran wildly up and down +looking for it, while the rest of the party went back to the game. + + + + CHAPTER IX + + The Mock Turtle's Story + + + `You can't think how glad I am to see you again, you dear old +thing!' said the Duchess, as she tucked her arm affectionately +into Alice's, and they walked off together. + + Alice was very glad to find her in such a pleasant temper, and +thought to herself that perhaps it was only the pepper that had +made her so savage when they met in the kitchen. + + `When I'M a Duchess,' she said to herself, (not in a very +hopeful tone though), `I won't have any pepper in my kitchen AT +ALL. Soup does very well without--Maybe it's always pepper that +makes people hot-tempered,' she went on, very much pleased at +having found out a new kind of rule, `and vinegar that makes them +sour--and camomile that makes them bitter--and--and barley-sugar +and such things that make children sweet-tempered. I only wish +people knew that: then they wouldn't be so stingy about it, you +know--' + + She had quite forgotten the Duchess by this time, and was a +little startled when she heard her voice close to her ear. +`You're thinking about something, my dear, and that makes you +forget to talk. I can't tell you just now what the moral of that +is, but I shall remember it in a bit.' + + `Perhaps it hasn't one,' Alice ventured to remark. + + `Tut, tut, child!' said the Duchess. `Everything's got a +moral, if only you can find it.' And she squeezed herself up +closer to Alice's side as she spoke. + + Alice did not much like keeping so close to her: first, +because the Duchess was VERY ugly; and secondly, because she was +exactly the right height to rest her chin upon Alice's shoulder, +and it was an uncomfortably sharp chin. However, she did not +like to be rude, so she bore it as well as she could. + + `The game's going on rather better now,' she said, by way of +keeping up the conversation a little. + + `'Tis so,' said the Duchess: `and the moral of that is--"Oh, +'tis love, 'tis love, that makes the world go round!"' + + `Somebody said,' Alice whispered, `that it's done by everybody +minding their own business!' + + `Ah, well! It means much the same thing,' said the Duchess, +digging her sharp little chin into Alice's shoulder as she added, +`and the moral of THAT is--"Take care of the sense, and the +sounds will take care of themselves."' + + `How fond she is of finding morals in things!' Alice thought to +herself. + + `I dare say you're wondering why I don't put my arm round your +waist,' the Duchess said after a pause: `the reason is, that I'm +doubtful about the temper of your flamingo. Shall I try the +experiment?' + + `HE might bite,' Alice cautiously replied, not feeling at all +anxious to have the experiment tried. + + `Very true,' said the Duchess: `flamingoes and mustard both +bite. And the moral of that is--"Birds of a feather flock +together."' + + `Only mustard isn't a bird,' Alice remarked. + + `Right, as usual,' said the Duchess: `what a clear way you +have of putting things!' + + `It's a mineral, I THINK,' said Alice. + + `Of course it is,' said the Duchess, who seemed ready to agree +to everything that Alice said; `there's a large mustard-mine near +here. And the moral of that is--"The more there is of mine, the +less there is of yours."' + + `Oh, I know!' exclaimed Alice, who had not attended to this +last remark, `it's a vegetable. It doesn't look like one, but it +is.' + + `I quite agree with you,' said the Duchess; `and the moral of +that is--"Be what you would seem to be"--or if you'd like it put +more simply--"Never imagine yourself not to be otherwise than +what it might appear to others that what you were or might have +been was not otherwise than what you had been would have appeared +to them to be otherwise."' + + `I think I should understand that better,' Alice said very +politely, `if I had it written down: but I can't quite follow it +as you say it.' + + `That's nothing to what I could say if I chose,' the Duchess +replied, in a pleased tone. + + `Pray don't trouble yourself to say it any longer than that,' +said Alice. + + `Oh, don't talk about trouble!' said the Duchess. `I make you +a present of everything I've said as yet.' + + `A cheap sort of present!' thought Alice. `I'm glad they don't +give birthday presents like that!' But she did not venture to +say it out loud. + + `Thinking again?' the Duchess asked, with another dig of her +sharp little chin. + + `I've a right to think,' said Alice sharply, for she was +beginning to feel a little worried. + + `Just about as much right,' said the Duchess, `as pigs have to fly; +and the m--' + + But here, to Alice's great surprise, the Duchess's voice died +away, even in the middle of her favourite word `moral,' and the +arm that was linked into hers began to tremble. Alice looked up, +and there stood the Queen in front of them, with her arms folded, +frowning like a thunderstorm. + + `A fine day, your Majesty!' the Duchess began in a low, weak +voice. + + `Now, I give you fair warning,' shouted the Queen, stamping on +the ground as she spoke; `either you or your head must be off, +and that in about half no time! Take your choice!' + + The Duchess took her choice, and was gone in a moment. + + `Let's go on with the game,' the Queen said to Alice; and Alice +was too much frightened to say a word, but slowly followed her +back to the croquet-ground. + + The other guests had taken advantage of the Queen's absence, +and were resting in the shade: however, the moment they saw her, +they hurried back to the game, the Queen merely remarking that a +moment's delay would cost them their lives. + + All the time they were playing the Queen never left off +quarrelling with the other players, and shouting `Off with his +head!' or `Off with her head!' Those whom she sentenced were +taken into custody by the soldiers, who of course had to leave +off being arches to do this, so that by the end of half an hour +or so there were no arches left, and all the players, except the +King, the Queen, and Alice, were in custody and under sentence of +execution. + + Then the Queen left off, quite out of breath, and said to +Alice, `Have you seen the Mock Turtle yet?' + + `No,' said Alice. `I don't even know what a Mock Turtle is.' + + `It's the thing Mock Turtle Soup is made from,' said the Queen. + + `I never saw one, or heard of one,' said Alice. + + `Come on, then,' said the Queen, `and he shall tell you his +history,' + + As they walked off together, Alice heard the King say in a low +voice, to the company generally, `You are all pardoned.' `Come, +THAT'S a good thing!' she said to herself, for she had felt quite +unhappy at the number of executions the Queen had ordered. + + They very soon came upon a Gryphon, lying fast asleep in the +sun. (IF you don't know what a Gryphon is, look at the picture.) +`Up, lazy thing!' said the Queen, `and take this young lady to +see the Mock Turtle, and to hear his history. I must go back and +see after some executions I have ordered'; and she walked off, +leaving Alice alone with the Gryphon. Alice did not quite like +the look of the creature, but on the whole she thought it would +be quite as safe to stay with it as to go after that savage +Queen: so she waited. + + The Gryphon sat up and rubbed its eyes: then it watched the +Queen till she was out of sight: then it chuckled. `What fun!' +said the Gryphon, half to itself, half to Alice. + + `What IS the fun?' said Alice. + + `Why, SHE,' said the Gryphon. `It's all her fancy, that: they +never executes nobody, you know. Come on!' + + `Everybody says "come on!" here,' thought Alice, as she went +slowly after it: `I never was so ordered about in all my life, +never!' + + They had not gone far before they saw the Mock Turtle in the +distance, sitting sad and lonely on a little ledge of rock, and, +as they came nearer, Alice could hear him sighing as if his heart +would break. She pitied him deeply. `What is his sorrow?' she +asked the Gryphon, and the Gryphon answered, very nearly in the +same words as before, `It's all his fancy, that: he hasn't got +no sorrow, you know. Come on!' + + So they went up to the Mock Turtle, who looked at them with +large eyes full of tears, but said nothing. + + `This here young lady,' said the Gryphon, `she wants for to +know your history, she do.' + + `I'll tell it her,' said the Mock Turtle in a deep, hollow +tone: `sit down, both of you, and don't speak a word till I've +finished.' + + So they sat down, and nobody spoke for some minutes. Alice +thought to herself, `I don't see how he can EVEN finish, if he +doesn't begin.' But she waited patiently. + + `Once,' said the Mock Turtle at last, with a deep sigh, `I was +a real Turtle.' + + These words were followed by a very long silence, broken only +by an occasional exclamation of `Hjckrrh!' from the Gryphon, and +the constant heavy sobbing of the Mock Turtle. Alice was very +nearly getting up and saying, `Thank you, sir, for your +interesting story,' but she could not help thinking there MUST be +more to come, so she sat still and said nothing. + + `When we were little,' the Mock Turtle went on at last, more +calmly, though still sobbing a little now and then, `we went to +school in the sea. The master was an old Turtle--we used to call +him Tortoise--' + + `Why did you call him Tortoise, if he wasn't one?' Alice asked. + + `We called him Tortoise because he taught us,' said the Mock +Turtle angrily: `really you are very dull!' + + `You ought to be ashamed of yourself for asking such a simple +question,' added the Gryphon; and then they both sat silent and +looked at poor Alice, who felt ready to sink into the earth. At +last the Gryphon said to the Mock Turtle, `Drive on, old fellow! +Don't be all day about it!' and he went on in these words: + + `Yes, we went to school in the sea, though you mayn't believe +it--' + + `I never said I didn't!' interrupted Alice. + + `You did,' said the Mock Turtle. + + `Hold your tongue!' added the Gryphon, before Alice could speak +again. The Mock Turtle went on. + + `We had the best of educations--in fact, we went to school +every day--' + + `I'VE been to a day-school, too,' said Alice; `you needn't be +so proud as all that.' + + `With extras?' asked the Mock Turtle a little anxiously. + + `Yes,' said Alice, `we learned French and music.' + + `And washing?' said the Mock Turtle. + + `Certainly not!' said Alice indignantly. + + `Ah! then yours wasn't a really good school,' said the Mock +Turtle in a tone of great relief. `Now at OURS they had at the +end of the bill, "French, music, AND WASHING--extra."' + + `You couldn't have wanted it much,' said Alice; `living at the +bottom of the sea.' + + `I couldn't afford to learn it.' said the Mock Turtle with a +sigh. `I only took the regular course.' + + `What was that?' inquired Alice. + + `Reeling and Writhing, of course, to begin with,' the Mock +Turtle replied; `and then the different branches of Arithmetic-- +Ambition, Distraction, Uglification, and Derision.' + + `I never heard of "Uglification,"' Alice ventured to say. `What is it?' + + The Gryphon lifted up both its paws in surprise. `What! Never +heard of uglifying!' it exclaimed. `You know what to beautify is, +I suppose?' + + `Yes,' said Alice doubtfully: `it means--to--make--anything--prettier.' + + `Well, then,' the Gryphon went on, `if you don't know what to +uglify is, you ARE a simpleton.' + + Alice did not feel encouraged to ask any more questions about +it, so she turned to the Mock Turtle, and said `What else had you +to learn?' + + `Well, there was Mystery,' the Mock Turtle replied, counting +off the subjects on his flappers, `--Mystery, ancient and modern, +with Seaography: then Drawling--the Drawling-master was an old +conger-eel, that used to come once a week: HE taught us +Drawling, Stretching, and Fainting in Coils.' + + `What was THAT like?' said Alice. + + `Well, I can't show it you myself,' the Mock Turtle said: `I'm +too stiff. And the Gryphon never learnt it.' + + `Hadn't time,' said the Gryphon: `I went to the Classics +master, though. He was an old crab, HE was.' + + `I never went to him,' the Mock Turtle said with a sigh: `he +taught Laughing and Grief, they used to say.' + + `So he did, so he did,' said the Gryphon, sighing in his turn; +and both creatures hid their faces in their paws. + + `And how many hours a day did you do lessons?' said Alice, in a +hurry to change the subject. + + `Ten hours the first day,' said the Mock Turtle: `nine the +next, and so on.' + + `What a curious plan!' exclaimed Alice. + + `That's the reason they're called lessons,' the Gryphon +remarked: `because they lessen from day to day.' + + This was quite a new idea to Alice, and she thought it over a +little before she made her next remark. `Then the eleventh day +must have been a holiday?' + + `Of course it was,' said the Mock Turtle. + + `And how did you manage on the twelfth?' Alice went on eagerly. + + `That's enough about lessons,' the Gryphon interrupted in a +very decided tone: `tell her something about the games now.' + + + + CHAPTER X + + The Lobster Quadrille + + + The Mock Turtle sighed deeply, and drew the back of one flapper +across his eyes. He looked at Alice, and tried to speak, but for +a minute or two sobs choked his voice. `Same as if he had a bone +in his throat,' said the Gryphon: and it set to work shaking him +and punching him in the back. At last the Mock Turtle recovered +his voice, and, with tears running down his cheeks, he went on +again:-- + + `You may not have lived much under the sea--' (`I haven't,' said Alice)-- +`and perhaps you were never even introduced to a lobster--' +(Alice began to say `I once tasted--' but checked herself hastily, +and said `No, never') `--so you can have no idea what a delightful +thing a Lobster Quadrille is!' + + `No, indeed,' said Alice. `What sort of a dance is it?' + + `Why,' said the Gryphon, `you first form into a line along the sea-shore--' + + `Two lines!' cried the Mock Turtle. `Seals, turtles, salmon, and so on; +then, when you've cleared all the jelly-fish out of the way--' + + `THAT generally takes some time,' interrupted the Gryphon. + + `--you advance twice--' + + `Each with a lobster as a partner!' cried the Gryphon. + + `Of course,' the Mock Turtle said: `advance twice, set to +partners--' + + `--change lobsters, and retire in same order,' continued the +Gryphon. + + `Then, you know,' the Mock Turtle went on, `you throw the--' + + `The lobsters!' shouted the Gryphon, with a bound into the air. + + `--as far out to sea as you can--' + + `Swim after them!' screamed the Gryphon. + + `Turn a somersault in the sea!' cried the Mock Turtle, +capering wildly about. + + `Change lobsters again!' yelled the Gryphon at the top of its voice. + + `Back to land again, and that's all the first figure,' said the +Mock Turtle, suddenly dropping his voice; and the two creatures, +who had been jumping about like mad things all this time, sat +down again very sadly and quietly, and looked at Alice. + + `It must be a very pretty dance,' said Alice timidly. + + `Would you like to see a little of it?' said the Mock Turtle. + + `Very much indeed,' said Alice. + + `Come, let's try the first figure!' said the Mock Turtle to the +Gryphon. `We can do without lobsters, you know. Which shall +sing?' + + `Oh, YOU sing,' said the Gryphon. `I've forgotten the words.' + + So they began solemnly dancing round and round Alice, every now +and then treading on her toes when they passed too close, and +waving their forepaws to mark the time, while the Mock Turtle +sang this, very slowly and sadly:-- + + +`"Will you walk a little faster?" said a whiting to a snail. +"There's a porpoise close behind us, and he's treading on my + tail. +See how eagerly the lobsters and the turtles all advance! +They are waiting on the shingle--will you come and join the +dance? + +Will you, won't you, will you, won't you, will you join the +dance? +Will you, won't you, will you, won't you, won't you join the +dance? + + +"You can really have no notion how delightful it will be +When they take us up and throw us, with the lobsters, out to + sea!" +But the snail replied "Too far, too far!" and gave a look + askance-- +Said he thanked the whiting kindly, but he would not join the + dance. + Would not, could not, would not, could not, would not join + the dance. + Would not, could not, would not, could not, could not join + the dance. + +`"What matters it how far we go?" his scaly friend replied. +"There is another shore, you know, upon the other side. +The further off from England the nearer is to France-- +Then turn not pale, beloved snail, but come and join the dance. + + Will you, won't you, will you, won't you, will you join the + dance? + Will you, won't you, will you, won't you, won't you join the + dance?"' + + + + `Thank you, it's a very interesting dance to watch,' said +Alice, feeling very glad that it was over at last: `and I do so +like that curious song about the whiting!' + + `Oh, as to the whiting,' said the Mock Turtle, `they--you've +seen them, of course?' + + `Yes,' said Alice, `I've often seen them at dinn--' she +checked herself hastily. + + `I don't know where Dinn may be,' said the Mock Turtle, `but +if you've seen them so often, of course you know what they're +like.' + + `I believe so,' Alice replied thoughtfully. `They have their +tails in their mouths--and they're all over crumbs.' + + `You're wrong about the crumbs,' said the Mock Turtle: +`crumbs would all wash off in the sea. But they HAVE their tails +in their mouths; and the reason is--' here the Mock Turtle +yawned and shut his eyes.--`Tell her about the reason and all +that,' he said to the Gryphon. + + `The reason is,' said the Gryphon, `that they WOULD go with +the lobsters to the dance. So they got thrown out to sea. So +they had to fall a long way. So they got their tails fast in +their mouths. So they couldn't get them out again. That's all.' + + `Thank you,' said Alice, `it's very interesting. I never knew +so much about a whiting before.' + + `I can tell you more than that, if you like,' said the +Gryphon. `Do you know why it's called a whiting?' + + `I never thought about it,' said Alice. `Why?' + + `IT DOES THE BOOTS AND SHOES.' the Gryphon replied very +solemnly. + + Alice was thoroughly puzzled. `Does the boots and shoes!' she +repeated in a wondering tone. + + `Why, what are YOUR shoes done with?' said the Gryphon. `I +mean, what makes them so shiny?' + + Alice looked down at them, and considered a little before she +gave her answer. `They're done with blacking, I believe.' + + `Boots and shoes under the sea,' the Gryphon went on in a deep +voice, `are done with a whiting. Now you know.' + + `And what are they made of?' Alice asked in a tone of great +curiosity. + + `Soles and eels, of course,' the Gryphon replied rather +impatiently: `any shrimp could have told you that.' + + `If I'd been the whiting,' said Alice, whose thoughts were +still running on the song, `I'd have said to the porpoise, "Keep +back, please: we don't want YOU with us!"' + + `They were obliged to have him with them,' the Mock Turtle +said: `no wise fish would go anywhere without a porpoise.' + + `Wouldn't it really?' said Alice in a tone of great surprise. + + `Of course not,' said the Mock Turtle: `why, if a fish came +to ME, and told me he was going a journey, I should say "With +what porpoise?"' + + `Don't you mean "purpose"?' said Alice. + + `I mean what I say,' the Mock Turtle replied in an offended +tone. And the Gryphon added `Come, let's hear some of YOUR +adventures.' + + `I could tell you my adventures--beginning from this morning,' +said Alice a little timidly: `but it's no use going back to +yesterday, because I was a different person then.' + + `Explain all that,' said the Mock Turtle. + + `No, no! The adventures first,' said the Gryphon in an +impatient tone: `explanations take such a dreadful time.' + + So Alice began telling them her adventures from the time when +she first saw the White Rabbit. She was a little nervous about +it just at first, the two creatures got so close to her, one on +each side, and opened their eyes and mouths so VERY wide, but she +gained courage as she went on. Her listeners were perfectly +quiet till she got to the part about her repeating `YOU ARE OLD, +FATHER WILLIAM,' to the Caterpillar, and the words all coming +different, and then the Mock Turtle drew a long breath, and said +`That's very curious.' + + `It's all about as curious as it can be,' said the Gryphon. + + `It all came different!' the Mock Turtle repeated +thoughtfully. `I should like to hear her try and repeat +something now. Tell her to begin.' He looked at the Gryphon as +if he thought it had some kind of authority over Alice. + + `Stand up and repeat "'TIS THE VOICE OF THE SLUGGARD,"' said +the Gryphon. + + `How the creatures order one about, and make one repeat +lessons!' thought Alice; `I might as well be at school at once.' +However, she got up, and began to repeat it, but her head was so +full of the Lobster Quadrille, that she hardly knew what she was +saying, and the words came very queer indeed:-- + + `'Tis the voice of the Lobster; I heard him declare, + "You have baked me too brown, I must sugar my hair." + As a duck with its eyelids, so he with his nose + Trims his belt and his buttons, and turns out his toes.' + + [later editions continued as follows + When the sands are all dry, he is gay as a lark, + And will talk in contemptuous tones of the Shark, + But, when the tide rises and sharks are around, + His voice has a timid and tremulous sound.] + + `That's different from what I used to say when I was a child,' +said the Gryphon. + + `Well, I never heard it before,' said the Mock Turtle; `but it +sounds uncommon nonsense.' + + Alice said nothing; she had sat down with her face in her +hands, wondering if anything would EVER happen in a natural way +again. + + `I should like to have it explained,' said the Mock Turtle. + + `She can't explain it,' said the Gryphon hastily. `Go on with +the next verse.' + + `But about his toes?' the Mock Turtle persisted. `How COULD +he turn them out with his nose, you know?' + + `It's the first position in dancing.' Alice said; but was +dreadfully puzzled by the whole thing, and longed to change the +subject. + + `Go on with the next verse,' the Gryphon repeated impatiently: +`it begins "I passed by his garden."' + + Alice did not dare to disobey, though she felt sure it would +all come wrong, and she went on in a trembling voice:-- + + `I passed by his garden, and marked, with one eye, + How the Owl and the Panther were sharing a pie--' + + [later editions continued as follows + The Panther took pie-crust, and gravy, and meat, + While the Owl had the dish as its share of the treat. + When the pie was all finished, the Owl, as a boon, + Was kindly permitted to pocket the spoon: + While the Panther received knife and fork with a growl, + And concluded the banquet--] + + `What IS the use of repeating all that stuff,' the Mock Turtle +interrupted, `if you don't explain it as you go on? It's by far +the most confusing thing I ever heard!' + + `Yes, I think you'd better leave off,' said the Gryphon: and +Alice was only too glad to do so. + + `Shall we try another figure of the Lobster Quadrille?' the +Gryphon went on. `Or would you like the Mock Turtle to sing you +a song?' + + `Oh, a song, please, if the Mock Turtle would be so kind,' +Alice replied, so eagerly that the Gryphon said, in a rather +offended tone, `Hm! No accounting for tastes! Sing her +"Turtle Soup," will you, old fellow?' + + The Mock Turtle sighed deeply, and began, in a voice sometimes +choked with sobs, to sing this:-- + + + `Beautiful Soup, so rich and green, + Waiting in a hot tureen! + Who for such dainties would not stoop? + Soup of the evening, beautiful Soup! + Soup of the evening, beautiful Soup! + Beau--ootiful Soo--oop! + Beau--ootiful Soo--oop! + Soo--oop of the e--e--evening, + Beautiful, beautiful Soup! + + `Beautiful Soup! Who cares for fish, + Game, or any other dish? + Who would not give all else for two + Pennyworth only of beautiful Soup? + Pennyworth only of beautiful Soup? + Beau--ootiful Soo--oop! + Beau--ootiful Soo--oop! + Soo--oop of the e--e--evening, + Beautiful, beauti--FUL SOUP!' + + `Chorus again!' cried the Gryphon, and the Mock Turtle had +just begun to repeat it, when a cry of `The trial's beginning!' +was heard in the distance. + + `Come on!' cried the Gryphon, and, taking Alice by the hand, +it hurried off, without waiting for the end of the song. + + `What trial is it?' Alice panted as she ran; but the Gryphon +only answered `Come on!' and ran the faster, while more and more +faintly came, carried on the breeze that followed them, the +melancholy words:-- + + `Soo--oop of the e--e--evening, + Beautiful, beautiful Soup!' + + + + CHAPTER XI + + Who Stole the Tarts? + + + The King and Queen of Hearts were seated on their throne when +they arrived, with a great crowd assembled about them--all sorts +of little birds and beasts, as well as the whole pack of cards: +the Knave was standing before them, in chains, with a soldier on +each side to guard him; and near the King was the White Rabbit, +with a trumpet in one hand, and a scroll of parchment in the +other. In the very middle of the court was a table, with a large +dish of tarts upon it: they looked so good, that it made Alice +quite hungry to look at them--`I wish they'd get the trial done,' +she thought, `and hand round the refreshments!' But there seemed +to be no chance of this, so she began looking at everything about +her, to pass away the time. + + Alice had never been in a court of justice before, but she had +read about them in books, and she was quite pleased to find that +she knew the name of nearly everything there. `That's the +judge,' she said to herself, `because of his great wig.' + + The judge, by the way, was the King; and as he wore his crown +over the wig, (look at the frontispiece if you want to see how he +did it,) he did not look at all comfortable, and it was certainly +not becoming. + + `And that's the jury-box,' thought Alice, `and those twelve +creatures,' (she was obliged to say `creatures,' you see, because +some of them were animals, and some were birds,) `I suppose they +are the jurors.' She said this last word two or three times over +to herself, being rather proud of it: for she thought, and +rightly too, that very few little girls of her age knew the +meaning of it at all. However, `jury-men' would have done just +as well. + + The twelve jurors were all writing very busily on slates. +`What are they doing?' Alice whispered to the Gryphon. `They +can't have anything to put down yet, before the trial's begun.' + + `They're putting down their names,' the Gryphon whispered in +reply, `for fear they should forget them before the end of the +trial.' + + `Stupid things!' Alice began in a loud, indignant voice, but +she stopped hastily, for the White Rabbit cried out, `Silence in +the court!' and the King put on his spectacles and looked +anxiously round, to make out who was talking. + + Alice could see, as well as if she were looking over their +shoulders, that all the jurors were writing down `stupid things!' +on their slates, and she could even make out that one of them +didn't know how to spell `stupid,' and that he had to ask his +neighbour to tell him. `A nice muddle their slates'll be in +before the trial's over!' thought Alice. + + One of the jurors had a pencil that squeaked. This of course, +Alice could not stand, and she went round the court and got +behind him, and very soon found an opportunity of taking it +away. She did it so quickly that the poor little juror (it was +Bill, the Lizard) could not make out at all what had become of +it; so, after hunting all about for it, he was obliged to write +with one finger for the rest of the day; and this was of very +little use, as it left no mark on the slate. + + `Herald, read the accusation!' said the King. + + On this the White Rabbit blew three blasts on the trumpet, and +then unrolled the parchment scroll, and read as follows:-- + + `The Queen of Hearts, she made some tarts, + All on a summer day: + The Knave of Hearts, he stole those tarts, + And took them quite away!' + + `Consider your verdict,' the King said to the jury. + + `Not yet, not yet!' the Rabbit hastily interrupted. `There's +a great deal to come before that!' + + `Call the first witness,' said the King; and the White Rabbit +blew three blasts on the trumpet, and called out, `First +witness!' + + The first witness was the Hatter. He came in with a teacup in +one hand and a piece of bread-and-butter in the other. `I beg +pardon, your Majesty,' he began, `for bringing these in: but I +hadn't quite finished my tea when I was sent for.' + + `You ought to have finished,' said the King. `When did you +begin?' + + The Hatter looked at the March Hare, who had followed him into +the court, arm-in-arm with the Dormouse. `Fourteenth of March, I +think it was,' he said. + + `Fifteenth,' said the March Hare. + + `Sixteenth,' added the Dormouse. + + `Write that down,' the King said to the jury, and the jury +eagerly wrote down all three dates on their slates, and then +added them up, and reduced the answer to shillings and pence. + + `Take off your hat,' the King said to the Hatter. + + `It isn't mine,' said the Hatter. + + `Stolen!' the King exclaimed, turning to the jury, who +instantly made a memorandum of the fact. + + `I keep them to sell,' the Hatter added as an explanation; +`I've none of my own. I'm a hatter.' + + Here the Queen put on her spectacles, and began staring at the +Hatter, who turned pale and fidgeted. + + `Give your evidence,' said the King; `and don't be nervous, or +I'll have you executed on the spot.' + + This did not seem to encourage the witness at all: he kept +shifting from one foot to the other, looking uneasily at the +Queen, and in his confusion he bit a large piece out of his +teacup instead of the bread-and-butter. + + Just at this moment Alice felt a very curious sensation, which +puzzled her a good deal until she made out what it was: she was +beginning to grow larger again, and she thought at first she +would get up and leave the court; but on second thoughts she +decided to remain where she was as long as there was room for +her. + + `I wish you wouldn't squeeze so.' said the Dormouse, who was +sitting next to her. `I can hardly breathe.' + + `I can't help it,' said Alice very meekly: `I'm growing.' + + `You've no right to grow here,' said the Dormouse. + + `Don't talk nonsense,' said Alice more boldly: `you know +you're growing too.' + + `Yes, but I grow at a reasonable pace,' said the Dormouse: +`not in that ridiculous fashion.' And he got up very sulkily +and crossed over to the other side of the court. + + All this time the Queen had never left off staring at the +Hatter, and, just as the Dormouse crossed the court, she said to +one of the officers of the court, `Bring me the list of the +singers in the last concert!' on which the wretched Hatter +trembled so, that he shook both his shoes off. + + `Give your evidence,' the King repeated angrily, `or I'll have +you executed, whether you're nervous or not.' + + `I'm a poor man, your Majesty,' the Hatter began, in a +trembling voice, `--and I hadn't begun my tea--not above a week +or so--and what with the bread-and-butter getting so thin--and +the twinkling of the tea--' + + `The twinkling of the what?' said the King. + + `It began with the tea,' the Hatter replied. + + `Of course twinkling begins with a T!' said the King sharply. +`Do you take me for a dunce? Go on!' + + `I'm a poor man,' the Hatter went on, `and most things +twinkled after that--only the March Hare said--' + + `I didn't!' the March Hare interrupted in a great hurry. + + `You did!' said the Hatter. + + `I deny it!' said the March Hare. + + `He denies it,' said the King: `leave out that part.' + + `Well, at any rate, the Dormouse said--' the Hatter went on, +looking anxiously round to see if he would deny it too: but the +Dormouse denied nothing, being fast asleep. + + `After that,' continued the Hatter, `I cut some more bread- +and-butter--' + + `But what did the Dormouse say?' one of the jury asked. + + `That I can't remember,' said the Hatter. + + `You MUST remember,' remarked the King, `or I'll have you +executed.' + + The miserable Hatter dropped his teacup and bread-and-butter, +and went down on one knee. `I'm a poor man, your Majesty,' he +began. + + `You're a very poor speaker,' said the King. + + Here one of the guinea-pigs cheered, and was immediately +suppressed by the officers of the court. (As that is rather a +hard word, I will just explain to you how it was done. They had +a large canvas bag, which tied up at the mouth with strings: +into this they slipped the guinea-pig, head first, and then sat +upon it.) + + `I'm glad I've seen that done,' thought Alice. `I've so often +read in the newspapers, at the end of trials, "There was some +attempts at applause, which was immediately suppressed by the +officers of the court," and I never understood what it meant +till now.' + + `If that's all you know about it, you may stand down,' +continued the King. + + `I can't go no lower,' said the Hatter: `I'm on the floor, as +it is.' + + `Then you may SIT down,' the King replied. + + Here the other guinea-pig cheered, and was suppressed. + + `Come, that finished the guinea-pigs!' thought Alice. `Now we +shall get on better.' + + `I'd rather finish my tea,' said the Hatter, with an anxious +look at the Queen, who was reading the list of singers. + + `You may go,' said the King, and the Hatter hurriedly left the +court, without even waiting to put his shoes on. + + `--and just take his head off outside,' the Queen added to one +of the officers: but the Hatter was out of sight before the +officer could get to the door. + + `Call the next witness!' said the King. + + The next witness was the Duchess's cook. She carried the +pepper-box in her hand, and Alice guessed who it was, even before +she got into the court, by the way the people near the door began +sneezing all at once. + + `Give your evidence,' said the King. + + `Shan't,' said the cook. + + The King looked anxiously at the White Rabbit, who said in a +low voice, `Your Majesty must cross-examine THIS witness.' + + `Well, if I must, I must,' the King said, with a melancholy +air, and, after folding his arms and frowning at the cook till +his eyes were nearly out of sight, he said in a deep voice, `What +are tarts made of?' + + `Pepper, mostly,' said the cook. + + `Treacle,' said a sleepy voice behind her. + + `Collar that Dormouse,' the Queen shrieked out. `Behead that +Dormouse! Turn that Dormouse out of court! Suppress him! Pinch +him! Off with his whiskers!' + + For some minutes the whole court was in confusion, getting the +Dormouse turned out, and, by the time they had settled down +again, the cook had disappeared. + + `Never mind!' said the King, with an air of great relief. +`Call the next witness.' And he added in an undertone to the +Queen, `Really, my dear, YOU must cross-examine the next witness. +It quite makes my forehead ache!' + + Alice watched the White Rabbit as he fumbled over the list, +feeling very curious to see what the next witness would be like, +`--for they haven't got much evidence YET,' she said to herself. +Imagine her surprise, when the White Rabbit read out, at the top +of his shrill little voice, the name `Alice!' + + + + CHAPTER XII + + Alice's Evidence + + + `Here!' cried Alice, quite forgetting in the flurry of the +moment how large she had grown in the last few minutes, and she +jumped up in such a hurry that she tipped over the jury-box with +the edge of her skirt, upsetting all the jurymen on to the heads +of the crowd below, and there they lay sprawling about, reminding +her very much of a globe of goldfish she had accidentally upset +the week before. + + `Oh, I BEG your pardon!' she exclaimed in a tone of great +dismay, and began picking them up again as quickly as she could, +for the accident of the goldfish kept running in her head, and +she had a vague sort of idea that they must be collected at once +and put back into the jury-box, or they would die. + + `The trial cannot proceed,' said the King in a very grave +voice, `until all the jurymen are back in their proper places-- +ALL,' he repeated with great emphasis, looking hard at Alice as +he said do. + + Alice looked at the jury-box, and saw that, in her haste, she +had put the Lizard in head downwards, and the poor little thing +was waving its tail about in a melancholy way, being quite unable +to move. She soon got it out again, and put it right; `not that +it signifies much,' she said to herself; `I should think it +would be QUITE as much use in the trial one way up as the other.' + + As soon as the jury had a little recovered from the shock of +being upset, and their slates and pencils had been found and +handed back to them, they set to work very diligently to write +out a history of the accident, all except the Lizard, who seemed +too much overcome to do anything but sit with its mouth open, +gazing up into the roof of the court. + + `What do you know about this business?' the King said to +Alice. + + `Nothing,' said Alice. + + `Nothing WHATEVER?' persisted the King. + + `Nothing whatever,' said Alice. + + `That's very important,' the King said, turning to the jury. +They were just beginning to write this down on their slates, when +the White Rabbit interrupted: `UNimportant, your Majesty means, +of course,' he said in a very respectful tone, but frowning and +making faces at him as he spoke. + + `UNimportant, of course, I meant,' the King hastily said, and +went on to himself in an undertone, `important--unimportant-- +unimportant--important--' as if he were trying which word +sounded best. + + Some of the jury wrote it down `important,' and some +`unimportant.' Alice could see this, as she was near enough to +look over their slates; `but it doesn't matter a bit,' she +thought to herself. + + At this moment the King, who had been for some time busily +writing in his note-book, cackled out `Silence!' and read out +from his book, `Rule Forty-two. ALL PERSONS MORE THAN A MILE +HIGH TO LEAVE THE COURT.' + + Everybody looked at Alice. + + `I'M not a mile high,' said Alice. + + `You are,' said the King. + + `Nearly two miles high,' added the Queen. + + `Well, I shan't go, at any rate,' said Alice: `besides, +that's not a regular rule: you invented it just now.' + + `It's the oldest rule in the book,' said the King. + + `Then it ought to be Number One,' said Alice. + + The King turned pale, and shut his note-book hastily. +`Consider your verdict,' he said to the jury, in a low, trembling +voice. + + `There's more evidence to come yet, please your Majesty,' said +the White Rabbit, jumping up in a great hurry; `this paper has +just been picked up.' + + `What's in it?' said the Queen. + + `I haven't opened it yet,' said the White Rabbit, `but it seems +to be a letter, written by the prisoner to--to somebody.' + + `It must have been that,' said the King, `unless it was +written to nobody, which isn't usual, you know.' + + `Who is it directed to?' said one of the jurymen. + + `It isn't directed at all,' said the White Rabbit; `in fact, +there's nothing written on the OUTSIDE.' He unfolded the paper +as he spoke, and added `It isn't a letter, after all: it's a set +of verses.' + + `Are they in the prisoner's handwriting?' asked another of +the jurymen. + + `No, they're not,' said the White Rabbit, `and that's the +queerest thing about it.' (The jury all looked puzzled.) + + `He must have imitated somebody else's hand,' said the King. +(The jury all brightened up again.) + + `Please your Majesty,' said the Knave, `I didn't write it, and +they can't prove I did: there's no name signed at the end.' + + `If you didn't sign it,' said the King, `that only makes the +matter worse. You MUST have meant some mischief, or else you'd +have signed your name like an honest man.' + + There was a general clapping of hands at this: it was the +first really clever thing the King had said that day. + + `That PROVES his guilt,' said the Queen. + + `It proves nothing of the sort!' said Alice. `Why, you don't +even know what they're about!' + + `Read them,' said the King. + + The White Rabbit put on his spectacles. `Where shall I begin, +please your Majesty?' he asked. + + `Begin at the beginning,' the King said gravely, `and go on +till you come to the end: then stop.' + + These were the verses the White Rabbit read:-- + + `They told me you had been to her, + And mentioned me to him: + She gave me a good character, + But said I could not swim. + + He sent them word I had not gone + (We know it to be true): + If she should push the matter on, + What would become of you? + + I gave her one, they gave him two, + You gave us three or more; + They all returned from him to you, + Though they were mine before. + + If I or she should chance to be + Involved in this affair, + He trusts to you to set them free, + Exactly as we were. + + My notion was that you had been + (Before she had this fit) + An obstacle that came between + Him, and ourselves, and it. + + Don't let him know she liked them best, + For this must ever be + A secret, kept from all the rest, + Between yourself and me.' + + `That's the most important piece of evidence we've heard yet,' +said the King, rubbing his hands; `so now let the jury--' + + `If any one of them can explain it,' said Alice, (she had +grown so large in the last few minutes that she wasn't a bit +afraid of interrupting him,) `I'll give him sixpence. _I_ don't +believe there's an atom of meaning in it.' + + The jury all wrote down on their slates, `SHE doesn't believe +there's an atom of meaning in it,' but none of them attempted to +explain the paper. + + `If there's no meaning in it,' said the King, `that saves a +world of trouble, you know, as we needn't try to find any. And +yet I don't know,' he went on, spreading out the verses on his +knee, and looking at them with one eye; `I seem to see some +meaning in them, after all. "--SAID I COULD NOT SWIM--" you +can't swim, can you?' he added, turning to the Knave. + + The Knave shook his head sadly. `Do I look like it?' he said. +(Which he certainly did NOT, being made entirely of cardboard.) + + `All right, so far,' said the King, and he went on muttering +over the verses to himself: `"WE KNOW IT TO BE TRUE--" that's +the jury, of course-- "I GAVE HER ONE, THEY GAVE HIM TWO--" why, +that must be what he did with the tarts, you know--' + + `But, it goes on "THEY ALL RETURNED FROM HIM TO YOU,"' said +Alice. + + `Why, there they are!' said the King triumphantly, pointing to +the tarts on the table. `Nothing can be clearer than THAT. +Then again--"BEFORE SHE HAD THIS FIT--" you never had fits, my +dear, I think?' he said to the Queen. + + `Never!' said the Queen furiously, throwing an inkstand at the +Lizard as she spoke. (The unfortunate little Bill had left off +writing on his slate with one finger, as he found it made no +mark; but he now hastily began again, using the ink, that was +trickling down his face, as long as it lasted.) + + `Then the words don't FIT you,' said the King, looking round +the court with a smile. There was a dead silence. + + `It's a pun!' the King added in an offended tone, and +everybody laughed, `Let the jury consider their verdict,' the +King said, for about the twentieth time that day. + + `No, no!' said the Queen. `Sentence first--verdict afterwards.' + + `Stuff and nonsense!' said Alice loudly. `The idea of having +the sentence first!' + + `Hold your tongue!' said the Queen, turning purple. + + `I won't!' said Alice. + + `Off with her head!' the Queen shouted at the top of her voice. +Nobody moved. + + `Who cares for you?' said Alice, (she had grown to her full +size by this time.) `You're nothing but a pack of cards!' + + At this the whole pack rose up into the air, and came flying +down upon her: she gave a little scream, half of fright and half +of anger, and tried to beat them off, and found herself lying on +the bank, with her head in the lap of her sister, who was gently +brushing away some dead leaves that had fluttered down from the +trees upon her face. + + `Wake up, Alice dear!' said her sister; `Why, what a long +sleep you've had!' + + `Oh, I've had such a curious dream!' said Alice, and she told +her sister, as well as she could remember them, all these strange +Adventures of hers that you have just been reading about; and +when she had finished, her sister kissed her, and said, `It WAS a +curious dream, dear, certainly: but now run in to your tea; it's +getting late.' So Alice got up and ran off, thinking while she +ran, as well she might, what a wonderful dream it had been. + + But her sister sat still just as she left her, leaning her +head on her hand, watching the setting sun, and thinking of +little Alice and all her wonderful Adventures, till she too began +dreaming after a fashion, and this was her dream:-- + + First, she dreamed of little Alice herself, and once again the +tiny hands were clasped upon her knee, and the bright eager eyes +were looking up into hers--she could hear the very tones of her +voice, and see that queer little toss of her head to keep back +the wandering hair that WOULD always get into her eyes--and +still as she listened, or seemed to listen, the whole place +around her became alive the strange creatures of her little +sister's dream. + + The long grass rustled at her feet as the White Rabbit hurried +by--the frightened Mouse splashed his way through the +neighbouring pool--she could hear the rattle of the teacups as +the March Hare and his friends shared their never-ending meal, +and the shrill voice of the Queen ordering off her unfortunate +guests to execution--once more the pig-baby was sneezing on the +Duchess's knee, while plates and dishes crashed around it--once +more the shriek of the Gryphon, the squeaking of the Lizard's +slate-pencil, and the choking of the suppressed guinea-pigs, +filled the air, mixed up with the distant sobs of the miserable +Mock Turtle. + + So she sat on, with closed eyes, and half believed herself in +Wonderland, though she knew she had but to open them again, and +all would change to dull reality--the grass would be only +rustling in the wind, and the pool rippling to the waving of the +reeds--the rattling teacups would change to tinkling sheep- +bells, and the Queen's shrill cries to the voice of the shepherd +boy--and the sneeze of the baby, the shriek of the Gryphon, and +all thy other queer noises, would change (she knew) to the +confused clamour of the busy farm-yard--while the lowing of the +cattle in the distance would take the place of the Mock Turtle's +heavy sobs. + + Lastly, she pictured to herself how this same little sister of +hers would, in the after-time, be herself a grown woman; and how +she would keep, through all her riper years, the simple and +loving heart of her childhood: and how she would gather about +her other little children, and make THEIR eyes bright and eager +with many a strange tale, perhaps even with the dream of +Wonderland of long ago: and how she would feel with all their +simple sorrows, and find a pleasure in all their simple joys, +remembering her own child-life, and the happy summer days. + + THE END + diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/cabi2.cpp b/gcc/testsuite/gdc.test/runnable/extra-files/cabi2.cpp new file mode 100644 index 00000000000..31e5286cbc4 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extra-files/cabi2.cpp @@ -0,0 +1,255 @@ + +#include +#include +#include + +#if __cplusplus +extern "C" { +#endif + +struct Foo1 { char c; }; + +struct Foo1 ctest1() +{ + struct Foo1 f; + + f.c = 3; + return f; +} + +struct Foo2 { short s; }; + +struct Foo2 ctest2() +{ + struct Foo2 f; + + f.s = 0x1234; + return f; +} + +struct Foo3 { char c; short s; }; + +struct Foo3 ctest3() +{ + struct Foo3 f; + + f.s = 0x5678; + return f; +} + + +struct Foo4 { int i; }; + +struct Foo4 ctest4() +{ + struct Foo4 f; + + f.i = 0x12345678; + return f; +} + +struct Foo5 { int i, j; }; + +struct Foo5 ctest5() +{ + struct Foo5 f; + + f.i = 0x12345678; + f.j = 0x21436587; + return f; +} + + +struct Foo6 { int i, j, k; }; + +struct Foo6 ctest6() +{ + struct Foo6 f; + + f.i = 0x12345678; + f.j = 0x21463587; + f.k = 0x24163857; + return f; +} + +struct S7 { float a,b; }; + +struct S7 ctest10() +{ + struct S7 f; + + f.a = 2.5; + f.b = 1.5; + return f; +} + +// ================================= + +char ctest7(char c) +{ + return c + 1; +} + +unsigned char ctest8(unsigned char c) +{ + return c + 1; +} + +signed char ctest9(signed char c) +{ + return c + 1; +} + +/***********************************************/ + +void ctestrir(int x1, int x2, int x3, int x4, int x5, int x6, long double a, int b, long double c) +{ + assert(a == 100.0); + assert(b == 67); + assert(c == 200.0); +} + +/***********************************************/ + +extern void dtestrir(int x1, int x2, int x3, int x4, int x5, int x6, long double a, int b, long double c); + +void test4() +{ + dtestrir(1,2,3,4,5,6, 300.0, 68, 401.0); +} + +/**********************************************/ + +typedef struct S11 { + char a; + char b; + char c; +} S11; + +S11 ctest11(char x, S11 s, char y) { + printf("C sz = %d\n", (int)sizeof(S11)); + assert(sizeof(S11) == 3); + printf("x = %d\n", (int)x); + printf("s.a = %d\n", (int)s.a); + printf("s.b = %d\n", (int)s.b); + printf("s.c = %d\n", (int)s.c); + printf("y = %d\n", (int)y); + return s; +} + +/**********************************************/ + +typedef struct S12 { + char a,d; + char b,e; + char c; +} S12; + +S12 ctest12(char x, S12 s, char y) { + printf("C sz = %d\n", (int)sizeof(S12)); + assert(sizeof(S12) == 5); + printf("x = %d\n", (int)x); + printf("s.a = %d\n", (int)s.a); + printf("s.b = %d\n", (int)s.b); + printf("s.c = %d\n", (int)s.c); + printf("y = %d\n", (int)y); + return s; +} + + +/**********************************************/ + +typedef struct S13 { + short a; + short b; + short c; +} S13; + +S13 ctest13(char x, S13 s, char y) { + printf("C sz = %d\n", (int)sizeof(S13)); + assert(sizeof(S13) == 6); + printf("x = %d\n", (int)x); + printf("s.a = %d\n", (int)s.a); + printf("s.b = %d\n", (int)s.b); + printf("s.c = %d\n", (int)s.c); + printf("y = %d\n", (int)y); + return s; +} + + +/**********************************************/ + +typedef struct S14 { + char a,d,e,f; + char b,g; + char c; +} S14; + +S14 ctest14(char x, S14 s, char y) { + printf("C sz = %d\n", (int)sizeof(S14)); + assert(sizeof(S14) == 7); + printf("x = %d\n", (int)x); + printf("s.a = %d\n", (int)s.a); + printf("s.b = %d\n", (int)s.b); + printf("s.c = %d\n", (int)s.c); + printf("y = %d\n", (int)y); + return s; +} + + +/**********************************************/ + +typedef struct S15 { + char a,d,e,f; + char b,g,h,i; + char c; +} S15; + +S15 ctest15(char x, S15 s, char y) { + printf("C sz = %d\n", (int)sizeof(S15)); + assert(sizeof(S15) == 9); + printf("x = %d\n", (int)x); + printf("s.a = %d\n", (int)s.a); + printf("s.b = %d\n", (int)s.b); + printf("s.c = %d\n", (int)s.c); + printf("y = %d\n", (int)y); + return s; +} + + +/**********************************************/ + +typedef struct S16 { + char a[5]; +#ifdef __GNUC__ + struct __attribute__((packed)) +#else + #pragma pack(push, 1) + struct +#endif + { + char b; + int c; + }; +#ifndef __GNUC__ + #pragma pack(pop) +#endif +} S16; + +S16 ctest16(char x, S16 s, char y) { + printf("C sz = %d\n", (int)sizeof(S16)); + assert(sizeof(S16) == 10); + printf("x = %d\n", (int)x); + printf("s.a = %.*s\n", 5, s.a); + printf("s.b = %d\n", (int)s.b); + printf("s.c = %d\n", s.c); + printf("y = %d\n", (int)y); + return s; +} + + + +#if __cplusplus +} +#endif + diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/cpp_abi_tests.cpp b/gcc/testsuite/gdc.test/runnable/extra-files/cpp_abi_tests.cpp new file mode 100644 index 00000000000..63f74a280c1 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extra-files/cpp_abi_tests.cpp @@ -0,0 +1,60 @@ +struct S{ + float a; +}; + +bool passthrough(bool value) { return value; } +signed char passthrough(signed char value) { return value; } +unsigned char passthrough(unsigned char value) { return value; } +char passthrough(char value) { return value; } +wchar_t passthrough(wchar_t value) { return value; } +short passthrough(short value) { return value; } +unsigned short passthrough(unsigned short value) { return value; } +int passthrough(int value) { return value; } +unsigned int passthrough(unsigned int value) { return value; } +long passthrough(long value) { return value; } +unsigned long passthrough(unsigned long value) { return value; } +long long passthrough(long long value) { return value; } +unsigned long long passthrough(unsigned long long value) { return value; } +float passthrough(float value) { return value; } +double passthrough(double value) { return value; } +S passthrough(S value) { return value; } + +bool passthrough_ptr(bool *value) { return *value; } +signed char passthrough_ptr(signed char *value) { return *value; } +unsigned char passthrough_ptr(unsigned char *value) { return *value; } +char passthrough_ptr(char *value) { return *value; } +wchar_t passthrough_ptr(wchar_t *value) { return *value; } +short passthrough_ptr(short *value) { return *value; } +unsigned short passthrough_ptr(unsigned short *value) { return *value; } +int passthrough_ptr(int *value) { return *value; } +unsigned int passthrough_ptr(unsigned int *value) { return *value; } +long passthrough_ptr(long *value) { return *value; } +unsigned long passthrough_ptr(unsigned long *value) { return *value; } +long long passthrough_ptr(long long *value) { return *value; } +unsigned long long passthrough_ptr(unsigned long long *value) { return *value; } +float passthrough_ptr(float *value) { return *value; } +double passthrough_ptr(double *value) { return *value; } +S passthrough_ptr(S *value) { return *value; } + +bool passthrough_ref(bool &value) { return value; } +signed char passthrough_ref(signed char &value) { return value; } +unsigned char passthrough_ref(unsigned char &value) { return value; } +char passthrough_ref(char &value) { return value; } +wchar_t passthrough_ref(wchar_t &value) { return value; } +short passthrough_ref(short &value) { return value; } +unsigned short passthrough_ref(unsigned short &value) { return value; } +int passthrough_ref(int &value) { return value; } +unsigned int passthrough_ref(unsigned int &value) { return value; } +long passthrough_ref(long &value) { return value; } +unsigned long passthrough_ref(unsigned long &value) { return value; } +long long passthrough_ref(long long &value) { return value; } +unsigned long long passthrough_ref(unsigned long long &value) { return value; } +float passthrough_ref(float &value) { return value; } +double passthrough_ref(double &value) { return value; } +S passthrough_ref(S &value) { return value; } + +// Uncomment when mangling is fixed +// typedef void(*fn0)(); +// fn0 passthrough_fn0 (fn0 value) { return value; } +// typedef int (*fn1)(int); +// fn1 passthrough_fn1 (fn1 value) { return value; } diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/cppb.cpp b/gcc/testsuite/gdc.test/runnable/extra-files/cppb.cpp new file mode 100644 index 00000000000..7574c5fba72 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extra-files/cppb.cpp @@ -0,0 +1,812 @@ +/* +GCC 5.1 introduced new implementations of std::string and std::list: + +https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html + +This causes e.g. std::string to be actually defined as +std::__cxx11::string. + +On machines with GCC 5.1, this manifests as a linker error when +running the cppa.d / cppb.cpp test: + +cppa.o: In function `_D4cppa6test14FZv': +cppa.d:(.text._D4cppa6test14FZv+0x11): undefined reference to `foo14a(std::string*)' +cppa.d:(.text._D4cppa6test14FZv+0x18): undefined reference to `foo14b(std::basic_string, std::allocator >*)' +cppa.d:(.text._D4cppa6test14FZv+0x3a): undefined reference to `foo14f(std::char_traits*, std::string*, std::string*)' +cppa.o: In function `_D4cppa7testeh3FZv': +cppa.d:(.text._D4cppa7testeh3FZv+0x19): undefined reference to `throwle()' +collect2: error: ld returned 1 exit status +--- errorlevel 1 + +When the .cpp file is compiled with g++ 5.3.0, the actual function +signatures in the cppb.o object file are: + +foo14a(std::__cxx11::basic_string, std::allocator >*) +foo14b(std::__cxx11::basic_string, std::allocator >*) +foo14f(std::char_traits*, std::__cxx11::basic_string, std::allocator >*, std::__cxx11::basic_string, std::allocator >*) + +Fortunately, it is easily possible to disable the new feature +by defining _GLIBCXX_USE_CXX11_ABI as 0 before including any standard +headers. +*/ +#define _GLIBCXX_USE_CXX11_ABI 0 + +#include +#include +#include +#include + +/**************************************/ + +int foo(int i, int j, int k); + +int foob(int i, int j, int k) +{ + printf("i = %d\n", i); + printf("j = %d\n", j); + printf("k = %d\n", k); + assert(i == 1); + assert(j == 2); + assert(k == 3); + + foo(i, j, k); + + return 7; +} + +/**************************************/ + +class D *dthis; + +class D +{ + public: + virtual int bar(int i, int j, int k) + { + printf("this = %p\n", this); + assert(this == dthis); + printf("D.bar: i = %d\n", i); + printf("D.bar: j = %d\n", j); + printf("D.bar: k = %d\n", k); + assert(i == 9); + assert(j == 10); + assert(k == 11); + return 8; + } +}; + + +D* getD() +{ + D *d = new D(); + dthis = d; + return d; +} + +/**************************************/ + +class E +{ + public: + virtual int bar(int i, int j, int k); +}; + + +int callE(E *e) +{ + return e->bar(11,12,13); +} + +/**************************************/ + +void foo4(char *p) +{ +} + +/**************************************/ + +struct foo5 { int i; int j; void *p; }; + +class bar5 +{ +public: + virtual foo5 getFoo(int i){ + printf("This = %p\n", this); + foo5 f; + f.i = 1; + f.j = 2 + i; + f.p = (void*)this; + return f; + } +}; + +bar5* newBar() +{ + bar5* b = new bar5(); + printf("bar = %p\n", b); + return b; +} + + +/**************************************/ + +struct A11802; +struct B11802; + +class C11802 +{ +public: + virtual void fun(A11802 *); + virtual void fun(B11802 *); +}; + +class D11802 : public C11802 +{ +public: + void fun(A11802 *); + void fun(B11802 *); +}; + +void test11802x(D11802 *c) +{ + c->fun((A11802 *)0); + c->fun((B11802 *)0); +} + +/**************************************/ + +typedef struct +{ + int i; + double d; +} S6; + +union S6_2 +{ + int i; + double d; +}; + +enum S6_3 +{ + A, B +}; + + +S6 foo6(void) +{ + S6 s; + s.i = 42; + s.d = 2.5; + return s; +} + +S6_2 foo6_2(void) +{ + S6_2 s; + s.i = 42; + return s; +} + +S6_3 foo6_3(void) +{ + S6_3 s = A; + return s; +} + +extern "C" { int foosize6() +{ + return sizeof(S6); +} +} + +/**************************************/ + +typedef struct +{ + int i; + long long d; +} S7; + +extern "C" { int foo7() +{ + return sizeof(S7); +} +} + +/**************************************/ + +struct S13955a +{ + float a; + double b; +}; + +struct S13955b +{ + double a; + float b; +}; + +struct S13955c +{ + float a; + float b; +}; + +struct S13955d +{ + double a; + double b; +}; + +void check13955(S13955a a, S13955b b, S13955c c, S13955d d); + +void func13955(S13955a a, S13955b b, S13955c c, S13955d d) +{ + check13955(a, b, c, d); +} + +/**************************************/ + +struct Struct10071 +{ + void *p; + long double r; +}; + +size_t offset10071() +{ + Struct10071 s; + return (char *)&s.r - (char *)&s; +} + +/**************************************/ + +void foo8(const char *p) +{ +} + +/**************************************/ +// 4059 + +struct elem9 { }; +void foobar9(elem9*, elem9*) { } + +/**************************************/ +// 5148 + +void foo10(const char*, const char*) { } +void foo10(const int, const int) { } +void foo10(const char, const char) { } +void foo10(bool, bool) { } + +struct MyStructType { }; +void foo10(const MyStructType s, const MyStructType t) { } + +enum MyEnumType { onemember }; +void foo10(const MyEnumType s, const MyEnumType t) { } + +/**************************************/ + +namespace N11 { namespace M { void bar11() { } } } + +namespace A11 { namespace B { namespace C { void bar() { } } } } + +/**************************************/ + +void myvprintfx(const char* format, va_list); + +void myvprintf(const char* format, va_list va) +{ + myvprintfx(format, va); +} + +/**************************************/ + +class C13161 +{ +public: + virtual void dummyfunc() {} + long long val_5; + unsigned val_9; +}; + +class Test : public C13161 +{ +public: + unsigned val_0; + long long val_1; +}; + +size_t getoffset13161() +{ + Test s; + return (char *)&s.val_0 - (char *)&s; +} + +class C13161a +{ +public: + virtual void dummyfunc() {} + long double val_5; + unsigned val_9; +}; + +class Testa : public C13161a +{ +public: + bool val_0; +}; + +size_t getoffset13161a() +{ + Testa s; + return (char *)&s.val_0 - (char *)&s; +} + +/****************************************************/ + +#if __linux__ || __APPLE__ || __FreeBSD__ +#include +#include +#include + +#if __linux__ +template struct std::allocator; +template struct std::vector; + +void foo15() +{ + std::allocator* p; + p->deallocate(0, 0); +} + +#endif + +// _Z5foo14PSt6vectorIiSaIiEE +void foo14(std::vector > *p) { } + +void foo14a(std::basic_string *p) { } +void foo14b(std::basic_string *p) { } +void foo14c(std::basic_istream *p) { } +void foo14d(std::basic_ostream *p) { } +void foo14e(std::basic_iostream *p) { } + +void foo14f(std::char_traits* x, std::basic_string *p, std::basic_string *q) { } + +#endif + +/**************************************/ + +struct S13956 +{ +}; + +void check13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); + +void func13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) +{ + check13956(arg0, arg1, arg2, arg3, arg4, arg5, arg6); +} + +/**************************************/ + +wchar_t f13289_cpp_wchar_t(wchar_t ch) +{ + if (ch <= L'z' && ch >= L'a') + { + return ch - (L'a' - L'A'); + } + else + { + return ch; + } +} + +#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__ +unsigned short f13289_d_wchar(unsigned short ch); +wchar_t f13289_d_dchar(wchar_t ch); +#elif _WIN32 +wchar_t f13289_d_wchar(wchar_t ch); +unsigned int f13289_d_dchar(unsigned int ch); +#endif + +bool f13289_cpp_test() +{ +#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__ + if (!(f13289_d_wchar((unsigned short)'c') == (unsigned short)'C')) return false; + if (!(f13289_d_wchar((unsigned short)'D') == (unsigned short)'D')) return false; + if (!(f13289_d_dchar(L'e') == L'E')) return false; + if (!(f13289_d_dchar(L'F') == L'F')) return false; + return true; +#elif _WIN32 + if (!(f13289_d_wchar(L'c') == L'C')) return false; + if (!(f13289_d_wchar(L'D') == L'D')) return false; + if (!(f13289_d_dchar((unsigned int)'e') == (unsigned int)'E')) return false; + if (!(f13289_d_dchar((unsigned int)'F') == (unsigned int)'F')) return false; + return true; +#else + return false; +#endif +} + +/******************************************/ + +long double testld(long double ld) +{ + assert(ld == 5); + return ld + 1; +} + +long testl(long lng) +{ + assert(lng == 5); + return lng + sizeof(long); +} + +unsigned long testul(unsigned long ul) +{ + assert(ul == 5); + return ul + sizeof(unsigned long); +} + +/******************************************/ + +struct S13707 +{ + void* a; + void* b; + S13707(void *a, void* b) + { + this->a = a; + this->b = b; + } +}; + +S13707 func13707() +{ + S13707 pt(NULL, NULL); + return pt; +} + +/******************************************/ + +template struct S13932 +{ + int member; +}; + +void func13932(S13932<-1> s) {} + +/******************************************/ + +namespace N13337 { + namespace M13337 { + struct S13337 { }; + void foo13337(S13337 s) { } + } +} + +/****************************************/ +// 14195 + +template +struct Delegate1 {}; + +template +struct Delegate1 < R1() > {}; + +template +struct Delegate2 {}; + +template < typename R1, typename T1, typename T2, typename R2, typename T3, typename T4 > +struct Delegate2 {}; + +void test14195a(Delegate1 func) {} + +void test14195b(Delegate2 func) {} + +/******************************************/ +// 14200 + +void test14200a(int a) {}; +void test14200b(float a, int b, double c) {}; + +/******************************************/ +// 14956 + +namespace std { + namespace N14956 { + struct S14956 { }; + } +} + +void test14956(std::N14956::S14956 s) { } + +/******************************************/ +// check order of overloads in vtable + +class Statement; +class ErrorStatement; +class PeelStatement; +class ExpStatement; +class DtorExpStatement; + +class Visitor +{ +public: + virtual int visit(Statement*) { return 1; } + virtual int visit(ErrorStatement*) { return 2; } + virtual int visit(PeelStatement*) { return 3; } +}; + +class Visitor2 : public Visitor +{ +public: + virtual int visit2(ExpStatement*) { return 4; } + virtual int visit2(DtorExpStatement*) { return 5; } +}; + +bool testVtableCpp(Visitor2* sv) +{ + if (sv->visit((Statement*)0) != 1) return false; + if (sv->visit((ErrorStatement*)0) != 2) return false; + if (sv->visit((PeelStatement*)0) != 3) return false; + if (sv->visit2((ExpStatement*)0) != 4) return false; + if (sv->visit2((DtorExpStatement*)0) != 5) return false; + return true; +} + +Visitor2 inst; + +Visitor2* getVisitor2() +{ + return &inst; +} + +/******************************************/ +// issues detected by fuzzer +#if _LP64 +#define longlong long +#else +#define longlong long long +#endif + +void fuzz1_checkValues(longlong arg10, longlong arg11, bool arg12); +void fuzz1_cppvararg(longlong arg10, longlong arg11, bool arg12) +{ + fuzz1_checkValues(arg10, arg11, arg12); +} + +void fuzz2_checkValues(unsigned longlong arg10, unsigned longlong arg11, bool arg12); +void fuzz2_cppvararg(unsigned longlong arg10, unsigned longlong arg11, bool arg12) +{ + fuzz2_checkValues(arg10, arg11, arg12); +} + +#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__ +#define wchar unsigned short +#elif _WIN32 +#define wchar wchar_t +#endif + +void fuzz3_checkValues(wchar arg10, wchar arg11, bool arg12); +void fuzz3_cppvararg(wchar arg10, wchar arg11, bool arg12) +{ + fuzz3_checkValues(arg10, arg11, arg12); +} + +/******************************************/ + +void throwit() +{ +#if _WIN32 +#else + std::exception se; + throw se; +#endif +} + +/******************************************/ + +#if linux +#include + +void throwle() +{ + std::logic_error le("test"); + throw le; +} + +#endif + +/******************************************/ +// 15579 + +/******************************************/ +// 15579 + +class Base +{ +public: + //virtual ~Base() {} + virtual void base(); + unsigned char x; +}; + +class Interface +{ +public: + virtual int MethodCPP() = 0; + virtual int MethodD() = 0; +}; + +class Derived : public Base, public Interface +{ +public: + Derived(); + short y; + int MethodCPP(); +#if _WIN32 || _WIN64 + int MethodD(); + virtual int Method(); +#else + int MethodD() { return 3; } // need def or vtbl[] is not generated + virtual int Method() { return 6; } // need def or vtbl[] is not generated +#endif +}; + +void Base::base() { } +int Derived::MethodCPP() { + printf("Derived::MethodCPP() this = %p, x = %d, y = %d\n", this, x, y); + assert(x == 4 || x == 7); + assert(y == 5 || y == 8); + return 30; +} +Derived::Derived() { } + + +Derived *cppfoo(Derived *d) +{ + printf("cppfoo(): d = %p\n", d); + assert(d->x == 4); + assert(d->y == 5); + assert(d->MethodD() == 3); + assert(d->MethodCPP() == 30); + assert(d->Method() == 6); + + d = new Derived(); + d->x = 7; + d->y = 8; + assert(d->MethodD() == 3); + assert(d->MethodCPP() == 30); + assert(d->Method() == 6); + printf("d1 = %p\n", d); + return d; +} + +Interface *cppfooi(Interface *i) +{ + printf("cppfooi(): i = %p\n", i); + assert(i->MethodD() == 3); + assert(i->MethodCPP() == 30); + + Derived *d = new Derived(); + d->x = 7; + d->y = 8; + printf("d = %p, i = %p\n", d, (Interface *)d); + return d; +} + +/******************************************/ +// 15610 + +class Base2 +{ + public: + int i; + virtual void baser() { } +}; + +class Interface2 +{ + public: + virtual void f() = 0; +}; + +class Derived2 : public Base2, public Interface2 +{ + public: + void f(); +}; + +void Derived2::f() +{ + printf("Derived2::f() this = %p i = %d\n", this, i); + assert(i == 3); +} + +/******************************************/ +// 15455 + +struct X6 +{ + unsigned short a; + unsigned short b; + unsigned char c; + unsigned char d; +}; + +struct X8 +{ + unsigned short a; + X6 b; +}; + +void test15455b(X8 s) +{ + assert(sizeof(X6) == 6); + assert(sizeof(X8) == 8); + assert(s.a == 1); + assert(s.b.a == 2); + assert(s.b.b == 3); + assert(s.b.c == 4); + assert(s.b.d == 5); +} + +/******************************************/ +// 15372 + +template +int foo15372(int value) +{ + return value; +} + +void test15372b() +{ + int t = foo15372(1); +} + +/****************************************/ +// 15576 + +namespace ns15576 +{ + int global15576; + + namespace ns + { + int n_global15576; + } +} + +/****************************************/ +// 15802 + +template +class Foo15802 +{ +public: + static int boo(int value) + { + return value; + } +}; + +void test15802b() +{ + int t = Foo15802::boo(1); +} + + +/****************************************/ +// 16536 - mangling mismatch on OSX + +#if defined(__APPLE__) +__UINTMAX_TYPE__ pass16536(__UINTMAX_TYPE__ a) +{ + return a; +} +#endif diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/externmangle.cpp b/gcc/testsuite/gdc.test/runnable/extra-files/externmangle.cpp new file mode 100644 index 00000000000..da3e8449b2e --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extra-files/externmangle.cpp @@ -0,0 +1,404 @@ +#include + +template +struct Foo +{ + X *v; +}; + +template +struct Boo +{ + X *v; +}; + +void test1(Foo arg1) +{ +} + + +void test2(int* arg2, Boo arg1) +{ +} + +template +struct Test3 +{ + +}; + +void test3(Test3<3,3> arg1) +{ +} + +void test4(Foo arg1, Boo arg2, Boo arg3, int*, Foo) +{ +} + +void test5(Foo arg1, Boo arg2, Boo arg3) +{ +} + +struct Goo +{ + + template + struct Foo + { + X* v; + }; + + template + struct Boo + { + template + struct Xoo + { + Y* v; + }; + X* v; + }; + + + void test6(Foo > > arg1); + void test7(Boo::Xoo arg1); +}; + +void Goo::test6(Goo::Foo > > arg1) +{ +} + +void Goo::test7(Goo::Boo::Xoo arg1) +{ +} + +struct P1 +{ + template + struct Mem + { + }; +}; + +struct P2 +{ + template + struct Mem + { + }; +}; + +void test8(P1::Mem, P2::Mem){} +void test9(Foo, Foo, int**, int*){} + + + +class Test10 +{ + private: void test10(); + public: void test11(); + protected: void test12(); + public: void test13() const; + + private: void test14(); // Private methods in D are always non-virtual + public: virtual void test15(); + protected: virtual void test16(); + + private: static void test17(); + public: static void test18(); + protected: static void test19(); +}; + +Test10* Test10Ctor() +{ + return new Test10(); +} + +void Test10Dtor(Test10*& ptr) +{ + delete ptr; + ptr = 0; +} + +void Test10::test10(){} +void Test10::test11(){} +void Test10::test12(){} +void Test10::test13() const{} +void Test10::test14(){} +void Test10::test15(){} +void Test10::test16(){} +void Test10::test17(){} +void Test10::test18(){} +void Test10::test19(){} + +struct Test20 +{ + private: static int test20; + protected: static int test21; + public: static int test22; +}; + +int Test20::test20 = 20; +int Test20::test21 = 21; +int Test20::test22 = 22; + +int test23(Test10**, Test10*, Test10***, Test10 const *const) +{ + return 1; +} + +int test23b(Test10 const *const *const, Test10 const* const, Test10*) +{ + return 1; +} + +void test24(int(*)(int,int)) +{ +} + +void test25(int arr[2][5][6][291]) +{ +} + +int test26(int arr[5][6][291]) +{ + return arr[1][1][1]; +} + +void test27(int, ...){} +void test28(int){} + +void test29(float){} +void test30(const float){} + +template +struct Array +{ + int dim; +}; + +class Module +{ +public: + static void imports(Module*); + static int dim(Array*); +}; + + +void Module::imports(Module*) +{ +} + +int Module::dim(Array* arr) +{ + return arr->dim; +} + +#if _LP64 +unsigned long testlongmangle(int32_t a, uint32_t b, long c, unsigned long d) +{ + return a + b + c + d; +} +#else +unsigned long long testlongmangle(int a, unsigned int b, long long c, unsigned long long d) +{ + return a + b + c + d; +} +#endif + +int test31[2][2][2] = {1, 1, 1, 1, 1, 1, 1, 1}; +int *test32 = 0; + + + +class Expression; + +typedef int (*apply_fp_t)(Expression*, void*); + +class Expression +{ + int type; +public: + int apply(apply_fp_t fp, apply_fp_t fp2, void *param); + int getType(); + static Expression* create(int v); + static void dispose(Expression*&); +}; + +int Expression::apply(apply_fp_t fp, apply_fp_t fp2, void *param) +{ + return fp(this, param) * fp2(this, param); +} + +int Expression::getType() +{ + return type; +} + +Expression* Expression::create(int v) +{ + Expression *e = new Expression(); + e->type = v; + return e; +} + +void Expression::dispose(Expression *&e) +{ + if (e) + delete e; + e = 0; +} + +/*int test34(int v[0][0][0]) +{ + return 0; +}*/ + +#ifndef _MSC_VER + int test35(long double arg) + { + return (int)arg; + } +#endif + +const char *test36(const char *arg) +{ + return arg; +} + +class Test37 +{ +public: + static Test37 *create(); + bool test(); +}; + +bool test37() +{ + Test37 *o = Test37::create(); + return o->test(); +} + +class Test38 +{ +public: + int test(int, ...); + static Test38* create(); + static void dispose(Test38*&); +}; + +int Test38::test(int a, ...) +{ + return a; +} + +Test38* Test38::create() +{ + Test38 *t = new Test38(); + return t; +} + +void Test38::dispose(Test38 *&t) +{ + if (t) + delete t; + t = 0; +} + +class S1 +{ + int val; +public: + static S1* init(int); + S1(int v) : val(v) {} + int value(); +}; + +S1* S1::init(int x) +{ + return new S1(x); +} + +int S1::value() +{ + return val; +} + +template +class S2 +{ + T val; +public: + static S2* init(T); + S2(T v) : val(v) {} + T value(); +}; + +template<> +S2* S2::init(int x) +{ + return new S2(x); +} + +template<> +int S2::value() +{ + return val; +} + +struct C1 +{ + const char *data; + + static C1* init(const char *p); + + C1(const char* p) : data(p) { } + + virtual const char* getDataCPP(); + virtual const char* getDataD(); +}; + +C1* C1::init(const char *p) +{ + return new C1(p); +} + +const char* C1::getDataCPP() +{ + return data; +} + +template +struct C2 +{ + const T *data; + + static C2* init(const T *p); + + C2(const T* p) : data(p) { } + + virtual const T* getData(); +}; + +template<> +C2* C2::init(const char *p) +{ + return new C2(p); +} + +template<> +const char* C2::getData() +{ + return data; +} + +int test39cpp(C2* c2, S2* s2) +{ + C2* otherC2 = C2::init(c2->getData()); + if (c2->getData() != otherC2->getData()) + return 1; + S2* otherS2 = S2::init(s2->value()); + if (s2->value() != otherS2->value()) + return 2; + return 0; +} \ No newline at end of file diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/externmangle2.cpp b/gcc/testsuite/gdc.test/runnable/extra-files/externmangle2.cpp new file mode 100644 index 00000000000..b481348976a --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extra-files/externmangle2.cpp @@ -0,0 +1,145 @@ + +struct Test32NS1 +{ + template + struct Foo + { + X *v; + }; + + template + struct Bar + { + X *v; + }; + +}; + +struct Test32NS2 +{ + template + struct Foo + { + X *v; + }; +}; + +template