./.codecov.yml .azure-pipelines/lib.sh .azure-pipelines/windows-msbuild.bat .azure-pipelines/windows-visual-studio.sh .azure-pipelines/windows.sh .circleci/run.sh .editorconfig CODEOWNERS Jenkinsfile VERSION changelog/add_traits_child.dd changelog/array-literal-inference.dd changelog/debug-nothrow.dd changelog/hasAlwaysInlines.dd changelog/implicit-override-deprecation-end-17349.dd changelog/implicit-vector-conversions.dd changelog/in-identity.dd changelog/vector-operation-support.dd ci.sh config.d docs/Makefile docs/gen_man.d docs/man/man1/dumpobj.1 docs/man/man1/obj2asm.1 docs/man/man5/dmd.conf.5 dub.sdl ini/dragonflybsd/bin32/dmd.conf ini/dragonflybsd/bin64/dmd.conf ini/freebsd/bin32/dmd.conf ini/freebsd/bin64/dmd.conf ini/linux/bin32/dmd.conf ini/linux/bin64/dmd.conf ini/osx/bin/dmd.conf ini/osx/bin/dmdx.conf ini/solaris/bin32/dmd.conf ini/solaris/bin64/dmd.conf ini/windows/bin/sc.ini posix.mak samples/all.sh samples/build.bat samples/chello.d samples/clean.bat samples/d2html.d samples/d2html.kwd samples/dclient.d samples/dhry.d samples/dserver.d samples/dserver.def samples/dserver64.def samples/hello.d samples/htmlget.d samples/listener.d samples/mydll/build.bat samples/mydll/dll.d samples/mydll/mydll.d samples/mydll/mydll.def samples/mydll/mydll.di samples/mydll/test.d samples/pi.d samples/posix.mak samples/sieve.d samples/wc.d samples/wc2.d samples/win32.mak samples/winsamp.d samples/winsamp.def semaphoreci.sh src/.dscanner.ini src/build.d src/dmd/access.d src/dmd/aggregate.d src/dmd/aggregate.h src/dmd/aliasthis.d src/dmd/aliasthis.h src/dmd/apply.d src/dmd/argtypes.d src/dmd/argtypes_aarch64.d src/dmd/argtypes_sysv_x64.d src/dmd/arrayop.d src/dmd/arraytypes.d src/dmd/arraytypes.h src/dmd/ast_node.d src/dmd/ast_node.h src/dmd/astbase.d src/dmd/astcodegen.d src/dmd/asttypename.d src/dmd/attrib.d src/dmd/attrib.h src/dmd/backend/aarray.d src/dmd/backend/backconfig.d src/dmd/backend/backend.d src/dmd/backend/barray.d src/dmd/backend/bcomplex.d src/dmd/backend/blockopt.d src/dmd/backend/cc.d src/dmd/backend/cdef.d src/dmd/backend/cg.d src/dmd/backend/cg87.d src/dmd/backend/cgcod.d src/dmd/backend/cgcs.d src/dmd/backend/cgcse.d src/dmd/backend/cgcv.d src/dmd/backend/cgelem.d src/dmd/backend/cgen.d src/dmd/backend/cgobj.d src/dmd/backend/cgreg.d src/dmd/backend/cgsched.d src/dmd/backend/cgxmm.d src/dmd/backend/cod1.d src/dmd/backend/cod2.d src/dmd/backend/cod3.d src/dmd/backend/cod4.d src/dmd/backend/cod5.d src/dmd/backend/code.d src/dmd/backend/code_x86.d src/dmd/backend/codebuilder.d src/dmd/backend/compress.d src/dmd/backend/cv4.d src/dmd/backend/cv8.d src/dmd/backend/dcgcv.d src/dmd/backend/dcode.d src/dmd/backend/debugprint.d src/dmd/backend/divcoeff.d src/dmd/backend/dlist.d src/dmd/backend/drtlsym.d src/dmd/backend/dt.d src/dmd/backend/dtype.d src/dmd/backend/dvarstats.d src/dmd/backend/dvec.d src/dmd/backend/dwarf.d src/dmd/backend/dwarf2.d src/dmd/backend/dwarfdbginf.d src/dmd/backend/dwarfeh.d src/dmd/backend/ee.d src/dmd/backend/el.d src/dmd/backend/elem.d src/dmd/backend/elfobj.d src/dmd/backend/elpicpie.d src/dmd/backend/errors.di src/dmd/backend/evalu8.d src/dmd/backend/exh.d src/dmd/backend/filespec.d src/dmd/backend/fp.d src/dmd/backend/gdag.d src/dmd/backend/gflow.d src/dmd/backend/global.d src/dmd/backend/glocal.d src/dmd/backend/gloop.d src/dmd/backend/go.d src/dmd/backend/goh.d src/dmd/backend/gother.d src/dmd/backend/gsroa.d src/dmd/backend/iasm.d src/dmd/backend/mach.d src/dmd/backend/machobj.d src/dmd/backend/md5.d src/dmd/backend/md5.di src/dmd/backend/melf.d src/dmd/backend/mem.d src/dmd/backend/mscoff.d src/dmd/backend/mscoffobj.d src/dmd/backend/newman.d src/dmd/backend/nteh.d src/dmd/backend/obj.d src/dmd/backend/oper.d src/dmd/backend/os.d src/dmd/backend/out.d src/dmd/backend/outbuf.d src/dmd/backend/pdata.d src/dmd/backend/ph2.d src/dmd/backend/ptrntab.d src/dmd/backend/rtlsym.d src/dmd/backend/symbol.d src/dmd/backend/ty.d src/dmd/backend/type.d src/dmd/backend/util2.d src/dmd/backend/var.d src/dmd/backend/xmm.d src/dmd/blockexit.d src/dmd/builtin.d src/dmd/canthrow.d src/dmd/chkformat.d src/dmd/cli.d src/dmd/clone.d src/dmd/compiler.d src/dmd/compiler.h src/dmd/complex.d src/dmd/complex_t.h src/dmd/cond.d src/dmd/cond.h src/dmd/console.d src/dmd/constfold.d src/dmd/cppmangle.d src/dmd/cppmanglewin.d src/dmd/ctfe.h src/dmd/ctfeexpr.d src/dmd/ctorflow.d src/dmd/dcast.d src/dmd/dclass.d src/dmd/declaration.d src/dmd/declaration.h src/dmd/delegatize.d src/dmd/denum.d src/dmd/dimport.d src/dmd/dinifile.d src/dmd/dinterpret.d src/dmd/dmacro.d src/dmd/dmangle.d src/dmd/dmodule.d src/dmd/dmsc.d src/dmd/doc.d src/dmd/doc.h src/dmd/dscope.d src/dmd/dstruct.d src/dmd/dsymbol.d src/dmd/dsymbol.h src/dmd/dsymbolsem.d src/dmd/dtemplate.d src/dmd/dtoh.d src/dmd/dversion.d src/dmd/e2ir.d src/dmd/eh.d src/dmd/entity.d src/dmd/enum.h src/dmd/env.d src/dmd/errors.d src/dmd/errors.h src/dmd/escape.d src/dmd/expression.d src/dmd/expression.h src/dmd/expressionsem.d src/dmd/filecache.d src/dmd/foreachvar.d src/dmd/frontend.d src/dmd/func.d src/dmd/globals.d src/dmd/globals.h src/dmd/glue.d src/dmd/gluelayer.d src/dmd/hdrgen.d src/dmd/hdrgen.h src/dmd/iasm.d src/dmd/iasmdmd.d src/dmd/iasmgcc.d src/dmd/id.d src/dmd/id.h src/dmd/identifier.d src/dmd/identifier.h src/dmd/impcnvtab.d src/dmd/imphint.d src/dmd/import.h src/dmd/init.d src/dmd/init.h src/dmd/initsem.d src/dmd/inline.d src/dmd/inlinecost.d src/dmd/intrange.d src/dmd/json.d src/dmd/json.h src/dmd/lambdacomp.d src/dmd/lexer.d src/dmd/lib.d src/dmd/libelf.d src/dmd/libmach.d src/dmd/libmscoff.d src/dmd/libomf.d src/dmd/link.d src/dmd/mangle.h src/dmd/mars.d src/dmd/module.h src/dmd/mtype.d src/dmd/mtype.h src/dmd/nogc.d src/dmd/nspace.d src/dmd/nspace.h src/dmd/ob.d src/dmd/objc.d src/dmd/objc.h src/dmd/objc_glue.d src/dmd/opover.d src/dmd/optimize.d src/dmd/parse.d src/dmd/parsetimevisitor.d src/dmd/permissivevisitor.d src/dmd/printast.d src/dmd/res/default_ddoc_theme.ddoc src/dmd/root/aav.d src/dmd/root/array.d src/dmd/root/array.h src/dmd/root/bitarray.d src/dmd/root/bitarray.h src/dmd/root/ctfloat.d src/dmd/root/ctfloat.h src/dmd/root/dcompat.h src/dmd/root/dsystem.h src/dmd/root/file.d src/dmd/root/file.h src/dmd/root/filename.d src/dmd/root/filename.h src/dmd/root/hash.d src/dmd/root/longdouble.d src/dmd/root/longdouble.h src/dmd/root/man.d src/dmd/root/object.h src/dmd/root/outbuffer.d src/dmd/root/outbuffer.h src/dmd/root/port.d src/dmd/root/port.h src/dmd/root/region.d src/dmd/root/response.d src/dmd/root/rmem.d src/dmd/root/rmem.h src/dmd/root/root.h src/dmd/root/rootobject.d src/dmd/root/speller.d src/dmd/root/string.d src/dmd/root/stringtable.d src/dmd/root/strtold.d src/dmd/s2ir.d src/dmd/safe.d src/dmd/sapply.d src/dmd/scanelf.d src/dmd/scanmach.d src/dmd/scanmscoff.d src/dmd/scanomf.d src/dmd/scope.h src/dmd/semantic2.d src/dmd/semantic3.d src/dmd/sideeffect.d src/dmd/statement.d src/dmd/statement.h src/dmd/statement_rewrite_walker.d src/dmd/statementsem.d src/dmd/staticassert.d src/dmd/staticassert.h src/dmd/staticcond.d src/dmd/stmtstate.d src/dmd/strictvisitor.d src/dmd/target.d src/dmd/target.h src/dmd/template.h src/dmd/templateparamsem.d src/dmd/tocsym.d src/dmd/toctype.d src/dmd/tocvdebug.d src/dmd/todt.d src/dmd/toir.d src/dmd/tokens.d src/dmd/tokens.h src/dmd/toobj.d src/dmd/traits.d src/dmd/transitivevisitor.d src/dmd/typesem.d src/dmd/typinf.d src/dmd/utf.d src/dmd/utils.d src/dmd/version.h src/dmd/visitor.d src/dmd/visitor.h src/dmd/vsoptions.d src/dmd/vsoptions.h src/osmodel.mak src/posix.mak src/project.ddoc src/tests/cxxfrontend.c src/vcbuild/alloca.h src/vcbuild/dmd.sln src/vcbuild/dmd.vcxproj src/vcbuild/dmd.vcxproj.filters src/vcbuild/fenv.h src/vcbuild/msvc-lib.d src/vcbuild/stdint.h src/vcbuild/warnings.h src/win32.mak src/win64.mak test/Makefile test/compilable/99bottles.d test/compilable/Test16206.d test/compilable/a3682.d test/compilable/aggr_alignment.d test/compilable/aliasdecl.d test/compilable/alignment.d test/compilable/art4769.d test/compilable/b11118.d test/compilable/b12001.d test/compilable/b1215.d test/compilable/b12504.d test/compilable/b15206.d test/compilable/b15428.d test/compilable/b16244.d test/compilable/b16346.d test/compilable/b16355.d test/compilable/b16360.d test/compilable/b16382.d test/compilable/b16483.d test/compilable/b16598.d test/compilable/b16697.d test/compilable/b16967.d test/compilable/b16976.d test/compilable/b17111.d test/compilable/b17651.d test/compilable/b18197.d test/compilable/b18242.d test/compilable/b18489.d test/compilable/b19002.d test/compilable/b19432.d test/compilable/b19442.d test/compilable/b19775.d test/compilable/b19829.d test/compilable/b20011.d test/compilable/b20045.d test/compilable/b20067.d test/compilable/b20758.d test/compilable/b20780.d test/compilable/b20833.d test/compilable/b20885.d test/compilable/b20938.d test/compilable/b33.d test/compilable/b6227.d test/compilable/b6395.d test/compilable/b9490.d test/compilable/betterCarray.d test/compilable/betterCswitch.d test/compilable/betterc.d test/compilable/bug11735.d test/compilable/bug20796.d test/compilable/bug6963.d test/compilable/callconv.d test/compilable/ccompile.d test/compilable/cdcmp.d test/compilable/checkimports3.d test/compilable/chkformat.d test/compilable/commontype.d test/compilable/compile1.d test/compilable/const.d test/compilable/cpp_abi_tag_unused.d test/compilable/cppmangle.d test/compilable/cppmangle2.d test/compilable/cppmangle3.d test/compilable/cppmangle_abitag.d test/compilable/ctfe_math.d test/compilable/ctfesimd.d test/compilable/ddoc1.d test/compilable/ddoc10.d test/compilable/ddoc10236.d test/compilable/ddoc10236b.d test/compilable/ddoc10325.d test/compilable/ddoc10334.d test/compilable/ddoc10366.d test/compilable/ddoc10367.d test/compilable/ddoc10869.d test/compilable/ddoc10870.d test/compilable/ddoc11.d test/compilable/ddoc11479.d test/compilable/ddoc11511.d test/compilable/ddoc11823.d test/compilable/ddoc12.d test/compilable/ddoc12706.d test/compilable/ddoc12745.d test/compilable/ddoc13.d test/compilable/ddoc13270.d test/compilable/ddoc13502.d test/compilable/ddoc13645.d test/compilable/ddoc14.d test/compilable/ddoc14383.d test/compilable/ddoc14413.d test/compilable/ddoc14633.d test/compilable/ddoc14778.d test/compilable/ddoc15475.d test/compilable/ddoc17697.d test/compilable/ddoc18361.d test/compilable/ddoc198.d test/compilable/ddoc19814.d test/compilable/ddoc2.d test/compilable/ddoc2273.d test/compilable/ddoc3.d test/compilable/ddoc4.d test/compilable/ddoc4162.d test/compilable/ddoc4899.d test/compilable/ddoc5.d test/compilable/ddoc5446.d test/compilable/ddoc5446a.d test/compilable/ddoc5446b.d test/compilable/ddoc6.d test/compilable/ddoc648.d test/compilable/ddoc6491.d test/compilable/ddoc7.d test/compilable/ddoc7555.d test/compilable/ddoc7656.d test/compilable/ddoc7715.d test/compilable/ddoc7795.d test/compilable/ddoc8.d test/compilable/ddoc8271.d test/compilable/ddoc8739.d test/compilable/ddoc9.d test/compilable/ddoc9037.d test/compilable/ddoc9155.d test/compilable/ddoc9305.d test/compilable/ddoc9369.d test/compilable/ddoc9475.d test/compilable/ddoc9497a.d test/compilable/ddoc9497b.d test/compilable/ddoc9497c.d test/compilable/ddoc9497d.d test/compilable/ddoc9676a.d test/compilable/ddoc9676b.d test/compilable/ddoc9727.d test/compilable/ddoc9764.sh test/compilable/ddoc9789.d test/compilable/ddoc9903.d test/compilable/ddocYear.d test/compilable/ddoc_markdown_breaks.d test/compilable/ddoc_markdown_breaks_verbose.d test/compilable/ddoc_markdown_code.d test/compilable/ddoc_markdown_code_verbose.d test/compilable/ddoc_markdown_emphasis.d test/compilable/ddoc_markdown_emphasis_verbose.d test/compilable/ddoc_markdown_escapes.d test/compilable/ddoc_markdown_headings.d test/compilable/ddoc_markdown_headings_verbose.d test/compilable/ddoc_markdown_links.d test/compilable/ddoc_markdown_links_verbose.d test/compilable/ddoc_markdown_lists.d test/compilable/ddoc_markdown_lists_verbose.d test/compilable/ddoc_markdown_quote.d test/compilable/ddoc_markdown_quote_verbose.d test/compilable/ddoc_markdown_tables.d test/compilable/ddoc_markdown_tables_verbose.d test/compilable/ddocbackticks.d test/compilable/ddocunittest.d test/compilable/debugInference.d test/compilable/debuginfo.d test/compilable/defa.d test/compilable/depmsg.d test/compilable/deprecate12979a.d test/compilable/deprecate14283.d test/compilable/depsOutput9948.d test/compilable/derivedarray.d test/compilable/diag11066.d test/compilable/diag12598.d test/compilable/diag3243.d test/compilable/dip22.d test/compilable/dip22d.d test/compilable/disable_new.d test/compilable/dmdcliflags.sh test/compilable/dtoh_AliasDeclaration.d test/compilable/dtoh_AnonDeclaration.d test/compilable/dtoh_CPPNamespaceDeclaration.d test/compilable/dtoh_ClassDeclaration.d test/compilable/dtoh_StructDeclaration.d test/compilable/dtoh_TemplateDeclaration.d test/compilable/dtoh_VarDeclaration.d test/compilable/dtoh_enum.d test/compilable/dtoh_functions.d test/compilable/dtoh_unittest_block.d test/compilable/empty_file.d test/compilable/exception.d test/compilable/extra-files/c6395.d test/compilable/extra-files/c6815.d test/compilable/extra-files/cdcmp.out test/compilable/extra-files/d6815.d test/compilable/extra-files/ddoc10367.ddoc test/compilable/extra-files/ddoc198.ddoc test/compilable/extra-files/ddoc3.ddoc test/compilable/extra-files/ddoc9369.ddoc test/compilable/extra-files/ddoc9497a.ddoc test/compilable/extra-files/ddoc9497b.ddoc test/compilable/extra-files/ddoc9497c.ddoc test/compilable/extra-files/ddoc9497d.ddoc test/compilable/extra-files/ddoc9676a.ddoc test/compilable/extra-files/ddoc9764.dd test/compilable/extra-files/ddocAny-postscript.sh test/compilable/extra-files/ddocYear-postscript.sh test/compilable/extra-files/e6815.d test/compilable/extra-files/empty.conf test/compilable/extra-files/emptymain.d test/compilable/extra-files/example7190/controllers/HomeController.d test/compilable/extra-files/example7190/models/HomeModel.d test/compilable/extra-files/header-postscript.sh test/compilable/extra-files/header1.d test/compilable/extra-files/header1.di test/compilable/extra-files/header12567a.di test/compilable/extra-files/header12567b.di test/compilable/extra-files/header17125.d test/compilable/extra-files/header17125.di test/compilable/extra-files/header18364.di test/compilable/extra-files/header18365.d test/compilable/extra-files/header18365.di test/compilable/extra-files/header1i.di test/compilable/extra-files/header2.d test/compilable/extra-files/header2.di test/compilable/extra-files/header2i.di test/compilable/extra-files/header3.d test/compilable/extra-files/header3.di test/compilable/extra-files/headerudamodule.di test/compilable/extra-files/imp12624.d test/compilable/extra-files/imp9057.d test/compilable/extra-files/imp9057_2.d test/compilable/extra-files/json-postscript.sh test/compilable/extra-files/json.out test/compilable/extra-files/json2.out test/compilable/extra-files/jsonCompilerInfo.out test/compilable/extra-files/jsonNoOutFile.out test/compilable/extra-files/json_nosource.out test/compilable/extra-files/minimal/object.d test/compilable/extra-files/minimal/verify_symbols.sh test/compilable/extra-files/objdump-postscript.sh test/compilable/extra-files/pkgDIP37/datetime/common.d test/compilable/extra-files/pkgDIP37/datetime/package.d test/compilable/extra-files/pkgDIP37/test17629/common.di test/compilable/extra-files/pkgDIP37/test17629/package.di test/compilable/extra-files/pkgDIP37_10302/liba.d test/compilable/extra-files/pkgDIP37_10302/libb.d test/compilable/extra-files/pkgDIP37_10302/package.d test/compilable/extra-files/pkgDIP37_10354/mbar.d test/compilable/extra-files/pkgDIP37_10354/mfoo.d test/compilable/extra-files/pkgDIP37_10354/package.d test/compilable/extra-files/pkgDIP37_10421/algo/mod.d test/compilable/extra-files/pkgDIP37_10421/algo/package.d test/compilable/extra-files/pkgDIP37_10421/except.d test/compilable/extra-files/rdeps7016a.d test/compilable/extra-files/rdeps7016b.d test/compilable/extra-files/serenity7190/core/Controller.d test/compilable/extra-files/serenity7190/core/Model.d test/compilable/extra-files/test14894a.d test/compilable/extra-files/test14894main.d test/compilable/extra-files/test16080b.d test/compilable/extra-files/test19266.d test/compilable/extra-files/test19376.di test/compilable/extra-files/test19463.d test/compilable/extra-files/test20280a.d test/compilable/extra-files/test6461/a.d test/compilable/extra-files/test6461/b.d test/compilable/extra-files/test6461/main.d test/compilable/extra-files/test6461/tmpl.d test/compilable/extra-files/test9680dllmain.d test/compilable/extra-files/test9680main.d test/compilable/extra-files/test9680winmain.d test/compilable/extra-files/vcg-ast-postscript.sh test/compilable/fail137.d test/compilable/fail260.d test/compilable/fieldwise.d test/compilable/filefullpath_18911.d test/compilable/fix17123.d test/compilable/fix17145.d test/compilable/fix17335.d test/compilable/fix17686.d test/compilable/fix20416.d test/compilable/forward1.d test/compilable/future.d test/compilable/futurexf.d test/compilable/fwdref21063.d test/compilable/header18364.d test/compilable/header18365.d test/compilable/iasm_labeloperand.d test/compilable/ice10040.d test/compilable/ice10431a.d test/compilable/ice10431b.d test/compilable/ice10486.d test/compilable/ice10598.d test/compilable/ice11054.d test/compilable/ice11300.d test/compilable/ice11596.d test/compilable/ice11610.d test/compilable/ice11777.d test/compilable/ice11906.d test/compilable/ice12002.d test/compilable/ice12554.d test/compilable/ice12956.d test/compilable/ice13071.d test/compilable/ice13088.d test/compilable/ice13245.d test/compilable/ice13323.d test/compilable/ice13403.d test/compilable/ice13792.d test/compilable/ice13819.d test/compilable/ice13874.d test/compilable/ice13886.d test/compilable/ice13920.d test/compilable/ice13968.d test/compilable/ice14075.d test/compilable/ice14739.d test/compilable/ice1524.d test/compilable/ice15333.d test/compilable/ice15760.d test/compilable/ice15789.d test/compilable/ice15992.d test/compilable/ice20044.d test/compilable/ice20092.d test/compilable/ice6538.d test/compilable/ice8392.d test/compilable/ice854.d test/compilable/ice9663.d test/compilable/implicitconv.d test/compilable/imports/a12506.d test/compilable/imports/a12511.d test/compilable/imports/a12567.d test/compilable/imports/a13226.d test/compilable/imports/a14528.d test/compilable/imports/a15333.d test/compilable/imports/a15760.d test/compilable/imports/a15856.d test/compilable/imports/a18911.d test/compilable/imports/a313.d test/compilable/imports/a313templatemixin1.d test/compilable/imports/a313templatemixin2.d test/compilable/imports/a314.d test/compilable/imports/a8392.d test/compilable/imports/art4769a.d test/compilable/imports/art4769b.d test/compilable/imports/b313.d test/compilable/imports/b33a.d test/compilable/imports/b3682.d test/compilable/imports/bug8922.d test/compilable/imports/c314.d test/compilable/imports/checkimports3a.d test/compilable/imports/checkimports3b.d test/compilable/imports/checkimports3c.d test/compilable/imports/defaa.d test/compilable/imports/defab.d test/compilable/imports/defac.d test/compilable/imports/defad.d test/compilable/imports/depsOutput9948a.d test/compilable/imports/depsOutput9948b.d test/compilable/imports/diag12598a.d test/compilable/imports/dip22.d test/compilable/imports/dip22d.d test/compilable/imports/dip22e.d test/compilable/imports/f313.d test/compilable/imports/foofunc.d test/compilable/imports/foofunc2.d test/compilable/imports/fwdref12201a.d test/compilable/imports/fwdref2_test17548.d test/compilable/imports/fwdref9514.d test/compilable/imports/g313.d test/compilable/imports/g313public.d test/compilable/imports/g313staticif.d test/compilable/imports/g313stringmixin.d test/compilable/imports/g313templatemixin.d test/compilable/imports/ice10598a.d test/compilable/imports/ice10598b.d test/compilable/imports/ice11054a.d test/compilable/imports/ice11300a.d test/compilable/imports/ice13403a.d test/compilable/imports/imp12242a.d test/compilable/imports/imp12242a1.d test/compilable/imports/imp12242a2.d test/compilable/imports/imp12242b.d test/compilable/imports/imp12242b1.d test/compilable/imports/imp12242b2.d test/compilable/imports/imp15490a.d test/compilable/imports/imp15490b.d test/compilable/imports/imp15907.d test/compilable/imports/imp16080.d test/compilable/imports/imp16085.d test/compilable/imports/imp16085b.d test/compilable/imports/imp16088.d test/compilable/imports/imp16460.d test/compilable/imports/imp16798.d test/compilable/imports/impfieldwise.d test/compilable/imports/jsonimport1.d test/compilable/imports/jsonimport2.d test/compilable/imports/jsonimport3.d test/compilable/imports/jsonimport4.d test/compilable/imports/pkg11847/mod11847.d test/compilable/imports/pkg11847/package.d test/compilable/imports/pkg20537/package.d test/compilable/imports/pkg313/c313.d test/compilable/imports/pkgmod313/mod.d test/compilable/imports/pkgmod313/package.d test/compilable/imports/pkgmodule/package.d test/compilable/imports/pkgmodule/plainmodule.d test/compilable/imports/plainpackage/plainmodule.d test/compilable/imports/pr9471a.d test/compilable/imports/pr9471b.d test/compilable/imports/pr9471c.d test/compilable/imports/pr9471d.d test/compilable/imports/protectionimp.d test/compilable/imports/stdio4003.d test/compilable/imports/test10375a.d test/compilable/imports/test10752.d test/compilable/imports/test11225b.d test/compilable/imports/test11225c.d test/compilable/imports/test11563core_bitop.d test/compilable/imports/test11563std_array.d test/compilable/imports/test11563std_range.d test/compilable/imports/test11563std_traits.d test/compilable/imports/test1238a.d test/compilable/imports/test1238b.d test/compilable/imports/test13242a.d test/compilable/imports/test13242b.d test/compilable/imports/test13582.d test/compilable/imports/test14666a.d test/compilable/imports/test14666b.d test/compilable/imports/test15150a.d test/compilable/imports/test15150b.d test/compilable/imports/test15371.d test/compilable/imports/test15785.d test/compilable/imports/test15857a.d test/compilable/imports/test15857b.d test/compilable/imports/test15857c.d test/compilable/imports/test16214b.d test/compilable/imports/test16348.d test/compilable/imports/test16709a.d test/compilable/imports/test16709b.d test/compilable/imports/test16709c.d test/compilable/imports/test16709d.d test/compilable/imports/test17441foo/bar.d test/compilable/imports/test17441foo/package.d test/compilable/imports/test17541_2.d test/compilable/imports/test17541_3.d test/compilable/imports/test1754a.d test/compilable/imports/test1754b.d test/compilable/imports/test17991a/a.d test/compilable/imports/test17991a/package.d test/compilable/imports/test18651/algorithm.d test/compilable/imports/test18651/b.d test/compilable/imports/test18651/c.d test/compilable/imports/test18651/datetime.d test/compilable/imports/test18771a.d test/compilable/imports/test18771b.d test/compilable/imports/test18771c.d test/compilable/imports/test18771d.d test/compilable/imports/test19187.d test/compilable/imports/test19344.d test/compilable/imports/test19609a.d test/compilable/imports/test19609b.d test/compilable/imports/test19609c.d test/compilable/imports/test19656a.d test/compilable/imports/test19656b.d test/compilable/imports/test19656c.d test/compilable/imports/test19657b.d test/compilable/imports/test19657c.d test/compilable/imports/test19657d.d test/compilable/imports/test19657e.d test/compilable/imports/test19657f.d test/compilable/imports/test19657g.d test/compilable/imports/test19746a.d test/compilable/imports/test19746b.d test/compilable/imports/test19746c.d test/compilable/imports/test19746d.d test/compilable/imports/test19750a.d test/compilable/imports/test19750b.d test/compilable/imports/test19750c.d test/compilable/imports/test19750d.d test/compilable/imports/test1imp.d test/compilable/imports/test20151a/b/c/c.d test/compilable/imports/test20530a.d test/compilable/imports/test25a.d test/compilable/imports/test25b.d test/compilable/imports/test2991.d test/compilable/imports/test4003a.d test/compilable/imports/test50a.d test/compilable/imports/test55a.d test/compilable/imports/test59a.d test/compilable/imports/test59b.d test/compilable/imports/test6013.d test/compilable/imports/test61a.d test/compilable/imports/test62a.d test/compilable/imports/test63a.d test/compilable/imports/test66a.d test/compilable/imports/test67a.d test/compilable/imports/test68a.d test/compilable/imports/test70.d test/compilable/imports/test71.d test/compilable/imports/test72a.d test/compilable/imports/test72b.d test/compilable/imports/test72c.d test/compilable/imports/test7491a.d test/compilable/imports/test7491b.d test/compilable/imports/test9276decl.d test/compilable/imports/test9276expr.d test/compilable/imports/test9276hash.d test/compilable/imports/test9276parser.d test/compilable/imports/test9276sem.d test/compilable/imports/test9276type.d test/compilable/imports/test9276util.d test/compilable/imports/test9276visitors.d test/compilable/imports/test9399a.d test/compilable/imports/test9436aggr.d test/compilable/imports/test9436interp.d test/compilable/imports/test9436node.d test/compilable/imports/test9436type.d test/compilable/imports/test9672a.d test/compilable/imports/test9692b.d test/compilable/imports/test9919a.d test/compilable/imports/test9919b.d test/compilable/imports/test9919c.d test/compilable/imports/testcontracts.d test/compilable/imports/testcov1a.d test/compilable/imports/testcov1b.d test/compilable/imports/testlambda1.d test/compilable/imports/testlambda2.d test/compilable/imports/typecons4003.d test/compilable/imports/u20958.d test/compilable/imports/udamodule1.d test/compilable/imports/udamodule2.d test/compilable/imports/udamodule2a.d test/compilable/imports/wax16798.d test/compilable/interpret3.d test/compilable/isZeroInit.d test/compilable/isreturnonstack.d test/compilable/issue12520.d test/compilable/issue15478.d test/compilable/issue15574.sh test/compilable/issue15795.d test/compilable/issue15818.d test/compilable/issue16020.d test/compilable/issue17167.sh test/compilable/issue18097.d test/compilable/issue19243.sh test/compilable/issue19724.sh test/compilable/issue19925.d test/compilable/issue20362.d test/compilable/issue20915.d test/compilable/issue20995.d test/compilable/issue9884.d test/compilable/json.d test/compilable/json2.d test/compilable/json20742.d test/compilable/jsonCompilerInfo.d test/compilable/jsonNoOutFile.sh test/compilable/jsonStdout.d test/compilable/json_nosource.sh test/compilable/line.d test/compilable/minimal.d test/compilable/minimal2.d test/compilable/mixin.d test/compilable/mixinTemplateMangling.d test/compilable/mixintempl.d test/compilable/mixintype.d test/compilable/mixintype2.d test/compilable/needsmod.d test/compilable/needsmods.d test/compilable/needspkg.d test/compilable/needspkgmod.d test/compilable/nestedtempl0.d test/compilable/nestedtempl1.d test/compilable/noderef.d test/compilable/nogc.d test/compilable/ob1.d test/compilable/objc_class.d test/compilable/objc_gfunc.d test/compilable/objc_interface_final_19654.d test/compilable/paranoia_ctfe.d test/compilable/pr9374.d test/compilable/pr9383.d test/compilable/pr9471.d test/compilable/pragmainline2.d test/compilable/previewall.d test/compilable/previewhelp.d test/compilable/previewin.d test/compilable/protattr.d test/compilable/protection.d test/compilable/protection/aggregate/mod14275.d test/compilable/protection/basic/mod1.d test/compilable/protection/basic/tests.d test/compilable/protection/bug/bug14275.d test/compilable/protection/issue20796/package.d test/compilable/protection/subpkg/explicit.d test/compilable/protection/subpkg/tests.d test/compilable/protection/subpkg2/tests.d test/compilable/pull6815.d test/compilable/quadratic.d test/compilable/rdeps7016.d test/compilable/readmodify_structclass.d test/compilable/reverthelp.d test/compilable/riia_ctor.d test/compilable/rvalueref.d test/compilable/scope.d test/compilable/scopeinfer.d test/compilable/shared_destructor.d test/compilable/shared_ref.d test/compilable/sharedopt.d test/compilable/staticforeach.d test/compilable/sw_transition_complex.d test/compilable/sw_transition_field.d test/compilable/sw_transition_tls.d test/compilable/test1.d test/compilable/test10056.d test/compilable/test10066.d test/compilable/test10073.d test/compilable/test10186.d test/compilable/test10312.d test/compilable/test10375.d test/compilable/test10520.d test/compilable/test10695.d test/compilable/test10726.d test/compilable/test10752.d test/compilable/test10981.d test/compilable/test10992.d test/compilable/test10992b.d test/compilable/test10993.d test/compilable/test11137.d test/compilable/test11169.d test/compilable/test11225a.d test/compilable/test11259.d test/compilable/test11292.d test/compilable/test11371.d test/compilable/test11471.d test/compilable/test11559upgradeoptlink.d test/compilable/test11563.d test/compilable/test11656.d test/compilable/test1170.d test/compilable/test11824.d test/compilable/test11847.d test/compilable/test11914.d test/compilable/test11980.d test/compilable/test12009.d test/compilable/test1238.d test/compilable/test12496.d test/compilable/test12511.d test/compilable/test12523.d test/compilable/test12527.d test/compilable/test12567a.d test/compilable/test12567b.d test/compilable/test12567c.d test/compilable/test12567d.d test/compilable/test12567e.d test/compilable/test12593.d test/compilable/test12624.d test/compilable/test12807.d test/compilable/test12967.d test/compilable/test12979a.d test/compilable/test12979b.d test/compilable/test13008.d test/compilable/test13053.d test/compilable/test13193.d test/compilable/test13194.d test/compilable/test13226.d test/compilable/test13242.d test/compilable/test13281.d test/compilable/test13512.d test/compilable/test1353.d test/compilable/test13582a.d test/compilable/test13582b.d test/compilable/test13600.d test/compilable/test13668.d test/compilable/test13858.d test/compilable/test13902.d test/compilable/test13953.d test/compilable/test14198.d test/compilable/test14275.d test/compilable/test14317.d test/compilable/test14375.d test/compilable/test14528.d test/compilable/test14666.d test/compilable/test14747.d test/compilable/test14781.d test/compilable/test14838.d test/compilable/test14894.sh test/compilable/test14962.d test/compilable/test14973.d test/compilable/test15019.d test/compilable/test15056.d test/compilable/test15150.d test/compilable/test15292.d test/compilable/test15326.d test/compilable/test1537.d test/compilable/test15371.d test/compilable/test15389_x.d test/compilable/test15389_y.d test/compilable/test15402.d test/compilable/test15464.d test/compilable/test1547.d test/compilable/test15490.d test/compilable/test15519_x.d test/compilable/test15519_y.d test/compilable/test15550.d test/compilable/test15565.d test/compilable/test15578.d test/compilable/test15618.d test/compilable/test15668.d test/compilable/test15762.d test/compilable/test15780.d test/compilable/test15784.d test/compilable/test15785.d test/compilable/test15802.d test/compilable/test15856.d test/compilable/test15898.d test/compilable/test15907.d test/compilable/test16002.d test/compilable/test16013a.d test/compilable/test16013b.d test/compilable/test16031.d test/compilable/test16037.d test/compilable/test16080.d test/compilable/test16083.d test/compilable/test16085.d test/compilable/test16088.d test/compilable/test16107.d test/compilable/test16183.d test/compilable/test16214a.d test/compilable/test16225.d test/compilable/test16273.d test/compilable/test16292.d test/compilable/test16303.d test/compilable/test16340.d test/compilable/test16348.d test/compilable/test16460.d test/compilable/test16492.d test/compilable/test16525.d test/compilable/test16540.d test/compilable/test16563.d test/compilable/test16570.d test/compilable/test16572.d test/compilable/test16574.d test/compilable/test16578a.d test/compilable/test16578b.d test/compilable/test16607.d test/compilable/test16621.d test/compilable/test16627.d test/compilable/test16657.d test/compilable/test16685.d test/compilable/test16709.d test/compilable/test1673.d test/compilable/test16747.d test/compilable/test16798.d test/compilable/test17057.d test/compilable/test17059.d test/compilable/test17130.d test/compilable/test17143.d test/compilable/test17168.d test/compilable/test17215.d test/compilable/test17339.d test/compilable/test17349.d test/compilable/test17352.d test/compilable/test17373.d test/compilable/test17399.d test/compilable/test17419.d test/compilable/test17421.d test/compilable/test17441.d test/compilable/test17468.d test/compilable/test17512.d test/compilable/test1754.d test/compilable/test17541.d test/compilable/test17545.d test/compilable/test17548.d test/compilable/test17590.d test/compilable/test17752.d test/compilable/test17782.d test/compilable/test17791.d test/compilable/test17793.d test/compilable/test17807.d test/compilable/test17819.d test/compilable/test17853.d test/compilable/test17906.d test/compilable/test17908.d test/compilable/test17942.d test/compilable/test17970.d test/compilable/test17991.d test/compilable/test18000.d test/compilable/test18020.d test/compilable/test18030.d test/compilable/test18099.d test/compilable/test18115.d test/compilable/test18199.d test/compilable/test18367.sh test/compilable/test18430.d test/compilable/test18468.d test/compilable/test18474.d test/compilable/test18572.d test/compilable/test18578.d test/compilable/test18584.d test/compilable/test18645.d test/compilable/test18651a.d test/compilable/test18670.d test/compilable/test18694.d test/compilable/test18737.d test/compilable/test18771.d test/compilable/test18775.d test/compilable/test1878a.d test/compilable/test18821.d test/compilable/test18871.d test/compilable/test18905.d test/compilable/test18936.d test/compilable/test18951a.d test/compilable/test18951b.d test/compilable/test18955.d test/compilable/test18976.d test/compilable/test19014.d test/compilable/test19066.d test/compilable/test19081.d test/compilable/test19097.d test/compilable/test19108.d test/compilable/test19145.d test/compilable/test19187.d test/compilable/test19203.d test/compilable/test19224.d test/compilable/test19227.d test/compilable/test19266.sh test/compilable/test19292.d test/compilable/test19315.d test/compilable/test19376.sh test/compilable/test19409.d test/compilable/test19463.sh test/compilable/test19464.d test/compilable/test19491.d test/compilable/test19499.d test/compilable/test19519.d test/compilable/test19540.d test/compilable/test19557.d test/compilable/test19574.d test/compilable/test19609.d test/compilable/test19631.d test/compilable/test19652.d test/compilable/test19656.d test/compilable/test19657a.d test/compilable/test19713.d test/compilable/test19728.d test/compilable/test19746.d test/compilable/test19750.d test/compilable/test19778.d test/compilable/test19804.d test/compilable/test19809.d test/compilable/test19833.d test/compilable/test19840.d test/compilable/test19888.d test/compilable/test19895.d test/compilable/test19912.d test/compilable/test19936.d test/compilable/test19941.d test/compilable/test19954.d test/compilable/test20000.d test/compilable/test20021.d test/compilable/test20039.d test/compilable/test20051.d test/compilable/test20063.d test/compilable/test20065.d test/compilable/test20100.d test/compilable/test20136.d test/compilable/test20138.d test/compilable/test20151a.d test/compilable/test20181.d test/compilable/test20280.d test/compilable/test20318.d test/compilable/test20326.d test/compilable/test20367.d test/compilable/test20388.d test/compilable/test20406.d test/compilable/test20410.d test/compilable/test20417.d test/compilable/test20420.d test/compilable/test20488.d test/compilable/test20530.d test/compilable/test20537.d test/compilable/test20596.d test/compilable/test20653.d test/compilable/test20656.d test/compilable/test20692.d test/compilable/test20710.d test/compilable/test20744.d test/compilable/test20789.d test/compilable/test20795.d test/compilable/test20835.d test/compilable/test20842.d test/compilable/test20894.d test/compilable/test20906.d test/compilable/test20909.d test/compilable/test20923.d test/compilable/test20958.d test/compilable/test20990.d test/compilable/test21050.d test/compilable/test21058.d test/compilable/test25.d test/compilable/test2991.d test/compilable/test3004.d test/compilable/test313a.d test/compilable/test313b.d test/compilable/test313c.d test/compilable/test313d.d test/compilable/test313e.d test/compilable/test313f.d test/compilable/test313g.d test/compilable/test314.d test/compilable/test324.d test/compilable/test3673.d test/compilable/test3775.d test/compilable/test4003.d test/compilable/test4090.d test/compilable/test4364.d test/compilable/test4375.d test/compilable/test50.d test/compilable/test5227.d test/compilable/test55.d test/compilable/test59.d test/compilable/test5973.d test/compilable/test6013.d test/compilable/test602.d test/compilable/test6056a.d test/compilable/test6056b.d test/compilable/test6056c.d test/compilable/test6089.d test/compilable/test61.d test/compilable/test62.d test/compilable/test63.d test/compilable/test6319.d test/compilable/test6395.d test/compilable/test6461.sh test/compilable/test6534.d test/compilable/test6541.d test/compilable/test6552.d test/compilable/test66.d test/compilable/test67.d test/compilable/test6777.d test/compilable/test68.d test/compilable/test69.d test/compilable/test6999.d test/compilable/test70.d test/compilable/test7065.d test/compilable/test71.d test/compilable/test7172.d test/compilable/test7190.d test/compilable/test72.d test/compilable/test7252.d test/compilable/test7399.d test/compilable/test7491.d test/compilable/test7524.d test/compilable/test7569.d test/compilable/test7754.d test/compilable/test7815.d test/compilable/test7886.d test/compilable/test8038.d test/compilable/test8041.d test/compilable/test8296.d test/compilable/test8509.d test/compilable/test8513.d test/compilable/test8543.d test/compilable/test8631.d test/compilable/test8675.d test/compilable/test8696.d test/compilable/test8717.d test/compilable/test8802.d test/compilable/test8898.d test/compilable/test8922a.d test/compilable/test8922b.d test/compilable/test8922c.d test/compilable/test8922d.d test/compilable/test8922e.d test/compilable/test8922f.d test/compilable/test8937.d test/compilable/test8959.d test/compilable/test9029.d test/compilable/test9057.d test/compilable/test9209.d test/compilable/test9274.d test/compilable/test9276.d test/compilable/test9278a.d test/compilable/test9278b.d test/compilable/test930.d test/compilable/test9399.d test/compilable/test9434.d test/compilable/test9435.d test/compilable/test9436.d test/compilable/test9526.d test/compilable/test9554.d test/compilable/test9565.d test/compilable/test9570.d test/compilable/test9613.d test/compilable/test9639.d test/compilable/test9672.d test/compilable/test9680.sh test/compilable/test9692.d test/compilable/test9692a.d test/compilable/test9701.d test/compilable/test9766.d test/compilable/test9818.d test/compilable/test9919.d test/compilable/testAliasLookup.d test/compilable/testCpCtor.d test/compilable/testDIP37.d test/compilable/testDIP37_10302.d test/compilable/testDIP37_10354.d test/compilable/testDIP37_10421.d test/compilable/testDIP37a.d test/compilable/testDIP42.d test/compilable/testInference.d test/compilable/testVRP.d test/compilable/testcheckimports.d test/compilable/testclidflags.sh test/compilable/testcolor.sh test/compilable/testcontracts.d test/compilable/testcov1.d test/compilable/testdip1008.d test/compilable/testexpression.d test/compilable/testfptr.d test/compilable/testfwdref.d test/compilable/testheader1.d test/compilable/testheader12567a.d test/compilable/testheader12567b.d test/compilable/testheader17125.d test/compilable/testheader1i.d test/compilable/testheader2.d test/compilable/testheader2i.d test/compilable/testheader3.d test/compilable/testheaderudamodule.d test/compilable/testhelp.d test/compilable/testimport12242.d test/compilable/testlambdacomp.d test/compilable/testlibmain.d test/compilable/testparse.d test/compilable/testpostblit.d test/compilable/testprofile.d test/compilable/testtempl2.d test/compilable/traits.d test/compilable/traits_getFunctionAttributes.d test/compilable/transitionhelp.d test/compilable/typeid_name.d test/compilable/uda.d test/compilable/udamodule1.d test/compilable/udamodule2.d test/compilable/vcg-ast.d test/compilable/verrors_spec.d test/compilable/version.d test/compilable/vgc1.d test/compilable/vgc2.d test/compilable/vgc3.d test/compilable/vtemplates.d test/compilable/warn3882.d test/dshell/cpp_header_gen.d test/dshell/depsprot.d test/dshell/dll.d test/dshell/extra-files/cpp_header_gen/app.cpp test/dshell/extra-files/cpp_header_gen/library.d test/dshell/extra-files/depsprot.d test/dshell/extra-files/dll/dllmain.d test/dshell/extra-files/dll/mydll.d test/dshell/extra-files/dll/testdll.d test/dshell/extra-files/linker_flag_with_spaces_a.d test/dshell/extra-files/linker_flag_with_spaces_b.d test/dshell/extra-files/mul9377a.d test/dshell/extra-files/mul9377b.d test/dshell/extra-files/multi9377.d test/dshell/extra-files/printenv.d test/dshell/extra-files/source_date_epoch.d test/dshell/extra-files/test6952/main.d test/dshell/extra-files/test6952/object.d test/dshell/extra-files/test_shared.d test/dshell/imports/depsprot_default.d test/dshell/imports/depsprot_private.d test/dshell/imports/depsprot_public.d test/dshell/issue20444_SOURCE_DATE_EPOCH.d test/dshell/linker_flag_with_spaces.d test/dshell/sameenv.d test/dshell/test6952.d test/dshell/test9377.d test/dshell/test_shared.d test/dub_package/avg.d test/dub_package/frontend.d test/dub_package/frontend_file.d test/dub_package/impvisitor.d test/dub_package/lexer.d test/dub_package/parser.d test/dub_package/retrieveScope.d test/dub_package/testfiles/correct.d test/dub_package/testfiles/testavg.d test/fail_compilation/aacmp10381.d test/fail_compilation/b12504.d test/fail_compilation/b15069.d test/fail_compilation/b15875.d test/fail_compilation/b17259.d test/fail_compilation/b17285.d test/fail_compilation/b17918.d test/fail_compilation/b19523.d test/fail_compilation/b19685.d test/fail_compilation/b19691.d test/fail_compilation/b19691e.d test/fail_compilation/b19717.d test/fail_compilation/b19717a.d test/fail_compilation/b19730.d test/fail_compilation/b20011.d test/fail_compilation/b20780.d test/fail_compilation/b20875.d test/fail_compilation/b3841.d test/fail_compilation/b6227.d test/fail_compilation/betterc.d test/fail_compilation/bug15613.d test/fail_compilation/bug16165.d test/fail_compilation/bug18743.d test/fail_compilation/bug19569.d test/fail_compilation/bug4283.d test/fail_compilation/bug5.d test/fail_compilation/bug5b.d test/fail_compilation/bug8150a.d test/fail_compilation/bug8150b.d test/fail_compilation/bug8891.d test/fail_compilation/bug9631.d test/fail_compilation/ccast.d test/fail_compilation/cerrors.d test/fail_compilation/checkimports2.d test/fail_compilation/chkformat.d test/fail_compilation/circ10280.d test/fail_compilation/class1.d test/fail_compilation/class2.d test/fail_compilation/commaexp.d test/fail_compilation/constraints_aggr.d test/fail_compilation/constraints_defs.d test/fail_compilation/constraints_func1.d test/fail_compilation/constraints_func2.d test/fail_compilation/constraints_func3.d test/fail_compilation/constraints_tmpl.d test/fail_compilation/cpp_abi_tag.d test/fail_compilation/cpp_abi_tag2.d test/fail_compilation/cppeh1.d test/fail_compilation/cppeh2.d test/fail_compilation/cppmangle.d test/fail_compilation/cppmangle2.d test/fail_compilation/ctfe10989.d test/fail_compilation/ctfe10995.d test/fail_compilation/ctfe11467.d test/fail_compilation/ctfe13612.d test/fail_compilation/ctfe14207.d test/fail_compilation/ctfe14465.d test/fail_compilation/ctfe14731.d test/fail_compilation/ctypes.d test/fail_compilation/cwords.d test/fail_compilation/ddoc_18083.d test/fail_compilation/dep_d1_ops.d test/fail_compilation/dephexstrings.d test/fail_compilation/depmsg.d test/fail_compilation/depmsg15814.d test/fail_compilation/depmsg15815.d test/fail_compilation/deprecate12979a.d test/fail_compilation/deprecate12979b.d test/fail_compilation/deprecate12979c.d test/fail_compilation/deprecate12979d.d test/fail_compilation/deprecate1553.d test/fail_compilation/deprecate_objc_interface.d test/fail_compilation/deprecated6760.d test/fail_compilation/deprecatedImports.d test/fail_compilation/deprecatedTemplates.d test/fail_compilation/deprecateopdot.d test/fail_compilation/deprecations.d test/fail_compilation/diag10089.d test/fail_compilation/diag10099.d test/fail_compilation/diag10141.d test/fail_compilation/diag10169.d test/fail_compilation/diag10221.d test/fail_compilation/diag10221a.d test/fail_compilation/diag10319.d test/fail_compilation/diag10327.d test/fail_compilation/diag10359.d test/fail_compilation/diag10405.d test/fail_compilation/diag10415.d test/fail_compilation/diag10688.d test/fail_compilation/diag10768.d test/fail_compilation/diag10783.d test/fail_compilation/diag10792.d test/fail_compilation/diag10805.d test/fail_compilation/diag10862.d test/fail_compilation/diag10926.d test/fail_compilation/diag10984.d test/fail_compilation/diag11078.d test/fail_compilation/diag11132.d test/fail_compilation/diag11198.d test/fail_compilation/diag11423.d test/fail_compilation/diag11425.d test/fail_compilation/diag11727.d test/fail_compilation/diag11756.d test/fail_compilation/diag11759.d test/fail_compilation/diag11769.d test/fail_compilation/diag11819a.d test/fail_compilation/diag11819b.d test/fail_compilation/diag11840.d test/fail_compilation/diag12063.d test/fail_compilation/diag12124.d test/fail_compilation/diag12280.d test/fail_compilation/diag12312.d test/fail_compilation/diag12380.d test/fail_compilation/diag12432.d test/fail_compilation/diag12480.d test/fail_compilation/diag12487.d test/fail_compilation/diag12640.d test/fail_compilation/diag12678.d test/fail_compilation/diag12777.d test/fail_compilation/diag12829.d test/fail_compilation/diag13028.d test/fail_compilation/diag13082.d test/fail_compilation/diag13109.d test/fail_compilation/diag13142.d test/fail_compilation/diag13281.d test/fail_compilation/diag13320.d test/fail_compilation/diag13333.d test/fail_compilation/diag13528.d test/fail_compilation/diag13609a.d test/fail_compilation/diag13609b.d test/fail_compilation/diag13787.d test/fail_compilation/diag13884.d test/fail_compilation/diag13942.d test/fail_compilation/diag14102.d test/fail_compilation/diag14163.d test/fail_compilation/diag14235.d test/fail_compilation/diag14818.d test/fail_compilation/diag14875.d test/fail_compilation/diag14876.d test/fail_compilation/diag15001.d test/fail_compilation/diag15186.d test/fail_compilation/diag15209.d test/fail_compilation/diag15235.d test/fail_compilation/diag15340.d test/fail_compilation/diag15411.d test/fail_compilation/diag1566.d test/fail_compilation/diag15669.d test/fail_compilation/diag15713.d test/fail_compilation/diag15974.d test/fail_compilation/diag16271.d test/fail_compilation/diag16499.d test/fail_compilation/diag16976.d test/fail_compilation/diag16977.d test/fail_compilation/diag1730.d test/fail_compilation/diag18460.d test/fail_compilation/diag18574.d test/fail_compilation/diag19022.d test/fail_compilation/diag19196.d test/fail_compilation/diag19225.d test/fail_compilation/diag20059.d test/fail_compilation/diag20518.d test/fail_compilation/diag2452.d test/fail_compilation/diag3013.d test/fail_compilation/diag3438.d test/fail_compilation/diag3438b.d test/fail_compilation/diag3672.d test/fail_compilation/diag3672a.d test/fail_compilation/diag3673.d test/fail_compilation/diag3869.d test/fail_compilation/diag3913.d test/fail_compilation/diag4479.d test/fail_compilation/diag4528.d test/fail_compilation/diag4540.d test/fail_compilation/diag4596.d test/fail_compilation/diag5385.d test/fail_compilation/diag5450.d test/fail_compilation/diag6373.d test/fail_compilation/diag6539.d test/fail_compilation/diag6677.d test/fail_compilation/diag6699.d test/fail_compilation/diag6707.d test/fail_compilation/diag6717.d test/fail_compilation/diag6743.d test/fail_compilation/diag6796.d test/fail_compilation/diag7050a.d test/fail_compilation/diag7050b.d test/fail_compilation/diag7050c.d test/fail_compilation/diag7420.d test/fail_compilation/diag7477.d test/fail_compilation/diag7747.d test/fail_compilation/diag7998.d test/fail_compilation/diag8101.d test/fail_compilation/diag8101b.d test/fail_compilation/diag8178.d test/fail_compilation/diag8318.d test/fail_compilation/diag8425.d test/fail_compilation/diag8510.d test/fail_compilation/diag8559.d test/fail_compilation/diag8648.d test/fail_compilation/diag8684.d test/fail_compilation/diag8697.d test/fail_compilation/diag8714.d test/fail_compilation/diag8777.d test/fail_compilation/diag8787.d test/fail_compilation/diag8825.d test/fail_compilation/diag8892.d test/fail_compilation/diag8894.d test/fail_compilation/diag8928.d test/fail_compilation/diag9004.d test/fail_compilation/diag9148.d test/fail_compilation/diag9191.d test/fail_compilation/diag9210a.d test/fail_compilation/diag9247.d test/fail_compilation/diag9250.d test/fail_compilation/diag9312.d test/fail_compilation/diag9357.d test/fail_compilation/diag9358.d test/fail_compilation/diag9398.d test/fail_compilation/diag9420.d test/fail_compilation/diag9451.d test/fail_compilation/diag9479.d test/fail_compilation/diag9574.d test/fail_compilation/diag9620.d test/fail_compilation/diag9635.d test/fail_compilation/diag9679.d test/fail_compilation/diag9765.d test/fail_compilation/diag9831.d test/fail_compilation/diag9861.d test/fail_compilation/diag9880.d test/fail_compilation/diag9961.d test/fail_compilation/diag_class_alloc.d test/fail_compilation/diag_cstyle.d test/fail_compilation/diag_err1.d test/fail_compilation/diag_funclit.d test/fail_compilation/diagin.d test/fail_compilation/dip22a.d test/fail_compilation/dip22b.d test/fail_compilation/dip22e.d test/fail_compilation/dip25.d test/fail_compilation/disable.d test/fail_compilation/disable_new.d test/fail_compilation/e15876_1.d test/fail_compilation/e15876_2.d test/fail_compilation/e15876_3.d test/fail_compilation/e15876_4.d test/fail_compilation/e15876_5.d test/fail_compilation/e15876_6.d test/fail_compilation/e7804_1.d test/fail_compilation/e7804_2.d test/fail_compilation/emptyModulePattern.d test/fail_compilation/enum9921.d test/fail_compilation/extra-files/a14446.d test/fail_compilation/extra-files/bar11453.d test/fail_compilation/extra-files/fail12485.d test/fail_compilation/extra-files/fail6592.d test/fail_compilation/extra-files/fake.a test/fail_compilation/extra-files/fake.lib test/fail_compilation/extra-files/foo11453.d test/fail_compilation/extra-files/minimal/object.d test/fail_compilation/fail10.d test/fail_compilation/fail100.d test/fail_compilation/fail10082.d test/fail_compilation/fail101.d test/fail_compilation/fail10102.d test/fail_compilation/fail10115.d test/fail_compilation/fail10207.d test/fail_compilation/fail10254.d test/fail_compilation/fail10277.d test/fail_compilation/fail10285.d test/fail_compilation/fail10299.d test/fail_compilation/fail10346.d test/fail_compilation/fail104.d test/fail_compilation/fail10481.d test/fail_compilation/fail105.d test/fail_compilation/fail10528.d test/fail_compilation/fail10534.d test/fail_compilation/fail106.d test/fail_compilation/fail10630.d test/fail_compilation/fail10666.d test/fail_compilation/fail10806.d test/fail_compilation/fail109.d test/fail_compilation/fail10905.d test/fail_compilation/fail10947.d test/fail_compilation/fail10964.d test/fail_compilation/fail10968.d test/fail_compilation/fail10980.d test/fail_compilation/fail11.d test/fail_compilation/fail110.d test/fail_compilation/fail11038.d test/fail_compilation/fail11042.d test/fail_compilation/fail111.d test/fail_compilation/fail11125.d test/fail_compilation/fail11151.d test/fail_compilation/fail11163.d test/fail_compilation/fail113.d test/fail_compilation/fail11355.d test/fail_compilation/fail11375.d test/fail_compilation/fail114.d test/fail_compilation/fail11426.d test/fail_compilation/fail11445.d test/fail_compilation/fail11453a.d test/fail_compilation/fail11453b.d test/fail_compilation/fail115.d test/fail_compilation/fail11503a.d test/fail_compilation/fail11503b.d test/fail_compilation/fail11503c.d test/fail_compilation/fail11503d.d test/fail_compilation/fail11510.d test/fail_compilation/fail11532.d test/fail_compilation/fail11542.d test/fail_compilation/fail11545.d test/fail_compilation/fail11552.d test/fail_compilation/fail11562.d test/fail_compilation/fail11591b.d test/fail_compilation/fail116.d test/fail_compilation/fail11653.d test/fail_compilation/fail117.d test/fail_compilation/fail11714.d test/fail_compilation/fail11717.d test/fail_compilation/fail11720.d test/fail_compilation/fail11746.d test/fail_compilation/fail11748.d test/fail_compilation/fail11751.d test/fail_compilation/fail118.d test/fail_compilation/fail12.d test/fail_compilation/fail120.d test/fail_compilation/fail12047.d test/fail_compilation/fail121.d test/fail_compilation/fail122.d test/fail_compilation/fail12236.d test/fail_compilation/fail12255.d test/fail_compilation/fail123.d test/fail_compilation/fail12378.d test/fail_compilation/fail12390.d test/fail_compilation/fail124.d test/fail_compilation/fail12436.d test/fail_compilation/fail12485.sh test/fail_compilation/fail125.d test/fail_compilation/fail126.d test/fail_compilation/fail12604.d test/fail_compilation/fail12622.d test/fail_compilation/fail12635.d test/fail_compilation/fail12636.d test/fail_compilation/fail127.d test/fail_compilation/fail12730a.d test/fail_compilation/fail12730b.d test/fail_compilation/fail12744.d test/fail_compilation/fail12749.d test/fail_compilation/fail12764.d test/fail_compilation/fail12809.d test/fail_compilation/fail129.d test/fail_compilation/fail12901.d test/fail_compilation/fail12908.d test/fail_compilation/fail12932.d test/fail_compilation/fail13064.d test/fail_compilation/fail131.d test/fail_compilation/fail13116.d test/fail_compilation/fail13120.d test/fail_compilation/fail13187.d test/fail_compilation/fail132.d test/fail_compilation/fail13203.d test/fail_compilation/fail133.d test/fail_compilation/fail13336a.d test/fail_compilation/fail13336b.d test/fail_compilation/fail134.d test/fail_compilation/fail13424.d test/fail_compilation/fail13434_m32.d test/fail_compilation/fail13434_m64.d test/fail_compilation/fail13435.d test/fail_compilation/fail13498.d test/fail_compilation/fail13574.d test/fail_compilation/fail136.d test/fail_compilation/fail13601.d test/fail_compilation/fail13701.d test/fail_compilation/fail13756.d test/fail_compilation/fail13775.d test/fail_compilation/fail139.d test/fail_compilation/fail13902.d test/fail_compilation/fail13938.d test/fail_compilation/fail13939.d test/fail_compilation/fail14.d test/fail_compilation/fail14009.d test/fail_compilation/fail14089.d test/fail_compilation/fail142.d test/fail_compilation/fail14249.d test/fail_compilation/fail143.d test/fail_compilation/fail14304.d test/fail_compilation/fail144.d test/fail_compilation/fail14406.d test/fail_compilation/fail14416.d test/fail_compilation/fail14486.d test/fail_compilation/fail145.d test/fail_compilation/fail14554.d test/fail_compilation/fail14669.d test/fail_compilation/fail14965.d test/fail_compilation/fail14997.d test/fail_compilation/fail15.d test/fail_compilation/fail150.d test/fail_compilation/fail15044.d test/fail_compilation/fail15068.d test/fail_compilation/fail15089.d test/fail_compilation/fail152.d test/fail_compilation/fail153.d test/fail_compilation/fail15361.d test/fail_compilation/fail154.d test/fail_compilation/fail155.d test/fail_compilation/fail15535.d test/fail_compilation/fail15550.d test/fail_compilation/fail156.d test/fail_compilation/fail15616a.d test/fail_compilation/fail15616b.d test/fail_compilation/fail15626.d test/fail_compilation/fail15667.d test/fail_compilation/fail15691.d test/fail_compilation/fail15755.d test/fail_compilation/fail158.d test/fail_compilation/fail15896.d test/fail_compilation/fail159.d test/fail_compilation/fail15999.d test/fail_compilation/fail15999b.d test/fail_compilation/fail16.d test/fail_compilation/fail160.d test/fail_compilation/fail161.d test/fail_compilation/fail162.d test/fail_compilation/fail16206a.d test/fail_compilation/fail16206b.d test/fail_compilation/fail163.d test/fail_compilation/fail16600.d test/fail_compilation/fail169.d test/fail_compilation/fail16997.d test/fail_compilation/fail17.d test/fail_compilation/fail170.d test/fail_compilation/fail172.d test/fail_compilation/fail17275.d test/fail_compilation/fail17354.d test/fail_compilation/fail17382.d test/fail_compilation/fail17419.d test/fail_compilation/fail17421.d test/fail_compilation/fail17491.d test/fail_compilation/fail17492.d test/fail_compilation/fail17502.d test/fail_compilation/fail17518.d test/fail_compilation/fail17570.d test/fail_compilation/fail176.d test/fail_compilation/fail17602.d test/fail_compilation/fail17612.d test/fail_compilation/fail17625.d test/fail_compilation/fail17630.d test/fail_compilation/fail17646.d test/fail_compilation/fail17689.d test/fail_compilation/fail177.d test/fail_compilation/fail17722a.d test/fail_compilation/fail17722b.d test/fail_compilation/fail17842.d test/fail_compilation/fail179.d test/fail_compilation/fail17927.d test/fail_compilation/fail17955.d test/fail_compilation/fail17969.d test/fail_compilation/fail17976.d test/fail_compilation/fail18.d test/fail_compilation/fail180.d test/fail_compilation/fail18057.d test/fail_compilation/fail18057b.d test/fail_compilation/fail18093.d test/fail_compilation/fail18143.d test/fail_compilation/fail18219.d test/fail_compilation/fail18228.d test/fail_compilation/fail18236.d test/fail_compilation/fail18243.d test/fail_compilation/fail18266.d test/fail_compilation/fail183.d test/fail_compilation/fail18372.d test/fail_compilation/fail184.d test/fail_compilation/fail18417.d test/fail_compilation/fail185.d test/fail_compilation/fail18620.d test/fail_compilation/fail187.d test/fail_compilation/fail18719.d test/fail_compilation/fail188.d test/fail_compilation/fail18892.d test/fail_compilation/fail189.d test/fail_compilation/fail18938.d test/fail_compilation/fail18970.d test/fail_compilation/fail18979.d test/fail_compilation/fail18985.d test/fail_compilation/fail18994.d test/fail_compilation/fail190.d test/fail_compilation/fail1900.d test/fail_compilation/fail19038.d test/fail_compilation/fail19076.d test/fail_compilation/fail19098.d test/fail_compilation/fail19099.d test/fail_compilation/fail19103.d test/fail_compilation/fail19181.d test/fail_compilation/fail19182.d test/fail_compilation/fail192.d test/fail_compilation/fail19202.d test/fail_compilation/fail19209.d test/fail_compilation/fail193.d test/fail_compilation/fail19319a.d test/fail_compilation/fail19319b.d test/fail_compilation/fail19336.d test/fail_compilation/fail194.d test/fail_compilation/fail19441.d test/fail_compilation/fail19447.d test/fail_compilation/fail195.d test/fail_compilation/fail19520.d test/fail_compilation/fail196.d test/fail_compilation/fail19609.d test/fail_compilation/fail19687.d test/fail_compilation/fail19744.d test/fail_compilation/fail19757_m32.d test/fail_compilation/fail19757_m64.d test/fail_compilation/fail198.d test/fail_compilation/fail19871.d test/fail_compilation/fail19881.d test/fail_compilation/fail19890a.d test/fail_compilation/fail19890b.d test/fail_compilation/fail19897.d test/fail_compilation/fail19898a.d test/fail_compilation/fail19898b.d test/fail_compilation/fail199.d test/fail_compilation/fail19911a.d test/fail_compilation/fail19911b.d test/fail_compilation/fail19911c.d test/fail_compilation/fail19912a.d test/fail_compilation/fail19912b.d test/fail_compilation/fail19912c.d test/fail_compilation/fail19912d.d test/fail_compilation/fail19912e.d test/fail_compilation/fail19913.d test/fail_compilation/fail19914.d test/fail_compilation/fail19915.d test/fail_compilation/fail19917.d test/fail_compilation/fail19919.d test/fail_compilation/fail19922.d test/fail_compilation/fail19923.d test/fail_compilation/fail19931.d test/fail_compilation/fail19941.d test/fail_compilation/fail1995.d test/fail_compilation/fail19955.d test/fail_compilation/fail19965.d test/fail_compilation/fail20.d test/fail_compilation/fail200.d test/fail_compilation/fail20000.d test/fail_compilation/fail20033.d test/fail_compilation/fail20040.d test/fail_compilation/fail20073.d test/fail_compilation/fail20084.d test/fail_compilation/fail201.d test/fail_compilation/fail20108.d test/fail_compilation/fail20163.d test/fail_compilation/fail20164.d test/fail_compilation/fail20183.d test/fail_compilation/fail202.d test/fail_compilation/fail203.d test/fail_compilation/fail20376.d test/fail_compilation/fail204.d test/fail_compilation/fail20448.d test/fail_compilation/fail20461.d test/fail_compilation/fail205.d test/fail_compilation/fail20538.d test/fail_compilation/fail20547.d test/fail_compilation/fail20551.d test/fail_compilation/fail206.d test/fail_compilation/fail20609.d test/fail_compilation/fail20637.d test/fail_compilation/fail20638.d test/fail_compilation/fail20658.d test/fail_compilation/fail207.d test/fail_compilation/fail20730a.d test/fail_compilation/fail20730b.d test/fail_compilation/fail20771.d test/fail_compilation/fail20772.d test/fail_compilation/fail20775.d test/fail_compilation/fail20779.d test/fail_compilation/fail208.d test/fail_compilation/fail20800.d test/fail_compilation/fail209.d test/fail_compilation/fail21001.d test/fail_compilation/fail21091a.d test/fail_compilation/fail21091b.d test/fail_compilation/fail21092.d test/fail_compilation/fail212.d test/fail_compilation/fail213.d test/fail_compilation/fail215.d test/fail_compilation/fail216.d test/fail_compilation/fail217.d test/fail_compilation/fail218.d test/fail_compilation/fail2195.d test/fail_compilation/fail22.d test/fail_compilation/fail220.d test/fail_compilation/fail221.d test/fail_compilation/fail222.d test/fail_compilation/fail223.d test/fail_compilation/fail224.d test/fail_compilation/fail225.d test/fail_compilation/fail228.d test/fail_compilation/fail229.d test/fail_compilation/fail23.d test/fail_compilation/fail231.d test/fail_compilation/fail232.d test/fail_compilation/fail233.d test/fail_compilation/fail235.d test/fail_compilation/fail2350.d test/fail_compilation/fail236.d test/fail_compilation/fail2361.d test/fail_compilation/fail237.d test/fail_compilation/fail238_m32.d test/fail_compilation/fail238_m64.d test/fail_compilation/fail239.d test/fail_compilation/fail24.d test/fail_compilation/fail240.d test/fail_compilation/fail241.d test/fail_compilation/fail243.d test/fail_compilation/fail244.d test/fail_compilation/fail245.d test/fail_compilation/fail2450.d test/fail_compilation/fail2456.d test/fail_compilation/fail246.d test/fail_compilation/fail247.d test/fail_compilation/fail248.d test/fail_compilation/fail249.d test/fail_compilation/fail25.d test/fail_compilation/fail250.d test/fail_compilation/fail251.d test/fail_compilation/fail252.d test/fail_compilation/fail253.d test/fail_compilation/fail254.d test/fail_compilation/fail256.d test/fail_compilation/fail257.d test/fail_compilation/fail258.d test/fail_compilation/fail259.d test/fail_compilation/fail261.d test/fail_compilation/fail262.d test/fail_compilation/fail263.d test/fail_compilation/fail264.d test/fail_compilation/fail265.d test/fail_compilation/fail2656.d test/fail_compilation/fail267.d test/fail_compilation/fail27.d test/fail_compilation/fail270.d test/fail_compilation/fail272.d test/fail_compilation/fail273.d test/fail_compilation/fail274.d test/fail_compilation/fail2740.d test/fail_compilation/fail275.d test/fail_compilation/fail276.d test/fail_compilation/fail278.d test/fail_compilation/fail2789.d test/fail_compilation/fail279.d test/fail_compilation/fail280.d test/fail_compilation/fail281.d test/fail_compilation/fail282.d test/fail_compilation/fail284.d test/fail_compilation/fail285.d test/fail_compilation/fail287.d test/fail_compilation/fail288.d test/fail_compilation/fail289.d test/fail_compilation/fail290.d test/fail_compilation/fail291.d test/fail_compilation/fail296.d test/fail_compilation/fail2962.d test/fail_compilation/fail297.d test/fail_compilation/fail298.d test/fail_compilation/fail299.d test/fail_compilation/fail3.d test/fail_compilation/fail301.d test/fail_compilation/fail302.d test/fail_compilation/fail303.d test/fail_compilation/fail304.d test/fail_compilation/fail305.d test/fail_compilation/fail306.d test/fail_compilation/fail307.d test/fail_compilation/fail308.d test/fail_compilation/fail309.d test/fail_compilation/fail310.d test/fail_compilation/fail311.d test/fail_compilation/fail312.d test/fail_compilation/fail313.d test/fail_compilation/fail314.d test/fail_compilation/fail3144.d test/fail_compilation/fail315.d test/fail_compilation/fail3150.d test/fail_compilation/fail316.d test/fail_compilation/fail317.d test/fail_compilation/fail318.d test/fail_compilation/fail319.d test/fail_compilation/fail320.d test/fail_compilation/fail322.d test/fail_compilation/fail325.d test/fail_compilation/fail327.d test/fail_compilation/fail328.d test/fail_compilation/fail329.d test/fail_compilation/fail3290.d test/fail_compilation/fail330.d test/fail_compilation/fail331.d test/fail_compilation/fail332.d test/fail_compilation/fail333.d test/fail_compilation/fail334.d test/fail_compilation/fail335.d test/fail_compilation/fail3354.d test/fail_compilation/fail336.d test/fail_compilation/fail337.d test/fail_compilation/fail34.d test/fail_compilation/fail340.d test/fail_compilation/fail341.d test/fail_compilation/fail343.d test/fail_compilation/fail344.d test/fail_compilation/fail346.d test/fail_compilation/fail347.d test/fail_compilation/fail349.d test/fail_compilation/fail35.d test/fail_compilation/fail351.d test/fail_compilation/fail352.d test/fail_compilation/fail353.d test/fail_compilation/fail354.d test/fail_compilation/fail355.d test/fail_compilation/fail356a.d test/fail_compilation/fail356b.d test/fail_compilation/fail356c.d test/fail_compilation/fail3581a.d test/fail_compilation/fail3581b.d test/fail_compilation/fail359.d test/fail_compilation/fail36.d test/fail_compilation/fail3672.d test/fail_compilation/fail3673a.d test/fail_compilation/fail3673b.d test/fail_compilation/fail3703.d test/fail_compilation/fail3731.d test/fail_compilation/fail3753.d test/fail_compilation/fail37_m32.d test/fail_compilation/fail37_m64.d test/fail_compilation/fail38.d test/fail_compilation/fail3882.d test/fail_compilation/fail3895.d test/fail_compilation/fail39.d test/fail_compilation/fail3990.d test/fail_compilation/fail40.d test/fail_compilation/fail4082.d test/fail_compilation/fail41.d test/fail_compilation/fail42.d test/fail_compilation/fail4206.d test/fail_compilation/fail4269a.d test/fail_compilation/fail4269b.d test/fail_compilation/fail4269c.d test/fail_compilation/fail4269d.d test/fail_compilation/fail4269e.d test/fail_compilation/fail4269f.d test/fail_compilation/fail4269g.d test/fail_compilation/fail4374.d test/fail_compilation/fail4375a.d test/fail_compilation/fail4375b.d test/fail_compilation/fail4375c.d test/fail_compilation/fail4375d.d test/fail_compilation/fail4375e.d test/fail_compilation/fail4375f.d test/fail_compilation/fail4375g.d test/fail_compilation/fail4375h.d test/fail_compilation/fail4375i.d test/fail_compilation/fail4375j.d test/fail_compilation/fail4375k.d test/fail_compilation/fail4375l.d test/fail_compilation/fail4375m.d test/fail_compilation/fail4375o.d test/fail_compilation/fail4375p.d test/fail_compilation/fail4375q.d test/fail_compilation/fail4375r.d test/fail_compilation/fail4375s.d test/fail_compilation/fail4375t.d test/fail_compilation/fail4375u.d test/fail_compilation/fail4375v.d test/fail_compilation/fail4375w.d test/fail_compilation/fail4375x.d test/fail_compilation/fail4375y.d test/fail_compilation/fail44.d test/fail_compilation/fail4421.d test/fail_compilation/fail4448.d test/fail_compilation/fail45.d test/fail_compilation/fail4510.d test/fail_compilation/fail4511.d test/fail_compilation/fail4517.d test/fail_compilation/fail4544.d test/fail_compilation/fail4559.d test/fail_compilation/fail46.d test/fail_compilation/fail4611.d test/fail_compilation/fail47.d test/fail_compilation/fail4923.d test/fail_compilation/fail4958.d test/fail_compilation/fail50.d test/fail_compilation/fail51.d test/fail_compilation/fail5153.d test/fail_compilation/fail52.d test/fail_compilation/fail53.d test/fail_compilation/fail54.d test/fail_compilation/fail5435.d test/fail_compilation/fail55.d test/fail_compilation/fail56.d test/fail_compilation/fail5634.d test/fail_compilation/fail57.d test/fail_compilation/fail5733.d test/fail_compilation/fail58.d test/fail_compilation/fail5851.d test/fail_compilation/fail59.d test/fail_compilation/fail5908.d test/fail_compilation/fail5953a1.d test/fail_compilation/fail5953a2.d test/fail_compilation/fail5953s1.d test/fail_compilation/fail5953s2.d test/fail_compilation/fail60.d test/fail_compilation/fail6029.d test/fail_compilation/fail61.d test/fail_compilation/fail6107.d test/fail_compilation/fail62.d test/fail_compilation/fail6242.d test/fail_compilation/fail63.d test/fail_compilation/fail6334.d test/fail_compilation/fail6451.d test/fail_compilation/fail6453.d test/fail_compilation/fail6458.d test/fail_compilation/fail6497.d test/fail_compilation/fail6561.d test/fail_compilation/fail6592.sh test/fail_compilation/fail66.d test/fail_compilation/fail6611.d test/fail_compilation/fail6652.d test/fail_compilation/fail6781.d test/fail_compilation/fail6795.d test/fail_compilation/fail6889.d test/fail_compilation/fail6968.d test/fail_compilation/fail7077.d test/fail_compilation/fail7173.d test/fail_compilation/fail7178.d test/fail_compilation/fail72.d test/fail_compilation/fail7234.d test/fail_compilation/fail73.d test/fail_compilation/fail7369.d test/fail_compilation/fail74.d test/fail_compilation/fail7424b.d test/fail_compilation/fail7424c.d test/fail_compilation/fail7424d.d test/fail_compilation/fail7424e.d test/fail_compilation/fail7424f.d test/fail_compilation/fail7424g.d test/fail_compilation/fail7424h.d test/fail_compilation/fail7424i.d test/fail_compilation/fail7443.d test/fail_compilation/fail75.d test/fail_compilation/fail7524a.d test/fail_compilation/fail7524b.d test/fail_compilation/fail76.d test/fail_compilation/fail7603a.d test/fail_compilation/fail7603b.d test/fail_compilation/fail7603c.d test/fail_compilation/fail77.d test/fail_compilation/fail7702.d test/fail_compilation/fail7751.d test/fail_compilation/fail78.d test/fail_compilation/fail7848.d test/fail_compilation/fail7851.d test/fail_compilation/fail7859.d test/fail_compilation/fail7861.d test/fail_compilation/fail7862.d test/fail_compilation/fail79.d test/fail_compilation/fail7903.d test/fail_compilation/fail8009.d test/fail_compilation/fail8032.d test/fail_compilation/fail809.d test/fail_compilation/fail80_m32.d test/fail_compilation/fail80_m64.d test/fail_compilation/fail8168.d test/fail_compilation/fail8179b.d test/fail_compilation/fail8217.d test/fail_compilation/fail8262.d test/fail_compilation/fail8313.d test/fail_compilation/fail8373.d test/fail_compilation/fail86.d test/fail_compilation/fail8631.d test/fail_compilation/fail8691.d test/fail_compilation/fail8724.d test/fail_compilation/fail9.d test/fail_compilation/fail9063.d test/fail_compilation/fail9081.d test/fail_compilation/fail91.d test/fail_compilation/fail9199.d test/fail_compilation/fail92.d test/fail_compilation/fail9279.d test/fail_compilation/fail9290.d test/fail_compilation/fail93.d test/fail_compilation/fail9301.d test/fail_compilation/fail9346.d test/fail_compilation/fail9368.d test/fail_compilation/fail94.d test/fail_compilation/fail9413.d test/fail_compilation/fail9414a.d test/fail_compilation/fail9414b.d test/fail_compilation/fail9414c.d test/fail_compilation/fail9414d.d test/fail_compilation/fail95.d test/fail_compilation/fail9537.d test/fail_compilation/fail9562.d test/fail_compilation/fail9572.d test/fail_compilation/fail96.d test/fail_compilation/fail9613.d test/fail_compilation/fail9665a.d test/fail_compilation/fail9665b.d test/fail_compilation/fail97.d test/fail_compilation/fail9710.d test/fail_compilation/fail9735.d test/fail_compilation/fail9766.d test/fail_compilation/fail9773.d test/fail_compilation/fail9790.d test/fail_compilation/fail98.d test/fail_compilation/fail9891.d test/fail_compilation/fail9892.d test/fail_compilation/fail99.d test/fail_compilation/fail9936.d test/fail_compilation/failCopyCtor.d test/fail_compilation/failCopyCtor2.d test/fail_compilation/fail_arrayexp.d test/fail_compilation/fail_arrayop1.d test/fail_compilation/fail_arrayop2.d test/fail_compilation/fail_arrayop3a.d test/fail_compilation/fail_arrayop3b.d test/fail_compilation/fail_arrayop3c.d test/fail_compilation/fail_casting.d test/fail_compilation/fail_casting1.d test/fail_compilation/fail_casting2.d test/fail_compilation/fail_circular.d test/fail_compilation/fail_circular2.d test/fail_compilation/fail_contracts1.d test/fail_compilation/fail_contracts2.d test/fail_compilation/fail_contracts3.d test/fail_compilation/fail_contracts4.d test/fail_compilation/fail_isZeroInit.d test/fail_compilation/fail_opover.d test/fail_compilation/fail_pretty_errors.d test/fail_compilation/fail_scope.d test/fail_compilation/failattr.d test/fail_compilation/failcontracts.d test/fail_compilation/faildeleteaa.d test/fail_compilation/faildottypeinfo.d test/fail_compilation/failescape.d test/fail_compilation/failinout1.d test/fail_compilation/failinout2.d test/fail_compilation/failinout3748a.d test/fail_compilation/failinout3748b.d test/fail_compilation/failob1.d test/fail_compilation/failoffset.d test/fail_compilation/failsafea.d test/fail_compilation/failsafeb.d test/fail_compilation/failsafec.d test/fail_compilation/fix17349.d test/fail_compilation/fix17635.d test/fail_compilation/fix17751.d test/fail_compilation/fix18575.d test/fail_compilation/fix19018.d test/fail_compilation/fix19059.d test/fail_compilation/fix19246.d test/fail_compilation/fix350a.d test/fail_compilation/fix350b.d test/fail_compilation/fix5212.d test/fail_compilation/fob1.d test/fail_compilation/fob2.d test/fail_compilation/format.d test/fail_compilation/gag4269a.d test/fail_compilation/gag4269b.d test/fail_compilation/gag4269c.d test/fail_compilation/gag4269d.d test/fail_compilation/gag4269e.d test/fail_compilation/gag4269f.d test/fail_compilation/gag4269g.d test/fail_compilation/goto1.d test/fail_compilation/goto2.d test/fail_compilation/goto3.d test/fail_compilation/goto4.d test/fail_compilation/goto5.d test/fail_compilation/ice10016.d test/fail_compilation/ice10076.d test/fail_compilation/ice10212.d test/fail_compilation/ice10259.d test/fail_compilation/ice10273.d test/fail_compilation/ice10283.d test/fail_compilation/ice10341.d test/fail_compilation/ice10382.d test/fail_compilation/ice10419.d test/fail_compilation/ice10599.d test/fail_compilation/ice10600.d test/fail_compilation/ice10616.d test/fail_compilation/ice10624.d test/fail_compilation/ice10651.d test/fail_compilation/ice10713.d test/fail_compilation/ice10727a.d test/fail_compilation/ice10727b.d test/fail_compilation/ice10770.d test/fail_compilation/ice10922.d test/fail_compilation/ice10938.d test/fail_compilation/ice10949.d test/fail_compilation/ice11086.d test/fail_compilation/ice11136.d test/fail_compilation/ice11153.d test/fail_compilation/ice11404.d test/fail_compilation/ice1144.d test/fail_compilation/ice11472.d test/fail_compilation/ice11513a.d test/fail_compilation/ice11513b.d test/fail_compilation/ice11518.d test/fail_compilation/ice11552.d test/fail_compilation/ice11553.d test/fail_compilation/ice11626.d test/fail_compilation/ice11726.d test/fail_compilation/ice11793.d test/fail_compilation/ice11822.d test/fail_compilation/ice11849b.d test/fail_compilation/ice11850.d test/fail_compilation/ice11856_0.d test/fail_compilation/ice11856_1.d test/fail_compilation/ice11919.d test/fail_compilation/ice11922.d test/fail_compilation/ice11925.d test/fail_compilation/ice11926.d test/fail_compilation/ice11944.d test/fail_compilation/ice11963.d test/fail_compilation/ice11965.d test/fail_compilation/ice11967.d test/fail_compilation/ice11968.d test/fail_compilation/ice11969.d test/fail_compilation/ice11974.d test/fail_compilation/ice11982.d test/fail_compilation/ice12040.d test/fail_compilation/ice12158.d test/fail_compilation/ice12174.d test/fail_compilation/ice12235.d test/fail_compilation/ice12350.d test/fail_compilation/ice12362.d test/fail_compilation/ice12397.d test/fail_compilation/ice12501.d test/fail_compilation/ice12534.d test/fail_compilation/ice12539.d test/fail_compilation/ice12574.d test/fail_compilation/ice12581.d test/fail_compilation/ice12673.d test/fail_compilation/ice12727.d test/fail_compilation/ice12827.d test/fail_compilation/ice12836.d test/fail_compilation/ice12838.d test/fail_compilation/ice12841.d test/fail_compilation/ice12850.d test/fail_compilation/ice12902.d test/fail_compilation/ice12907.d test/fail_compilation/ice13027.d test/fail_compilation/ice13081.d test/fail_compilation/ice13131.d test/fail_compilation/ice13220.d test/fail_compilation/ice13221.d test/fail_compilation/ice13225.d test/fail_compilation/ice13311.d test/fail_compilation/ice13356.d test/fail_compilation/ice13382.d test/fail_compilation/ice13385.d test/fail_compilation/ice13459.d test/fail_compilation/ice13465a.d test/fail_compilation/ice13465b.d test/fail_compilation/ice13563.d test/fail_compilation/ice1358.d test/fail_compilation/ice13644.d test/fail_compilation/ice13788.d test/fail_compilation/ice13816.d test/fail_compilation/ice13835.d test/fail_compilation/ice13921.d test/fail_compilation/ice13987.d test/fail_compilation/ice14055.d test/fail_compilation/ice14096.d test/fail_compilation/ice14116.d test/fail_compilation/ice14130.d test/fail_compilation/ice14146.d test/fail_compilation/ice14177.d test/fail_compilation/ice14185.d test/fail_compilation/ice14272.d test/fail_compilation/ice14424.d test/fail_compilation/ice14446.d test/fail_compilation/ice14621.d test/fail_compilation/ice14642.d test/fail_compilation/ice14844.d test/fail_compilation/ice14907.d test/fail_compilation/ice14923.d test/fail_compilation/ice14929.d test/fail_compilation/ice15002.d test/fail_compilation/ice15092.d test/fail_compilation/ice15127.d test/fail_compilation/ice15172.d test/fail_compilation/ice15239.d test/fail_compilation/ice15317.d test/fail_compilation/ice15332.d test/fail_compilation/ice15441.d test/fail_compilation/ice15688.d test/fail_compilation/ice15788.d test/fail_compilation/ice15816.d test/fail_compilation/ice15855.d test/fail_compilation/ice15922.d test/fail_compilation/ice16035.d test/fail_compilation/ice16657.d test/fail_compilation/ice17074.d test/fail_compilation/ice17690.d test/fail_compilation/ice17831.d test/fail_compilation/ice18469.d test/fail_compilation/ice18753.d test/fail_compilation/ice18803a.d test/fail_compilation/ice18803b.d test/fail_compilation/ice19295.d test/fail_compilation/ice19755.d test/fail_compilation/ice19762.d test/fail_compilation/ice19887.d test/fail_compilation/ice19950.d test/fail_compilation/ice20042.d test/fail_compilation/ice20056.d test/fail_compilation/ice20057.d test/fail_compilation/ice20264.d test/fail_compilation/ice20545.d test/fail_compilation/ice20709.d test/fail_compilation/ice21060.d test/fail_compilation/ice21095.d test/fail_compilation/ice2843.d test/fail_compilation/ice4094.d test/fail_compilation/ice4983.d test/fail_compilation/ice5996.d test/fail_compilation/ice6538.d test/fail_compilation/ice7645.d test/fail_compilation/ice7782.d test/fail_compilation/ice8100.d test/fail_compilation/ice8255.d test/fail_compilation/ice8309.d test/fail_compilation/ice8499.d test/fail_compilation/ice8511.d test/fail_compilation/ice8604.d test/fail_compilation/ice8630.d test/fail_compilation/ice8711.d test/fail_compilation/ice8742.d test/fail_compilation/ice8795.d test/fail_compilation/ice8795b.d test/fail_compilation/ice9013.d test/fail_compilation/ice9254a.d test/fail_compilation/ice9254b.d test/fail_compilation/ice9254c.d test/fail_compilation/ice9273a.d test/fail_compilation/ice9273b.d test/fail_compilation/ice9284.d test/fail_compilation/ice9291.d test/fail_compilation/ice9338.d test/fail_compilation/ice9406.d test/fail_compilation/ice9439.d test/fail_compilation/ice9494.d test/fail_compilation/ice9540.d test/fail_compilation/ice9545.d test/fail_compilation/ice9759.d test/fail_compilation/ice9806.d test/fail_compilation/ice9865.d test/fail_compilation/impconv.d test/fail_compilation/imphint.d test/fail_compilation/imports/a10169.d test/fail_compilation/imports/a10528.d test/fail_compilation/imports/a11850.d test/fail_compilation/imports/a11919.d test/fail_compilation/imports/a13131checkpoint.d test/fail_compilation/imports/a13131elec.d test/fail_compilation/imports/a13131parameters.d test/fail_compilation/imports/a13311.d test/fail_compilation/imports/a13465.d test/fail_compilation/imports/a14116.d test/fail_compilation/imports/a14235.d test/fail_compilation/imports/a14424.d test/fail_compilation/imports/a15667.d test/fail_compilation/imports/a15816.d test/fail_compilation/imports/a17625.d test/fail_compilation/imports/a17630.d test/fail_compilation/imports/a18219.d test/fail_compilation/imports/a18243.d test/fail_compilation/imports/a313.d test/fail_compilation/imports/a314.d test/fail_compilation/imports/b13465.d test/fail_compilation/imports/b17625.d test/fail_compilation/imports/b17630.d test/fail_compilation/imports/b17918a.d test/fail_compilation/imports/b18219.d test/fail_compilation/imports/b19762.d test/fail_compilation/imports/b313.d test/fail_compilation/imports/b314.d test/fail_compilation/imports/bar11136.d test/fail_compilation/imports/c19762.d test/fail_compilation/imports/c314.d test/fail_compilation/imports/constraints.d test/fail_compilation/imports/deprecatedImporta.d test/fail_compilation/imports/deprecatedImportb.d test/fail_compilation/imports/diag10089a.d test/fail_compilation/imports/diag10089b.d test/fail_compilation/imports/diag10141a.d test/fail_compilation/imports/diag10141b.d test/fail_compilation/imports/diag20518a.d test/fail_compilation/imports/diag20518a/b.d test/fail_compilation/imports/diag9210b.d test/fail_compilation/imports/diag9210c.d test/fail_compilation/imports/diag9210stdcomplex.d test/fail_compilation/imports/diag9210stdtraits.d test/fail_compilation/imports/dip22a.d test/fail_compilation/imports/dip22b.d test/fail_compilation/imports/dip22c.d test/fail_compilation/imports/dip22d.d test/fail_compilation/imports/dip22e.d test/fail_compilation/imports/fail10277.d test/fail_compilation/imports/fail17646.d test/fail_compilation/imports/fail1900a.d test/fail_compilation/imports/fail1900b.d test/fail_compilation/imports/fail19609a.d test/fail_compilation/imports/fail19609b.d test/fail_compilation/imports/fail19609c.d test/fail_compilation/imports/fail19609d.d test/fail_compilation/imports/fail20164.d test/fail_compilation/imports/fail20637b.d test/fail_compilation/imports/fail20638b.d test/fail_compilation/imports/fail21001b.d test/fail_compilation/imports/fail2962a.d test/fail_compilation/imports/fail320a.d test/fail_compilation/imports/fail320b.d test/fail_compilation/imports/fail347a.d test/fail_compilation/imports/fail355.d test/fail_compilation/imports/fail356.d test/fail_compilation/imports/fail4479.d test/fail_compilation/imports/fail5385.d test/fail_compilation/imports/foo10727a.d test/fail_compilation/imports/foo10727b.d test/fail_compilation/imports/foofunc.d test/fail_compilation/imports/i20057.d test/fail_compilation/imports/ice10600a.d test/fail_compilation/imports/ice10600b.d test/fail_compilation/imports/ice11513x.d test/fail_compilation/imports/ice11513y.d test/fail_compilation/imports/ice21060a/package.d test/fail_compilation/imports/ice21060b/package.d test/fail_compilation/imports/ice21060c/package.d test/fail_compilation/imports/ice21060d/package.d test/fail_compilation/imports/ice7782algorithm.d test/fail_compilation/imports/ice7782range.d test/fail_compilation/imports/ice9865b.d test/fail_compilation/imports/imp1.d test/fail_compilation/imports/imp15896.d test/fail_compilation/imports/imp15925.d test/fail_compilation/imports/imp17602.d test/fail_compilation/imports/imp18554.d test/fail_compilation/imports/imp18979.d test/fail_compilation/imports/imp19661.d test/fail_compilation/imports/imp2.d test/fail_compilation/imports/imp20709.d test/fail_compilation/imports/pkg313/package.d test/fail_compilation/imports/range15788.d test/fail_compilation/imports/spell9644a.d test/fail_compilation/imports/spell9644b.d test/fail_compilation/imports/stdtraits10727.d test/fail_compilation/imports/test10327/empty.d test/fail_compilation/imports/test13152a.d test/fail_compilation/imports/test13152b.d test/fail_compilation/imports/test13152c.d test/fail_compilation/imports/test13152d.d test/fail_compilation/imports/test13152e.d test/fail_compilation/imports/test13152f.d test/fail_compilation/imports/test13152g.d test/fail_compilation/imports/test13152h.d test/fail_compilation/imports/test13152i.d test/fail_compilation/imports/test13152j.d test/fail_compilation/imports/test13152k.d test/fail_compilation/imports/test13152l.d test/fail_compilation/imports/test13152m.d test/fail_compilation/imports/test13152n.d test/fail_compilation/imports/test13152o.d test/fail_compilation/imports/test13152p.d test/fail_compilation/imports/test13152q.d test/fail_compilation/imports/test13152r.d test/fail_compilation/imports/test13152s.d test/fail_compilation/imports/test13152t.d test/fail_compilation/imports/test13152u.d test/fail_compilation/imports/test13152v.d test/fail_compilation/imports/test13152w.d test/fail_compilation/imports/test13152x.d test/fail_compilation/imports/test13152y.d test/fail_compilation/imports/test13152z.d test/fail_compilation/imports/test143.d test/fail_compilation/imports/test15117a.d test/fail_compilation/imports/test15785.d test/fail_compilation/imports/test15897.d test/fail_compilation/imports/test18480a.d test/fail_compilation/imports/test18480b.d test/fail_compilation/imports/test18938a/cache.d test/fail_compilation/imports/test18938a/file.d test/fail_compilation/imports/test18938b/file.d test/fail_compilation/imports/test19107a.d test/fail_compilation/imports/test19107b.d test/fail_compilation/imports/test20267.d test/fail_compilation/imports/test5412a.d test/fail_compilation/imports/test5412b.d test/fail_compilation/imports/test64a.d test/fail_compilation/invalid_lib.d test/fail_compilation/isreturnonstack.d test/fail_compilation/issue15103.d test/fail_compilation/issue16020.d test/fail_compilation/issue20422.d test/fail_compilation/issue20627.d test/fail_compilation/issue3827.d test/fail_compilation/json.d test/fail_compilation/json2.d test/fail_compilation/json3.d test/fail_compilation/jsonBadField1.d test/fail_compilation/jsonBadField2.d test/fail_compilation/lexer1.d test/fail_compilation/lexer2.d test/fail_compilation/lexer3.d test/fail_compilation/lexer4.d test/fail_compilation/lexer5.d test/fail_compilation/lookup.d test/fail_compilation/mangle1.d test/fail_compilation/mangle2.d test/fail_compilation/misc1.d test/fail_compilation/misc_parser_err_cov1.d test/fail_compilation/mixin.d test/fail_compilation/mixin_gc.d test/fail_compilation/mixintype2.d test/fail_compilation/moduleundefuda.d test/fail_compilation/needspkgmod.d test/fail_compilation/needspkgmod2.d test/fail_compilation/nestedtempl0.d test/fail_compilation/nestedtempl1.d test/fail_compilation/nestedtempl2.d test/fail_compilation/nestedtempl3.d test/fail_compilation/no_Throwable.d test/fail_compilation/no_TypeInfo.d test/fail_compilation/no_object.d test/fail_compilation/nogc1.d test/fail_compilation/nogc2.d test/fail_compilation/nogc3.d test/fail_compilation/nosharedaccess.d test/fail_compilation/notype.d test/fail_compilation/objc_class1.d test/fail_compilation/objc_class2.d test/fail_compilation/objc_class3.d test/fail_compilation/objc_non_objc_base.d test/fail_compilation/objc_offsetof.d test/fail_compilation/objc_tupleof.d test/fail_compilation/parse12924.d test/fail_compilation/parse12967a.d test/fail_compilation/parse12967b.d test/fail_compilation/parse13361.d test/fail_compilation/parse14285.d test/fail_compilation/parse14745.d test/fail_compilation/parse19277.d test/fail_compilation/parseStc.d test/fail_compilation/parseStc2.d test/fail_compilation/parseStc3.d test/fail_compilation/parseStc4.d test/fail_compilation/parseStc5.d test/fail_compilation/pragmainline.d test/fail_compilation/pragmas.d test/fail_compilation/protattr1.d test/fail_compilation/protattr2.d test/fail_compilation/protattr3.d test/fail_compilation/protection/subpkg/test1.d test/fail_compilation/protection/subpkg/test2.d test/fail_compilation/protection/subpkg/test3.d test/fail_compilation/reg6769.d test/fail_compilation/reserved_version.d test/fail_compilation/reserved_version_switch.d test/fail_compilation/retref2.d test/fail_compilation/retscope.d test/fail_compilation/retscope2.d test/fail_compilation/retscope3.d test/fail_compilation/retscope4.d test/fail_compilation/retscope5.d test/fail_compilation/retscope6.d test/fail_compilation/scope_class.d test/fail_compilation/scope_type.d test/fail_compilation/skip.d test/fail_compilation/spell9644.d test/fail_compilation/staticarrayoverflow.d test/fail_compilation/staticforeach1.d test/fail_compilation/staticforeach2.d test/fail_compilation/staticforeach3.d test/fail_compilation/switches.d test/fail_compilation/t1252.d test/fail_compilation/test1.d test/fail_compilation/test10.d test/fail_compilation/test1021.d test/fail_compilation/test11006.d test/fail_compilation/test11047.d test/fail_compilation/test11176.d test/fail_compilation/test12228.d test/fail_compilation/test12385.d test/fail_compilation/test12430.d test/fail_compilation/test12558.d test/fail_compilation/test12822.d test/fail_compilation/test12979.d test/fail_compilation/test13152.d test/fail_compilation/test13536.d test/fail_compilation/test13537.d test/fail_compilation/test13698.d test/fail_compilation/test13786.d test/fail_compilation/test13867.d test/fail_compilation/test14238.d test/fail_compilation/test143.d test/fail_compilation/test14496.d test/fail_compilation/test14538.d test/fail_compilation/test15177.d test/fail_compilation/test15191.d test/fail_compilation/test15306.d test/fail_compilation/test15373.d test/fail_compilation/test15399.d test/fail_compilation/test15544.d test/fail_compilation/test15660.d test/fail_compilation/test15672.d test/fail_compilation/test15703.d test/fail_compilation/test15704.d test/fail_compilation/test15785.d test/fail_compilation/test15785b.d test/fail_compilation/test15897.d test/fail_compilation/test15925.d test/fail_compilation/test15989.d test/fail_compilation/test16095.d test/fail_compilation/test16116.d test/fail_compilation/test16188.d test/fail_compilation/test16193.d test/fail_compilation/test16195.d test/fail_compilation/test16228.d test/fail_compilation/test16284.d test/fail_compilation/test16365.d test/fail_compilation/test16381.d test/fail_compilation/test16523.d test/fail_compilation/test16589.d test/fail_compilation/test16694.d test/fail_compilation/test17096.d test/fail_compilation/test17284.d test/fail_compilation/test17307.d test/fail_compilation/test17380.d test/fail_compilation/test17380spec.d test/fail_compilation/test17422.d test/fail_compilation/test17423.d test/fail_compilation/test17425.d test/fail_compilation/test17450.d test/fail_compilation/test17451.d test/fail_compilation/test17586.d test/fail_compilation/test17868.d test/fail_compilation/test17868b.d test/fail_compilation/test17892.d test/fail_compilation/test17908a.d test/fail_compilation/test17908b.d test/fail_compilation/test17959.d test/fail_compilation/test18130.d test/fail_compilation/test18282.d test/fail_compilation/test18312.d test/fail_compilation/test18480.d test/fail_compilation/test18484.d test/fail_compilation/test18554.d test/fail_compilation/test18597.d test/fail_compilation/test18607.d test/fail_compilation/test18644.d test/fail_compilation/test18708.d test/fail_compilation/test18736.d test/fail_compilation/test19097.d test/fail_compilation/test19107.d test/fail_compilation/test19112.d test/fail_compilation/test19176.d test/fail_compilation/test19193.d test/fail_compilation/test19473.d test/fail_compilation/test19608.d test/fail_compilation/test19646.d test/fail_compilation/test19661.d test/fail_compilation/test19971.d test/fail_compilation/test20096.d test/fail_compilation/test20149.d test/fail_compilation/test20267.d test/fail_compilation/test20383.d test/fail_compilation/test20515.d test/fail_compilation/test20549.d test/fail_compilation/test20569.d test/fail_compilation/test20610.d test/fail_compilation/test20626.d test/fail_compilation/test20696.d test/fail_compilation/test20719.d test/fail_compilation/test20903.d test/fail_compilation/test20919.d test/fail_compilation/test21096.d test/fail_compilation/test314.d test/fail_compilation/test4682.d test/fail_compilation/test4682a.d test/fail_compilation/test4838.d test/fail_compilation/test4946.d test/fail_compilation/test5412a.d test/fail_compilation/test5412b.d test/fail_compilation/test5412c.d test/fail_compilation/test5412c2.di test/fail_compilation/test64.d test/fail_compilation/test6883.d test/fail_compilation/test8509.d test/fail_compilation/test8556.d test/fail_compilation/test8751.d test/fail_compilation/test9150.d test/fail_compilation/test9176.d test/fail_compilation/test9701.d test/fail_compilation/test9701b.d test/fail_compilation/testCols.d test/fail_compilation/testInference.d test/fail_compilation/testpull1810.d test/fail_compilation/testscopestatic.d test/fail_compilation/trait_loc_err.d test/fail_compilation/trait_loc_ov_err.d test/fail_compilation/traits.d test/fail_compilation/traits_alone.d test/fail_compilation/traits_child.d test/fail_compilation/typeerrors.d test/fail_compilation/udaparams.d test/fail_compilation/vararg2.d test/fail_compilation/varargsstc.d test/fail_compilation/vector_types.d test/fail_compilation/verifyhookexist.d test/fail_compilation/verrors0.d test/fail_compilation/verrors5.d test/fail_compilation/warn12809.d test/fail_compilation/warn13679.d test/fail_compilation/warn7444.d test/fail_compilation/widechars.d test/run.d test/runnable/A16.d test/runnable/Same.d test/runnable/a17.d test/runnable/a18.d test/runnable/a19.d test/runnable/a20.d test/runnable/a21.d test/runnable/aliasthis.d test/runnable/argufilem.d test/runnable/arrayop.d test/runnable/auto1.d test/runnable/b10562.d test/runnable/b16278.d test/runnable/b16360.d test/runnable/b17073.d test/runnable/b18034.d test/runnable/b18504.d test/runnable/b19584.d test/runnable/b20470.d test/runnable/b20890.d test/runnable/b26.d test/runnable/b6400.d test/runnable/bcraii.d test/runnable/bcraii2.d test/runnable/bench1.d test/runnable/betterc.d test/runnable/bettercUnittest.d test/runnable/bitops.d test/runnable/bug11155.d test/runnable/bug12928.d test/runnable/bug16146.d test/runnable/bug19652.d test/runnable/bug5.d test/runnable/bug7068.d test/runnable/bug846.d test/runnable/bug9010.d test/runnable/builtin.d test/runnable/c22.d test/runnable/casting.d test/runnable/cdvecfill.sh test/runnable/closure.d test/runnable/complex.d test/runnable/constfold.d test/runnable/cov2.d test/runnable/ctfe_cov.d test/runnable/ctorpowtests.d test/runnable/debug_info.d test/runnable/declaration.d test/runnable/delegate.d test/runnable/dhry.d test/runnable/e7804.d test/runnable/eh.d test/runnable/eh2.d test/runnable/entity1.d test/runnable/evalorder.d test/runnable/extern1.d test/runnable/extra-files/cdvecfill.d test/runnable/extra-files/cdvecfill.out test/runnable/extra-files/cdvecfillavx.out test/runnable/extra-files/cdvecfillavx2.out test/runnable/extra-files/coverage-postscript.sh test/runnable/extra-files/gdb15729.d test/runnable/extra-files/hello-profile-postscript.sh test/runnable/extra-files/hello-profile.d.trace.def test/runnable/extra-files/lib10386/foo/bar.d test/runnable/extra-files/lib10386/foo/package.d test/runnable/extra-files/lib13666.d test/runnable/extra-files/lib13742a.d test/runnable/extra-files/lib13742b.d test/runnable/extra-files/lib13774a.d test/runnable/extra-files/lib13774b.d test/runnable/extra-files/lib15729.d test/runnable/extra-files/lib18456.d test/runnable/extra-files/lib18456b.d test/runnable/extra-files/lib846.d test/runnable/extra-files/link14834a.d test/runnable/extra-files/link14834b.d test/runnable/extra-files/main846.d test/runnable/extra-files/minimal/object.d test/runnable/extra-files/moreBettercUnittests.d test/runnable/extra-files/objc_class.m test/runnable/extra-files/objc_instance_variable.m test/runnable/extra-files/objc_objc_msgSend.m test/runnable/extra-files/objc_self_test.m test/runnable/extra-files/objc_super_call.m test/runnable/extra-files/paranoia.d test/runnable/extra-files/runnable-a20.lst test/runnable/extra-files/runnable-bug9010.lst test/runnable/extra-files/runnable-cov2.lst test/runnable/extra-files/runnable-sieve.lst test/runnable/extra-files/runnable-test19163.lst test/runnable/extra-files/std14198/array.d test/runnable/extra-files/std14198/conv.d test/runnable/extra-files/std14198/format.d test/runnable/extra-files/std14198/uni.d test/runnable/extra-files/test10386.d test/runnable/extra-files/test10567.d test/runnable/extra-files/test10567a.d test/runnable/extra-files/test13666.d test/runnable/extra-files/test13742.d test/runnable/extra-files/test14198.d test/runnable/extra-files/test16096.d test/runnable/extra-files/test16096a.d test/runnable/extra-files/test17619.d test/runnable/extra-files/test18456.d test/runnable/extra-files/test35.d test/runnable/extra-files/test39.d test/runnable/extra-files/test44.d test/runnable/fix17429.d test/runnable/fix20466.d test/runnable/fldconst.d test/runnable/foreach.d test/runnable/foreach2.d test/runnable/foreach3.d test/runnable/foreach4.d test/runnable/foreach5.d test/runnable/funclit.d test/runnable/functype.d test/runnable/future.d test/runnable/gdb1.d test/runnable/gdb10311.d test/runnable/gdb14225.d test/runnable/gdb14276.d test/runnable/gdb14313.d test/runnable/gdb14330.d test/runnable/gdb15729.sh test/runnable/gdb4149.d test/runnable/gdb4181.d test/runnable/hello-profile.d test/runnable/hello.d test/runnable/helloUTF16.d test/runnable/helloUTF16BE.d test/runnable/helloUTF8.d test/runnable/hospital.d test/runnable/iasm.d test/runnable/iasm64.d test/runnable/ice10086a.d test/runnable/ice10086b.d test/runnable/ice10857.d test/runnable/ice15030.d test/runnable/ice15138.d test/runnable/ice15176.d test/runnable/ice15200.d test/runnable/ice4481.d test/runnable/ifti.d test/runnable/implicit.d test/runnable/imports/A16a.d test/runnable/imports/Other.d test/runnable/imports/a11447.d test/runnable/imports/a12010.d test/runnable/imports/a12037.d test/runnable/imports/a12874.d test/runnable/imports/a14267.d test/runnable/imports/a14992.d test/runnable/imports/a15030.d test/runnable/imports/a15079.d test/runnable/imports/a17a.d test/runnable/imports/a18a.d test/runnable/imports/a19a.d test/runnable/imports/a20a.d test/runnable/imports/a21a.d test/runnable/imports/a7595.d test/runnable/imports/a9546.d test/runnable/imports/a9741.d test/runnable/imports/another_module_with_tests.d test/runnable/imports/argufile.d test/runnable/imports/b11447.d test/runnable/imports/b15030.d test/runnable/imports/b26a.d test/runnable/imports/bar10378.d test/runnable/imports/bug10425.d test/runnable/imports/bug846.d test/runnable/imports/c11447.d test/runnable/imports/c22a.d test/runnable/imports/c22b.d test/runnable/imports/circularA.d test/runnable/imports/extern1a.d test/runnable/imports/ice10086x.d test/runnable/imports/ice10086y.d test/runnable/imports/ice10857a.d test/runnable/imports/ice10857b.d test/runnable/imports/ice15138a.d test/runnable/imports/ice15176a.d test/runnable/imports/ice15176b.d test/runnable/imports/ice15200a.d test/runnable/imports/ice15200b.d test/runnable/imports/ice4481a.d test/runnable/imports/ice4481b.d test/runnable/imports/inc11239.d test/runnable/imports/inline2a.d test/runnable/imports/link10920a.d test/runnable/imports/link11069x.d test/runnable/imports/link11069y.d test/runnable/imports/link11069z.d test/runnable/imports/link11127a.d test/runnable/imports/link11395a.d test/runnable/imports/link12144a.d test/runnable/imports/link13043a.d test/runnable/imports/link13394a.d test/runnable/imports/link13400a.d test/runnable/imports/link13415a.d test/runnable/imports/link14074x.d test/runnable/imports/link14074y.d test/runnable/imports/link14074z.d test/runnable/imports/link14541traits.d test/runnable/imports/link14588a.d test/runnable/imports/link14814a.d test/runnable/imports/link15194b.d test/runnable/imports/link15194std.d test/runnable/imports/link2500a.d test/runnable/imports/link2500b.d test/runnable/imports/link2644a.d test/runnable/imports/link2644b.d test/runnable/imports/link2644c.d test/runnable/imports/link7745b.d test/runnable/imports/link8023b.d test/runnable/imports/link9571a.d test/runnable/imports/linktypeinfo_file.d test/runnable/imports/m1a.d test/runnable/imports/m8668a.d test/runnable/imports/m8668b.d test/runnable/imports/m8668c.d test/runnable/imports/mangle10077.d test/runnable/imports/mod2.d test/runnable/imports/module_with_tests.d test/runnable/imports/ovs1528a.d test/runnable/imports/ovs1528b.d test/runnable/imports/pubprivtmpla.d test/runnable/imports/std11069array.d test/runnable/imports/std11069container.d test/runnable/imports/std11069range.d test/runnable/imports/std11069typecons.d test/runnable/imports/std11863bitmanip.d test/runnable/imports/std11863conv.d test/runnable/imports/std11863format.d test/runnable/imports/std12010container.d test/runnable/imports/std15017variant.d test/runnable/imports/std15021conv.d test/runnable/imports/std15021format.d test/runnable/imports/std15030algo.d test/runnable/imports/template13478a.d test/runnable/imports/template13478b.d test/runnable/imports/template2962a.d test/runnable/imports/template_ovs1.d test/runnable/imports/template_ovs2.d test/runnable/imports/template_ovs3.d test/runnable/imports/test10441b.d test/runnable/imports/test10441c.d test/runnable/imports/test10573a.d test/runnable/imports/test10736a.d test/runnable/imports/test10736b.d test/runnable/imports/test10736c.d test/runnable/imports/test10a.d test/runnable/imports/test11039b.d test/runnable/imports/test11745b.d test/runnable/imports/test11931a.d test/runnable/imports/test11931b.d test/runnable/imports/test11931c.d test/runnable/imports/test11931d.d test/runnable/imports/test13a.d test/runnable/imports/test14901a.d test/runnable/imports/test14901b.d test/runnable/imports/test14901c.d test/runnable/imports/test14901d.d test/runnable/imports/test15777a.d test/runnable/imports/test15777b.d test/runnable/imports/test17181a.d test/runnable/imports/test17181b.d test/runnable/imports/test17181c.d test/runnable/imports/test17968a.d test/runnable/imports/test18322import.d test/runnable/imports/test18868_a.d test/runnable/imports/test18868_fls.d test/runnable/imports/test19655b.d test/runnable/imports/test19655c.d test/runnable/imports/test19655d.d test/runnable/imports/test19655e.d test/runnable/imports/test19655f.d test/runnable/imports/test19655g.d test/runnable/imports/test21a.d test/runnable/imports/test24a.d test/runnable/imports/test24b.d test/runnable/imports/test27a.d test/runnable/imports/test29a.d test/runnable/imports/test29b.d test/runnable/imports/test31a.d test/runnable/imports/test32a.d test/runnable/imports/test35a.d test/runnable/imports/test38a.d test/runnable/imports/test39a.d test/runnable/imports/test3a.d test/runnable/imports/test3b.d test/runnable/imports/test40a.d test/runnable/imports/test41a.d test/runnable/imports/test44a.d test/runnable/imports/test45a.d test/runnable/imports/test45b.d test/runnable/imports/test46a.d test/runnable/imports/test46b.d test/runnable/imports/test46c.d test/runnable/imports/test48a.d test/runnable/imports/test49a.d test/runnable/imports/test57a.d test/runnable/imports/test57b.d test/runnable/imports/test58a.d test/runnable/imports/test61a.d test/runnable/imports/test7494a.d test/runnable/imports/test8997a.d test/runnable/imports/test9271a.d test/runnable/imports/testkwd_file.d test/runnable/imports/testmangle.d test/runnable/imports/testminitAA.d test/runnable/imports/testminitBB.d test/runnable/imports/testmod1a.d test/runnable/imports/testmod1b.d test/runnable/imports/testmod2a.d test/runnable/imports/tlsa.d test/runnable/imports/traits_getUnitTests_import.d test/runnable/imports/ufcs5a.d test/runnable/imports/ufcs5b.d test/runnable/imports/ufcs5c.d test/runnable/imports/ufcs5d.d test/runnable/imports/ufcs5e.d test/runnable/inline.d test/runnable/inline14560.d test/runnable/inline2.d test/runnable/inner.d test/runnable/integrate.d test/runnable/interface.d test/runnable/interface1.d test/runnable/interface2.d test/runnable/interface3.d test/runnable/interpret.d test/runnable/interpret2.d test/runnable/issue16995.d test/runnable/issue8671.d test/runnable/lazy.d test/runnable/ldc_github_1677.d test/runnable/lexer.d test/runnable/link10425.d test/runnable/link10920.d test/runnable/link11069a.d test/runnable/link11069b.d test/runnable/link11127.d test/runnable/link11395.d test/runnable/link11931.d test/runnable/link12010.d test/runnable/link12037.d test/runnable/link12144.d test/runnable/link13043.d test/runnable/link13350.d test/runnable/link13394.d test/runnable/link13400.d test/runnable/link13415.d test/runnable/link13843.d test/runnable/link14074a.d test/runnable/link14074b.d test/runnable/link14198a.sh test/runnable/link14425.d test/runnable/link14541.d test/runnable/link14588.d test/runnable/link14814.d test/runnable/link14834.sh test/runnable/link14992.d test/runnable/link15017.d test/runnable/link15021.d test/runnable/link15149.d test/runnable/link2500.d test/runnable/link2644.d test/runnable/link6574.d test/runnable/link7745.d test/runnable/link7966.d test/runnable/link8023.d test/runnable/link846.sh test/runnable/link9571.d test/runnable/linktypeinfo.d test/runnable/literal.d test/runnable/loopunroll.d test/runnable/m1.d test/runnable/manboy.d test/runnable/mangle.d test/runnable/mars1.d test/runnable/minimal.d test/runnable/minimal2.d test/runnable/mixin1.d test/runnable/mixin2.d test/runnable/mod1.d test/runnable/nan.d test/runnable/nested.d test/runnable/newdel.d test/runnable/nogc.d test/runnable/nulltype.d test/runnable/objc_call.d test/runnable/objc_call_static.d test/runnable/objc_class.d test/runnable/objc_external_class_19700.d test/runnable/objc_instance_variable.d test/runnable/objc_objc_msgSend.d test/runnable/objc_self_test.d test/runnable/objc_super_call.d test/runnable/opdisp.d test/runnable/opover.d test/runnable/opover2.d test/runnable/opover3.d test/runnable/overload.d test/runnable/paranoia.d test/runnable/pi.d test/runnable/polysemous.d test/runnable/printargs.d test/runnable/property.d test/runnable/property2.d test/runnable/pubprivtmpl.d test/runnable/s2ir.d test/runnable/sctor.d test/runnable/sctor2.d test/runnable/sdtor.d test/runnable/sieve.d test/runnable/staticforeach.d test/runnable/statictor.d test/runnable/stress.d test/runnable/structlit.d test/runnable/template1.d test/runnable/template10.d test/runnable/template13478.d test/runnable/template2.d test/runnable/template2962.d test/runnable/template3.d test/runnable/template4.d test/runnable/template6.d test/runnable/template8.d test/runnable/template9.d test/runnable/test10.d test/runnable/test10378.d test/runnable/test10386.sh test/runnable/test10441.d test/runnable/test10567.sh test/runnable/test10573.d test/runnable/test10736.d test/runnable/test10942.d test/runnable/test11.d test/runnable/test11039.d test/runnable/test11239.d test/runnable/test11447a.d test/runnable/test11447b.d test/runnable/test11447c.d test/runnable/test11745.d test/runnable/test11863.d test/runnable/test11934.d test/runnable/test12.d test/runnable/test12197.d test/runnable/test12486.d test/runnable/test12874.d test/runnable/test13.d test/runnable/test13117.d test/runnable/test13117b.d test/runnable/test13504.d test/runnable/test13613.d test/runnable/test13666.sh test/runnable/test13742.sh test/runnable/test13774.sh test/runnable/test13944.d test/runnable/test14613.d test/runnable/test14874.d test/runnable/test14901.d test/runnable/test14903.d test/runnable/test15.d test/runnable/test15079.d test/runnable/test15373.d test/runnable/test15568.d test/runnable/test15624.d test/runnable/test15779.d test/runnable/test15862.d test/runnable/test15913.d test/runnable/test16.d test/runnable/test16047.d test/runnable/test16096.sh test/runnable/test16115.d test/runnable/test16555.d test/runnable/test16640.d test/runnable/test16980.d test/runnable/test17.d test/runnable/test17072.d test/runnable/test17181.d test/runnable/test17181b.d test/runnable/test17246.d test/runnable/test17258.d test/runnable/test17337.d test/runnable/test17338.d test/runnable/test17559.d test/runnable/test17619.sh test/runnable/test17684.d test/runnable/test17868.d test/runnable/test17868b.d test/runnable/test17878.d test/runnable/test17885.d test/runnable/test17899.d test/runnable/test17940.d test/runnable/test17943.d test/runnable/test17968.d test/runnable/test18076.sh test/runnable/test18141.sh test/runnable/test18296.d test/runnable/test18322.d test/runnable/test18335.sh test/runnable/test18456.sh test/runnable/test18534.d test/runnable/test18545.d test/runnable/test18746.d test/runnable/test18772.d test/runnable/test18868.d test/runnable/test18868_2.d test/runnable/test18868_3.d test/runnable/test18880.d test/runnable/test18902.sh test/runnable/test18916.d test/runnable/test19.d test/runnable/test19086.d test/runnable/test19122.d test/runnable/test19163.d test/runnable/test19185.d test/runnable/test19223.d test/runnable/test19251.d test/runnable/test19317.d test/runnable/test19386.d test/runnable/test19393.d test/runnable/test19441.d test/runnable/test19639.d test/runnable/test19655a.d test/runnable/test19672.d test/runnable/test19679.d test/runnable/test19688.d test/runnable/test19731.d test/runnable/test19734.d test/runnable/test19735.d test/runnable/test19774.d test/runnable/test19782.d test/runnable/test19822.d test/runnable/test19825.d test/runnable/test19891.d test/runnable/test2.d test/runnable/test20.d test/runnable/test20025.d test/runnable/test20036.d test/runnable/test20130.d test/runnable/test20401.d test/runnable/test20649.d test/runnable/test20734.d test/runnable/test20893.d test/runnable/test21.d test/runnable/test21040.d test/runnable/test22.d test/runnable/test23.d test/runnable/test24.d test/runnable/test27.d test/runnable/test28.d test/runnable/test29.d test/runnable/test3.d test/runnable/test30.d test/runnable/test31.d test/runnable/test32.d test/runnable/test34.d test/runnable/test3449.d test/runnable/test35.sh test/runnable/test3574a.d test/runnable/test3574b.d test/runnable/test3574c.d test/runnable/test3574d.d test/runnable/test36.d test/runnable/test37.d test/runnable/test38.d test/runnable/test39.sh test/runnable/test4.d test/runnable/test40.d test/runnable/test41.d test/runnable/test42.d test/runnable/test42a.d test/runnable/test435.d test/runnable/test44b.d test/runnable/test45.d test/runnable/test46.d test/runnable/test48.d test/runnable/test49.d test/runnable/test5.d test/runnable/test52.d test/runnable/test5305.d test/runnable/test57.d test/runnable/test58.d test/runnable/test5943.d test/runnable/test61.d test/runnable/test6423.d test/runnable/test7.d test/runnable/test711.d test/runnable/test7452.d test/runnable/test7453.d test/runnable/test7494.d test/runnable/test7511.d test/runnable/test7595.d test/runnable/test7603.d test/runnable/test7618.d test/runnable/test7932.d test/runnable/test8.d test/runnable/test809.d test/runnable/test8182.d test/runnable/test8544.d test/runnable/test8997.d test/runnable/test9259.d test/runnable/test9271.d test/runnable/test9287.sh test/runnable/test9309.d test/runnable/test9495.d test/runnable/testCopyCtor.d test/runnable/testTypePropAsm.d test/runnable/testUTF32.d test/runnable/test_cdstrpar.d test/runnable/test_dip1006.d test/runnable/test_dip1006b.d test/runnable/test_switches.sh test/runnable/testaa.d test/runnable/testaa2.d test/runnable/testaa3.d test/runnable/testabi.d test/runnable/testaliascast.d test/runnable/testappend.d test/runnable/testargtypes.d test/runnable/testarray.d test/runnable/testassert.d test/runnable/testassign.d test/runnable/testbitarray.d test/runnable/testbounds.d test/runnable/testbounds_off.d test/runnable/testbounds_on.d test/runnable/testbounds_safeonly.d test/runnable/testbtst.d test/runnable/testcgelem.d test/runnable/testclass.d test/runnable/testconst.d test/runnable/testconstsection.d test/runnable/testcontracts.d test/runnable/testdefault_after_variadic.d test/runnable/testdstress.d test/runnable/testdt.d test/runnable/testenum.d test/runnable/testfloat.d test/runnable/testgc2.d test/runnable/testgc3.d test/runnable/testinvariant.d test/runnable/testkeyword.d test/runnable/testline.d test/runnable/testmain.d test/runnable/testminit.d test/runnable/testmmfile.d test/runnable/testmod1.d test/runnable/testmod2.d test/runnable/testmodule.d test/runnable/testpdb.d test/runnable/testpic.d test/runnable/testprofile.d test/runnable/testptrref.d test/runnable/testptrref_gc.d test/runnable/testreturn.d test/runnable/testrightthis.d test/runnable/testsafe.d test/runnable/testscope.d test/runnable/testscope2.d test/runnable/testswitch.d test/runnable/testthread.d test/runnable/testthread2.d test/runnable/testtypeid.d test/runnable/testv.d test/runnable/testxmm.d test/runnable/tls.d test/runnable/tls_dup.d test/runnable/traits.d test/runnable/traits_child.d test/runnable/traits_getPointerBitmap.d test/runnable/traits_getUnitTests.d test/runnable/traits_getVirtualIndex.d test/runnable/uda.d test/runnable/ufcs.d test/runnable/uniformctor.d test/runnable/untag.d test/runnable/variadic.d test/runnable/version.d test/runnable/warning1.d test/runnable/wc.d test/runnable/wc2.d test/runnable/wc3.d test/runnable/whetstone.d test/runnable/xdtor.d test/runnable/xpostblit.d test/runnable/xtest46.d test/runnable/xtest46_gc.d test/runnable/xtest47.d test/runnable/xtest55.d test/runnable/xtestenum.d test/runnable_cxx/abi_tags.d test/runnable_cxx/cabi1.d test/runnable_cxx/cpp11.d test/runnable_cxx/cpp_abi_tests.d test/runnable_cxx/cpp_stdlib.d test/runnable_cxx/cppa.d test/runnable_cxx/externmangle.d test/runnable_cxx/externmangle2.d test/runnable_cxx/extra-files/abi_tags.cpp test/runnable_cxx/extra-files/cabi2.cpp test/runnable_cxx/extra-files/cpp11.cpp test/runnable_cxx/extra-files/cpp_abi_tests.cpp test/runnable_cxx/extra-files/cpp_stdlib.cpp test/runnable_cxx/extra-files/cppb.cpp test/runnable_cxx/extra-files/cppb.h test/runnable_cxx/extra-files/externmangle.cpp test/runnable_cxx/extra-files/externmangle2.cpp test/runnable_cxx/extra-files/stdint.cpp test/runnable_cxx/extra-files/test6716.cpp test/runnable_cxx/stdint.d test/runnable_cxx/test6716.d test/tools/common_funcs.sh test/tools/d_do_test.d test/tools/dshell_prebuilt/dshell_prebuilt.d test/tools/exported_vars.sh test/tools/paths.d test/tools/postscript.sh test/tools/sanitize_json.d test/tools/sh_do_test.sh test/tools/unit_test_runner.d test/unit/compilable/crlf.d test/unit/deinitialization.d test/unit/frontend.d test/unit/interfaces/check_implementations_20861.d test/unit/lexer/diagnostic_reporter.d test/unit/parser/diagnostic_reporter.d test/unit/self_test.d test/unit/support.d win32.mak win64.mak <<<<<< network # path=./src-dmd-root-aav.lst |/** | * Associative array implementation. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: Walter Bright, http://www.digitalmars.com | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d) | * Documentation: https://dlang.org/phobos/dmd_root_aav.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/aav.d | */ | |module dmd.root.aav; | |import core.stdc.string; |import dmd.root.rmem; | |private size_t hash(size_t a) pure nothrow @nogc @safe |{ 91434996| a ^= (a >> 20) ^ (a >> 12); 91434996| return a ^ (a >> 7) ^ (a >> 4); |} | |struct KeyValueTemplate(K,V) |{ | K key; | V value; |} | |alias Key = void*; |alias Value = void*; | |alias KeyValue = KeyValueTemplate!(Key, Value); | |struct aaA |{ | aaA* next; | KeyValue keyValue; | alias keyValue this; |} | |struct AA |{ | aaA** b; | size_t b_length; | size_t nodes; // total number of aaA nodes | aaA*[4] binit; // initial value of b[] | aaA aafirst; // a lot of these AA's have only one entry |} | |/**************************************************** | * Determine number of entries in associative array. | */ |private size_t dmd_aaLen(const AA* aa) pure nothrow @nogc @safe |{ 78558| 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. | */ |private Value* dmd_aaGet(AA** paa, Key key) pure nothrow |{ | //printf("paa = %p\n", paa); 25496242| if (!*paa) | { 9167829| AA* a = cast(AA*)mem.xmalloc(AA.sizeof); 9167829| a.b = cast(aaA**)a.binit; 9167829| a.b_length = 4; 9167829| a.nodes = 0; 9167829| a.binit[0] = null; 9167829| a.binit[1] = null; 9167829| a.binit[2] = null; 9167829| a.binit[3] = null; 9167829| *paa = a; 9167829| assert((*paa).b_length == 4); | } | //printf("paa = %p, *paa = %p\n", paa, *paa); 25496242| assert((*paa).b_length); 25496242| size_t i = hash(cast(size_t)key) & ((*paa).b_length - 1); 25496242| aaA** pe = &(*paa).b[i]; 25496242| aaA* e; 34590572| while ((e = *pe) !is null) | { 13814931| if (key == e.key) 4720601| return &e.value; 9094330| pe = &e.next; | } | // Not found, create new elem | //printf("create new one\n"); 20775641| size_t nodes = ++(*paa).nodes; 41551282| e = (nodes != 1) ? cast(aaA*)mem.xmalloc(aaA.sizeof) : &(*paa).aafirst; | //e = new aaA(); 20775641| e.next = null; 20775641| e.key = key; 20775641| e.value = null; 20775641| *pe = e; | //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes); 20775641| if (nodes > (*paa).b_length * 2) | { | //printf("rehash\n"); 176128| dmd_aaRehash(paa); | } 20775641| return &e.value; |} | |/************************************************* | * Get value in associative array indexed by key. | * Returns NULL if it is not already there. | */ |private Value dmd_aaGetRvalue(AA* aa, Key key) pure nothrow @nogc |{ | //printf("_aaGetRvalue(key = %p)\n", key); 63776147| if (aa) | { 63219082| size_t i; 63219082| size_t len = aa.b_length; 63219082| i = hash(cast(size_t)key) & (len - 1); 63219082| aaA* e = aa.b[i]; 75473498| while (e) | { 18874503| if (key == e.key) 6620087| return e.value; 12254416| e = e.next; | } | } 57156060| return null; // not found |} | |/** |Gets a range of key/values for `aa`. | |Returns: a range of key/values for `aa`. |*/ |@property auto asRange(AA* aa) pure nothrow @nogc |{ 00000000| return AARange!(Key, Value)(aa); |} | |private struct AARange(K,V) |{ | AA* aa; | // current index into bucket array `aa.b` | size_t bIndex; | aaA* current; | 6608| this(AA* aa) pure nothrow @nogc | { 6608| if (aa) | { 6608| this.aa = aa; 6608| toNext(); | } | } | | @property bool empty() const pure nothrow @nogc @safe | { 14453| return current is null; | } | | @property auto front() const pure nothrow @nogc | { 7845| return cast(KeyValueTemplate!(K,V))current.keyValue; | } | | void popFront() pure nothrow @nogc | { 7845| if (current.next) 470| current = current.next; | else | { 7375| bIndex++; 7375| toNext(); | } | } | | private void toNext() pure nothrow @nogc | { 52321| for (; bIndex < aa.b_length; bIndex++) | { 26544| if (auto next = aa.b[bIndex]) | { 7375| current = next; 7375| return; | } | } 6608| current = null; | } |} | |unittest |{ | AA* aa = null; | foreach(keyValue; aa.asRange) | assert(0); | | enum totalKeyLength = 50; | foreach (i; 1 .. totalKeyLength + 1) | { | auto key = cast(void*)i; | { | auto valuePtr = dmd_aaGet(&aa, key); | assert(valuePtr); | *valuePtr = key; | } | bool[totalKeyLength] found; | size_t rangeCount = 0; | foreach (keyValue; aa.asRange) | { | assert(keyValue.key <= key); | assert(keyValue.key == keyValue.value); | rangeCount++; | assert(!found[cast(size_t)keyValue.key - 1]); | found[cast(size_t)keyValue.key - 1] = true; | } | assert(rangeCount == i); | } |} | |/******************************************** | * Rehash an array. | */ |private void dmd_aaRehash(AA** paa) pure nothrow |{ | //printf("Rehash\n"); 176128| if (*paa) | { 176128| AA* aa = *paa; 176128| if (aa) | { 176128| size_t len = aa.b_length; 176128| if (len == 4) 163679| len = 32; | else 12449| len *= 4; 176128| aaA** newb = cast(aaA**)mem.xmalloc(aaA.sizeof * len); 176128| memset(newb, 0, len * (aaA*).sizeof); 2895800| for (size_t k = 0; k < aa.b_length; k++) | { 1271772| aaA* e = aa.b[k]; 3991444| while (e) | { 2719672| aaA* enext = e.next; 2719672| size_t j = hash(cast(size_t)e.key) & (len - 1); 2719672| e.next = newb[j]; 2719672| newb[j] = e; 2719672| e = enext; | } | } 176128| if (aa.b != cast(aaA**)aa.binit) 12449| mem.xfree(aa.b); 176128| aa.b = newb; 176128| aa.b_length = len; | } | } |} | |unittest |{ | AA* aa = null; | Value v = dmd_aaGetRvalue(aa, null); | assert(!v); | Value* pv = dmd_aaGet(&aa, null); | assert(pv); | *pv = cast(void*)3; | v = dmd_aaGetRvalue(aa, null); | assert(v == cast(void*)3); |} | |struct AssocArray(K,V) |{ | private AA* aa; | | /** | Returns: The number of key/value pairs. | */ | @property size_t length() const pure nothrow @nogc @safe | { 39279| return dmd_aaLen(aa); | } | | /** | Lookup value associated with `key` and return the address to it. If the `key` | has not been added, it adds it and returns the address to the new value. | | Params: | key = key to lookup the value for | | Returns: the address to the value associated with `key`. If `key` does not exist, it | is added and the address to the new value is returned. | */ | V* getLvalue(const(K) key) pure nothrow | { 25496242| return cast(V*)dmd_aaGet(&aa, cast(void*)key); | } | | /** | Lookup and return the value associated with `key`, if the `key` has not been | added, it returns null. | | Params: | key = key to lookup the value for | | Returns: the value associated with `key` if present, otherwise, null. | */ | V opIndex(const(K) key) pure nothrow @nogc | { 63776147| return cast(V)dmd_aaGetRvalue(aa, cast(void*)key); | } | | /** | Gets a range of key/values for `aa`. | | Returns: a range of key/values for `aa`. | */ | @property auto asRange() pure nothrow @nogc | { 6608| return AARange!(K,V)(aa); | } |} | |/// |unittest |{ | auto foo = new Object(); | auto bar = new Object(); | | AssocArray!(Object, Object) aa; | | assert(aa[foo] is null); | assert(aa.length == 0); | | auto fooValuePtr = aa.getLvalue(foo); | *fooValuePtr = bar; | | assert(aa[foo] is bar); | assert(aa.length == 1); |} src/dmd/root/aav.d is 98% covered <<<<<< EOF # path=./src-dmd-backend-exh.lst |/** | * Compiler implementation of the | * $(LINK2 http://www.dlang.org, D programming language). | * | * Copyright: Copyright (C) 1993-1998 by Symantec | * Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/exh.d, backend/exh.d) | */ | |module dmd.backend.exh; | |// Online documentation: https://dlang.org/phobos/dmd_backend_exh.html | |import dmd.backend.cc; |import dmd.backend.cdef; |import dmd.backend.el; |import dmd.backend.type; | |extern (C++): |@nogc: |nothrow: | |struct Aobject |{ | Symbol *AOsym; // Symbol for active object | targ_size_t AOoffset; // offset from that object | Symbol *AOfunc; // cleanup function |} | | |/* except.c */ |void except_init(); |void except_term(); |elem *except_obj_ctor(elem *e,Symbol *s,targ_size_t offset,Symbol *sdtor); |elem *except_obj_dtor(elem *e,Symbol *s,targ_size_t offset); |elem *except_throw_expression(); |type *except_declaration(Symbol *cv); |void except_exception_spec(type *t); |void except_index_set(int index); |int except_index_get(); |void except_pair_setoffset(void *p,targ_size_t offset); |void except_pair_append(void *p, int index); |void except_push(void *p,elem *e,block *b); |void except_pop(void *p,elem *e,block *b); |void except_mark(); |void except_release(); |Symbol *except_gensym(); |Symbol *except_gentables(); |void except_fillInEHTable(Symbol *s); |void except_reset(); | |/* pdata.c */ |void win64_pdata(Symbol *sf); | src/dmd/backend/exh.d has no code <<<<<< EOF # path=./src-dmd-backend-outbuf.lst |/** | * Compiler implementation of the | * $(LINK2 http://www.dlang.org, D programming language). | * | * Copyright: Copyright (C) 1994-1998 by Symantec | * Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/outbuf.d, backend/outbuf.d) | * Documentation: https://dlang.org/phobos/dmd_backend_outbuf.html | */ | |module dmd.backend.outbuf; | |import core.stdc.stdio; |import core.stdc.stdlib; |import core.stdc.string; | |// Output buffer | |// (This used to be called OutBuffer, renamed to avoid name conflicts with Mars.) | |extern (C++): | |private nothrow void err_nomem(); | |struct Outbuffer |{ | ubyte *buf; // the buffer itself | ubyte *pend; // pointer past the end of the buffer | private ubyte *p; // current position in buffer | | nothrow: 00000000| this(size_t initialSize) | { 00000000| reserve(initialSize); | } | | //~this() { dtor(); } | | void dtor() | { 2066| if (auto slice = this.extractSlice()) 1950| free(slice.ptr); | } | | void reset() | { 174391| p = buf; | } | | // Returns: A slice to the data written so far | extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout | @trusted pure nothrow @nogc | { 00000000| assert(this.buf, "Attempt to dereference a null pointer"); 00000000| assert(from < to, "First index must be smaller than the second one"); 00000000| assert(this.length() <= (to - from), "Out of bound access"); 00000000| return this.buf[from .. to]; | } | | /// Ditto | extern(D) inout(ubyte)[] opSlice() inout @trusted pure nothrow @nogc | { 185549| return this.buf[0 .. this.p - this.buf]; | } | | extern(D) ubyte[] extractSlice() @safe pure nothrow @nogc | { 2182| auto ret = this[]; 2182| this.buf = this.p = this.pend = null; 2182| return ret; | } | | /******************** | * Make sure we have at least `nbytes` available for writing, | * allocate more if necessary. | * This is the inlinable fast path. Prefer `enlarge` if allocation | * will always happen. | */ | void reserve(size_t nbytes) | { | // Keep small so it is inlined 19123749| if (pend - p < nbytes) 1089692| enlarge(nbytes); | } | | // Reserve nbytes in buffer | void enlarge(size_t nbytes) | { | pragma(inline, false); // do not inline slow path 1089692| const size_t oldlen = pend - buf; 1089692| const size_t used = p - buf; | 1089692| size_t len = used + nbytes; | // No need to reallocate 1089692| if (nbytes < (pend - p)) 00000000| return; | 1089692| const size_t newlen = oldlen + (oldlen >> 1); // oldlen * 1.5 1089692| if (len < newlen) 241129| len = newlen; 1089692| len = (len + 15) & ~15; | 1089692| buf = cast(ubyte*) realloc(buf,len); 1089692| if (!buf) 00000000| err_nomem(); | 1089692| pend = buf + len; 1089692| p = buf + used; | } | | | // Write n zeros; return pointer to start of zeros | void *writezeros(size_t n) | { 511597| reserve(n); 511597| void *pstart = memset(p,0,n); 511597| p += n; 511597| return pstart; | } | | // Position buffer to accept the specified number of bytes at offset | void position(size_t offset, size_t nbytes) | { 2366742| if (offset + nbytes > pend - buf) | { 5631| reserve(offset + nbytes - (p - buf)); | } 2366742| p = buf + offset; | 2366742| debug assert(buf <= p); 2366742| debug assert(p <= pend); 2366742| debug assert(p + nbytes <= pend); | } | | // Write an array to the buffer, no reserve check | void writen(const void *b, size_t len) | { 2046400| memcpy(p,b,len); 2046400| p += len; | } | | // Write an array to the buffer. | extern (D) | void write(const(void)[] b) | { 7069726| reserve(b.length); 7069726| memcpy(p, b.ptr, b.length); 7069726| p += b.length; | } | | void write(const(void)* b, size_t len) | { 4473299| write(b[0 .. len]); | } | | /** | * Writes an 8 bit byte, no reserve check. | */ | void writeByten(ubyte v) | { 1193993| *p++ = v; | } | | /** | * Writes an 8 bit byte. | */ | void writeByte(int v) | { 7822224| reserve(1); 7822224| *p++ = cast(ubyte)v; | } | | /** | * Writes a 16 bit value, no reserve check. | */ | void write16n(int v) | { 55422| *(cast(ushort *) p) = cast(ushort)v; 55422| p += 2; | } | | | /** | * Writes a 16 bit value. | */ | void write16(int v) | { 55422| reserve(2); 55422| write16n(v); | } | | /** | * Writes a 32 bit int. | */ | void write32(int v) | { 2092105| reserve(4); 2092105| *cast(int *)p = v; 2092105| p += 4; | } | | /** | * Writes a 64 bit long. | */ | void write64(long v) | { 830624| reserve(8); 830624| *cast(long *)p = v; 830624| p += 8; | } | | | /** | * Writes a 32 bit float. | */ | void writeFloat(float v) | { 00000000| reserve(float.sizeof); 00000000| *cast(float *)p = v; 00000000| p += float.sizeof; | } | | /** | * Writes a 64 bit double. | */ | void writeDouble(double v) | { 00000000| reserve(double.sizeof); 00000000| *cast(double *)p = v; 00000000| p += double.sizeof; | } | | /** | * Writes a String as a sequence of bytes. | */ | void write(const(char)* s) | { 377| write(s[0 .. strlen(s)]); | } | | /** | * Writes a 0 terminated String | */ | void writeString(const(char)* s) | { 1750695| write(s[0 .. strlen(s)+1]); | } | | /// Ditto | extern(D) void writeString(const(char)[] s) | { 98175| write(s); 98175| writeByte(0); | } | | /// Disembiguation for `string` | extern(D) void writeString(string s) | { 90952| writeString(cast(const(char)[])(s)); | } | | /** | * Inserts string at beginning of buffer. | */ | void prependBytes(const(char)* s) | { 00000000| prepend(s, strlen(s)); | } | | /** | * Inserts bytes at beginning of buffer. | */ | void prepend(const(void)* b, size_t len) | { 00000000| reserve(len); 00000000| memmove(buf + len,buf,p - buf); 00000000| memcpy(buf,b,len); 00000000| p += len; | } | | /** | * Bracket buffer contents with c1 and c2. | */ | void bracket(char c1,char c2) | { 00000000| reserve(2); 00000000| memmove(buf + 1,buf,p - buf); 00000000| buf[0] = c1; 00000000| p[1] = c2; 00000000| p += 2; | } | | /** | * Returns the number of bytes written. | */ | size_t length() const @safe pure nothrow @nogc | { 13796638| return p - buf; | } | | /** | * Set current size of buffer. | */ | | void setsize(size_t size) | { 3315034| p = buf + size; | //debug assert(buf <= p); | //debug assert(p <= pend); | } | | void writesLEB128(int value) | { 603890| while (1) | { 603890| ubyte b = value & 0x7F; | 603890| value >>= 7; // arithmetic right shift 886547| if (value == 0 && !(b & 0x40) || 557187| value == -1 && (b & 0x40)) | { 477249| writeByte(b); 477249| break; | } 126641| writeByte(b | 0x80); | } | } | | void writeuLEB128(uint value) | { | do | { 2417109| ubyte b = value & 0x7F; | 2417109| value >>= 7; 2417109| if (value) 149611| b |= 0x80; 2417109| writeByte(b); 2417109| } while (value); | } |} src/dmd/backend/outbuf.d is 74% covered <<<<<< EOF # path=./src-dmd-backend-xmm.lst |/** | * Compiler implementation of the | * $(LINK2 http://www.dlang.org, D programming language). | * | * Copyright: Copyright (C) ?-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/xmm.d, backend/_xmm.d) | */ | |module dmd.backend.xmm; | |// Online documentation: https://dlang.org/phobos/dmd_backend_xmm.html | |// XMM opcodes | |enum |{ | ADDSS = 0xF30F58, // ADDSS xmm1, xmm2/mem32 F3 0F 58 /r | ADDSD = 0xF20F58, // ADDSD xmm1, xmm2/mem64 F2 0F 58 /r | ADDPS = 0x000F58, // ADDPS xmm1, xmm2/mem128 0F 58 /r | ADDPD = 0x660F58, // ADDPD xmm1, xmm2/mem128 66 0F 58 /r | PADDB = 0x660FFC, // PADDB xmm1, xmm2/mem128 66 0F FC /r | PADDW = 0x660FFD, // PADDW xmm1, xmm2/mem128 66 0F FD /r | PADDD = 0x660FFE, // PADDD xmm1, xmm2/mem128 66 0F FE /r | PADDQ = 0x660FD4, // PADDQ xmm1, xmm2/mem128 66 0F D4 /r | | SUBSS = 0xF30F5C, // SUBSS xmm1, xmm2/mem32 F3 0F 5C /r | SUBSD = 0xF20F5C, // SUBSD xmm1, xmm2/mem64 F2 0F 5C /r | SUBPS = 0x000F5C, // SUBPS xmm1, xmm2/mem128 0F 5C /r | SUBPD = 0x660F5C, // SUBPD xmm1, xmm2/mem128 66 0F 5C /r | PSUBB = 0x660FF8, // PSUBB xmm1, xmm2/mem128 66 0F F8 /r | PSUBW = 0x660FF9, // PSUBW xmm1, xmm2/mem128 66 0F F9 /r | PSUBD = 0x660FFA, // PSUBD xmm1, xmm2/mem128 66 0F FA /r | PSUBQ = 0x660FFB, // PSUBQ xmm1, xmm2/mem128 66 0F FB /r | | MULSS = 0xF30F59, // MULSS xmm1, xmm2/mem32 F3 0F 59 /r | MULSD = 0xF20F59, // MULSD xmm1, xmm2/mem64 F2 0F 59 /r | MULPS = 0x000F59, // MULPS xmm1, xmm2/mem128 0F 59 /r | MULPD = 0x660F59, // MULPD xmm1, xmm2/mem128 66 0F 59 /r | PMULLW = 0x660FD5, // PMULLW xmm1, xmm2/mem128 66 0F D5 /r | | DIVSS = 0xF30F5E, // DIVSS xmm1, xmm2/mem32 F3 0F 5E /r | DIVSD = 0xF20F5E, // DIVSD xmm1, xmm2/mem64 F2 0F 5E /r | DIVPS = 0x000F5E, // DIVPS xmm1, xmm2mem/128 0F 5E /r | DIVPD = 0x660F5E, // DIVPD xmm1, xmm2/mem128 66 0F 5E /r | | PAND = 0x660FDB, // PAND xmm1, xmm2/mem128 66 0F DB /r | POR = 0x660FEB, // POR xmm1, xmm2/mem128 66 0F EB /r | | UCOMISS = 0x000F2E, // UCOMISS xmm1, xmm2/mem32 0F 2E /r | UCOMISD = 0x660F2E, // UCOMISD xmm1, xmm2/mem64 66 0F 2E /r | | XORPS = 0x000F57, // XORPS xmm1, xmm2/mem128 0F 57 /r | XORPD = 0x660F57, // XORPD xmm1, xmm2/mem128 66 0F 57 /r | | // Use STO and LOD instead of MOV to distinguish the direction | STOSS = 0xF30F11, // MOVSS xmm1/mem32, xmm2 F3 0F 11 /r | STOSD = 0xF20F11, // MOVSD xmm1/mem64, xmm2 F2 0F 11 /r | STOAPS = 0x000F29, // MOVAPS xmm1/mem128, xmm2 0F 29 /r | STOAPD = 0x660F29, // MOVAPD xmm1/mem128, xmm2 66 0F 29 /r | STODQA = 0x660F7F, // MOVDQA xmm1/mem128, xmm2 66 0F 7F /r | STOD = 0x660F7E, // MOVD reg/mem64, xmm 66 0F 7E /r | STOQ = 0x660FD6, // MOVQ xmm1/mem64, xmm2 66 0F D6 / | | LODSS = 0xF30F10, // MOVSS xmm1, xmm2/mem32 F3 0F 10 /r | LODSD = 0xF20F10, // MOVSD xmm1, xmm2/mem64 F2 0F 10 /r | LODAPS = 0x000F28, // MOVAPS xmm1, xmm2/mem128 0F 28 /r | LODAPD = 0x660F28, // MOVAPD xmm1, xmm2/mem128 66 0F 28 /r | LODDQA = 0x660F6F, // MOVDQA xmm1, xmm2/mem128 66 0F 6F /r | LODD = 0x660F6E, // MOVD xmm, reg/mem64 66 0F 6E /r | LODQ = 0xF30F7E, // MOVQ xmm1, xmm2/mem64 F3 0F 7E /r | | LODDQU = 0xF30F6F, // MOVDQU xmm1, xmm2/mem128 F3 0F 6F /r | STODQU = 0xF30F7F, // MOVDQU xmm1/mem128, xmm2 F3 0F 7F /r | MOVDQ2Q = 0xF20FD6, // MOVDQ2Q mmx, xmm F2 0F D6 /r | MOVHLPS = 0x0F12, // MOVHLPS xmm1, xmm2 0F 12 /r | LODHPD = 0x660F16, // MOVHPD xmm, mem64 66 0F 16 /r | STOHPD = 0x660F17, // MOVHPD mem64, xmm 66 0F 17 /r | LODHPS = 0x0F16, // MOVHPS xmm, mem64 0F 16 /r | STOHPS = 0x0F17, // MOVHPS mem64, xmm 0F 17 /r | MOVLHPS = 0x0F16, // MOVLHPS xmm1, xmm2 0F 16 /r | LODLPD = 0x660F12, // MOVLPD xmm, mem64 66 0F 12 /r | STOLPD = 0x660F13, // MOVLPD mem64, xmm 66 0F 13 /r | LODLPS = 0x0F12, // MOVLPS xmm, mem64 0F 12 /r | STOLPS = 0x0F13, // MOVLPS mem64, xmm 0F 13 /r | MOVMSKPD = 0x660F50, // MOVMSKPD reg32, xmm 66 0F 50 /r | MOVMSKPS = 0x0F50, // MOVMSKPS reg32, xmm 0F 50 /r | MOVNTDQ = 0x660FE7, // MOVNTDQ mem128, xmm 66 0F E7 /r | MOVNTI = 0x0FC3, // MOVNTI m32,r32 0F C3 /r | // MOVNTI m64,r64 0F C3 /r | MOVNTPD = 0x660F2B, // MOVNTPD mem128, xmm 66 0F 2B /r | MOVNTPS = 0x0F2B, // MOVNTPS mem128, xmm 0F 2B /r | MOVNTQ = 0x0FE7, // MOVNTQ m64, mmx 0F E7 /r | MOVQ2DQ = 0xF30FD6, // MOVQ2DQ xmm, mmx F3 0F D6 /r | LODUPD = 0x660F10, // MOVUPD xmm1, xmm2/mem128 66 0F 10 /r | STOUPD = 0x660F11, // MOVUPD xmm1/mem128, xmm2 66 0F 11 /r | LODUPS = 0x0F10, // MOVUPS xmm1, xmm2/mem128 0F 10 /r | STOUPS = 0x0F11, // MOVUPS xmm1/mem128, xmm2 0F 11 /r | | PACKSSDW = 0x660F6B, // PACKSSDW xmm1, xmm2/mem128 66 0F 6B /r | PACKSSWB = 0x660F63, // PACKSSWB xmm1, xmm2/mem128 66 0F 63 /r | PACKUSWB = 0x660F67, // PACKUSWB xmm1, xmm2/mem128 66 0F 67 /r | PADDSB = 0x660FEC, // PADDSB xmm1, xmm2/mem128 66 0F EC /r | PADDSW = 0x660FED, // PADDSW xmm1, xmm2/mem128 66 0F ED /r | PADDUSB = 0x660FDC, // PADDUSB xmm1, xmm2/mem128 66 0F DC /r | PADDUSW = 0x660FDD, // PADDUSW xmm1, xmm2/mem128 66 0F DD /r | PANDN = 0x660FDF, // PANDN xmm1, xmm2/mem128 66 0F DF /r | PCMPEQB = 0x660F74, // PCMPEQB xmm1, xmm2/mem128 66 0F 74 /r | PCMPEQD = 0x660F76, // PCMPEQD xmm1, xmm2/mem128 66 0F 76 /r | PCMPEQW = 0x660F75, // PCMPEQW xmm1, xmm2/mem128 66 0F 75 /r | PCMPGTB = 0x660F64, // PCMPGTB xmm1, xmm2/mem128 66 0F 64 /r | PCMPGTD = 0x660F66, // PCMPGTD xmm1, xmm2/mem128 66 0F 66 /r | PCMPGTW = 0x660F65, // PCMPGTW xmm1, xmm2/mem128 66 0F 65 /r | PMADDWD = 0x660FF5, // PMADDWD xmm1, xmm2/mem128 66 0F F5 /r | PSLLW = 0x660FF1, // PSLLW xmm1, xmm2/mem128 66 0F F1 /r | // PSLLW xmm, imm8 66 0F 71 /6 ib | PSLLD = 0x660FF2, // PSLLD xmm1, xmm2/mem128 66 0F F2 /r | // PSLLD xmm, imm8 66 0F 72 /6 ib | PSLLQ = 0x660FF3, // PSLLQ xmm1, xmm2/mem128 66 0F F3 /r | // PSLLQ xmm, imm8 66 0F 73 /6 ib | PSRAW = 0x660FE1, // PSRAW xmm1, xmm2/mem128 66 0F E1 /r | // PSRAW xmm, imm8 66 0F 71 /4 ib | PSRAD = 0x660FE2, // PSRAD xmm1, xmm2/mem128 66 0F E2 /r | // PSRAD xmm, imm8 66 0F 72 /4 ib | PSRLW = 0x660FD1, // PSRLW xmm1, xmm2/mem128 66 0F D1 /r | // PSRLW xmm, imm8 66 0F 71 /2 ib | PSRLD = 0x660FD2, // PSRLD xmm1, xmm2/mem128 66 0F D2 /r | // PSRLD xmm, imm8 66 0F 72 /2 ib | PSRLQ = 0x660FD3, // PSRLQ xmm1, xmm2/mem128 66 0F D3 /r | // PSRLQ xmm, imm8 66 0F 73 /2 ib | PSUBSB = 0x660FE8, // PSUBSB xmm1, xmm2/mem128 66 0F E8 /r | PSUBSW = 0x660FE9, // PSUBSW xmm1, xmm2/mem128 66 0F E9 /r | PSUBUSB = 0x660FD8, // PSUBUSB xmm1, xmm2/mem128 66 0F D8 /r | PSUBUSW = 0x660FD9, // PSUBUSW xmm1, xmm2/mem128 66 0F D9 /r | PUNPCKHBW = 0x660F68, // PUNPCKHBW xmm1, xmm2/mem128 66 0F 68 /r | PUNPCKHDQ = 0x660F6A, // PUNPCKHDQ xmm1, xmm2/mem128 66 0F 6A /r | PUNPCKHWD = 0x660F69, // PUNPCKHWD xmm1, xmm2/mem128 66 0F 69 /r | PUNPCKLBW = 0x660F60, // PUNPCKLBW xmm1, xmm2/mem128 66 0F 60 /r | PUNPCKLDQ = 0x660F62, // PUNPCKLDQ xmm1, xmm2/mem128 66 0F 62 /r | PUNPCKLWD = 0x660F61, // PUNPCKLWD xmm1, xmm2/mem128 66 0F 61 /r | PXOR = 0x660FEF, // PXOR xmm1, xmm2/mem128 66 0F EF /r | ANDPD = 0x660F54, // ANDPD xmm1, xmm2/mem128 66 0F 54 /r | ANDPS = 0x0F54, // ANDPS xmm1, xmm2/mem128 0F 54 /r | ANDNPD = 0x660F55, // ANDNPD xmm1, xmm2/mem128 66 0F 55 /r | ANDNPS = 0x0F55, // ANDNPS xmm1, xmm2/mem128 0F 55 /r | CMPPS = 0x0FC2, // CMPPS xmm1, xmm2/mem128, imm8 0F C2 /r ib | CMPPD = 0x660FC2, // CMPPD xmm1, xmm2/mem128, imm8 66 0F C2 /r ib | CMPSD = 0xF20FC2, // CMPSD xmm1, xmm2/mem64, imm8 F2 0F C2 /r ib | CMPSS = 0xF30FC2, // CMPSS xmm1, xmm2/mem32, imm8 F3 0F C2 /r ib | COMISD = 0x660F2F, // COMISD xmm1, xmm2/mem64 66 0F 2F /r | COMISS = 0x0F2F, // COMISS xmm1, xmm2/mem32 0F 2F /r | CVTDQ2PD = 0xF30FE6, // CVTDQ2PD xmm1, xmm2/mem64 F3 0F E6 /r | CVTDQ2PS = 0x0F5B, // CVTDQ2PS xmm1, xmm2/mem128 0F 5B /r | CVTPD2DQ = 0xF20FE6, // CVTPD2DQ xmm1, xmm2/mem128 F2 0F E6 /r | CVTPD2PI = 0x660F2D, // CVTPD2PI mmx, xmm2/mem128 66 0F 2D /r | CVTPD2PS = 0x660F5A, // CVTPD2PS xmm1, xmm2/mem128 66 0F 5A /r | CVTPI2PD = 0x660F2A, // CVTPI2PD xmm, mmx/mem64 66 0F 2A /r | CVTPI2PS = 0x0F2A, // CVTPI2PS xmm, mmx/mem64 0F 2A /r | CVTPS2DQ = 0x660F5B, // CVTPS2DQ xmm1, xmm2/mem128 66 0F 5B /r | CVTPS2PD = 0x0F5A, // CVTPS2PD xmm1, xmm2/mem64 0F 5A /r | CVTPS2PI = 0x0F2D, // CVTPS2PI mmx, xmm/mem64 0F 2D /r | CVTSD2SI = 0xF20F2D, // CVTSD2SI reg32, xmm/mem64 F2 0F 2D /r | // CVTSD2SI reg64, xmm/mem64 F2 0F 2D /r | CVTSD2SS = 0xF20F5A, // CVTSD2SS xmm1, xmm2/mem64 F2 0F 5A /r | CVTSI2SD = 0xF20F2A, // CVTSI2SD xmm, reg/mem32 F2 0F 2A /r | // CVTSI2SD xmm, reg/mem64 F2 0F 2A /r | CVTSI2SS = 0xF30F2A, // CVTSI2SS xmm, reg/mem32 F3 0F 2A /r | // CVTSI2SS xmm, reg/mem64 F3 0F 2A /r | CVTSS2SD = 0xF30F5A, // CVTSS2SD xmm1, xmm2/mem32 F3 0F 5A /r | CVTSS2SI = 0xF30F2D, // CVTSS2SI reg32, xmm2/mem32 F3 0F 2D /r | // CVTSS2SI reg64, xmm2/mem32 F3 0F 2D /r | CVTTPD2PI = 0x660F2C, // CVTPD2PI mmx, xmm/mem128 66 0F 2C /r | CVTTPD2DQ = 0x660FE6, // CVTTPD2DQ xmm1, xmm2/mem128 66 0F E6 /r | CVTTPS2DQ = 0xF30F5B, // CVTTPS2DQ xmm1, xmm2/mem128 F3 0F 5B /r | CVTTPS2PI = 0x0F2C, // CVTTPS2PI mmx xmm/mem64 0F 2C /r | CVTTSD2SI = 0xF20F2C, // CVTTSD2SI reg32, xmm/mem64 F2 0F 2C /r | // CVTTSD2SI reg64, xmm/mem64 F2 0F 2C /r | CVTTSS2SI = 0xF30F2C, // CVTTSS2SI reg32, xmm/mem32 F3 0F 2C /r | // CVTTSS2SI reg64, xmm/mem32 F3 0F 2C /r | MASKMOVDQU = 0x660FF7, // MASKMOVDQU xmm1, xmm2 66 0F F7 /r | MASKMOVQ = 0x0FF7, // MASKMOVQ mm1,mm2 0F F7 /r | MAXPD = 0x660F5F, // MAXPD xmm1, xmm2/mem128 66 0F 5F /r | MAXPS = 0x0F5F, // MAXPS xmm1, xmm2/mem128 0F 5F /r | MAXSD = 0xF20F5F, // MAXSD xmm1, xmm2/mem64 F2 0F 5F /r | MAXSS = 0xF30F5F, // MAXSS xmm1, xmm2/mem32 F3 0F 5F /r | MINPD = 0x660F5D, // MINPD xmm1, xmm2/mem128 66 0F 5D /r | MINPS = 0x0F5D, // MINPS xmm1, xmm2/mem128 0F 5D /r | MINSD = 0xF20F5D, // MINSD xmm1, xmm2/mem64 F2 0F 5D /r | MINSS = 0xF30F5D, // MINSS xmm1, xmm2/mem32 F3 0F 5D /r | ORPD = 0x660F56, // ORPD xmm1, xmm2/mem128 66 0F 56 /r | ORPS = 0x0F56, // ORPS xmm1, xmm2/mem128 0F 56 /r | PAVGB = 0x660FE0, // PAVGB xmm1, xmm2/mem128 66 0F E0 /r | PAVGW = 0x660FE3, // PAVGW xmm1, xmm2/mem128 66 0F E3 /r | PMAXSW = 0x660FEE, // PMAXSW xmm1, xmm2/mem128 66 0F EE / | PINSRW = 0x660FC4, // PINSRW xmm, reg32/mem16, imm8 66 0F C4 /r ib | PMAXUB = 0x660FDE, // PMAXUB xmm1, xmm2/mem128 66 0F DE /r | PMINSW = 0x660FEA, // PMINSW xmm1, xmm2/mem128 66 0F EA /r | PMINUB = 0x660FDA, // PMINUB xmm1, xmm2/mem128 66 0F DA /r | PMOVMSKB = 0x660FD7, // PMOVMSKB reg32, xmm 66 0F D7 /r | PMULHUW = 0x660FE4, // PMULHUW xmm1, xmm2/mem128 66 0F E4 /r | PMULHW = 0x660FE5, // PMULHW xmm1, xmm2/mem128 66 0F E5 / | PMULUDQ = 0x660FF4, // PMULUDQ xmm1, xmm2/mem128 66 0F F4 /r | PSADBW = 0x660FF6, // PSADBW xmm1, xmm2/mem128 66 0F F6 /r | PUNPCKHQDQ = 0x660F6D, // PUNPCKHQDQ xmm1, xmm2/mem128 66 0F 6D /r | PUNPCKLQDQ = 0x660F6C, // PUNPCKLQDQ xmm1, xmm2/mem128 66 0F 6C /r | RCPPS = 0x0F53, // RCPPS xmm1, xmm2/mem128 0F 53 /r | RCPSS = 0xF30F53, // RCPSS xmm1, xmm2/mem32 F3 0F 53 /r | RSQRTPS = 0x0F52, // RSQRTPS xmm1, xmm2/mem128 0F 52 /r | RSQRTSS = 0xF30F52, // RSQRTSS xmm1, xmm2/mem32 F3 0F 52 /r | SQRTPD = 0x660F51, // SQRTPD xmm1, xmm2/mem128 66 0F 51 /r | SHUFPD = 0x660FC6, // SHUFPD xmm1, xmm2/mem128, imm8 66 0F C6 /r ib | SHUFPS = 0x0FC6, // SHUFPS xmm1, xmm2/mem128, imm8 0F C6 /r ib | SQRTPS = 0x0F51, // SQRTPS xmm1, xmm2/mem128 0F 51 /r | SQRTSD = 0xF20F51, // SQRTSD xmm1, xmm2/mem64 F2 0F 51 /r | SQRTSS = 0xF30F51, // SQRTSS xmm1, xmm2/mem32 F3 0F 51 /r | UNPCKHPD = 0x660F15, // UNPCKHPD xmm1, xmm2/mem12866 0F 15 /r | UNPCKHPS = 0x0F15, // UNPCKHPS xmm1, xmm2/mem1280F 15 /r | UNPCKLPD = 0x660F14, // UNPCKLPD xmm1, xmm2/mem128 66 0F 14 /r | UNPCKLPS = 0x0F14, // UNPCKLPS xmm1, xmm2/mem1280F 14 /r | | PSHUFD = 0x660F70, // PSHUFD xmm1, xmm2/mem128, imm8 66 0F 70 /r ib | PSHUFHW = 0xF30F70, // PSHUFHW xmm1, xmm2/mem128, imm8 F3 0F 70 /r ib | PSHUFLW = 0xF20F70, // PSHUFLW xmm1, xmm2/mem128, imm8 F2 0F 70 /r ib | PSHUFW = 0x0F70, // PSHUFW mm1, mm2/mem64, imm8 0F 70 /r ib | PSLLDQ = 0x07660F73, // PSLLDQ xmm, imm8 66 0F 73 /7 ib | PSRLDQ = 0x03660F73, // PSRLDQ xmm, imm8 66 0F 73 /3 ib | | PREFETCH = 0x0F18, | | PEXTRW = 0x660FC5, // PEXTRW reg32, xmm, imm8 66 0F C5 /r ib | STMXCSR = 0x0FAE, // STMXCSR mem32 0F AE /3 | |// SSE3 Pentium 4 (Prescott) | | ADDSUBPD = 0x660FD0, // ADDSUBPD xmm1, xmm2/m128 | ADDSUBPS = 0xF20FD0, | HADDPD = 0x660F7C, | HADDPS = 0xF20F7C, | HSUBPD = 0x660F7D, | HSUBPS = 0xF20F7D, | MOVDDUP = 0xF20F12, | MOVSHDUP = 0xF30F16, | MOVSLDUP = 0xF30F12, | LDDQU = 0xF20FF0, | MONITOR = 0x0F01C8, | MWAIT = 0x0F01C9, | |// SSSE3 | PALIGNR = 0x660F3A0F, | PHADDD = 0x660F3802, | PHADDW = 0x660F3801, | PHADDSW = 0x660F3803, | PABSB = 0x660F381C, | PABSD = 0x660F381E, | PABSW = 0x660F381D, | PSIGNB = 0x660F3808, | PSIGND = 0x660F380A, | PSIGNW = 0x660F3809, | PSHUFB = 0x660F3800, | PMADDUBSW = 0x660F3804, | PMULHRSW = 0x660F380B, | PHSUBD = 0x660F3806, | PHSUBW = 0x660F3805, | PHSUBSW = 0x660F3807, | |// SSE4.1 |// See Intel SSE4 Programming Reference | | BLENDPD = 0x660F3A0D, // 66 0F 3A 0D /r ib BLENDPD xmm1, xmm2/m128, imm8 | BLENDPS = 0x660F3A0C, // 66 0F 3A 0C /r ib BLENDPS xmm1, xmm2/m128, imm8 | BLENDVPD = 0x660F3815, // 66 0F 38 15 /r BLENDVPD xmm1, xmm2/m128, | BLENDVPS = 0x660F3814, // 66 0F 38 14 /r BLENDVPS xmm1, xmm2/m128, | DPPD = 0x660F3A41, | DPPS = 0x660F3A40, | EXTRACTPS = 0x660F3A17, | INSERTPS = 0x660F3A21, | MPSADBW = 0x660F3A42, | PBLENDVB = 0x660F3810, | PBLENDW = 0x660F3A0E, | PEXTRD = 0x660F3A16, | PEXTRQ = 0x660F3A16, | PINSRB = 0x660F3A20, // 66 0F 3A 20 /r ib PINSRB xmm1, r32/m8, imm8 | PINSRD = 0x660F3A22, | PINSRQ = 0x660F3A22, | | MOVNTDQA = 0x660F382A, | PACKUSDW = 0x660F382B, | PCMPEQQ = 0x660F3829, | PEXTRB = 0x660F3A14, // 66 0F 3A 14 /r ib PEXTRB r32/m8, xmm2, imm8 | // 66 REX.W 0F 3A 14 /r ib PEXTRB r64/m8, xmm2, imm8 | PHMINPOSUW = 0x660F3841, // 66 0F 38 41 /r PHMINPOSUW xmm1, xmm2/m128 | PMAXSB = 0x660F383C, | PMAXSD = 0x660F383D, | PMAXUD = 0x660F383F, | PMAXUW = 0x660F383E, | PMINSB = 0x660F3838, | PMINSD = 0x660F3839, | PMINUD = 0x660F383B, | PMINUW = 0x660F383A, | PMOVSXBW = 0x660F3820, | PMOVSXBD = 0x660F3821, | PMOVSXBQ = 0x660F3822, | PMOVSXWD = 0x660F3823, | PMOVSXWQ = 0x660F3824, | PMOVSXDQ = 0x660F3825, | PMOVZXBW = 0x660F3830, | PMOVZXBD = 0x660F3831, | PMOVZXBQ = 0x660F3832, | PMOVZXWD = 0x660F3833, | PMOVZXWQ = 0x660F3834, | PMOVZXDQ = 0x660F3835, | PMULDQ = 0x660F3828, | PMULLD = 0x660F3840, | PTEST = 0x660F3817, // 66 0F 38 17 /r PTEST xmm1, xmm2/m128 | | ROUNDPD = 0x660F3A09, // 66 0F 3A 09 /r ib ROUNDPD xmm1, xmm2/m128, imm8 | ROUNDPS = 0x660F3A08, | ROUNDSD = 0x660F3A0B, | ROUNDSS = 0x660F3A0A, | |// SSE4.2 | PCMPESTRI = 0x660F3A61, | PCMPESTRM = 0x660F3A60, | PCMPISTRI = 0x660F3A63, | PCMPISTRM = 0x660F3A62, | PCMPGTQ = 0x660F3837, | // CRC32 | |// SSE4a (AMD only) | // EXTRQ,INSERTQ,MOVNTSD,MOVNTSS | |// POPCNT and LZCNT (have their own CPUID bits) | POPCNT = 0xF30FB8, | // LZCNT | |// AVX | XGETBV = 0x0F01D0, | XSETBV = 0x0F01D1, | VBROADCASTSS = 0x660F3818, | VBROADCASTSD = 0x660F3819, | VBROADCASTF128 = 0x660F381A, | VINSERTF128 = 0x660F3A18, | |// AVX2 | VPBROADCASTB = 0x660F3878, | VPBROADCASTW = 0x660F3879, | VPBROADCASTD = 0x660F3858, | VPBROADCASTQ = 0x660F3859, | VBROADCASTI128 = 0x660F385A, | VINSERTI128 = 0x660F3A38, | |// AES | AESENC = 0x660F38DC, | AESENCLAST = 0x660F38DD, | AESDEC = 0x660F38DE, | AESDECLAST = 0x660F38DF, | AESIMC = 0x660F38DB, | AESKEYGENASSIST = 0x660F3ADF, |} src/dmd/backend/xmm.d has no code <<<<<< EOF # path=./src-dmd-backend-dvarstats.lst |/** | * Compiler implementation of the | * $(LINK2 http://www.dlang.org, D programming language). | * | * Copyright: Copyright (C) 2015-2020 by The D Language Foundation, All Rights Reserved | * Authors: Rainer Schuetze | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/dvarstats.d, backend/dvarstats.d) | */ | |module dmd.backend.dvarstats; | |/****************************************** | * support for lexical scope of local variables | */ | |import core.stdc.string; |import core.stdc.stdlib; | |import dmd.backend.cc; |import dmd.backend.cdef; |import dmd.backend.global; |import dmd.backend.code; | |extern (C++): | |nothrow: | |alias _compare_fp_t = extern(C) nothrow int function(const void*, const void*); |extern(C) void qsort(void* base, size_t nmemb, size_t size, _compare_fp_t compar); | |version (all) // free function version |{ | import dmd.backend.dvarstats; | | void varStats_writeSymbolTable(symtab_t* symtab, | void function(Symbol*) nothrow fnWriteVar, void function() nothrow fnEndArgs, | void function(int off,int len) nothrow fnBeginBlock, void function() nothrow fnEndBlock) | { 0000000| varStats.writeSymbolTable(symtab, fnWriteVar, fnEndArgs, fnBeginBlock, fnEndBlock); | } | | void varStats_startFunction() | { 0000000| varStats.startFunction(); | } | | void varStats_recordLineOffset(Srcpos src, targ_size_t off) | { 0000000| varStats.recordLineOffset(src, off); | } | | __gshared VarStatistics varStats; |} | | |// estimate of variable life time |struct LifeTime |{ | Symbol* sym; | int offCreate; // variable created before this code offset | int offDestroy; // variable destroyed after this code offset |} | |struct LineOffset |{ | targ_size_t offset; | uint linnum; | uint diffNextOffset; |} | |struct VarStatistics |{ |private: |nothrow: | LifeTime[] lifeTimes; | int cntUsedLifeTimes; | | // symbol table sorted by offset of variable creation | symtab_t sortedSymtab; | SYMIDX* nextSym; // next symbol with identifier with same hash, same size as sortedSymtab | int uniquecnt; // number of variables that have unique name and don't need lexical scope | | // line number records for the current function | LineOffset[] lineOffsets; | int cntUsedLineOffsets; | const(char)* srcfile; // only one file supported, no inline | |public void startFunction() |{ 0000000| cntUsedLineOffsets = 0; 0000000| srcfile = null; |} | |// figure if can we can add a lexical scope for the variable |// (this should exclude variables from inlined functions as there is |// no support for gathering stats from different files) |private bool isLexicalScopeVar(Symbol* sa) |{ 0000000| if (sa.lnoscopestart <= 0 || sa.lnoscopestart > sa.lnoscopeend) 0000000| return false; | | // is it inside the function? Unfortunately we cannot verify the source file in case of inlining 0000000| if (sa.lnoscopestart < funcsym_p.Sfunc.Fstartline.Slinnum) 0000000| return false; 0000000| if (sa.lnoscopeend > funcsym_p.Sfunc.Fendline.Slinnum) 0000000| return false; | 0000000| return true; |} | |// compare function to sort symbols by line offsets of their creation |private extern (C) static int cmpLifeTime(scope const void* p1, scope const void* p2) |{ 0000000| const LifeTime* lt1 = cast(const(LifeTime)*)p1; 0000000| const LifeTime* lt2 = cast(const(LifeTime)*)p2; | 0000000| return lt1.offCreate - lt2.offCreate; |} | |// a parent scope contains the creation offset of the child scope |private static extern(D) SYMIDX isParentScope(LifeTime[] lifetimes, SYMIDX parent, SYMIDX si) |{ 0000000| if(parent < 0) // full function 0000000| return true; 0000000| return lifetimes[parent].offCreate <= lifetimes[si].offCreate && 0000000| lifetimes[parent].offDestroy > lifetimes[si].offCreate; |} | |// find a symbol that includes the creation of the given symbol as part of its life time |private static extern(D) SYMIDX findParentScope(LifeTime[] lifetimes, SYMIDX si) |{ 0000000| for(SYMIDX sj = si - 1; sj >= 0; --sj) 0000000| if(isParentScope(lifetimes, sj, si)) 0000000| return sj; 0000000| return -1; |} | |private static int getHash(const(char)* s) |{ 0000000| int hash = 0; 0000000| for (; *s; s++) 0000000| hash = hash * 11 + *s; 0000000| return hash; |} | |private bool hashSymbolIdentifiers(symtab_t* symtab) |{ | // build circular-linked lists of symbols with same identifier hash 0000000| bool hashCollisions = false; 0000000| SYMIDX[256] firstSym = void; 0000000| memset(firstSym.ptr, -1, (firstSym).sizeof); 0000000| for (SYMIDX si = 0; si < symtab.top; si++) | { 0000000| Symbol* sa = symtab.tab[si]; 0000000| int hash = getHash(sa.Sident.ptr) & 255; 0000000| SYMIDX first = firstSym[hash]; 0000000| if (first == -1) | { | // connect full circle, so we don't have to recalculate the hash 0000000| nextSym[si] = si; 0000000| firstSym[hash] = si; | } | else | { | // insert after first entry 0000000| nextSym[si] = nextSym[first]; 0000000| nextSym[first] = si; 0000000| hashCollisions = true; | } | } 0000000| return hashCollisions; |} | |private bool hasUniqueIdentifier(symtab_t* symtab, SYMIDX si) |{ 0000000| Symbol* sa = symtab.tab[si]; 0000000| for (SYMIDX sj = nextSym[si]; sj != si; sj = nextSym[sj]) 0000000| if (strcmp(sa.Sident.ptr, symtab.tab[sj].Sident.ptr) == 0) 0000000| return false; 0000000| return true; |} | |// gather statistics about creation and destructions of variables that are |// used by the current function |private symtab_t* calcLexicalScope(symtab_t* symtab) return |{ | // make a copy of the symbol table | // - arguments should be kept at the very beginning | // - variables with unique name come first (will be emitted with full function scope) | // - variables with duplicate names are added with ascending code offset 0000000| if (sortedSymtab.symmax < symtab.top) | { 0000000| nextSym = cast(int*)util_realloc(nextSym, symtab.top, (*nextSym).sizeof); 0000000| sortedSymtab.tab = cast(Symbol**) util_realloc(sortedSymtab.tab, symtab.top, (Symbol*).sizeof); 0000000| sortedSymtab.symmax = symtab.top; | } | 0000000| if (!hashSymbolIdentifiers(symtab)) | { | // without any collisions, there are no duplicate symbol names, so bail out early 0000000| uniquecnt = symtab.top; 0000000| return symtab; | } | 0000000| SYMIDX argcnt; 0000000| for (argcnt = 0; argcnt < symtab.top; argcnt++) | { 0000000| Symbol* sa = symtab.tab[argcnt]; 0000000| if (sa.Sclass != SCparameter && sa.Sclass != SCregpar && sa.Sclass != SCfastpar && sa.Sclass != SCshadowreg) 0000000| break; 0000000| sortedSymtab.tab[argcnt] = sa; | } | | // find symbols with identical names, only these need lexical scope 0000000| uniquecnt = argcnt; 0000000| SYMIDX dupcnt = 0; 0000000| for (SYMIDX sj, si = argcnt; si < symtab.top; si++) | { 0000000| Symbol* sa = symtab.tab[si]; 0000000| if (!isLexicalScopeVar(sa) || hasUniqueIdentifier(symtab, si)) 0000000| sortedSymtab.tab[uniquecnt++] = sa; | else 0000000| sortedSymtab.tab[symtab.top - 1 - dupcnt++] = sa; // fill from the top | } 0000000| sortedSymtab.top = symtab.top; 0000000| if(dupcnt == 0) 0000000| return symtab; | 0000000| sortLineOffsets(); | | // precalc the lexical blocks to emit so that identically named symbols don't overlap 0000000| if (lifeTimes.length < dupcnt) 0000000| lifeTimes = (cast(LifeTime*) util_realloc(lifeTimes.ptr, dupcnt, (LifeTime).sizeof))[0 .. dupcnt]; | 0000000| for (SYMIDX si = 0; si < dupcnt; si++) | { 0000000| lifeTimes[si].sym = sortedSymtab.tab[uniquecnt + si]; 0000000| lifeTimes[si].offCreate = cast(int)getLineOffset(lifeTimes[si].sym.lnoscopestart); 0000000| lifeTimes[si].offDestroy = cast(int)getLineOffset(lifeTimes[si].sym.lnoscopeend); | } 0000000| cntUsedLifeTimes = dupcnt; 0000000| qsort(lifeTimes.ptr, dupcnt, (lifeTimes[0]).sizeof, &cmpLifeTime); | | // ensure that an inner block does not extend beyond the end of a parent block 0000000| for (SYMIDX si = 0; si < dupcnt; si++) | { 0000000| SYMIDX sj = findParentScope(lifeTimes, si); 0000000| if(sj >= 0 && lifeTimes[si].offDestroy > lifeTimes[sj].offDestroy) 0000000| lifeTimes[si].offDestroy = lifeTimes[sj].offDestroy; | } | | // extend life time to the creation of the next symbol that is not contained in the parent scope | // or that has the same name 0000000| for (SYMIDX sj, si = 0; si < dupcnt; si++) | { 0000000| SYMIDX parent = findParentScope(lifeTimes, si); | 0000000| for (sj = si + 1; sj < dupcnt; sj++) 0000000| if(!isParentScope(lifeTimes, parent, sj)) 0000000| break; 0000000| else if (strcmp(lifeTimes[si].sym.Sident.ptr, lifeTimes[sj].sym.Sident.ptr) == 0) 0000000| break; | 0000000| lifeTimes[si].offDestroy = cast(int)(sj < dupcnt ? lifeTimes[sj].offCreate : retoffset + retsize); // function length | } | | // store duplicate symbols back with new ordering 0000000| for (SYMIDX si = 0; si < dupcnt; si++) 0000000| sortedSymtab.tab[uniquecnt + si] = lifeTimes[si].sym; | 0000000| return &sortedSymtab; |} | |public void writeSymbolTable(symtab_t* symtab, | void function(Symbol*) nothrow fnWriteVar, void function() nothrow fnEndArgs, | void function(int off,int len) nothrow fnBeginBlock, void function() nothrow fnEndBlock) |{ 0000000| symtab = calcLexicalScope(symtab); | 0000000| int openBlocks = 0; 0000000| int lastOffset = 0; | | // Write local symbol table 0000000| bool endarg = false; 0000000| for (SYMIDX si = 0; si < symtab.top; si++) | { 0000000| Symbol *sa = symtab.tab[si]; 0000000| if (endarg == false && 0000000| sa.Sclass != SCparameter && 0000000| sa.Sclass != SCfastpar && 0000000| sa.Sclass != SCregpar && 0000000| sa.Sclass != SCshadowreg) | { 0000000| if(fnEndArgs) 0000000| (*fnEndArgs)(); 0000000| endarg = true; | } 0000000| if (si >= uniquecnt) | { 0000000| int off = lifeTimes[si - uniquecnt].offCreate; | // close scopes that end before the creation of this symbol 0000000| for (SYMIDX sj = si - 1; sj >= uniquecnt; --sj) | { 0000000| if (lastOffset < lifeTimes[sj - uniquecnt].offDestroy && lifeTimes[sj - uniquecnt].offDestroy <= off) | { 0000000| assert(openBlocks > 0); 0000000| if(fnEndBlock) 0000000| (*fnEndBlock)(); 0000000| openBlocks--; | } | } 0000000| int len = lifeTimes[si - uniquecnt].offDestroy - off; | // don't emit a block for length 0, it isn't captured by the close condition above 0000000| if (len > 0) | { 0000000| if(fnBeginBlock) 0000000| (*fnBeginBlock)(off, len); 0000000| openBlocks++; | } 0000000| lastOffset = off; | } 0000000| (*fnWriteVar)(sa); | } | 0000000| while (openBlocks > 0) | { 0000000| if(fnEndBlock) 0000000| (*fnEndBlock)(); 0000000| openBlocks--; | } |} | |// compare function to sort line offsets ascending by line (and offset on identical line) |private extern (C) static int cmpLineOffsets(scope const void* off1, scope const void* off2) |{ 0000000| const LineOffset* loff1 = cast(const(LineOffset)*)off1; 0000000| const LineOffset* loff2 = cast(const(LineOffset)*)off2; | 0000000| if (loff1.linnum == loff2.linnum) 0000000| return cast(int)(loff1.offset - loff2.offset); 0000000| return loff1.linnum - loff2.linnum; |} | |private void sortLineOffsets() |{ 0000000| if (cntUsedLineOffsets == 0) 0000000| return; | | // remember the offset to the next recorded offset on another line 0000000| for (int i = 1; i < cntUsedLineOffsets; i++) 0000000| lineOffsets[i-1].diffNextOffset = cast(uint)(lineOffsets[i].offset - lineOffsets[i-1].offset); 0000000| lineOffsets[cntUsedLineOffsets - 1].diffNextOffset = cast(uint)(retoffset + retsize - lineOffsets[cntUsedLineOffsets - 1].offset); | | // sort line records and remove duplicate lines preferring smaller offsets 0000000| qsort(lineOffsets.ptr, cntUsedLineOffsets, (lineOffsets[0]).sizeof, &cmpLineOffsets); 0000000| int j = 0; 0000000| for (int i = 1; i < cntUsedLineOffsets; i++) 0000000| if (lineOffsets[i].linnum > lineOffsets[j].linnum) 0000000| lineOffsets[++j] = lineOffsets[i]; 0000000| cntUsedLineOffsets = j + 1; |} | |private targ_size_t getLineOffset(int linnum) |{ 0000000| int idx = findLineIndex(linnum); 0000000| if (idx >= cntUsedLineOffsets || lineOffsets[idx].linnum < linnum) 0000000| return retoffset + retsize; // function length 0000000| if (idx > 0 && lineOffsets[idx].linnum != linnum) | // for inexact line numbers, use the offset following the previous line 0000000| return lineOffsets[idx-1].offset + lineOffsets[idx-1].diffNextOffset; 0000000| return lineOffsets[idx].offset; |} | |// return the first record index in the lineOffsets array with linnum >= line |private int findLineIndex(uint line) |{ 0000000| int low = 0; 0000000| int high = cntUsedLineOffsets; 0000000| while (low < high) | { 0000000| int mid = (low + high) >> 1; 0000000| int ln = lineOffsets[mid].linnum; 0000000| if (line < ln) 0000000| high = mid; 0000000| else if (line > ln) 0000000| low = mid + 1; | else 0000000| return mid; | } 0000000| return low; |} | |public void recordLineOffset(Srcpos src, targ_size_t off) |{ | version (MARS) 0000000| const sfilename = src.Sfilename; | else | const sfilename = srcpos_name(src); | | // only record line numbers from one file, symbol info does not include source file 0000000| if (!sfilename || !src.Slinnum) 0000000| return; 0000000| if (!srcfile) 0000000| srcfile = sfilename; 0000000| if (srcfile != sfilename && strcmp(srcfile, sfilename) != 0) 0000000| return; | | // assume ascending code offsets generated during codegen, ignore any other | // (e.g. there is an additional line number emitted at the end of the function | // or multiple line numbers at the same offset) 0000000| if (cntUsedLineOffsets > 0 && lineOffsets[cntUsedLineOffsets-1].offset >= off) 0000000| return; | 0000000| if (cntUsedLineOffsets > 0 && lineOffsets[cntUsedLineOffsets-1].linnum == src.Slinnum) | { | // optimize common case: new offset on same line 0000000| return; | } | // don't care for lineOffsets being ordered now, that is taken care of later (calcLexicalScope) 0000000| if (lineOffsets.length <= cntUsedLineOffsets) | { 0000000| const newSize = 2 * cntUsedLineOffsets + 16; 0000000| lineOffsets = (cast(LineOffset*) util_realloc(lineOffsets.ptr, newSize, (lineOffsets[0]).sizeof))[0 .. newSize]; | } 0000000| lineOffsets[cntUsedLineOffsets].linnum = src.Slinnum; 0000000| lineOffsets[cntUsedLineOffsets].offset = off; 0000000| cntUsedLineOffsets++; |} | |} src/dmd/backend/dvarstats.d is 0% covered <<<<<< EOF # path=./src-dmd-lexer.lst |/** | * Implements the lexical analyzer, which converts source code into lexical tokens. | * | * Specification: $(LINK2 https://dlang.org/spec/lex.html, Lexical) | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d, _lexer.d) | * Documentation: https://dlang.org/phobos/dmd_lexer.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/lexer.d | */ | |module dmd.lexer; | |import core.stdc.ctype; |import core.stdc.errno; |import core.stdc.stdarg; |import core.stdc.stdio; |import core.stdc.stdlib : getenv; |import core.stdc.string; |import core.stdc.time; | |import dmd.entity; |import dmd.errors; |import dmd.globals; |import dmd.id; |import dmd.identifier; |import dmd.root.ctfloat; |import dmd.root.outbuffer; |import dmd.root.port; |import dmd.root.rmem; |import dmd.root.string; |import dmd.tokens; |import dmd.utf; |import dmd.utils; | |nothrow: | |private enum LS = 0x2028; // UTF line separator |private enum PS = 0x2029; // UTF paragraph separator | |/******************************************** | * Do our own char maps | */ |private static immutable cmtable = () { | ubyte[256] table; | foreach (const c; 0 .. table.length) | { | if ('0' <= c && c <= '7') | table[c] |= CMoctal; | if (c_isxdigit(c)) | table[c] |= CMhex; | if (c_isalnum(c) || c == '_') | table[c] |= CMidchar; | | switch (c) | { | case 'x': case 'X': | case 'b': case 'B': | table[c] |= CMzerosecond; | break; | | case '0': .. case '9': | case 'e': case 'E': | case 'f': case 'F': | case 'l': case 'L': | case 'p': case 'P': | case 'u': case 'U': | case 'i': | case '.': | case '_': | table[c] |= CMzerosecond | CMdigitsecond; | break; | | default: | break; | } | | switch (c) | { | case '\\': | case '\n': | case '\r': | case 0: | case 0x1A: | case '\'': | break; | default: | if (!(c & 0x80)) | table[c] |= CMsinglechar; | break; | } | } | return table; |}(); | |private |{ | enum CMoctal = 0x1; | enum CMhex = 0x2; | enum CMidchar = 0x4; | enum CMzerosecond = 0x8; | enum CMdigitsecond = 0x10; | enum CMsinglechar = 0x20; |} | |private bool isoctal(const char c) pure @nogc @safe |{ 20168| return (cmtable[c] & CMoctal) != 0; |} | |private bool ishex(const char c) pure @nogc @safe |{ 507766| return (cmtable[c] & CMhex) != 0; |} | |private bool isidchar(const char c) pure @nogc @safe |{ 625988677| return (cmtable[c] & CMidchar) != 0; |} | |private bool isZeroSecond(const char c) pure @nogc @safe |{ 7189698| return (cmtable[c] & CMzerosecond) != 0; |} | |private bool isDigitSecond(const char c) pure @nogc @safe |{ 8288399| return (cmtable[c] & CMdigitsecond) != 0; |} | |private bool issinglechar(const char c) pure @nogc @safe |{ 367138| return (cmtable[c] & CMsinglechar) != 0; |} | |private bool c_isxdigit(const int c) pure @nogc @safe |{ 000000000| return (( c >= '0' && c <= '9') || 000000000| ( c >= 'a' && c <= 'f') || 000000000| ( c >= 'A' && c <= 'F')); |} | |private bool c_isalnum(const int c) pure @nogc @safe |{ 000000000| return (( c >= '0' && c <= '9') || 000000000| ( c >= 'a' && c <= 'z') || 000000000| ( c >= 'A' && c <= 'Z')); |} | |unittest |{ | //printf("lexer.unittest\n"); | /* Not much here, just trying things out. | */ | string text = "int"; // We rely on the implicit null-terminator | scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0); | TOK tok; | tok = lex1.nextToken(); | //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); | assert(tok == TOK.int32); | tok = lex1.nextToken(); | assert(tok == TOK.endOfFile); | tok = lex1.nextToken(); | assert(tok == TOK.endOfFile); | tok = lex1.nextToken(); | assert(tok == TOK.endOfFile); |} | |unittest |{ | // We don't want to see Lexer error output during these tests. | uint errors = global.startGagging(); | scope(exit) global.endGagging(errors); | | // Test malformed input: even malformed input should end in a TOK.endOfFile. | static immutable char[][] testcases = | [ // Testcase must end with 0 or 0x1A. | [0], // not malformed, but pathological | ['\'', 0], | ['\'', 0x1A], | ['{', '{', 'q', '{', 0], | [0xFF, 0], | [0xFF, 0x80, 0], | [0xFF, 0xFF, 0], | [0xFF, 0xFF, 0], | ['x', '"', 0x1A], | ]; | | foreach (testcase; testcases) | { | scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0); | TOK tok = lex2.nextToken(); | size_t iterations = 1; | while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) | { | tok = lex2.nextToken(); | } | assert(tok == TOK.endOfFile); | tok = lex2.nextToken(); | assert(tok == TOK.endOfFile); | } |} | |/*********************************************************** | */ |class Lexer |{ | private __gshared OutBuffer stringbuffer; | | Loc scanloc; // for error messages | Loc prevloc; // location of token before current | | const(char)* p; // current character | | Token token; | | private | { | const(char)* base; // pointer to start of buffer | const(char)* end; // pointer to last element of buffer | const(char)* line; // start of current line | | bool doDocComment; // collect doc comment information | bool anyToken; // seen at least one token | bool commentToken; // comments are TOK.comment's | int inTokenStringConstant; // can be larger than 1 when in nested q{} strings | int lastDocLine; // last line of previous doc comment | | Token* tokenFreelist; | } | | nothrow: | | /********************* | * Creates a Lexer for the source code base[begoffset..endoffset+1]. | * The last character, base[endoffset], must be null (0) or EOF (0x1A). | * | * Params: | * filename = used for error messages | * base = source code, must be terminated by a null (0) or EOF (0x1A) character | * begoffset = starting offset into base[] | * endoffset = the last offset to read into base[] | * doDocComment = handle documentation comments | * commentToken = comments become TOK.comment's | */ 111816| this(const(char)* filename, const(char)* base, size_t begoffset, | size_t endoffset, bool doDocComment, bool commentToken) pure | { 111816| scanloc = Loc(filename, 1, 1); | //printf("Lexer::Lexer(%p,%d)\n",base,length); | //printf("lexer.filename = %s\n", filename); 111816| token = Token.init; 111816| this.base = base; 111816| this.end = base + endoffset; 111816| p = base + begoffset; 111816| line = p; 111816| this.doDocComment = doDocComment; 111816| this.commentToken = commentToken; 111816| this.inTokenStringConstant = 0; 111816| this.lastDocLine = 0; | //initKeywords(); | /* If first line starts with '#!', ignore the line | */ 223642| if (p && p[0] == '#' && p[1] == '!') | { 9| p += 2; 152| while (1) | { 152| char c = *p++; 152| switch (c) | { 000000000| case 0: 000000000| case 0x1A: 000000000| p--; 000000000| goto case; 9| case '\n': 9| break; 143| default: 143| continue; | } 9| break; | } 9| endOfLine(); | } | } | | /// Returns: a newly allocated `Token`. | Token* allocateToken() pure nothrow @safe | { 73946815| if (tokenFreelist) | { 68411802| Token* t = tokenFreelist; 68411802| tokenFreelist = t.next; 68411802| t.next = null; 68411802| return t; | } 5535013| return new Token(); | } | | /// Frees the given token by returning it to the freelist. | private void releaseToken(Token* token) pure nothrow @nogc @safe | { 71890000| if (mem.isGCEnabled) 1014125| *token = Token.init; 71890000| token.next = tokenFreelist; 71890000| tokenFreelist = token; | } | | final TOK nextToken() | { 294677914| prevloc = token.loc; 294677914| if (token.next) | { 71890000| Token* t = token.next; 71890000| memcpy(&token, t, Token.sizeof); 71890000| releaseToken(t); | } | else | { 222787914| scan(&token); | } | //printf(token.toChars()); 294677914| return token.value; | } | | /*********************** | * Look ahead at next token's value. | */ | final TOK peekNext() | { 55582944| return peek(&token).value; | } | | /*********************** | * Look 2 tokens ahead at value. | */ | final TOK peekNext2() | { 3006623| Token* t = peek(&token); 3006623| return peek(t).value; | } | | /**************************** | * Turn next token in buffer into a token. | */ | final void scan(Token* t) | { 303191529| const lastLine = scanloc.linnum; 303191529| Loc startLoc; 303191529| t.blockComment = null; 303191529| t.lineComment = null; | 489151161| while (1) | { 489151161| t.ptr = p; | //printf("p = %p, *p = '%c'\n",p,*p); 489151161| t.loc = loc(); 489151161| switch (*p) | { 111872| case 0: 111872| case 0x1A: 111872| t.value = TOK.endOfFile; // end of file | // Intentionally not advancing `p`, such that subsequent calls keep returning TOK.endOfFile. 111872| return; 133394910| case ' ': 133441221| case '\t': 133441221| case '\v': 133441221| case '\f': 133441221| p++; 133441221| continue; // skip white space 53| case '\r': 53| p++; 53| if (*p != '\n') // if CR stands by itself | { 000000000| endOfLine(); 000000000| goto skipFourSpaces; | } 53| continue; // skip white space 47735039| case '\n': 47735039| p++; 47735039| endOfLine(); | skipFourSpaces: 118006117| while (*(cast(uint*)p) == 0x20202020) //' ' == 0x20 | { 70271078| p+=4; | } 47735039| continue; // skip white space 7189698| case '0': 7189698| if (!isZeroSecond(p[1])) // if numeric literal does not continue | { 2525368| ++p; 2525368| t.unsvalue = 0; 2525368| t.value = TOK.int32Literal; 2525368| return; | } 4664330| goto Lnumber; | 58607494| case '1': .. case '9': 8288399| if (!isDigitSecond(p[1])) // if numeric literal does not continue | { 5294309| t.unsvalue = *p - '0'; 5294309| ++p; 5294309| t.value = TOK.int32Literal; 5294309| return; | } | Lnumber: 7658420| t.value = number(t); 7658420| return; | 367138| case '\'': 655987| if (issinglechar(p[1]) && p[2] == '\'') | { 288843| t.unsvalue = p[1]; // simple one character literal 288843| t.value = TOK.charLiteral; 288843| p += 3; | } | else 78295| t.value = charConstant(t); 367138| return; 5446503| case 'r': 5446503| if (p[1] != '"') 5446297| goto case_ident; 206| p++; 206| goto case '`'; 57278| case '`': 57278| wysiwygStringConstant(t); 57278| return; 882906| case 'x': 882906| if (p[1] != '"') 882901| goto case_ident; 5| p++; 5| auto start = p; 5| auto hexString = new OutBuffer(); 5| t.value = hexStringConstant(t); 5| hexString.write(start[0 .. p - start]); 5| error("Built-in hex string literals are obsolete, use `std.conv.hexString!%s` instead.", hexString.extractChars()); 5| return; 80457| case 'q': 80457| if (p[1] == '"') | { 19| p++; 19| delimitedStringConstant(t); 19| return; | } 80438| else if (p[1] == '{') | { 56323| p++; 56323| tokenStringConstant(t); 56323| return; | } | else 24115| goto case_ident; 3744273| case '"': 3744273| escapeStringConstant(t); 3744273| return; 10527805| case 'a': 13018871| case 'b': 21018458| case 'c': 23395227| case 'd': 28658469| case 'e': 31980265| case 'f': 32465376| case 'g': 34103622| case 'h': 46916361| case 'i': 47035562| case 'j': 47285353| case 'k': 49138753| case 'l': 51575269| case 'm': 55340112| case 'n': 57675326| case 'o': 62711187| case 'p': | /*case 'q': case 'r':*/ 76120525| case 's': 82010550| case 't': 84718246| case 'u': 89062978| case 'v': 89611039| case 'w': | /*case 'x':*/ 89751349| case 'y': 89789474| case 'z': 91064415| case 'A': 91475365| case 'B': 92252843| case 'C': 93333869| case 'D': 94441517| case 'E': 96359340| case 'F': 96586689| case 'G': 96624205| case 'H': 97195563| case 'I': 97201155| case 'J': 97568232| case 'K': 97727810| case 'L': 98668880| case 'M': 98970792| case 'N': 99404941| case 'O': 99691838| case 'P': 99733841| case 'Q': 100760496| case 'R': 102952937| case 'S': 109415894| case 'T': 110596252| case 'U': 111670881| case 'V': 111848149| case 'W': 111959139| case 'X': 111976627| case 'Y': 112021840| case 'Z': 115051676| case '_': | case_ident: | { 625988677| while (1) | { 625988677| const c = *++p; 625988677| if (isidchar(c)) 504583670| continue; 121405007| else if (c & 0x80) | { 7| const s = p; 7| const u = decodeUTF(); 7| if (isUniAlpha(u)) 7| continue; 000000000| error("char 0x%04x not allowed in identifier", u); 000000000| p = s; | } 121405000| break; | } 121405000| Identifier id = Identifier.idPool(cast(char*)t.ptr, cast(uint)(p - t.ptr)); 121405000| t.ident = id; 121405000| t.value = cast(TOK)id.getValue(); 121405000| anyToken = 1; 121405000| if (*t.ptr == '_') // if special identifier token | { | // Lazy initialization 3029836| TimeStampInfo.initialize(t.loc); | 3029836| if (id == Id.DATE) | { 3| t.ustring = TimeStampInfo.date.ptr; 3| goto Lstr; | } 3029833| else if (id == Id.TIME) | { 2| t.ustring = TimeStampInfo.time.ptr; 2| goto Lstr; | } 3029831| else if (id == Id.VENDOR) | { 000000000| t.ustring = global.vendor.xarraydup.ptr; 000000000| goto Lstr; | } 3029831| else if (id == Id.TIMESTAMP) | { 2| t.ustring = TimeStampInfo.timestamp.ptr; | Lstr: 7| t.value = TOK.string_; 7| t.postfix = 0; 7| t.len = cast(uint)strlen(t.ustring); | } 3029829| else if (id == Id.VERSIONX) | { 1| t.value = TOK.int64Literal; 1| t.unsvalue = global.versionNumber(); | } 3029828| else if (id == Id.EOFX) | { 000000000| t.value = TOK.endOfFile; | // Advance scanner to end of file 000000000| while (!(*p == 0 || *p == 0x1A)) 000000000| p++; | } | } | //printf("t.value = %d\n",t.value); 121405000| return; | } 4921849| case '/': 4921849| p++; 4921849| switch (*p) | { 7958| case '=': 7958| p++; 7958| t.value = TOK.divAssign; 7958| return; 805345| case '*': 805345| p++; 805345| startLoc = loc(); 1462952| while (1) | { 199203263| while (1) | { 199203263| const c = *p; 199203263| switch (c) | { 1462952| case '/': 1462952| break; 4831927| case '\n': 4831927| endOfLine(); 4831927| p++; 4831927| continue; 000000000| case '\r': 000000000| p++; 000000000| if (*p != '\n') 000000000| endOfLine(); 000000000| continue; 000000000| case 0: 000000000| case 0x1A: 000000000| error("unterminated /* */ comment"); 000000000| p = end; 000000000| t.loc = loc(); 000000000| t.value = TOK.endOfFile; 000000000| return; 192908384| default: 192908384| if (c & 0x80) | { 11994| const u = decodeUTF(); 23988| if (u == PS || u == LS) 000000000| endOfLine(); | } 192908384| p++; 192908384| continue; | } 1462952| break; | } 1462952| p++; 2268297| if (p[-2] == '*' && p - 3 != t.ptr) 805345| break; | } 805345| if (commentToken) | { 4| t.loc = startLoc; 4| t.value = TOK.comment; 4| return; | } 805715| else if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr) | { | // if /** but not /**/ 162| getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); 162| lastDocLine = scanloc.linnum; | } 805341| continue; 3913189| case '/': // do // style comments 3913189| startLoc = loc(); 126090177| while (1) | { 126090177| const c = *++p; 126090177| switch (c) | { 3913189| case '\n': 3913189| break; 000000000| case '\r': 000000000| if (p[1] == '\n') 000000000| p++; 000000000| break; 000000000| case 0: 000000000| case 0x1A: 000000000| if (commentToken) | { 000000000| p = end; 000000000| t.loc = startLoc; 000000000| t.value = TOK.comment; 000000000| return; | } 000000000| if (doDocComment && t.ptr[2] == '/') | { 000000000| getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); 000000000| lastDocLine = scanloc.linnum; | } 000000000| p = end; 000000000| t.loc = loc(); 000000000| t.value = TOK.endOfFile; 000000000| return; 122176988| default: 122176988| if (c & 0x80) | { 1934| const u = decodeUTF(); 3868| if (u == PS || u == LS) 000000000| break; | } 122176988| continue; | } 3913189| break; | } 3913189| if (commentToken) | { 24| p++; 24| endOfLine(); 24| t.loc = startLoc; 24| t.value = TOK.comment; 24| return; | } 3914018| if (doDocComment && t.ptr[2] == '/') | { 501| getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); 501| lastDocLine = scanloc.linnum; | } 3913165| p++; 3913165| endOfLine(); 3913165| continue; 64681| case '+': | { 64681| int nest; 64681| startLoc = loc(); 64681| p++; 64681| nest = 1; 23736504| while (1) | { 23736504| char c = *p; 23736504| switch (c) | { 48128| case '/': 48128| p++; 48128| if (*p == '+') | { 000000000| p++; 000000000| nest++; | } 48128| continue; 113302| case '+': 113302| p++; 113302| if (*p == '/') | { 64681| p++; 64681| if (--nest == 0) 64681| break; | } 48621| continue; 000000000| case '\r': 000000000| p++; 000000000| if (*p != '\n') 000000000| endOfLine(); 000000000| continue; 561064| case '\n': 561064| endOfLine(); 561064| p++; 561064| continue; 000000000| case 0: 000000000| case 0x1A: 000000000| error("unterminated /+ +/ comment"); 000000000| p = end; 000000000| t.loc = loc(); 000000000| t.value = TOK.endOfFile; 000000000| return; 23014010| default: 23014010| if (c & 0x80) | { 1181| uint u = decodeUTF(); 2362| if (u == PS || u == LS) 000000000| endOfLine(); | } 23014010| p++; 23014010| continue; | } 64681| break; | } 64681| if (commentToken) | { 1| t.loc = startLoc; 1| t.value = TOK.comment; 1| return; | } 64728| if (doDocComment && t.ptr[2] == '+' && p - 4 != t.ptr) | { | // if /++ but not /++/ 23| getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1); 23| lastDocLine = scanloc.linnum; | } 64680| continue; | } 130676| default: 130676| break; | } 130676| t.value = TOK.div; 130676| return; 9162636| case '.': 9162636| p++; 9162636| if (isdigit(*p)) | { | /* Note that we don't allow ._1 and ._ as being | * valid floating point numbers. | */ 2890| p--; 2890| t.value = inreal(t); | } 9159746| else if (p[0] == '.') | { 562910| if (p[1] == '.') | { 109848| p += 2; 109848| t.value = TOK.dotDotDot; | } | else | { 453062| p++; 453062| t.value = TOK.slice; | } | } | else 8596836| t.value = TOK.dot; 9162636| return; 1781302| case '&': 1781302| p++; 1781302| if (*p == '=') | { 6119| p++; 6119| t.value = TOK.andAssign; | } 1775183| else if (*p == '&') | { 847143| p++; 847143| t.value = TOK.andAnd; | } | else 928040| t.value = TOK.and; 1781302| return; 743444| case '|': 743444| p++; 743444| if (*p == '=') | { 26970| p++; 26970| t.value = TOK.orAssign; | } 716474| else if (*p == '|') | { 644834| p++; 644834| t.value = TOK.orOr; | } | else 71640| t.value = TOK.or; 743444| return; 892643| case '-': 892643| p++; 892643| if (*p == '=') | { 22662| p++; 22662| t.value = TOK.minAssign; | } 869981| else if (*p == '-') | { 30248| p++; 30248| t.value = TOK.minusMinus; | } | else 839733| t.value = TOK.min; 892643| return; 826438| case '+': 826438| p++; 826438| if (*p == '=') | { 125146| p++; 125146| t.value = TOK.addAssign; | } 701292| else if (*p == '+') | { 252695| p++; 252695| t.value = TOK.plusPlus; | } | else 448597| t.value = TOK.add; 826438| return; 554671| case '<': 554671| p++; 554671| if (*p == '=') | { 133985| p++; 133985| t.value = TOK.lessOrEqual; // <= | } 420686| else if (*p == '<') | { 120208| p++; 120208| if (*p == '=') | { 8068| p++; 8068| t.value = TOK.leftShiftAssign; // <<= | } | else 112140| t.value = TOK.leftShift; // << | } | else 300478| t.value = TOK.lessThan; // < 554671| return; 412094| case '>': 412094| p++; 412094| if (*p == '=') | { 97124| p++; 97124| t.value = TOK.greaterOrEqual; // >= | } 314970| else if (*p == '>') | { 103444| p++; 103444| if (*p == '=') | { 21801| p++; 21801| t.value = TOK.rightShiftAssign; // >>= | } 81643| else if (*p == '>') | { 18518| p++; 18518| if (*p == '=') | { 530| p++; 530| t.value = TOK.unsignedRightShiftAssign; // >>>= | } | else 17988| t.value = TOK.unsignedRightShift; // >>> | } | else 63125| t.value = TOK.rightShift; // >> | } | else 211526| t.value = TOK.greaterThan; // > 412094| return; 5725100| case '!': 5725100| p++; 5725100| if (*p == '=') | { 190276| p++; 190276| t.value = TOK.notEqual; // != | } | else 5534824| t.value = TOK.not; // ! 5725100| return; 11351655| case '=': 11351655| p++; 11351655| if (*p == '=') | { 4025130| p++; 4025130| t.value = TOK.equal; // == | } 7326525| else if (*p == '>') | { 93472| p++; 93472| t.value = TOK.goesTo; // => | } | else 7233053| t.value = TOK.assign; // = 11351655| return; 930403| case '~': 930403| p++; 930403| if (*p == '=') | { 198715| p++; 198715| t.value = TOK.concatenateAssign; // ~= | } | else 731688| t.value = TOK.tilde; // ~ 930403| return; 75782| case '^': 75782| p++; 75782| if (*p == '^') | { 22221| p++; 22221| if (*p == '=') | { 76| p++; 76| t.value = TOK.powAssign; // ^^= | } | else 22145| t.value = TOK.pow; // ^^ | } 53561| else if (*p == '=') | { 24667| p++; 24667| t.value = TOK.xorAssign; // ^= | } | else 28894| t.value = TOK.xor; // ^ 75782| return; 29373438| case '(': 29373438| p++; 29373438| t.value = TOK.leftParentheses; 29373438| return; 29373436| case ')': 29373436| p++; 29373436| t.value = TOK.rightParentheses; 29373436| return; 4987894| case '[': 4987894| p++; 4987894| t.value = TOK.leftBracket; 4987894| return; 4987887| case ']': 4987887| p++; 4987887| t.value = TOK.rightBracket; 4987887| return; 7324098| case '{': 7324098| p++; 7324098| t.value = TOK.leftCurly; 7324098| return; 7380407| case '}': 7380407| p++; 7380407| t.value = TOK.rightCurly; 7380407| return; 191732| case '?': 191732| p++; 191732| t.value = TOK.question; 191732| return; 17073629| case ',': 17073629| p++; 17073629| t.value = TOK.comma; 17073629| return; 20087124| case ';': 20087124| p++; 20087124| t.value = TOK.semicolon; 20087124| return; 1645958| case ':': 1645958| p++; 1645958| t.value = TOK.colon; 1645958| return; 124512| case '$': 124512| p++; 124512| t.value = TOK.dollar; 124512| return; 2957910| case '@': 2957910| p++; 2957910| t.value = TOK.at; 2957910| return; 3641727| case '*': 3641727| p++; 3641727| if (*p == '=') | { 50102| p++; 50102| t.value = TOK.mulAssign; | } | else 3591625| t.value = TOK.mul; 3641727| return; 226938| case '%': 226938| p++; 226938| if (*p == '=') | { 1720| p++; 1720| t.value = TOK.modAssign; | } | else 225218| t.value = TOK.mod; 226938| return; 133| case '#': | { 133| p++; 133| Token n; 133| scan(&n); 133| if (n.value == TOK.identifier) | { 132| if (n.ident == Id.line) | { 130| poundLine(); 130| continue; | } | else | { 2| const locx = loc(); 2| warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); | } | } 1| else if (n.value == TOK.if_) | { 1| error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); | } 3| t.value = TOK.pound; 3| return; | } 14| default: | { 14| dchar c = *p; 14| if (c & 0x80) | { 11| c = decodeUTF(); | // Check for start of unicode identifier 11| if (isUniAlpha(c)) 11| goto case_ident; 000000000| if (c == PS || c == LS) | { 000000000| endOfLine(); 000000000| p++; 000000000| continue; | } | } 6| if (c < 0x80 && isprint(c)) 3| error("character '%c' is not a valid token", c); | else 000000000| error("character 0x%02x is not a valid token", c); 3| p++; 3| continue; | } | } | } | } | | final Token* peek(Token* ct) | { 119917317| Token* t; 119917317| if (ct.next) 48027312| t = ct.next; | else | { 71890005| t = allocateToken(); 71890005| scan(t); 71890005| ct.next = t; | } 119917317| return t; | } | | /********************************* | * tk is on the opening (. | * Look ahead and return token that is past the closing ). | */ | final Token* peekPastParen(Token* tk) | { | //printf("peekPastParen()\n"); 3564928| int parens = 1; 3564928| int curlynest = 0; 21879804| while (1) | { 21879804| tk = peek(tk); | //tk.print(); 21879804| switch (tk.value) | { 952444| case TOK.leftParentheses: 952444| parens++; 952444| continue; 4517371| case TOK.rightParentheses: 4517371| --parens; 4517371| if (parens) 952444| continue; 3564927| tk = peek(tk); 3564927| break; 833| case TOK.leftCurly: 833| curlynest++; 833| continue; 832| case TOK.rightCurly: 832| if (--curlynest >= 0) 832| continue; 000000000| break; 1438| case TOK.semicolon: 1438| if (curlynest) 1438| continue; 000000000| break; 1| case TOK.endOfFile: 1| break; 16406885| default: 16406885| continue; | } 3564928| return tk; | } | } | | /******************************************* | * Parse escape sequence. | */ | private uint escapeSequence() | { 265853| return Lexer.escapeSequence(token.loc, p); | } | | /** | Parse the given string literal escape sequence into a single character. | Params: | loc = the location of the current token | sequence = pointer to string with escape sequence to parse. this is a reference | variable that is also used to return the position after the sequence | Returns: | the escaped sequence as a single character | */ | private static dchar escapeSequence(const ref Loc loc, ref const(char)* sequence) | { 265853| const(char)* p = sequence; // cache sequence reference on stack 265853| scope(exit) sequence = p; | 265853| uint c = *p; 265853| int ndigits; 265853| switch (c) | { 15465| case '\'': 19196| case '"': 19402| case '?': 28405| case '\\': | Lconsume: 144663| p++; 144663| break; 394| case 'a': 394| c = 7; 394| goto Lconsume; 400| case 'b': 400| c = 8; 400| goto Lconsume; 1286| case 'f': 1286| c = 12; 1286| goto Lconsume; 77995| case 'n': 77995| c = 10; 77995| goto Lconsume; 17170| case 'r': 17170| c = 13; 17170| goto Lconsume; 16609| case 't': 16609| c = 9; 16609| goto Lconsume; 2404| case 'v': 2404| c = 11; 2404| goto Lconsume; 65739| case 'u': 65739| ndigits = 4; 65739| goto Lhex; 24238| case 'U': 24238| ndigits = 8; 24238| goto Lhex; 20928| case 'x': 20928| ndigits = 2; | Lhex: 110905| p++; 110905| c = *p; 110905| if (ishex(cast(char)c)) | { 110904| uint v = 0; 110904| int n = 0; 498713| while (1) | { 498713| if (isdigit(cast(char)c)) 420991| c -= '0'; 77722| else if (islower(c)) 7884| c -= 'a' - 10; | else 69838| c -= 'A' - 10; 498713| v = v * 16 + c; 498713| c = *++p; 498713| if (++n == ndigits) 110903| break; 387810| if (!ishex(cast(char)c)) | { 1| .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); 1| break; | } | } 200881| if (ndigits != 2 && !utf_isValidDchar(v)) | { 1| .error(loc, "invalid UTF character \\U%08x", v); 1| v = '?'; // recover with valid UTF character | } 110904| c = v; | } | else | { 1| .error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c); 1| p++; | } 110905| break; 349| case '&': | // named character entity 4234| for (const idstart = ++p; 1; p++) | { 2117| switch (*p) | { 345| case ';': 345| c = HtmlNamedEntity(idstart, p - idstart); 345| if (c == ~0) | { 1| .error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); 1| c = '?'; | } 345| p++; 345| break; 1772| default: 1801| if (isalpha(*p) || (p != idstart && isdigit(*p))) 1768| continue; 4| .error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); 4| c = '?'; 4| break; | } 349| break; | } 349| break; 000000000| case 0: 000000000| case 0x1A: | // end of file 000000000| c = '\\'; 000000000| break; 9936| default: 9936| if (isoctal(cast(char)c)) | { 9936| uint v = 0; 9936| int n = 0; | do | { 10525| v = v * 8 + (c - '0'); 10525| c = *++p; | } 20757| while (++n < 3 && isoctal(cast(char)c)); 9936| c = v; 9936| if (c > 0xFF) 1| .error(loc, "escape octal sequence \\%03o is larger than \\377", c); | } | else | { 000000000| .error(loc, "undefined escape sequence \\%c", c); 000000000| p++; | } 9936| break; | } 265853| return c; | } | | /** | Lex a wysiwyg string. `p` must be pointing to the first character before the | contents of the string literal. The character pointed to by `p` will be used as | the terminating character (i.e. backtick or double-quote). | Params: | result = pointer to the token that accepts the result | */ | private void wysiwygStringConstant(Token* result) | { 57278| result.value = TOK.string_; 57278| Loc start = loc(); 57278| auto terminator = p[0]; 57278| p++; 57278| stringbuffer.setsize(0); 1032538| while (1) | { 1032538| dchar c = p[0]; 1032538| p++; 1032538| switch (c) | { 8262| case '\n': 8262| endOfLine(); 8262| break; 000000000| case '\r': 000000000| if (p[0] == '\n') 000000000| continue; // ignore 000000000| c = '\n'; // treat EndOfLine as \n character 000000000| endOfLine(); 000000000| break; 000000000| case 0: 000000000| case 0x1A: 000000000| error("unterminated string constant starting at %s", start.toChars()); 000000000| result.setString(); | // rewind `p` so it points to the EOF character 000000000| p--; 000000000| return; 1024276| default: 1024276| if (c == terminator) | { 57278| result.setString(stringbuffer); 57278| stringPostfix(result); 57278| return; | } 966998| else if (c & 0x80) | { 12408| p--; 12408| const u = decodeUTF(); 12408| p++; 24816| if (u == PS || u == LS) 000000000| endOfLine(); 12408| stringbuffer.writeUTF8(u); 12408| continue; | } 954590| break; | } 962852| stringbuffer.writeByte(c); | } | } | | /************************************** | * Lex hex strings: | * x"0A ae 34FE BD" | */ | private TOK hexStringConstant(Token* t) | { 5| Loc start = loc(); 5| uint n = 0; 5| uint v = ~0; // dead assignment, needed to suppress warning 5| p++; 5| stringbuffer.setsize(0); 30| while (1) | { 30| dchar c = *p++; 30| switch (c) | { 4| case ' ': 4| case '\t': 4| case '\v': 4| case '\f': 4| continue; // skip white space 000000000| case '\r': 000000000| if (*p == '\n') 000000000| continue; // ignore '\r' if followed by '\n' | // Treat isolated '\r' as if it were a '\n' 000000000| goto case '\n'; 000000000| case '\n': 000000000| endOfLine(); 000000000| continue; 000000000| case 0: 000000000| case 0x1A: 000000000| error("unterminated string constant starting at %s", start.toChars()); 000000000| t.setString(); | // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). 000000000| p--; 000000000| return TOK.hexadecimalString; 5| case '"': 5| if (n & 1) | { 1| error("odd number (%d) of hex characters in hex string", n); 1| stringbuffer.writeByte(v); | } 5| t.setString(stringbuffer); 5| stringPostfix(t); 5| return TOK.hexadecimalString; 21| default: 42| if (c >= '0' && c <= '9') 14| c -= '0'; 7| else if (c >= 'a' && c <= 'f') 000000000| c -= 'a' - 10; 14| else if (c >= 'A' && c <= 'F') 6| c -= 'A' - 10; 1| else if (c & 0x80) | { 000000000| p--; 000000000| const u = decodeUTF(); 000000000| p++; 000000000| if (u == PS || u == LS) 000000000| endOfLine(); | else 000000000| error("non-hex character \\u%04x in hex string", u); | } | else 1| error("non-hex character '%c' in hex string", c); 21| if (n & 1) | { 10| v = (v << 4) | c; 10| stringbuffer.writeByte(v); | } | else 11| v = c; 21| n++; 21| break; | } | } 000000000| assert(0); // see bug 15731 | } | | /** | Lex a delimited string. Some examples of delimited strings are: | --- | q"(foo(xxx))" // "foo(xxx)" | q"[foo$(LPAREN)]" // "foo$(LPAREN)" | q"/foo]/" // "foo]" | q"HERE | foo | HERE" // "foo\n" | --- | It is assumed that `p` points to the opening double-quote '"'. | Params: | result = pointer to the token that accepts the result | */ | private void delimitedStringConstant(Token* result) | { 19| result.value = TOK.string_; 19| Loc start = loc(); 19| dchar delimleft = 0; 19| dchar delimright = 0; 19| uint nest = 1; 19| uint nestcount = ~0; // dead assignment, needed to suppress warning 19| Identifier hereid = null; 19| uint blankrol = 0; 19| uint startline = 0; 19| p++; 19| stringbuffer.setsize(0); 4078| while (1) | { 4078| dchar c = *p++; | //printf("c = '%c'\n", c); 4078| switch (c) | { 81| case '\n': | Lnextline: 81| endOfLine(); 81| startline = 1; 81| if (blankrol) | { 8| blankrol = 0; 8| continue; | } 73| if (hereid) | { 25| stringbuffer.writeUTF8(c); 25| continue; | } 48| break; 000000000| case '\r': 000000000| if (*p == '\n') 000000000| continue; // ignore 000000000| c = '\n'; // treat EndOfLine as \n character 000000000| goto Lnextline; 1| case 0: 1| case 0x1A: 1| error("unterminated delimited string constant starting at %s", start.toChars()); 1| result.setString(); | // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). 1| p--; 1| return; 3996| default: 3996| if (c & 0x80) | { 000000000| p--; 000000000| c = decodeUTF(); 000000000| p++; 000000000| if (c == PS || c == LS) 000000000| goto Lnextline; | } 3996| break; | } 4044| if (delimleft == 0) | { 19| delimleft = c; 19| nest = 1; 19| nestcount = 1; 19| if (c == '(') 2| delimright = ')'; 17| else if (c == '{') 3| delimright = '}'; 14| else if (c == '[') 2| delimright = ']'; 12| else if (c == '<') 1| delimright = '>'; 16| else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) | { | // Start of identifier; must be a heredoc 9| Token tok; 9| p--; 9| scan(&tok); // read in heredoc identifier 9| if (tok.value != TOK.identifier) | { 000000000| error("identifier expected for heredoc, not %s", tok.toChars()); 000000000| delimright = c; | } | else | { 9| hereid = tok.ident; | //printf("hereid = '%s'\n", hereid.toChars()); 9| blankrol = 1; | } 9| nest = 0; | } | else | { 2| delimright = c; 2| nest = 0; 2| if (isspace(c)) 1| error("delimiter cannot be whitespace"); | } | } | else | { 4025| if (blankrol) | { 1| error("heredoc rest of line should be blank"); 1| blankrol = 0; 1| continue; | } 4024| if (nest == 1) | { 3894| if (c == delimleft) 5| nestcount++; 3889| else if (c == delimright) | { 13| nestcount--; 13| if (nestcount == 0) 8| goto Ldone; | } | } 130| else if (c == delimright) 2| goto Ldone; 4239| if (startline && (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) && hereid) | { 12| Token tok; 12| auto psave = p; 12| p--; 12| scan(&tok); // read in possible heredoc identifier | //printf("endid = '%s'\n", tok.ident.toChars()); 23| if (tok.value == TOK.identifier && tok.ident is hereid) | { | /* should check that rest of line is blank | */ 8| goto Ldone; | } 4| p = psave; | } 4006| stringbuffer.writeUTF8(c); 4006| startline = 0; | } | } | Ldone: 18| if (*p == '"') 15| p++; 3| else if (hereid) 1| error("delimited string must end in %s\"", hereid.toChars()); | else 2| error("delimited string must end in %c\"", delimright); 18| result.setString(stringbuffer); 18| stringPostfix(result); | } | | /** | Lex a token string. Some examples of token strings are: | --- | q{ foo(xxx) } // " foo(xxx) " | q{foo$(LPAREN)} // "foo$(LPAREN)" | q{{foo}"}"} // "{foo}"}"" | --- | It is assumed that `p` points to the opening curly-brace '{'. | Params: | result = pointer to the token that accepts the result | */ | private void tokenStringConstant(Token* result) | { 56323| result.value = TOK.string_; | 56323| uint nest = 1; 56323| const start = loc(); 56323| const pstart = ++p; 56323| inTokenStringConstant++; 56323| scope(exit) inTokenStringConstant--; 8512202| while (1) | { 8512202| Token tok; 8512202| scan(&tok); 8512202| switch (tok.value) | { 95352| case TOK.leftCurly: 95352| nest++; 95352| continue; 151674| case TOK.rightCurly: 151674| if (--nest == 0) | { 56322| result.setString(pstart, p - 1 - pstart); 56322| stringPostfix(result); 56322| return; | } 95352| continue; 1| case TOK.endOfFile: 1| error("unterminated token string constant starting at %s", start.toChars()); 1| result.setString(); 1| return; 8265175| default: 8265175| continue; | } | } | } | | /** | Scan a double-quoted string while building the processed string value by | handling escape sequences. The result is returned in the given `t` token. | This function assumes that `p` currently points to the opening double-quote | of the string. | Params: | t = the token to set the resulting string to | */ | private void escapeStringConstant(Token* t) | { 3744273| t.value = TOK.string_; | 3744273| const start = loc(); 3744273| p++; 3744273| stringbuffer.setsize(0); 43903962| while (1) | { 43903962| dchar c = *p++; 43903962| switch (c) | { 198913| case '\\': 198913| switch (*p) | { 49129| case 'u': 69777| case 'U': 69990| case '&': 69990| c = escapeSequence(); 69990| stringbuffer.writeUTF8(c); 69990| continue; 128923| default: 128923| c = escapeSequence(); 128923| break; | } 128923| break; 54697| case '\n': 54697| endOfLine(); 54697| break; 000000000| case '\r': 000000000| if (*p == '\n') 000000000| continue; // ignore 000000000| c = '\n'; // treat EndOfLine as \n character 000000000| endOfLine(); 000000000| break; 3744270| case '"': 3744270| t.setString(stringbuffer); 3744270| stringPostfix(t); 3744270| return; 3| case 0: 3| case 0x1A: | // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). 3| p--; 3| error("unterminated string constant starting at %s", start.toChars()); 3| t.setString(); 3| return; 39906079| default: 39906079| if (c & 0x80) | { 271237| p--; 271237| c = decodeUTF(); 542474| if (c == LS || c == PS) | { 000000000| c = '\n'; 000000000| endOfLine(); | } 271237| p++; 271237| stringbuffer.writeUTF8(c); 271237| continue; | } 39634842| break; | } 39818462| stringbuffer.writeByte(c); | } | } | | /************************************** | */ | private TOK charConstant(Token* t) | { 78295| TOK tk = TOK.charLiteral; | //printf("Lexer::charConstant\n"); 78295| p++; 78295| dchar c = *p++; 78295| switch (c) | { 66940| case '\\': 66940| switch (*p) | { 16610| case 'u': 16610| t.unsvalue = escapeSequence(); 16610| tk = TOK.wcharLiteral; 16610| break; 3590| case 'U': 3726| case '&': 3726| t.unsvalue = escapeSequence(); 3726| tk = TOK.dcharLiteral; 3726| break; 46604| default: 46604| t.unsvalue = escapeSequence(); 46604| break; | } 66940| break; 1| case '\n': | L1: 1| endOfLine(); 1| goto case; 1| case '\r': 1| goto case '\''; 000000000| case 0: 000000000| case 0x1A: | // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). 000000000| p--; 000000000| goto case; 2| case '\'': 2| error("unterminated character constant"); 2| t.unsvalue = '?'; 2| return tk; 11353| default: 11353| if (c & 0x80) | { 11347| p--; 11347| c = decodeUTF(); 11347| p++; 22694| if (c == LS || c == PS) 000000000| goto L1; 12233| if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) 11031| tk = TOK.wcharLiteral; | else 316| tk = TOK.dcharLiteral; | } 11353| t.unsvalue = c; 11353| break; | } 78293| if (*p != '\'') | { 482| while (*p != '\'' && *p != 0x1A && *p != 0 && *p != '\n' && 591| *p != '\r' && *p != ';' && *p != ')' && *p != ']' && *p != '}') | { 116| if (*p & 0x80) | { 000000000| const s = p; 000000000| c = decodeUTF(); 000000000| if (c == LS || c == PS) | { 000000000| p = s; 000000000| break; | } | } 116| p++; | } | 6| if (*p == '\'') | { 2| error("character constant has multiple characters"); 2| p++; | } | else 4| error("unterminated character constant"); 6| t.unsvalue = '?'; 6| return tk; | } 78287| p++; 78287| return tk; | } | | /*************************************** | * Get postfix of string literal. | */ | private void stringPostfix(Token* t) pure @nogc | { 3857893| switch (*p) | { 9928| case 'c': 28955| case 'w': 52988| case 'd': 52988| t.postfix = *p; 52988| p++; 52988| break; 3804905| default: 3804905| t.postfix = 0; 3804905| 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,... | */ | private TOK number(Token* t) | { 7658420| int base = 10; 7658420| const start = p; 7658420| uinteger_t n = 0; // unsigned >=64 bit integer type 7658420| int d; 7658420| bool err = false; 7658420| bool overflow = false; 7658420| bool anyBinaryDigitsNoSingleUS = false; 7658420| bool anyHexDigitsNoSingleUS = false; 7658420| dchar c = *p; 7658420| if (c == '0') | { 4664330| ++p; 4664330| c = *p; 4664330| switch (c) | { 523| case '0': 3494| case '1': 3539| case '2': 3623| case '3': 4024| case '4': 4064| case '5': 4064| case '6': 6227| case '7': 6228| case '8': 6229| case '9': 6229| base = 8; 6229| break; 4507551| case 'x': 4507614| case 'X': 4507614| ++p; 4507614| base = 16; 4507614| break; 7372| case 'b': 7375| case 'B': 7375| ++p; 7375| base = 2; 7375| break; 136891| case '.': 136891| if (p[1] == '.') 28706| goto Ldone; // if ".." 320965| if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80) 1796| goto Ldone; // if ".identifier" or ".unicode" 106389| goto Lreal; // '.' is part of current token 34| case 'i': 408| case 'f': 410| case 'F': 410| goto Lreal; 5| case '_': 5| ++p; 5| base = 8; 5| break; 2550| case 'L': 2550| if (p[1] == 'i') 1| goto Lreal; 2549| break; 3256| default: 3256| break; | } | } 37010306| while (1) | { 37010306| c = *p; 37010306| switch (c) | { 5635505| case '0': 9004897| case '1': 11587993| case '2': 13289904| case '3': 14589253| case '4': 15470407| case '5': 16300478| case '6': 17107869| case '7': 17933306| case '8': 19097358| case '9': 19097358| ++p; 19097358| d = c - '0'; 19097358| break; 445918| case 'a': 833032| case 'b': 1210788| case 'c': 1509779| case 'd': 1877210| case 'e': 9857693| case 'f': 9871976| case 'A': 9881629| case 'B': 9903901| case 'C': 9922584| case 'D': 9933348| case 'E': 10164954| case 'F': 10164954| ++p; 10164954| if (base != 16) | { 13786| if (c == 'e' || c == 'E' || c == 'f' || c == 'F') 10024| goto Lreal; | } 10154930| if (c >= 'a') 9847991| d = c + 10 - 'a'; | else 306939| d = c + 10 - 'A'; 10154930| break; 29736| case 'L': 29736| if (p[1] == 'i') 1| goto Lreal; 29735| goto Ldone; 179522| case '.': 179522| if (p[1] == '.') 4268| goto Ldone; // if ".." 642775| if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)) 15539| goto Ldone; // if ".identifier" or ".unicode" 186866| if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80)) 1| goto Ldone; // if ".identifier" or ".unicode" 159714| if (base == 2) 1| goto Ldone; // if ".identifier" or ".unicode" 159713| goto Lreal; // otherwise as part of a floating point literal 2563| case 'p': 2571| case 'P': 3393| case 'i': | Lreal: 279931| p = start; 279931| return inreal(t); 236900| case '_': 236900| ++p; 236900| continue; 7298443| default: 7298443| goto Ldone; | } | // got a digit here, set any necessary flags, check for errors 29252288| anyHexDigitsNoSingleUS = true; 29252288| anyBinaryDigitsNoSingleUS = true; 58504576| if (!err && d >= base) | { 6| error("%s digit expected, not `%c`", base == 2 ? "binary".ptr : 7| base == 8 ? "octal".ptr : 1| "decimal".ptr, c); 5| err = true; | } | // Avoid expensive overflow check if we aren't at risk of overflow 29252288| if (n <= 0x0FFF_FFFF_FFFF_FFFFUL) 29250369| n = n * base + d; | else | { | import core.checkedint : mulu, addu; | 1919| n = mulu(n, base, overflow); 1919| n = addu(n, d, overflow); | } | } | Ldone: 7378494| if (overflow && !err) | { 5| error("integer overflow"); 5| err = true; | } 7385864| if ((base == 2 && !anyBinaryDigitsNoSingleUS) || 11874476| (base == 16 && !anyHexDigitsNoSingleUS)) 10| error("`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start); | enum FLAGS : int | { | none = 0, | decimal = 1, // decimal | unsigned = 2, // u or U suffix | long_ = 4, // L suffix | } | 14756978| FLAGS flags = (base == 10) ? FLAGS.decimal : FLAGS.none; | // Parse trailing 'u', 'U', 'l' or 'L' in any combination 7378489| const psuffix = p; 7593023| while (1) | { 7593023| FLAGS f; 7593023| switch (*p) | { 96973| case 'U': 108021| case 'u': 108021| f = FLAGS.unsigned; 108021| goto L1; 2| case 'l': 2| f = FLAGS.long_; 2| error("lower case integer suffix 'l' is not allowed. Please use 'L' instead"); 2| goto L1; 106511| case 'L': 106511| f = FLAGS.long_; | L1: 214534| p++; 214535| if ((flags & f) && !err) | { 1| error("unrecognized token"); 1| err = true; | } 214534| flags = cast(FLAGS)(flags | f); 214534| continue; 7378489| default: 7378489| break; | } 7378489| break; | } 7384720| if (base == 8 && n >= 8) | { 18| if (err) | // can't translate invalid octal value, just show a generic message 3| error("octal literals larger than 7 are no longer supported"); | else 15| error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!%llo%.*s` instead", | n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix); | } 7378489| TOK result; 7378489| switch (flags) | { 4451177| case FLAGS.none: | /* Octal or Hexadecimal constant. | * First that fits: int, uint, long, ulong | */ 4451177| if (n & 0x8000000000000000L) 226678| result = TOK.uns64Literal; 4224499| else if (n & 0xFFFFFFFF00000000L) 275823| result = TOK.int64Literal; 3948676| else if (n & 0x80000000) 476050| result = TOK.uns32Literal; | else 3472626| result = TOK.int32Literal; 4451177| break; 2790864| case FLAGS.decimal: | /* First that fits: int, long, long long | */ 2790864| if (n & 0x8000000000000000L) | { 50| result = TOK.uns64Literal; | } 2790814| else if (n & 0xFFFFFFFF80000000L) 15329| result = TOK.int64Literal; | else 2775485| result = TOK.int32Literal; 2790864| break; 4274| case FLAGS.unsigned: 29935| case FLAGS.decimal | FLAGS.unsigned: | /* First that fits: uint, ulong | */ 29935| if (n & 0xFFFFFFFF00000000L) 1430| result = TOK.uns64Literal; | else 28505| result = TOK.uns32Literal; 29935| break; 26356| case FLAGS.decimal | FLAGS.long_: 26356| if (n & 0x8000000000000000L) | { 24| if (!err) | { 24| error("signed integer overflow"); 24| err = true; | } 24| result = TOK.uns64Literal; | } | else 26332| result = TOK.int64Literal; 26356| break; 2072| case FLAGS.long_: 2072| if (n & 0x8000000000000000L) 259| result = TOK.uns64Literal; | else 1813| result = TOK.int64Literal; 2072| break; 52076| case FLAGS.unsigned | FLAGS.long_: 78085| case FLAGS.decimal | FLAGS.unsigned | FLAGS.long_: 78085| result = TOK.uns64Literal; 78085| break; 000000000| default: | debug | { 000000000| printf("%x\n", flags); | } 000000000| assert(0); | } 7378489| t.unsvalue = n; 7378489| return result; | } | | /************************************** | * Read in characters, converting them to real. | * Bugs: | * Exponent overflow not detected. | * Too much requested precision is not detected. | */ | private TOK inreal(Token* t) | { | //printf("Lexer::inreal()\n"); | debug | { 562752| assert(*p == '.' || isdigit(*p)); | } 282821| bool isWellformedString = true; 282821| stringbuffer.setsize(0); 282821| auto pstart = p; 282821| bool hex = false; 282821| dchar c = *p++; | // Leading '0x' 282821| if (c == '0') | { 118424| c = *p++; 225235| if (c == 'x' || c == 'X') | { 11621| hex = true; 11621| c = *p++; | } | } | // Digits to left of '.' 511426| while (1) | { 511426| if (c == '.') | { 268992| c = *p++; 268992| break; | } 287519| if (isdigit(c) || (hex && isxdigit(c)) || c == '_') | { 228605| c = *p++; 228605| continue; | } 13829| break; | } | // Digits to right of '.' 1134740| while (1) | { 1771035| if (isdigit(c) || (hex && isxdigit(c)) || c == '_') | { 851919| c = *p++; 851919| continue; | } 282821| break; | } 827265| if (c == 'e' || c == 'E' || (hex && (c == 'p' || c == 'P'))) | { 34775| c = *p++; 55704| if (c == '-' || c == '+') | { 18870| c = *p++; | } 34775| bool anyexp = false; 91849| while (1) | { 91849| if (isdigit(c)) | { 57070| anyexp = true; 57070| c = *p++; 57070| continue; | } 34779| if (c == '_') | { 4| c = *p++; 4| continue; | } 34775| if (!anyexp) | { 1| error("missing exponent"); 1| isWellformedString = false; | } 34775| break; | } | } 248046| else if (hex) | { 1| error("exponent required for hex float"); 1| isWellformedString = false; | } 282821| --p; 1873101| while (pstart < p) | { 1590280| if (*pstart != '_') 1584361| stringbuffer.writeByte(*pstart); 1590280| ++pstart; | } 282821| stringbuffer.writeByte(0); 282821| auto sbufptr = cast(const(char)*)stringbuffer[].ptr; 282821| TOK result; 282821| bool isOutOfRange = false; 565642| t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, &isOutOfRange) : CTFloat.zero); 282821| switch (*p) | { 329| case 'F': 37364| case 'f': 74728| if (isWellformedString && !isOutOfRange) 37364| isOutOfRange = Port.isFloat32LiteralOutOfRange(sbufptr); 37364| result = TOK.float32Literal; 37364| p++; 37364| break; 180487| default: 360972| if (isWellformedString && !isOutOfRange) 180485| isOutOfRange = Port.isFloat64LiteralOutOfRange(sbufptr); 180487| result = TOK.float64Literal; 180487| break; 000000000| case 'l': 000000000| error("use 'L' suffix instead of 'l'"); 000000000| goto case 'L'; 64970| case 'L': 64970| result = TOK.float80Literal; 64970| p++; 64970| break; | } 563663| if (*p == 'i' || *p == 'I') | { 1980| if (*p == 'I') 1| error("use 'i' suffix instead of 'I'"); 1980| p++; 1980| switch (result) | { 21| case TOK.float32Literal: 21| result = TOK.imaginary32Literal; 21| break; 1877| case TOK.float64Literal: 1877| result = TOK.imaginary64Literal; 1877| break; 82| case TOK.float80Literal: 82| result = TOK.imaginary80Literal; 82| break; 000000000| default: 000000000| break; | } | } 500754| const isLong = (result == TOK.float80Literal || result == TOK.imaginary80Literal); 282928| if (isOutOfRange && !isLong) | { 2| const char* suffix = (result == TOK.float32Literal || result == TOK.imaginary32Literal) ? "f" : ""; 1| error(scanloc, "number `%s%s` is not representable", sbufptr, suffix); | } | debug | { 282821| switch (result) | { 37343| case TOK.float32Literal: 215953| case TOK.float64Literal: 280841| case TOK.float80Literal: 280862| case TOK.imaginary32Literal: 282739| case TOK.imaginary64Literal: 282821| case TOK.imaginary80Literal: 282821| break; 000000000| default: 000000000| assert(0); | } | } 282821| return result; | } | | final Loc loc() pure @nogc | { 497792406| scanloc.charnum = cast(uint)(1 + p - line); 497792406| return scanloc; | } | | final void error(const(char)* format, ...) | { 502| va_list args; 502| va_start(args, format); 502| .verror(token.loc, format, args); 502| va_end(args); | } | | final void error(const ref Loc loc, const(char)* format, ...) | { 80| va_list args; 80| va_start(args, format); 80| .verror(loc, format, args); 80| va_end(args); | } | | final void deprecation(const(char)* format, ...) | { 22| va_list args; 22| va_start(args, format); 22| .vdeprecation(token.loc, format, args); 22| va_end(args); | } | | /********************************************* | * parse: | * #line linnum [filespec] | * also allow __LINE__ for linnum, and __FILE__ for filespec | */ | private void poundLine() | { 130| auto linnum = this.scanloc.linnum; 130| const(char)* filespec = null; 130| const loc = this.loc(); 130| Token tok; 130| scan(&tok); 133| if (tok.value == TOK.int32Literal || tok.value == TOK.int64Literal) | { 128| const lin = cast(int)(tok.unsvalue - 1); 128| if (lin != tok.unsvalue - 1) 1| error("line number `%lld` out of range", cast(ulong)tok.unsvalue); | else 127| linnum = lin; | } 2| else if (tok.value == TOK.line) | { | } | else 1| goto Lerr; 155| while (1) | { 155| switch (*p) | { 000000000| case 0: 000000000| case 0x1A: 125| case '\n': | Lnewline: 125| if (!inTokenStringConstant) | { 122| this.scanloc.linnum = linnum; 122| if (filespec) 9| this.scanloc.filename = filespec; | } 125| return; 000000000| case '\r': 000000000| p++; 000000000| if (*p != '\n') | { 000000000| p--; 000000000| goto Lnewline; | } 000000000| continue; 15| case ' ': 15| case '\t': 15| case '\v': 15| case '\f': 15| p++; 15| continue; // skip white space 4| case '_': 4| if (memcmp(p, "__FILE__".ptr, 8) == 0) | { 1| p += 8; 1| filespec = mem.xstrdup(scanloc.filename); 1| continue; | } 3| goto Lerr; 11| case '"': 11| if (filespec) 1| goto Lerr; 10| stringbuffer.setsize(0); 10| p++; 85| while (1) | { 85| uint c; 85| c = *p; 85| switch (c) | { 000000000| case '\n': 000000000| case '\r': 000000000| case 0: 000000000| case 0x1A: 000000000| goto Lerr; 10| case '"': 10| stringbuffer.writeByte(0); 10| filespec = mem.xstrdup(cast(const(char)*)stringbuffer[].ptr); 10| p++; 10| break; 75| default: 75| if (c & 0x80) | { 000000000| uint u = decodeUTF(); 000000000| if (u == PS || u == LS) 000000000| goto Lerr; | } 75| stringbuffer.writeByte(c); 75| p++; 75| continue; | } 10| break; | } 10| continue; 000000000| default: 000000000| if (*p & 0x80) | { 000000000| uint u = decodeUTF(); 000000000| if (u == PS || u == LS) 000000000| goto Lnewline; | } 000000000| goto Lerr; | } | } | Lerr: 5| 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. | */ | private uint decodeUTF() | { 310119| const s = p; 310119| assert(*s & 0x80); | // Check length of remaining string up to 4 UTF-8 characters 310119| size_t len; 3411309| for (len = 1; len < 4 && s[len]; len++) | { | } 310119| size_t idx = 0; 310119| dchar u; 310119| const msg = utf_decodeChar(s[0 .. len], idx, u); 310119| p += idx - 1; 310119| if (msg) | { 1| error("%.*s", cast(int)msg.length, msg.ptr); | } 310119| 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. | * | * If newParagraph is true, an extra newline will be | * added between adjoining doc comments. | */ | private void getDocComment(Token* t, uint lineComment, bool newParagraph) pure | { | /* ct tells us which kind of comment it is: '/', '*', or '+' | */ 686| const ct = t.ptr[2]; | /* Start of comment text skips over / * *, / + +, or / / / | */ 686| const(char)* q = t.ptr + 3; // start of comment text 686| const(char)* qend = p; 1210| if (ct == '*' || ct == '+') 185| qend -= 2; | /* Scan over initial row of ****'s or ++++'s or ////'s | */ 1816| for (; q < qend; q++) | { 1038| if (*q != ct) 473| break; | } | /* Remove leading spaces until start of the comment | */ 686| int linestart = 0; 686| if (ct == '/') | { 1649| while (q < qend && (*q == ' ' || *q == '\t')) 287| ++q; | } 185| else if (q < qend) | { 185| if (*q == '\r') | { 000000000| ++q; 000000000| if (q < qend && *q == '\n') 000000000| ++q; 000000000| linestart = 1; | } 185| else if (*q == '\n') | { 97| ++q; 97| linestart = 1; | } | } | /* Remove trailing row of ****'s or ++++'s | */ 686| if (ct != '/') | { 241| for (; q < qend; qend--) | { 213| if (qend[-1] != ct) 185| break; | } | } | /* Comment is now [q .. qend]. | * Canonicalize it into buf[]. | */ 1372| OutBuffer buf; | | void trimTrailingWhitespace() | { 1757| const s = buf[]; 1757| auto len = s.length; 5537| while (len && (s[len - 1] == ' ' || s[len - 1] == '\t')) 455| --len; 1757| buf.setsize(len); | } | 38676| for (; q < qend; q++) | { 18995| char c = *q; 18995| switch (c) | { 305| case '*': 349| case '+': 622| if (linestart && c == ct) | { 240| linestart = 0; | /* Trim preceding whitespace up to preceding \n | */ 240| trimTrailingWhitespace(); 240| continue; | } 109| break; 3020| case ' ': 3122| case '\t': 3122| break; 000000000| case '\r': 000000000| if (q[1] == '\n') 000000000| continue; // skip the \r 000000000| goto Lnewline; 14693| default: 14693| if (c == 226) | { | // If LS or PS 15| if (q[1] == 128 && (q[2] == 168 || q[2] == 169)) | { 000000000| q += 2; 000000000| goto Lnewline; | } | } 14693| linestart = 0; 14693| break; | Lnewline: 000000000| c = '\n'; // replace all newlines with \n 000000000| goto case; 831| case '\n': 831| linestart = 1; | /* Trim trailing whitespace | */ 831| trimTrailingWhitespace(); 831| break; | } 18755| buf.writeByte(c); | } | /* Trim trailing whitespace (if the last line does not have newline) | */ 686| trimTrailingWhitespace(); | | // Always end with a newline 686| const s = buf[]; 1093| if (s.length == 0 || s[$ - 1] != '\n') 590| buf.writeByte('\n'); | | // It's a line comment if the start of the doc comment comes | // after other non-whitespace on the same line. 1538| auto dc = (lineComment && anyToken) ? &t.lineComment : &t.blockComment; | // Combine with previous doc comment, if any 686| if (*dc) 12| *dc = combineComments(*dc, buf[], newParagraph).toDString(); | else 674| *dc = buf.extractSlice(true); | } | | /******************************************** | * Combine two document comments into one, | * separated by an extra newline if newParagraph is true. | */ | static const(char)* combineComments(const(char)[] c1, const(char)[] c2, bool newParagraph) pure | { | //printf("Lexer::combineComments('%s', '%s', '%i')\n", c1, c2, newParagraph); 24473620| const(int) newParagraphSize = newParagraph ? 1 : 0; // Size of the combining '\n' 12236810| if (!c1) 12236213| return c2.ptr; 597| if (!c2) 578| return c1.ptr; | 19| int insertNewLine = 0; 38| if (c1.length && c1[$ - 1] != '\n') 000000000| insertNewLine = 1; 19| const retSize = c1.length + insertNewLine + newParagraphSize + c2.length; 19| auto p = cast(char*)mem.xmalloc_noscan(retSize + 1); 19| p[0 .. c1.length] = c1[]; 19| if (insertNewLine) 000000000| p[c1.length] = '\n'; 19| if (newParagraph) 13| p[c1.length + insertNewLine] = '\n'; 19| p[retSize - c2.length .. retSize] = c2[]; 19| p[retSize] = 0; 19| return p; | } | |private: | void endOfLine() pure @nogc @safe | { 57104269| scanloc.linnum++; 57104269| line = p; | } |} | |/// Support for `__DATE__`, `__TIME__`, and `__TIMESTAMP__` |private struct TimeStampInfo |{ | private __gshared bool initdone = false; | | // Note: Those properties need to be guarded by a call to `init` | // The API isn't safe, and quite brittle, but it was left this way | // over performance concerns. | // This is currently only called once, from the lexer. | __gshared char[11 + 1] date; | __gshared char[8 + 1] time; | __gshared char[24 + 1] timestamp; | | public static void initialize(const ref Loc loc) nothrow | { 3029836| if (initdone) 3026415| return; | 3421| initdone = true; 3421| time_t ct; | // https://issues.dlang.org/show_bug.cgi?id=20444 3421| if (auto p = getenv("SOURCE_DATE_EPOCH")) | { 1| if (!ct.parseDigits(p.toDString())) 000000000| error(loc, "Value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); | } | else 3420| .time(&ct); 3421| const p = ctime(&ct); 3421| assert(p); 3421| sprintf(&date[0], "%.6s %.4s", p + 4, p + 20); 3421| sprintf(&time[0], "%.8s", p + 11); 3421| sprintf(×tamp[0], "%.24s", p); | } |} | |unittest |{ | import dmd.console; | nothrow bool assertDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, | const(char)* format, va_list ap, const(char)* p1, const(char)* p2) | { | assert(0); | } | diagnosticHandler = &assertDiagnosticHandler; | | static void test(T)(string sequence, T expected) | { | auto p = cast(const(char)*)sequence.ptr; | assert(expected == Lexer.escapeSequence(Loc.initial, p)); | assert(p == sequence.ptr + sequence.length); | } | | test(`'`, '\''); | test(`"`, '"'); | test(`?`, '?'); | test(`\`, '\\'); | test(`0`, '\0'); | test(`a`, '\a'); | test(`b`, '\b'); | test(`f`, '\f'); | test(`n`, '\n'); | test(`r`, '\r'); | test(`t`, '\t'); | test(`v`, '\v'); | | test(`x00`, 0x00); | test(`xff`, 0xff); | test(`xFF`, 0xff); | test(`xa7`, 0xa7); | test(`x3c`, 0x3c); | test(`xe2`, 0xe2); | | test(`1`, '\1'); | test(`42`, '\42'); | test(`357`, '\357'); | | test(`u1234`, '\u1234'); | test(`uf0e4`, '\uf0e4'); | | test(`U0001f603`, '\U0001f603'); | | test(`"`, '"'); | test(`<`, '<'); | test(`>`, '>'); | | diagnosticHandler = null; |} |unittest |{ | import dmd.console; | string expected; | bool gotError; | | nothrow bool expectDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, | const(char)* format, va_list ap, const(char)* p1, const(char)* p2) | { | assert(cast(Classification)headerColor == Classification.error); | | gotError = true; | char[100] buffer = void; | auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)]; | assert(expected == actual); | return true; | } | | diagnosticHandler = &expectDiagnosticHandler; | | void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength) | { | uint errors = global.errors; | gotError = false; | expected = expectedError; | auto p = cast(const(char)*)sequence.ptr; | auto actualReturnValue = Lexer.escapeSequence(Loc.initial, p); | assert(gotError); | assert(expectedReturnValue == actualReturnValue); | | auto actualScanLength = p - sequence.ptr; | assert(expectedScanLength == actualScanLength); | global.errors = errors; | } | | test("c", `undefined escape sequence \c`, 'c', 1); | test("!", `undefined escape sequence \!`, '!', 1); | | test("x1", `escape hex sequence has 1 hex digits instead of 2`, '\x01', 2); | | test("u1" , `escape hex sequence has 1 hex digits instead of 4`, 0x1, 2); | test("u12" , `escape hex sequence has 2 hex digits instead of 4`, 0x12, 3); | test("u123", `escape hex sequence has 3 hex digits instead of 4`, 0x123, 4); | | test("U0" , `escape hex sequence has 1 hex digits instead of 8`, 0x0, 2); | test("U00" , `escape hex sequence has 2 hex digits instead of 8`, 0x00, 3); | test("U000" , `escape hex sequence has 3 hex digits instead of 8`, 0x000, 4); | test("U0000" , `escape hex sequence has 4 hex digits instead of 8`, 0x0000, 5); | test("U0001f" , `escape hex sequence has 5 hex digits instead of 8`, 0x0001f, 6); | test("U0001f6" , `escape hex sequence has 6 hex digits instead of 8`, 0x0001f6, 7); | test("U0001f60", `escape hex sequence has 7 hex digits instead of 8`, 0x0001f60, 8); | | test("ud800" , `invalid UTF character \U0000d800`, '?', 5); | test("udfff" , `invalid UTF character \U0000dfff`, '?', 5); | test("U00110000", `invalid UTF character \U00110000`, '?', 9); | | test("xg0" , `undefined escape hex sequence \xg`, 'g', 2); | test("ug000" , `undefined escape hex sequence \ug`, 'g', 2); | test("Ug0000000", `undefined escape hex sequence \Ug`, 'g', 2); | | test("&BAD;", `unnamed character entity &BAD;` , '?', 5); | test(""", `unterminated named entity "`, '?', 5); | | test("400", `escape octal sequence \400 is larger than \377`, 0x100, 3); | | diagnosticHandler = null; |} src/dmd/lexer.d is 88% covered <<<<<< EOF # path=./src-dmd-libmscoff.lst |/** | * A library in the COFF format, used on 32-bit and 64-bit Windows targets. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/libmscoff.d, _libmscoff.d) | * Documentation: https://dlang.org/phobos/dmd_libmscoff.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/libmscoff.d | */ | |module dmd.libmscoff; | |version(Windows): | |import core.stdc.stdlib; |import core.stdc.string; |import core.stdc.time; |import core.stdc.stdio; |import core.stdc.string; | |import core.sys.windows.stat; | |import dmd.globals; |import dmd.lib; |import dmd.utils; | |import dmd.root.array; |import dmd.root.file; |import dmd.root.filename; |import dmd.root.outbuffer; |import dmd.root.port; |import dmd.root.rmem; |import dmd.root.string; |import dmd.root.stringtable; | |import dmd.scanmscoff; | |// Entry point (only public symbol in this module). |public extern (C++) Library LibMSCoff_factory() |{ | return new LibMSCoff(); |} | |private: // for the remainder of this module | |enum LOG = false; | |alias stat_t = struct_stat; | |struct MSCoffObjSymbol |{ | const(char)[] name; // still has a terminating 0 | MSCoffObjModule* om; | | /// Predicate for `Array.sort`for name comparison | static int name_pred (scope const MSCoffObjSymbol** ppe1, scope const MSCoffObjSymbol** ppe2) nothrow @nogc pure | { | return dstrcmp((**ppe1).name, (**ppe2).name); | } | | /// Predicate for `Array.sort`for offset comparison | static int offset_pred (scope const MSCoffObjSymbol** ppe1, scope const MSCoffObjSymbol** ppe2) nothrow @nogc pure | { | return (**ppe1).om.offset - (**ppe2).om.offset; | } |} | |alias MSCoffObjModules = Array!(MSCoffObjModule*); |alias MSCoffObjSymbols = Array!(MSCoffObjSymbol*); | |final class LibMSCoff : Library |{ | MSCoffObjModules objmodules; // MSCoffObjModule[] | MSCoffObjSymbols objsymbols; // MSCoffObjSymbol[] | | /*************************************** | * Add object module or library to the library. | * Examine the buffer to see which it is. | * If the buffer is NULL, use module_name as the file name | * and load the file. | */ | override void addObject(const(char)[] module_name, const ubyte[] buffer) | { | static if (LOG) | { | printf("LibMSCoff::addObject(%.*s)\n", cast(int)module_name.length, | module_name.ptr); | } | | void corrupt(int reason) | { | error("corrupt MS Coff object module %.*s %d", | cast(int)module_name.length, module_name.ptr, reason); | } | | int fromfile = 0; | auto buf = buffer.ptr; | auto buflen = buffer.length; | if (!buf) | { | assert(module_name.length, "No module nor buffer provided to `addObject`"); | // read file and take buffer ownership | auto data = readFile(Loc.initial, module_name).extractSlice(); | buf = data.ptr; | buflen = data.length; | fromfile = 1; | } | if (buflen < 16) | { | static if (LOG) | { | printf("buf = %p, buflen = %d\n", buf, buflen); | } | return corrupt(__LINE__); | } | if (memcmp(buf, "!\n".ptr, 8) == 0) | { | /* It's a library file. | * Pull each object module out of the library and add it | * to the object module array. | */ | static if (LOG) | { | printf("archive, buf = %p, buflen = %d\n", buf, buflen); | } | MSCoffLibHeader* flm = null; // first linker member | MSCoffLibHeader* slm = null; // second linker member | uint number_of_members = 0; | uint* member_file_offsets = null; | uint number_of_symbols = 0; | ushort* indices = null; | char* string_table = null; | size_t string_table_length = 0; | MSCoffLibHeader* lnm = null; // longname member | char* longnames = null; | size_t longnames_length = 0; | size_t offset = 8; | size_t mstart = objmodules.dim; | while (1) | { | offset = (offset + 1) & ~1; // round to even boundary | if (offset >= buflen) | break; | if (offset + MSCoffLibHeader.sizeof >= buflen) | return corrupt(__LINE__); | MSCoffLibHeader* header = cast(MSCoffLibHeader*)(cast(ubyte*)buf + offset); | offset += MSCoffLibHeader.sizeof; | char* endptr = null; | uint size = strtoul(cast(char*)header.file_size, &endptr, 10); | if (endptr >= header.file_size.ptr + 10 || *endptr != ' ') | return corrupt(__LINE__); | if (offset + size > buflen) | return corrupt(__LINE__); | //printf("header.object_name = '%.*s'\n", cast(int)MSCOFF_OBJECT_NAME_SIZE, header.object_name); | if (memcmp(cast(char*)header.object_name, cast(char*)"/ ", MSCOFF_OBJECT_NAME_SIZE) == 0) | { | if (!flm) | { | // First Linker Member, which is ignored | flm = header; | } | else if (!slm) | { | // Second Linker Member, which we require even though the format doesn't require it | slm = header; | if (size < 4 + 4) | return corrupt(__LINE__); | number_of_members = Port.readlongLE(cast(char*)buf + offset); | member_file_offsets = cast(uint*)(cast(char*)buf + offset + 4); | if (size < 4 + number_of_members * 4 + 4) | return corrupt(__LINE__); | number_of_symbols = Port.readlongLE(cast(char*)buf + offset + 4 + number_of_members * 4); | indices = cast(ushort*)(cast(char*)buf + offset + 4 + number_of_members * 4 + 4); | string_table = cast(char*)(cast(char*)buf + offset + 4 + number_of_members * 4 + 4 + number_of_symbols * 2); | if (size <= (4 + number_of_members * 4 + 4 + number_of_symbols * 2)) | return corrupt(__LINE__); | string_table_length = size - (4 + number_of_members * 4 + 4 + number_of_symbols * 2); | /* The number of strings in the string_table must be number_of_symbols; check it | * The strings must also be in ascending lexical order; not checked. | */ | size_t i = 0; | for (uint n = 0; n < number_of_symbols; n++) | { | while (1) | { | if (i >= string_table_length) | return corrupt(__LINE__); | if (!string_table[i++]) | break; | } | } | if (i != string_table_length) | return corrupt(__LINE__); | } | } | else if (memcmp(cast(char*)header.object_name, cast(char*)"// ", MSCOFF_OBJECT_NAME_SIZE) == 0) | { | if (!lnm) | { | lnm = header; | longnames = cast(char*)buf + offset; | longnames_length = size; | } | } | else | { | if (!slm) | return corrupt(__LINE__); | version (none) | { | // Microsoft Spec says longnames member must appear, but Microsoft Lib says otherwise | if (!lnm) | return corrupt(__LINE__); | } | auto om = new MSCoffObjModule(); | // Include MSCoffLibHeader in base[0..length], so we don't have to repro it | om.base = cast(ubyte*)buf + offset - MSCoffLibHeader.sizeof; | om.length = cast(uint)(size + MSCoffLibHeader.sizeof); | om.offset = 0; | if (header.object_name[0] == '/') | { | /* Pick long name out of longnames[] | */ | uint foff = strtoul(cast(char*)header.object_name + 1, &endptr, 10); | uint i; | for (i = 0; 1; i++) | { | if (foff + i >= longnames_length) | return corrupt(__LINE__); | char c = longnames[foff + i]; | if (c == 0) | break; | } | char* oname = cast(char*)Mem.check(malloc(i + 1)); | memcpy(oname, longnames + foff, i); | oname[i] = 0; | om.name = oname[0 .. i]; | //printf("\tname = '%s'\n", om.name); | } | else | { | /* Pick short name out of header | */ | char* oname = cast(char*)Mem.check(malloc(MSCOFF_OBJECT_NAME_SIZE)); | int i; | for (i = 0; 1; i++) | { | if (i == MSCOFF_OBJECT_NAME_SIZE) | return corrupt(__LINE__); | char c = header.object_name[i]; | if (c == '/') | { | oname[i] = 0; | break; | } | oname[i] = c; | } | om.name = oname[0 .. i]; | } | om.file_time = strtoul(cast(char*)header.file_time, &endptr, 10); | om.user_id = strtoul(cast(char*)header.user_id, &endptr, 10); | om.group_id = strtoul(cast(char*)header.group_id, &endptr, 10); | om.file_mode = strtoul(cast(char*)header.file_mode, &endptr, 8); | om.scan = 0; // don't scan object module for symbols | objmodules.push(om); | } | offset += size; | } | if (offset != buflen) | return corrupt(__LINE__); | /* Scan the library's symbol table, and insert it into our own. | * We use this instead of rescanning the object module, because | * the library's creator may have a different idea of what symbols | * go into the symbol table than we do. | * This is also probably faster. | */ | if (!slm) | return corrupt(__LINE__); | char* s = string_table; | for (uint i = 0; i < number_of_symbols; i++) | { | const(char)[] name = s.toDString(); | s += name.length + 1; | uint memi = indices[i] - 1; | if (memi >= number_of_members) | return corrupt(__LINE__); | uint moff = member_file_offsets[memi]; | for (size_t m = mstart; 1; m++) | { | if (m == objmodules.dim) | return corrupt(__LINE__); // didn't find it | MSCoffObjModule* om = objmodules[m]; | //printf("\tom offset = x%x\n", (char *)om.base - (char *)buf); | if (moff == cast(char*)om.base - cast(char*)buf) | { | addSymbol(om, name, 1); | //if (mstart == m) | // mstart++; | break; | } | } | } | return; | } | /* It's an object module | */ | auto om = new MSCoffObjModule(); | om.base = cast(ubyte*)buf; | om.length = cast(uint)buflen; | om.offset = 0; | // remove path, but not extension | om.name = global.params.preservePaths ? module_name : FileName.name(module_name); | om.scan = 1; | if (fromfile) | { | stat_t statbuf; | int i = module_name.toCStringThen!(name => stat(name.ptr, &statbuf)); | if (i == -1) // error, errno is set | return corrupt(__LINE__); | om.file_time = statbuf.st_ctime; | om.user_id = statbuf.st_uid; | om.group_id = statbuf.st_gid; | om.file_mode = statbuf.st_mode; | } | else | { | /* Mock things up for the object module file that never was | * actually written out. | */ | time_t file_time = 0; | time(&file_time); | om.file_time = cast(long)file_time; | om.user_id = 0; // meaningless on Windows | om.group_id = 0; // meaningless on Windows | om.file_mode = (1 << 15) | (6 << 6) | (4 << 3) | (4 << 0); // 0100644 | } | objmodules.push(om); | } | | /*****************************************************************************/ | | void addSymbol(MSCoffObjModule* om, const(char)[] name, int pickAny = 0) | { | static if (LOG) | { | printf("LibMSCoff::addSymbol(%s, %s, %d)\n", om.name.ptr, name, pickAny); | } | auto os = new MSCoffObjSymbol(); | os.name = xarraydup(name); | os.om = om; | objsymbols.push(os); | } | |private: | /************************************ | * Scan single object module for dictionary symbols. | * Send those symbols to LibMSCoff::addSymbol(). | */ | void scanObjModule(MSCoffObjModule* om) | { | static if (LOG) | { | printf("LibMSCoff::scanObjModule(%s)\n", om.name.ptr); | } | | extern (D) void addSymbol(const(char)[] name, int pickAny) | { | this.addSymbol(om, name, pickAny); | } | | scanMSCoffObjModule(&addSymbol, om.base[0 .. om.length], om.name.ptr, loc); | } | | /*****************************************************************************/ | /*****************************************************************************/ | /********************************************** | * Create and write library to libbuf. | * The library consists of: | * !\n | * header | * 1st Linker Member | * Header | * 2nd Linker Member | * Header | * Longnames Member | * object modules... | */ | protected override void WriteLibToBuffer(OutBuffer* libbuf) | { | static if (LOG) | { | printf("LibElf::WriteLibToBuffer()\n"); | } | assert(MSCoffLibHeader.sizeof == 60); | /************* Scan Object Modules for Symbols ******************/ | for (size_t i = 0; i < objmodules.dim; i++) | { | MSCoffObjModule* om = objmodules[i]; | if (om.scan) | { | scanObjModule(om); | } | } | /************* Determine longnames size ******************/ | /* The longnames section is where we store long file names. | */ | uint noffset = 0; | for (size_t i = 0; i < objmodules.dim; i++) | { | MSCoffObjModule* om = objmodules[i]; | size_t len = om.name.length; | if (len >= MSCOFF_OBJECT_NAME_SIZE) | { | om.name_offset = noffset; | noffset += len + 1; | } | else | om.name_offset = -1; | } | static if (LOG) | { | printf("\tnoffset = x%x\n", noffset); | } | /************* Determine string table length ******************/ | size_t slength = 0; | for (size_t i = 0; i < objsymbols.dim; i++) | { | MSCoffObjSymbol* os = objsymbols[i]; | slength += os.name.length + 1; | } | /************* Offset of first module ***********************/ | size_t moffset = 8; // signature | size_t firstLinkerMemberOffset = moffset; | moffset += MSCoffLibHeader.sizeof + 4 + objsymbols.dim * 4 + slength; // 1st Linker Member | moffset += moffset & 1; | size_t secondLinkerMemberOffset = moffset; | moffset += MSCoffLibHeader.sizeof + 4 + objmodules.dim * 4 + 4 + objsymbols.dim * 2 + slength; | moffset += moffset & 1; | size_t LongnamesMemberOffset = moffset; | moffset += MSCoffLibHeader.sizeof + noffset; // Longnames Member size | static if (LOG) | { | printf("\tmoffset = x%x\n", moffset); | } | /************* Offset of each module *************************/ | for (size_t i = 0; i < objmodules.dim; i++) | { | MSCoffObjModule* om = objmodules[i]; | moffset += moffset & 1; | om.offset = cast(uint)moffset; | if (om.scan) | moffset += MSCoffLibHeader.sizeof + om.length; | else | moffset += om.length; | } | libbuf.reserve(moffset); | /************* Write the library ******************/ | libbuf.write("!\n"); | MSCoffObjModule om; | om.name_offset = -1; | om.base = null; | om.length = cast(uint)(4 + objsymbols.dim * 4 + slength); | om.offset = 8; | om.name = ""; | time_t file_time = 0; | .time(&file_time); | om.file_time = cast(long)file_time; | om.user_id = 0; | om.group_id = 0; | om.file_mode = 0; | /*** Write out First Linker Member ***/ | assert(libbuf.length == firstLinkerMemberOffset); | MSCoffLibHeader h; | MSCoffOmToHeader(&h, &om); | libbuf.write((&h)[0 .. 1]); | char[4] buf; | Port.writelongBE(cast(uint)objsymbols.dim, buf.ptr); | libbuf.write(buf[0 .. 4]); | // Sort objsymbols[] in module offset order | objsymbols.sort!(MSCoffObjSymbol.offset_pred); | uint lastoffset; | for (size_t i = 0; i < objsymbols.dim; i++) | { | MSCoffObjSymbol* os = objsymbols[i]; | //printf("objsymbols[%d] = '%s', offset = %u\n", i, os.name, os.om.offset); | if (i) | { | // Should be sorted in module order | assert(lastoffset <= os.om.offset); | } | lastoffset = os.om.offset; | Port.writelongBE(lastoffset, buf.ptr); | libbuf.write(buf[0 .. 4]); | } | for (size_t i = 0; i < objsymbols.dim; i++) | { | MSCoffObjSymbol* os = objsymbols[i]; | libbuf.writestring(os.name); | libbuf.writeByte(0); | } | /*** Write out Second Linker Member ***/ | if (libbuf.length & 1) | libbuf.writeByte('\n'); | assert(libbuf.length == secondLinkerMemberOffset); | om.length = cast(uint)(4 + objmodules.dim * 4 + 4 + objsymbols.dim * 2 + slength); | MSCoffOmToHeader(&h, &om); | libbuf.write((&h)[0 .. 1]); | Port.writelongLE(cast(uint)objmodules.dim, buf.ptr); | libbuf.write(buf[0 .. 4]); | for (size_t i = 0; i < objmodules.dim; i++) | { | MSCoffObjModule* om2 = objmodules[i]; | om2.index = cast(ushort)i; | Port.writelongLE(om2.offset, buf.ptr); | libbuf.write(buf[0 .. 4]); | } | Port.writelongLE(cast(uint)objsymbols.dim, buf.ptr); | libbuf.write(buf[0 .. 4]); | // Sort objsymbols[] in lexical order | objsymbols.sort!(MSCoffObjSymbol.name_pred); | for (size_t i = 0; i < objsymbols.dim; i++) | { | MSCoffObjSymbol* os = objsymbols[i]; | Port.writelongLE(os.om.index + 1, buf.ptr); | libbuf.write(buf[0 .. 2]); | } | for (size_t i = 0; i < objsymbols.dim; i++) | { | MSCoffObjSymbol* os = objsymbols[i]; | libbuf.writestring(os.name); | libbuf.writeByte(0); | } | /*** Write out longnames Member ***/ | if (libbuf.length & 1) | libbuf.writeByte('\n'); | //printf("libbuf %x longnames %x\n", (int)libbuf.length, (int)LongnamesMemberOffset); | assert(libbuf.length == LongnamesMemberOffset); | // header | memset(&h, ' ', MSCoffLibHeader.sizeof); | h.object_name[0] = '/'; | h.object_name[1] = '/'; | size_t len = sprintf(h.file_size.ptr, "%u", noffset); | assert(len < 10); | h.file_size[len] = ' '; | h.trailer[0] = '`'; | h.trailer[1] = '\n'; | libbuf.write((&h)[0 .. 1]); | for (size_t i = 0; i < objmodules.dim; i++) | { | MSCoffObjModule* om2 = objmodules[i]; | if (om2.name_offset >= 0) | { | libbuf.writestring(om2.name); | libbuf.writeByte(0); | } | } | /* Write out each of the object modules | */ | for (size_t i = 0; i < objmodules.dim; i++) | { | MSCoffObjModule* om2 = objmodules[i]; | if (libbuf.length & 1) | libbuf.writeByte('\n'); // module alignment | //printf("libbuf %x om %x\n", (int)libbuf.length, (int)om2.offset); | assert(libbuf.length == om2.offset); | if (om2.scan) | { | MSCoffOmToHeader(&h, om2); | libbuf.write((&h)[0 .. 1]); // module header | libbuf.write(om2.base[0 .. om2.length]); // module contents | } | else | { | // Header is included in om.base[0..length] | libbuf.write(om2.base[0 .. om2.length]); // module contents | } | } | static if (LOG) | { | printf("moffset = x%x, libbuf.length = x%x\n", cast(uint)moffset, cast(uint)libbuf.length); | } | assert(libbuf.length == moffset); | } |} | |/*****************************************************************************/ |/*****************************************************************************/ |struct MSCoffObjModule |{ | ubyte* base; // where are we holding it in memory | uint length; // in bytes | uint offset; // offset from start of library | ushort index; // index in Second Linker Member | const(char)[] name; // module name (file name) terminated with 0 | int name_offset; // if not -1, offset into string table of name | long file_time; // file time | uint user_id; | uint group_id; | uint file_mode; | int scan; // 1 means scan for symbols |} | |enum MSCOFF_OBJECT_NAME_SIZE = 16; | |struct MSCoffLibHeader |{ | char[MSCOFF_OBJECT_NAME_SIZE] object_name; | char[12] file_time; | char[6] user_id; | char[6] group_id; | char[8] file_mode; // in octal | char[10] file_size; | char[2] trailer; |} | |extern (C++) void MSCoffOmToHeader(MSCoffLibHeader* h, MSCoffObjModule* om) |{ | size_t len; | if (om.name_offset == -1) | { | len = om.name.length; | memcpy(h.object_name.ptr, om.name.ptr, len); | h.object_name[len] = '/'; | } | else | { | len = sprintf(h.object_name.ptr, "/%d", om.name_offset); | h.object_name[len] = ' '; | } | assert(len < MSCOFF_OBJECT_NAME_SIZE); | memset(h.object_name.ptr + len + 1, ' ', MSCOFF_OBJECT_NAME_SIZE - (len + 1)); | /* In the following sprintf's, don't worry if the trailing 0 | * that sprintf writes goes off the end of the field. It will | * write into the next field, which we will promptly overwrite | * anyway. (So make sure to write the fields in ascending order.) | */ | len = sprintf(h.file_time.ptr, "%llu", cast(long)om.file_time); | assert(len <= 12); | memset(h.file_time.ptr + len, ' ', 12 - len); | // Match what MS tools do (set to all blanks) | memset(h.user_id.ptr, ' ', (h.user_id).sizeof); | memset(h.group_id.ptr, ' ', (h.group_id).sizeof); | len = sprintf(h.file_mode.ptr, "%o", om.file_mode); | assert(len <= 8); | memset(h.file_mode.ptr + len, ' ', 8 - len); | len = sprintf(h.file_size.ptr, "%u", om.length); | assert(len <= 10); | memset(h.file_size.ptr + len, ' ', 10 - len); | h.trailer[0] = '`'; | h.trailer[1] = '\n'; |} src/dmd/libmscoff.d has no code <<<<<< EOF # path=./src-dmd-backend-cgelem.lst |/** | * Compiler implementation of the | * $(LINK2 http://www.dlang.org, D programming language). | * | * Does strength reduction optimizations on the elem trees, | * i.e. rewriting trees to less expensive trees. | * | * Copyright: Copyright (C) 1985-1998 by Symantec | * Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cgelem.d, backend/cgelem.d) | * Documentation: https://dlang.org/phobos/dmd_backend_cgelem.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/cgelem.d | * Add coverage tests to https://github.com/dlang/dmd/blob/master/test/runnable/testcgelem.d | */ | |module dmd.backend.cgelem; | |version (SPP) |{ |} |else |{ | |import core.stdc.stdio; |import core.stdc.stdlib; |import core.stdc.string; | |import dmd.backend.cc; |import dmd.backend.cdef; |import dmd.backend.code_x86; |import dmd.backend.oper; |import dmd.backend.global; |import dmd.backend.goh; |import dmd.backend.el; |import dmd.backend.outbuf; |import dmd.backend.rtlsym; |import dmd.backend.ty; |import dmd.backend.type; | |import dmd.backend.dlist; |import dmd.backend.dvec; | |version (SCPP) | import tk.mem; |else |{ | extern (C) | { | nothrow void *mem_calloc(size_t); | } |} | |extern (C++): | |nothrow: | |elem * evalu8(elem *e, goal_t goal); | | |/* Masks so we can easily check size */ |enum CHARMASK = 0xFF; |enum SHORTMASK = 0xFFFF; |enum INTMASK = SHORTMASK; |enum LONGMASK = 0xFFFFFFFF; | |/* Common constants often checked for */ |enum LLONGMASK = 0xFFFFFFFFFFFFFFFFL; |enum ZEROLL = 0L; | |private __gshared |{ | bool again; | bool topair; | tym_t global_tyf; |} | 4959338|private bool cnst(const elem* e) { return e.Eoper == OPconst; } |int REGSIZE(); | |version (MARS) |{ | import dmd.backend.errors; |} | |/***************************** | */ | |private elem * cgel_lvalue(elem *e) |{ | //printf("cgel_lvalue()\n"); elem_print(e); 17762| elem *e1 = e.EV.E1; 17762| if (e1.Eoper == OPbit) | { 00000000| elem *e11 = e1.EV.E1; | 00000000| if (e11.Eoper == OPcomma) | { | // Replace (((e,v) bit x) op e2) with (e,((v bit x) op e2)) 00000000| e1.EV.E1 = e11.EV.E2; 00000000| e11.EV.E2 = e; 00000000| e11.Ety = e.Ety; 00000000| e11.ET = e.ET; 00000000| e = e11; 00000000| goto L1; | } 00000000| else if (OTassign(e11.Eoper)) | { | // Replace (((e op= v) bit x) op e2) with ((e op= v) , ((e bit x) op e2)) 00000000| e1.EV.E1 = el_copytree(e11.EV.E1); 00000000| e = el_bin(OPcomma,e.Ety,e11,e); 00000000| goto L1; | } | } 17762| else if (e1.Eoper == OPcomma) | { | // Replace ((e,v) op e2) with (e,(v op e2)) 17714| const op = e.Eoper; 17714| e.Eoper = OPcomma; 17714| e1.Eoper = op; 17714| e1.Ety = e.Ety; 17714| e1.ET = e.ET; 17714| e.EV.E1 = e1.EV.E1; 17714| e1.EV.E1 = e1.EV.E2; 17714| e1.EV.E2 = e.EV.E2; 17714| e.EV.E2 = e1; 17714| goto L1; | } 48| else if (OTassign(e1.Eoper)) | { | // Replace ((e op= v) op e2) with ((e op= v) , (e op e2)) 00000000| e.EV.E1 = el_copytree(e1.EV.E1); 00000000| e = el_bin(OPcomma,e.Ety,e1,e); | L1: 17714| e = optelem(e,GOALvalue); | } 17762| return e; |} | | |/****************************** | * Scan down commas. | */ | |private elem * elscancommas(elem *e) |{ 205895| while (e.Eoper == OPcomma 204215| || e.Eoper == OPinfo | ) 1680| e = e.EV.E2; 204215| return e; |} | |/************************* | * Returns: | * true if elem is the constant 1. | */ | |int elemisone(elem *e) |{ 74487| if (e.Eoper == OPconst) | { 74480| switch (tybasic(e.Ety)) | { 49| case TYchar: 87| case TYuchar: 151| case TYschar: 151| case TYchar16: 171| case TYshort: 190| case TYushort: 12813| case TYint: 15740| case TYuint: 15740| case TYlong: 15740| case TYulong: 22476| case TYllong: 72921| case TYullong: 72921| case TYnullptr: 72921| case TYsptr: 72921| case TYcptr: 72921| case TYhptr: 72921| case TYfptr: 72921| case TYvptr: 72921| case TYnptr: 72921| case TYimmutPtr: 72921| case TYsharePtr: 72921| case TYrestrictPtr: 72921| case TYfgPtr: 72921| case TYbool: 72921| case TYwchar_t: 72921| case TYdchar: 72921| if (el_tolong(e) != 1) 52212| goto nomatch; 20709| break; 501| case TYldouble: 552| case TYildouble: 552| if (e.EV.Vldouble != 1) 197| goto nomatch; 355| break; 630| case TYdouble: 663| case TYidouble: 663| case TYdouble_alias: 663| if (e.EV.Vdouble != 1) 299| goto nomatch; 364| break; 235| case TYfloat: 244| case TYifloat: 244| if (e.EV.Vfloat != 1) 20| goto nomatch; 224| break; 100| default: 100| goto nomatch; | } 21652| return true; | } | |nomatch: 52835| return false; |} | |/************************* | * Returns: true if elem is the constant -1. | */ | |int elemisnegone(elem *e) |{ 15432| if (e.Eoper == OPconst) | { 15432| switch (tybasic(e.Ety)) | { 00000000| case TYchar: 00000000| case TYuchar: 10| case TYschar: 10| case TYchar16: 10| case TYshort: 10| case TYushort: 6244| case TYint: 7159| case TYuint: 7159| case TYlong: 7159| case TYulong: 8392| case TYllong: 14821| case TYullong: 14821| case TYnullptr: 14821| case TYnptr: 14821| case TYsptr: 14821| case TYcptr: 14821| case TYhptr: 14821| case TYfptr: 14821| case TYvptr: 14821| case TYimmutPtr: 14821| case TYsharePtr: 14821| case TYrestrictPtr: 14821| case TYfgPtr: 14821| case TYbool: 14821| case TYwchar_t: 14821| case TYdchar: 14821| if (el_tolong(e) != -1) 14819| goto nomatch; 2| break; 152| case TYldouble: | //case TYildouble: 152| if (e.EV.Vldouble != -1) 152| goto nomatch; 00000000| break; 343| case TYdouble: | //case TYidouble: 343| case TYdouble_alias: 343| if (e.EV.Vdouble != -1) 341| goto nomatch; 2| break; 9| case TYfloat: | //case TYifloat: 9| if (e.EV.Vfloat != -1) 9| goto nomatch; 00000000| break; 107| default: 107| goto nomatch; | } 4| return true; | } | |nomatch: 15428| return false; |} | |/********************************** | * Swap relational operators (like if we swapped the leaves). | */ | |OPER swaprel(OPER op) |{ 60949| assert(op < OPMAX); 60949| if (OTrel(op)) 34976| op = rel_swap(op); 60949| return op; |} | |/************************** | * Replace e1 by t=e1, replace e2 by t. | */ | |private void fixside(elem **pe1,elem **pe2) |{ 9| const tym = (*pe1).Ety; 9| elem *tmp = el_alloctmp(tym); 9| *pe1 = el_bin(OPeq,tym,tmp,*pe1); 9| elem *e2 = el_copytree(tmp); 9| el_free(*pe2); 9| *pe2 = e2; |} | | | |/**************************** | * Compute the 'cost' of evaluating a elem. Could be done | * as Sethi-Ullman numbers, but that ain't worth the bother. | * We'll fake it. | */ | 3003844|private int cost(const elem* n) { return opcost[n.Eoper]; } | |/******************************* | * For floating point expressions, the cost would be the number | * of registers in the FPU stack needed. | */ | |private int fcost(const elem *e) |{ 00000000| int cost; | | //printf("fcost()\n"); 00000000| switch (e.Eoper) | { 00000000| case OPadd: 00000000| case OPmin: 00000000| case OPmul: 00000000| case OPdiv: | { 00000000| const int cost1 = fcost(e.EV.E1); 00000000| const int cost2 = fcost(e.EV.E2); 00000000| cost = cost2 + 1; 00000000| if (cost1 > cost) 00000000| cost = cost1; 00000000| break; | } | 00000000| case OPcall: 00000000| case OPucall: 00000000| cost = 8; 00000000| break; | 00000000| case OPneg: 00000000| case OPabs: 00000000| case OPtoprec: 00000000| return fcost(e.EV.E1); | 00000000| case OPvar: 00000000| case OPconst: 00000000| case OPind: 00000000| default: 00000000| return 1; | } 00000000| if (cost > 8) 00000000| cost = 8; 00000000| return cost; |} | |/******************************* | * The lvalue of an op= is a conversion operator. Since the code | * generator cannot handle this, we will have to fix it here. The | * general strategy is: | * (conv) e1 op= e2 => e1 = (conv) e1 op e2 | * Since e1 can only be evaluated once, if it is an expression we | * must use a temporary. | */ | |private elem *fixconvop(elem *e) |{ | static immutable ubyte[CNVOPMAX - CNVOPMIN + 1] invconvtab = | [ | OPbool, // OPb_8 | OPs32_d, // OPd_s32 | OPd_s32, // OPs32_d | OPs16_d, /* OPd_s16 */ | OPd_s16, /* OPs16_d */ | OPu16_d, // OPd_u16 | OPd_u16, // OPu16_d | OPu32_d, /* OPd_u32 */ | OPd_u32, /* OPu32_d */ | OPs64_d, // OPd_s64 | OPd_s64, // OPs64_d | OPu64_d, // OPd_u64 | OPd_u64, // OPu64_d | OPf_d, // OPd_f | OPd_f, // OPf_d | OP32_16, // OPs16_32 | OP32_16, // OPu16_32 | OPs16_32, // OP32_16 | OP16_8, // OPu8_16 | OP16_8, // OPs8_16 | OPs8_16, // OP16_8 | OP64_32, // OPu32_64 | OP64_32, // OPs32_64 | OPs32_64, // OP64_32 | OP128_64, // OPu64_128 | OP128_64, // OPs64_128 | OPs64_128, // OP128_64 | | 0, /* OPvp_fp */ | 0, /* OPcvp_fp */ | OPnp_fp, /* OPoffset */ | OPoffset, /* OPnp_fp */ | OPf16p_np, /* OPnp_f16p */ | OPnp_f16p, /* OPf16p_np */ | | OPd_ld, // OPld_d | OPld_d, // OPd_ld | OPu64_d, // OPld_u64 | ]; | | //print("fixconvop before\n"); | //elem_print(e); 6444| assert(invconvtab.length == CNVOPMAX - CNVOPMIN + 1); 6444| assert(e); 6444| tym_t tyme = e.Ety; 6444| const cop = e.EV.E1.Eoper; /* the conversion operator */ 6444| assert(cop <= CNVOPMAX); | 6444| if (e.EV.E1.EV.E1.Eoper == OPcomma) | { /* conv(a,b) op= e2 | * => | * a, (conv(b) op= e2) | */ 52| elem *ecomma = e.EV.E1.EV.E1; 52| e.EV.E1.EV.E1 = ecomma.EV.E2; 52| e.EV.E1.EV.E1.Ety = ecomma.Ety; 52| ecomma.EV.E2 = e; 52| ecomma.Ety = e.Ety; 52| return optelem(ecomma, GOALvalue); | } | 6594| if (e.EV.E1.Eoper == OPd_f && OTconv(e.EV.E1.EV.E1.Eoper) && tyintegral(tyme)) | { 101| elem *e1 = e.EV.E1; 101| e.EV.E1 = e1.EV.E1; 101| e.EV.E2 = el_una(OPf_d, e.EV.E1.Ety, e.EV.E2); 101| e1.EV.E1 = null; 101| el_free(e1); 101| return fixconvop(e); | } | 6291| tym_t tycop = e.EV.E1.Ety; 6291| tym_t tym = e.EV.E1.EV.E1.Ety; 6291| e.EV.E1 = el_selecte1(e.EV.E1); /* dump it for now */ 6291| elem *e1 = e.EV.E1; 6291| e1.Ety = tym; 6291| elem *e2 = e.EV.E2; 12582| assert(e1 && e2); | /* select inverse conversion operator */ 6291| const icop = invconvtab[convidx(cop)]; | | /* First, let's see if we can just throw it away. */ | /* (unslng or shtlng) e op= e2 => e op= (lngsht) e2 */ 6291| if (OTwid(e.Eoper) && 11093| (cop == OPs16_32 || cop == OPu16_32 || 7242| cop == OPu8_16 || cop == OPs8_16)) 15281| { if (e.Eoper != OPshlass && e.Eoper != OPshrass && e.Eoper != OPashrass) 4861| e.EV.E2 = el_una(icop,tym,e2); | //print("after1\n"); | //elem_print(e); 5364| return e; | } | | /* Oh well, just split up the op and the =. */ 927| const op = opeqtoop(e.Eoper); // convert op= to op 927| e.Eoper = OPeq; // just plain = 927| elem *ed = el_copytree(e1); // duplicate e1 | // make: e1 = (icop) ((cop) ed op e2) 927| e.EV.E2 = el_una(icop,e1.Ety, | el_bin(op,tycop,el_una(cop,tycop,ed), | e2)); | | //printf("after1\n"); | //elem_print(e); | 927| if (op == OPdiv && 189| tybasic(e2.Ety) == TYcdouble) | { 2| if (tycop == TYdouble) | { 00000000| e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 00000000| e.EV.E2.EV.E1 = el_una(OPc_r, tycop, e.EV.E2.EV.E1); | } 2| else if (tycop == TYidouble) | { 00000000| e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 00000000| e.EV.E2.EV.E1 = el_una(OPc_i, tycop, e.EV.E2.EV.E1); | } | } | 927| if (op == OPdiv && 189| tybasic(e2.Ety) == TYcfloat) | { 00000000| if (tycop == TYfloat) | { 00000000| e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 00000000| e.EV.E2.EV.E1 = el_una(OPc_r, tycop, e.EV.E2.EV.E1); | } 00000000| else if (tycop == TYifloat) | { 00000000| e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 00000000| e.EV.E2.EV.E1 = el_una(OPc_i, tycop, e.EV.E2.EV.E1); | } | } | | // Handle case of multiple conversion operators on lvalue | // (such as (intdbl 8int char += double)) 927| elem *ex = e; 927| elem **pe = &e; 1353| while (OTconv(ed.Eoper)) | { 426| const uint copx = ed.Eoper; 426| const uint icopx = invconvtab[convidx(copx)]; 426| tym_t tymx = ex.EV.E1.EV.E1.Ety; 426| ex.EV.E1 = el_selecte1(ex.EV.E1); // dump it for now 426| e1 = ex.EV.E1; 426| e1.Ety = tymx; 426| ex.EV.E2 = el_una(icopx,e1.Ety,ex.EV.E2); 426| ex.Ety = tymx; 426| tym = tymx; | 426| if (ex.Ety != tyme) 40| { *pe = el_una(copx, ed.Ety, ex); 40| pe = &(*pe).EV.E1; | } | 426| ed = ed.EV.E1; | } | //print("after2\n"); | //elem_print(e); | 927| e.Ety = tym; 927| if (tym != tyme && 00000000| !(tyintegral(tym) && tyintegral(tyme) && tysize(tym) == tysize(tyme))) 00000000| e = el_una(cop, tyme, e); | 927| if (ed.Eoper == OPbit) // special handling | { 00000000| ed = ed.EV.E1; 00000000| e1 = e1.EV.E1; // go down one | } | | /* If we have a *, must assign a temporary to the expression | * underneath it (even if it's a var, as e2 may modify the var) | */ 927| if (ed.Eoper == OPind) | { 20| elem *T = el_alloctmp(ed.EV.E1.Ety); // make temporary 20| ed.EV.E1 = el_bin(OPeq,T.Ety,T,ed.EV.E1); // ed: *(T=e) 20| el_free(e1.EV.E1); 20| e1.EV.E1 = el_copytree(T); | } | //print("after3\n"); | //elem_print(e); 927| return e; |} | |private elem * elerr(elem *e, goal_t goal) |{ 00000000| debug elem_print(e); 00000000| assert(0); |} | |/* For ops with no optimizations */ | |private elem * elzot(elem *e, goal_t goal) |{ 28013| return e; |} | |/**************************** | */ | |private elem * elstring(elem *e, goal_t goal) |{ 00000000| return e; |} | |/************************ | */ | |/************************ | * Convert far pointer to pointer. | */ | |private void eltonear(elem **pe) |{ 00000000| elem *e = *pe; 00000000| const tym_t ty = e.EV.E1.Ety; 00000000| e = el_selecte1(e); 00000000| e.Ety = ty; 00000000| *pe = optelem(e,GOALvalue); |} | |/************************ | */ | |private elem * elstrcpy(elem *e, goal_t goal) |{ 00000000| elem_debug(e); 00000000| switch (e.EV.E2.Eoper) | { 00000000| case OPnp_fp: 00000000| if (OPTIMIZER) | { 00000000| eltonear(&e.EV.E2); 00000000| e = optelem(e,GOALvalue); | } 00000000| break; | 00000000| case OPstring: | /* Replace strcpy(e1,"string") with memcpy(e1,"string",sizeof("string")) */ | // As streq 00000000| e.Eoper = OPstreq; 00000000| type *t = type_allocn(TYarray, tstypes[TYchar]); 00000000| t.Tdim = strlen(e.EV.E2.EV.Vstring) + 1; 00000000| e.ET = t; 00000000| t.Tcount++; 00000000| e.EV.E1 = el_una(OPind,TYstruct,e.EV.E1); 00000000| e.EV.E2 = el_una(OPind,TYstruct,e.EV.E2); | 00000000| e = el_bin(OPcomma,e.Ety,e,el_copytree(e.EV.E1.EV.E1)); 00000000| if (el_sideeffect(e.EV.E2)) 00000000| fixside(&e.EV.E1.EV.E1.EV.E1,&e.EV.E2); 00000000| e = optelem(e,GOALvalue); 00000000| break; | 00000000| default: 00000000| break; | } 00000000| return e; |} | |/************************ | */ | |private elem * elstrcmp(elem *e, goal_t goal) |{ 00000000| elem_debug(e); 00000000| if (OPTIMIZER) | { 00000000| if (e.EV.E1.Eoper == OPnp_fp) 00000000| eltonear(&e.EV.E1); 00000000| switch (e.EV.E2.Eoper) | { 00000000| case OPnp_fp: 00000000| eltonear(&e.EV.E2); 00000000| break; | 00000000| case OPstring: | // Replace strcmp(e1,"string") with memcmp(e1,"string",sizeof("string")) 00000000| e.Eoper = OPparam; 00000000| e = el_bin(OPmemcmp,e.Ety,e,el_long(TYint,strlen(e.EV.E2.EV.Vstring) + 1)); 00000000| e = optelem(e,GOALvalue); 00000000| break; | 00000000| default: 00000000| break; | } | } 00000000| return e; |} | |/**************************** | * For OPmemcmp | * memcmp(a, b, nbytes) => ((a param b) OPmemcmp nbytes) | */ | |private elem * elmemcmp(elem *e, goal_t goal) |{ 3734| elem_debug(e); 3734| if (!OPTIMIZER) 2797| return e; | | /* Hoist comma operators in `a` out of OPmemcmp | */ | { 937| elem* ec = e.EV.E1.EV.E1; 937| if (ec.Eoper == OPcomma) | { | /* Rewrite: (((a,b) param c) OPmemcmp nbytes) | * As: a,((b param c) OPmemcmp nbytes) | */ 46| e.EV.E1.EV.E1 = ec.EV.E2; 46| e.EV.E1.EV.E1.Ety = ec.Ety; 46| e.EV.E1.EV.E1.ET = ec.ET; 46| ec.EV.E2 = e; 46| ec.Ety = e.Ety; 46| return optelem(ec, goal); | } | } | | /* Hoist comma operators in `b` out of OPmemcmp | */ | { 891| elem* ec = e.EV.E1.EV.E2; 891| if (ec.Eoper == OPcomma) | { | /* Have: ((a param (b,c)) OPmemcmp nbytes) | */ 78| elem* a = e.EV.E1.EV.E1; 78| elem* b = ec.EV.E1; 78| if (a.canHappenAfter(b)) | { | /* Rewrite: ((a param (b,c)) OPmemcmp nbytes) | * As: b,((a param c) OPmemcmp nbytes) | */ 30| e.EV.E1.EV.E2 = ec.EV.E2; 30| e.EV.E1.EV.E2.Ety = ec.Ety; 30| e.EV.E1.EV.E2.ET = ec.ET; 30| ec.EV.E2 = e; 30| ec.Ety = e.Ety; 30| return optelem(ec, goal); | } | } | } | 861| elem *ex = e.EV.E1; 861| if (ex.EV.E1.Eoper == OPnp_fp) 00000000| eltonear(&ex.EV.E1); 861| if (ex.EV.E2.Eoper == OPnp_fp) 00000000| eltonear(&ex.EV.E2); | 861| return e; |} | |/**************************** | * For OPmemset | */ | |private elem * elmemset(elem *e, goal_t goal) |{ 15286| elem_debug(e); 15286| if (OPTIMIZER) | { 7156| elem *ex = e.EV.E1; 7156| if (ex.Eoper == OPnp_fp) 00000000| eltonear(&ex); | else | { | // lvalue OPmemset (nbytes param value) 7156| elem *enbytes = e.EV.E2.EV.E1; 7156| elem *evalue = e.EV.E2.EV.E2; | | version (MARS) 14120| if (enbytes.Eoper == OPconst && evalue.Eoper == OPconst) | { 4902| int nbytes = cast(int)el_tolong(enbytes); 4902| targ_llong value = el_tolong(evalue); 4902| elem *e1 = e.EV.E1; | 9804| if (e1.Eoper == OPcomma || OTassign(e1.Eoper)) 00000000| return cgel_lvalue(e); // replace (e,v)op=e2 with e,(v op= e2) | 4902| tym_t tym; 4902| switch (nbytes) | { 2478| case CHARSIZE: tym = TYchar; goto L1; 132| case SHORTSIZE: tym = TYshort; goto L1; 2703| case LONGSIZE: tym = TYlong; goto L1; 424| case LLONGSIZE: if (_tysize[TYint] == 2) 00000000| goto Ldefault; 424| tym = TYllong; goto L1; | L1: | { 1983| tym_t ety = e.Ety; 1983| memset(&value, value & 0xFF, value.sizeof); 1983| evalue.EV.Vullong = value; 1983| evalue.Ety = tym; 1983| e.Eoper = OPeq; 1983| e.Ety = (e.Ety & ~mTYbasic) | tym; 1983| if (tybasic(e1.Ety) == TYstruct) 00000000| e1.Ety = tym; | else 1983| e.EV.E1 = el_una(OPind, tym, e1); 1983| elem *tmp = el_same(&e.EV.E1); 1983| tmp = el_una(OPaddr, ety, tmp); 1983| e.EV.E2.Ety = tym; 1983| e.EV.E2 = el_selecte2(e.EV.E2); 1983| e = el_combine(e, tmp); 1983| e = optelem(e,GOALvalue); 1983| break; | } | 2919| default: | Ldefault: 2919| break; | } | } | } | } 15286| return e; |} | | |/**************************** | * For OPmemcpy | * OPmemcpy | * / \ | * s1 OPparam | * / \ | * s2 n | */ | |private elem * elmemcpy(elem *e, goal_t goal) |{ 2216| elem_debug(e); 2216| if (OPTIMIZER) | { 715| elem *ex = e.EV.E1; 715| if (ex.Eoper == OPnp_fp) 00000000| eltonear(&e.EV.E1); 715| ex = e.EV.E2; 715| if (ex.EV.E1.Eoper == OPnp_fp) 00000000| eltonear(&ex.EV.E1); 715| if (ex.EV.E2.Eoper == OPconst) | { 464| if (!boolres(ex.EV.E2)) | { // Copying 0 bytes, so remove memcpy 8| e.EV.E2 = e.EV.E1; 8| e.EV.E1 = ex.EV.E1; 8| ex.EV.E1 = null; 8| e.Eoper = OPcomma; 8| el_free(ex); 8| return optelem(e, GOALvalue); | } | // Convert OPmemcpy to OPstreq 456| e.Eoper = OPstreq; 456| type *t = type_allocn(TYarray, tstypes[TYchar]); 456| t.Tdim = cast(uint)el_tolong(ex.EV.E2); 456| e.ET = t; 456| t.Tcount++; 456| e.EV.E1 = el_una(OPind,TYstruct,e.EV.E1); 456| e.EV.E2 = el_una(OPind,TYstruct,ex.EV.E1); 456| ex.EV.E1 = null; 456| el_free(ex); 456| ex = el_copytree(e.EV.E1.EV.E1); 456| if (tysize(e.Ety) > tysize(ex.Ety)) 9| ex = el_una(OPnp_fp,e.Ety,ex); 456| e = el_bin(OPcomma,e.Ety,e,ex); 456| if (el_sideeffect(e.EV.E2)) 00000000| fixside(&e.EV.E1.EV.E1.EV.E1,&e.EV.E2); 456| return optelem(e,GOALvalue); | } | | /+ The following fails the autotester for Linux32 and FreeBSD32 | + for unknown reasons I cannot reproduce | // Convert to memcpy(s1, s2, n) | elem* ep = el_params(e.EV.E2.EV.E2, e.EV.E2.EV.E1, e.EV.E1, null); | const ty = e.Ety; | e.EV.E1 = null; | e.EV.E2.EV.E1 = null; | e.EV.E2.EV.E2 = null; | el_free(e); | e = el_bin(OPcall, ty, el_var(getRtlsym(RTLSYM_MEMCPY)), ep); | +/ | } 1752| return e; |} | | |/*********************** | * + # (combine offsets with addresses) | * / \ => | | * # c v,c | * | | * v | */ | |private elem * eladd(elem *e, goal_t goal) |{ | //printf("eladd(%p)\n",e); 857131| targ_size_t ptrmask = ~cast(targ_size_t)0; 857131| if (_tysize[TYnptr] <= 4) 23| ptrmask = 0xFFFFFFFF; |L1: 857240| elem *e1 = e.EV.E1; 857240| elem *e2 = e.EV.E2; 857240| if (e2.Eoper == OPconst) | { 955301| if (e1.Eoper == OPrelconst && e1.EV.Vsym.Sfl == FLgot) 00000000| return e; 755940| if (e1.Eoper == OPrelconst || // if (&v) + c 556579| e1.Eoper == OPstring) | { 199361| e1.EV.Voffset += e2.EV.Vpointer; 199361| e1.EV.Voffset &= ptrmask; 199361| e = el_selecte1(e); 199361| return e; | } | } 101300| else if (e1.Eoper == OPconst) | { 1292| if (e2.Eoper == OPrelconst && e2.EV.Vsym.Sfl == FLgot) 00000000| return e; 646| if (e2.Eoper == OPrelconst || // if c + (&v) 00000000| e2.Eoper == OPstring) | { 646| e2.EV.Voffset += e1.EV.Vpointer; 646| e2.EV.Voffset &= ptrmask; 646| e = el_selecte2(e); 646| return e; | } | } | 657233| if (!OPTIMIZER) 440351| return e; | | // Replace ((e + &v) + c) with (e + (&v+c)) 406012| if (e2.Eoper == OPconst && e1.Eoper == OPadd && 12624| (e1.EV.E2.Eoper == OPrelconst || e1.EV.E2.Eoper == OPstring)) | { 108| e1.EV.E2.EV.Voffset += e2.EV.Vpointer; 108| e1.EV.E2.EV.Voffset &= ptrmask; 108| e = el_selecte1(e); 108| goto L1; | } | // Replace ((e + c) + &v) with (e + (&v+c)) 431796| else if ((e2.Eoper == OPrelconst || e2.Eoper == OPstring) && 1752| e1.Eoper == OPadd && cnst(e1.EV.E2)) | { 00000000| e2.EV.Voffset += e1.EV.E2.EV.Vpointer; 00000000| e2.EV.Voffset &= ptrmask; 00000000| e.EV.E1 = el_selecte1(e1); 00000000| goto L1; /* try and find some more */ | } | // Replace (e1 + -e) with (e1 - e) 216774| else if (e2.Eoper == OPneg) | { 1| e.EV.E2 = el_selecte1(e2); 1| e.Eoper = OPmin; 1| again = 1; 1| return e; | } | // Replace (-v + e) with (e + -v) 216800| else if (e1.Eoper == OPneg && OTleaf(e1.EV.E1.Eoper)) | { 1| e.EV.E1 = e2; 1| e.EV.E2 = e1; /* swap leaves */ 1| goto L1; | } | /* Replace ((e - e2) + e2) with (e) | * The optimizer sometimes generates this case | */ 216772| else if (!tyfloating(e.Ety) && /* no floating bugs */ 215685| e1.Eoper == OPmin && 97| el_match(e1.EV.E2,e2) && 42| !el_sideeffect(e2)) | { 42| tym_t tym = e.Ety; 42| e = el_selecte1(el_selecte1(e)); 42| e.Ety = tym; /* retain original type */ 42| return e; | } | // Replace ((e - #v+c1) + #v+c2) with ((e - c1) + c2) 216730| else if (e2.Eoper == OPrelconst && 1752| e1.Eoper == OPmin && 00000000| e1.EV.E2.Eoper == OPrelconst && 00000000| e1.EV.E2.EV.Vsym == e2.EV.Vsym) | { 00000000| e2.Eoper = OPconst; 00000000| e2.Ety = TYint; 00000000| e1.Ety = e1.EV.E1.Ety; 00000000| e1.EV.E2.Eoper = OPconst; 00000000| e1.EV.E2.Ety = TYint; | { | /* Watch out for pointer types changing, requiring a conversion */ 00000000| tym_t ety = tybasic(e.Ety); 00000000| tym_t e11ty = tybasic(e1.EV.E1.Ety); 00000000| if (typtr(ety) && typtr(e11ty) && 00000000| _tysize[ety] != _tysize[e11ty]) | { 00000000| e = el_una((_tysize[ety] > _tysize[e11ty]) ? OPnp_fp : OPoffset, | e.Ety,e); 00000000| e.EV.E1.Ety = e1.Ety; | } | } 00000000| again = 1; 00000000| return e; | } | // Replace (e + e) with (e * 2) 216846| else if (el_match(e1,e2) && !el_sideeffect(e1) && !tyfloating(e1.Ety)) | { 00000000| e.Eoper = OPmul; 00000000| el_free(e2); 00000000| e.EV.E2 = el_long(e1.Ety,2); 00000000| again = 1; 00000000| return e; | } | | // Replace ((e11 + c) + e2) with ((e11 + e2) + c) 223602| if (e1.Eoper == OPadd && e1.EV.E2.Eoper == OPconst && 1337| (e2.Eoper == OPvar || !OTleaf(e2.Eoper)) && 231| tysize(e1.Ety) == tysize(e2.Ety) && 231| tysize(e1.EV.E2.Ety) == tysize(e2.Ety)) | { 231| e.EV.E2 = e1.EV.E2; 231| e1.EV.E2 = e2; 231| e1.Ety = e.Ety; 231| return e; | } | | // Replace (~e1 + 1) with (-e1) 216511| if (e1.Eoper == OPcom && e2.Eoper == OPconst && el_tolong(e2) == 1) | { 6| e = el_selecte1(e); 6| e.Eoper = OPneg; 6| e = optelem(e, goal); 6| return e; | } | | // Replace ((e11 - e12) + e2) with ((e11 + e2) - e12) | // (this should increase the number of LEA possibilities) 216493| int sz = tysize(e.Ety); 216493| if (e1.Eoper == OPmin && 143| tysize(e1.Ety) == sz && 143| tysize(e2.Ety) == sz && 143| tysize(e1.EV.E1.Ety) == sz && 143| tysize(e1.EV.E2.Ety) == sz && 143| !tyfloating(e.Ety) | ) | { 55| e.Eoper = OPmin; 55| e.EV.E2 = e1.EV.E2; 55| e1.EV.E2 = e2; 55| e1.Eoper = OPadd; | } | 216493| return e; |} | | |/************************ | * Multiply (for OPmul && OPmulass) | * e * (c**2) => e << c ;replace multiply by power of 2 with shift | */ | |private elem * elmul(elem *e, goal_t goal) |{ 47597| tym_t tym = e.Ety; | 47597| if (OPTIMIZER) | { | // Replace -a*-b with a*b. | // This is valid for all floating point types as well as integers. 32390| if (tyarithmetic(tym) && e.EV.E2.Eoper == OPneg && e.EV.E1.Eoper == OPneg) | { 00000000| e.EV.E1 = el_selecte1(e.EV.E1); 00000000| e.EV.E2 = el_selecte1(e.EV.E2); | } | } | 47597| elem *e2 = e.EV.E2; 47597| if (e2.Eoper == OPconst) // try to replace multiplies with shifts | { 44454| if (OPTIMIZER) | { 15177| elem *e1 = e.EV.E1; 15177| uint op1 = e1.Eoper; | 15177| if (tyintegral(tym) && // skip floating types 15062| OTbinary(op1) && 504| e1.EV.E2.Eoper == OPconst | ) | { | /* Attempt to replace ((e + c1) * c2) with (e * c2 + (c1 * c2)) | * because the + can be frequently folded out (merged into an | * array offset, for example. | */ 285| if (op1 == OPadd) | { 241| e.Eoper = OPadd; 241| e1.Eoper = OPmul; 241| e.EV.E2 = el_bin(OPmul,tym,e1.EV.E2,e2); 241| e1.EV.E2 = el_copytree(e2); 241| again = 1; 241| return e; | } | | // ((e << c1) * c2) => e * ((1 << c1) * c2) 44| if (op1 == OPshl) | { 00000000| e2.EV.Vullong *= cast(targ_ullong)1 << el_tolong(e1.EV.E2); 00000000| e1.EV.E2.EV.Vullong = 0; 00000000| again = 1; 00000000| return e; | } | } | 14936| if (elemisnegone(e2)) | { 4| e.Eoper = (e.Eoper == OPmul) ? OPneg : OPnegass; 2| e.EV.E2 = null; 2| el_free(e2); 2| return e; | } | } | 87942| if (tyintegral(tym) && !tyvector(tym)) | { 43715| int i = ispow2(el_tolong(e2)); // check for power of 2 43715| if (i != -1) // if it is a power of 2 18027| { e2.EV.Vint = i; 18027| e2.Ety = TYint; 18027| e.Eoper = (e.Eoper == OPmul) /* convert to shift left */ 18027| ? OPshl : OPshlass; 18027| again = 1; 18027| return e; | } 25688| else if (el_allbits(e2,-1)) 11| goto Lneg; | } 498| else if (elemisnegone(e2) && !tycomplex(e.EV.E1.Ety)) | { 2| goto Lneg; | } | } 29314| return e; | |Lneg: 13| e.Eoper = (e.Eoper == OPmul) /* convert to negate */ 13| ? OPneg : OPnegass; 13| el_free(e.EV.E2); 13| e.EV.E2 = null; 13| again = 1; 13| return e; |} | |/************************ | * Subtract | * - + | * / \ => / \ (propagate minuses) | * e c e -c | */ | |private elem * elmin(elem *e, goal_t goal) |{ 27335| elem *e2 = e.EV.E2; | 27335| if (OPTIMIZER) | { 5132| tym_t tym = e.Ety; 5132| elem *e1 = e.EV.E1; 5132| if (e2.Eoper == OPrelconst) | { 98| if (e1.Eoper == OPrelconst && e1.EV.Vsym == e2.EV.Vsym) | { 1| e.Eoper = OPconst; 1| e.EV.Vllong = e1.EV.Voffset - e2.EV.Voffset; 1| el_free(e1); 1| el_free(e2); 1| return e; | } | } | | // Convert subtraction of long pointers to subtraction of integers 5131| if (tyfv(e2.Ety) && tyfv(e1.Ety)) | { 00000000| e.EV.E1 = el_una(OP32_16,tym,e1); 00000000| e.EV.E2 = el_una(OP32_16,tym,e2); 00000000| return optelem(e,GOALvalue); | } | | // Replace (0 - e2) with (-e2) 5208| if (cnst(e1) && !boolres(e1) && 1| !(tycomplex(tym) && !tycomplex(e1.Ety) && !tycomplex(e2.Ety)) && 1| !tyvector(e1.Ety) | ) | { 1| e.EV.E1 = e2; 1| e.EV.E2 = null; 1| e.Eoper = OPneg; 1| el_free(e1); 1| return optelem(e,GOALvalue); | } | | // Replace (e - e) with (0) 5162| if (el_match(e1,e2) && !el_sideeffect(e1)) | { 00000000| el_free(e); 00000000| e = el_calloc(); 00000000| e.Eoper = OPconst; 00000000| e.Ety = tym; 00000000| return e; | } | | // Replace ((e1 + c) - e2) with ((e1 - e2) + c), but not | // for floating or far or huge pointers! 5130| if (e1.Eoper == OPadd && 204| cnst(e1.EV.E2) && 54| (tyintegral(tym) || 00000000| tybasic(tym) == TYnptr || 00000000| tybasic(tym) == TYsptr || 00000000| tybasic(tym) == TYfgPtr || 00000000| tybasic(tym) == TYimmutPtr || 00000000| tybasic(tym) == TYrestrictPtr || 00000000| tybasic(tym) == TYsharePtr) | ) | { 54| e.Eoper = OPadd; 54| e1.Eoper = OPmin; 54| elem* c = e1.EV.E2; 54| e1.EV.E2 = e2; 54| e.EV.E2 = c; 54| return optelem(e,GOALvalue); | } | | // Replace (e1 + c1) - (e2 + c2) with (e1 - e2) + (c1 - c2), but not | // for floating or far or huge pointers! 5226| if (e1.Eoper == OPadd && e2.Eoper == OPadd && 00000000| cnst(e1.EV.E2) && cnst(e2.EV.E2) && 00000000| (tyintegral(tym) || 00000000| tybasic(tym) == TYnptr || 00000000| tybasic(tym) == TYsptr || 00000000| tybasic(tym) == TYfgPtr || 00000000| tybasic(tym) == TYimmutPtr || 00000000| tybasic(tym) == TYrestrictPtr || 00000000| tybasic(tym) == TYsharePtr) | ) | { 00000000| e.Eoper = OPadd; 00000000| e1.Eoper = OPmin; 00000000| e2.Eoper = OPmin; 00000000| elem *tmp = e1.EV.E2; 00000000| e1.EV.E2 = e2.EV.E1; 00000000| e2.EV.E1 = tmp; 00000000| return optelem(e,GOALvalue); | } | | // Replace (-e1 - 1) with (~e1) 5148| if (e1.Eoper == OPneg && e2.Eoper == OPconst && tyintegral(tym) && el_tolong(e2) == 1) | { 12| e = el_selecte1(e); 12| e.Eoper = OPcom; 12| e = optelem(e, goal); 12| return e; | } | | // Replace (-1 - e2) with (~e2) 5256| if (e1.Eoper == OPconst && tyintegral(tym) && !tyvector(tym) && el_tolong(e1) == -1) | { 00000000| el_free(e1); 00000000| e.EV.E1 = e.EV.E2; 00000000| e.EV.E2 = null; 00000000| e.Eoper = OPcom; 00000000| e = optelem(e, goal); 00000000| return e; | } | | /* Replace e1 - (v * c) with e1 + (v * -c) | */ 5064| if (e2.Eoper == OPmul && 21| e2.EV.E2.Eoper == OPconst) | { 12| e.Eoper = OPadd; 12| e2.EV.E2 = el_una(OPneg, e2.EV.E2.Ety, e2.EV.E2); 12| return optelem(e, goal); | } | } | 27255| if (I16 && tybasic(e2.Ety) == TYhptr && tybasic(e.EV.E1.Ety) == TYhptr) | { // Convert to _aNahdiff(e1,e2) 00000000| __gshared Symbol *hdiff; 00000000| if (!hdiff) | { 00000000| Symbol *s = symbol_calloc(LARGECODE ? "_aFahdiff".ptr : "_aNahdiff".ptr); 00000000| s.Stype = tsclib; 00000000| s.Sclass = SCextern; 00000000| s.Sfl = FLfunc; 00000000| s.Ssymnum = 0; 00000000| s.Sregsaved = mBX|mCX|mSI|mDI|mBP|mES; 00000000| hdiff = s; | } 00000000| e.Eoper = OPcall; 00000000| e.EV.E2 = el_bin(OPparam,TYint,e2,e.EV.E1); 00000000| e.EV.E1 = el_var(hdiff); 00000000| return e; | } | | /* Disallow the optimization on doubles. The - operator is not | * rearrangable by K+R, and can cause floating point problems if | * converted to an add ((a + 1.0) - 1.0 shouldn't be folded). | */ 39236| if (cnst(e2) && !tyfloating(e2.Ety) && 11760| !tyvector(e2.Ety)) // don't do vectors until we get constant folding for them | { 11760| e.EV.E2 = el_una(OPneg,e2.Ety,e2); 11760| e.Eoper = OPadd; 11760| return optelem(e,GOALvalue); | } 15495| return e; |} | |/***************************** | * OPand,OPor,OPxor | * This should be expanded to include long type stuff. | */ | |private elem * elbitwise(elem *e, goal_t goal) |{ | //printf("elbitwise(e = %p, goal = x%x)\n", e, goal); | 131345| elem *e2 = e.EV.E2; 131345| elem *e1 = e.EV.E1; 131345| const op = e1.Eoper; 131345| uint sz = tysize(e2.Ety); | 131345| if (e2.Eoper == OPconst) | { 127055| switch (sz) | { 116835| case CHARSIZE: | /* Replace (c & 0xFF) with (c) */ 213940| if (OPTIMIZER && e2.EV.Vuchar == CHARMASK) | { | L1: 8| switch (e.Eoper) 8| { case OPand: /* (c & 0xFF) => (c) */ 8| return el_selecte1(e); 00000000| case OPor: /* (c | 0xFF) => (0xFF) */ 00000000| return el_selecte2(e); 00000000| case OPxor: /* (c ^ 0xFF) => (~c) */ 00000000| return el_una(OPcom,e.Ety,el_selecte1(e)); 00000000| default: 00000000| assert(0); | } | } 116831| break; | 7076| case LONGSIZE: | { 7076| if (!OPTIMIZER) 6547| break; 529| targ_ulong ul = e2.EV.Vulong; | 529| if (ul == 0xFFFFFFFF) /* if e1 & 0xFFFFFFFF */ 00000000| goto L1; | /* (x >> 16) & 0xFFFF => (cast(uint)x >> 16) */ 529| if (ul == 0xFFFF && e.Eoper == OPand && (op == OPshr || op == OPashr) && 00000000| e1.EV.E2.Eoper == OPconst && el_tolong(e1.EV.E2) == 16) | { 00000000| elem *e11 = e1.EV.E1; 00000000| e11.Ety = touns(e11.Ety) | (e11.Ety & ~mTYbasic); 00000000| goto L1; | } | | /* Replace (L & 0x0000XXXX) with (unslng)((lngsht) & 0xXXXX) */ 529| if (_tysize[TYint] < LONGSIZE && 00000000| e.Eoper == OPand && 00000000| ul <= SHORTMASK) | { 00000000| tym_t tym = e.Ety; 00000000| e.EV.E1 = el_una(OP32_16,TYushort,e.EV.E1); 00000000| e.EV.E2 = el_una(OP32_16,TYushort,e.EV.E2); 00000000| e.Ety = TYushort; 00000000| e = el_una(OPu16_32,tym,e); 00000000| goto Lopt; | } | | // Replace ((s8sht)L & 0xFF) with (u8sht)L 557| if (ul == 0xFF && _tysize[TYint] == LONGSIZE && e.Eoper == OPand && 28| (op == OPs8_16 || op == OPu8_16) | ) | { 00000000| e1.Eoper = OPu8_16; 00000000| e = el_selecte1(e); 00000000| goto Lopt; | } 529| break; | } | 28| case SHORTSIZE: | { 28| targ_short i = e2.EV.Vshort; 28| if (i == cast(targ_short)SHORTMASK) // e2 & 0xFFFF 4| goto L1; | | /* (x >> 8) & 0xFF => ((uint short)x >> 8) */ 60| if (OPTIMIZER && i == 0xFF && e.Eoper == OPand && 24| (op == OPshr || op == OPashr) && e1.EV.E2.Eoper == OPconst && e1.EV.E2.EV.Vint == 8) | { 00000000| elem *e11 = e1.EV.E1; 00000000| e11.Ety = touns(e11.Ety) | (e11.Ety & ~mTYbasic); 00000000| goto L1; | } | | // (s8_16(e) & 0xFF) => u8_16(e) 48| if (OPTIMIZER && op == OPs8_16 && e.Eoper == OPand && 00000000| i == 0xFF) | { 00000000| e1.Eoper = OPu8_16; 00000000| e = el_selecte1(e); 00000000| goto Lopt; | } | 24| if ( | /* OK for uint if AND or high bits of i are 0 */ 00000000| op == OPu8_16 && (e.Eoper == OPand || !(i & ~0xFF)) || | /* OK for signed if i is 'sign-extended' */ 24| op == OPs8_16 && cast(targ_short)cast(targ_schar)i == i | ) | { | /* Convert ((u8int) e) & i) to (u8int)(e & (int8) i) */ | /* or similar for s8int */ 00000000| e = el_una(e1.Eoper,e.Ety,e); 00000000| e.EV.E1.Ety = e1.Ety = e1.EV.E1.Ety; 00000000| e.EV.E1.EV.E1 = el_selecte1(e1); 00000000| e.EV.E1.EV.E2 = el_una(OP16_8,e.EV.E1.Ety,e.EV.E1.EV.E2); 00000000| goto Lopt; | } 24| break; | } | 3044| case LLONGSIZE: 3044| if (OPTIMIZER) | { 106| if (e2.EV.Vullong == LLONGMASK) 00000000| goto L1; | } 3044| break; | 72| default: 72| break; | } 224807| if (OPTIMIZER && sz < 16) | { 97760| targ_ullong ul = el_tolong(e2); | 97804| if (e.Eoper == OPor && op == OPand && e1.EV.E2.Eoper == OPconst) | { | // ((x & c1) | c2) => (x | c2) 00000000| targ_ullong c3; | 00000000| c3 = ul | e1.EV.E2.EV.Vullong; 00000000| switch (sz) | { 00000000| case CHARSIZE: 00000000| if ((c3 & CHARMASK) == CHARMASK) 00000000| goto L2; 00000000| break; | 00000000| case SHORTSIZE: 00000000| if ((c3 & SHORTMASK) == SHORTMASK) 00000000| goto L2; 00000000| break; | 00000000| case LONGSIZE: 00000000| if ((c3 & LONGMASK) == LONGMASK) | { | L2: 00000000| e1.EV.E2.EV.Vullong = c3; 00000000| e.EV.E1 = elbitwise(e1, GOALvalue); 00000000| goto Lopt; | } 00000000| break; | 00000000| case LLONGSIZE: 00000000| if ((c3 & LLONGMASK) == LLONGMASK) 00000000| goto L2; 00000000| break; | 00000000| default: 00000000| assert(0); | } | } | 97760| if (op == OPs16_32 && (ul & 0xFFFFFFFFFFFF8000L) == 0 || 97760| op == OPu16_32 && (ul & 0xFFFFFFFFFFFF0000L) == 0 || 97760| op == OPs8_16 && (ul & 0xFFFFFFFFFFFFFF80L) == 0 || 97764| op == OPu8_16 && (ul & 0xFFFFFFFFFFFFFF00L) == 0 || 97760| op == OPs32_64 && (ul & 0xFFFFFFFF80000000L) == 0 || 97760| op == OPu32_64 && (ul & 0xFFFFFFFF00000000L) == 0 | ) | { 00000000| if (e.Eoper == OPand) | { 00000000| if (op == OPs16_32 && (ul & 0x8000) == 0) 00000000| e1.Eoper = OPu16_32; 00000000| else if (op == OPs8_16 && (ul & 0x80) == 0) 00000000| e1.Eoper = OPu8_16; 00000000| else if (op == OPs32_64 && (ul & 0x80000000) == 0) 00000000| e1.Eoper = OPu32_64; | } | | // ((shtlng)s & c) => ((shtlng)(s & c) 00000000| e1.Ety = e.Ety; 00000000| e.Ety = e2.Ety = e1.EV.E1.Ety; 00000000| e.EV.E1 = e1.EV.E1; 00000000| e1.EV.E1 = e; 00000000| e = e1; 00000000| goto Lopt; | } | | // Replace (((a & b) ^ c) & d) with ((a ^ c) & e), where | // e is (b&d). 187081| if (e.Eoper == OPand && op == OPxor && e1.EV.E1.Eoper == OPand && 00000000| e1.EV.E1.EV.E2.Eoper == OPconst) | { 00000000| e2.EV.Vullong &= e1.EV.E1.EV.E2.EV.Vullong; 00000000| e1.EV.E1 = el_selecte1(e1.EV.E1); 00000000| goto Lopt; | } | | // Replace ((a >> b) & 1) with (a btst b) 195520| if ((I32 || I64) && 97760| e.Eoper == OPand && 88641| ul == 1 && 176500| (e.EV.E1.Eoper == OPshr || e.EV.E1.Eoper == OPashr) && 12| sz <= REGSIZE && 12| tysize(e1.Ety) >= 2 // BT doesn't work on byte operands | ) | { 9| e.EV.E1.Eoper = OPbtst; 9| e = el_selecte1(e); 9| goto Lopt; | } | } | } | 258133| if (OPTIMIZER && goal & GOALflags && (I32 || I64) && e.Eoper == OPand && 2290| (sz == 4 || sz == 8)) | { | /* These should all compile to a BT instruction when -O, for -m32 and -m64 | * int bt32(uint *p, uint b) { return ((p[b >> 5] & (1 << (b & 0x1F)))) != 0; } | * int bt64a(ulong *p, uint b) { return ((p[b >> 6] & (1L << (b & 63)))) != 0; } | * int bt64b(ulong *p, size_t b) { return ((p[b >> 6] & (1L << (b & 63)))) != 0; } | */ | 498| static bool ELCONST(elem* e, long c) { return e.Eoper == OPconst && el_tolong(e) == c; } 118| int pow2sz = ispow2(sz); | 118| if (e1.Eoper == OPind) | { // Swap e1 and e2 so that e1 is the mask and e2 is the memory location 32| e2 = e1; 32| e1 = e.EV.E2; | } | | /* Replace: | * ((1 << (b & 31)) & *(((b >>> 5) << 2) + p) | * with: | * p bt b | */ 118| elem *e12; // the (b & 31), which may be preceded by (64_32) 118| elem *e2111; // the (b >>> 5), which may be preceded by (u32_64) 118| if (e1.Eoper == OPshl && 74| ELCONST(e1.EV.E1,1) && 148| (((e12 = e1.EV.E2).Eoper == OP64_32 ? (e12 = e12.EV.E1) : e12).Eoper == OPand) && 46| ELCONST(e12.EV.E2,sz * 8 - 1) && 34| tysize(e12.Ety) <= sz && | 34| e2.Eoper == OPind && 34| e2.EV.E1.Eoper == OPadd && 34| e2.EV.E1.EV.E1.Eoper == OPshl && 34| ELCONST(e2.EV.E1.EV.E1.EV.E2,pow2sz) && 68| (((e2111 = e2.EV.E1.EV.E1.EV.E1).Eoper == OPu32_64 ? (e2111 = e2111.EV.E1) : e2111).Eoper == OPshr) && 34| ELCONST(e2111.EV.E2,pow2sz + 3) | ) | { 34| elem **pb1 = &e12.EV.E1; 34| elem **pb2 = &e2111.EV.E1; 34| elem **pp = &e2.EV.E1.EV.E2; | 34| if (el_match(*pb1, *pb2) && 7| !el_sideeffect(*pb1)) | { 7| e.Eoper = OPbt; 7| e.EV.E1 = *pp; // p 7| *pp = null; 7| e.EV.E2 = *pb1; // b 7| *pb1 = null; 7| *pb2 = null; 7| el_free(e1); 7| el_free(e2); 7| return optelem(e,goal); | } | } | | /* Replace: | * (1 << a) & b | * with: | * b btst a | */ 111| if (e1.Eoper == OPshl && 67| ELCONST(e1.EV.E1,1) && 67| tysize(e.EV.E1.Ety) <= REGSIZE) | { 67| const int sz1 = tysize(e.EV.E1.Ety); 67| e.Eoper = OPbtst; 67| e.Ety = TYbool; 67| e.EV.E1 = e2; 67| e.EV.E2 = e1.EV.E2; | //e.EV.E2.Ety = e.EV.E1.Ety; // leave type as int 67| e1.EV.E2 = null; 67| el_free(e1); | 67| if (sz1 >= 2) 67| e = el_una(OPu8_16, TYushort, e); 67| if (sz1 >= 4) 67| e = el_una(OPu16_32, TYulong, e); 67| if (sz1 >= 8) 31| e = el_una(OPu32_64, TYullong, e); | 67| return optelem(e, goal); | } | } | 131254| return e; | |Lopt: | debug | { 9| __gshared int nest; 9| nest++; 9| if (nest > 100) 00000000| { elem_print(e); 00000000| assert(0); | } 9| e = optelem(e,GOALvalue); 9| nest--; 9| return e; | } | else | return optelem(e,GOALvalue); |} | |/*************************************** | * Fill in ops[maxops] with operands of repeated operator oper. | * Returns: | * true didn't fail | * false more than maxops operands | */ | |bool fillinops(elem **ops, int *opsi, int maxops, int oper, elem *e) |{ 1546| if (e.Eoper == oper) | { 552| if (!fillinops(ops, opsi, maxops, oper, e.EV.E1) || 552| !fillinops(ops, opsi, maxops, oper, e.EV.E2)) 72| return false; | } | else | { 994| if (*opsi >= maxops) 18| return false; // error, too many 976| ops[*opsi] = e; 976| *opsi += 1; | } 1456| return true; |} | | |/************************************* | * Replace shift|shift with rotate. | */ | |private elem *elor(elem *e, goal_t goal) |{ | //printf("elor()\n"); | /* ROL: (a << shift) | (a >> (sizeof(a) * 8 - shift)) | * ROR: (a >> shift) | (a << (sizeof(a) * 8 - shift)) | */ 3750| elem *e1 = e.EV.E1; 3750| elem *e2 = e.EV.E2; 3750| uint sz = tysize(e.Ety); 3750| if (sz <= REGSIZE) | { 4611| if (e1.Eoper == OPshl && e2.Eoper == OPshr && 242| tyuns(e2.EV.E1.Ety) && e2.EV.E2.Eoper == OPmin && 28| e2.EV.E2.EV.E1.Eoper == OPconst && 27| el_tolong(e2.EV.E2.EV.E1) == sz * 8 && 27| el_match5(e1.EV.E1, e2.EV.E1) && 25| el_match5(e1.EV.E2, e2.EV.E2.EV.E2) && 25| !el_sideeffect(e) | ) | { 25| e1.Eoper = OProl; 25| return el_selecte1(e); | } 3864| if (e1.Eoper == OPshr && e2.Eoper == OPshl && 58| tyuns(e1.EV.E1.Ety) && e2.EV.E2.Eoper == OPmin && 25| e2.EV.E2.EV.E1.Eoper == OPconst && 24| el_tolong(e2.EV.E2.EV.E1) == sz * 8 && 24| el_match5(e1.EV.E1, e2.EV.E1) && 24| el_match5(e1.EV.E2, e2.EV.E2.EV.E2) && 24| !el_sideeffect(e) | ) | { 24| e1.Eoper = OPror; 24| return el_selecte1(e); | } | // rotate left by a constant 4537| if (e1.Eoper == OPshl && e2.Eoper == OPshr && 96| tyuns(e2.EV.E1.Ety) && 96| e1.EV.E2.Eoper == OPconst && 93| e2.EV.E2.Eoper == OPconst && 93| el_tolong(e2.EV.E2) == sz * 8 - el_tolong(e1.EV.E2) && 93| el_match5(e1.EV.E1, e2.EV.E1) && 93| !el_sideeffect(e) | ) | { 93| e1.Eoper = OProl; 93| return el_selecte1(e); | } | // rotate right by a constant 3723| if (e1.Eoper == OPshr && e2.Eoper == OPshl && 5| tyuns(e2.EV.E1.Ety) && 5| e1.EV.E2.Eoper == OPconst && 4| e2.EV.E2.Eoper == OPconst && 4| el_tolong(e2.EV.E2) == sz * 8 - el_tolong(e1.EV.E2) && 3| el_match5(e1.EV.E1, e2.EV.E1) && 2| !el_sideeffect(e) | ) | { 2| e1.Eoper = OPror; 2| return el_selecte1(e); | } | } | | /* Recognize the following function and replace it with OPbswap: | ushort byteswap(ushort x) { return cast(ushort)(((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); } | | | TYunsigned short | & TYshort | 32_16 TYshort | >> TYint | u16_32 TYint | var TYunsigned short x | const TYint 8L | const TYshort 255 | & TYshort | << TYshort | var TYshort x | const TYshort 8 | const TYshort 0xFF00 | */ 3627| if (sz == 2 && OPTIMIZER) | { 18| if (e.Eoper == OPor && 18| e1.Eoper == OPand && 18| e2.Eoper == OPand) | { 18| elem* evar; 18| elem* evar2; 18| auto e11 = e1.EV.E1; 18| auto e12 = e1.EV.E2; 18| if (e11.Eoper == OP32_16 && 30| e12.Eoper == OPconst && el_tolong(e12) == 0xFF) | { 12| auto e111 = e11.EV.E1; 24| if (e111.Eoper == OPshr || e111.Eoper == OPashr) | { 12| auto e1111 = e111.EV.E1; 12| auto e1112 = e111.EV.E2; 24| if (e1112.Eoper == OPconst && el_tolong(e1112) == 8 && 12| e1111.Eoper == OPu16_32) 12| evar = e1111.EV.E1; | } | } | 18| if (evar) | { 12| auto e22 = e2.EV.E2; 24| if (e22.Eoper == OPconst && el_tolong(e22) == 0xFF00) | { 12| auto e21 = e2.EV.E1; 12| if (e21.Eoper == OPshl) | { 12| auto e211 = e21.EV.E1; 12| auto e212 = e21.EV.E2; 18| if (e212.Eoper == OPconst && el_tolong(e212) == 8) | { 12| if (el_match5(evar, e211) && !el_sideeffect(e211)) | { 6| evar2 = e211; 6| e21.EV.E1 = null; | } | } | } | } | } | 18| if (evar2) | { 6| el_free(e1); 6| el_free(e2); 6| e.Eoper = OPbswap; 6| e.EV.E1 = evar2; 6| e.EV.E2 = null; | //printf("Matched byteswap(ushort)\n"); 6| return e; | } | } | } | | /* BSWAP: (data[0]<< 24) | (data[1]<< 16) | (data[2]<< 8) | (data[3]<< 0) | */ 5785| if (sz == 4 && OPTIMIZER) | { 442| elem*[4] ops; 442| int opsi = 0; 866| if (fillinops(ops.ptr, &opsi, 4, OPor, e) && opsi == 4) | { 18| elem *ex = null; 18| uint bmask = 0; 36| for (int i = 0; i < 4; i++) | { 18| elem *eo = ops[i]; 18| elem *eo2; 18| int shift; 18| elem *eo111; 18| if (eo.Eoper == OPu8_16 && 00000000| eo.EV.E1.Eoper == OPind) | { 00000000| eo111 = eo.EV.E1.EV.E1; 00000000| shift = 0; | } 18| else if (eo.Eoper == OPshl && 18| eo.EV.E1.Eoper == OPu8_16 && 18| (eo2 = eo.EV.E2).Eoper == OPconst && 18| eo.EV.E1.EV.E1.Eoper == OPind) | { 00000000| shift = cast(int)el_tolong(eo2); 00000000| switch (shift) | { 00000000| case 8: 00000000| case 16: 00000000| case 24: 00000000| break; | 00000000| default: 00000000| goto L1; | } 00000000| eo111 = eo.EV.E1.EV.E1.EV.E1; | } | else 18| goto L1; | 00000000| uint off; 00000000| elem *ed; 00000000| if (eo111.Eoper == OPadd) | { 00000000| ed = eo111.EV.E1; 00000000| if (eo111.EV.E2.Eoper != OPconst) 00000000| goto L1; 00000000| off = cast(uint)el_tolong(eo111.EV.E2); 00000000| if (off < 1 || off > 3) 00000000| goto L1; | } | else | { 00000000| ed = eo111; 00000000| off = 0; | } 00000000| switch ((off << 5) | shift) | { | // BSWAP 00000000| case (0 << 5) | 24: bmask |= 1; break; 00000000| case (1 << 5) | 16: bmask |= 2; break; 00000000| case (2 << 5) | 8: bmask |= 4; break; 00000000| case (3 << 5) | 0: bmask |= 8; break; | | // No swap 00000000| case (0 << 5) | 0: bmask |= 0x10; break; 00000000| case (1 << 5) | 8: bmask |= 0x20; break; 00000000| case (2 << 5) | 16: bmask |= 0x40; break; 00000000| case (3 << 5) | 24: bmask |= 0x80; break; | 00000000| default: 00000000| goto L1; | } 00000000| if (ex) | { 00000000| if (!el_match(ex, ed)) 00000000| goto L1; | } | else 00000000| { if (el_sideeffect(ed)) 00000000| goto L1; 00000000| ex = ed; | } | } | /* Got a match, build: | * BSWAP(*ex) | */ 00000000| if (bmask == 0x0F) 00000000| e = el_una(OPbswap, e.Ety, el_una(OPind, e.Ety, ex)); 00000000| else if (bmask == 0xF0) 00000000| e = el_una(OPind, e.Ety, ex); | else 00000000| goto L1; 00000000| return e; | } | } | L1: | 3600| return elbitwise(e, goal); |} | |/************************************* | */ | |private elem *elxor(elem *e, goal_t goal) |{ 20704| if (OPTIMIZER) | { 9114| elem *e1 = e.EV.E1; 9114| elem *e2 = e.EV.E2; | | /* Recognize: | * (a & c) ^ (b & c) => (a ^ b) & c | */ 9122| if (e1.Eoper == OPand && e2.Eoper == OPand && 00000000| el_match5(e1.EV.E2, e2.EV.E2) && 00000000| (e2.EV.E2.Eoper == OPconst || (!el_sideeffect(e2.EV.E1) && !el_sideeffect(e2.EV.E2)))) | { 00000000| el_free(e1.EV.E2); 00000000| e1.EV.E2 = e2.EV.E1; 00000000| e1.Eoper = OPxor; 00000000| e.Eoper = OPand; 00000000| e.EV.E2 = e2.EV.E2; 00000000| e2.EV.E1 = null; 00000000| e2.EV.E2 = null; 00000000| el_free(e2); 00000000| return optelem(e, GOALvalue); | } | } 20704| return elbitwise(e, goal); |} | |/************************** | * Optimize nots. | * ! ! e => bool e | * ! bool e => ! e | * ! OTrel => !OTrel (invert the condition) | * ! OTconv => ! | */ | |private elem * elnot(elem *e, goal_t goal) |{ 56179| elem *e1 = e.EV.E1; 56179| const op = e1.Eoper; 56179| switch (op) | { 107| case OPnot: // ! ! e => bool e 206| case OPbool: // ! bool e => ! e 206| e1.Eoper = cast(ubyte)(op ^ (OPbool ^ OPnot)); | /* That was a clever substitute for the following: */ | /* e.Eoper = (op == OPnot) ? OPbool : OPnot; */ 206| e = optelem(el_selecte1(e), goal); 206| break; | 54597| default: 54597| if (OTrel(op)) /* ! OTrel => !OTrel */ | { | /* Find the logical negation of the operator */ 216| auto op2 = rel_not(op); 216| if (!tyfloating(e1.EV.E1.Ety)) 193| { op2 = rel_integral(op2); 193| assert(OTrel(op2)); | } 216| e1.Eoper = cast(ubyte)op2; 216| e = optelem(el_selecte1(e), goal); | } 66880| else if (tybasic(e1.Ety) == TYbool && tysize(e.Ety) == 1) | { | // !e1 => (e1 ^ 1) 12499| e.Eoper = OPxor; 12499| e.EV.E2 = el_long(e1.Ety,1); 12499| e = optelem(e, goal); | } | else | { | static if (0) | { | // Can't use this because what if OPd_s32? | // Note: !(long)(.1) != !(.1) | if (OTconv(op)) // don't use case because of differ target | { // conversion operators | e1.Eoper = e.Eoper; | e = optelem(el_selecte1(e), goal); | break; | } | } | } 54597| break; | 00000000| case OPs32_d: 00000000| case OPs16_d: 00000000| case OPu16_d: 00000000| case OPu32_d: 2| case OPf_d: 2| case OPs16_32: 26| case OPu16_32: 53| case OPu8_16: 53| case OPs8_16: 67| case OPu32_64: 72| case OPs32_64: 72| case OPvp_fp: 72| case OPcvp_fp: 72| case OPnp_fp: 72| e1.Eoper = e.Eoper; 72| e = optelem(el_selecte1(e), goal); 72| break; | 1304| case OPcomma: | /* !(a,b) => (a,!b) */ 1304| e.Eoper = OPcomma; 1304| e.EV.E1 = e1.EV.E1; // a 1304| e.EV.E2 = e1; // ! 1304| e1.Eoper = OPnot; 1304| e1.Ety = e.Ety; 1304| e1.EV.E1 = e1.EV.E2; // b 1304| e1.EV.E2 = null; 1304| e = optelem(e, goal); 1304| break; | } 56179| return e; |} | |/************************* | * Complement | * ~ ~ e => e | */ | |private elem * elcom(elem *e, goal_t goal) |{ 766| elem *e1 = e.EV.E1; 766| if (e1.Eoper == OPcom) // ~ ~ e => e | // Typing problem here 00000000| e = el_selecte1(el_selecte1(e)); 766| return e; |} | |/************************* | * If it is a conditional of a constant | * then we know which exp to evaluate. | * BUG: | * doesn't detect ("string" ? et : ef) | */ | |private elem * elcond(elem *e, goal_t goal) |{ 27233| elem *e1 = e.EV.E1; 27233| switch (e1.Eoper) | { 00000000| case OPconst: 00000000| if (boolres(e1)) | L1: 00000000| e = el_selecte1(el_selecte2(e)); | else 00000000| e = el_selecte2(el_selecte2(e)); 00000000| break; | 00000000| case OPrelconst: 00000000| case OPstring: 00000000| goto L1; | 994| case OPcomma: | // ((a,b) ? c) => (a,(b ? c)) 994| e.Eoper = OPcomma; 994| e.EV.E1 = e1.EV.E1; 994| e1.EV.E1 = e1.EV.E2; 994| e1.EV.E2 = e.EV.E2; 994| e.EV.E2 = e1; 994| e1.Eoper = OPcond; 994| e1.Ety = e.Ety; 994| return optelem(e,GOALvalue); | 402| case OPnot: | { | // (!a ? b : c) => (a ? c : b) 402| elem *ex = e.EV.E2.EV.E1; 402| e.EV.E2.EV.E1 = e.EV.E2.EV.E2; 402| e.EV.E2.EV.E2 = ex; 402| goto L2; | } | 25837| default: 25837| if (OTboolnop(e1.Eoper)) | { | L2: 598| e.EV.E1 = e1.EV.E1; 598| e1.EV.E1 = null; 598| el_free(e1); 598| return elcond(e,goal); | } 25641| if (!OPTIMIZER) 12635| break; | | { 13006| tym_t ty = e.Ety; 13006| elem *ec1 = e.EV.E2.EV.E1; 13006| elem *ec2 = e.EV.E2.EV.E2; | 16317| if (tyintegral(ty) && ec1.Eoper == OPconst && ec2.Eoper == OPconst) | { 478| targ_llong i1 = el_tolong(ec1); 478| targ_llong i2 = el_tolong(ec2); 478| tym_t ty1 = tybasic(e1.Ety); | 1063| if ((ty1 == TYbool && !OTlogical(e1.Eoper) || e1.Eoper == OPand && e1.EV.E2.Eoper == OPconst) && 113| tysize(ty) == tysize(ec1.Ety)) | { 226| targ_llong b = ty1 == TYbool ? 1 : el_tolong(e1.EV.E2); | 226| if (b == 1 && ispow2(i1 - i2) != -1) | { | // replace (e1 ? i1 : i2) with (i1 + (e1 ^ 1) * (i2 - i1)) | // replace (e1 ? i2 : i1) with (i1 + e1 * (i2 - i1)) 24| int sz = tysize(e1.Ety); 72| while (sz < tysize(ec1.Ety)) | { | // Increase the size of e1 until it matches the size of ec1 48| switch (sz) | { 24| case 1: 24| e1 = el_una(OPu8_16, TYushort, e1); 24| sz = 2; 24| break; 24| case 2: 24| e1 = el_una(OPu16_32, TYulong, e1); 24| sz = 4; 24| break; 00000000| case 4: 00000000| e1 = el_una(OPu32_64, TYullong, e1); 00000000| sz = 8; 00000000| break; 00000000| default: 00000000| assert(0); | } | } 24| if (i1 < i2) | { 00000000| ec2.EV.Vllong = i2 - i1; 00000000| e1 = el_bin(OPxor,e1.Ety,e1,el_long(e1.Ety,1)); | } | else | { 24| ec1.EV.Vllong = i2; 24| ec2.EV.Vllong = i1 - i2; | } 24| e.EV.E1 = ec1; 24| e.EV.E2.Eoper = OPmul; 24| e.EV.E2.Ety = ty; 24| e.EV.E2.EV.E1 = e1; 24| e.Eoper = OPadd; 24| return optelem(e,GOALvalue); | } | | /* If b is an integer with only 1 bit set then | * replace ((a & b) ? b : 0) with (a & b) | * replace ((a & b) ? 0 : b) with ((a & b) ^ b) | */ 149| if (e1.Eoper == OPand && e1.EV.E2.Eoper == OPconst && ispow2(b) != -1) // if only 1 bit is set | { 24| if (b == i1 && i2 == 0) 00000000| { e = el_selecte1(e); 00000000| e.EV.E1.Ety = ty; 00000000| e.EV.E2.Ety = ty; 00000000| e.EV.E2.EV.Vllong = b; 00000000| return optelem(e,GOALvalue); | } 24| else if (i1 == 0 && b == i2) | { 00000000| e1.Ety = ty; 00000000| e1.EV.E1.Ety = ty; 00000000| e1.EV.E2.Ety = ty; 00000000| e1.EV.E2.EV.Vllong = b; 00000000| e.EV.E1 = el_bin(OPxor,ty,e1,el_long(ty,b)); 00000000| e = el_selecte1(e); 00000000| return optelem(e,GOALvalue); | } | } | } | | /* Replace ((a relop b) ? 1 : 0) with (a relop b) */ 365| else if (OTrel(e1.Eoper) && 323| tysize(ty) <= tysize(TYint)) | { 240| if (i1 == 1 && i2 == 0) 3| e = el_selecte1(e); 206| else if (i1 == 0 && i2 == 1) | { 5| e.EV.E1 = el_una(OPnot,ty,e1); 5| e = optelem(el_selecte1(e),GOALvalue); | } | } | | // The next two optimizations attempt to replace with an | // uint compare, which the code generator can generate | // code for without using jumps. | | // Try to replace (!e1) with (e1 < 1) 161| else if (e1.Eoper == OPnot && !OTrel(e1.EV.E1.Eoper) && e1.EV.E1.Eoper != OPand) | { 00000000| e.EV.E1 = el_bin(OPlt,TYint,e1.EV.E1,el_long(touns(e1.EV.E1.Ety),1)); 00000000| e1.EV.E1 = null; 00000000| el_free(e1); | } | // Try to replace (e1) with (e1 >= 1) 203| else if (!OTrel(e1.Eoper) && e1.Eoper != OPand) | { 42| if (tyfv(e1.Ety)) | { 00000000| if (tysize(e.Ety) == tysize(TYint)) | { 00000000| if (i1 == 1 && i2 == 0) 00000000| { e.Eoper = OPbool; 00000000| el_free(e.EV.E2); 00000000| e.EV.E2 = null; | } 00000000| else if (i1 == 0 && i2 == 1) 00000000| { e.Eoper = OPnot; 00000000| el_free(e.EV.E2); 00000000| e.EV.E2 = null; | } | } | } 42| else if(tyintegral(e1.Ety)) 42| e.EV.E1 = el_bin(OPge,TYint,e1,el_long(touns(e1.Ety),1)); | } | } | | // Try to detect absolute value expression | // (a < 0) -a : a 23897| else if ((e1.Eoper == OPlt || e1.Eoper == OPle) && 1285| e1.EV.E2.Eoper == OPconst && 00000000| !boolres(e1.EV.E2) && 00000000| !tyuns(e1.EV.E1.Ety) && 00000000| !tyuns(e1.EV.E2.Ety) && 00000000| ec1.Eoper == OPneg && 00000000| !el_sideeffect(ec2) && 00000000| el_match(e.EV.E1.EV.E1,ec2) && 00000000| el_match(ec1.EV.E1,ec2) && 00000000| tysize(ty) >= _tysize[TYint] | ) 00000000| { e.EV.E2.EV.E2 = null; 00000000| el_free(e); 00000000| e = el_una(OPabs,ty,ec2); | } | // (a >= 0) a : -a 25021| else if ((e1.Eoper == OPge || e1.Eoper == OPgt) && 43| e1.EV.E2.Eoper == OPconst && 43| !boolres(e1.EV.E2) && 43| !tyuns(e1.EV.E1.Ety) && 43| !tyuns(e1.EV.E2.Ety) && 43| ec2.Eoper == OPneg && 13| !el_sideeffect(ec1) && 6| el_match(e.EV.E1.EV.E1,ec1) && 6| el_match(ec2.EV.E1,ec1) && 6| tysize(ty) >= _tysize[TYint] | ) 6| { e.EV.E2.EV.E1 = null; 6| el_free(e); 6| e = el_una(OPabs,ty,ec1); | } | | /* Replace: | * a ? noreturn : c | * with: | * (a && noreturn), c | * because that means fewer noreturn cases for the data flow analysis to deal with | */ 12522| else if (!el_returns(ec1)) | { 00000000| e.Eoper = OPcomma; 00000000| e.EV.E1 = e.EV.E2; 00000000| e.EV.E2 = ec2; 00000000| e.EV.E1.Eoper = OPandand; 00000000| e.EV.E1.Ety = TYvoid; 00000000| e.EV.E1.EV.E2 = ec1; 00000000| e.EV.E1.EV.E1 = e1; | } | | /* Replace: | * a ? b : noreturn | * with: | * (a || noreturn), b | */ 12522| else if (!el_returns(ec2)) | { 00000000| e.Eoper = OPcomma; 00000000| e.EV.E1 = e.EV.E2; 00000000| e.EV.E2 = ec1; 00000000| e.EV.E1.Eoper = OPoror; 00000000| e.EV.E1.Ety = TYvoid; 00000000| e.EV.E1.EV.E2 = ec2; 00000000| e.EV.E1.EV.E1 = e1; | } | 12982| break; | } | } 25617| return e; |} | | |/**************************** | * Comma operator. | * , e | * / \ => expression with no effect | * c e | * , , | * / \ => / \ operators with no effect | * + e , e | * / \ / \ | * e e e e | */ | |private elem * elcomma(elem *e, goal_t goal) |{ 76| int changes = -1; |L1: 116| changes++; |L2: | //printf("elcomma()\n"); 116| elem *e2 = e.EV.E2; 116| elem **pe1 = &(e.EV.E1); 116| elem *e1 = *pe1; 116| int e1op = e1.Eoper; | | // c,e => e 268| if (OTleaf(e1op) && !OTsideff(e1op) && !(e1.Ety & (mTYvolatile | mTYshared))) | { 76| e2.Ety = e.Ety; 76| e = el_selecte2(e); 76| goto Lret; | } | | // ((a op b),e2) => ((a,b),e2) if op has no side effects 120| if (!el_sideeffect(e1) && e1op != OPcomma && e1op != OPandand && 80| e1op != OPoror && e1op != OPcond) | { 40| if (OTunary(e1op)) 40| *pe1 = el_selecte1(e1); /* get rid of e1 */ | else | { 00000000| e1.Eoper = OPcomma; 00000000| e1.Ety = e1.EV.E2.Ety; | } 40| goto L1; | } | 00000000| if (!OPTIMIZER) 00000000| goto Lret; | | /* Replace (a,b),e2 with a,(b,e2) */ 00000000| if (e1op == OPcomma) | { 00000000| e1.Ety = e.Ety; 00000000| e.EV.E1 = e1.EV.E1; 00000000| e1.EV.E1 = e1.EV.E2; 00000000| e1.EV.E2 = e2; 00000000| e.EV.E2 = elcomma(e1, GOALvalue); 00000000| goto L2; | } | 00000000| if ((OTopeq(e1op) || e1op == OPeq) && 00000000| (e1.EV.E1.Eoper == OPvar || e1.EV.E1.Eoper == OPind) && 00000000| !el_sideeffect(e1.EV.E1) | ) | { 00000000| if (el_match(e1.EV.E1,e2)) | // ((a = b),a) => (a = b) 00000000| e = el_selecte1(e); 00000000| else if (OTrel(e2.Eoper) && 00000000| OTleaf(e2.EV.E2.Eoper) && 00000000| el_match(e1.EV.E1,e2.EV.E1) | ) | { // ((a = b),(a < 0)) => ((a = b) < 0) 00000000| e1.Ety = e2.EV.E1.Ety; 00000000| e.EV.E1 = e2.EV.E1; 00000000| e2.EV.E1 = e1; 00000000| goto L1; | } 00000000| else if ((e2.Eoper == OPandand || 00000000| e2.Eoper == OPoror || 00000000| e2.Eoper == OPcond) && 00000000| el_match(e1.EV.E1,e2.EV.E1) | ) | { | /* ((a = b),(a || c)) => ((a = b) || c) */ 00000000| e1.Ety = e2.EV.E1.Ety; 00000000| e.EV.E1 = e2.EV.E1; 00000000| e2.EV.E1 = e1; 00000000| e = el_selecte2(e); 00000000| changes++; 00000000| goto Lret; | } 00000000| else if (e1op == OPeq) | { | /* Replace ((a = b),(c = a)) with a,(c = (a = b)) */ 00000000| for (; e2.Eoper == OPcomma; e2 = e2.EV.E1) | { } 00000000| if ((OTopeq(e2.Eoper) || e2.Eoper == OPeq) && 00000000| el_match(e1.EV.E1,e2.EV.E2) && | //!(e1.EV.E1.Eoper == OPvar && el_appears(e2.EV.E1,e1.EV.E1.EV.Vsym)) && 00000000| ERTOL(e2)) | { 00000000| e.EV.E1 = e2.EV.E2; 00000000| e1.Ety = e2.EV.E2.Ety; 00000000| e2.EV.E2 = e1; 00000000| goto L1; | } | } | else | { | static if (1) // This optimization is undone in eleq(). | { | // Replace ((a op= b),(a op= c)) with (0,a = (a op b) op c) 00000000| for (; e2.Eoper == OPcomma; e2 = e2.EV.E1) | { } 00000000| if ((OTopeq(e2.Eoper)) && 00000000| el_match(e1.EV.E1,e2.EV.E1)) | { 00000000| elem *ex; 00000000| e.EV.E1 = el_long(TYint,0); 00000000| e1.Eoper = cast(ubyte)opeqtoop(e1op); 00000000| e2.EV.E2 = el_bin(opeqtoop(e2.Eoper),e2.Ety,e1,e2.EV.E2); 00000000| e2.Eoper = OPeq; 00000000| goto L1; | } | } | } | } |Lret: 76| again = changes != 0; 76| return e; |} | |/******************************** | */ | |private elem * elremquo(elem *e, goal_t goal) |{ | static if (0) version (MARS) | if (cnst(e.EV.E2) && !boolres(e.EV.E2)) | error(e.Esrcpos.Sfilename, e.Esrcpos.Slinnum, e.Esrcpos.Scharnum, "divide by zero\n"); | 2400| return e; |} | |/******************************** | */ | |private elem * elmod(elem *e, goal_t goal) |{ 5500| tym_t tym = e.EV.E1.Ety; 5500| if (!tyfloating(tym)) 5267| return eldiv(e, goal); 233| return e; |} | |/***************************** | * Convert divides to >> if power of 2. | * Can handle OPdiv, OPdivass, OPmod. | */ | |private elem * eldiv(elem *e, goal_t goal) |{ | //printf("eldiv()\n"); 13015| elem *e2 = e.EV.E2; 13015| tym_t tym = e.EV.E1.Ety; 13015| int uns = tyuns(tym) | tyuns(e2.Ety); 13015| if (cnst(e2)) | { | static if (0) version (MARS) | if (!boolres(e2)) | error(e.Esrcpos.Sfilename, e.Esrcpos.Slinnum, e.Esrcpos.Scharnum, "divide by zero\n"); | 9852| if (uns) | { 4009| e2.Ety = touns(e2.Ety); 4009| int i = ispow2(el_tolong(e2)); 4009| if (i != -1) | { 873| OPER op; 873| switch (e.Eoper) 609| { case OPdiv: 609| op = OPshr; 609| goto L1; | 6| case OPdivass: 6| op = OPshrass; | L1: 615| e2.EV.Vint = i; 615| e2.Ety = TYint; 615| e.EV.E1.Ety = touns(tym); 615| break; | 258| case OPmod: 258| op = OPand; 258| goto L3; 00000000| case OPmodass: 00000000| op = OPandass; | L3: 258| e2.EV.Vullong = el_tolong(e2) - 1; 258| break; | 00000000| default: 00000000| assert(0); | } 873| e.Eoper = cast(ubyte)op; 873| return optelem(e,GOALvalue); | } | } | } | 12142| if (OPTIMIZER) | { 6665| const int SQRT_INT_MAX = 0xB504; 6665| const uint SQRT_UINT_MAX = 0x10000; 6665| elem *e1 = e.EV.E1; 16546| if (tyintegral(tym) && e.Eoper == OPdiv && e2.Eoper == OPconst && 3131| e1.Eoper == OPdiv && e1.EV.E2.Eoper == OPconst) | { | /* Replace: | * (e / c1) / c2 | * With: | * e / (c1 * c2) | */ 32| targ_llong c1 = el_tolong(e1.EV.E2); 32| targ_llong c2 = el_tolong(e2); 56| bool uns1 = tyuns(e1.EV.E1.Ety) || tyuns(e1.EV.E2.Ety); 56| bool uns2 = tyuns(e1.Ety) || tyuns(e2.Ety); 32| if (uns1 == uns2) // identity doesn't hold for mixed sign case | { | // The transformation will fail if c1*c2 overflows. This substitutes | // for a proper overflow check. 48| if (uns1 ? (c1 < SQRT_UINT_MAX && c2 < SQRT_UINT_MAX) 96| : (-SQRT_INT_MAX < c1 && c1 < SQRT_INT_MAX && -SQRT_INT_MAX < c2 && c2 < SQRT_INT_MAX)) | { 32| e.EV.E1 = e1.EV.E1; 32| e1.EV.E1 = e1.EV.E2; 32| e1.EV.E2 = e2; 32| e.EV.E2 = e1; 32| e1.Eoper = OPmul; 32| return optelem(e, GOALvalue); | } | } | } | 16450| if (tyintegral(tym) && e.Eoper == OPdiv && e2.Eoper == OPconst && 3067| e1.Eoper == OP64_32 && 00000000| e1.EV.E1.Eoper == OPremquo && e1.EV.E1.EV.E2.Eoper == OPconst) | { | /* Replace: | * (64_32 (e /% c1)) / c2 | * With: | * e / (c1 * c2) | */ 00000000| elem *erq = e1.EV.E1; 00000000| targ_llong c1 = el_tolong(erq.EV.E2); 00000000| targ_llong c2 = el_tolong(e2); 00000000| bool uns1 = tyuns(erq.EV.E1.Ety) || tyuns(erq.EV.E2.Ety); 00000000| bool uns2 = tyuns(e1.Ety) || tyuns(e2.Ety); 00000000| if (uns1 == uns2) // identity doesn't hold for mixed sign case | { | // The transformation will fail if c1*c2 overflows. This substitutes | // for a proper overflow check. 00000000| if (uns1 ? (c1 < SQRT_UINT_MAX && c2 < SQRT_UINT_MAX) 00000000| : (-SQRT_INT_MAX < c1 && c1 < SQRT_INT_MAX && -SQRT_INT_MAX < c2 && c2 < SQRT_INT_MAX)) | { 00000000| e.EV.E1 = erq.EV.E1; 00000000| erq.EV.E1 = erq.EV.E2; 00000000| erq.EV.E2 = e2; 00000000| e.EV.E2 = erq; 00000000| erq.Eoper = OPmul; 00000000| erq.Ety = e1.Ety; 00000000| e1.EV.E1 = null; 00000000| el_free(e1); 00000000| return optelem(e, GOALvalue); | } | } | } | | /* Convert if(e1/e2) to if(e1>=e2) iff uint division. | */ 7013| if (goal == GOALflags && uns && e.Eoper == OPdiv) | { 12| e.Eoper = OPge; 12| e.Ety = TYbool; 12| return e; | } | | /* TODO: (i*c1)/c2 => i*(c1/c2) if (c1%c2)==0 | * TODO: i/(x?c1:c2) => i>>(x?log2(c1):log2(c2)) if c1 and c2 are powers of 2 | */ | 15845| if (tyintegral(tym) && (e.Eoper == OPdiv || e.Eoper == OPmod)) | { 6339| int sz = tysize(tym); | | // See if we can replace with OPremquo 6339| if (sz == REGSIZE | // Currently don't allow this because OPmsw doesn't work for the case | //|| (I64 && sz == 4) | ) | { | // Don't do it if there are special code sequences in the | // code generator (see cdmul()) 2840| int pow2; 2840| if (e2.Eoper == OPconst && 2711| !uns && 2232| (pow2 = ispow2(el_tolong(e2))) != -1 && 1790| !(config.target_cpu < TARGET_80286 && pow2 != 1 && e.Eoper == OPdiv) | ) | { } | else | { 3150| assert(sz == 2 || sz == 4 || sz == 8); 1050| OPER op = OPmsw; 1050| if (e.Eoper == OPdiv) | { 1710| op = (sz == 2) ? OP32_16 : (sz == 4) ? OP64_32 : OP128_64; | } 1050| e.Eoper = OPremquo; 1050| e = el_una(op, tym, e); 3150| e.EV.E1.Ety = (sz == 2) ? TYlong : (sz == 4) ? TYllong : TYcent; 1050| return e; | } | } | } | } | 11048| return e; |} | |/************************** | * Convert (a op b) op c to a op (b op c). | */ | |private elem * swaplog(elem *e, goal_t goal) |{ 3744| elem *e1 = e.EV.E1; 3744| e.EV.E1 = e1.EV.E2; 3744| e1.EV.E2 = e; 3744| return optelem(e1,goal); |} | |private elem * eloror(elem *e, goal_t goal) |{ 252288| tym_t ty1,ty2; | 126144| elem *e1 = e.EV.E1; 126144| if (OTboolnop(e1.Eoper)) | { 3726| e.EV.E1 = e1.EV.E1; 3726| e1.EV.E1 = null; 3726| el_free(e1); 3726| return eloror(e, goal); | } | 122418| elem *e2 = e.EV.E2; 122418| if (OTboolnop(e2.Eoper)) | { 69| e.EV.E2 = e2.EV.E1; 69| e2.EV.E1 = null; 69| el_free(e2); 69| return eloror(e, goal); | } | 122349| if (OPTIMIZER) | { 27969| if (e1.Eoper == OPbool) 00000000| { ty1 = e1.EV.E1.Ety; 00000000| e1 = e.EV.E1 = el_selecte1(e1); 00000000| e1.Ety = ty1; | } 27969| if (e1.Eoper == OPoror) | { /* convert (a||b)||c to a||(b||c). This will find more CSEs. */ 96| return swaplog(e, goal); | } 27873| e2 = elscancommas(e2); 27873| e1 = elscancommas(e1); | } | 122253| tym_t t = e.Ety; 366681| if (e2.Eoper == OPconst || e2.Eoper == OPrelconst || e2.Eoper == OPstring) | { 39| if (boolres(e2)) /* e1 || 1 => e1 , 1 */ | { 1| if (e.EV.E2 == e2) 00000000| goto L2; | } | else /* e1 || 0 => bool e1 */ | { 38| if (e.EV.E2 == e2) | { 34| el_free(e.EV.E2); 34| e.EV.E2 = null; 34| e.Eoper = OPbool; 34| goto L3; | } | } | } | 351561| if (e1.Eoper == OPconst || e1.Eoper == OPrelconst || e1.Eoper == OPstring) | { 7549| if (boolres(e1)) /* (x,1) || e2 => (x,1),1 */ | { 2| if (tybasic(e.EV.E2.Ety) == TYvoid) | { 2| assert(!goal); 2| el_free(e); 2| return null; | } | else | { | L2: 00000000| e.Eoper = OPcomma; 00000000| el_free(e.EV.E2); 00000000| e.EV.E2 = el_long(t,1); | } | } | else /* (x,0) || e2 => (x,0),(bool e2) */ | { 7547| e.Eoper = OPcomma; 7547| if (tybasic(e.EV.E2.Ety) != TYvoid) 238| e.EV.E2 = el_una(OPbool,t,e.EV.E2); | } | } 114670| else if (OPTIMIZER && 27224| e.EV.E2.Eoper == OPvar && 00000000| !OTlogical(e1.Eoper) && 00000000| tysize(ty2 = e2.Ety) == tysize(ty1 = e1.Ety) && 00000000| tysize(ty1) <= _tysize[TYint] && 00000000| !tyfloating(ty2) && 00000000| !tyfloating(ty1) && 00000000| !(ty2 & (mTYvolatile | mTYshared))) | { /* Convert (e1 || e2) => (e1 | e2) */ 00000000| e.Eoper = OPor; 00000000| e.Ety = ty1; 00000000| e = el_una(OPbool,t,e); | } 114670| else if (OPTIMIZER && 27361| e1.Eoper == OPand && e2.Eoper == OPand && 00000000| tysize(e1.Ety) == tysize(e2.Ety) && 00000000| el_match(e1.EV.E1,e2.EV.E1) && !el_sideeffect(e1.EV.E1) && 00000000| !el_sideeffect(e2.EV.E2) | ) | { // Convert ((a & b) || (a & c)) => bool(a & (b | c)) 00000000| e.Eoper = OPbool; 00000000| e.EV.E2 = null; 00000000| e2.Eoper = OPor; 00000000| el_free(e2.EV.E1); 00000000| e2.EV.E1 = e1.EV.E2; 00000000| e1.EV.E2 = e2; | } | else 114670| goto L1; |L3: 7581| e = optelem(e,GOALvalue); |L1: 122251| return e; |} | |/********************************************** | * Try to rewrite sequence of || and && with faster operations, such as BT. | * Returns: | * false nothing changed | * true *pe is rewritten | */ | |private bool optim_loglog(elem **pe) |{ 107801| if (I16) 00000000| return false; 107801| elem *e = *pe; 107801| const op = e.Eoper; 138264| assert(op == OPandand || op == OPoror); 107801| size_t n = el_opN(e, op); 107801| if (n <= 3) 65021| return false; 42780| uint ty = e.Ety; 42780| elem **array = cast(elem **)malloc(n * (elem *).sizeof); 42780| assert(array); 42780| elem **p = array; 42780| el_opArray(&p, e, op); | 42780| bool any = false; 85560| size_t first, last; 85560| targ_ullong emin, emax; 85560| int cmpop = op == OPandand ? OPne : OPeqeq; 1361884| for (size_t i = 0; i < n; ++i) | { 638168| elem *eq = array[i]; 638168| if (eq.Eoper == cmpop && 872| eq.EV.E2.Eoper == OPconst && 872| tyintegral(eq.EV.E2.Ety) && 872| !el_sideeffect(eq.EV.E1)) | { 872| targ_ullong m = el_tolong(eq.EV.E2); 872| if (any) | { 748| if (el_match(array[first].EV.E1, eq.EV.E1)) | { 748| last = i; 748| if (m < emin) 170| emin = m; 748| if (m > emax) 496| emax = m; | } 00000000| else if (last - first > 2) 00000000| break; | else | { 00000000| first = last = i; 00000000| emin = emax = m; | } | } | else | { 124| any = true; 124| first = last = i; 124| emin = emax = m; | } | } 637322| else if (any && last - first > 2) 6| break; | else 637290| any = false; | } | | //printf("n = %d, count = %d, min = %d, max = %d\n", (int)n, last - first + 1, (int)emin, (int)emax); 42988| if (any && last - first > 2 && emax - emin < REGSIZE * 8) | { | /** | * Transforms expressions of the form x==c1 || x==c2 || x==c3 || ... into a single | * comparison by using a bitmapped representation of data, as follows. First, the | * smallest constant of c1, c2, ... (call it min) is subtracted from all constants | * and also from x (this step may be elided if all constants are small enough). Then, | * the test is expressed as | * (1 << (x-min)) | ((1 << (c1-min)) | (1 << (c2-min)) | ...) | * The test is guarded for overflow (x must be no larger than the largest of c1, c2, ...). | * Since each constant is encoded as a displacement in a bitmap, hitting any bit yields | * true for the expression. | * | * I.e. replace: | * e==c1 || e==c2 || e==c3 ... | * with: | * (e - emin) <= (emax - emin) && (1 << (int)(e - emin)) & bits | * where bits is: | * (1<<(c1-emin)) | (1<<(c2-emin)) | (1<<(c3-emin)) ... | * | * For the case of: | * x!=c1 && x!=c2 && x!=c3 && ... | * using De Morgan's theorem, rewrite as: | * (e - emin) > (emax - emin) || ((1 << (int)(e - emin)) & ~bits) | */ | | // Delete all the || nodes that are no longer referenced 104| el_opFree(e, op); | 104| if (emax < 32) // if everything fits in a 32 bit register 6| emin = 0; // no need for bias | | // Compute bit mask 104| targ_ullong bits = 0; 1832| for (size_t i = first; i <= last; ++i) | { 812| elem *eq = array[i]; 812| if (0 && eq.EV.E2.Eoper != OPconst) | { 00000000| printf("eq = %p, eq.EV.E2 = %p\n", eq, eq.EV.E2); 00000000| printf("first = %d, i = %d, last = %d, Eoper = %d\n", cast(int)first, cast(int)i, cast(int)last, eq.EV.E2.Eoper); 00000000| printf("any = %d, n = %d, count = %d, min = %d, max = %d\n", any, cast(int)n, cast(int)(last - first + 1), cast(int)emin, cast(int)emax); | } 812| assert(eq.EV.E2.Eoper == OPconst); 812| bits |= cast(targ_ullong)1 << (el_tolong(eq.EV.E2) - emin); | } | //printf("n = %d, count = %d, min = %d, max = %d\n", cast(int)n, last - first + 1, cast(int)emin, cast(int)emax); | //printf("bits = x%llx\n", bits); | 104| if (op == OPandand) 44| bits = ~bits; | 104| uint tyc = array[first].EV.E1.Ety; | 104| elem *ex = el_bin(OPmin, tyc, array[first].EV.E1, el_long(tyc,emin)); 208| ex = el_bin(op == OPandand ? OPgt : OPle, TYbool, ex, el_long(touns(tyc), emax - emin)); 104| elem *ey = el_bin(OPmin, tyc, array[first + 1].EV.E1, el_long(tyc,emin)); | 104| tym_t tybits = TYuint; 104| if ((emax - emin) >= 32) | { 82| assert(I64); // need 64 bit BT 82| tybits = TYullong; | } | | // Shift count must be an int 104| switch (tysize(tyc)) | { 00000000| case 1: 00000000| ey = el_una(OPu8_16,TYint,ey); 00000000| goto case 2; | 00000000| case 2: 00000000| ey = el_una(OPu16_32,TYint,ey); 00000000| break; | 85| case 4: 85| break; | 19| case 8: 19| ey = el_una(OP64_32,TYint,ey); 19| break; | 00000000| default: 00000000| assert(0); | } 104| ey = el_bin(OPbtst,TYbool,el_long(tybits,bits),ey); 208| ex = el_bin(op == OPandand ? OPoror : OPandand, ty, ex, ey); | | /* Free unneeded nodes | */ 104| array[first].EV.E1 = null; 104| el_free(array[first]); 104| array[first + 1].EV.E1 = null; 104| el_free(array[first + 1]); 1416| for (size_t i = first + 2; i <= last; ++i) 604| el_free(array[i]); | 104| array[first] = ex; | 220| for (size_t i = first + 1; i + (last - first) < n; ++i) 6| array[i] = array[i + (last - first)]; 104| n -= last - first; 104| (*pe) = el_opCombine(array, n, op, ty); | 104| free(array); 104| return true; | } | 42676| free(array); 42676| return false; |} | |private elem * elandand(elem *e, goal_t goal) |{ 112831| elem *e1 = e.EV.E1; 112831| if (OTboolnop(e1.Eoper)) | { 190| e.EV.E1 = e1.EV.E1; 190| e1.EV.E1 = null; 190| el_free(e1); 190| return elandand(e, goal); | } 112641| elem *e2 = e.EV.E2; 112641| if (OTboolnop(e2.Eoper)) | { 234| e.EV.E2 = e2.EV.E1; 234| e2.EV.E1 = null; 234| el_free(e2); 234| return elandand(e, goal); | } 112407| if (OPTIMIZER) | { | /* Recognize: (a >= c1 && a < c2) | */ 153609| if ((e1.Eoper == OPge || e1.Eoper == OPgt) && 4940| (e2.Eoper == OPlt || e2.Eoper == OPle) && 3916| e1.EV.E2.Eoper == OPconst && e2.EV.E2.Eoper == OPconst && 3627| !el_sideeffect(e1.EV.E1) && el_match(e1.EV.E1, e2.EV.E1) && 1684| tyintegral(e1.EV.E1.Ety) && 1680| tybasic(e1.EV.E2.Ety) == tybasic(e2.EV.E2.Ety) && 1680| tysize(e1.EV.E1.Ety) == _tysize[TYnptr]) | { | /* Replace with: ((a - c1) < (c2 - c1)) | */ 00000000| targ_llong c1 = el_tolong(e1.EV.E2); 00000000| if (e1.Eoper == OPgt) 00000000| ++c1; 00000000| targ_llong c2 = el_tolong(e2.EV.E2); 00000000| if (0 <= c1 && c1 <= c2) | { 00000000| e1.Eoper = OPmin; 00000000| e1.Ety = e1.EV.E1.Ety; 00000000| e1.EV.E2.EV.Vllong = c1; 00000000| e.EV.E2 = el_long(touns(e2.EV.E2.Ety), c2 - c1); 00000000| e.Eoper = e2.Eoper; 00000000| el_free(e2); 00000000| return optelem(e, GOALvalue); | } | } | | // Look for (!(e >>> c) && ...) 89792| if (e1.Eoper == OPnot && e1.EV.E1.Eoper == OPshr && 00000000| e1.EV.E1.EV.E2.Eoper == OPconst) | { | // Replace (e >>> c) with (e & x) 00000000| elem *e11 = e1.EV.E1; | 00000000| targ_ullong shift = el_tolong(e11.EV.E2); 00000000| if (shift < _tysize[TYint] * 8) | { 00000000| targ_ullong m; 00000000| m = ~0L << cast(int)shift; 00000000| e11.Eoper = OPand; 00000000| e11.EV.E2.EV.Vullong = m; 00000000| e11.EV.E2.Ety = e11.Ety; 00000000| return optelem(e,GOALvalue); | } | } | 76955| if (e1.Eoper == OPbool) | { 00000000| tym_t t = e1.EV.E1.Ety; 00000000| e1 = e.EV.E1 = el_selecte1(e1); 00000000| e1.Ety = t; | } 76955| if (e1.Eoper == OPandand) | { // convert (a&&b)&&c to a&&(b&&c). This will find more CSEs. 3648| return swaplog(e, goal); | } 73307| e2 = elscancommas(e2); | 73307| while (1) | { 73307| e1 = elscancommas(e1); 73307| if (e1.Eoper == OPeq) 00000000| e1 = e1.EV.E2; | else 73307| break; | } | } | 325747| if (e2.Eoper == OPconst || e2.Eoper == OPrelconst || e2.Eoper == OPstring) | { 265| if (boolres(e2)) // e1 && (x,1) => e1 ? ((x,1),1) : 0 | { 204| if (e2 == e.EV.E2) // if no x, replace e with (bool e1) | { 194| el_free(e2); 194| e.EV.E2 = null; 194| e.Eoper = OPbool; 194| goto L3; | } | } | else // e1 && (x,0) => e1 , (x,0) | { 61| if (e2 == e.EV.E2) 61| { e.Eoper = OPcomma; 61| goto L3; | } | } | } | 324852| if (e1.Eoper == OPconst || e1.Eoper == OPrelconst || e1.Eoper == OPstring) | { 330| e.Eoper = OPcomma; 330| if (boolres(e1)) // (x,1) && e2 => (x,1),bool e2 | { 330| if (tybasic(e.EV.E2.Ety) != TYvoid) 324| e.EV.E2 = el_una(OPbool,e.Ety,e.EV.E2); | } | else // (x,0) && e2 => (x,0),0 | { 00000000| if (tybasic(e.EV.E2.Ety) == TYvoid) | { 00000000| assert(!goal); 00000000| el_free(e); 00000000| return null; | } | else | { 00000000| el_free(e.EV.E2); 00000000| e.EV.E2 = el_long(e.Ety,0); | } | } | } | else 108174| goto L1; |L3: 585| e = optelem(e,GOALvalue); |L1: 108759| return e; |} | |/************************** | * Reference to bit field | * bit | * / \ => ((e << c) >> b) & m | * e w,b | * | * Note that this routine can handle long bit fields, though this may | * not be supported later on. | */ | |private elem * elbit(elem *e, goal_t goal) |{ | 00000000| tym_t tym1 = e.EV.E1.Ety; 00000000| uint sz = tysize(tym1) * 8; 00000000| elem *e2 = e.EV.E2; 00000000| uint wb = e2.EV.Vuns; | 00000000| uint w = (wb >> 8) & 0xFF; // width in bits of field 00000000| targ_ullong m = (cast(targ_ullong)1 << w) - 1; // mask w bits wide 00000000| uint b = wb & 0xFF; // bits to right of field 00000000| uint c = 0; 00000000| assert(w + b <= sz); | 00000000| if (tyuns(tym1)) // if uint bit field | { | // Should use a more general solution to this 00000000| if (w == 8 && sz == 16 && b == 0) | { 00000000| e.EV.E1 = el_una(OP16_8,TYuchar,e.EV.E1); 00000000| e.Eoper = OPu8_16; 00000000| e.EV.E2 = null; 00000000| el_free(e2); 00000000| goto L1; | } | 00000000| if (w + b == sz) // if field is left-justified 00000000| m = ~cast(targ_ullong)0; // no need to mask | } | else // signed bit field | { 00000000| if (w == 8 && sz == 16 && b == 0) | { 00000000| e.EV.E1 = el_una(OP16_8,TYschar,e.EV.E1); 00000000| e.Eoper = OPs8_16; 00000000| e.EV.E2 = null; 00000000| el_free(e2); 00000000| goto L1; | } 00000000| m = ~cast(targ_ullong)0; 00000000| c = sz - (w + b); 00000000| b = sz - w; | } | 00000000| e.Eoper = OPand; | 00000000| e2.EV.Vullong = m; // mask w bits wide 00000000| e2.Ety = e.Ety; | 00000000| e.EV.E1 = el_bin(OPshr,tym1, | el_bin(OPshl,tym1,e.EV.E1,el_long(TYint,c)), | el_long(TYint,b)); |L1: 00000000| return optelem(e,GOALvalue); // optimize result |} | |/***************** | * Indirection | * * & e => e | */ | |private elem * elind(elem *e, goal_t goal) |{ 1648191| tym_t tym = e.Ety; 1648191| elem *e1 = e.EV.E1; 1648191| switch (e1.Eoper) | { 289557| case OPrelconst: 289557| e.EV.E1.ET = e.ET; 289557| e = el_selecte1(e); 289557| e.Eoper = OPvar; 289557| e.Ety = tym; /* preserve original type */ 289557| break; | 560316| case OPadd: 560316| if (OPTIMIZER) | { /* Try to convert far pointer to stack pointer */ 171405| elem *e12 = e1.EV.E2; | 171405| if (e12.Eoper == OPrelconst && 902| tybasic(e12.Ety) == TYfptr && | /* If symbol is located on the stack */ 00000000| sytab[e12.EV.Vsym.Sclass] & SCSS) 00000000| { e1.Ety = (e1.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared | mTYLINK)) | TYsptr; 00000000| e12.Ety = (e12.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared | mTYLINK)) | TYsptr; | } | } 560316| break; | 27227| case OPcomma: | // Replace (*(ea,eb)) with (ea,*eb) 27227| e.EV.E1.ET = e.ET; 27227| type *t = e.ET; 27227| e = el_selecte1(e); 27227| e.Ety = tym; 27227| e.EV.E2 = el_una(OPind,tym,e.EV.E2); 27227| e.EV.E2.ET = t; 27227| again = 1; 27227| return e; | 771091| default: 771091| break; | } 3241928| topair |= (config.fpxmmregs && tycomplex(tym)); 1620964| return e; |} | |/***************** | * Address of. | * & v => &v | * & * e => e | * & (v1 = v2) => ((v1 = v2), &v1) | */ | |private elem * eladdr(elem *e, goal_t goal) |{ 540243| tym_t tym = e.Ety; 540243| elem *e1 = e.EV.E1; 540243| elem_debug(e1); 540243| switch (e1.Eoper) | { 44127| case OPvar: 44127| e1.Eoper = OPrelconst; 44127| e1.EV.Vsym.Sflags &= ~(SFLunambig | GTregcand); 44127| e1.Ety = tym; 44127| e = optelem(el_selecte1(e),GOALvalue); 44127| break; | 458270| case OPind: | { 458270| tym_t tym2 = e1.EV.E1.Ety; | | // Watch out for conversions between near and far pointers 458270| int sz = tysize(tym) - tysize(tym2); 458270| if (sz != 0) | { 00000000| OPER op; 00000000| if (sz > 0) // if &far * near 00000000| op = OPnp_fp; | else // else &near * far 00000000| op = OPoffset; 00000000| e.Ety = tym2; 00000000| e = el_una(op,tym,e); 00000000| goto L1; | } | 458270| e = el_selecte1(el_selecte1(e)); 458270| e.Ety = tym; 458270| break; | } | 36492| case OPcomma: | // Replace (&(ea,eb)) with (ea,&eb) 36492| e = el_selecte1(e); 36492| e.Ety = tym; 36492| e.EV.E2 = el_una(OPaddr,tym,e.EV.E2); | L1: 36526| e = optelem(e,GOALvalue); 36526| break; | 00000000| case OPnegass: 00000000| assert(0); | 00000000| default: 00000000| if (OTassign(e1.Eoper)) | { 34| case OPstreq: | // & (v1 = e) => ((v1 = e), &v1) 34| if (e1.EV.E1.Eoper == OPvar) | { 34| e.Eoper = OPcomma; 34| e.EV.E2 = el_una(OPaddr,tym,el_copytree(e1.EV.E1)); 34| goto L1; | } | // & (*p1 = e) => ((*(t = p1) = e), t) 00000000| else if (e1.EV.E1.Eoper == OPind) | { 00000000| const tym_t tym111 = e1.EV.E1.EV.E1.Ety; 00000000| elem *tmp = el_alloctmp(tym111); 00000000| e1.EV.E1.EV.E1 = el_bin(OPeq,tym111,tmp,e1.EV.E1.EV.E1); 00000000| e.Eoper = OPcomma; 00000000| e.EV.E2 = el_copytree(tmp); 00000000| goto L1; | } | } 00000000| break; | 1288| case OPcond: | { // Replace &(x ? y : z) with (x ? &y : &z) 1288| elem *ecolon = e1.EV.E2; 1288| ecolon.Ety = tym; 1288| ecolon.EV.E1 = el_una(OPaddr,tym,ecolon.EV.E1); 1288| ecolon.EV.E2 = el_una(OPaddr,tym,ecolon.EV.E2); 1288| e = el_selecte1(e); 1288| e = optelem(e,GOALvalue); 1288| break; | } | 32| case OPinfo: | // Replace &(e1 info e2) with (e1 info &e2) 32| e = el_selecte1(e); 32| e.EV.E2 = el_una(OPaddr,tym,e.EV.E2); 32| e = optelem(e,GOALvalue); 32| break; | } 540243| return e; |} | |/******************************************* | */ | |private elem * elneg(elem *e, goal_t goal) |{ 2450| if (e.EV.E1.Eoper == OPneg) | { 8| e = el_selecte1(e); 8| e = el_selecte1(e); | } | /* Convert -(e1 + c) to (-e1 - c) | */ 2459| else if (e.EV.E1.Eoper == OPadd && e.EV.E1.EV.E2.Eoper == OPconst) | { 14| e.Eoper = OPmin; 14| e.EV.E2 = e.EV.E1.EV.E2; 14| e.EV.E1.Eoper = OPneg; 14| e.EV.E1.EV.E2 = null; 14| e = optelem(e,goal); | } | else 2428| e = evalu8(e, goal); 2450| return e; |} | |private elem * elcall(elem *e, goal_t goal) |{ 1622551| if (e.EV.E1.Eoper == OPcomma || OTassign(e.EV.E1.Eoper)) 49| e = cgel_lvalue(e); 811300| return e; |} | |/*************************** | * Walk tree, converting types to tym. | */ | |private void elstructwalk(elem *e,tym_t tym) |{ 22606| tym_t ety; | 26249| while ((ety = tybasic(e.Ety)) == TYstruct || 450| ety == TYarray) 26167| { elem_debug(e); 26167| e.Ety = (e.Ety & ~mTYbasic) | tym; 26167| switch (e.Eoper) | { 3523| case OPcomma: 3583| case OPcond: 3583| case OPinfo: 3583| break; | 00000000| case OPeq: 60| case OPcolon: 60| case OPcolon2: 60| elstructwalk(e.EV.E1,tym); 60| break; | 22524| default: 22524| return; | } 3643| e = e.EV.E2; | } |} | |/******************************* | * See if we can replace struct operations with simpler ones. | * For OPstreq and OPstrpar. | */ | |elem * elstruct(elem *e, goal_t goal) |{ | //printf("elstruct(%p)\n", e); | //elem_print(e); 442477| if (e.Eoper == OPstreq && (e.EV.E1.Eoper == OPcomma || OTassign(e.EV.E1.Eoper))) 307| return cgel_lvalue(e); | 298609| if (e.Eoper == OPstreq && e.EV.E2.Eoper == OPcomma) | { | /* Replace (e1 streq (e21, e22)) with (e21, (e1 streq e22)) | */ 15461| e.EV.E2.Eoper = e.Eoper; 15461| e.EV.E2.Ety = e.Ety; 15461| e.EV.E2.ET = e.ET; 15461| e.Eoper = OPcomma; 15461| elem *etmp = e.EV.E1; 15461| e.EV.E1 = e.EV.E2.EV.E1; 15461| e.EV.E2.EV.E1 = etmp; 15461| return optelem(e, goal); | } | 139894| if (!e.ET) 87| return e; | //printf("\tnumbytes = %d\n", (int)type_size(e.ET)); | 139807| type *t = e.ET; 139807| tym_t tym = ~0; 139807| tym_t ty = tybasic(t.Tty); | 287701| uint sz = (e.Eoper == OPstrpar && type_zeroSize(t, global_tyf)) ? 0 : cast(uint)type_size(t); | //printf("\tsz = %d\n", (int)sz); 139807| if (sz == 16) | { 33801| while (ty == TYarray && t.Tdim == 1) | { 22| t = t.Tnext; 22| ty = tybasic(t.Tty); | } | } | 139807| type *targ1 = null; 139807| type *targ2 = null; 139807| if (ty == TYstruct) | { // If a struct is a wrapper for another type, prefer that other type 133078| targ1 = t.Ttag.Sstruct.Sarg1type; 133078| targ2 = t.Ttag.Sstruct.Sarg2type; | } | | //if (targ1) { printf("targ1\n"); type_print(targ1); } | //if (targ2) { printf("targ2\n"); type_print(targ2); } 139807| switch (cast(int)sz) | { 61194| case 1: tym = TYchar; goto L1; 7737| case 2: tym = TYshort; goto L1; 122715| case 4: tym = TYlong; goto L1; 56084| case 8: if (_tysize[TYint] == 2) 00000000| goto Ldefault; 56084| tym = TYllong; goto L1; | 2454| case 3: tym = TYlong; goto L2; 200| case 5: 295| case 6: 606| case 7: tym = TYllong; | L2: 1329| if (e.Eoper == OPstrpar && config.exe == EX_WIN64) | { 00000000| goto L1; | } 1537| if (e.Eoper == OPstrpar && I64 && ty == TYstruct) | { 36| goto L1; | } 1085| tym = ~0; 1085| goto Ldefault; | 43| case 10: 1105| case 12: 1105| if (tysize(TYldouble) == sz && targ1 && !targ2 && tybasic(targ1.Tty) == TYldouble) | { 00000000| tym = TYldouble; 00000000| goto L1; | } 1105| goto case 9; | 1151| case 9: 1188| case 11: 1196| case 13: 1212| case 14: 1220| case 15: 1712| if (e.Eoper == OPstrpar && I64 && ty == TYstruct && config.exe != EX_WIN64) | { 102| goto L1; | } 1118| goto Ldefault; | 31393| case 16: 67519| if (I64 && (ty == TYstruct || (ty == TYarray && config.exe == EX_WIN64))) | { 29024| tym = TYucent; 29024| goto L1; | } 2369| if (config.exe == EX_WIN64) 00000000| goto Ldefault; 2369| if (targ1 && !targ2) 00000000| goto L1; 2369| goto Ldefault; | | L1: 121086| if (ty == TYstruct) | { // This needs to match what TypeFunction::retStyle() does 120297| if (config.exe == EX_WIN64) | { | //if (t.Ttag.Sstruct.Sflags & STRnotpod) | //goto Ldefault; | } | // If a struct is a wrapper for another type, prefer that other type 134495| else if (targ1 && !targ2) 7089| tym = targ1.Tty; 332515| else if (I64 && !targ1 && !targ2) | { 106099| if (t.Ttag.Sstruct.Sflags & STRnotpod) | { | // In-memory only 104564| goto Ldefault; | } |// if (type_size(t) == 16) 1535| goto Ldefault; | } 21327| else if (I64 && targ1 && targ2) | { 7109| if (tyfloating(tybasic(targ1.Tty))) 367| tym = TYcdouble; | else 6742| tym = TYucent; | } 14198| assert(tym != TYstruct); | } 14987| assert(tym != ~0); 14987| switch (e.Eoper) | { 7559| case OPstreq: 7559| e.Eoper = OPeq; 7559| e.Ety = (e.Ety & ~mTYbasic) | tym; 7559| elstructwalk(e.EV.E1,tym); 7559| elstructwalk(e.EV.E2,tym); 7559| e = optelem(e,GOALvalue); 7559| break; | 4749| case OPstrpar: 4749| e = el_selecte1(e); 4749| goto default; | 7428| default: /* called by doptelem() */ 7428| elstructwalk(e,tym); 7428| break; | } 14987| break; | 55| case 0: 55| if (e.Eoper == OPstreq) | { 38| e.Eoper = OPcomma; 38| e = optelem(e,GOALvalue); 38| again = 1; | } | else 17| goto Ldefault; 38| break; | 14094| default: | Ldefault: | { 124782| elem **pe2; 124782| if (e.Eoper == OPstreq) 120196| pe2 = &e.EV.E2; 4586| else if (e.Eoper == OPstrpar) 3338| pe2 = &e.EV.E1; | else 1248| break; 124388| while ((*pe2).Eoper == OPcomma) 854| pe2 = &(*pe2).EV.E2; 123534| elem *e2 = *pe2; | 123534| if (e2.Eoper == OPvar) 79757| e2.EV.Vsym.Sflags &= ~GTregcand; | | // Convert (x streq (a?y:z)) to (x streq *(a ? &y : &z)) 123534| if (e2.Eoper == OPcond) | { 1287| tym_t ty2 = e2.Ety; | | /* We should do the analysis to see if we can use | something simpler than TYfptr. | */ 2574| tym_t typ = (_tysize[TYint] == LONGSIZE) ? TYnptr : TYfptr; 1287| e2 = el_una(OPaddr,typ,e2); 1287| e2 = optelem(e2,GOALvalue); /* distribute & to x and y leaves */ 1287| *pe2 = el_una(OPind,ty2,e2); 1287| break; | } 122247| break; | } | } 139807| return e; |} | |/************************** | * Assignment. Replace bit field assignment with | * equivalent tree. | * = | * / \ | * / r | * bit | * / \ | * l w,b | * | * becomes: | * , | * / \ | * = (r&m) | * / \ | * l | | * / \ | * (r&m)<= 4) 12| ty = (REGSIZE == 8) ? TYdouble : TYfloat; 2003| ty |= e1.Ety & ~mTYbasic; 2003| e2.Ety = ty; 2003| e.Ety = ty; 2003| e1.Ety = ty; 2003| elem *eb = el_copytree(e1); 2003| eb.EV.Voffset += REGSIZE; | 2003| if (e2.Eoper == OPpair) | { 166| e.EV.E2 = e2.EV.E1; 166| eb = el_bin(OPeq,ty,eb,e2.EV.E2); 166| e2.EV.E1 = e; 166| e2.EV.E2 = eb; | } | else | { 1837| e.EV.E2 = e2.EV.E2; 1837| eb = el_bin(OPeq,ty,eb,e2.EV.E1); 1837| e2.EV.E1 = eb; 1837| e2.EV.E2 = e; | } | 2003| e2.Eoper = OPcomma; | // printf("** after:\n"); elem_print(e2); printf("\n"); 2003| return optelem(e2,goal); | } | | // Replace (a=b) with (a1=b1),(a2=b2) 541544| if (tysize(e1.Ety) == 2 * REGSIZE && 25141| e1.Eoper == OPvar && 18603| e2.Eoper == OPvar && 2563| goal == GOALnone && 4161| !tyfloating(e1.Ety) && !tyvector(e1.Ety) | ) | { 3532| tym_t ty = (REGSIZE == 8) ? TYllong : TYint; 1766| ty |= e1.Ety & ~mTYbasic; 1766| e2.Ety = ty; 1766| e.Ety = ty; 1766| e1.Ety = ty; | 1766| elem *eb = el_copytree(e); 1766| eb.EV.E1.EV.Voffset += REGSIZE; 1766| eb.EV.E2.EV.Voffset += REGSIZE; | 1766| e = el_bin(OPcomma,ty,e,eb); 1766| return optelem(e,goal); | } | } | 998881| if (e1.Eoper == OPcomma) 00000000| return cgel_lvalue(e); |version (MARS) |{ | // No bit fields to deal with 998881| return e; |} |else |{ | if (e1.Eoper != OPbit) | return e; | if (e1.EV.E1.Eoper == OPcomma || OTassign(e1.EV.E1.Eoper)) | return cgel_lvalue(e); | | uint t = e.Ety; | elem *l = e1.EV.E1; // lvalue | elem *r = e.EV.E2; | tym_t tyl = l.Ety; | uint sz = tysize(tyl) * 8; | uint w = (e1.EV.E2.EV.Vuns >> 8); // width in bits of field | targ_ullong m = (cast(targ_ullong)1 << w) - 1; // mask w bits wide | uint b = e1.EV.E2.EV.Vuns & 0xFF; // bits to shift | | elem *l2; | elem *r2; | elem *eres = el_bin(OPeq,t, | l, | el_bin(OPor,t, | el_bin(OPshl,t, | (r2 = el_bin(OPand,t,r,el_long(t,m))), | el_long(TYint,b) | ), | el_bin(OPand,t, | (l2 = el_copytree(l)), | el_long(t,~(m << b)) | ) | ) | ); | eres.Esrcpos = e.Esrcpos; // save line information | if (OPTIMIZER && w + b == sz) | r2.EV.E2.EV.Vllong = ~ZEROLL; // no need to mask if left justified | if (wantres) | { | uint c; | elem **pe; | elem *e2; | | r = el_copytree(r); | if (tyuns(tyl)) /* uint bit field */ | { | e2 = el_bin(OPand,t,r,el_long(t,m)); | pe = &e2.EV.E1; | } | else /* signed bit field */ | { | c = sz - w; /* e2 = (r << c) >> c */ | e2 = el_bin(OPshr,t,el_bin(OPshl,tyl,r,el_long(TYint,c)),el_long(TYint,c)); | pe = &e2.EV.E1.EV.E1; | } | eres = el_bin(OPcomma,t,eres,e2); | if (!OTleaf(r.Eoper)) | fixside(&(r2.EV.E1),pe); | } | | if (!OTleaf(l.Eoper) && !OTleaf(l.EV.E1.Eoper)) | fixside(&(l2.EV.E1),&(l.EV.E1)); | e1.EV.E1 = e.EV.E2 = null; | el_free(e); | return optelem(eres,GOALvalue); |} |} | |/********************************** | */ | |private elem * elnegass(elem *e, goal_t goal) |{ 48| e = cgel_lvalue(e); 48| return e; |} | |/************************** | * Add assignment. Replace bit field assignment with | * equivalent tree. | * += | * / \ | * / r | * bit | * / \ | * l w,b | * | * becomes: | * = | * / \ | * l | | * / \ | * << \ | * / \ \ | * & b & | * / \ / \ | * op m l ~(m<> m | * / \ | * l b | */ | |private elem * elopass(elem *e, goal_t goal) |{ 234166| elem *e1 = e.EV.E1; 234166| if (OTconv(e1.Eoper)) 6343| { e = fixconvop(e); 6343| return optelem(e,GOALvalue); | } |version (SCPP) // have bit fields to worry about? |{ | goal_t wantres = goal; | if (e1.Eoper == OPbit) | { | const op = opeqtoop(e.Eoper); | | // Make sure t is uint | // so >> doesn't have to be masked | tym_t t = touns(e.Ety); | | assert(tyintegral(t)); | elem *l = e1.EV.E1; // lvalue | tym_t tyl = l.Ety; | elem *r = e.EV.E2; | uint w = (e1.EV.E2.EV.Vuns >> 8) & 0xFF; // width in bits of field | targ_llong m = (cast(targ_llong)1 << w) - 1; // mask w bits wide | uint b = e1.EV.E2.EV.Vuns & 0xFF; // bits to shift | | elem* l2,l3,op2,eres; | | if (tyuns(tyl)) | { | eres = el_bin(OPeq,t, | l, | el_bin(OPor,t, | (op2=el_bin(OPshl,t, | el_bin(OPand,t, | el_bin(op,t, | el_bin(OPand,t, | el_bin(OPshr,t, | (l2=el_copytree(l)), | el_long(TYint,b) | ), | el_long(t,m) | ), | r | ), | el_long(t,m) | ), | el_long(TYint,b) | )), | el_bin(OPand,t, | l3=el_copytree(l), | el_long(t,~(m << b)) | ) | ) | ); | | if (wantres) | { | eres = el_bin(OPcomma,t,eres,el_copytree(op2.EV.E1)); | fixside(&(op2.EV.E1),&(eres.EV.E2)); | } | } | else | { /* signed bit field | rewrite to: (l bit w,b) = ((l bit w,b) op r) | */ | e.Eoper = OPeq; | e.EV.E2 = el_bin(op,t,el_copytree(e1),r); | if (l.Eoper == OPind) | fixside(&e.EV.E2.EV.E1.EV.E1.EV.E1,&l.EV.E1); | eres = e; | goto ret; | } | | if (!OTleaf(l.Eoper) && !OTleaf(l.EV.E1.Eoper)) | { | fixside(&(l2.EV.E1),&(l.EV.E1)); | el_free(l3.EV.E1); | l3.EV.E1 = el_copytree(l.EV.E1); | } | | e1.EV.E1 = e.EV.E2 = null; | el_free(e); | ret: | e = optelem(eres,GOALvalue); | return e; | } |} | { 450364| if (e1.Eoper == OPcomma || OTassign(e1.Eoper)) 5282| e = cgel_lvalue(e); // replace (e,v)op=e2 with e,(v op= e2) | else | { 222541| switch (e.Eoper) | { 10841| case OPmulass: 10841| e = elmul(e,GOALvalue); 10841| break; | 786| case OPdivass: | // Replace r/=c with r=r/c 804| if (tycomplex(e.EV.E2.Ety) && !tycomplex(e1.Ety)) | { 00000000| elem *ed; 00000000| e.Eoper = OPeq; 00000000| if (e1.Eoper == OPind) | { // ed: *(tmp=e1.EV.E1) | // e1: *tmp 00000000| elem *tmp = el_alloctmp(e1.EV.E1.Ety); 00000000| ed = el_bin(OPeq, tmp.Ety, tmp, e1.EV.E1); 00000000| e1.EV.E1 = el_copytree(tmp); 00000000| ed = el_una(OPind, e1.Ety, ed); | } | else 00000000| ed = el_copytree(e1); | // e: e1=ed/e2 00000000| e.EV.E2 = el_bin(OPdiv, e.EV.E2.Ety, ed, e.EV.E2); 00000000| if (tyreal(e1.Ety)) 00000000| e.EV.E2 = el_una(OPc_r, e1.Ety, e.EV.E2); | else 00000000| e.EV.E2 = el_una(OPc_i, e1.Ety, e.EV.E2); 00000000| return optelem(e, GOALvalue); | } | // Replace x/=y with x=x/y 786| if (OPTIMIZER && 296| tyintegral(e.EV.E1.Ety) && 296| e.EV.E1.Eoper == OPvar && 296| !el_sideeffect(e.EV.E1)) | { 296| e.Eoper = OPeq; 296| e.EV.E2 = el_bin(OPdiv, e.EV.E2.Ety, el_copytree(e.EV.E1), e.EV.E2); 296| return optelem(e, GOALvalue); | } 490| e = eldiv(e, GOALvalue); 490| break; | 1046| case OPmodass: | // Replace x%=y with x=x%y 1046| if (OPTIMIZER && 294| tyintegral(e.EV.E1.Ety) && 294| e.EV.E1.Eoper == OPvar && 294| !el_sideeffect(e.EV.E1)) | { 294| e.Eoper = OPeq; 294| e.EV.E2 = el_bin(OPmod, e.EV.E2.Ety, el_copytree(e.EV.E1), e.EV.E2); 294| return optelem(e, GOALvalue); | } 752| break; | 209868| default: 209868| break; | } | } | } 227233| return e; |} | |/************************** | * Add assignment. Replace bit field post assignment with | * equivalent tree. | * (l bit w,b) ++ r | * becomes: | * (((l bit w,b) += r) - r) & m | */ | |private elem * elpost(elem *e, goal_t goal) |{ 17480| elem *e1 = e.EV.E1; 17480| if (e1.Eoper != OPbit) | { 34959| if (e1.Eoper == OPcomma || OTassign(e1.Eoper)) 1| return cgel_lvalue(e); // replace (e,v)op=e2 with e,(v op= e2) 17479| return e; | } | 00000000| assert(e.EV.E2.Eoper == OPconst); 00000000| targ_llong r = el_tolong(e.EV.E2); | 00000000| uint w = (e1.EV.E2.EV.Vuns >> 8) & 0xFF; // width in bits of field 00000000| targ_llong m = (cast(targ_llong)1 << w) - 1; // mask w bits wide | 00000000| tym_t ty = e.Ety; 00000000| if (e.Eoper != OPpostinc) 00000000| r = -r; 00000000| e.Eoper = (e.Eoper == OPpostinc) ? OPaddass : OPminass; 00000000| e = el_bin(OPmin,ty,e,el_long(ty,r)); 00000000| if (tyuns(e1.EV.E1.Ety)) /* if uint bit field */ 00000000| e = el_bin(OPand,ty,e,el_long(ty,m)); 00000000| return optelem(e,GOALvalue); |} | |/*************************** | * Take care of compares. | * (e == 0) => (!e) | * (e != 0) => (bool e) | */ | |private elem * elcmp(elem *e, goal_t goal) |{ 305521| elem *e2 = e.EV.E2; 305521| elem *e1 = e.EV.E1; | | //printf("elcmp(%p)\n",e); elem_print(e); | 305521| if (OPTIMIZER) | { 125325| auto op = e.Eoper; | | // Convert comparison of OPrelconsts of the same symbol to comparisons | // of their offsets. 125350| if (e1.Eoper == OPrelconst && e2.Eoper == OPrelconst && 25| e1.EV.Vsym == e2.EV.Vsym) | { 3| e1.Eoper = OPconst; 3| e1.Ety = TYptrdiff; 3| e2.Eoper = OPconst; 3| e2.Ety = TYptrdiff; 3| return optelem(e,GOALvalue); | } | | // Convert comparison of long pointers to comparison of integers 444331| if ((op == OPlt || op == OPle || op == OPgt || op == OPge) && 27680| tyfv(e2.Ety) && tyfv(e1.Ety)) | { 00000000| e.EV.E1 = el_una(OP32_16,e.Ety,e1); 00000000| e.EV.E2 = el_una(OP32_16,e.Ety,e2); 00000000| return optelem(e,GOALvalue); | } | | // Convert ((e & 1) == 1) => (e & 1) 260427| if (op == OPeqeq && e2.Eoper == OPconst && e1.Eoper == OPand) | { 338| elem *e12 = e1.EV.E2; | 879| if (e12.Eoper == OPconst && el_tolong(e2) == 1 && el_tolong(e12) == 1) | { 203| tym_t ty = e.Ety; 203| tym_t ty1 = e1.Ety; 203| e = el_selecte1(e); 203| e.Ety = ty1; 203| int sz = tysize(ty); 406| for (int sz1 = tysize(ty1); sz1 != sz; sz1 = tysize(e.Ety)) | { 00000000| switch (sz1) | { 00000000| case 1: 00000000| e = el_una(OPu8_16,TYshort,e); 00000000| break; 00000000| case 2: 00000000| if (sz > 2) 00000000| e = el_una(OPu16_32,TYlong,e); | else 00000000| e = el_una(OP16_8,TYuchar,e); 00000000| break; 00000000| case 4: 00000000| if (sz > 2) 00000000| e = el_una(OPu32_64,TYshort,e); | else 00000000| e = el_una(OP32_16,TYshort,e); 00000000| break; 00000000| case 8: 00000000| e = el_una(OP64_32,TYlong,e); 00000000| break; 00000000| default: 00000000| assert(0); | } | } 203| e.Ety = ty; 203| return optelem(e,GOALvalue); | } | } | } | 305315| int uns = tyuns(e1.Ety) | tyuns(e2.Ety); 305315| if (cnst(e2)) | { 182795| tym_t tym; 182795| int sz = tysize(e2.Ety); | 183051| if (e1.Eoper == OPu16_32 && e2.EV.Vulong <= cast(targ_ulong) SHORTMASK || 182539| e1.Eoper == OPs16_32 && 215| e2.EV.Vlong == cast(targ_short) e2.EV.Vlong) | { 1403| tym = (uns || e1.Eoper == OPu16_32) ? TYushort : TYshort; 471| e.EV.E2 = el_una(OP32_16,tym,e2); 471| goto L2; | } | | /* Try to convert to byte/word comparison for ((x & c)==d) | when mask c essentially casts x to a smaller type | */ 182324| if (OPTIMIZER && 65858| e1.Eoper == OPand && 251| e1.EV.E2.Eoper == OPconst && 225| sz > CHARSIZE) | { 11| OPER op; 11| assert(tyintegral(e2.Ety) || typtr(e2.Ety)); | /* ending up with byte ops in A regs */ 11| if (!(el_tolong(e2) & ~CHARMASK) && 11| !(el_tolong(e1.EV.E2) & ~CHARMASK) | ) | { 3| if (sz == LLONGSIZE) | { 00000000| e1.EV.E1 = el_una(OP64_32,TYulong,e1.EV.E1); 00000000| e1.EV.E1 = el_una(OP32_16,TYushort,e1.EV.E1); | } 3| else if (sz == LONGSIZE) 3| e1.EV.E1 = el_una(OP32_16,TYushort,e1.EV.E1); 3| tym = TYuchar; 3| op = OP16_8; 3| goto L4; | } 8| if (_tysize[TYint] == SHORTSIZE && /* not a win when regs are long */ 00000000| sz == LONGSIZE && 00000000| !(e2.EV.Vulong & ~SHORTMASK) && 00000000| !(e1.EV.E2.EV.Vulong & ~SHORTMASK) | ) | { 00000000| tym = TYushort; 00000000| op = OP32_16; | L4: 3| e2.Ety = tym; 3| e1.Ety = tym; 3| e1.EV.E2.Ety = tym; 3| e1.EV.E1 = el_una(op,tym,e1.EV.E1); 3| e = optelem(e,GOALvalue); 3| goto ret; | } | } | | /* Convert (ulong > uint.max) to (msw(ulong) != 0) | */ 248176| if (OPTIMIZER && I32 && e.Eoper == OPgt && sz == LLONGSIZE && e2.EV.Vullong == 0xFFFFFFFF) | { 00000000| e.Eoper = OPne; 00000000| e2.Ety = TYulong; 00000000| e2.EV.Vulong = 0; 00000000| e.EV.E1 = el_una(OPmsw,TYulong,e1); 00000000| e = optelem(e,GOALvalue); 00000000| goto ret; | } | 204759| if (e1.Eoper == OPu8_16 && e2.EV.Vuns < 256 || 159883| e1.Eoper == OPs8_16 && 683| e2.EV.Vint == cast(targ_schar) e2.EV.Vint) | { 69356| tym = (uns || e1.Eoper == OPu8_16) ? TYuchar : TYschar; 23119| e.EV.E2 = el_una(OP16_8,tym,e2); | L2: 23590| tym |= e1.Ety & ~mTYbasic; 23590| e.EV.E1 = el_selecte1(e1); 23590| e.EV.E1.Ety = tym; 23590| e = optelem(e,GOALvalue); | } 159202| else if (!boolres(e2)) | { 28815| targ_int i; 28815| switch (e.Eoper) | { 761| case OPle: // (u <= 0) becomes (u == 0) 761| if (!uns) 735| break; 26| goto case OPeqeq; | 14093| case OPeqeq: 14093| e.Eoper = OPnot; 14093| goto L5; | 6096| case OPgt: // (u > 0) becomes (u != 0) 6096| if (!uns) 1717| break; 4379| goto case OPne; | 7554| case OPne: 7554| e.Eoper = OPbool; 21647| L5: el_free(e2); 21647| e.EV.E2 = null; 21647| e = optelem(e,GOALvalue); 21647| break; | 2040| case OPge: 2040| i = 1; // (u >= 0) becomes (u,1) 2040| goto L3; | 2676| case OPlt: // (u < 0) becomes (u,0) 2676| i = 0; | L3: 4716| if (uns) | { 296| e2.EV.Vint = i; 296| e2.Ety = TYint; 296| e.Eoper = OPcomma; 296| e = optelem(e,GOALvalue); | } | else | { 8117| if (tyintegral(e1.Ety) && sz == 2 * REGSIZE) | { | // Only need to examine MSW 00000000| tym_t ty = sz == 4 ? TYint : 00000000| sz == 8 ? TYint : 00000000| TYlong; // for TYcent's 00000000| e.EV.E1 = el_una(OPmsw, ty, e1); 00000000| e2.Ety = ty; 00000000| return optelem(e, GOALvalue); | } | } 4716| break; | 00000000| default: 00000000| break; | } | } 206143| else if (OPTIMIZER && uns && tysize(e2.Ety) == 2 && 116| cast(ushort)e2.EV.Vuns == 0x8000 && 00000000| (e.Eoper == OPlt || e.Eoper == OPge) | ) | { | // Convert to signed comparison against 0 00000000| tym_t ty = tybasic(e2.Ety); 00000000| switch (_tysize[ty]) | { 00000000| case 1: ty = TYschar; break; 00000000| case 2: ty = TYshort; break; 00000000| default: assert(0); | } 00000000| e.Eoper ^= (OPlt ^ OPge); // switch between them 00000000| e2.EV.Vuns = 0; 00000000| e2.Ety = ty | (e2.Ety & ~mTYbasic); 00000000| e1.Ety = ty | (e1.Ety & ~mTYbasic); | } 189119| else if (OPTIMIZER && e1.Eoper == OPeq && 22| e1.EV.E2.Eoper == OPconst) | { // Convert ((x = c1) rel c2) to ((x = c1),(c1 rel c2) 00000000| elem *ec = el_copytree(e1.EV.E2); 00000000| ec.Ety = e1.Ety; 00000000| e.EV.E1 = ec; 00000000| e = el_bin(OPcomma,e.Ety,e1,e); 00000000| e = optelem(e,GOALvalue); | } | } 122520| else if (( | (e1.Eoper == OPu8_16 || 119066| e1.Eoper == OPs8_16)|| 118862| (e1.Eoper == OPu16_32 || 118679| e1.Eoper == OPs16_32) | ) && 3901| e1.Eoper == e2.Eoper) | { 3013| if (uns) | { 00000000| e1.EV.E1.Ety = touns(e1.EV.E1.Ety); 00000000| e2.EV.E1.Ety = touns(e2.EV.E1.Ety); | } 3013| e1.Ety = e1.EV.E1.Ety; 3013| e2.Ety = e2.EV.E1.Ety; 3013| e.EV.E1 = el_selecte1(e1); 3013| e.EV.E2 = el_selecte1(e2); 3013| e = optelem(e,GOALvalue); | } |ret: 305315| return e; |} | |/***************************** | * Boolean operator. | * OPbool | */ | |private elem * elbool(elem *e, goal_t goal) |{ | //printf("elbool()\n"); 9784| if (OTlogical(e.EV.E1.Eoper) || | // bool bool => bool 9239| (tybasic(e.EV.E1.Ety) == TYbool && tysize(e.Ety) == 1) | ) 769| return el_selecte1(e); | 9015| if (OPTIMIZER) | { 1855| int shift; | | // Replace bool(x,1) with (x,1),1 1855| elem *e1 = elscancommas(e.EV.E1); 3710| if (cnst(e1) || e1.Eoper == OPrelconst) | { 00000000| int i = boolres(e1) != 0; 00000000| e.Eoper = OPcomma; 00000000| e.EV.E2 = el_long(e.Ety,i); 00000000| e = optelem(e,GOALvalue); 00000000| return e; | } | | // Replace bool(e & 1) with (uint char)(e & 1) 2009| else if (e.EV.E1.Eoper == OPand && e.EV.E1.EV.E2.Eoper == OPconst && el_tolong(e.EV.E1.EV.E2) == 1) | { | L1: 77| uint sz = tysize(e.EV.E1.Ety); 77| tym_t ty = e.Ety; 77| switch (sz) | { 77| case 1: 77| e = el_selecte1(e); 77| break; | 00000000| case 2: 00000000| e.Eoper = OP16_8; 00000000| break; | 00000000| case 4: 00000000| e.Eoper = OP32_16; 00000000| e.Ety = TYushort; 00000000| e = el_una(OP16_8, ty, e); 00000000| break; | 00000000| case 8: 00000000| e.Eoper = OP64_32; 00000000| e.Ety = TYulong; 00000000| e = el_una(OP32_16, TYushort, e); 00000000| e = el_una(OP16_8, ty, e); 00000000| break; | 00000000| default: 00000000| assert(0); | } 77| e = optelem(e,GOALvalue); | } | | // Replace bool(e % 2) with (uint char)(e & 1) 1833| else if (e.EV.E1.Eoper == OPmod && e.EV.E1.EV.E2.Eoper == OPconst && el_tolong(e.EV.E1.EV.E2) == 2 26| && !tyfloating(e.EV.E1.Ety)) // dont optimize fmod() | { 24| uint sz = tysize(e.EV.E1.Ety); 24| tym_t ty = e.Ety; 24| e.EV.E1.Eoper = OPand; 24| e.EV.E1.EV.E2.EV.Vullong = 1; 24| switch (sz) | { 00000000| case 1: 00000000| e = el_selecte1(e); 00000000| break; | 00000000| case 2: 00000000| e.Eoper = OP16_8; 00000000| break; | 24| case 4: 24| e.Eoper = OP32_16; 24| e.Ety = TYushort; 24| e = el_una(OP16_8, ty, e); 24| break; | 00000000| case 8: 00000000| e.Eoper = OP64_32; 00000000| e.Ety = TYulong; 00000000| e = el_una(OP32_16, TYushort, e); 00000000| e = el_una(OP16_8, ty, e); 00000000| break; | 00000000| default: 00000000| assert(0); | } 24| e = optelem(e,GOALvalue); | } | | // Replace bool((1<> shift) & 1) 1755| else if (e.EV.E1.Eoper == OPand && 1| e.EV.E1.EV.E2.Eoper == OPconst && 1| (shift = ispow2(el_tolong(e.EV.E1.EV.E2))) != -1 | ) | { 1| e.EV.E1.EV.E1 = el_bin(OPshr, e.EV.E1.EV.E1.Ety, e.EV.E1.EV.E1, el_long(TYint, shift)); 1| e.EV.E1.EV.E2.EV.Vullong = 1; 1| goto L1; | } | } 9015| return e; |} | | |/********************************* | * Conversions of pointers to far pointers. | */ | |private elem * elptrlptr(elem *e, goal_t goal) |{ 18| if (e.EV.E1.Eoper == OPrelconst || e.EV.E1.Eoper == OPstring) | { 00000000| e.EV.E1.Ety = e.Ety; 00000000| e = el_selecte1(e); | } 9| return e; |} | | |/********************************* | * Conversions of handle pointers to far pointers. | */ |private elem * elvptrfptr(elem *e, goal_t goal) |{ 00000000| elem *e1 = e.EV.E1; 00000000| if (e1.Eoper == OPadd || e1.Eoper == OPmin) | { 00000000| elem *e12 = e1.EV.E2; 00000000| if (tybasic(e12.Ety) != TYvptr) | { | /* Rewrite (vtof(e11 + e12)) to (vtof(e11) + e12) */ 00000000| const op = e.Eoper; 00000000| e.Eoper = e1.Eoper; 00000000| e.EV.E2 = e12; 00000000| e1.Ety = e.Ety; 00000000| e1.Eoper = cast(ubyte)op; 00000000| e1.EV.E2 = null; 00000000| e = optelem(e,GOALvalue); | } | } 00000000| return e; |} | | |/************************ | * Optimize conversions of longs to ints. | * Also used for (OPoffset) (TYfptr|TYvptr). | * Also used for conversions of ints to bytes. | */ | |private elem * ellngsht(elem *e, goal_t goal) |{ | //printf("ellngsht()\n"); 9942| tym_t ty = e.Ety; 9942| elem *e1 = e.EV.E1; 9942| switch (e1.Eoper) | { 61| case OPs16_32: 105| case OPu16_32: 635| case OPu8_16: 856| case OPs8_16: | // This fix is not quite right. For example, it fails | // if e.Ety != e.EV.E1.EV.E1.Ety. The difference is when | // one is uint and the other isn't. 856| if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety)) 481| break; 375| e = el_selecte1(el_selecte1(e)); 375| e.Ety = ty; 375| return e; | 1266| case OPvar: // simply paint type of variable | // Do not paint type of ints into bytes, as this causes | // many CSEs to be missed, resulting in bad code. | // Loading a word anyway is just as fast as loading a byte. | // for 68000 byte is swapped, load byte != load word 1266| if (e.Eoper == OP16_8) | { | // Mark symbol as being used sometimes as a byte to | // 80X86 - preclude using SI or DI | // 68000 - preclude using An 591| e1.EV.Vsym.Sflags |= GTbyte; | } | else 675| e1.Ety = ty; 1266| e = el_selecte1(e); 1266| break; | 713| case OPind: 713| e = el_selecte1(e); 713| break; | 00000000| case OPnp_fp: 00000000| if (e.Eoper != OPoffset) 00000000| goto case_default; | // Replace (offset)(ptrlptr)e11 with e11 00000000| e = el_selecte1(el_selecte1(e)); 00000000| e.Ety = ty; // retain original type 00000000| break; | 00000000| case OPbtst: 00000000| e = el_selecte1(e); 00000000| break; | 7107| default: // operator | case_default: | // Attempt to replace (lngsht)(a op b) with | // ((lngsht)a op (lngsht)b). | // op is now an integer op, which is cheaper. 12295| if (OTwid(e1.Eoper) && !OTassign(e1.Eoper)) | { 5188| tym_t ty1 = e1.EV.E1.Ety; 5188| switch (e.Eoper) | { 2519| case OP16_8: | // Make sure e1.EV.E1 is of the type we're converting from 2519| if (tysize(ty1) <= _tysize[TYint]) | { 5038| ty1 = (tyuns(ty1) ? TYuchar : TYschar) | | (ty1 & ~mTYbasic); 2519| e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1); | } | // Rvalue may be an int if it is a shift operator 2519| if (OTbinary(e1.Eoper)) 2499| { tym_t ty2 = e1.EV.E2.Ety; | 2499| if (tysize(ty2) <= _tysize[TYint]) | { 4998| ty2 = (tyuns(ty2) ? TYuchar : TYschar) | | (ty2 & ~mTYbasic); 2499| e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2); | } | } 2519| break; | 00000000| case OPoffset: 00000000| if (_tysize[TYint] == LONGSIZE) | { | // Make sure e1.EV.E1 is of the type we're converting from 00000000| if (tysize(ty1) > LONGSIZE) | { 00000000| ty1 = (tyuns(ty1) ? TYuint : TYint) | (ty1 & ~mTYbasic); 00000000| e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1); | } | // Rvalue may be an int if it is a shift operator 00000000| if (OTbinary(e1.Eoper)) 00000000| { tym_t ty2 = e1.EV.E2.Ety; | 00000000| if (tysize(ty2) > LONGSIZE) | { 00000000| ty2 = (tyuns(ty2) ? TYuint : TYint) | | (ty2 & ~mTYbasic); 00000000| e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2); | } | } 00000000| break; | } 00000000| goto case OP32_16; | 2669| case OP32_16: | // Make sure e1.EV.E1 is of the type we're converting from 2669| if (tysize(ty1) == LONGSIZE) | { 5338| ty1 = (tyuns(ty1) ? TYushort : TYshort) | (ty1 & ~mTYbasic); 2669| e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1); | } | // Rvalue may be an int if it is a shift operator 2669| if (OTbinary(e1.Eoper)) 2648| { tym_t ty2 = e1.EV.E2.Ety; | 2648| if (tysize(ty2) == LONGSIZE) | { 5296| ty2 = (tyuns(ty2) ? TYushort : TYshort) | | (ty2 & ~mTYbasic); 2648| e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2); | } | } 2669| break; | 00000000| default: 00000000| assert(0); | } 5188| e1.Ety = ty; 5188| e = el_selecte1(e); 5188| again = 1; 5188| return e; | } 1919| break; | } 4379| return e; |} | | |/************************ | * Optimize conversions of long longs to ints. | * OP64_32, OP128_64 | */ | |private elem * el64_32(elem *e, goal_t goal) |{ 83353| tym_t ty = e.Ety; 83353| elem *e1 = e.EV.E1; 83353| switch (e1.Eoper) | { 81| case OPs32_64: 91| case OPu32_64: 91| case OPs64_128: 91| case OPu64_128: 91| if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety)) 00000000| break; 91| e = el_selecte1(el_selecte1(e)); 91| e.Ety = ty; 91| break; | 2108| case OPpair: 2108| if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety)) 00000000| break; 2108| if (el_sideeffect(e1.EV.E2)) | { | // Rewrite (OP64_32(a pair b)) as ((t=a),(b,t)) 00000000| elem *a = e1.EV.E1; 00000000| elem *b = e1.EV.E2; 00000000| elem *t = el_alloctmp(a.Ety); | 00000000| e.Eoper = OPcomma; 00000000| e.EV.E1 = el_bin(OPeq,a.Ety,t,a); 00000000| e.EV.E2 = e1; | 00000000| e1.Eoper = OPcomma; 00000000| e1.EV.E1 = b; 00000000| e1.EV.E2 = el_copytree(t); 00000000| e1.Ety = e.Ety; 00000000| break; | } 2108| e = el_selecte1(el_selecte1(e)); 2108| e.Ety = ty; 2108| break; | 503| case OPrpair: 503| if (tysize(ty) != tysize(e.EV.E1.EV.E2.Ety)) 00000000| break; 503| if (el_sideeffect(e1.EV.E1)) | { | // Rewrite (OP64_32(a rpair b)) as (a,b) 00000000| e = el_selecte1(e); 00000000| e.Eoper = OPcomma; 00000000| e.Ety = ty; 00000000| break; | } 503| e = el_selecte2(el_selecte1(e)); 503| e.Ety = ty; 503| break; | 49027| case OPvar: // simply paint type of variable 68250| case OPind: 68250| e = el_selecte1(e); 68250| break; | 4188| case OPshr: // OP64_32(x >> 32) => OPmsw(x) 4188| if (e1.EV.E2.Eoper == OPconst && 4207| (e.Eoper == OP64_32 && el_tolong(e1.EV.E2) == 32 && !I64 || 12471| e.Eoper == OP128_64 && el_tolong(e1.EV.E2) == 64 && I64) | ) | { 4147| e.Eoper = OPmsw; 4147| e.EV.E1 = el_selecte1(e.EV.E1); | } 4188| break; | 122| case OPmul: | static if (TARGET_OSX) // https://issues.dlang.org/show_bug.cgi?id=21047 | break; | else 122| goto case; | 765| case OPadd: 1118| case OPmin: 1172| case OPor: 1480| case OPand: 1527| case OPxor: | // OP64_32(a op b) => (OP64_32(a) op OP64_32(b)) 1527| e1.EV.E1 = el_una(e.Eoper, ty, e1.EV.E1); 1527| e1.EV.E2 = el_una(e.Eoper, ty, e1.EV.E2); 1527| e = el_selecte1(e); 1527| break; | 6686| default: 6686| break; | } 83353| return e; |} | | |/******************************* | * Convert complex to real. | */ | |private elem *elc_r(elem *e, goal_t goal) |{ 64| elem *e1 = e.EV.E1; | 72| if (e1.Eoper == OPvar || e1.Eoper == OPind) | { 56| e1.Ety = e.Ety; 56| e = el_selecte1(e); | } 64| return e; |} | |/******************************* | * Convert complex to imaginary. | */ | |private elem *elc_i(elem *e, goal_t goal) |{ 59| elem *e1 = e.EV.E1; | 59| if (e1.Eoper == OPvar) | { 48| e1.Ety = e.Ety; 48| e1.EV.Voffset += tysize(e.Ety); 48| e = el_selecte1(e); | } 11| else if (e1.Eoper == OPind) | { 00000000| e1.Ety = e.Ety; 00000000| e = el_selecte1(e); 00000000| e.EV.E1 = el_bin(OPadd, e.EV.E1.Ety, e.EV.E1, el_long(TYint, tysize(e.Ety))); 00000000| return optelem(e, GOALvalue); | } | 59| return e; |} | |/****************************** | * Handle OPu8_16 and OPs8_16. | */ | |private elem * elbyteint(elem *e, goal_t goal) |{ 114399| if (OTlogical(e.EV.E1.Eoper) || e.EV.E1.Eoper == OPbtst) | { 67| e.EV.E1.Ety = e.Ety; 67| e = el_selecte1(e); 67| return e; | } 57166| return evalu8(e, goal); |} | |/****************************** | * OPs32_64 | * OPu32_64 | */ |private elem * el32_64(elem *e, goal_t goal) |{ 125778| if (REGSIZE == 8 && e.EV.E1.Eoper == OPbtst) | { 00000000| e.EV.E1.Ety = e.Ety; 00000000| e = el_selecte1(e); 00000000| return e; | } 62889| return evalu8(e, goal); |} | |/**************************** | * Handle OPu64_d, | * OPd_ld OPu64_d, | * OPd_f OPu64_d | */ | |private elem *elu64_d(elem *e, goal_t goal) |{ 79| tym_t ty; 79| elem** pu; 79| if (e.Eoper == OPu64_d) | { 43| pu = &e.EV.E1; 43| ty = TYdouble; | } 68| else if (e.Eoper == OPd_ld && e.EV.E1.Eoper == OPu64_d) | { 32| pu = &e.EV.E1.EV.E1; 32| *pu = optelem(*pu, GOALvalue); 32| ty = TYldouble; | } 8| else if (e.Eoper == OPd_f && e.EV.E1.Eoper == OPu64_d) | { 4| pu = &e.EV.E1.EV.E1; 4| *pu = optelem(*pu, GOALvalue); 4| ty = TYfloat; | } | 158| if (!pu || (*pu).Eoper == OPconst) 00000000| return evalu8(e, goal); | 79| elem* u = *pu; 312| if (config.fpxmmregs && I64 && (ty == TYfloat || ty == TYdouble)) | { | /* Rewrite for SIMD as: | * u >= 0 ? OPs64_d(u) : OPs64_d((u >> 1) | (u & 1)) * 2 | */ 47| u.Ety = TYllong; 47| elem *u1 = el_copytree(u); 47| if (!OTleaf(u.Eoper)) 5| fixside(&u, &u1); 47| elem *u2 = el_copytree(u1); | 47| u = el_bin(OPge, TYint, u, el_long(TYllong, 0)); | 47| u1 = el_una(OPs64_d, TYdouble, u1); 47| if (ty == TYfloat) 4| u1 = el_una(OPd_f, TYfloat, u1); | 47| elem* u3 = el_copytree(u2); 47| u2 = el_bin(OPshr, TYullong, u2, el_long(TYullong, 1)); 47| u3 = el_bin(OPand, TYullong, u3, el_long(TYullong, 1)); 47| u2 = el_bin(OPor, TYllong, u2, u3); | 47| u2 = el_una(OPs64_d, TYdouble, u2); 47| if (ty == TYfloat) 4| u2 = el_una(OPd_f, TYfloat, u2); | 47| u2 = el_bin(OPmul, ty, u2, el_long(ty, 2)); | 47| elem* r = el_bin(OPcond, e.Ety, u, el_bin(OPcolon, e.Ety, u1, u2)); 47| *pu = null; 47| el_free(e); 47| return optelem(r, GOALvalue); | } 32| if (config.inline8087) | { | /* Rewrite for x87 as: | * u < 0 ? OPs64_d(u) : OPs64_d(u) + 0x1p+64 | */ 32| u.Ety = TYllong; 32| elem *u1 = el_copytree(u); 32| if (!OTleaf(u.Eoper)) 2| fixside(&u, &u1); | 32| elem* eop1 = el_una(OPs64_d, TYdouble, u1); 32| eop1 = el_una(OPd_ld, TYldouble, eop1); | 32| elem* eoff = el_calloc(); 32| eoff.Eoper = OPconst; 32| eoff.Ety = TYldouble; 32| eoff.EV.Vldouble = 0x1p+64; | 32| elem* u2 = el_copytree(u1); 32| u2 = el_una(OPs64_d, TYdouble, u2); 32| u2 = el_una(OPd_ld, TYldouble, u2); | 32| elem* eop2 = el_bin(OPadd, TYldouble, u2, eoff); | 32| elem* r = el_bin(OPcond, TYldouble, | el_bin(OPge, OPbool, u, el_long(TYllong, 0)), | el_bin(OPcolon, TYldouble, eop1, eop2)); | 32| if (ty != TYldouble) 00000000| r = el_una(OPtoprec, e.Ety, r); | 32| *pu = null; 32| el_free(e); | 32| return optelem(r, GOALvalue); | } | 00000000| return evalu8(e, goal); |} | | |/************************ | * Handle <<, OProl and OPror | */ | |private elem *elshl(elem *e, goal_t goal) |{ 22191| tym_t ty = e.Ety; 22191| elem *e1 = e.EV.E1; 22191| elem *e2 = e.EV.E2; | 22939| if (e1.Eoper == OPconst && !boolres(e1)) // if e1 is 0 | { 1| e1.Ety = ty; 1| e = el_selecte1(e); // (0 << e2) => 0 | } 22190| else if (OPTIMIZER && 8726| e2.Eoper == OPconst && 16902| (e1.Eoper == OPshr || e1.Eoper == OPashr) && 222| e1.EV.E2.Eoper == OPconst && 222| el_tolong(e2) == el_tolong(e1.EV.E2)) | { /* Rewrite: | * (x >> c) << c) | * with: | * x & ~((1 << c) - 1); | */ 8| targ_ullong c = el_tolong(e.EV.E2); 8| e = el_selecte1(e); 8| e = el_selecte1(e); 8| e = el_bin(OPand, e.Ety, e, el_long(e.Ety, ~((1UL << c) - 1))); 8| return optelem(e, goal); | } 22183| return e; |} | |/************************ | * Handle >> | * OPshr, OPashr | */ | |private elem * elshr(elem *e, goal_t goal) |{ 7423| tym_t ty = e.Ety; 7423| elem *e1 = e.EV.E1; 7423| elem *e2 = e.EV.E2; | | // (x >> 16) replaced with ((shtlng) x+2) 7423| if (OPTIMIZER && 1787| e2.Eoper == OPconst && e2.EV.Vshort == SHORTSIZE * 8 && 22| tysize(ty) == LONGSIZE) | { 2| if (e1.Eoper == OPvar) | { 00000000| Symbol *s = e1.EV.Vsym; | 00000000| if (s.Sclass != SCfastpar && s.Sclass != SCshadowreg) | { 00000000| e1.EV.Voffset += SHORTSIZE; // address high word in long 00000000| if (I32) | // Cannot independently address high word of register 00000000| s.Sflags &= ~GTregcand; 00000000| goto L1; | } | } 2| else if (e1.Eoper == OPind) | { | /* Replace (*p >> 16) with (shtlng)(*(&*p + 2)) */ 00000000| e.EV.E1 = el_una(OPind,TYshort, | el_bin(OPadd,e1.EV.E1.Ety, | el_una(OPaddr,e1.EV.E1.Ety,e1), | el_long(TYint,SHORTSIZE))); | L1: 00000000| e.Eoper = tyuns(e1.Ety) ? OPu16_32 : OPs16_32; 00000000| el_free(e2); 00000000| e.EV.E2 = null; 00000000| e1.Ety = TYshort; 00000000| e = optelem(e,GOALvalue); | } | } | | // (x >> 32) replaced with ((lngllng) x+4) 14172| if (e2.Eoper == OPconst && e2.EV.Vlong == LONGSIZE * 8 && 92| tysize(ty) == LLONGSIZE) | { 92| if (e1.Eoper == OPvar) | { 50| e1.EV.Voffset += LONGSIZE; // address high dword in longlong 50| if (I64) | // Cannot independently address high word of register 50| e1.EV.Vsym.Sflags &= ~GTregcand; 50| goto L2; | } 42| else if (e1.Eoper == OPind) | { | // Replace (*p >> 32) with (lngllng)(*(&*p + 4)) 00000000| e.EV.E1 = el_una(OPind,TYlong, | el_bin(OPadd,e1.EV.E1.Ety, | el_una(OPaddr,e1.EV.E1.Ety,e1), | el_long(TYint,LONGSIZE))); | L2: 100| e.Eoper = tyuns(e1.Ety) ? OPu32_64 : OPs32_64; 50| el_free(e2); 50| e.EV.E2 = null; 50| e1.Ety = TYlong; 50| e = optelem(e,GOALvalue); | } | } 7423| return e; |} | |/*********************************** | * Handle OPmsw. | */ | |elem *elmsw(elem *e, goal_t goal) |{ 54672| tym_t ty = e.Ety; 54672| elem *e1 = e.EV.E1; | 54672| if (OPTIMIZER && 4835| tysize(e1.Ety) == LLONGSIZE && 00000000| tysize(ty) == LONGSIZE) | { | // Replace (int)(msw (long)x) with (int)*(&x+4) 00000000| if (e1.Eoper == OPvar) | { 00000000| e1.EV.Voffset += LONGSIZE; // address high dword in longlong 00000000| if (I64) | // Cannot independently address high word of register 00000000| e1.EV.Vsym.Sflags &= ~GTregcand; 00000000| e1.Ety = ty; 00000000| e = optelem(e1,GOALvalue); | } | // Replace (int)(msw (long)*x) with (int)*(&*x+4) 00000000| else if (e1.Eoper == OPind) | { 00000000| e1 = el_una(OPind,ty, | el_bin(OPadd,e1.EV.E1.Ety, | el_una(OPaddr,e1.EV.E1.Ety,e1), | el_long(TYint,LONGSIZE))); 00000000| e = optelem(e1,GOALvalue); | } | else | { 00000000| e = evalu8(e, goal); | } | } 59507| else if (OPTIMIZER && I64 && 4835| tysize(e1.Ety) == CENTSIZE && 4835| tysize(ty) == LLONGSIZE) | { | // Replace (long)(msw (cent)x) with (long)*(&x+8) 4835| if (e1.Eoper == OPvar) | { 3312| e1.EV.Voffset += LLONGSIZE; // address high dword in longlong 3312| e1.Ety = ty; 3312| e = optelem(e1,GOALvalue); | } | // Replace (long)(msw (cent)*x) with (long)*(&*x+8) 1523| else if (e1.Eoper == OPind) | { 371| e1 = el_una(OPind,ty, | el_bin(OPadd,e1.EV.E1.Ety, | el_una(OPaddr,e1.EV.E1.Ety,e1), | el_long(TYint,LLONGSIZE))); 371| e = optelem(e1,GOALvalue); | } | else | { 1152| e = evalu8(e, goal); | } | } | else | { 49837| e = evalu8(e, goal); | } | 54672| return e; |} | |/*********************************** | * Handle OPpair, OPrpair. | */ | |elem *elpair(elem *e, goal_t goal) |{ | //printf("elpair()\n"); 123164| elem *e1 = e.EV.E1; 123164| if (e1.Eoper == OPconst) | { 66609| e.EV.E1 = e.EV.E2; 66609| e.EV.E2 = e1; 66609| e.Eoper ^= OPpair ^ OPrpair; | } 123164| return e; |} | |/******************************** | * Handle OPddtor | */ | |elem *elddtor(elem *e, goal_t goal) |{ 8264| return e; |} | |/******************************** | * Handle OPinfo, OPmark, OPctor, OPdtor | */ | |private elem * elinfo(elem *e, goal_t goal) |{ | //printf("elinfo()\n"); | version (SCPP) | static if (NTEXCEPTIONS) | { | if (funcsym_p.Sfunc.Fflags3 & Fnteh) | { // Eliminate cleanup info if using NT structured EH | if (e.Eoper == OPinfo) | e = el_selecte2(e); | else | { el_free(e); | e = el_long(TYint,0); | } | } | } 12974| return e; |} | |/******************************************** | */ | |private elem * elclassinit(elem *e, goal_t goal) |{ 00000000| return e; |} | |/******************************************** | */ | |private elem * elvalist(elem *e, goal_t goal) |{ 235| assert(e.Eoper == OPva_start); | 235| if (funcsym_p.ty() & mTYnaked) | { // do not generate prolog 00000000| el_free(e); 00000000| e = el_long(TYint, 0); 00000000| return e; | } | 235| if (I32) | { | // (OPva_start &va) | // (OPeq (OPind E1) (OPptr lastNamed+T.sizeof)) | //elem_print(e); | | // Find last named parameter 00000000| Symbol *lastNamed = null; 00000000| Symbol *arguments_typeinfo = null; 00000000| for (SYMIDX si = 0; si < globsym.top; si++) | { 00000000| Symbol *s = globsym.tab[si]; | 00000000| if (s.Sclass == SCparameter || s.Sclass == SCregpar) 00000000| lastNamed = s; 00000000| if (s.Sident[0] == '_' && strcmp(s.Sident.ptr, "_arguments_typeinfo") == 0) 00000000| arguments_typeinfo = s; | } | 00000000| if (!lastNamed) 00000000| lastNamed = arguments_typeinfo; | 00000000| e.Eoper = OPeq; 00000000| e.EV.E1 = el_una(OPind, TYnptr, e.EV.E1); 00000000| if (lastNamed) | { 00000000| e.EV.E2 = el_ptr(lastNamed); 00000000| e.EV.E2.EV.Voffset = (type_size(lastNamed.Stype) + 3) & ~3; | } | else 00000000| e.EV.E2 = el_long(TYnptr, 0); | // elem_print(e); | 00000000| return e; | } | |static if (TARGET_WINDOS) |{ | assert(config.exe == EX_WIN64); // va_start is not an intrinsic on 32-bit | | // (OPva_start &va) | // (OPeq (OPind E1) (OPptr &lastNamed+8)) | //elem_print(e); | | // Find last named parameter | Symbol *lastNamed = null; | for (SYMIDX si = 0; si < globsym.top; si++) | { | Symbol *s = globsym.tab[si]; | | if (s.Sclass == SCfastpar || s.Sclass == SCshadowreg) | lastNamed = s; | } | | e.Eoper = OPeq; | e.EV.E1 = el_una(OPind, TYnptr, e.EV.E1); | if (lastNamed) | { | e.EV.E2 = el_ptr(lastNamed); | e.EV.E2.EV.Voffset = REGSIZE; | } | else | e.EV.E2 = el_long(TYnptr, 0); | //elem_print(e); | |} | |static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_DRAGONFLYBSD || TARGET_SOLARIS) |{ 235| assert(I64); // va_start is not an intrinsic on 32-bit | // (OPva_start &va) | // (OPeq (OPind E1) __va_argsave+offset) | //elem_print(e); | | // Find __va_argsave 235| Symbol *va_argsave = null; 1512| for (SYMIDX si = 0; si < globsym.top; si++) | { 756| Symbol *s = globsym.tab[si]; 1135| if (s.Sident[0] == '_' && strcmp(s.Sident.ptr, "__va_argsave") == 0) | { 235| va_argsave = s; 235| break; | } | } | 235| e.Eoper = OPeq; 235| e.EV.E1 = el_una(OPind, TYnptr, e.EV.E1); 235| if (va_argsave) | { 235| e.EV.E2 = el_ptr(va_argsave); 235| e.EV.E2.EV.Voffset = 6 * 8 + 8 * 16; | } | else 00000000| e.EV.E2 = el_long(TYnptr, 0); | //elem_print(e); |} | 235| return e; |} | |/****************************************** | * OPparam | */ | |private void elparamx(elem *e) |{ | //printf("elparam()\n"); 1| if (e.EV.E1.Eoper == OPrpair) | { 00000000| e.EV.E1.Eoper = OPparam; | } 1| else if (e.EV.E1.Eoper == OPpair && !el_sideeffect(e.EV.E1)) | { 00000000| e.EV.E1.Eoper = OPparam; 00000000| elem *ex = e.EV.E1.EV.E2; 00000000| e.EV.E1.EV.E2 = e.EV.E1.EV.E1; 00000000| e.EV.E1.EV.E1 = ex; | } | else | { | static if (0) | { | // Unfortunately, these don't work because if the last parameter | // is a pair, and it is a D function, the last parameter will get | // passed in EAX. | if (e.EV.E2.Eoper == OPrpair) | { | e.EV.E2.Eoper = OPparam; | } | else if (e.EV.E2.Eoper == OPpair) | { | e.EV.E2.Eoper = OPparam; | elem *ex = e.EV.E2.EV.E2; | e.EV.E2.EV.E2 = e.EV.E2.EV.E1; | e.EV.E2.EV.E1 = ex; | } | } | } |} | |private elem * elparam(elem *e, goal_t goal) |{ 752476| if (!OPTIMIZER) | { 497653| if (!I64) 00000000| elparamx(e); | } 752476| return e; |} | |/******************************** | * Optimize an element. This routine is recursive! | * Be careful not to do this if VBEs have been done (else the VBE | * work will be undone), or if DAGs have been built (will crash if | * there is more than one parent for an elem). | * If (goal) | * we care about the result. | */ | |private elem * optelem(elem *e, goal_t goal) |{ |beg: | //__gshared uint count; | //printf("count: %u\n", ++count); | //{ printf("xoptelem: %p ",e); WROP(e.Eoper); print(" goal x%x\n", goal); } 18146695| assert(e); 18146695| elem_debug(e); 18146695| assert(e.Ecount == 0); // no CSEs | 18146695| if (OPTIMIZER) | { 6818960| if (goal) 5003484| e.Nflags &= ~NFLnogoal; | else 1815476| e.Nflags |= NFLnogoal; | } | 18146695| auto op = e.Eoper; 18146695| if (OTleaf(op)) // if not an operator node | { 9193901| if (goal || OTsideff(op) || e.Ety & (mTYvolatile | mTYshared)) | { 7556070| return e; | } | else | { | retnull: 649312| el_free(e); 649312| return null; | } | } 10050567| else if (OTbinary(op)) // if binary operator | { | /* Determine goals for left and right subtrees */ 7035367| goal_t leftgoal = GOALvalue; 17266492| goal_t rightgoal = (goal || OTsideff(op)) ? GOALvalue : GOALnone; 7035367| switch (op) | { 1949210| case OPcomma: | { 1949210| elem *e1 = e.EV.E1 = optelem(e.EV.E1,GOALnone); |// if (e1 && !OTsideff(e1.Eoper)) |// e1 = e.EV.E1 = optelem(e1, GOALnone); 1949210| elem *e2 = e.EV.E2 = optelem(e.EV.E2,goal); 1949210| if (!e1) | { 269380| if (!e2) 42022| goto retnull; 227358| if (!goal) 106582| e.Ety = e.EV.E2.Ety; 227358| e = el_selecte2(e); 227358| return e; | } 1679830| if (!e2) | { 194048| e.Ety = e.EV.E1.Ety; 194048| return el_selecte1(e); | } 1485782| if (!goal) 892517| e.Ety = e2.Ety; 1485782| return e; | } | 28119| case OPcond: 28119| if (!goal) | { // Transform x?y:z into x&&y or x||z 1165| elem *e2 = e.EV.E2; 1165| if (!el_sideeffect(e2.EV.E1)) | { 57| e.Eoper = OPoror; 57| e.EV.E2 = el_selecte2(e2); 57| e.Ety = TYint; 57| goto beg; | } 1108| else if (!el_sideeffect(e2.EV.E2)) | { 00000000| e.Eoper = OPandand; 00000000| e.EV.E2 = el_selecte1(e2); 00000000| e.Ety = TYint; 00000000| goto beg; | } 1108| assert(e2.Eoper == OPcolon || e2.Eoper == OPcolon2); 1108| elem *e21 = e2.EV.E1 = optelem(e2.EV.E1, goal); 1108| elem *e22 = e2.EV.E2 = optelem(e2.EV.E2, goal); 1108| if (!e21) | { 6| if (!e22) | { 6| e = el_selecte1(e); 6| goto beg; | } | // Rewrite (e1 ? null : e22) as (e1 || e22) 00000000| e.Eoper = OPoror; 00000000| e.EV.E2 = el_selecte2(e2); 00000000| goto beg; | } 1102| if (!e22) | { | // Rewrite (e1 ? e21 : null) as (e1 && e21) 48| e.Eoper = OPandand; 48| e.EV.E2 = el_selecte1(e2); 48| goto beg; | } 1054| if (!rightgoal) 1054| rightgoal = GOALvalue; | } 28008| goto Llog; | 127123| case OPoror: 127123| if (rightgoal) 12593| rightgoal = GOALflags; 157586| if (OPTIMIZER && optim_loglog(&e)) 60| goto beg; 127063| goto Llog; | 112811| case OPandand: 112811| if (rightgoal) 89836| rightgoal = GOALflags; 190149| if (OPTIMIZER && optim_loglog(&e)) 44| goto beg; 112767| goto Llog; | | Llog: // case (c log f()) with no goal 406397| if (goal || el_sideeffect(e.EV.E2)) 267777| leftgoal = GOALflags; 267838| break; | 4042771| default: 4042771| leftgoal = rightgoal; 4042771| break; | 27532| case OPcolon: 27546| case OPcolon2: 27546| if (!goal && !el_sideeffect(e)) 00000000| goto retnull; 27546| leftgoal = rightgoal; 27546| break; | 3734| case OPmemcmp: 3734| if (!goal) | { // So OPmemcmp is removed cleanly 00000000| assert(e.EV.E1.Eoper == OPparam); 00000000| e.EV.E1.Eoper = OPcomma; | } 3734| leftgoal = rightgoal; 3734| break; | 743031| case OPcall: 744053| case OPcallns: | { 744053| const tyf = tybasic(e.EV.E1.Ety); 744053| leftgoal = rightgoal; 744053| elem *e1 = e.EV.E1 = optelem(e.EV.E1, leftgoal); | | // Need argument to type_zeroSize() 744053| const tyf_save = global_tyf; 744053| global_tyf = tyf; 744053| elem *e2 = e.EV.E2 = optelem(e.EV.E2, rightgoal); 744053| global_tyf = tyf_save; | 744053| if (!e1) | { 161| if (!e2) 161| goto retnull; 00000000| return el_selecte2(e); | } 743892| if (!e2) | { 00000000| if (!leftgoal) 00000000| e.Ety = e1.Ety; 00000000| return el_selecte1(e); | } 743892| return (*elxxx[op])(e, goal); | } | } | 4341889| elem *e1 = e.EV.E1; 4341889| if (OTassign(op)) | { 1418242| elem *ex = e1; 1425112| while (OTconv(ex.Eoper)) 6870| ex = ex.EV.E1; 1418242| if (ex.Eoper == OPbit) 00000000| ex.EV.E1 = optelem(ex.EV.E1, leftgoal); 1418242| else if (e1.Eoper == OPu64_d) 17| e1.EV.E1 = optelem(e1.EV.E1, leftgoal); 2836551| else if ((e1.Eoper == OPd_ld || e1.Eoper == OPd_f) && e1.EV.E1.Eoper == OPu64_d) 25| e1.EV.E1.EV.E1 = optelem(e1.EV.E1.EV.E1, leftgoal); | else 1418200| e1 = e.EV.E1 = optelem(e1,leftgoal); | } | else 2923647| e1 = e.EV.E1 = optelem(e1,leftgoal); | 12940908| if ((op == OPandand || op == OPoror || op == OPcond) && e1) // short circuit evaluations | { 267838| switch (op) | { 112767| case OPandand: 112767| if (iffalse(e1)) | { | // Do not evaluate E2 90| el_free(e.EV.E2); 90| e.EV.E2 = null; 90| e.Eoper = OPbool; 90| goto beg; | } 112677| break; | 127063| case OPoror: 127063| if (iftrue(e1)) | { | // Do not evaluate E2 2935| el_free(e.EV.E2); 2935| e.EV.E2 = null; 2935| e.Eoper = OPbool; 2935| goto beg; | } 124128| break; | 28008| case OPcond: 28008| if (iftrue(e1)) | { 185| e.EV.E2 = el_selecte1(e.EV.E2); 185| e.EV.E2.Ety = e.Ety; 185| e.Eoper = OPcomma; 185| goto beg; | } 27823| if (iffalse(e1)) | { 277| e.EV.E2 = el_selecte2(e.EV.E2); 277| e.EV.E2.Ety = e.Ety; 277| e.Eoper = OPcomma; 277| goto beg; | } 27546| break; | 00000000| default: 00000000| assert(0); | } | } | 4338402| elem *e2 = e.EV.E2 = optelem(e.EV.E2,rightgoal); 4338402| if (!e1) | { 70711| if (!e2) 67071| goto retnull; 3640| return el_selecte2(e); | } 4267691| if (!e2) | { 277| if (!leftgoal) 224| e.Ety = e1.Ety; 277| return el_selecte1(e); | } | 5047379| if (op == OPparam && !goal) 00000000| e.Eoper = OPcomma; // DMD bug 6733 | 4606563| if (cnst(e1) && cnst(e2)) | { 65583| e = evalu8(e, GOALvalue); 65583| return e; | } 4201831| if (OPTIMIZER) | { 1682130| if (OTassoc(op)) | { | /* Replace (a op1 (b op2 c)) with ((a op2 b) op1 c) | (this must come before the leaf swapping, or we could cause | infinite loops) | */ 376393| if (e2.Eoper == op && 1419| e2.EV.E2.Eoper == OPconst && 859| tysize(e2.EV.E1.Ety) == tysize(e2.EV.E2.Ety) && 859| (!tyfloating(e1.Ety) || e1.Ety == e2.Ety) | ) | { 859| e.EV.E1 = e2; 859| e.EV.E2 = e2.EV.E2; 859| e2.EV.E2 = e2.EV.E1; 859| e2.EV.E1 = e1; 859| if (op == OPadd) /* fix types */ | { 859| e1 = e.EV.E1; 859| if (typtr(e1.EV.E2.Ety)) 2| e1.Ety = e1.EV.E2.Ety; | else | /* suppose a and b are ints, and c is a pointer */ | /* then this will fix the type of op2 to be int */ 857| e1.Ety = e1.EV.E1.Ety; | } 859| goto beg; | } | | // Replace ((a op c1) op c2) with (a op (c2 op c1)) 375534| if (e1.Eoper == op && 7392| e2.Eoper == OPconst && 6797| e1.EV.E2.Eoper == OPconst && 1010| e1.EV.E1.Eoper != OPconst && 1010| tysize(e2.Ety) == tysize(e1.EV.E2.Ety)) | { 457| e.EV.E1 = e1.EV.E1; 457| e1.EV.E1 = e2; 457| e1.Ety = e2.Ety; 457| e.EV.E2 = e1; | 457| if (tyfloating(e1.Ety)) | { 00000000| e1 = evalu8(e1, GOALvalue); 00000000| if (!OTleaf(e1.Eoper)) // if failed to fold the constants | { // Undo the changes so we don't infinite loop 00000000| e.EV.E2 = e1.EV.E1; 00000000| e1.EV.E1 = e.EV.E1; 00000000| e.EV.E1 = e1; | } | else 00000000| { e.EV.E2 = e1; 00000000| goto beg; | } | } | else 457| goto beg; | } | } | 4048418| if (!OTrtol(op) && op != OPparam && op != OPcolon && op != OPcolon2 && 695329| e1.Eoper == OPcomma) | { // Convert ((a,b) op c) to (a,(b op c)) 5783| e1.Ety = e.Ety; 5783| e1.ET = e.ET; 5783| e.EV.E1 = e1.EV.E2; 5783| e1.EV.E2 = e; 5783| e = e1; 5783| goto beg; | } | } | 4194732| if (OTcommut(op)) // if commutative | { | /* see if we should swap the leaves */ | version (MARS) { enum MARS = true; } else { enum MARS = false; } 1501922| if ( | MARS ? ( | cost(e2) > cost(e1) | /* Swap only if order of evaluation can be proved | * to not matter, as we must evaluate Left-to-Right | */ 52771| && e1.canHappenAfter(e2) | ) | : cost(e2) > cost(e1) | ) | { 39827| e.EV.E1 = e2; 39827| e2 = e.EV.E2 = e1; 39827| e1 = e.EV.E1; // reverse the leaves 39827| op = e.Eoper = cast(ubyte)swaprel(op); | } 1501922| if (OTassoc(op)) // if commutative and associative | { 1196401| if (!OTleaf(e1.Eoper) && 353663| op == e1.Eoper && 33008| e1.EV.E2.Eoper == OPconst && 24692| e.Ety == e1.Ety && 21837| tysize(e1.EV.E2.Ety) == tysize(e2.Ety) | | // Reordering floating point can change the semantics 21284| && (!MARS || !tyfloating(e1.Ety)) | ) | { | // look for ((e op c1) op c2), | // replace with (e op (c1 op c2)) 21283| if (e2.Eoper == OPconst) | { 20465| e.EV.E1 = e1.EV.E1; 20465| e.EV.E2 = e1; 20465| e1.EV.E1 = e1.EV.E2; 20465| e1.EV.E2 = e2; 20465| e1.Ety = e2.Ety; | 20465| e1 = e.EV.E1; 20465| e2 = e.EV.E2 = evalu8(e.EV.E2, GOALvalue); | } | else | { // Replace ((e op c) op e2) with ((e op e2) op c) 818| e.EV.E2 = e1.EV.E2; 818| e1.EV.E2 = e2; 818| e2 = e.EV.E2; | } | } | } | } | 4194732| if (e2.Eoper == OPconst && // if right operand is a constant 2426732| !(OTopeq(op) && OTconv(e1.Eoper)) | ) | { 3400061| debug assert(!(OTeop0e(op) && (OTeop00(op)))); 2197406| if (OTeop0e(op)) /* if e1 op 0 => e1 */ | { 1202655| if (!boolres(e2)) /* if e2 is 0 */ | { | // Don't do it for ANSI floating point 159161| if (tyfloating(e1.Ety) && !(config.flags4 & CFG4fastfloat)) | { } | // Don't do it if we're assembling a complex value 158851| else if ((tytab[e.EV.E1.Ety & 0xFF] ^ | tytab[e.EV.E2.Ety & 0xFF]) == (TYFLreal | TYFLimaginary)) | { } | else 158851| return optelem(el_selecte1(e),goal); | } | } 1162372| else if (OTeop00(op) && !boolres(e2) && !tyfloating(e.Ety)) | { 76| if (OTassign(op)) 00000000| op = e.Eoper = OPeq; | else 76| op = e.Eoper = OPcomma; | } | 2038555| if (OTeop1e(op)) /* if e1 op 1 => e1 */ | { 85404| if (elemisone(e2) && !tyimaginary(e2.Ety)) 17414| return optelem(el_selecte1(e),goal); | } | } | 4041799| if (OTpost(op) && !goal) | { 11704| op = e.Eoper = (op == OPpostinc) ? OPaddass : OPminass; | } | } | else /* unary operator */ | { 3015200| assert(!e.EV.E2 || op == OPinfo || op == OPddtor); 3745717| if (!goal && !OTsideff(op) && !(e.Ety & (mTYvolatile | mTYshared))) | { 347930| tym_t tym = e.EV.E1.Ety; | 347930| e = el_selecte1(e); 347930| e.Ety = tym; 347930| return optelem(e,GOALnone); | } | 5335399| if ((op == OPd_f || op == OPd_ld) && e.EV.E1.Eoper == OPu64_d) | { 36| return elu64_d(e, goal); | } | 2667234| elem *e1 = e.EV.E1 = optelem(e.EV.E1, (op == OPddtor) 8264| ? GOALnone 7967060| : (op == OPbool || op == OPnot) ? GOALflags : GOALvalue); 2667234| if (!e1) 00000000| goto retnull; 2667234| if (e1.Eoper == OPconst) | { 44798| if (!(op == OPnp_fp && el_tolong(e1) != 0)) 44798| return evalu8(e, GOALvalue); | } | } | |// if (debugb) |// { print("optelem: %p ",e); WROP(op); print("\n"); } | | static if (0) | { | { print("xoptelem: %p ",e); WROP(e.Eoper); print("\n"); } | elem_print(e); | e = (*elxxx[op])(e, goal); | printf("After:\n"); | elem_print(e); | return e; | } | else | { 6640903| return (*elxxx[op])(e, goal); | } |} | | |/******************************** | * Optimize and canonicalize an expression tree. | * Fiddle with double operators so that the rvalue is a pointer | * (this is needed by the 8086 code generator). | * | * op op | * / \ / \ | * e1 e2 e1 , | * / \ | * = & | * / \ \ | * fr e2 fr | * | * e1 op (*p) e1 op p | * e1 op c e1 op &dc | * e1 op v e1 op &v | */ | |elem *doptelem(elem *e, goal_t goal) |{ | //printf("doptelem(e = %p, goal = x%x)\n", e, goal); 631647| assert(!PARSER); | do 637420| { again = false; 637420| topair = false; 637420| e = optelem(e,goal & (GOALflags | GOALvalue | GOALnone)); 672099| } while (again && goal & GOALagain && e); | | /* If entire expression is a struct, and we can replace it with */ | /* something simpler, do so. */ 2000096| if (goal & GOALstruct && e && (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray)) 4574| e = elstruct(e, goal); | 631647| if (topair) 934| e = elToPair(e); | 631647| return e; |} | |/**************************************** | * Do optimizations after bltailrecursion() and before common subexpressions. | */ | |void postoptelem(elem *e) |{ 367818| Srcpos pos = {0}; | 367818| elem_debug(e); 741440| while (1) | { 741440| if (OTunary(e.Eoper)) | { | /* This is necessary as the optimizer tends to lose this information | */ | version (MARS) 53365| if (e.Esrcpos.Slinnum > pos.Slinnum) 12491| pos = e.Esrcpos; | 53365| if (e.Eoper == OPind) | { | version (MARS) 43051| if (e.EV.E1.Eoper == OPconst && 00000000| tybasic(e.EV.E1.Ety) == TYnptr && // Allow TYfgptr to reference GS:[0000] etc. 00000000| el_tolong(e.EV.E1) >= 0 && el_tolong(e.EV.E1) < 4096) | { 00000000| error(pos.Sfilename, pos.Slinnum, pos.Scharnum, "null dereference in function %s", funcsym_p.Sident.ptr); 00000000| e.EV.E1.EV.Vlong = 4096; // suppress redundant messages | } | } 53365| e = e.EV.E1; | } 688075| else if (OTbinary(e.Eoper)) | { | /* This is necessary as the optimizer tends to lose this information | */ | version (MARS) 320257| if (e.Esrcpos.Slinnum > pos.Slinnum) 65299| pos = e.Esrcpos; | 320257| if (e.Eoper == OPparam) | { 46251| if (!I64) 1| elparamx(e); | } 320257| postoptelem(e.EV.E2); 320257| e = e.EV.E1; | } | else 367818| break; | } |} | |/*********************************** | * Rewrite rvalues of complex numbers to pairs of floating point numbers. | */ |private elem *elToPair(elem *e) |{ 12715| switch (e.Eoper) | { 1764| case OPvar: | { | /* Rewrite complex number loads as a pair of loads | * e => (e.0 pair e.offset) | */ 1764| tym_t ty0; 1764| tym_t ty = e.Ety; 1764| switch (tybasic(ty)) | { 702| case TYcfloat: ty0 = TYfloat | (ty & ~mTYbasic); goto L1; 729| case TYcdouble: ty0 = TYdouble | (ty & ~mTYbasic); goto L1; | L1: 477| if (_tysize[tybasic(ty0)] < REGSIZE) 234| break; // func parameters, for example, can't handle this 243| e.Ety = ty0; 243| elem *e2 = el_copytree(e); 243| e2.EV.Voffset += _tysize[tybasic(ty0)]; 243| return el_bin(OPpair, ty, e, e2); | 1287| default: 1287| break; | } 1521| break; | } | 319| case OPind: | { 319| e.EV.E1 = elToPair(e.EV.E1); | /* Rewrite complex number loads as a pair of loads | * *e1 => (*e1 pair *(e1 + offset)) | */ 319| tym_t ty0; 319| tym_t ty = e.Ety; 319| switch (tybasic(ty)) | { 63| case TYcfloat: ty0 = TYfloat | (ty & ~mTYbasic); goto L2; 408| case TYcdouble: ty0 = TYdouble | (ty & ~mTYbasic); goto L2; | L2: 157| if (_tysize[tybasic(ty0)] < REGSIZE) 21| break; // func parameters, for example, can't handle this 136| e.Ety = ty0; 136| elem *e2 = el_copytree(e.EV.E1); 136| if (el_sideeffect(e2)) 2| fixside(&e.EV.E1, &e2); 136| e2 = el_bin(OPadd,e2.Ety,e2,el_long(TYsize, _tysize[tybasic(ty0)])); 136| e2 = el_una(OPind, ty0, e2); 136| return el_bin(OPpair, ty, e, e2); | 162| default: 162| break; | } 183| break; | } | 10632| default: 10632| if (OTassign(e.Eoper)) | { | // Skip over OPvar and OPind lvalues 3031| if (OTbinary(e.Eoper)) 3031| e.EV.E2 = elToPair(e.EV.E2); 3031| if (e.EV.E1.Eoper == OPvar) | { | } 52| else if (e.EV.E1.Eoper == OPind) 52| e.EV.E1.EV.E1 = elToPair(e.EV.E1.EV.E1); | else 00000000| e.EV.E1 = elToPair(e.EV.E1); | } 7601| else if (OTunary(e.Eoper)) | { 487| e.EV.E1 = elToPair(e.EV.E1); | } 7114| else if (OTbinary(e.Eoper)) | { 3946| e.EV.E2 = elToPair(e.EV.E2); 3946| e.EV.E1 = elToPair(e.EV.E1); | } 10632| break; | } 12336| return e; |} | |/****************************************** | * Determine if `b` can be moved before `a` without disturbing | * order-of-evaluation semantics. | */ | |private bool canHappenAfter(elem* a, elem* b) |{ 52849| return a.Eoper == OPconst || 41237| a.Eoper == OPrelconst || | | /* a is a variable that is not aliased | * and is not assigned to in b | */ 60147| (a.Eoper == OPvar && a.EV.Vsym.Sflags & SFLunambig && !el_appears(b, a.EV.Vsym)) || | 64044| !(el_sideeffect(a) || el_sideeffect(b)); |} | | |/*************************************************** | * Call table, index is OPER | */ | |private extern (C++) alias elfp_t = elem *function(elem *, goal_t) nothrow; | |private extern (D) immutable elfp_t[OPMAX] elxxx = |[ | OPunde: &elerr, | OPadd: &eladd, | OPmul: &elmul, | OPand: &elbitwise, | OPmin: &elmin, | OPnot: &elnot, | OPcom: &elcom, | OPcond: &elcond, | OPcomma: &elcomma, | OPremquo: &elremquo, | OPdiv: &eldiv, | OPmod: &elmod, | OPxor: &elxor, | OPstring: &elstring, | OPrelconst: &elzot, | OPinp: &elzot, | OPoutp: &elzot, | OPasm: &elzot, | OPinfo: &elinfo, | OPdctor: &elzot, | OPddtor: &elddtor, | OPctor: &elinfo, | OPdtor: &elinfo, | OPmark: &elinfo, | OPvoid: &elzot, | OPhalt: &elzot, | OPnullptr: &elerr, | OPpair: &elpair, | OPrpair: &elpair, | | OPor: &elor, | OPoror: &eloror, | OPandand: &elandand, | OProl: &elshl, | OPror: &elshl, | OPshl: &elshl, | OPshr: &elshr, | OPashr: &elshr, | OPbit: &elbit, | OPind: &elind, | OPaddr: &eladdr, | OPneg: &elneg, | OPuadd: &elzot, | OPabs: &evalu8, | OPsqrt: &evalu8, | OPsin: &evalu8, | OPcos: &evalu8, | OPscale: &elzot, | OPyl2x: &elzot, | OPyl2xp1: &elzot, | OPcmpxchg: &elzot, | OPtoprec: &elzot, | OPrint: &evalu8, | OPrndtol: &evalu8, | OPstrlen: &elzot, | OPstrcpy: &elstrcpy, | OPmemcpy: &elmemcpy, | OPmemset: &elmemset, | OPstrcat: &elzot, | OPstrcmp: &elstrcmp, | OPmemcmp: &elmemcmp, | OPsetjmp: &elzot, | OPnegass: &elnegass, | OPpreinc: &elzot, | OPpredec: &elzot, | OPstreq: &elstruct, | OPpostinc: &elpost, | OPpostdec: &elpost, | OPeq: &eleq, | OPaddass: &elopass, | OPminass: &elopass, | OPmulass: &elopass, | OPdivass: &elopass, | OPmodass: &elopass, | OPshrass: &elopass, | OPashrass: &elopass, | OPshlass: &elopass, | OPandass: &elopass, | OPxorass: &elopass, | OPorass: &elopass, | | OPle: &elcmp, | OPgt: &elcmp, | OPlt: &elcmp, | OPge: &elcmp, | OPeqeq: &elcmp, | OPne: &elcmp, | | OPunord: &elcmp, | OPlg: &elcmp, | OPleg: &elcmp, | OPule: &elcmp, | OPul: &elcmp, | OPuge: &elcmp, | OPug: &elcmp, | OPue: &elcmp, | OPngt: &elcmp, | OPnge: &elcmp, | OPnlt: &elcmp, | OPnle: &elcmp, | OPord: &elcmp, | OPnlg: &elcmp, | OPnleg: &elcmp, | OPnule: &elcmp, | OPnul: &elcmp, | OPnuge: &elcmp, | OPnug: &elcmp, | OPnue: &elcmp, | | OPvp_fp: &elvptrfptr, | OPcvp_fp: &elvptrfptr, | OPoffset: &ellngsht, | OPnp_fp: &elptrlptr, | OPnp_f16p: &elzot, | OPf16p_np: &elzot, | | OPs16_32: &evalu8, | OPu16_32: &evalu8, | OPd_s32: &evalu8, | OPb_8: &evalu8, | OPs32_d: &evalu8, | OPd_s16: &evalu8, | OPs16_d: &evalu8, | OPd_u16: &evalu8, | OPu16_d: &evalu8, | OPd_u32: &evalu8, | OPu32_d: &evalu8, | OP32_16: &ellngsht, | OPd_f: &evalu8, | OPf_d: &evalu8, | OPd_ld: &evalu8, | OPld_d: &evalu8, | OPc_r: &elc_r, | OPc_i: &elc_i, | OPu8_16: &elbyteint, | OPs8_16: &elbyteint, | OP16_8: &ellngsht, | OPu32_64: &el32_64, | OPs32_64: &el32_64, | OP64_32: &el64_32, | OPu64_128: &evalu8, | OPs64_128: &evalu8, | OP128_64: &el64_32, | OPmsw: &elmsw, | | OPd_s64: &evalu8, | OPs64_d: &evalu8, | OPd_u64: &evalu8, | OPu64_d: &elu64_d, | OPld_u64: &evalu8, | OPparam: &elparam, | OPsizeof: &elzot, | OParrow: &elzot, | OParrowstar: &elzot, | OPcolon: &elzot, | OPcolon2: &elzot, | OPbool: &elbool, | OPcall: &elcall, | OPucall: &elcall, | OPcallns: &elcall, | OPucallns: &elcall, | OPstrpar: &elstruct, | OPstrctor: &elzot, | OPstrthis: &elzot, | OPconst: &elerr, | OPvar: &elerr, | OPreg: &elerr, | OPnew: &elerr, | OPanew: &elerr, | OPdelete: &elerr, | OPadelete: &elerr, | OPbrack: &elerr, | OPframeptr: &elzot, | OPgot: &elzot, | | OPbsf: &elzot, | OPbsr: &elzot, | OPbtst: &elzot, | OPbt: &elzot, | OPbtc: &elzot, | OPbtr: &elzot, | OPbts: &elzot, | | OPbswap: &evalu8, | OPpopcnt: &evalu8, | OPvector: &elzot, | OPvecsto: &elzot, | OPvecfill: &elzot, | OPva_start: &elvalist, | OPprefetch: &elzot, |]; | |} src/dmd/backend/cgelem.d is 69% covered <<<<<< EOF # path=./src-dmd-func.lst |/** | * Defines a function declaration. | * | * Includes: | * - function/delegate literals | * - function aliases | * - (static/shared) constructors/destructors/post-blits | * - `invariant` | * - `unittest` | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d) | * Documentation: https://dlang.org/phobos/dmd_func.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d | */ | |module dmd.func; | |import core.stdc.stdio; |import core.stdc.string; |import dmd.aggregate; |import dmd.arraytypes; |import dmd.blockexit; |import dmd.gluelayer; |import dmd.dclass; |import dmd.declaration; |import dmd.delegatize; |import dmd.dinterpret; |import dmd.dmodule; |import dmd.dscope; |import dmd.dstruct; |import dmd.dsymbol; |import dmd.dsymbolsem; |import dmd.dtemplate; |import dmd.errors; |import dmd.escape; |import dmd.expression; |import dmd.globals; |import dmd.hdrgen; |import dmd.id; |import dmd.identifier; |import dmd.init; |import dmd.mtype; |import dmd.objc; |import dmd.root.outbuffer; |import dmd.root.rootobject; |import dmd.root.string; |import dmd.root.stringtable; |import dmd.semantic2; |import dmd.semantic3; |import dmd.statement_rewrite_walker; |import dmd.statement; |import dmd.statementsem; |import dmd.tokens; |import dmd.visitor; | |/// Inline Status |enum ILS : int |{ | uninitialized, /// not computed yet | no, /// cannot inline | yes, /// can inline |} | |enum BUILTIN : byte |{ | unknown = -1, /// not known if this is a builtin | unimp, /// this is not a builtin | gcc, /// this is a GCC builtin | llvm, /// this is an LLVM builtin | sin, | cos, | tan, | sqrt, | fabs, | ldexp, | log, | log2, | log10, | exp, | expm1, | exp2, | round, | floor, | ceil, | trunc, | copysign, | pow, | fmin, | fmax, | fma, | isnan, | isinfinity, | isfinite, | bsf, | bsr, | bswap, | popcnt, | yl2x, | yl2xp1, | toPrecFloat, | toPrecDouble, | toPrecReal |} | |/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO. | */ |extern (C++) final class NrvoWalker : StatementRewriteWalker |{ | alias visit = typeof(super).visit; |public: | FuncDeclaration fd; | Scope* sc; | | override void visit(ReturnStatement s) | { | // See if all returns are instead to be replaced with a goto returnLabel; 2933| if (fd.returnLabel) | { | /* Rewrite: | * return exp; | * as: | * vresult = exp; goto Lresult; | */ 1181| auto gs = new GotoStatement(s.loc, Id.returnLabel); 1181| gs.label = fd.returnLabel; | 1181| Statement s1 = gs; 1181| if (s.exp) 1180| s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs); | 1181| replaceCurrent(s1); | } | } | | override void visit(TryFinallyStatement s) | { 584| DtorExpStatement des; 1490| if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && 453| fd.nrvo_var == des.var) | { 838| if (!(global.params.useExceptions && ClassDeclaration.throwable)) | { | /* Don't need to call destructor at all, since it is nrvo | */ 2| replaceCurrent(s._body); 2| s._body.accept(this); 2| return; | } | | /* 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; | */ 418| Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var); 418| Identifier id = Identifier.generateId("__o"); | 418| Statement handler = new PeelStatement(sexception); 418| if (sexception.blockExit(fd, false) & BE.fallthru) | { 418| auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id)); 418| ts.internalThrow = true; 418| handler = new CompoundStatement(Loc.initial, handler, ts); | } | 418| auto catches = new Catches(); 418| auto ctch = new Catch(Loc.initial, getThrowable(), id, handler); 418| ctch.internalCatch = true; 418| ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o' 418| catches.push(ctch); | 418| Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches); 418| fd.eh_none = false; 418| replaceCurrent(s2); 418| s2.accept(this); | } | else 164| StatementRewriteWalker.visit(s); | } |} | |enum FUNCFLAG : uint |{ | purityInprocess = 1, /// working on determining purity | safetyInprocess = 2, /// working on determining safety | nothrowInprocess = 4, /// working on determining nothrow | nogcInprocess = 8, /// working on determining @nogc | returnInprocess = 0x10, /// working on inferring 'return' for parameters | inlineScanned = 0x20, /// function has been scanned for inline possibilities | inferScope = 0x40, /// infer 'scope' for parameters | hasCatches = 0x80, /// function has try-catch statements | compileTimeOnly = 0x100, /// is a compile time only function; no code will be generated for it | printf = 0x200, /// is a printf-like function | scanf = 0x400, /// is a scanf-like function |} | |/*********************************************************** | * Tuple of result identifier (possibly null) and statement. | * This is used to store out contracts: out(id){ ensure } | */ |extern (C++) struct Ensure |{ | Identifier id; | Statement ensure; | | Ensure syntaxCopy() | { 628| return Ensure(id, ensure.syntaxCopy()); | } | | /***************************************** | * Do syntax copy of an array of Ensure's. | */ | static Ensures* arraySyntaxCopy(Ensures* a) | { 628| Ensures* b = null; 628| if (a) | { 628| b = a.copy(); 4396| foreach (i, e; *a) | { 628| (*b)[i] = e.syntaxCopy(); | } | } 628| return b; | } | |} | |/*********************************************************** | */ |extern (C++) class FuncDeclaration : Declaration |{ | Statements* frequires; /// in contracts | Ensures* fensures; /// out contracts | Statement frequire; /// lowered in contract | Statement fensure; /// lowered out contract | Statement fbody; /// function body | | FuncDeclarations foverrides; /// functions this function overrides | FuncDeclaration fdrequire; /// function that does the in contract | FuncDeclaration fdensure; /// function that does the out contract | | Expressions* fdrequireParams; /// argument list for __require | Expressions* fdensureParams; /// argument list for __ensure | | const(char)* mangleString; /// mangled symbol created from mangleExact() | | VarDeclaration vresult; /// result variable for out contracts | 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) | bool isThis2; /// has a dual-context 'this' parameter | VarDeclaration v_arguments; /// '_arguments' parameter | ObjcSelector* selector; /// Objective-C method selector (member function only) | VarDeclaration selectorParameter; /// Objective-C implicit selector parameter | | 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 = -1; /// 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 | bool hasAlwaysInlines; /// contains references to functions that must be inlined | ubyte isCrtCtorDtor; /// has attribute pragma(crt_constructor(1)/crt_destructor(2)) | /// not set before the glue layer | | ILS inlineStatusStmt = ILS.uninitialized; | ILS inlineStatusExp = ILS.uninitialized; | PINLINE inlining = PINLINE.default_; | | int inlineNest; /// !=0 if nested inline | bool eh_none; /// true if no exception unwinding is needed | | bool semantic3Errors; /// true if errors in semantic3 this function's frame ptr | ForeachStatement fes; /// if foreach body, this is the foreach | BaseClass* interfaceVirtual; /// if virtual, but only appears in base 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; /// true means we can do NRVO | 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 = BUILTIN.unknown; | | /// 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 | * (They'll get put into the "closure" for this function.) | */ | VarDeclarations closureVars; | | /** Outer variables which are referenced by this nested function | * (the inverse of closureVars) | */ | VarDeclarations outerVars; | | /// Sibling nested functions which called this one | FuncDeclarations siblingCallers; | | FuncDeclarations *inlinedNestedCallees; | | uint flags; /// FUNCFLAG.xxxxx | 3780743| extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type) | { 3780743| super(loc, ident); | //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type); | //printf("storage_class = x%x\n", storage_class); 3780743| this.storage_class = storage_class; 3780743| this.type = type; 3780743| if (type) | { | // Normalize storage_class, because function-type related attributes | // are already set in the 'type' in parsing phase. 3066064| this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); | } 3780743| this.endloc = endloc; | /* The type given for "infer the return type" is a TypeFunction with | * NULL for the return type. | */ 6846807| inferRetType = (type && type.nextOf() is null); | } | | static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type) | { 00000000| return new FuncDeclaration(loc, endloc, id, storage_class, type); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { | //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); 423224| FuncDeclaration f = s ? cast(FuncDeclaration)s : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy()); 423224| f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null; 423224| f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null; 423224| f.fbody = fbody ? fbody.syntaxCopy() : null; 211612| return f; | } | | /**************************************************** | * Resolve forward reference of function signature - | * parameter types, return type, and attributes. | * Returns false if any errors exist in the signature. | */ | final bool functionSemantic() | { 973735| if (!_scope) 1443| return !errors; | 972292| this.cppnamespace = _scope.namespace; | 972292| if (!originalType) // semantic not yet run | { 3493| TemplateInstance spec = isSpeculative(); 3493| uint olderrs = global.errors; 3493| uint oldgag = global.gag; 3556| if (global.gag && !spec) 63| global.gag = 0; 3493| dsymbolSemantic(this, _scope); 3493| global.gag = oldgag; 3493| if (spec && global.errors != olderrs) 00000000| spec.errors = (global.errors - olderrs != 0); 3493| if (olderrs != global.errors) // if errors compiling this function 3| 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. 1145643| if (inferRetType && type && !type.nextOf()) 1816| return functionSemantic3(); | 970473| TemplateInstance ti; 1523834| if (isInstantiated() && !isVirtualMethod() && 1152397| ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)) | { 489136| AggregateDeclaration ad = isMemberLocal(); 690050| if (ad && ad.sizeok != Sizeok.done) | { | /* 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.dsymbolSemantic() done. | */ | //ad.sizeok = Sizeok.fwd; | } | else 488891| return functionSemantic3() || !errors; | } | 481781| if (storage_class & STC.inference) 14040| return functionSemantic3() || !errors; | 467745| return !errors; | } | | /**************************************************** | * Resolve forward reference of function body. | * Returns false if any errors exist in the body. | */ | final bool functionSemantic3() | { 5449355| if (semanticRun < PASS.semantic3 && _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. | */ 15623| TemplateInstance spec = isSpeculative(); 15623| uint olderrs = global.errors; 15623| uint oldgag = global.gag; 19944| if (global.gag && !spec) 1488| global.gag = 0; 15623| semantic3(this, _scope); 15620| global.gag = oldgag; | | // If it is a speculatively-instantiated template, and errors occur, | // we need to mark the template as having errors. 18455| if (spec && global.errors != olderrs) 130| spec.errors = (global.errors - olderrs != 0); 15620| if (olderrs != global.errors) // if errors compiling this function 163| return false; | } | 10867129| return !errors && !semantic3Errors; | } | | /**************************************************** | * Check that this function type is properly resolved. | * If not, report "forward reference error" and return true. | */ | extern (D) final bool checkForwardRef(const ref Loc loc) | { 5590| if (!functionSemantic()) 00000000| return true; | | /* No deco means the functionSemantic() call could not resolve | * forward referenes in the type of this function. | */ 5590| if (!type.deco) | { 43| bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3); 24| .error(loc, "forward reference to %s`%s`", 24| (inSemantic3 ? "inferred return type of function " : "").ptr, | toChars()); 24| return true; | } 5566| return false; | } | | // called from semantic3 | /** | * Creates and returns the hidden parameters for this function declaration. | * | * Hidden parameters include the `this` parameter of a class, struct or | * nested function and the selector parameter for Objective-C methods. | */ | extern (D) final void declareThis(Scope* sc) | { 342447| isThis2 = toParent2() != toParentLocal(); 342447| auto ad = isThis(); 952525| if (!isThis2 && !ad && !isNested()) | { 224214| vthis = null; 224214| selectorParameter = null; 224214| return; | } | | Type addModStc(Type t) | { 118233| return t.addMod(type.mod).addStorageClass(storage_class); | } | 236362| if (isThis2 || 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. | */ 43625| Type tthis = addModStc(isThis2 ? 104| Type.tvoidptr.sarrayOf(2).pointerTo() : 43521| Type.tvoid.pointerTo()); 87250| vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null); 43625| vthis.storage_class |= STC.parameter | STC.nodtor; | } 74608| else if (ad) | { 74608| Type thandle = addModStc(ad.handleType()); 74608| vthis = new ThisDeclaration(loc, thandle); 74608| vthis.storage_class |= STC.parameter; 74608| if (thandle.ty == Tstruct) | { 59688| vthis.storage_class |= STC.ref_; | // if member function is marked 'inout', then 'this' is 'return ref' 119376| if (type.ty == Tfunction && (cast(TypeFunction)type).isInOutQual()) 2040| vthis.storage_class |= STC.return_; | } | } | 118233| if (type.ty == Tfunction) | { 118233| TypeFunction tf = cast(TypeFunction)type; 118233| if (tf.isreturn) 7333| vthis.storage_class |= STC.return_; 118233| if (tf.isScopeQual) 1222| vthis.storage_class |= STC.scope_; | } 153895| if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_)) 35660| vthis.storage_class |= STC.maybescope; | 118233| vthis.dsymbolSemantic(sc); 118233| if (!sc.insert(vthis)) 00000000| assert(0); 118233| vthis.parent = this; 118233| if (ad) 74655| selectorParameter = objc.createSelectorParameter(this, sc); | } | | override final bool equals(const RootObject o) const | { 675| if (this == o) 667| return true; | 8| if (auto s = isDsymbol(o)) | { 8| auto fd1 = this; 8| auto fd2 = s.isFuncDeclaration(); 8| if (!fd2) 00000000| return false; | 8| auto fa1 = fd1.isFuncAliasDeclaration(); 16| auto faf1 = fa1 ? fa1.toAliasFunc() : fd1; | 8| auto fa2 = fd2.isFuncAliasDeclaration(); 16| auto faf2 = fa2 ? fa2.toAliasFunc() : fd2; | 9| if (fa1 && fa2) | { 1| return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads; | } | 7| bool b1 = fa1 !is null; 7| if (b1 && faf1.isUnique() && !fa1.hasOverloads) 00000000| b1 = false; | 7| bool b2 = fa2 !is null; 13| if (b2 && faf2.isUnique() && !fa2.hasOverloads) 00000000| b2 = false; | 7| if (b1 != b2) 6| return false; | 1| return faf1.toParent().equals(faf2.toParent()) && 1| faf1.ident.equals(faf2.ident) && 1| faf1.type.equals(faf2.type); | } 00000000| return false; | } | | /**************************************************** | * Determine if 'this' overrides fd. | * Return !=0 if it does. | */ | final int overrides(FuncDeclaration fd) | { 8708| int result = 0; 8708| if (fd.ident == ident) | { 8708| int cov = type.covariant(fd.type); 8708| if (cov) | { 2337| ClassDeclaration cd1 = toParent().isClassDeclaration(); 2337| ClassDeclaration cd2 = fd.toParent().isClassDeclaration(); 4525| if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) 540| result = 1; | } | } 8708| return result; | } | | /************************************************* | * Find index of function in vtbl[0..dim] that | * this function overrides. | * Prefer an exact match to a covariant one. | * Params: | * vtbl = vtable to use | * dim = maximal vtable dimension | * Returns: | * -1 didn't find one | * -2 can't determine because of forward references | */ | final int findVtblIndex(Dsymbols* vtbl, int dim) | { | //printf("findVtblIndex() %s\n", toChars()); 619326| FuncDeclaration mismatch = null; 619326| StorageClass mismatchstc = 0; 619326| int mismatchvi = -1; 619326| int exactvi = -1; 619326| int bestvi = -1; 19226094| for (int vi = 0; vi < dim; vi++) | { 9169852| FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration(); 17727745| if (fdv && fdv.ident == ident) | { 930511| if (type.equals(fdv.type)) // if exact match | { 176185| if (fdv.parent.isClassDeclaration()) | { 176136| if (fdv.isFuture()) | { 6| bestvi = vi; 6| continue; // keep looking | } 176130| return vi; // no need to look further | } | 49| if (exactvi >= 0) | { 1| error("cannot determine overridden function"); 1| return exactvi; | } 48| exactvi = vi; 48| bestvi = vi; 48| continue; | } | 754326| StorageClass stc = 0; 754326| int cov = type.covariant(fdv.type, &stc); | //printf("\tbaseclass cov = %d\n", cov); 754326| switch (cov) | { 407302| case 0: | // types are distinct 407302| break; | 26302| case 1: 26302| bestvi = vi; // covariant, but not identical 26302| break; | // keep looking for an exact match | 320722| case 2: 320722| mismatchvi = vi; 320722| mismatchstc = stc; 320722| mismatch = fdv; // overrides, but is not covariant 320722| break; | // keep looking for an exact match | 00000000| case 3: 00000000| return -2; // forward references | 00000000| default: 00000000| assert(0); | } | } | } 860044| if (bestvi == -1 && mismatch) | { | //type.print(); | //mismatch.type.print(); | //printf("%s %s\n", type.deco, mismatch.type.deco); | //printf("stc = %llx\n", mismatchstc); 320715| if (mismatchstc) | { | // Fix it by modifying the type to add the storage classes 320706| type = type.addStorageClass(mismatchstc); 320706| bestvi = mismatchvi; | } | } 443195| return bestvi; | } | | /********************************* | * If function a function in a base class, | * return that base class. | * Returns: | * base class if overriding, null if not | */ | final BaseClass* overrideInterface() | { 00000000| if (ClassDeclaration cd = toParent2().isClassDeclaration()) | { 00000000| foreach (b; cd.interfaces) | { 00000000| auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim); 00000000| if (v >= 0) 00000000| return b; | } | } 00000000| return null; | } | | /**************************************************** | * Overload this FuncDeclaration with the new one f. | * Return true if successful; i.e. no conflict. | */ | override bool overloadInsert(Dsymbol s) | { | //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars()); 205384| assert(s != this); 205384| AliasDeclaration ad = s.isAliasDeclaration(); 205384| if (ad) | { 78| if (overnext) 00000000| return overnext.overloadInsert(ad); 167| if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof) | { | //printf("\tad = '%s'\n", ad.type.toChars()); 1| return false; | } 77| overnext = ad; | //printf("\ttrue: no conflict\n"); 77| return true; | } 205306| TemplateDeclaration td = s.isTemplateDeclaration(); 205306| if (td) | { 3288| if (!td.funcroot) 1302| td.funcroot = this; 3288| if (overnext) 604| return overnext.overloadInsert(td); 2684| overnext = td; 2684| return true; | } 202018| FuncDeclaration fd = s.isFuncDeclaration(); 202018| if (!fd) 00000000| return false; | | version (none) | { | /* Disable this check because: | * const void foo(); | * semantic() isn't run yet on foo(), so the const hasn't been | * applied yet. | */ | if (type) | { | printf("type = %s\n", type.toChars()); | printf("fd.type = %s\n", fd.type.toChars()); | } | // fd.type can be NULL for overloaded constructors | if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration()) | { | //printf("\tfalse: conflict %s\n", kind()); | return false; | } | } | 202018| if (overnext) | { 150769| td = overnext.isTemplateDeclaration(); 150769| if (td) 950| fd.overloadInsert(td); | else 149819| return overnext.overloadInsert(fd); | } 52199| overnext = fd; | //printf("\ttrue: no conflict\n"); 52199| return true; | } | | /******************************************** | * Find function in overload list that exactly matches t. | */ | extern (D) final FuncDeclaration overloadExactMatch(Type t) | { 8586| FuncDeclaration fd; 8586| overloadApply(this, (Dsymbol s) | { 34641| auto f = s.isFuncDeclaration(); 34641| if (!f) 105| return 0; 34536| if (t.equals(f.type)) | { 1618| fd = f; 1618| 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. | */ 32918| if (t.ty == Tfunction) | { 32918| auto tf = cast(TypeFunction)f.type; 32918| if (tf.covariant(t) == 1 && 1765| tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant) | { 1764| fd = f; 1764| return 1; | } | } 31154| return 0; | }); 8586| return fd; | } | | /******************************************** | * 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. | */ | extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads) | { | //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars()); 34| MatchAccumulator m; 34| overloadApply(this, (Dsymbol s) | { 62| auto f = s.isFuncDeclaration(); 124| if (!f || f == m.lastf) // skip duplicates 00000000| return 0; | 62| auto tf = f.type.toTypeFunction(); | //printf("tf = %s\n", tf.toChars()); | 62| MATCH match; 62| if (tthis) // non-static functions are preferred than static ones | { 62| if (f.needThis()) 124| match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod); | else 00000000| match = MATCH.constant; // keep static function in overload candidates | } | else // static functions are preferred than non-static ones | { 00000000| if (f.needThis()) 00000000| match = MATCH.convert; | else 00000000| match = MATCH.exact; | } 62| if (match == MATCH.nomatch) 32| return 0; | 58| if (match > m.last) goto LcurrIsBetter; 4| if (match < m.last) goto LlastIsBetter; | | // See if one of the matches overrides the other. 00000000| if (m.lastf.overrides(f)) goto LlastIsBetter; 00000000| if (f.overrides(m.lastf)) goto LcurrIsBetter; | | //printf("\tambiguous\n"); 00000000| m.nextf = f; 00000000| m.count++; 00000000| return 0; | | LlastIsBetter: | //printf("\tlastbetter\n"); 2| m.count++; // count up 2| return 0; | | LcurrIsBetter: | //printf("\tisbetter\n"); 28| if (m.last <= MATCH.convert) | { | // clear last secondary matching 26| m.nextf = null; 26| m.count = 0; | } 28| m.last = match; 28| m.lastf = f; 28| m.count++; // count up 28| return 0; | }); | 34| if (m.count == 1) // exact match | { 22| hasOverloads = false; | } 12| else if (m.count > 1) // better or ambiguous match | { 4| hasOverloads = true; | } | else // no match | { 8| hasOverloads = true; 8| auto tf = this.type.toTypeFunction(); 8| assert(tthis); 8| assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch | { 32| OutBuffer thisBuf, funcBuf; 8| MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); 8| MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); 8| .error(loc, "%smethod %s is not callable using a %sobject", | funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars()); | } | } 34| return m.lastf; | } | | /******************************************** | * find function template root in overload list | */ | extern (D) final TemplateDeclaration findTemplateDeclRoot() | { 33| FuncDeclaration f = this; 71| while (f && f.overnext) | { | //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars()); 20| TemplateDeclaration td = f.overnext.isTemplateDeclaration(); 20| if (td) 17| return td; 3| f = f.overnext.isFuncDeclaration(); | } 16| return null; | } | | /******************************************** | * Returns true if function was declared | * directly or indirectly in a unittest block | */ | final bool inUnittest() | { 38| Dsymbol f = this; | do | { 76| if (f.isUnitTestDeclaration()) 00000000| return true; 76| f = f.toParent(); | } 76| while (f); 38| return false; | } | | /************************************* | * 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' | */ | final MATCH leastAsSpecialized(FuncDeclaration g) | { | enum LOG_LEASTAS = 0; | static if (LOG_LEASTAS) | { | printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars()); | printf("%s, %s\n", type.toChars(), g.type.toChars()); | } | | /* This works by calling g() with f()'s parameters, and | * if that is possible, then f() is at least as specialized | * as g() is. | */ | 8132| TypeFunction tf = type.toTypeFunction(); 8132| TypeFunction tg = g.type.toTypeFunction(); | | /* 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. | */ 18544| if (needThis() && g.needThis() && tf.mod != tg.mod) | { 284| if (isCtorDeclaration()) | { 138| if (!MODimplicitConv(tg.mod, tf.mod)) 134| return MATCH.nomatch; | } | else | { 146| if (!MODimplicitConv(tf.mod, tg.mod)) 103| return MATCH.nomatch; | } | } | | /* Create a dummy array of arguments out of the parameters to f() | */ 15790| Expressions args; 7895| foreach (u, p; tf.parameterList) | { 11012| Expression e; 11012| if (p.isReference()) | { 924| e = new IdentifierExp(Loc.initial, p.ident); 924| e.type = p.type; | } | else 10088| e = p.type.defaultInitLiteral(Loc.initial); 11012| args.push(e); | } | 7895| MATCH m = tg.callMatch(null, args[], 1); 7895| if (m > MATCH.nomatch) | { | /* A variadic parameter list is less specialized than a | * non-variadic one. | */ 3848| if (tf.parameterList.varargs && !tg.parameterList.varargs) 2| goto L1; // less specialized | | static if (LOG_LEASTAS) | { | printf(" matches %d, so is least as specialized\n", m); | } 3139| return m; | } | L1: | static if (LOG_LEASTAS) | { | printf(" doesn't match, so is not as specialized\n"); | } 4756| return MATCH.nomatch; | } | | /******************************** | * Labels are in a separate scope, one per function. | */ | final LabelDsymbol searchLabel(Identifier ident) | { 9077| Dsymbol s; 9077| if (!labtab) 3728| labtab = new DsymbolTable(); // guess we need one | 9077| s = labtab.lookup(ident); 9077| if (!s) | { 4400| s = new LabelDsymbol(ident); 4400| labtab.insert(s); | } 9077| return cast(LabelDsymbol)s; | } | | /***************************************** | * Determine lexical level difference from `this` to nested function `fd`. | * Params: | * fd = target of call | * intypeof = !=0 if inside typeof | * Returns: | * 0 same level | * >0 decrease nesting by number | * -1 increase nesting by 1 (`fd` is nested within `this`) | * LevelError error, `this` cannot call `fd` | */ | final int getLevel(FuncDeclaration fd, int intypeof) | { | //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars()); 53896| Dsymbol fdparent = fd.toParent2(); 53896| if (fdparent == this) 00000000| return -1; | 53896| Dsymbol s = this; 53896| int level = 0; 170613| while (fd != s && fdparent != s.toParent2()) | { | //printf("\ts = %s, '%s'\n", s.kind(), s.toChars()); 58348| if (auto thisfd = s.isFuncDeclaration()) | { 58381| if (!thisfd.isNested() && !thisfd.vthis && !intypeof) 9| return LevelError; | } | else | { 3007| if (auto thiscd = s.isAggregateDeclaration()) | { | /* 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'. | * } | */ 3007| if (!thiscd.isNested() && !intypeof) 00000000| return LevelError; | } | else 4| return LevelError; | } | 58335| s = s.toParentP(fd); 58335| assert(s); 58335| level++; | } 53883| return level; | } | | /*********************************** | * Determine lexical level difference from `this` to nested function `fd`. | * Issue error if `this` cannot call `fd`. | * Params: | * loc = location for error messages | * sc = context | * fd = target of call | * Returns: | * 0 same level | * >0 decrease nesting by number | * -1 increase nesting by 1 (`fd` is nested within 'this') | * LevelError error | */ | final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd) | { 53868| int level = getLevel(fd, sc.intypeof); 53868| if (level != LevelError) 53855| return level; | | // Don't give error if in template constraint 13| if (!(sc.flags & SCOPE.constraint)) | { 18| const(char)* xstatic = isStatic() ? "static " : ""; | // better diagnostics for static functions 9| .error(loc, "%s%s %s cannot access frame of function %s", | xstatic, kind(), toPrettyChars(), fd.toPrettyChars()); 9| return LevelError; | } 4| return 1; | } | | enum LevelError = -2; | | override const(char)* toPrettyChars(bool QualifyTypes = false) | { 172015| if (isMain()) 1277| return "D main"; | else 170738| return Dsymbol.toPrettyChars(QualifyTypes); | } | | /** for diagnostics, e.g. 'int foo(int x, int y) pure' */ | final const(char)* toFullSignature() | { 24| OutBuffer buf; 12| functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars()); 12| return buf.extractChars(); | } | | final bool isMain() const | { 3261828| return ident == Id.main && linkage != LINK.c && !isMember() && !isNested(); | } | | final bool isCMain() const | { 147537| return ident == Id.main && linkage == LINK.c && !isMember() && !isNested(); | } | | final bool isWinMain() const | { | //printf("FuncDeclaration::isWinMain() %s\n", toChars()); | version (none) | { | bool x = ident == Id.WinMain && linkage != LINK.c && !isMember(); | printf("%s\n", x ? "yes" : "no"); | return x; | } | else | { 180670| return ident == Id.WinMain && linkage != LINK.c && !isMember(); | } | } | | final bool isDllMain() const | { 180670| return ident == Id.DllMain && linkage != LINK.c && !isMember(); | } | | final bool isRtInit() const | { 143607| return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested(); | } | | override final bool isExport() const | { 158549| return protection.kind == Prot.Kind.export_; | } | | override final bool isImportedSymbol() const | { | //printf("isImportedSymbol()\n"); | //printf("protection = %d\n", protection); 211434| return (protection.kind == Prot.Kind.export_) && !fbody; | } | | override final bool isCodeseg() const pure nothrow @nogc @safe | { 411| return true; // functions are always in the code segment | } | | override final bool isOverloadable() const | { 396149| return true; // functions can be overloaded | } | | /*********************************** | * Override so it can work even if semantic() hasn't yet | * been run. | */ | override final bool isAbstract() | { 3013315| if (storage_class & STC.abstract_) 32397| return true; 2980918| if (semanticRun >= PASS.semanticdone) 70003| return false; | 2910915| if (_scope) | { 5| if (_scope.stc & STC.abstract_) 00000000| return true; 5| parent = _scope.parent; 5| Dsymbol parent = toParent(); 5| if (parent.isInterfaceDeclaration()) 00000000| return true; | } 2910915| return false; | } | | /********************************** | * Decide if attributes for this function can be inferred from examining | * the function body. | * Returns: | * true if can | */ | final bool canInferAttributes(Scope* sc) | { 1350947| if (!fbody) 237761| return false; | 1113186| if (isVirtualMethod()) 610415| return false; // since they may be overridden | 502771| if (sc.func && | /********** this is for backwards compatibility for the moment ********/ 61336| (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated())) 25366| return true; | 477405| if (isFuncLiteralDeclaration() || // externs are not possible with literals 454941| (storage_class & STC.inference) || // do attribute inference 497215| (inferRetType && !isCtorDeclaration())) 52025| return true; | 425380| if (isInstantiated()) | { 91369| auto ti = parent.isTemplateInstance(); 225384| if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident) 90732| return true; | } | 334648| return false; | } | | /***************************************** | * Initialize for inferring the attributes of this function. | */ | final void initInferAttributes() | { | //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars()); 168123| TypeFunction tf = type.toTypeFunction(); 168123| if (tf.purity == PURE.impure) // purity not specified 143311| flags |= FUNCFLAG.purityInprocess; | 168123| if (tf.trust == TRUST.default_) 133998| flags |= FUNCFLAG.safetyInprocess; | 168123| if (!tf.isnothrow) 144480| flags |= FUNCFLAG.nothrowInprocess; | 168123| if (!tf.isnogc) 153969| flags |= FUNCFLAG.nogcInprocess; | 168381| if (!isVirtual() || introducing) 167865| flags |= FUNCFLAG.returnInprocess; | | // Initialize for inferring STC.scope_ 168123| if (global.params.vsafe) 824| flags |= FUNCFLAG.inferScope; | } | | final PURE isPure() | { | //printf("FuncDeclaration::isPure() '%s'\n", toChars()); 877474| TypeFunction tf = type.toTypeFunction(); 877474| if (flags & FUNCFLAG.purityInprocess) 45| setImpure(); 877474| if (tf.purity == PURE.fwdref) 92251| tf.purityLevel(); 877474| PURE purity = tf.purity; 1091436| if (purity > PURE.weak && isNested()) 2863| purity = PURE.weak; 1088573| if (purity > PURE.weak && needThis()) | { | // The attribute of the 'this' reference affects purity strength 57114| if (type.mod & MODFlags.immutable_) | { | } 103525| else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_) 46640| purity = PURE.const_; | else 10245| purity = PURE.weak; | } 877474| tf.purity = purity; | // ^ This rely on the current situation that every FuncDeclaration has a | // unique TypeFunction. 877474| return purity; | } | | final PURE isPureBypassingInference() | { 30220| if (flags & FUNCFLAG.purityInprocess) 8511| return PURE.fwdref; | else 21709| return isPure(); | } | | /************************************** | * The function is doing something impure, | * so mark it as impure. | * If there's a purity error, return true. | */ | extern (D) final bool setImpure() | { 226939| if (flags & FUNCFLAG.purityInprocess) | { 21974| flags &= ~FUNCFLAG.purityInprocess; 21974| if (fes) 242| fes.func.setImpure(); | } 204965| else if (isPure()) 65| return true; 226874| return false; | } | | final bool isSafe() | { 979710| if (flags & FUNCFLAG.safetyInprocess) 30| setUnsafe(); 979710| return type.toTypeFunction().trust == TRUST.safe; | } | | final bool isSafeBypassingInference() | { 863861| return !(flags & FUNCFLAG.safetyInprocess) && isSafe(); | } | | final bool isTrusted() | { 209826| if (flags & FUNCFLAG.safetyInprocess) 00000000| setUnsafe(); 209826| return type.toTypeFunction().trust == TRUST.trusted; | } | | /************************************** | * The function is doing something unsafe, | * so mark it as unsafe. | * If there's a safe error, return true. | */ | extern (D) final bool setUnsafe() | { 246342| if (flags & FUNCFLAG.safetyInprocess) | { 20333| flags &= ~FUNCFLAG.safetyInprocess; 20333| type.toTypeFunction().trust = TRUST.system; 20333| if (fes) 161| fes.func.setUnsafe(); | } 226009| else if (isSafe()) 358| return true; 245984| return false; | } | | final bool isNogc() | { | //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess)); 584861| if (flags & FUNCFLAG.nogcInprocess) 315| setGC(); 584861| return type.toTypeFunction().isnogc; | } | | final bool isNogcBypassingInference() | { 394| return !(flags & FUNCFLAG.nogcInprocess) && 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 | */ | extern (D) final bool setGC() | { | //printf("setGC() %s\n", toChars()); 270407| if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope) | { 161| this.semantic2(_scope); 161| this.semantic3(_scope); | } | 229857| if (flags & FUNCFLAG.nogcInprocess) | { 40228| flags &= ~FUNCFLAG.nogcInprocess; 40228| type.toTypeFunction().isnogc = false; 40228| if (fes) 180| fes.func.setGC(); | } 189629| else if (isNogc()) 125| return true; 229732| return false; | } | | extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn) | { 6058| if (!global.params.vgc) 6018| return; | 40| Module m = getModule(); 118| if (m && m.isRoot() && !inUnittest()) | { 38| message(loc, "vgc: %s", warn); | } | } | | /******************************************** | * See if pointers from function parameters, mutable globals, or uplevel functions | * could leak into return value. | * Returns: | * true if the function return value is isolated from | * any inputs to the function | */ | extern (D) final bool isReturnIsolated() | { | //printf("isReturnIsolated(this: %s)\n", this.toChars); 6898| TypeFunction tf = type.toTypeFunction(); 6898| assert(tf.next); | 6898| Type treti = tf.next; 6898| if (tf.isref) 1542| return isTypeIsolatedIndirect(treti); // check influence from parameters | 5356| return isTypeIsolated(treti); | } | | /******************** | * See if pointers from function parameters, mutable globals, or uplevel functions | * could leak into type `t`. | * Params: | * t = type to check if it is isolated | * Returns: | * true if `t` is isolated from | * any inputs to the function | */ | extern (D) final bool isTypeIsolated(Type t) | { 10864| StringTable!Type parentTypes; 5432| parentTypes._init(); 5432| return isTypeIsolated(t, parentTypes); | } | | ///ditto | extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes) | { | //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars()); | 6774| t = t.baseElemOf(); 6774| switch (t.ty) | { 2916| case Tarray: 3549| case Tpointer: 3549| return isTypeIsolatedIndirect(t.nextOf()); // go down one level | 00000000| case Taarray: 1474| case Tclass: 1474| return isTypeIsolatedIndirect(t); | 914| case Tstruct: | /* Drill down and check the struct's fields | */ 914| auto sym = t.toDsymbol(null).isStructDeclaration(); 914| const tName = t.toChars.toDString; 914| const entry = parentTypes.insert(tName, t); 914| if (entry == null) | { | //we've already seen this type in a parent, not isolated 23| return false; | } 5429| foreach (v; sym.fields) | { 1342| Type tmi = v.type.addMod(t.mod); | //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n", | // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars()); 1342| if (!isTypeIsolated(tmi, parentTypes)) 635| return false; | } 256| return true; | 837| default: 837| return true; | } | } | | /******************************************** | * Params: | * t = type of object to test one level of indirection down | * Returns: | * true if an object typed `t` has no indirections | * which could have come from the function's parameters, mutable | * globals, or uplevel functions. | */ | private bool isTypeIsolatedIndirect(Type t) | { | //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars()); 6565| assert(t); | | /* Since `t` is one level down from an indirection, it could pick | * up a reference to a mutable global or an outer function, so | * return false. | */ 10909| if (!isPureBypassingInference() || isNested()) 2254| return false; | 4311| TypeFunction tf = type.toTypeFunction(); | | //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars()); | 4311| foreach (i, fparam; tf.parameterList) | { 2671| Type tp = fparam.type; 2671| if (!tp) | continue; | 2671| if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_)) | { 9| if (!traverseIndirections(tp, t)) 7| return false; | continue; | } | | /* Goes down one level of indirection, then calls traverseIndirection() on | * the result. | * Returns: | * true if t is isolated from tp | */ | static bool traverse(Type tp, Type t) | { 4835| tp = tp.baseElemOf(); 4835| switch (tp.ty) | { 472| case Tarray: 1179| case Tpointer: 1179| return traverseIndirections(tp.nextOf(), t); | 00000000| case Taarray: 19| case Tclass: 19| return traverseIndirections(tp, t); | 1117| case Tstruct: | /* Drill down and check the struct's fields | */ 1117| auto sym = tp.toDsymbol(null).isStructDeclaration(); 9410| foreach (v; sym.fields) | { 2173| Type tprmi = v.type.addMod(tp.mod); | //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars()); 2173| if (!traverse(tprmi, t)) 230| return false; | } 887| return true; | 2520| default: 2520| return true; | } | } | 2662| if (!traverse(tp, t)) 1108| return false; | } | // The 'this' reference is a parameter, too 6392| if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis()) | { 1822| Type tthis = ad.getType().addMod(tf.mod); | //printf("\ttthis = %s\n", tthis.toChars()); 1822| if (!traverseIndirections(tthis, t)) 1717| return false; | } | 1479| 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, | * unless the function needs a dual-context pointer. | */ | bool isNested() const | { 11520468| auto f = toAliasFunc(); | //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars()); 11520468| return ((f.storage_class & STC.static_) == 0) && 11222566| (f.linkage == LINK.d) && 10850734| (f.toParent2().isFuncDeclaration() !is null || 10653405| f.toParent2() !is f.toParentLocal()); | } | | /**************************************** | * 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: | * Both isThis() and isNested() should return true if function needs a dual-context pointer, | * otherwise if isThis() returns true, isNested() should return false. | */ | override inout(AggregateDeclaration) isThis() inout | { | //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); 26656870| auto ad = (storage_class & STC.static_) ? objc.isThis(this) : isMemberLocal(); | //printf("-FuncDeclaration::isThis() %p\n", ad); 13328435| return ad; | } | | override final bool needThis() | { | //printf("FuncDeclaration::needThis() '%s'\n", toChars()); 9189348| return toAliasFunc().isThis() !is null; | } | | // Determine if a function is pedantically virtual | final bool isVirtualMethod() | { 1666718| if (toAliasFunc() != this) 1| return toAliasFunc().isVirtualMethod(); | | //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); 1666717| if (!isVirtual()) 975138| return false; | // If it's a final method, and does not override anything, then it is not virtual 723159| if (isFinalFunc() && foverrides.dim == 0) | { 22084| return false; | } 669495| return true; | } | | // Determine if function goes into virtual function pointer table | bool isVirtual() const | { 7899650| if (toAliasFunc() != this) 1| return toAliasFunc().isVirtual(); | 7899649| auto p = toParent(); | 13918568| if (!isMember || !p.isClassDeclaration) 5236159| return false; | // https://issues.dlang.org/show_bug.cgi?id=19654 2663490| if (p.isClassDeclaration.classKind == ClassKind.objc && !p.isInterfaceDeclaration) 00000000| return objc.isVirtual(this); | | version (none) | { | printf("FuncDeclaration::isVirtual(%s)\n", toChars()); | printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == Prot.Kind.private_, isCtorDeclaration(), linkage != LINK.d); | printf("result is %d\n", isMember() && !(isStatic() || protection == Prot.Kind.private_ || protection == Prot.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc())); | } 10515627| return !(isStatic() || protection.kind == Prot.Kind.private_ || protection.kind == Prot.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc()); | } | | final bool isFinalFunc() const | { 1415262| if (toAliasFunc() != this) 1| return toAliasFunc().isFinalFunc(); | | version (none) | {{ | auto cd = toParent().isClassDeclaration(); | printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal()); | printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_)); | printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_))); | if (cd) | printf("\tmember of %s\n", cd.toChars()); | }} 1415261| if (!isMember()) 00000000| return false; 1415261| if (Declaration.isFinal()) 50576| return true; 1364685| auto cd = toParent().isClassDeclaration(); 2729369| return (cd !is null) && (cd.storage_class & STC.final_); | } | | bool addPreInvariant() | { 157569| auto ad = isThis(); 315138| ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; 340185| return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked); | } | | bool addPostInvariant() | { 313835| auto ad = isThis(); 627670| ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; 498271| return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked); | } | | override const(char)* kind() const | { 10326| return generated ? "generated function" : "function"; | } | | /******************************************** | * Returns: | * true if there are no overloads of this function | */ | final bool isUnique() const | { 9585| bool result = false; 9585| overloadApply(cast() this, (Dsymbol s) | { 9810| auto f = s.isFuncDeclaration(); 9810| if (!f) 8| return 0; 9802| if (result) | { 217| result = false; 217| return 1; // ambiguous, done | } | else | { 9585| result = true; 9585| return 0; | } | }); 9585| return result; | } | | /********************************************* | * 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. | */ | extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc) | { | //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars()); | 460815| if (auto fld = this.isFuncLiteralDeclaration()) | { 8578| if (fld.tok == TOK.reserved) | { 4171| fld.tok = TOK.function_; 4171| fld.vthis = null; | } | } | 921595| if (!parent || parent == sc.parent) 21825| return false; 877498| if (ident == Id.require || ident == Id.ensure) 1198| return false; 829718| if (!isThis() && !isNested()) 379705| return false; | | // The current function 58087| FuncDeclaration fdthis = sc.parent.isFuncDeclaration(); 58087| if (!fdthis) 154| return false; // out of function scope | 57933| Dsymbol p = toParentLocal(); 57933| Dsymbol p2 = toParent2(); | | // Function literals from fdthis to p must be delegates 57933| ensureStaticLinkTo(fdthis, p); 57933| if (p != p2) 23| ensureStaticLinkTo(fdthis, p2); | 57933| if (isNested()) | { | // The function that this function is in | bool checkEnclosing(FuncDeclaration fdv) | { 24376| if (!fdv) 12180| return false; 12196| if (fdv == fdthis) 6813| 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 5383| if (fdthis != this) | { 5231| bool found = false; 89734| for (size_t i = 0; i < siblingCallers.dim; ++i) | { 39636| if (siblingCallers[i] == fdthis) 1673| found = true; | } 5231| if (!found) | { | //printf("\tadding sibling %s\n", fdthis.toPrettyChars()); 7039| if (!sc.intypeof && !(sc.flags & SCOPE.compile)) 3481| siblingCallers.push(fdthis); | } | } | 5383| const lv = fdthis.getLevelAndCheck(loc, sc, fdv); 5383| if (lv == LevelError) 4| return true; // error 5379| if (lv == -1) 00000000| return false; // downlevel call 5379| if (lv == 0) 24| return false; // same level call | 5355| return false; // Uplevel call | } | 12190| if (checkEnclosing(p.isFuncDeclaration())) 4| return true; 24372| if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration())) 00000000| return true; | } 57929| return false; | } | | /******************************* | * 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. | */ | final bool 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()); | 383700| if (requiresClosure) 2165| goto Lyes; | 791586| for (size_t i = 0; i < closureVars.dim; i++) | { 14258| VarDeclaration v = closureVars[i]; | //printf("\tv = %s\n", v.toChars()); | 71142| for (size_t j = 0; j < v.nestedrefs.dim; j++) | { 21313| FuncDeclaration f = v.nestedrefs[j]; 21313| assert(f != this); | | /* __require and __ensure will always get called directly, | * so they never make outer functions closure. | */ 42265| if (f.ident == Id.require || f.ident == Id.ensure) 602| continue; | | //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, 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. | */ 129629| for (Dsymbol s = f; s && s != this; s = s.toParentP(this)) | { 22501| FuncDeclaration fx = s.isFuncDeclaration(); 22501| if (!fx) 992| continue; 41965| 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 | */ 5314| markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this); | 2657| 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. | */ 21509| if (checkEscapingSiblings(fx, this)) 196| requiresClosure = true; | | /* https://issues.dlang.org/show_bug.cgi?id=12406 | * Iterate all closureVars to mark all descendant | * nested functions that access to the closing context of this function. | */ | } | } | } 381535| if (requiresClosure) 1164| goto Lyes; | 380371| return false; | | Lyes: | //printf("\tneeds closure\n"); 3329| 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. | */ | extern (D) final bool checkClosure() | { 224061| if (!needsClosure()) 222900| return false; | 1161| if (setGC()) | { 6| error("is `@nogc` yet allocates closures with the GC"); 6| if (global.gag) // need not report supplemental errors 00000000| return true; | } | else | { 1155| printGCUsage(loc, "using closure causes GC allocation"); 1155| return false; | } | 12| FuncDeclarations a; 36| foreach (v; closureVars) | { 39| foreach (f; v.nestedrefs) | { 7| assert(f !is this); | | LcheckAncestorsOfANestedRef: 21| for (Dsymbol s = f; s && s !is this; s = s.toParentP(this)) | { 7| auto fx = s.isFuncDeclaration(); 7| if (!fx) 00000000| continue; 7| if (fx.isThis() || 6| fx.tookAddressOf || 00000000| checkEscapingSiblings(fx, this)) | { 24| foreach (f2; a) | { 1| if (f2 == f) 00000000| break LcheckAncestorsOfANestedRef; | } 7| a.push(f); 7| .errorSupplemental(f.loc, "%s closes over variable %s at %s", | f.toPrettyChars(), v.toChars(), v.loc.toChars()); 7| break LcheckAncestorsOfANestedRef; | } | } | } | } | 6| return true; | } | | /*********************************************** | * Determine if function's variables are referenced by a function | * nested within it. | */ | final bool hasNestedFrameRefs() | { 49188| if (closureVars.dim) 29848| 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 | * https://issues.dlang.org/show_bug.cgi?id=7335 will bite. | */ 38279| if (fdrequire || fdensure) 869| return true; | 18623| if (foverrides.dim && isVirtualMethod()) | { 496| for (size_t i = 0; i < foverrides.dim; i++) | { 152| FuncDeclaration fdv = foverrides[i]; 152| if (fdv.hasNestedFrameRefs()) 56| return true; | } | } 18415| return false; | } | | /**************************************************** | * Check whether result variable can be built. | * Returns: | * `true` if the function has a return type that | * is different from `void`. | */ | extern (D) private bool canBuildResultVar() | { 12884| auto f = cast(TypeFunction)type; 38652| return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid; | } | | /**************************************************** | * Declare result variable lazily. | */ | extern (D) final void buildResultVar(Scope* sc, Type tret) | { 2193| if (!vresult) | { 2394| 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.dsymbolSemantic() running, vresult.type might be modified. | */ 1197| vresult = new VarDeclaration(loc, tret, Id.result, null); 1197| vresult.storage_class |= STC.nodtor | STC.temp; 1197| if (!isVirtual()) 891| vresult.storage_class |= STC.const_; 1197| vresult.storage_class |= STC.result; | | // set before the semantic() for checkNestedReference() 1197| vresult.parent = this; | } | 4233| if (sc && vresult.semanticRun == PASS.init) | { 1197| TypeFunction tf = type.toTypeFunction(); 1197| if (tf.isref) 101| vresult.storage_class |= STC.ref_; 1197| vresult.type = tret; | 1197| vresult.dsymbolSemantic(sc); | 1197| if (!sc.insert(vresult)) 00000000| error("out result %s is already defined", vresult.toChars()); 1197| 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. | */ | extern (D) final Statement mergeFrequire(Statement sf, Expressions* params) | { | /* 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. | */ | 675535| foreach (fdv; foverrides) | { | /* 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 | */ 8184| if (fdv.frequires && fdv.semanticRun != PASS.semantic3done) | { 9| assert(fdv._scope); 9| Scope* sc = fdv._scope.push(); 9| sc.stc &= ~STC.override_; 9| fdv.semantic3(sc); 9| sc.pop(); | } | 7934| sf = fdv.mergeFrequire(sf, params); 8188| if (sf && fdv.fdrequire) | { | //printf("fdv.frequire: %s\n", fdv.frequire.toChars()); | /* Make the call: | * try { __require(params); } | * catch (Throwable) { frequire; } | */ 241| params = Expression.arraySyntaxCopy(params); 241| Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params); 241| Statement s2 = new ExpStatement(loc, e); | 241| auto c = new Catch(loc, getThrowable(), null, sf); 241| c.internalCatch = true; 241| auto catches = new Catches(); 241| catches.push(c); 241| sf = new TryCatchStatement(loc, s2, catches); | } | else 7693| return null; | } 214680| return sf; | } | | /**************************************************** | * 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 | */ | static bool needsFensure(FuncDeclaration fd) | { 241939| if (fd.fensures) 1772| return true; | 749972| foreach (fdv; fd.foverrides) | { 9885| if (needsFensure(fdv)) 92| return true; | } 240075| return false; | } | | /**************************************************** | * Rewrite contracts as statements. | */ | final void buildEnsureRequire() | { | 214439| if (frequires) | { | /* in { statements1... } | * in { statements2... } | * ... | * becomes: | * in { { statements1... } { statements2... } ... } | */ 2155| assert(frequires.dim); 2155| auto loc = (*frequires)[0].loc; 2155| auto s = new Statements; 13053| foreach (r; *frequires) | { 2196| s.push(new ScopeStatement(r.loc, r, r.loc)); | } 2155| frequire = new CompoundStatement(loc, s); | } | 214439| if (fensures) | { | /* out(id1) { statements1... } | * out(id2) { statements2... } | * ... | * becomes: | * out(__result) { { ref id1 = __result; { statements1... } } | * { ref id2 = __result; { statements2... } } ... } | */ 1326| assert(fensures.dim); 1326| auto loc = (*fensures)[0].ensure.loc; 1326| auto s = new Statements; 8181| foreach (r; *fensures) | { 2174| if (r.id && canBuildResultVar()) | { 771| auto rloc = r.ensure.loc; 771| auto resultId = new IdentifierExp(rloc, Id.result); 771| auto init = new ExpInitializer(rloc, resultId); 771| auto stc = STC.ref_ | STC.temp | STC.result; 771| auto decl = new VarDeclaration(rloc, null, r.id, init, stc); 771| auto sdecl = new ExpStatement(rloc, decl); 771| s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc)); | } | else | { 630| s.push(r.ensure); | } | } 1326| fensure = new CompoundStatement(loc, s); | } | 214439| if (!isVirtual()) 203262| return; | | /* Rewrite contracts as nested functions, then call them. Doing it as nested | * functions means that overriding functions can call them. | */ 11177| TypeFunction f = cast(TypeFunction) type; | | /* Make a copy of the parameters and make them all ref */ | static Parameters* toRefCopy(ParameterList parameterList) | { 1106| auto result = new Parameters(); | 1106| foreach (n, p; parameterList) | { 920| p = p.syntaxCopy(); 920| if (!(p.storageClass & STC.lazy_)) 896| p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_; 920| p.defaultArg = null; // won't be the same with ref 920| result.push(p); | } | 1106| return result; | } | 11177| if (frequire) | { | /* in { ... } | * becomes: | * void __require(ref params) { ... } | * __require(params); | */ 530| Loc loc = frequire.loc; 530| fdrequireParams = new Expressions(); 530| if (parameters) | { 2976| foreach (vd; *parameters) 510| fdrequireParams.push(new VarExp(loc, vd)); | } 1060| auto fo = cast(TypeFunction)(originalType ? originalType : f); 530| auto fparams = toRefCopy(fo.parameterList); 530| auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d); 530| tf.isnothrow = f.isnothrow; 530| tf.isnogc = f.isnogc; 530| tf.purity = f.purity; 530| tf.trust = f.trust; 530| auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf); 530| fd.fbody = frequire; 530| Statement s1 = new ExpStatement(loc, fd); 530| Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams); 530| Statement s2 = new ExpStatement(loc, e); 530| frequire = new CompoundStatement(loc, s1, s2); 530| fdrequire = fd; | } | | /* We need to set fdensureParams here and not in the block below to | * have the parameters available when calling a base class ensure(), | * even if this function doesn't have an out contract. | */ 11177| fdensureParams = new Expressions(); 11177| if (canBuildResultVar()) 4678| fdensureParams.push(new IdentifierExp(loc, Id.result)); 11177| if (parameters) | { 45834| foreach (vd; *parameters) 8179| fdensureParams.push(new VarExp(loc, vd)); | } | 11177| if (fensure) | { | /* out (result) { ... } | * becomes: | * void __ensure(ref tret result, ref params) { ... } | * __ensure(result, params); | */ 576| Loc loc = fensure.loc; 576| auto fparams = new Parameters(); 576| if (canBuildResultVar()) | { 223| Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null); 223| fparams.push(p); | } 1152| auto fo = cast(TypeFunction)(originalType ? originalType : f); 576| fparams.pushSlice((*toRefCopy(fo.parameterList))[]); 576| auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d); 576| tf.isnothrow = f.isnothrow; 576| tf.isnogc = f.isnogc; 576| tf.purity = f.purity; 576| tf.trust = f.trust; 576| auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf); 576| fd.fbody = fensure; 576| Statement s1 = new ExpStatement(loc, fd); 576| Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams); 576| Statement s2 = new ExpStatement(loc, e); 576| fensure = new CompoundStatement(loc, s1, s2); 576| fdensure = fd; | } | } | | /**************************************************** | * 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. | */ | extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params) | { | /* 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. | */ 691023| foreach (fdv; foverrides) | { | /* 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 | */ 8313| if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done) | { 2| assert(fdv._scope); 2| Scope* sc = fdv._scope.push(); 2| sc.stc &= ~STC.override_; 2| fdv.semantic3(sc); 2| sc.pop(); | } | 7951| sf = fdv.mergeFensure(sf, oid, params); 7951| if (fdv.fdensure) | { | //printf("fdv.fensure: %s\n", fdv.fensure.toChars()); | // Make the call: __ensure(result, params) 358| params = Expression.arraySyntaxCopy(params); 358| if (canBuildResultVar()) | { 187| Type t1 = fdv.type.nextOf().toBasetype(); 187| Type t2 = this.type.nextOf().toBasetype(); 187| if (t1.isBaseOf(t2, null)) | { | /* Making temporary reference variable is necessary | * in covariant return. | * https://issues.dlang.org/show_bug.cgi?id=5204 | * https://issues.dlang.org/show_bug.cgi?id=10479 | */ 16| Expression* eresult = &(*params)[0]; 16| auto ei = new ExpInitializer(Loc.initial, *eresult); 16| auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei); 16| v.storage_class |= STC.temp; 16| auto de = new DeclarationExp(Loc.initial, v); 16| auto ve = new VarExp(Loc.initial, v); 16| *eresult = new CommaExp(Loc.initial, de, ve); | } | } 358| Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params); 358| Statement s2 = new ExpStatement(loc, e); | 358| if (sf) | { 274| sf = new CompoundStatement(sf.loc, s2, sf); | } | else 84| sf = s2; | } | } 222390| return sf; | } | | /********************************************* | * Returns: the function's parameter list, and whether | * it is variadic or not. | */ | final ParameterList getParameterList() | { 301170| if (type) | { 301170| TypeFunction fdtype = type.isTypeFunction(); 301170| return fdtype.parameterList; | } | 00000000| return ParameterList(null, VarArg.none); | } | | /********************************** | * Generate a FuncDeclaration for a runtime library function. | */ | static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0) | { 189| return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc); | } | | static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0) | { 552| FuncDeclaration fd; 552| TypeFunction tf; 552| Dsymbol s; 552| __gshared DsymbolTable st = null; | | //printf("genCfunc(name = '%s')\n", id.toChars()); | //printf("treturn\n\t"); treturn.print(); | | // See if already in table 552| if (!st) 146| st = new DsymbolTable(); 552| s = st.lookup(id); 552| if (s) | { 248| fd = s.isFuncDeclaration(); 248| assert(fd); 248| assert(fd.type.nextOf().equals(treturn)); | } | else | { 304| tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc); 304| fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf); 304| fd.protection = Prot(Prot.Kind.public_); 304| fd.linkage = LINK.c; | 304| st.insert(fd); | } 552| return fd; | } | | /****************** | * Check parameters and return type of D main() function. | * Issue error messages. | */ | extern (D) final void checkDmain() | { 1861| TypeFunction tf = type.toTypeFunction(); 1861| const nparams = tf.parameterList.length; 1861| bool argerr; 1861| if (nparams == 1) | { 132| auto fparam0 = tf.parameterList[0]; 132| auto t = fparam0.type.toBasetype(); 132| if (t.ty != Tarray || 132| t.nextOf().ty != Tarray || 132| t.nextOf().nextOf().ty != Tchar || 132| fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_)) | { 1| argerr = true; | } | } | 1861| if (!tf.nextOf()) 1| error("must return `int` or `void`"); 3307| else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid) 00000000| error("must return `int` or `void`, not `%s`", tf.nextOf().toChars()); 5580| else if (tf.parameterList.varargs || nparams >= 2 || argerr) 1| error("parameters must be `main()` or `main(string[] args)`"); | } | | /*********************************************** | * Check all return statements for a function to verify that returning | * using NRVO is possible. | * | * Returns: | * true if the result cannot be returned by hidden reference. | */ | final bool checkNrvo() | { 7027| if (!nrvo_can) 00000000| return true; | 7027| if (returns is null) 34| return true; | 6993| auto tf = type.toTypeFunction(); 6993| if (tf.isref) 00000000| return true; | 31614| foreach (rs; *returns) | { 7247| if (auto ve = rs.exp.isVarExp()) | { 2322| auto v = ve.var.isVarDeclaration(); 6966| if (!v || v.isOut() || v.isRef()) 00000000| return true; 2322| else if (nrvo_var is null) | { 5668| if (!v.isDataseg() && !v.isParameter() && v.toParent2() == this) | { | //printf("Setting nrvo to %s\n", v.toChars()); 1514| nrvo_var = v; | } | else 564| return true; | } 244| else if (nrvo_var != v) 64| return true; | } | else //if (!exp.isLvalue()) // keep NRVO-ability 4925| return true; | } 1440| return false; | } | | override final inout(FuncDeclaration) isFuncDeclaration() inout | { 54488604| return this; | } | | inout(FuncDeclaration) toAliasFunc() inout | { 32476469| return this; | } | | override void accept(Visitor v) | { 2963655| v.visit(this); | } |} | |/******************************************************** | * Generate Expression to call the invariant. | * Input: | * ad aggregate with the invariant | * vthis variable with 'this' | * Returns: | * void expression that calls the invariant | */ |Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis) |{ 41161| Expression e = null; | // Call invariant directly only if it exists 41161| FuncDeclaration inv = ad.inv; 41161| ClassDeclaration cd = ad.isClassDeclaration(); | 100820| while (!inv && cd) | { 15290| cd = cd.baseClass; 15290| if (!cd) 5484| break; 9806| inv = cd.inv; | } 41161| if (inv) | { | version (all) | { | // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 | // For the correct mangling, | // run attribute inference on inv if needed. 1114| inv.functionSemantic(); | } | | //e = new DsymbolExp(Loc.initial, inv); | //e = new CallExp(Loc.initial, e); | //e = e.semantic(sc2); | | /* https://issues.dlang.org/show_bug.cgi?id=13113 | * Currently virtual invariant calls completely | * bypass attribute enforcement. | * Change the behavior of pre-invariant call by following it. | */ 1114| e = new ThisExp(Loc.initial); 1114| e.type = ad.type.addMod(vthis.type.mod); 1114| e = new DotVarExp(Loc.initial, e, inv, false); 1114| e.type = inv.type; 1114| e = new CallExp(Loc.initial, e); 1114| e.type = Type.tvoid; | } 41161| return e; |} | |/*************************************************** | * Visit each overloaded function/template in turn, and call dg(s) on it. | * Exit when no more, or dg(s) returns nonzero. | * | * Params: | * fstart = symbol to start from | * dg = the delegate to be called on the overload | * sc = context used to check if symbol is accessible (and therefore visible), | * can be null | * | * Returns: | * ==0 continue | * !=0 done (and the return value from the last dg() call) | */ |extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null) |{ 2269610| Dsymbol next; 23458968| for (auto d = fstart; d; d = next) | { | import dmd.access : checkSymbolAccess; 9644991| if (auto od = d.isOverDeclaration()) | { 1064| if (od.hasOverloads) | { | /* The scope is needed here to check whether a function in | an overload set was added by means of a private alias (or a | selective import). If the scope where the alias is created | is imported somewhere, the overload set is visible, but the private | alias is not. | */ 1064| if (sc) | { 863| if (checkSymbolAccess(sc, od)) | { 860| if (int r = overloadApply(od.aliassym, dg, sc)) 00000000| return r; | } | } 201| else if (int r = overloadApply(od.aliassym, dg, sc)) 27| return r; | } | else | { 00000000| if (int r = dg(od.aliassym)) 00000000| return r; | } 1037| next = od.overnext; | } 9643927| else if (auto fa = d.isFuncAliasDeclaration()) | { 102431| if (fa.hasOverloads) | { 102412| if (int r = overloadApply(fa.funcalias, dg, sc)) 81968| return r; | } 19| else if (auto fd = fa.toAliasFunc()) | { 19| if (int r = dg(fd)) 3| return r; | } | else | { 00000000| d.error("is aliased to a function"); 00000000| break; | } 20460| next = fa.overnext; | } 9541496| else if (auto ad = d.isAliasDeclaration()) | { 1581| if (sc) | { 434| if (checkSymbolAccess(sc, ad)) 434| next = ad.toAlias(); | } | else 1147| next = ad.toAlias(); 1581| if (next == ad) 00000000| break; 1581| if (next == fstart) 00000000| break; | } 9539915| else if (auto td = d.isTemplateDeclaration()) | { 2113413| if (int r = dg(td)) 15840| return r; 2097573| next = td.overnext; | } 7426502| else if (auto fd = d.isFuncDeclaration()) | { 7426497| if (int r = dg(fd)) 87274| return r; 7339223| next = fd.overnext; | } | else | { 5| d.error("is aliased to a function"); 5| break; | // BUG: should print error message? | } | } 2084498| return 0; |} | |/** |Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the |mismatching modifiers to `buf`. | |The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e. |lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared". | |Params: | buf = output buffer to write to | lhsMod = modifier on the left-hand side | lhsMod = modifier on the right-hand side | |Returns: | |A tuple with `isMutable` and `isNotShared` set |if the `lhsMod` is missing those modifiers (compared to rhs). |*/ |auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod) |{ | static struct Mismatches | { | bool isNotShared; | bool isMutable; | } | 2730| Mismatches mismatches; | 2730| bool bothMutable = ((lhsMod & rhsMod) == 0); 2730| bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0; 2730| bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_); | 2730| if (lhsMod & MODFlags.shared_) 52| buf.writestring("`shared` "); 2728| else if (sharedMismatch && !(lhsMod & MODFlags.immutable_)) | { 43| buf.writestring("non-shared "); 43| mismatches.isNotShared = true; | } | 5446| if (bothMutable && sharedMismatchOnly) | { | } 2706| else if (lhsMod & MODFlags.immutable_) 100| buf.writestring("`immutable` "); 2606| else if (lhsMod & MODFlags.const_) 249| buf.writestring("`const` "); 2357| else if (lhsMod & MODFlags.wild) 1044| buf.writestring("`inout` "); | else | { 1313| buf.writestring("mutable "); 1313| mismatches.isMutable = true; | } | 2730| return mismatches; |} | |/// |unittest |{ | OutBuffer buf; | auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0); | assert(buf[] == "`shared` "); | assert(!mismatches.isNotShared); | | buf.setsize(0); | mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_); | assert(buf[] == "non-shared "); | assert(mismatches.isNotShared); | | buf.setsize(0); | mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0); | assert(buf[] == "`const` "); | assert(!mismatches.isMutable); | | buf.setsize(0); | mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_); | assert(buf[] == "mutable "); | assert(mismatches.isMutable); |} | |private const(char)* prependSpace(const(char)* str) |{ 233| if (!str || !*str) return ""; | 1| return (" " ~ str.toDString() ~ "\0").ptr; |} | |/// Flag used by $(LREF resolveFuncCall). |enum FuncResolveFlag : ubyte |{ | standard = 0, /// issue error messages, solve the call. | quiet = 1, /// do not issue error message on no match, just return `null`. | overloadOnly = 2, /// only resolve overloads. |} | |/******************************************* | * Given a symbol that could be either a FuncDeclaration or | * a function template, resolve it to a function symbol. | * Params: | * loc = instantiation location | * sc = instantiation scope | * s = instantiation symbol | * tiargs = initial list of template arguments | * tthis = if !NULL, the `this` argument type | * fargs = arguments to function | * flags = see $(LREF FuncResolveFlag). | * Returns: | * if match is found, then function symbol, else null | */ |FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, | Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags) |{ 394671| if (!s) 00000000| return null; // no match | | version (none) | { | printf("resolveFuncCall('%s')\n", s.toChars()); | if (tthis) | printf("\tthis: %s\n", tthis.toChars()); | if (fargs) | { | for (size_t i = 0; i < fargs.dim; i++) | { | Expression arg = (*fargs)[i]; | assert(arg.type); | printf("\t%s: ", arg.toChars()); | arg.type.print(); | } | } | } | 409583| if (tiargs && arrayObjectIsError(tiargs) || 656437| fargs && arrayObjectIsError(cast(Objects*)fargs)) | { 2| return null; | } | 394669| MatchAccumulator m; 394669| functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null); 394668| auto orig_s = s; | 777947| if (m.last > MATCH.nomatch && m.lastf) | { 383279| if (m.count == 1) // exactly one match | { 383210| if (!(flags & FuncResolveFlag.quiet)) 296557| m.lastf.functionSemantic(); 383207| return m.lastf; | } 153| if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis()) | { 22| return m.lastf; | } | } | | /* Failed to find a best match. | * Do nothing or print error. | */ 11436| if (m.last <= MATCH.nomatch) | { | // error was caused on matched function, not on the matching itself, | // so return the function to produce a better diagnostic 11389| if (m.count == 1) 783| return m.lastf; | } | | // We are done at this point, as the rest of this function generate | // a diagnostic on invalid match 10653| if (flags & FuncResolveFlag.quiet) 2622| return null; | 8031| auto fd = s.isFuncDeclaration(); 8031| auto od = s.isOverDeclaration(); 8031| auto td = s.isTemplateDeclaration(); 11293| if (td && td.funcroot) 1| s = fd = td.funcroot; | 16062| OutBuffer tiargsBuf; 8031| arrayObjectsToBuffer(&tiargsBuf, tiargs); | 16062| OutBuffer fargsBuf; 8031| fargsBuf.writeByte('('); 8031| argExpTypesToCBuffer(&fargsBuf, fargs); 8031| fargsBuf.writeByte(')'); 8031| if (tthis) 5106| tthis.modToBuffer(&fargsBuf); | | // The call is ambiguous 8070| if (m.lastf && m.nextf) | { 39| TypeFunction tf1 = m.lastf.type.toTypeFunction(); 39| TypeFunction tf2 = m.nextf.type.toTypeFunction(); 39| const(char)* lastprms = parametersTypeToChars(tf1.parameterList); 39| const(char)* nextprms = parametersTypeToChars(tf2.parameterList); | 39| const(char)* mod1 = prependSpace(MODtoChars(tf1.mod)); 39| const(char)* mod2 = prependSpace(MODtoChars(tf2.mod)); | 39| .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`", | s.parent.toPrettyChars(), s.ident.toChars(), | fargsBuf.peekChars(), | m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1, | m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2); 39| return null; | } | | // no match, generate an error messages 7992| if (!fd) | { | // all of overloads are templates 3246| if (td) | { 3243| .error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`, candidates are:", | td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), | tiargsBuf.peekChars(), fargsBuf.peekChars()); | 3243| printCandidates(loc, td, sc.isDeprecated()); 3243| return null; | } | /* This case happens when several ctors are mixed in an agregate. | A (bad) error message is already generated in overloadApply(). | see https://issues.dlang.org/show_bug.cgi?id=19729 | */ 3| if (!od) 1| return null; | } | 4748| if (od) | { 2| .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`", | od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); 2| return null; | } | | // remove when deprecation period of class allocators and deallocators is over 4748| if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc)) 2| return null; | 4744| bool hasOverloads = fd.overnext !is null; 4744| auto tf = fd.type.toTypeFunction(); 9466| if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch | { 5384| OutBuffer thisBuf, funcBuf; 1346| MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); 1346| auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); 1346| if (hasOverloads) | { 19| .error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:", | fd.ident.toChars(), thisBuf.peekChars()); 19| printCandidates(loc, fd, sc.isDeprecated()); 19| return null; | } | 1327| const(char)* failMessage; 1327| functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); 1327| if (failMessage) | { 1| .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", | fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), | tf.modToChars(), fargsBuf.peekChars()); 1| errorSupplemental(loc, failMessage); 1| return null; | } | 1326| auto fullFdPretty = fd.toPrettyChars(); 1326| .error(loc, "%smethod `%s` is not callable using a %sobject", | funcBuf.peekChars(), fullFdPretty, thisBuf.peekChars()); | 1326| if (mismatches.isNotShared) 26| .errorSupplemental(loc, "Consider adding `shared` to %s", fullFdPretty); 1300| else if (mismatches.isMutable) 230| .errorSupplemental(loc, "Consider adding `const` or `inout` to %s", fullFdPretty); 1326| return null; | } | | //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco); 3398| if (hasOverloads) | { 123| .error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:", | fd.toChars(), fargsBuf.peekChars()); 123| printCandidates(loc, fd, sc.isDeprecated()); 123| return null; | } | 3275| .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", | fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), | tf.modToChars(), fargsBuf.peekChars()); | // re-resolve to check for supplemental message 3275| const(char)* failMessage; 3275| functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); 3275| if (failMessage) 9| errorSupplemental(loc, failMessage); 3275| return null; |} | |/******************************************* | * Prints template and function overload candidates as supplemental errors. | * Params: | * loc = instantiation location | * declaration = the declaration to print overload candidates for | * showDeprecated = If `false`, `deprecated` function won't be shown | */ |private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated) |if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) |{ | // max num of overloads to print (-v overrides this). | enum int DisplayLimit = 5; 3385| int displayed; 3385| const(char)* constraintsTip; | 3385| overloadApply(declaration, (Dsymbol s) | { 5791| Dsymbol nextOverload; | 5791| if (auto fd = s.isFuncDeclaration()) | { | // Don't print overloads which have errors. | // Not that if the whole overload set has errors, we'll never reach | // this point so there's no risk of printing no candidate 607| if (fd.errors || fd.type.ty == Terror) 1| return 0; | // Don't print disabled functions, or `deprecated` outside of deprecated scope 607| if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated)) 6| return 0; | 297| auto tf = cast(TypeFunction) fd.type; 297| .errorSupplemental(fd.loc, "`%s%s`", fd.toPrettyChars(), | parametersTypeToChars(tf.parameterList)); 297| nextOverload = fd.overnext; | } 5487| else if (auto td = s.isTemplateDeclaration()) | { | import dmd.staticcond; | 5487| const tmsg = td.toCharsNoConstraints(); 5487| const cmsg = td.getConstraintEvalError(constraintsTip); 5487| if (cmsg) 1450| .errorSupplemental(td.loc, "`%s`\n%s", tmsg, cmsg); | else 4037| .errorSupplemental(td.loc, "`%s`", tmsg); 5487| nextOverload = td.overnext; | } | 11560| if (global.params.verbose || ++displayed < DisplayLimit) 5767| return 0; | | // Too many overloads to sensibly display. | // Just show count of remaining overloads. 17| int num = 0; 195| overloadApply(nextOverload, (s) { ++num; return 0; }); | 17| if (num > 0) 17| .errorSupplemental(loc, "... (%d more, -v to show) ...", num); 17| return 1; // stop iterating | }); | | // Nothing was displayed, all overloads are either disabled or deprecated 3385| if (!displayed) 2| .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`"); | // should be only in verbose mode 3385| if (constraintsTip) 1| .tip(constraintsTip); |} | |/************************************** | * Returns an indirect type one step from t. | */ |Type getIndirection(Type t) |{ 453| t = t.baseElemOf(); 766| if (t.ty == Tarray || t.ty == Tpointer) 190| return t.nextOf().toBasetype(); 526| if (t.ty == Taarray || t.ty == Tclass) 49| return t; 214| if (t.ty == Tstruct) 428| return t.hasPointers() ? t : null; // TODO | | // should consider TypeDelegate? 00000000| return null; |} | |/************************************** | * Performs type-based alias analysis between a newly created value and a pre- | * existing memory reference: | * | * Assuming that a reference A to a value of type `ta` was available to the code | * that created a reference B to a value of type `tb`, it returns whether B | * might alias memory reachable from A based on the types involved (either | * directly or via any number of indirections in either A or B). | * | * This relation is not symmetric in the two arguments. For example, a | * a `const(int)` reference can point to a pre-existing `int`, but not the other | * way round. | * | * Examples: | * | * ta, tb, result | * `const(int)`, `int`, `false` | * `int`, `const(int)`, `true` | * `int`, `immutable(int)`, `false` | * const(immutable(int)*), immutable(int)*, false // BUG: returns true | * | * Params: | * ta = value type being referred to | * tb = referred to value type that could be constructed from ta | * | * Returns: | * true if reference to `tb` is isolated from reference to `ta` | */ |private bool traverseIndirections(Type ta, Type tb) |{ | //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars()); | | /* Threaded list of aggregate types already examined, | * used to break cycles. | * Cycles in type graphs can only occur with aggregates. | */ | static struct Ctxt | { | Ctxt* prev; | Type type; // an aggregate type | } | | static bool traverse(Type ta, Type tb, Ctxt* ctxt, bool reversePass) | { | //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); 23237786| ta = ta.baseElemOf(); 23237786| tb = tb.baseElemOf(); | | // First, check if the pointed-to types are convertible to each other such | // that they might alias directly. | static bool mayAliasDirect(Type source, Type target) | { 23237786| return | // if source is the same as target or can be const-converted to target | source.constConv(target) != MATCH.nomatch || | // if target is void and source can be const-converted to target 23234990| (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod)); | } | 69713358| if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb)) | { | //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); 2832| return false; | } 23236485| if (ta.nextOf() && ta.nextOf() == tb.nextOf()) | { | //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); 1| return true; | } | 46431226| if (tb.ty == Tclass || tb.ty == Tstruct) | { 86175994| for (Ctxt* c = ctxt; c; c = c.prev) 41024351| if (tb == c.type) 3394417| return true; 2063646| Ctxt c; 2063646| c.prev = ctxt; 2063646| c.type = tb; | | /* Traverse the type of each field of the aggregate | */ 2063646| AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); 57168536| foreach (v; sym.fields) | { 16994432| Type tprmi = v.type.addMod(tb.mod); | //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars()); 16994432| if (!traverse(ta, tprmi, &c, reversePass)) 2849| return false; | } | } 53299142| else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer) | { 6237234| Type tind = tb.nextOf(); 6237234| if (!traverse(ta, tind, ctxt, reversePass)) 1841| return false; | } 11539656| else if (tb.hasPointers()) | { | // BUG: consider the context pointer of delegate types 00000000| return false; | } | | // Still no match, so try breaking up ta if we have not done so yet. 19835846| if (!reversePass) 3091| return traverse(tb, ta, ctxt, true); | 19832755| return true; | } | | // To handle arbitrary levels of indirections in both parameters, we | // recursively descend into aggregate members/levels of indirection in both | // `ta` and `tb` while avoiding cycles. Start with the original types. 3029| const result = traverse(ta, tb, null, false); | //printf(" returns %d\n", result); 3029| return result; |} | |/* For all functions between outerFunc and f, mark them as needing | * a closure. | */ |private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc) |{ 24229| for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc)) | { 3339| FuncDeclaration fy = sx.isFuncDeclaration(); 5544| if (fy && fy.closureVars.dim) | { | /* fy needs a closure if it has closureVars[], | * because the frame pointer in the closure will be accessed. | */ 41| 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. | * 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. | * Params: | * f = inner function (nested within outerFunc) | * outerFunc = outer function | * p = for internal recursion use | * Returns: | * true if any closures were needed | */ |private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null) |{ | static struct PrevSibling | { | PrevSibling* p; | FuncDeclaration f; | } | 28876| PrevSibling ps; 28876| ps.p = cast(PrevSibling*)p; 28876| ps.f = f; | | //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars()); 28876| bool bAnyClosures = false; 72494| for (size_t i = 0; i < f.siblingCallers.dim; ++i) | { 7371| FuncDeclaration g = f.siblingCallers[i]; 14590| if (g.isThis() || g.tookAddressOf) | { 2078| markAsNeedingClosure(g, outerFunc); 2078| bAnyClosures = true; | } | 29388| for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc)) | { | // A parent of the sibling had its address taken. | // Assume escaping of parent affects its children, so needs propagating. | // see https://issues.dlang.org/show_bug.cgi?id=19679 2432| FuncDeclaration parentFunc = parent.isFuncDeclaration; 4700| if (parentFunc && parentFunc.tookAddressOf) | { 5| markAsNeedingClosure(parentFunc, outerFunc); 5| bAnyClosures = true; | } | } | 7371| PrevSibling* prev = cast(PrevSibling*)p; 10635| while (1) | { 10635| if (!prev) | { 7367| bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps); 7367| break; | } 3268| if (prev.f == g) 4| break; 3264| prev = prev.p; | } | } | //printf("\t%d\n", bAnyClosures); 28876| return bAnyClosures; |} | |/*********************************************************** | * Used as a way to import a set of functions from another scope into this one. | */ |extern (C++) final class FuncAliasDeclaration : FuncDeclaration |{ | FuncDeclaration funcalias; | bool hasOverloads; | 1027| extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true) | { 1027| super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type); 1027| assert(funcalias != this); 1027| this.funcalias = funcalias; | 1027| this.hasOverloads = hasOverloads; 1027| if (hasOverloads) | { 281| if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration()) 196| this.hasOverloads = fad.hasOverloads; | } | else | { | // for internal use 746| assert(!funcalias.isFuncAliasDeclaration()); 746| this.hasOverloads = false; | } 1027| userAttribDecl = funcalias.userAttribDecl; | } | | override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout | { 103766| return this; | } | | override const(char)* kind() const | { 1| return "function alias"; | } | | override inout(FuncDeclaration) toAliasFunc() inout | { 3816| return funcalias.toAliasFunc(); | } | | override void accept(Visitor v) | { 10| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class FuncLiteralDeclaration : FuncDeclaration |{ | TOK tok; // TOK.function_ or TOK.delegate_ | Type treq; // target of return type inference | | // backend | bool deferToObj; | 240389| extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null) | { 240389| super(loc, endloc, null, STC.undefined_, type); 480778| this.ident = id ? id : Id.empty; 240389| this.tok = tok; 240389| this.fes = fes; | // Always infer scope for function literals | // See https://issues.dlang.org/show_bug.cgi?id=20362 240389| this.flags |= FUNCFLAG.inferScope; | //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars()); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { | //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); 72129| assert(!s); 72129| auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident); 72129| f.treq = treq; // don't need to copy 72129| return FuncDeclaration.syntaxCopy(f); | } | | override bool isNested() const | { | //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); 574963| return (tok != TOK.function_) && !isThis(); | } | | override inout(AggregateDeclaration) isThis() inout | { 939780| return tok == TOK.delegate_ ? super.isThis() : null; | } | | override bool isVirtual() const | { 162914| return false; | } | | override bool addPreInvariant() | { 35949| return false; | } | | override bool addPostInvariant() | { 71818| 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 modifyReturns(Scope* sc, Type tret) | { | import dmd.statement_rewrite_walker; | | extern (C++) final class RetWalker : StatementRewriteWalker | { | alias visit = typeof(super).visit; | public: | Scope* sc; | Type tret; | FuncLiteralDeclaration fld; | | override void visit(ReturnStatement s) | { 1393| Expression exp = s.exp; 2712| if (exp && !exp.type.equals(tret)) | { 43| s.exp = exp.castTo(sc, tret); | } | } | } | 2221| if (semanticRun < PASS.semantic3done) 00000000| return; | 2221| if (fes) 188| return; | 2033| scope RetWalker w = new RetWalker(); 2033| w.sc = sc; 2033| w.tret = tret; 2033| w.fld = this; 2033| 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. 3902| if (inferRetType && type.nextOf() != tret) 44| type.toTypeFunction().next = tret; | } | | override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout | { 633403| return this; | } | | override const(char)* kind() const | { | // GCC requires the (char*) casts 1394| return (tok != TOK.function_) ? "delegate" : "function"; | } | | override const(char)* toPrettyChars(bool QualifyTypes = false) | { 8514| if (parent) | { 8514| TemplateInstance ti = parent.isTemplateInstance(); 8514| if (ti) 1477| return ti.tempdecl.toPrettyChars(QualifyTypes); | } 7037| return Dsymbol.toPrettyChars(QualifyTypes); | } | | override void accept(Visitor v) | { 247607| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class CtorDeclaration : FuncDeclaration |{ | bool isCpCtor; 62554| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false) | { 62554| super(loc, endloc, Id.ctor, stc, type); 62554| this.isCpCtor = isCpCtor; | //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 4739| assert(!s); 4739| auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy()); 4739| return FuncDeclaration.syntaxCopy(f); | } | | override const(char)* kind() const | { 172| return isCpCtor ? "copy constructor" : "constructor"; | } | | override const(char)* toChars() const | { 6557| return "this"; | } | | override bool isVirtual() const | { 390032| return false; | } | | override bool addPreInvariant() | { 6909| return false; | } | | override bool addPostInvariant() | { 41424| return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on); | } | | override inout(CtorDeclaration) isCtorDeclaration() inout | { 406516| return this; | } | | override void accept(Visitor v) | { 102021| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class PostBlitDeclaration : FuncDeclaration |{ 15090| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id) | { 15090| super(loc, endloc, id, stc, null); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 358| assert(!s); 358| auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident); 358| return FuncDeclaration.syntaxCopy(dd); | } | | override bool isVirtual() const | { 39117| return false; | } | | override bool addPreInvariant() | { 5191| return false; | } | | override bool addPostInvariant() | { 31122| return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on); | } | | override bool overloadInsert(Dsymbol s) | { 00000000| return false; // cannot overload postblits | } | | override inout(PostBlitDeclaration) isPostBlitDeclaration() inout | { 1580| return this; | } | | override void accept(Visitor v) | { 38111| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class DtorDeclaration : FuncDeclaration |{ 00000000| extern (D) this(const ref Loc loc, const ref Loc endloc) | { 00000000| super(loc, endloc, Id.dtor, STC.undefined_, null); | } | 19521| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id) | { 19521| super(loc, endloc, id, stc, null); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 596| assert(!s); 596| auto dd = new DtorDeclaration(loc, endloc, storage_class, ident); 596| return FuncDeclaration.syntaxCopy(dd); | } | | override const(char)* kind() const | { 370| return "destructor"; | } | | override const(char)* toChars() const | { 7157| return "~this"; | } | | override bool isVirtual() const | { | // D dtor's don't get put into the vtbl[] | // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable 74624| return vtblIndex != -1; | } | | override bool addPreInvariant() | { 20832| return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on); | } | | override bool addPostInvariant() | { 13880| return false; | } | | override bool overloadInsert(Dsymbol s) | { 00000000| return false; // cannot overload destructors | } | | override inout(DtorDeclaration) isDtorDeclaration() inout | { 21652| return this; | } | | override void accept(Visitor v) | { 51403| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) class StaticCtorDeclaration : FuncDeclaration |{ 311| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) | { 311| super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null); | } | 354| extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc) | { 354| super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 12| assert(!s); 12| auto scd = new StaticCtorDeclaration(loc, endloc, storage_class); 12| return FuncDeclaration.syntaxCopy(scd); | } | | override final inout(AggregateDeclaration) isThis() inout | { 1733| return null; | } | | override final bool isVirtual() const | { 1933| return false; | } | | override final bool addPreInvariant() | { 242| return false; | } | | override final bool addPostInvariant() | { 484| return false; | } | | override final bool hasStaticCtorOrDtor() | { 00000000| return true; | } | | override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout | { 659| return this; | } | | override void accept(Visitor v) | { 1158| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration |{ 354| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) | { 354| super(loc, endloc, "_sharedStaticCtor", stc); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 11| assert(!s); 11| auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class); 11| return FuncDeclaration.syntaxCopy(scd); | } | | override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout | { 72| return this; | } | | override void accept(Visitor v) | { 750| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) class StaticDtorDeclaration : FuncDeclaration |{ | VarDeclaration vgate; // 'gate' variable | 102| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) | { 102| super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null); | } | 145| extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc) | { 145| super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 8| assert(!s); 8| auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class); 8| return FuncDeclaration.syntaxCopy(sdd); | } | | override final inout(AggregateDeclaration) isThis() inout | { 887| return null; | } | | override final bool isVirtual() const | { 771| return false; | } | | override final bool hasStaticCtorOrDtor() | { 00000000| return true; | } | | override final bool addPreInvariant() | { 135| return false; | } | | override final bool addPostInvariant() | { 270| return false; | } | | override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout | { 114| return this; | } | | override void accept(Visitor v) | { 444| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration |{ 145| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) | { 145| super(loc, endloc, "_sharedStaticDtor", stc); | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 3| assert(!s); 3| auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class); 3| return FuncDeclaration.syntaxCopy(sdd); | } | | override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout | { 96| return this; | } | | override void accept(Visitor v) | { 452| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class InvariantDeclaration : FuncDeclaration |{ 833| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody) | { 1666| super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null); 833| this.fbody = fbody; | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 8| assert(!s); 8| auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null); 8| return FuncDeclaration.syntaxCopy(id); | } | | override bool isVirtual() const | { 4456| return false; | } | | override bool addPreInvariant() | { 632| return false; | } | | override bool addPostInvariant() | { 1604| return false; | } | | override inout(InvariantDeclaration) isInvariantDeclaration() inout | { 348| return this; | } | | override void accept(Visitor v) | { 4131| v.visit(this); | } |} | | |/*********************************************************** | */ |extern (C++) final class UnitTestDeclaration : FuncDeclaration |{ | char* codedoc; // for documented unittest | | // toObjFile() these nested functions after this one | FuncDeclarations deferredNested; | 678318| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc) | { 678318| super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null); 678318| this.codedoc = codedoc; | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 4650| assert(!s); 4650| auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc); 4650| return FuncDeclaration.syntaxCopy(utd); | } | | override inout(AggregateDeclaration) isThis() inout | { 289819| return null; | } | | override bool isVirtual() const | { 68821| return false; | } | | override bool addPreInvariant() | { 906| return false; | } | | override bool addPostInvariant() | { 1812| return false; | } | | override inout(UnitTestDeclaration) isUnitTestDeclaration() inout | { 1875| return this; | } | | override void accept(Visitor v) | { 1236600| v.visit(this); | } |} | |/*********************************************************** | */ |extern (C++) final class NewDeclaration : FuncDeclaration |{ | ParameterList parameterList; | 5| extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, ref ParameterList parameterList) | { 5| super(loc, endloc, Id.classNew, STC.static_ | stc, null); 5| this.parameterList = parameterList; | } | | override Dsymbol syntaxCopy(Dsymbol s) | { 00000000| assert(!s); 00000000| auto parameterList = parameterList.syntaxCopy(); 00000000| auto f = new NewDeclaration(loc, endloc, storage_class, parameterList); 00000000| return FuncDeclaration.syntaxCopy(f); | } | | override const(char)* kind() const | { 2| return "allocator"; | } | | override bool isVirtual() const | { 9| return false; | } | | override bool addPreInvariant() | { 00000000| return false; | } | | override bool addPostInvariant() | { 00000000| return false; | } | | override inout(NewDeclaration) isNewDeclaration() inout | { 2| return this; | } | | override void accept(Visitor v) | { 16| v.visit(this); | } |} src/dmd/func.d is 94% covered <<<<<< EOF # path=./src-dmd-root-rmem.lst |/** | * Allocate memory using `malloc` or the GC depending on the configuration. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: Walter Bright, http://www.digitalmars.com | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d) | * Documentation: https://dlang.org/phobos/dmd_root_rmem.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/rmem.d | */ | |module dmd.root.rmem; | |import core.exception : onOutOfMemoryError; |import core.stdc.stdio; |import core.stdc.stdlib; |import core.stdc.string; | |version = GC; | |version (GC) |{ | import core.memory : GC; | | enum isGCAvailable = true; |} |else | enum isGCAvailable = false; | |extern (C++) struct Mem |{ | static char* xstrdup(const(char)* s) nothrow | { | version (GC) 95047| if (isGCEnabled) 964| return s ? s[0 .. strlen(s) + 1].dup.ptr : null; | 189130| return s ? cast(char*)check(.strdup(s)) : null; | } | | static void xfree(void* p) pure nothrow | { | version (GC) 31109523| if (isGCEnabled) 9633624| return GC.free(p); | 26292711| pureFree(p); | } | | static void* xmalloc(size_t size) pure nothrow | { | version (GC) 56708253| if (isGCEnabled) 8948330| return size ? GC.malloc(size) : null; | 104468176| return size ? check(pureMalloc(size)) : null; | } | | static void* xmalloc_noscan(size_t size) pure nothrow | { | version (GC) 4933356| if (isGCEnabled) 155048| return size ? GC.malloc(size, GC.BlkAttr.NO_SCAN) : null; | 9711664| return size ? check(pureMalloc(size)) : null; | } | | static void* xcalloc(size_t size, size_t n) pure nothrow | { | version (GC) 744735| if (isGCEnabled) 16490| return size * n ? GC.calloc(size * n) : null; | 2208719| return (size && n) ? check(pureCalloc(size, n)) : null; | } | | static void* xcalloc_noscan(size_t size, size_t n) pure nothrow | { | version (GC) 6| if (isGCEnabled) 000000000| return size * n ? GC.calloc(size * n, GC.BlkAttr.NO_SCAN) : null; | 18| return (size && n) ? check(pureCalloc(size, n)) : null; | } | | static void* xrealloc(void* p, size_t size) pure nothrow | { | version (GC) 203096| if (isGCEnabled) 2110| return GC.realloc(p, size); | 200986| if (!size) | { 000000000| pureFree(p); 000000000| return null; | } | 200986| return check(pureRealloc(p, size)); | } | | static void* xrealloc_noscan(void* p, size_t size) pure nothrow | { | version (GC) 95975| if (isGCEnabled) 661| return GC.realloc(p, size, GC.BlkAttr.NO_SCAN); | 95314| if (!size) | { 000000000| pureFree(p); 000000000| return null; | } | 95314| return check(pureRealloc(p, size)); | } | | static void* error() pure nothrow @nogc | { 000000000| onOutOfMemoryError(); 000000000| assert(0); | } | | /** | * Check p for null. If it is, issue out of memory error | * and exit program. | * Params: | * p = pointer to check for null | * Returns: | * p if not null | */ | static void* check(void* p) pure nothrow @nogc | { 117099914| return p ? p : error(); | } | | version (GC) | { | __gshared bool _isGCEnabled = true; | | // fake purity by making global variable immutable (_isGCEnabled only modified before startup) | enum _pIsGCEnabled = cast(immutable bool*) &_isGCEnabled; | | static bool isGCEnabled() pure nothrow @nogc @safe | { 469527360| return *_pIsGCEnabled; | } | | static void disableGC() nothrow @nogc | { 3611| _isGCEnabled = false; | } | | static void addRange(const(void)* p, size_t size) nothrow @nogc | { 000000000| if (isGCEnabled) 000000000| GC.addRange(p, size); | } | | static void removeRange(const(void)* p) nothrow @nogc | { 000000000| if (isGCEnabled) 000000000| GC.removeRange(p); | } | } |} | |extern (C++) const __gshared Mem mem; | |enum CHUNK_SIZE = (256 * 4096 - 64); | |__gshared size_t heapleft = 0; |__gshared void* heapp; | |extern (D) void* allocmemoryNoFree(size_t m_size) nothrow @nogc |{ | // 16 byte alignment is better (and sometimes needed) for doubles 234839071| m_size = (m_size + 15) & ~15; | | // The layout of the code is selected so the most common case is straight through 234839071| if (m_size <= heapleft) | { | L1: 234839071| heapleft -= m_size; 234839071| auto p = heapp; 234839071| heapp = cast(void*)(cast(char*)heapp + m_size); 234839071| return p; | } | 23637| if (m_size > CHUNK_SIZE) | { 000000000| return Mem.check(malloc(m_size)); | } | 23637| heapleft = CHUNK_SIZE; 23637| heapp = Mem.check(malloc(CHUNK_SIZE)); 23637| goto L1; |} | |extern (D) void* allocmemory(size_t m_size) nothrow |{ | version (GC) 33144275| if (mem.isGCEnabled) 16820651| return GC.malloc(m_size); | 16323624| return allocmemoryNoFree(m_size); |} | |version (DigitalMars) |{ | enum OVERRIDE_MEMALLOC = true; |} |else version (LDC) |{ | // Memory allocation functions gained weak linkage when the @weak attribute was introduced. | import ldc.attributes; | enum OVERRIDE_MEMALLOC = is(typeof(ldc.attributes.weak)); |} |else version (GNU) |{ | version (IN_GCC) | enum OVERRIDE_MEMALLOC = false; | else | enum OVERRIDE_MEMALLOC = true; |} |else |{ | enum OVERRIDE_MEMALLOC = false; |} | |static if (OVERRIDE_MEMALLOC) |{ | // Override the host druntime allocation functions in order to use the bump- | // pointer allocation scheme (`allocmemoryNoFree()` above) if the GC is disabled. | // That scheme is faster and comes with less memory overhead than using a | // disabled GC alone. | | extern (C) void* _d_allocmemory(size_t m_size) nothrow | { 175576| return allocmemory(m_size); | } | | version (GC) | { | private void* allocClass(const ClassInfo ci) nothrow pure | { | alias BlkAttr = GC.BlkAttr; | 10147981| assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass)); | 10147981| BlkAttr attr = BlkAttr.NONE; 10147981| if (ci.m_flags & TypeInfo_Class.ClassFlags.hasDtor 1885956| && !(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass)) 000000000| attr |= BlkAttr.FINALIZE; 10147981| if (ci.m_flags & TypeInfo_Class.ClassFlags.noPointers) 10| attr |= BlkAttr.NO_SCAN; 10147981| return GC.malloc(ci.initializer.length, attr, ci); | } | | extern (C) void* _d_newitemU(const TypeInfo ti) nothrow; | } | | extern (C) Object _d_newclass(const ClassInfo ci) nothrow | { 174718709| const initializer = ci.initializer; | | version (GC) 349437418| auto p = mem.isGCEnabled ? allocClass(ci) : allocmemoryNoFree(initializer.length); | else | auto p = allocmemoryNoFree(initializer.length); | 174718709| memcpy(p, initializer.ptr, initializer.length); 174718709| return cast(Object) p; | } | | version (LDC) | { | extern (C) Object _d_allocclass(const ClassInfo ci) nothrow | { | version (GC) | if (mem.isGCEnabled) | return cast(Object) allocClass(ci); | | return cast(Object) allocmemoryNoFree(ci.initializer.length); | } | } | | extern (C) void* _d_newitemT(TypeInfo ti) nothrow | { | version (GC) 89029308| auto p = mem.isGCEnabled ? _d_newitemU(ti) : allocmemoryNoFree(ti.tsize); | else | auto p = allocmemoryNoFree(ti.tsize); | 44514654| memset(p, 0, ti.tsize); 44514654| return p; | } | | extern (C) void* _d_newitemiT(TypeInfo ti) nothrow | { | version (GC) 24453576| auto p = mem.isGCEnabled ? _d_newitemU(ti) : allocmemoryNoFree(ti.tsize); | else | auto p = allocmemoryNoFree(ti.tsize); | 12226788| const initializer = ti.initializer; 12226788| memcpy(p, initializer.ptr, initializer.length); 12226788| return p; | } | | // TypeInfo.initializer for compilers older than 2.070 | static if(!__traits(hasMember, TypeInfo, "initializer")) | private const(void[]) initializer(T : TypeInfo)(const T t) | nothrow pure @safe @nogc | { | return t.init; | } |} | |extern (C) pure @nogc nothrow |{ | /** | * Pure variants of C's memory allocation functions `malloc`, `calloc`, and | * `realloc` and deallocation function `free`. | * | * UNIX 98 requires that errno be set to ENOMEM upon failure. | * https://linux.die.net/man/3/malloc | * However, this is irrelevant for DMD's purposes, and best practice | * protocol for using errno is to treat it as an `out` parameter, and not | * something with state that can be relied on across function calls. | * So, we'll ignore it. | * | * See_Also: | * $(LINK2 https://dlang.org/spec/function.html#pure-functions, D's rules for purity), | * which allow for memory allocation under specific circumstances. | */ | pragma(mangle, "malloc") void* pureMalloc(size_t size) @trusted; | | /// ditto | pragma(mangle, "calloc") void* pureCalloc(size_t nmemb, size_t size) @trusted; | | /// ditto | pragma(mangle, "realloc") void* pureRealloc(void* ptr, size_t size) @system; | | /// ditto | pragma(mangle, "free") void pureFree(void* ptr) @system; | |} | |/** |Makes a null-terminated copy of the given string on newly allocated memory. |The null-terminator won't be part of the returned string slice. It will be |at position `n` where `n` is the length of the input string. | |Params: | s = string to copy | |Returns: A null-terminated copy of the input array. |*/ |extern (D) char[] xarraydup(const(char)[] s) pure nothrow |{ 269253| if (!s) 000000000| return null; | 269253| auto p = cast(char*)mem.xmalloc_noscan(s.length + 1); 269253| char[] a = p[0 .. s.length]; 269253| a[] = s[0 .. s.length]; 269253| p[s.length] = 0; // preserve 0 terminator semantics 269253| return a; |} | |/// |pure nothrow unittest |{ | auto s1 = "foo"; | auto s2 = s1.xarraydup; | s2[0] = 'b'; | assert(s1 == "foo"); | assert(s2 == "boo"); | assert(*(s2.ptr + s2.length) == '\0'); | string sEmpty; | assert(sEmpty.xarraydup is null); |} | |/** |Makes a copy of the given array on newly allocated memory. | |Params: | s = array to copy | |Returns: A copy of the input array. |*/ |extern (D) T[] arraydup(T)(const scope T[] s) pure nothrow |{ | if (!s) | return null; | | const dim = s.length; | auto p = (cast(T*)mem.xmalloc(T.sizeof * dim))[0 .. dim]; | p[] = s; | return p; |} | |/// |pure nothrow unittest |{ | auto s1 = [0, 1, 2]; | auto s2 = s1.arraydup; | s2[0] = 4; | assert(s1 == [0, 1, 2]); | assert(s2 == [4, 1, 2]); | string sEmpty; | assert(sEmpty.arraydup is null); |} | |// Define this to have Pool emit traces of objects allocated and disposed |//debug = Pool; |// Define this in addition to Pool to emit per-call traces (otherwise summaries are printed at the end). |//debug = PoolVerbose; | |/** |Defines a pool for class objects. Objects can be fetched from the pool with make() and returned to the pool with |dispose(). Using a reference that has been dispose()d has undefined behavior. make() may return memory that has been |previously dispose()d. | |Currently the pool has effect only if the GC is NOT used (i.e. either `version(GC)` or `mem.isGCEnabled` is false). |Otherwise `make` just forwards to `new` and `dispose` does nothing. | |Internally the implementation uses a singly-linked freelist with a global root. The "next" pointer is stored in the |first word of each disposed object. |*/ |struct Pool(T) |if (is(T == class)) |{ | /// The freelist's root | private static T root; | | private static void trace(string fun, string f, uint l)() | { | debug(Pool) | { | debug(PoolVerbose) | { | fprintf(stderr, "%.*s(%u): bytes: %lu Pool!(%.*s)."~fun~"()\n", | cast(int) f.length, f.ptr, l, T.classinfo.initializer.length, | cast(int) T.stringof.length, T.stringof.ptr); | } | else | { | static ulong calls; | if (calls == 0) | { | // Plant summary printer | static extern(C) void summarize() | { | fprintf(stderr, "%.*s(%u): bytes: %lu calls: %lu Pool!(%.*s)."~fun~"()\n", | cast(int) f.length, f.ptr, l, ((T.classinfo.initializer.length + 15) & ~15) * calls, | calls, cast(int) T.stringof.length, T.stringof.ptr); | } | atexit(&summarize); | } | ++calls; | } | } | } | | /** | Returns a reference to a new object in the same state as if created with new T(args). | */ | static T make(string f = __FILE__, uint l = __LINE__, A...)(auto ref A args) | { | if (!root) | { | trace!("makeNew", f, l)(); | return new T(args); | } | else | { | trace!("makeReuse", f, l)(); | auto result = root; | root = *(cast(T*) root); | memcpy(cast(void*) result, T.classinfo.initializer.ptr, T.classinfo.initializer.length); | result.__ctor(args); | return result; | } | } | | /** | Signals to the pool that this object is no longer used, so it can recycle its memory. | */ | static void dispose(string f = __FILE__, uint l = __LINE__, A...)(T goner) | { | version(GC) | { | if (mem.isGCEnabled) return; | } | trace!("dispose", f, l)(); | debug | { | // Stomp the memory so as to maximize the chance of quick failure if used after dispose(). | auto p = cast(ulong*) goner; | p[0 .. T.classinfo.initializer.length / ulong.sizeof] = 0xdeadbeef; | } | *(cast(T*) goner) = root; | root = goner; | } |} src/dmd/root/rmem.d is 82% covered <<<<<< EOF # path=./src-dmd-vsoptions.lst |/** | * When compiling on Windows with the Microsoft toolchain, try to detect the Visual Studio setup. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/link.d, _vsoptions.d) | * Documentation: https://dlang.org/phobos/dmd_vsoptions.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/vsoptions.d | */ | |module dmd.vsoptions; | |version (Windows): |import core.stdc.ctype; |import core.stdc.stdlib; |import core.stdc.string; |import core.stdc.wchar_; |import core.sys.windows.winbase; |import core.sys.windows.windef; |import core.sys.windows.winreg; | |import dmd.env; |import dmd.root.file; |import dmd.root.filename; |import dmd.root.outbuffer; |import dmd.root.rmem; |import dmd.root.string : toDString; | |private immutable supportedPre2017Versions = ["14.0", "12.0", "11.0", "10.0", "9.0"]; | |extern(C++) struct VSOptions |{ | // evaluated once at startup, reflecting the result of vcvarsall.bat | // from the current environment or the latest Visual Studio installation | const(char)* WindowsSdkDir; | const(char)* WindowsSdkVersion; | const(char)* UCRTSdkDir; | const(char)* UCRTVersion; | const(char)* VSInstallDir; | const(char)* VCInstallDir; | const(char)* VCToolsInstallDir; // used by VS 2017+ | | /** | * fill member variables from environment or registry | */ | void initialize() | { | detectWindowsSDK(); | detectUCRT(); | detectVSInstallDir(); | detectVCInstallDir(); | detectVCToolsInstallDir(); | } | | /** | * retrieve the name of the default C runtime library | * Params: | * x64 = target architecture (x86 if false) | * Returns: | * name of the default C runtime library | */ | const(char)* defaultRuntimeLibrary(bool x64) | { | if (VCInstallDir is null) | { | detectVCInstallDir(); | detectVCToolsInstallDir(); | } | if (getVCLibDir(x64)) | return "libcmt"; | else | return "msvcrt120"; // mingw replacement | } | | /** | * retrieve options to be passed to the Microsoft linker | * Params: | * x64 = target architecture (x86 if false) | * Returns: | * allocated string of options to add to the linker command line | */ | const(char)* linkOptions(bool x64) | { | OutBuffer cmdbuf; | if (auto vclibdir = getVCLibDir(x64)) | { | cmdbuf.writestring(" /LIBPATH:\""); | cmdbuf.writestring(vclibdir); | cmdbuf.writeByte('\"'); | | if (FileName.exists(FileName.combine(vclibdir, "legacy_stdio_definitions.lib"))) | { | // VS2015 or later use UCRT | cmdbuf.writestring(" legacy_stdio_definitions.lib"); | if (auto p = getUCRTLibPath(x64)) | { | cmdbuf.writestring(" /LIBPATH:\""); | cmdbuf.writestring(p); | cmdbuf.writeByte('\"'); | } | } | } | if (auto p = getSDKLibPath(x64)) | { | cmdbuf.writestring(" /LIBPATH:\""); | cmdbuf.writestring(p); | cmdbuf.writeByte('\"'); | } | if (auto p = getenv("DXSDK_DIR"w)) | { | // support for old DX SDK installations | cmdbuf.writestring(" /LIBPATH:\""); | cmdbuf.writestring(p); | cmdbuf.writestring(x64 ? `\Lib\x64"` : `\Lib\x86"`); | mem.xfree(p); | } | return cmdbuf.extractChars(); | } | | /** | * retrieve path to the Microsoft linker executable | * also modifies PATH environment variable if necessary to find conditionally loaded DLLs | * Params: | * x64 = target architecture (x86 if false) | * Returns: | * absolute path to link.exe, just "link.exe" if not found | */ | const(char)* linkerPath(bool x64) | { | const(char)* addpath; | if (auto p = getVCBinDir(x64, addpath)) | { | OutBuffer cmdbuf; | cmdbuf.writestring(p); | cmdbuf.writestring(r"\link.exe"); | if (addpath) | { | // debug info needs DLLs from $(VSInstallDir)\Common7\IDE for most linker versions | // so prepend it too the PATH environment variable | char* path = getenv("PATH"w); | const pathlen = strlen(path); | const addpathlen = strlen(addpath); | | const length = addpathlen + 1 + pathlen; | char* npath = cast(char*)mem.xmalloc(length); | memcpy(npath, addpath, addpathlen); | npath[addpathlen] = ';'; | memcpy(npath + addpathlen + 1, path, pathlen); | if (putenvRestorable("PATH", npath[0 .. length])) | assert(0); | mem.xfree(npath); | mem.xfree(path); | } | return cmdbuf.extractChars(); | } | | // try lld-link.exe alongside dmd.exe | char[MAX_PATH + 1] dmdpath = void; | const len = GetModuleFileNameA(null, dmdpath.ptr, dmdpath.length); | if (len <= MAX_PATH) | { | auto lldpath = FileName.replaceName(dmdpath[0 .. len], "lld-link.exe"); | if (FileName.exists(lldpath)) | return lldpath.ptr; | } | | // search PATH to avoid createProcess preferring "link.exe" from the dmd folder | if (auto p = FileName.searchPath(getenv("PATH"w), "link.exe"[], false)) | return p.ptr; | return "link.exe"; | } | |private: | /** | * detect WindowsSdkDir and WindowsSDKVersion from environment or registry | */ | void detectWindowsSDK() | { | if (WindowsSdkDir is null) | WindowsSdkDir = getenv("WindowsSdkDir"w); | | if (WindowsSdkDir is null) | { | WindowsSdkDir = GetRegistryString(r"Microsoft\Windows Kits\Installed Roots", "KitsRoot10"w); | if (WindowsSdkDir && !findLatestSDKDir(FileName.combine(WindowsSdkDir, "Include"), r"um\windows.h")) | WindowsSdkDir = null; | } | if (WindowsSdkDir is null) | { | WindowsSdkDir = GetRegistryString(r"Microsoft\Microsoft SDKs\Windows\v8.1", "InstallationFolder"w); | if (WindowsSdkDir && !FileName.exists(FileName.combine(WindowsSdkDir, "Lib"))) | WindowsSdkDir = null; | } | if (WindowsSdkDir is null) | { | WindowsSdkDir = GetRegistryString(r"Microsoft\Microsoft SDKs\Windows\v8.0", "InstallationFolder"w); | if (WindowsSdkDir && !FileName.exists(FileName.combine(WindowsSdkDir, "Lib"))) | WindowsSdkDir = null; | } | if (WindowsSdkDir is null) | { | WindowsSdkDir = GetRegistryString(r"Microsoft\Microsoft SDKs\Windows", "CurrentInstallationFolder"w); | if (WindowsSdkDir && !FileName.exists(FileName.combine(WindowsSdkDir, "Lib"))) | WindowsSdkDir = null; | } | | if (WindowsSdkVersion is null) | WindowsSdkVersion = getenv("WindowsSdkVersion"w); | | if (WindowsSdkVersion is null && WindowsSdkDir !is null) | { | const(char)* rootsDir = FileName.combine(WindowsSdkDir, "Include"); | WindowsSdkVersion = findLatestSDKDir(rootsDir, r"um\windows.h"); | } | } | | /** | * detect UCRTSdkDir and UCRTVersion from environment or registry | */ | void detectUCRT() | { | if (UCRTSdkDir is null) | UCRTSdkDir = getenv("UniversalCRTSdkDir"w); | | if (UCRTSdkDir is null) | UCRTSdkDir = GetRegistryString(r"Microsoft\Windows Kits\Installed Roots", "KitsRoot10"w); | | if (UCRTVersion is null) | UCRTVersion = getenv("UCRTVersion"w); | | if (UCRTVersion is null && UCRTSdkDir !is null) | { | const(char)* rootsDir = FileName.combine(UCRTSdkDir, "Lib"); | UCRTVersion = findLatestSDKDir(rootsDir, r"ucrt\x86\libucrt.lib"); | } | } | | /** | * detect VSInstallDir from environment or registry | */ | void detectVSInstallDir() | { | if (VSInstallDir is null) | VSInstallDir = getenv("VSINSTALLDIR"w); | | if (VSInstallDir is null) | VSInstallDir = detectVSInstallDirViaCOM(); | | if (VSInstallDir is null) | VSInstallDir = GetRegistryString(r"Microsoft\VisualStudio\SxS\VS7", "15.0"w); // VS2017 | | if (VSInstallDir is null) | { | wchar[260] buffer = void; | // VS Build Tools 2017 (default installation path) | const numWritten = ExpandEnvironmentStringsW(r"%ProgramFiles(x86)%\Microsoft Visual Studio\2017\BuildTools"w.ptr, buffer.ptr, buffer.length); | if (numWritten <= buffer.length && exists(buffer.ptr)) | VSInstallDir = toNarrowStringz(buffer[0 .. numWritten - 1]).ptr; | } | | if (VSInstallDir is null) | foreach (ver; supportedPre2017Versions) | { | VSInstallDir = GetRegistryString(FileName.combine(r"Microsoft\VisualStudio", ver), "InstallDir"w); | if (VSInstallDir) | break; | } | } | | /** | * detect VCInstallDir from environment or registry | */ | void detectVCInstallDir() | { | if (VCInstallDir is null) | VCInstallDir = getenv("VCINSTALLDIR"w); | | if (VCInstallDir is null) | if (VSInstallDir && FileName.exists(FileName.combine(VSInstallDir, "VC"))) | VCInstallDir = FileName.combine(VSInstallDir, "VC"); | | // detect from registry (build tools?) | if (VCInstallDir is null) | foreach (ver; supportedPre2017Versions) | { | auto regPath = FileName.buildPath(r"Microsoft\VisualStudio", ver, r"Setup\VC"); | VCInstallDir = GetRegistryString(regPath, "ProductDir"w); | FileName.free(regPath.ptr); | if (VCInstallDir) | break; | } | } | | /** | * detect VCToolsInstallDir from environment or registry (only used by VC 2017) | */ | void detectVCToolsInstallDir() | { | if (VCToolsInstallDir is null) | VCToolsInstallDir = getenv("VCTOOLSINSTALLDIR"w); | | if (VCToolsInstallDir is null && VCInstallDir) | { | const(char)* defverFile = FileName.combine(VCInstallDir, r"Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"); | if (!FileName.exists(defverFile)) // file renamed with VS2019 Preview 2 | defverFile = FileName.combine(VCInstallDir, r"Auxiliary\Build\Microsoft.VCToolsVersion.v142.default.txt"); | if (FileName.exists(defverFile)) | { | // VS 2017 | auto readResult = File.read(defverFile); // adds sentinel 0 at end of file | if (readResult.success) | { | auto ver = cast(char*)readResult.buffer.data.ptr; | // trim version number | while (*ver && isspace(*ver)) | ver++; | auto p = ver; | while (*p == '.' || (*p >= '0' && *p <= '9')) | p++; | *p = 0; | | if (ver && *ver) | VCToolsInstallDir = FileName.buildPath(VCInstallDir.toDString, r"Tools\MSVC", ver.toDString).ptr; | } | } | } | } | |public: | /** | * get Visual C bin folder | * Params: | * x64 = target architecture (x86 if false) | * addpath = [out] path that needs to be added to the PATH environment variable | * Returns: | * folder containing the VC executables | * | * Selects the binary path according to the host and target OS, but verifies | * that link.exe exists in that folder and falls back to 32-bit host/target if | * missing | * Note: differences for the linker binaries are small, they all | * allow cross compilation | */ | const(char)* getVCBinDir(bool x64, out const(char)* addpath) const | { | alias linkExists = returnDirIfContainsFile!"link.exe"; | | const bool isHost64 = isWin64Host(); | if (VCToolsInstallDir !is null) | { | const vcToolsInstallDir = VCToolsInstallDir.toDString; | if (isHost64) | { | if (x64) | { | if (auto p = linkExists(vcToolsInstallDir, r"bin\HostX64\x64")) | return p; | // in case of missing linker, prefer other host binaries over other target architecture | } | else | { | if (auto p = linkExists(vcToolsInstallDir, r"bin\HostX64\x86")) | { | addpath = FileName.combine(vcToolsInstallDir, r"bin\HostX64\x64").ptr; | return p; | } | } | } | if (x64) | { | if (auto p = linkExists(vcToolsInstallDir, r"bin\HostX86\x64")) | { | addpath = FileName.combine(vcToolsInstallDir, r"bin\HostX86\x86").ptr; | return p; | } | } | if (auto p = linkExists(vcToolsInstallDir, r"bin\HostX86\x86")) | return p; | } | if (VCInstallDir !is null) | { | const vcInstallDir = VCInstallDir.toDString; | if (isHost64) | { | if (x64) | { | if (auto p = linkExists(vcInstallDir, r"bin\amd64")) | return p; | // in case of missing linker, prefer other host binaries over other target architecture | } | else | { | if (auto p = linkExists(vcInstallDir, r"bin\amd64_x86")) | { | addpath = FileName.combine(vcInstallDir, r"bin\amd64").ptr; | return p; | } | } | } | | if (VSInstallDir) | addpath = FileName.combine(VSInstallDir.toDString, r"Common7\IDE").ptr; | else | addpath = FileName.combine(vcInstallDir, r"bin").ptr; | | if (x64) | if (auto p = linkExists(vcInstallDir, r"x86_amd64")) | return p; | | if (auto p = linkExists(vcInstallDir, r"bin\HostX86\x86")) | return p; | } | return null; | } | | /** | * get Visual C Library folder | * Params: | * x64 = target architecture (x86 if false) | * Returns: | * folder containing the the VC runtime libraries | */ | const(char)* getVCLibDir(bool x64) const | { | if (VCToolsInstallDir !is null) | return FileName.combine(VCToolsInstallDir, x64 ? r"lib\x64" : r"lib\x86"); | if (VCInstallDir !is null) | return FileName.combine(VCInstallDir, x64 ? r"lib\amd64" : "lib"); | return null; | } | | /** | * get the path to the universal CRT libraries | * Params: | * x64 = target architecture (x86 if false) | * Returns: | * folder containing the universal CRT libraries | */ | const(char)* getUCRTLibPath(bool x64) const | { | if (UCRTSdkDir && UCRTVersion) | return FileName.buildPath(UCRTSdkDir.toDString, "Lib", UCRTVersion.toDString, x64 ? r"ucrt\x64" : r"ucrt\x86").ptr; | return null; | } | | /** | * get the path to the Windows SDK CRT libraries | * Params: | * x64 = target architecture (x86 if false) | * Returns: | * folder containing the Windows SDK libraries | */ | const(char)* getSDKLibPath(bool x64) const | { | if (WindowsSdkDir) | { | alias kernel32Exists = returnDirIfContainsFile!"kernel32.lib"; | | const arch = x64 ? "x64" : "x86"; | const sdk = FileName.combine(WindowsSdkDir.toDString, "lib"); | if (WindowsSdkVersion) | { | if (auto p = kernel32Exists(sdk, WindowsSdkVersion.toDString, "um", arch)) // SDK 10.0 | return p; | } | if (auto p = kernel32Exists(sdk, r"win8\um", arch)) // SDK 8.0 | return p; | if (auto p = kernel32Exists(sdk, r"winv6.3\um", arch)) // SDK 8.1 | return p; | if (x64) | { | if (auto p = kernel32Exists(sdk, arch)) // SDK 7.1 or earlier | return p; | } | else | { | if (auto p = kernel32Exists(sdk)) // SDK 7.1 or earlier | return p; | } | } | | // try mingw fallback relative to phobos library folder that's part of LIB | if (auto p = FileName.searchPath(getenv("LIB"w), r"mingw\kernel32.lib"[], false)) | return FileName.path(p).ptr; | | return null; | } | |private: |extern(D): | | // iterate through subdirectories named by SDK version in baseDir and return the | // one with the largest version that also contains the test file | static const(char)* findLatestSDKDir(const(char)* baseDir, string testfile) | { | const(char)* pattern = FileName.combine(baseDir, "*"); | wchar* wpattern = toWStringz(pattern.toDString).ptr; | scope(exit) mem.xfree(wpattern); | FileName.free(pattern); | | WIN32_FIND_DATAW fileinfo; | HANDLE h = FindFirstFileW(wpattern, &fileinfo); | if (h == INVALID_HANDLE_VALUE) | return null; | | const dBaseDir = baseDir.toDString; | | char* res; | do | { | if (fileinfo.cFileName[0] >= '1' && fileinfo.cFileName[0] <= '9') | { | char[] name = toNarrowStringz(fileinfo.cFileName.ptr.toDString); | // FIXME: proper version strings comparison | if ((!res || strcmp(res, name.ptr) < 0) && | FileName.exists(FileName.buildPath(dBaseDir, name, testfile))) | { | if (res) | mem.xfree(res); | res = name.ptr; | } | else | mem.xfree(name.ptr); | } | } | while(FindNextFileW(h, &fileinfo)); | | if (!FindClose(h)) | res = null; | return res; | } | | pragma(lib, "advapi32.lib"); | | /** | * read a string from the 32-bit registry | * Params: | * softwareKeyPath = path below HKLM\SOFTWARE | * valueName = name of the value to read | * Returns: | * the registry value if it exists and has string type | */ | const(char)* GetRegistryString(const(char)[] softwareKeyPath, wstring valueName) const | { | enum x64hive = false; // VS registry entries always in 32-bit hive | | version(Win64) | enum prefix = x64hive ? r"SOFTWARE\" : r"SOFTWARE\WOW6432Node\"; | else | enum prefix = r"SOFTWARE\"; | | char[260] regPath = void; | assert(prefix.length + softwareKeyPath.length < regPath.length); | | regPath[0 .. prefix.length] = prefix; | regPath[prefix.length .. prefix.length + softwareKeyPath.length] = softwareKeyPath; | regPath[prefix.length + softwareKeyPath.length] = 0; | | enum KEY_WOW64_64KEY = 0x000100; // not defined in core.sys.windows.winnt due to restrictive version | enum KEY_WOW64_32KEY = 0x000200; | HKEY key; | LONG lRes = RegOpenKeyExA(HKEY_LOCAL_MACHINE, regPath.ptr, (x64hive ? KEY_WOW64_64KEY : KEY_WOW64_32KEY), KEY_READ, &key); | if (FAILED(lRes)) | return null; | scope(exit) RegCloseKey(key); | | wchar[260] buf = void; | DWORD size = buf.sizeof; | DWORD type; | int hr = RegQueryValueExW(key, valueName.ptr, null, &type, cast(ubyte*) buf.ptr, &size); | if (type != REG_SZ || size == 0) | return null; | | wchar* wideValue = buf.ptr; | scope(exit) wideValue != buf.ptr && mem.xfree(wideValue); | if (hr == ERROR_MORE_DATA) | { | wideValue = cast(wchar*) mem.xmalloc_noscan(size); | hr = RegQueryValueExW(key, valueName.ptr, null, &type, cast(ubyte*) wideValue, &size); | } | if (hr != 0) | return null; | | auto wideLength = size / wchar.sizeof; | if (wideValue[wideLength - 1] == 0) // may or may not be null-terminated | --wideLength; | return toNarrowStringz(wideValue[0 .. wideLength]).ptr; | } | | /*** | * get architecture of host OS | */ | static bool isWin64Host() | { | version (Win64) | { | return true; | } | else | { | // running as a 32-bit process on a 64-bit host? | alias fnIsWow64Process = extern(Windows) BOOL function(HANDLE, PBOOL); | __gshared fnIsWow64Process pIsWow64Process; | | if (!pIsWow64Process) | { | //IsWow64Process is not available on all supported versions of Windows. | pIsWow64Process = cast(fnIsWow64Process) GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process"); | if (!pIsWow64Process) | return false; | } | BOOL bIsWow64 = FALSE; | if (!pIsWow64Process(GetCurrentProcess(), &bIsWow64)) | return false; | | return bIsWow64 != 0; | } | } |} | |private: | |inout(wchar)[] toDString(inout(wchar)* s) |{ | return s ? s[0 .. wcslen(s)] : null; |} | |extern(C) wchar* _wgetenv(const(wchar)* name); | |char* getenv(wstring name) |{ | if (auto wide = _wgetenv(name.ptr)) | return toNarrowStringz(wide.toDString).ptr; | return null; |} | |const(char)* returnDirIfContainsFile(string fileName)(scope const(char)[][] dirs...) |{ | auto dirPath = FileName.buildPath(dirs); | | auto filePath = FileName.combine(dirPath, fileName); | scope(exit) FileName.free(filePath.ptr); | | if (FileName.exists(filePath)) | return dirPath.ptr; | | FileName.free(dirPath.ptr); | return null; |} | |extern (C) int _waccess(const(wchar)* _FileName, int _AccessMode); | |bool exists(const(wchar)* path) |{ | return _waccess(path, 0) == 0; |} | |/////////////////////////////////////////////////////////////////////// |// COM interfaces to find VS2017+ installations |import core.sys.windows.com; |import core.sys.windows.wtypes : BSTR; |import core.sys.windows.oleauto : SysFreeString, SysStringLen; | |pragma(lib, "ole32.lib"); |pragma(lib, "oleaut32.lib"); | |interface ISetupInstance : IUnknown |{ | // static const GUID iid = uuid("B41463C3-8866-43B5-BC33-2B0676F7F42E"); | static const GUID iid = { 0xB41463C3, 0x8866, 0x43B5, [ 0xBC, 0x33, 0x2B, 0x06, 0x76, 0xF7, 0xF4, 0x2E ] }; | | int GetInstanceId(BSTR* pbstrInstanceId); | int GetInstallDate(LPFILETIME pInstallDate); | int GetInstallationName(BSTR* pbstrInstallationName); | int GetInstallationPath(BSTR* pbstrInstallationPath); | int GetInstallationVersion(BSTR* pbstrInstallationVersion); | int GetDisplayName(LCID lcid, BSTR* pbstrDisplayName); | int GetDescription(LCID lcid, BSTR* pbstrDescription); | int ResolvePath(LPCOLESTR pwszRelativePath, BSTR* pbstrAbsolutePath); |} | |interface IEnumSetupInstances : IUnknown |{ | // static const GUID iid = uuid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848"); | | int Next(ULONG celt, ISetupInstance* rgelt, ULONG* pceltFetched); | int Skip(ULONG celt); | int Reset(); | int Clone(IEnumSetupInstances* ppenum); |} | |interface ISetupConfiguration : IUnknown |{ | // static const GUID iid = uuid("42843719-DB4C-46C2-8E7C-64F1816EFD5B"); | static const GUID iid = { 0x42843719, 0xDB4C, 0x46C2, [ 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B ] }; | | int EnumInstances(IEnumSetupInstances* ppEnumInstances) ; | int GetInstanceForCurrentProcess(ISetupInstance* ppInstance); | int GetInstanceForPath(LPCWSTR wzPath, ISetupInstance* ppInstance); |} | |const GUID iid_SetupConfiguration = { 0x177F0C4A, 0x1CD3, 0x4DE7, [ 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D ] }; | |const(char)* detectVSInstallDirViaCOM() |{ | CoInitialize(null); | scope(exit) CoUninitialize(); | | ISetupConfiguration setup; | IEnumSetupInstances instances; | ISetupInstance instance; | DWORD fetched; | | HRESULT hr = CoCreateInstance(&iid_SetupConfiguration, null, CLSCTX_ALL, &ISetupConfiguration.iid, cast(void**) &setup); | if (hr != S_OK || !setup) | return null; | scope(exit) setup.Release(); | | if (setup.EnumInstances(&instances) != S_OK) | return null; | scope(exit) instances.Release(); | | static struct WrappedBString | { | BSTR ptr; | this(this) @disable; | ~this() { SysFreeString(ptr); } | bool opCast(T : bool)() const { return ptr !is null; } | size_t length() { return SysStringLen(ptr); } | void moveTo(ref WrappedBString other) | { | SysFreeString(other.ptr); | other.ptr = ptr; | ptr = null; | } | } | | WrappedBString versionString, installDir; | | while (instances.Next(1, &instance, &fetched) == S_OK && fetched) | { | WrappedBString thisVersionString, thisInstallDir; | if (instance.GetInstallationVersion(&thisVersionString.ptr) != S_OK || | instance.GetInstallationPath(&thisInstallDir.ptr) != S_OK) | continue; | | // FIXME: proper version strings comparison | // existing versions are 15.0 to 16.5 (May 2020), problems expected in distant future | if (versionString && wcscmp(thisVersionString.ptr, versionString.ptr) <= 0) | continue; // not a newer version, skip | | const installDirLength = thisInstallDir.length; | const vcInstallDirLength = installDirLength + 4; | auto vcInstallDir = (cast(wchar*) mem.xmalloc_noscan(vcInstallDirLength * wchar.sizeof))[0 .. vcInstallDirLength]; | scope(exit) mem.xfree(vcInstallDir.ptr); | vcInstallDir[0 .. installDirLength] = thisInstallDir.ptr[0 .. installDirLength]; | vcInstallDir[installDirLength .. $] = "\\VC\0"w; | if (!exists(vcInstallDir.ptr)) | continue; // Visual C++ not included, skip | | thisVersionString.moveTo(versionString); | thisInstallDir.moveTo(installDir); | } | | return !installDir ? null : toNarrowStringz(installDir.ptr[0 .. installDir.length]).ptr; |} src/dmd/vsoptions.d has no code <<<<<< EOF # path=./src-dmd-inlinecost.lst |/** | * Compute the cost of inlining a function call by counting expressions. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inlinecost.d, _inlinecost.d) | * Documentation: https://dlang.org/phobos/dmd_inlinecost.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/inlinecost.d | */ | |module dmd.inlinecost; | |import core.stdc.stdio; |import core.stdc.string; | |import dmd.aggregate; |import dmd.apply; |import dmd.arraytypes; |import dmd.attrib; |import dmd.dclass; |import dmd.declaration; |import dmd.dmodule; |import dmd.dscope; |import dmd.dstruct; |import dmd.dsymbol; |import dmd.expression; |import dmd.func; |import dmd.globals; |import dmd.id; |import dmd.identifier; |import dmd.init; |import dmd.mtype; |import dmd.opover; |import dmd.statement; |import dmd.tokens; |import dmd.visitor; | |enum COST_MAX = 250; | |private enum STATEMENT_COST = 0x1000; |private enum STATEMENT_COST_MAX = 250 * STATEMENT_COST; | |// STATEMENT_COST be power of 2 and greater than COST_MAX |static assert((STATEMENT_COST & (STATEMENT_COST - 1)) == 0); |static assert(STATEMENT_COST > COST_MAX); | |/********************************* | * Determine if too expensive to inline. | * Params: | * cost = cost of inlining | * Returns: | * true if too costly | */ |bool tooCostly(int cost) pure nothrow |{ 110816| return ((cost & (STATEMENT_COST - 1)) >= COST_MAX); |} | |/********************************* | * Determine cost of inlining Expression | * Params: | * e = Expression to determine cost of | * Returns: | * cost of inlining e | */ |int inlineCostExpression(Expression e) |{ 31429| scope InlineCostVisitor icv = new InlineCostVisitor(false, true, true, null); 31429| icv.expressionInlineCost(e); 31429| return icv.cost; |} | | |/********************************* | * Determine cost of inlining function | * Params: | * fd = function to determine cost of | * hasthis = if the function call has explicit 'this' expression | * hdrscan = if generating a header file | * Returns: | * cost of inlining fd | */ |int inlineCostFunction(FuncDeclaration fd, bool hasthis, bool hdrscan) |{ 21783| scope InlineCostVisitor icv = new InlineCostVisitor(hasthis, hdrscan, false, fd); 21783| fd.fbody.accept(icv); 21783| return icv.cost; |} | |/** | * Indicates if a nested aggregate prevents or not a function to be inlined. | * It's used to compute the cost but also to avoid a copy of the aggregate | * while the inliner processes. | * | * Params: | * e = the declaration expression that may represent an aggregate. | * | * Returns: `null` if `e` is not an aggregate or if it is an aggregate that | * doesn't permit inlining, and the aggregate otherwise. | */ |AggregateDeclaration isInlinableNestedAggregate(DeclarationExp e) |{ 28156| AggregateDeclaration result; 28621| if (e.declaration.isAnonymous() && e.declaration.isAttribDeclaration) | { 465| AttribDeclaration ad = e.declaration.isAttribDeclaration; 465| if (ad.decl.dim == 1) | { 465| if ((result = (*ad.decl)[0].isAggregateDeclaration) !is null) | { | // classes would have to be destroyed 445| if (auto cdecl = result.isClassDeclaration) 0000000| return null; | // if it's a struct: must not have dtor 445| StructDeclaration sdecl = result.isStructDeclaration; 1335| if (sdecl && (sdecl.fieldDtor || sdecl.dtor)) 85| return null; | // the aggregate must be static 360| UnionDeclaration udecl = result.isUnionDeclaration; 720| if ((sdecl || udecl) && !(result.storage_class & STC.static_)) 0000000| return null; | 360| return result; | } | } | } 27691| else if ((result = e.declaration.isStructDeclaration) !is null) | { 68| return result; | } 27623| else if ((result = e.declaration.isUnionDeclaration) !is null) | { 0000000| return result; | } 27643| return null; |} | |private: | |/*********************************************************** | * Compute cost of inlining. | * | * Walk trees to determine if inlining can be done, and if so, | * if it is too complex to be worth inlining or not. | */ |extern (C++) final class InlineCostVisitor : Visitor |{ | alias visit = Visitor.visit; |public: | int nested; | bool hasthis; | bool hdrscan; // if inline scan for 'header' content | bool allowAlloca; | FuncDeclaration fd; | int cost; // zero start for subsequent AST | 0000000| extern (D) this() | { | } | 53212| extern (D) this(bool hasthis, bool hdrscan, bool allowAlloca, FuncDeclaration fd) | { 53212| this.hasthis = hasthis; 53212| this.hdrscan = hdrscan; 53212| this.allowAlloca = allowAlloca; 53212| this.fd = fd; | } | 166944| extern (D) this(InlineCostVisitor icv) | { 166944| nested = icv.nested; 166944| hasthis = icv.hasthis; 166944| hdrscan = icv.hdrscan; 166944| allowAlloca = icv.allowAlloca; 166944| fd = icv.fd; | } | | override void visit(Statement s) | { | //printf("Statement.inlineCost = %d\n", COST_MAX); | //printf("%p\n", s.isScopeStatement()); | //printf("%s\n", s.toChars()); 508| cost += COST_MAX; // default is we can't inline it | } | | override void visit(ExpStatement s) | { 46188| expressionInlineCost(s.exp); | } | | override void visit(CompoundStatement s) | { 57912| scope InlineCostVisitor icv = new InlineCostVisitor(this); 428486| foreach (i; 0 .. s.statements.dim) | { 89180| if (Statement s2 = (*s.statements)[i]) | { | /* Specifically allow: | * if (condition) | * return exp1; | * return exp2; | */ 88957| IfStatement ifs; 88957| Statement s3; 88957| if ((ifs = s2.isIfStatement()) !is null && 1486| ifs.ifbody && 1486| ifs.ifbody.endsWithReturnStatement() && 418| !ifs.elsebody && 407| i + 1 < s.statements.dim && 323| (s3 = (*s.statements)[i + 1]) !is null && 315| s3.endsWithReturnStatement() | ) | { 12| if (ifs.prm) // if variables are declared | { 0000000| cost = COST_MAX; 0000000| return; | } 12| expressionInlineCost(ifs.condition); 12| ifs.ifbody.accept(this); 12| s3.accept(this); | } | else 88945| s2.accept(icv); 88957| if (tooCostly(icv.cost)) 6395| break; | } | } 57912| cost += icv.cost; | } | | override void visit(UnrolledLoopStatement s) | { 68| scope InlineCostVisitor icv = new InlineCostVisitor(this); 320| foreach (s2; *s.statements) | { 76| if (s2) | { 76| s2.accept(icv); 76| if (tooCostly(icv.cost)) 56| break; | } | } 68| cost += icv.cost; | } | | override void visit(ScopeStatement s) | { 9359| cost++; 9359| if (s.statement) 9359| s.statement.accept(this); | } | | override void visit(IfStatement s) | { | /* Can't declare variables inside ?: expressions, so | * we cannot inline if a variable is declared. | */ 1577| if (s.prm) | { 32| cost = COST_MAX; 32| return; | } 1545| expressionInlineCost(s.condition); | /* Specifically allow: | * if (condition) | * return exp1; | * else | * return exp2; | * Otherwise, we can't handle return statements nested in if's. | */ 2271| if (s.elsebody && s.ifbody && s.ifbody.endsWithReturnStatement() && s.elsebody.endsWithReturnStatement()) | { 11| s.ifbody.accept(this); 11| s.elsebody.accept(this); | //printf("cost = %d\n", cost); | } | else | { 1534| nested += 1; 1534| if (s.ifbody) 1534| s.ifbody.accept(this); 1534| if (s.elsebody) 346| s.elsebody.accept(this); 1534| nested -= 1; | } | //printf("IfStatement.inlineCost = %d\n", cost); | } | | override void visit(ReturnStatement s) | { | // Can't handle return statements nested in if's 5655| if (nested) | { 426| cost = COST_MAX; | } | else | { 5229| expressionInlineCost(s.exp); | } | } | | override void visit(ImportStatement s) | { | } | | override void visit(ForStatement s) | { 1257| cost += STATEMENT_COST; 1257| if (s._init) 0000000| s._init.accept(this); 1257| if (s.condition) 1257| s.condition.accept(this); 1257| if (s.increment) 532| s.increment.accept(this); 1257| if (s._body) 1257| s._body.accept(this); | //printf("ForStatement: inlineCost = %d\n", cost); | } | | override void visit(ThrowStatement s) | { 236| cost += STATEMENT_COST; 236| s.exp.accept(this); | } | | /* -------------------------- */ | void expressionInlineCost(Expression e) | { | //printf("expressionInlineCost()\n"); | //e.print(); 108994| if (e) | { | extern (C++) final class LambdaInlineCost : StoppableVisitor | { | alias visit = typeof(super).visit; | InlineCostVisitor icv; | | public: 108964| extern (D) this(InlineCostVisitor icv) | { 108964| this.icv = icv; | } | | override void visit(Expression e) | { 356671| e.accept(icv); 356671| stop = icv.cost >= COST_MAX; | } | } | 108964| scope InlineCostVisitor icv = new InlineCostVisitor(this); 108964| scope LambdaInlineCost lic = new LambdaInlineCost(icv); 108964| walkPostorder(e, lic); 108964| cost += icv.cost; | } | } | | override void visit(Expression e) | { 213118| cost++; | } | | override void visit(VarExp e) | { | //printf("VarExp.inlineCost3() %s\n", toChars()); 89714| Type tb = e.type.toBasetype(); 89714| if (auto ts = tb.isTypeStruct()) | { 27042| StructDeclaration sd = ts.sym; 27042| if (sd.isNested()) | { | /* An inner struct will be nested inside another function hierarchy than where | * we're inlining into, so don't inline it. | * At least not until we figure out how to 'move' the struct to be nested | * locally. Example: | * struct S(alias pred) { void unused_func(); } | * void abc() { int w; S!(w) m; } | * void bar() { abc(); } | */ 261| cost = COST_MAX; 261| return; | } | } 89453| FuncDeclaration fd = e.var.isFuncDeclaration(); 98624| if (fd && fd.isNested()) // https://issues.dlang.org/show_bug.cgi?id=7199 for test case 51| cost = COST_MAX; | else 89402| cost++; | } | | override void visit(ThisExp e) | { | //printf("ThisExp.inlineCost3() %s\n", toChars()); 9566| if (!fd) | { 0000000| cost = COST_MAX; 0000000| return; | } 9566| if (!hdrscan) | { 19107| if (fd.isNested() || !hasthis) | { 25| cost = COST_MAX; 25| return; | } | } 9541| cost++; | } | | override void visit(StructLiteralExp e) | { | //printf("StructLiteralExp.inlineCost3() %s\n", toChars()); 5741| if (e.sd.isNested()) 75| cost = COST_MAX; | else 5666| cost++; | } | | override void visit(NewExp e) | { | //printf("NewExp.inlineCost3() %s\n", e.toChars()); 1243| AggregateDeclaration ad = isAggregate(e.newtype); 2367| if (ad && ad.isNested()) 0000000| cost = COST_MAX; | else 1243| cost++; | } | | override void visit(FuncExp e) | { | //printf("FuncExp.inlineCost3()\n"); | // Right now, this makes the function be output to the .obj file twice. 32| cost = COST_MAX; | } | | override void visit(DelegateExp e) | { | //printf("DelegateExp.inlineCost3()\n"); 33| cost = COST_MAX; | } | | override void visit(DeclarationExp e) | { | //printf("DeclarationExp.inlineCost3()\n"); 27467| if (auto vd = e.declaration.isVarDeclaration()) | { 25868| if (auto td = vd.toAlias().isTupleDeclaration()) | { 18| cost = COST_MAX; // finish DeclarationExp.doInlineAs 18| return; | } 51700| if (!hdrscan && vd.isDataseg()) | { 174| cost = COST_MAX; 174| return; | } 25676| if (vd.edtor) | { | // if destructor required | // needs work to make this work 1037| cost = COST_MAX; 1037| return; | } | // Scan initializer (vd.init) 24639| if (vd._init) | { 24639| if (auto ie = vd._init.isExpInitializer()) | { 24591| expressionInlineCost(ie.exp); | } | } 24639| ++cost; | } | | // aggregates are accepted under certain circumstances 26238| if (isInlinableNestedAggregate(e)) | { 330| cost++; 330| return; | } | | // These can contain functions, which when copied, get output twice. 25908| if (e.declaration.isStructDeclaration() || 25908| e.declaration.isClassDeclaration() || 25905| e.declaration.isFuncDeclaration() || 25674| e.declaration.isAttribDeclaration() || 25569| e.declaration.isTemplateMixin()) | { 339| cost = COST_MAX; 339| return; | } | //printf("DeclarationExp.inlineCost3('%s')\n", toChars()); | } | | override void visit(CallExp e) | { | //printf("CallExp.inlineCost3() %s\n", toChars()); | // https://issues.dlang.org/show_bug.cgi?id=3500 | // super.func() calls must be devirtualized, and the inliner | // can't handle that at present. 14204| if (e.e1.op == TOK.dotVariable && (cast(DotVarExp)e.e1).e1.op == TOK.super_) 0000000| cost = COST_MAX; 23340| else if (e.f && e.f.ident == Id.__alloca && e.f.linkage == LINK.c && !allowAlloca) 0000000| cost = COST_MAX; // inlining alloca may cause stack overflows | else 11782| cost++; | } |} | src/dmd/inlinecost.d is 92% covered <<<<<< EOF # path=./src-dmd-arraytypes.lst |/** | * Provide aliases for arrays of certain declarations or statements. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d) | * Documentation: https://dlang.org/phobos/dmd_arraytypes.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arraytypes.d | */ | |module dmd.arraytypes; | |import dmd.dclass; |import dmd.declaration; |import dmd.dmodule; |import dmd.dsymbol; |import dmd.dtemplate; |import dmd.expression; |import dmd.func; |import dmd.identifier; |import dmd.init; |import dmd.mtype; |import dmd.root.array; |import dmd.root.rootobject; |import dmd.statement; | |alias Strings = Array!(const(char)*); |alias Identifiers = Array!(Identifier); |alias TemplateParameters = Array!(TemplateParameter); |alias Expressions = Array!(Expression); |alias Statements = Array!(Statement); |alias BaseClasses = Array!(BaseClass*); |alias ClassDeclarations = Array!(ClassDeclaration); |alias Dsymbols = Array!(Dsymbol); |alias Objects = Array!(RootObject); |alias DtorDeclarations = Array!(DtorDeclaration); |alias FuncDeclarations = Array!(FuncDeclaration); |alias Parameters = Array!(Parameter); |alias Initializers = Array!(Initializer); |alias VarDeclarations = Array!(VarDeclaration); |alias Types = Array!(Type); |alias Catches = Array!(Catch); |alias StaticDtorDeclarations = Array!(StaticDtorDeclaration); |alias SharedStaticDtorDeclarations = Array!(SharedStaticDtorDeclaration); |alias AliasDeclarations = Array!(AliasDeclaration); |alias Modules = Array!(Module); |alias CaseStatements = Array!(CaseStatement); |alias ScopeStatements = Array!(ScopeStatement); |alias GotoCaseStatements = Array!(GotoCaseStatement); |alias ReturnStatements = Array!(ReturnStatement); |alias GotoStatements = Array!(GotoStatement); |alias TemplateInstances = Array!(TemplateInstance); |alias Ensures = Array!(Ensure); src/dmd/arraytypes.d has no code <<<<<< EOF # path=./src-dmd-root-stringtable.lst |/** | * A specialized associative array with string keys stored in a variable length structure. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: Walter Bright, http://www.digitalmars.com | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d, root/_stringtable.d) | * Documentation: https://dlang.org/phobos/dmd_root_stringtable.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/stringtable.d | */ | |module dmd.root.stringtable; | |import core.stdc.string; |import dmd.root.rmem, dmd.root.hash; | |private enum POOL_BITS = 12; |private enum POOL_SIZE = (1U << POOL_BITS); | |/* |Returns the smallest integer power of 2 larger than val. |if val > 2^^63 on 64-bit targets or val > 2^^31 on 32-bit targets it enters an |endless loop because of overflow. |*/ |private size_t nextpow2(size_t val) @nogc nothrow pure @safe |{ 32843| size_t res = 1; 214422| while (res < val) 181579| res <<= 1; 32843| return res; |} | |unittest |{ | assert(nextpow2(0) == 1); | assert(nextpow2(0xFFFF) == (1 << 16)); | assert(nextpow2(size_t.max / 2) == size_t.max / 2 + 1); | // note: nextpow2((1UL << 63) + 1) results in an endless loop |} | |private enum loadFactorNumerator = 8; |private enum loadFactorDenominator = 10; // for a load factor of 0.8 | |private struct StringEntry |{ | uint hash; | uint vptr; |} | |// 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(T) |{ | T value; //T is/should typically be a pointer or a slice | private size_t length; | | char* lstring() @nogc nothrow pure return | { 14420836| return cast(char*)(&this + 1); | } | | size_t len() const @nogc nothrow pure @safe | { 000000000| return length; | } | | const(char)* toDchars() const @nogc nothrow pure return | { 116976716| return cast(const(char)*)(&this + 1); | } | | /// Returns: The content of this entry as a D slice | inout(char)[] toString() inout @nogc nothrow pure | { 7210417| return (cast(inout(char)*)(&this + 1))[0 .. length]; | } |} | |struct StringTable(T) |{ |private: | StringEntry[] table; | ubyte*[] pools; | size_t nfill; | size_t count; | size_t countTrigger; // amount which will trigger growing the table | |public: | void _init(size_t size = 0) nothrow pure | { 7172| size = nextpow2((size * loadFactorDenominator) / loadFactorNumerator); 7172| if (size < 32) 3556| size = 32; 7172| table = (cast(StringEntry*)mem.xcalloc(size, (table[0]).sizeof))[0 .. size]; 7172| countTrigger = (table.length * loadFactorNumerator) / loadFactorDenominator; 7172| pools = null; 7172| nfill = 0; 7172| count = 0; | } | | void reset(size_t size = 0) nothrow pure | { 000000000| freeMem(); 000000000| _init(size); | } | | ~this() nothrow pure | { 000000000| freeMem(); | } | | /** | Looks up the given string in the string table and returns its associated | value. | | Params: | s = the string to look up | length = the length of $(D_PARAM s) | str = the string to look up | | Returns: the string's associated value, or `null` if the string doesn't | exist in the string table | */ | inout(StringValue!T)* lookup(const(char)[] str) inout @nogc nothrow pure | { 16962228| const(size_t) hash = calcHash(str); 16962228| const(size_t) i = findSlot(hash, str); | // printf("lookup %.*s %p\n", cast(int)str.length, str.ptr, table[i].value ?: null); 16962228| return getValue(table[i].vptr); | } | | /// ditto | inout(StringValue!T)* lookup(const(char)* s, size_t length) inout @nogc nothrow pure | { 000000000| return lookup(s[0 .. length]); | } | | /** | Inserts the given string and the given associated value into the string | table. | | Params: | s = the string to insert | length = the length of $(D_PARAM s) | ptrvalue = the value to associate with the inserted string | str = the string to insert | value = the value to associate with the inserted string | | Returns: the newly inserted value, or `null` if the string table already | contains the string | */ | StringValue!(T)* insert(const(char)[] str, T value) nothrow pure | { 401377| const(size_t) hash = calcHash(str); 401377| size_t i = findSlot(hash, str); 401377| if (table[i].vptr) 000000000| return null; // already in table 401377| if (++count > countTrigger) | { 000000000| grow(); 000000000| i = findSlot(hash, str); | } 401377| table[i].hash = hash; 401377| table[i].vptr = allocValue(str, value); | // printf("insert %.*s %p\n", cast(int)str.length, str.ptr, table[i].value ?: NULL); 401377| return getValue(table[i].vptr); | } | | /// ditto | StringValue!(T)* insert(const(char)* s, size_t length, T value) nothrow pure | { 000000000| return insert(s[0 .. length], value); | } | | StringValue!(T)* update(const(char)[] str) nothrow pure | { 123780937| const(size_t) hash = calcHash(str); 123780937| size_t i = findSlot(hash, str); 123780937| if (!table[i].vptr) | { 6809041| if (++count > countTrigger) | { 000000000| grow(); 000000000| i = findSlot(hash, str); | } 6809041| table[i].hash = hash; 6809041| table[i].vptr = allocValue(str, T.init); | } | // printf("update %.*s %p\n", cast(int)str.length, str.ptr, table[i].value ?: NULL); 123780937| return getValue(table[i].vptr); | } | | StringValue!(T)* update(const(char)* s, size_t length) nothrow pure | { 000000000| return update(s[0 .. length]); | } | | /******************************** | * 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 apply(int function(const(StringValue!T)*) nothrow fp) nothrow | { 000000000| foreach (const se; table) | { 000000000| if (!se.vptr) 000000000| continue; 000000000| const sv = getValue(se.vptr); 000000000| int result = (*fp)(sv); 000000000| if (result) 000000000| return result; | } 000000000| return 0; | } | | /// ditto | extern(D) int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow | { 000000000| foreach (const se; table) | { 000000000| if (!se.vptr) 000000000| continue; 000000000| const sv = getValue(se.vptr); 000000000| int result = dg(sv); 000000000| if (result) 000000000| return result; | } 000000000| return 0; | } | |private: | /// Free all memory in use by this StringTable | void freeMem() nothrow pure | { 000000000| foreach (pool; pools) 000000000| mem.xfree(pool); 000000000| mem.xfree(table.ptr); 000000000| mem.xfree(pools.ptr); 000000000| table = null; 000000000| pools = null; | } | | uint allocValue(const(char)[] str, T value) nothrow pure | { 7210418| const(size_t) nbytes = (StringValue!T).sizeof + str.length + 1; 14417219| if (!pools.length || nfill + nbytes > POOL_SIZE) | { 54359| pools = (cast(ubyte**) mem.xrealloc(pools.ptr, (pools.length + 1) * (pools[0]).sizeof))[0 .. pools.length + 1]; 108718| pools[$-1] = cast(ubyte*) mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE); 54359| if (mem.isGCEnabled) 450| memset(pools[$ - 1], 0xff, POOL_SIZE); // 0xff less likely to produce GC pointer 54359| nfill = 0; | } 7210418| StringValue!(T)* sv = cast(StringValue!(T)*)&pools[$ - 1][nfill]; 7210418| sv.value = value; 7210418| sv.length = str.length; 7210418| .memcpy(sv.lstring(), str.ptr, str.length); 7210418| sv.lstring()[str.length] = 0; 7210418| const(uint) vptr = cast(uint)(pools.length << POOL_BITS | nfill); 7210418| nfill += nbytes + (-nbytes & 7); // align to 8 bytes 7210418| return vptr; | } | | inout(StringValue!T)* getValue(uint vptr) inout @nogc nothrow pure | { 258121264| if (!vptr) 16957408| return null; 241163856| const(size_t) idx = (vptr >> POOL_BITS) - 1; 241163856| const(size_t) off = vptr & POOL_SIZE - 1; 241163856| return cast(inout(StringValue!T)*)&pools[idx][off]; | } | | size_t findSlot(hash_t hash, const(char)[] str) const @nogc nothrow pure | { | // quadratic probing using triangular numbers | // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774 284643109| for (size_t i = hash & (table.length - 1), j = 1;; ++j) | { 143498567| const(StringValue!T)* sv; 143498567| auto vptr = table[i].vptr; 496782746| if (!vptr || table[i].hash == hash && (sv = getValue(vptr)).length == str.length && .memcmp(str.ptr, sv.toDchars(), str.length) == 0) 141144542| return i; 2354025| i = (i + j) & (table.length - 1); | } | } | | void grow() nothrow pure | { 000000000| const odim = table.length; 000000000| auto otab = table; 000000000| const ndim = table.length * 2; 000000000| countTrigger = (ndim * loadFactorNumerator) / loadFactorDenominator; 000000000| table = (cast(StringEntry*)mem.xcalloc_noscan(ndim, (table[0]).sizeof))[0 .. ndim]; 000000000| foreach (const se; otab[0 .. odim]) | { 000000000| if (!se.vptr) 000000000| continue; 000000000| const sv = getValue(se.vptr); 000000000| table[findSlot(se.hash, sv.toString())] = se; | } 000000000| mem.xfree(otab.ptr); | } |} | |nothrow unittest |{ | StringTable!(const(char)*) tab; | tab._init(10); | | // construct two strings with the same text, but a different pointer | const(char)[6] fooBuffer = "foofoo"; | const(char)[] foo = fooBuffer[0 .. 3]; | const(char)[] fooAltPtr = fooBuffer[3 .. 6]; | | assert(foo.ptr != fooAltPtr.ptr); | | // first insertion returns value | assert(tab.insert(foo, foo.ptr).value == foo.ptr); | | // subsequent insertion of same string return null | assert(tab.insert(foo.ptr, foo.length, foo.ptr) == null); | assert(tab.insert(fooAltPtr, foo.ptr) == null); | | const lookup = tab.lookup("foo"); | assert(lookup.value == foo.ptr); | assert(lookup.len == 3); | assert(lookup.toString() == "foo"); | | assert(tab.lookup("bar") == null); | tab.update("bar".ptr, "bar".length); | assert(tab.lookup("bar").value == null); | | tab.reset(0); | assert(tab.lookup("foo".ptr, "foo".length) == null); | //tab.insert("bar"); |} | |nothrow unittest |{ | StringTable!(void*) tab; | tab._init(100); | | enum testCount = 2000; | | char[2 * testCount] buf; | | foreach(i; 0 .. testCount) | { | buf[i * 2 + 0] = cast(char) (i % 256); | buf[i * 2 + 1] = cast(char) (i / 256); | auto toInsert = cast(const(char)[]) buf[i * 2 .. i * 2 + 2]; | tab.insert(toInsert, cast(void*) i); | } | | foreach(i; 0 .. testCount) | { | auto toLookup = cast(const(char)[]) buf[i * 2 .. i * 2 + 2]; | assert(tab.lookup(toLookup).value == cast(void*) i); | } |} | |nothrow unittest |{ | StringTable!(int) tab; | tab._init(10); | tab.insert("foo", 4); | tab.insert("bar", 6); | | static int resultFp = 0; | int resultDg = 0; | static bool returnImmediately = false; | | int function(const(StringValue!int)*) nothrow applyFunc = (const(StringValue!int)* s) | { | resultFp += s.value; | return returnImmediately; | }; | | scope int delegate(const(StringValue!int)*) nothrow applyDeleg = (const(StringValue!int)* s) | { | resultDg += s.value; | return returnImmediately; | }; | | tab.apply(applyFunc); | tab.opApply(applyDeleg); | | assert(resultDg == 10); | assert(resultFp == 10); | | returnImmediately = true; | | tab.apply(applyFunc); | tab.opApply(applyDeleg); | | // Order of string table iteration is not specified, either foo or bar could | // have been visited first. | assert(resultDg == 14 || resultDg == 16); | assert(resultFp == 14 || resultFp == 16); |} src/dmd/root/stringtable.d is 56% covered <<<<<< EOF # path=./src-dmd-id.lst |/** | * Contains the `Id` struct with a list of predefined symbols the compiler knows about. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d) | * Documentation: https://dlang.org/phobos/dmd_id.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/id.d | */ | |module dmd.id; | |import dmd.identifier; |import dmd.tokens; | |/** | * Represents a list of predefined symbols the compiler knows about. | * | * All static fields in this struct represents a specific predefined symbol. | */ |extern (C++) struct Id |{ | static __gshared: | | mixin(msgtable.generate(&identifier)); | | /** | * Populates the identifier pool with all predefined symbols. | * | * An identifier that corresponds to each static field in this struct will | * be placed in the identifier pool. | */ | extern(C++) void initialize() | { | mixin(msgtable.generate(&initializer)); | } | | /** | * Deinitializes the global state of the compiler. | * | * This can be used to restore the state set by `initialize` to its original | * state. | */ | extern (D) void deinitialize() | { | mixin(msgtable.generate(&deinitializer)); | } |} | |private: | | |/** | * Each element in this array will generate one static field in the `Id` struct | * and a call to `Identifier.idPool` to populate the identifier pool in the | * `Id.initialize` method. | */ |immutable Msgtable[] msgtable = |[ | { "IUnknown" }, | { "Object" }, | { "object" }, | { "string" }, | { "wstring" }, | { "dstring" }, | { "max" }, | { "min" }, | { "This", "this" }, | { "_super", "super" }, | { "ctor", "__ctor" }, | { "dtor", "__dtor" }, | { "__xdtor", "__xdtor" }, | { "__fieldDtor", "__fieldDtor" }, | { "__aggrDtor", "__aggrDtor" }, | { "cppdtor", "__cppdtor" }, | { "ticppdtor", "__ticppdtor" }, | { "postblit", "__postblit" }, | { "__xpostblit", "__xpostblit" }, | { "__fieldPostblit", "__fieldPostblit" }, | { "__aggrPostblit", "__aggrPostblit" }, | { "classInvariant", "__invariant" }, | { "unitTest", "__unitTest" }, | { "require", "__require" }, | { "ensure", "__ensure" }, | { "capture", "__capture" }, | { "this2", "__this" }, | { "_init", "init" }, | { "__sizeof", "sizeof" }, | { "__xalignof", "alignof" }, | { "_mangleof", "mangleof" }, | { "stringof" }, | { "_tupleof", "tupleof" }, | { "length" }, | { "remove" }, | { "ptr" }, | { "array" }, | { "funcptr" }, | { "dollar", "__dollar" }, | { "ctfe", "__ctfe" }, | { "offset" }, | { "offsetof" }, | { "ModuleInfo" }, | { "ClassInfo" }, | { "classinfo" }, | { "typeinfo" }, | { "outer" }, | { "Exception" }, | { "RTInfo" }, | { "Throwable" }, | { "Error" }, | { "withSym", "__withSym" }, | { "result", "__result" }, | { "returnLabel", "__returnLabel" }, | { "line" }, | { "empty", "" }, | { "p" }, | { "q" }, | { "__vptr" }, | { "__monitor" }, | { "gate", "__gate" }, | { "__c_long" }, | { "__c_ulong" }, | { "__c_longlong" }, | { "__c_ulonglong" }, | { "__c_long_double" }, | { "__c_wchar_t" }, | { "cpp_type_info_ptr", "__cpp_type_info_ptr" }, | { "_assert", "assert" }, | { "_unittest", "unittest" }, | { "_body", "body" }, | { "printf" }, | { "scanf" }, | | { "TypeInfo" }, | { "TypeInfo_Class" }, | { "TypeInfo_Interface" }, | { "TypeInfo_Struct" }, | { "TypeInfo_Enum" }, | { "TypeInfo_Pointer" }, | { "TypeInfo_Vector" }, | { "TypeInfo_Array" }, | { "TypeInfo_StaticArray" }, | { "TypeInfo_AssociativeArray" }, | { "TypeInfo_Function" }, | { "TypeInfo_Delegate" }, | { "TypeInfo_Tuple" }, | { "TypeInfo_Const" }, | { "TypeInfo_Invariant" }, | { "TypeInfo_Shared" }, | { "TypeInfo_Wild", "TypeInfo_Inout" }, | { "elements" }, | { "_arguments_typeinfo" }, | { "_arguments" }, | { "_argptr" }, | { "destroy" }, | { "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" }, | { "infinity" }, | { "dig" }, | { "epsilon" }, | { "mant_dig" }, | { "max_10_exp" }, | { "max_exp" }, | { "min_10_exp" }, | { "min_exp" }, | { "min_normal" }, | { "re" }, | { "im" }, | | { "C" }, | { "D" }, | { "Windows" }, | { "Pascal" }, | { "System" }, | { "Objective" }, | | { "exit" }, | { "success" }, | { "failure" }, | | { "keys" }, | { "values" }, | { "rehash" }, | | { "future", "__future" }, | { "property" }, | { "nogc" }, | { "live" }, | { "safe" }, | { "trusted" }, | { "system" }, | { "disable" }, | | // For inline assembler | { "___out", "out" }, | { "___in", "in" }, | { "__int", "int" }, | { "_dollar", "$" }, | { "__LOCAL_SIZE" }, | | // 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" }, | { "opIn_r" }, | { "opStar" }, | { "opDot" }, | { "opDispatch" }, | { "opDollar" }, | { "opUnary" }, | { "opIndexUnary" }, | { "opSliceUnary" }, | { "opBinary" }, | { "opBinaryRight" }, | { "opOpAssign" }, | { "opIndexOpAssign" }, | { "opSliceOpAssign" }, | { "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" }, | { "__ArrayPostblit" }, | { "__ArrayDtor" }, | { "_d_delThrowable" }, | { "_d_assert_fail" }, | { "dup" }, | { "_aaApply" }, | { "_aaApply2" }, | | // For pragma's | { "Pinline", "inline" }, | { "lib" }, | { "linkerDirective" }, | { "mangle" }, | { "msg" }, | { "startaddress" }, | { "crt_constructor" }, | { "crt_destructor" }, | | // For special functions | { "tohash", "toHash" }, | { "tostring", "toString" }, | { "getmembers", "getMembers" }, | | // Special functions | { "__alloca", "alloca" }, | { "main" }, | { "WinMain" }, | { "DllMain" }, | { "CMain", "_d_cmain" }, | { "rt_init" }, | { "__cmp" }, | { "__equals"}, | { "__switch"}, | { "__switch_error"}, | { "__ArrayCast"}, | { "_d_HookTraceImpl" }, | { "_d_arraysetlengthTImpl"}, | { "_d_arraysetlengthT"}, | { "_d_arraysetlengthTTrace"}, | | // varargs implementation | { "stdc" }, | { "stdarg" }, | { "va_start" }, | | // Builtin functions | { "std" }, | { "core" }, | { "etc" }, | { "attribute" }, | { "math" }, | { "trig" }, | { "sin" }, | { "cos" }, | { "tan" }, | { "_sqrt", "sqrt" }, | { "_pow", "pow" }, | { "atan2" }, | { "rint" }, | { "ldexp" }, | { "rndtol" }, | { "exp" }, | { "expm1" }, | { "exp2" }, | { "yl2x" }, | { "yl2xp1" }, | { "log" }, | { "log2" }, | { "log10" }, | { "round" }, | { "floor" }, | { "trunc" }, | { "fmax" }, | { "fmin" }, | { "fma" }, | { "isnan" }, | { "isInfinity" }, | { "isfinite" }, | { "ceil" }, | { "copysign" }, | { "fabs" }, | { "toPrec" }, | { "simd" }, | { "__prefetch"}, | { "__simd_sto"}, | { "__simd"}, | { "__simd_ib"}, | { "bitop" }, | { "bsf" }, | { "bsr" }, | { "btc" }, | { "btr" }, | { "bts" }, | { "bswap" }, | { "volatile"}, | { "volatileLoad"}, | { "volatileStore"}, | { "_popcnt"}, | { "inp"}, | { "inpl"}, | { "inpw"}, | { "outp"}, | { "outpl"}, | { "outpw"}, | | // Traits | { "isAbstractClass" }, | { "isArithmetic" }, | { "isAssociativeArray" }, | { "isFinalClass" }, | { "isTemplate" }, | { "isPOD" }, | { "isDeprecated" }, | { "isDisabled" }, | { "isFuture" }, | { "isNested" }, | { "isFloating" }, | { "isIntegral" }, | { "isScalar" }, | { "isStaticArray" }, | { "isUnsigned" }, | { "isVirtualFunction" }, | { "isVirtualMethod" }, | { "isAbstractFunction" }, | { "isFinalFunction" }, | { "isOverrideFunction" }, | { "isStaticFunction" }, | { "isModule" }, | { "isPackage" }, | { "isRef" }, | { "isOut" }, | { "isLazy" }, | { "hasMember" }, | { "identifier" }, | { "getProtection" }, | { "parent" }, | { "child" }, | { "getMember" }, | { "getOverloads" }, | { "getVirtualFunctions" }, | { "getVirtualMethods" }, | { "classInstanceSize" }, | { "allMembers" }, | { "derivedMembers" }, | { "isSame" }, | { "compiles" }, | { "parameters" }, | { "getAliasThis" }, | { "getAttributes" }, | { "getFunctionAttributes" }, | { "getFunctionVariadicStyle" }, | { "getParameterStorageClasses" }, | { "getLinkage" }, | { "getUnitTests" }, | { "getVirtualIndex" }, | { "getPointerBitmap" }, | { "isReturnOnStack" }, | { "isZeroInit" }, | { "getTargetInfo" }, | { "getLocation" }, | { "hasPostblit" }, | { "hasCopyConstructor" }, | { "isCopyable" }, | | // For C++ mangling | { "allocator" }, | { "basic_string" }, | { "basic_istream" }, | { "basic_ostream" }, | { "basic_iostream" }, | { "char_traits" }, | | // Compiler recognized UDA's | { "udaGNUAbiTag", "gnuAbiTag" }, | { "udaSelector", "selector" }, | | // C names, for undefined identifier error messages | { "NULL" }, | { "TRUE" }, | { "FALSE" }, | { "unsigned" }, | { "wchar_t" }, |]; | | |/* | * Tuple of DMD source code identifier and symbol in the D executable. | * | * The first element of the tuple is the identifier to use in the DMD source | * code and the second element, if present, is the name to use in the D | * executable. If second element, `name`, is not present the identifier, | * `ident`, will be used instead | */ |struct Msgtable |{ | // The identifier to use in the DMD source. | string ident; | | // The name to use in the D executable | private string name_; | | /* | * Returns: the name to use in the D executable, `name_` if non-empty, | * otherwise `ident` | */ | string name() | { 0000000| return name_ ? name_ : ident; | } |} | |/* | * Iterates the given Msgtable array, passes each element to the given lambda | * and accumulates a string from each return value of calling the lambda. | * Appends a newline character after each call to the lambda. | */ |string generate(immutable(Msgtable)[] msgtable, string function(Msgtable) dg) |{ 0000000| string code; | 0000000| foreach (i, m ; msgtable) | { 0000000| if (i != 0) 0000000| code ~= '\n'; | 0000000| code ~= dg(m); | } | 0000000| return code; |} | |// Used to generate the code for each identifier. |string identifier(Msgtable m) |{ 0000000| return "Identifier " ~ m.ident ~ ";"; |} | |// Used to generate the code for each initializer. |string initializer(Msgtable m) |{ 0000000| return m.ident ~ ` = Identifier.idPool("` ~ m.name ~ `");`; |} | |// Used to generate the code for each deinitializer. |string deinitializer(Msgtable m) |{ 0000000| return m.ident ~ " = Identifier.init;"; |} src/dmd/id.d is 0% covered <<<<<< EOF # path=./src-dmd-hdrgen.lst |/** | * Generate $(LINK2 https://dlang.org/dmd-windows.html#interface-files, D interface files). | * | * Also used to convert AST nodes to D code in general, e.g. for error messages or `printf` debugging. | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d) | * Documentation: https://dlang.org/phobos/dmd_hdrgen.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/hdrgen.d | */ | |module dmd.hdrgen; | |import core.stdc.ctype; |import core.stdc.stdio; |import core.stdc.string; |import dmd.aggregate; |import dmd.aliasthis; |import dmd.arraytypes; |import dmd.attrib; |import dmd.complex; |import dmd.cond; |import dmd.ctfeexpr; |import dmd.dclass; |import dmd.declaration; |import dmd.denum; |import dmd.dimport; |import dmd.dmodule; |import dmd.doc; |import dmd.dstruct; |import dmd.dsymbol; |import dmd.dtemplate; |import dmd.dversion; |import dmd.expression; |import dmd.func; |import dmd.globals; |import dmd.id; |import dmd.identifier; |import dmd.init; |import dmd.mtype; |import dmd.nspace; |import dmd.parse; |import dmd.root.ctfloat; |import dmd.root.outbuffer; |import dmd.root.rootobject; |import dmd.root.string; |import dmd.statement; |import dmd.staticassert; |import dmd.target; |import dmd.tokens; |import dmd.utils; |import dmd.visitor; | |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; | | bool declstring; // set while declaring alias for string,wstring or dstring | EnumDeclaration inEnumDecl; |} | |enum TEST_EMIT_ALL = 0; | |extern (C++) void genhdrfile(Module m) |{ 84| OutBuffer buf; 42| buf.doindent = 1; 42| buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); 42| buf.writenl(); 42| HdrGenState hgs; 42| hgs.hdrgen = true; 42| toCBuffer(m, &buf, &hgs); 42| writeFile(m.loc, m.hdrfile.toString(), buf[]); |} | |/** | * Dumps the full contents of module `m` to `buf`. | * Params: | * buf = buffer to write to. | * m = module to visit all members of. | */ |extern (C++) void moduleToBuffer(OutBuffer* buf, Module m) |{ 1| HdrGenState hgs; 1| hgs.fullDump = true; 1| toCBuffer(m, buf, &hgs); |} | |void moduleToBuffer2(Module m, OutBuffer* buf, HdrGenState* hgs) |{ 43| if (m.md) | { 16| if (m.userAttribDecl) | { 1| buf.writestring("@("); 1| argsToBuffer(m.userAttribDecl.atts, buf, hgs); 1| buf.writeByte(')'); 1| buf.writenl(); | } 16| if (m.md.isdeprecated) | { 2| if (m.md.msg) | { 1| buf.writestring("deprecated("); 1| m.md.msg.expressionToBuffer(buf, hgs); 1| buf.writestring(") "); | } | else 1| buf.writestring("deprecated "); | } 16| buf.writestring("module "); 16| buf.writestring(m.md.toChars()); 16| buf.writeByte(';'); 16| buf.writenl(); | } | 2985| foreach (s; *m.members) | { 952| s.dsymbolToBuffer(buf, hgs); | } |} | |private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs) |{ 1065| scope v = new StatementPrettyPrintVisitor(buf, hgs); 1065| s.accept(v); |} | |private extern (C++) final class StatementPrettyPrintVisitor : Visitor |{ | alias visit = Visitor.visit; |public: | OutBuffer* buf; | HdrGenState* hgs; | 1065| extern (D) this(OutBuffer* buf, HdrGenState* hgs) | { 1065| this.buf = buf; 1065| this.hgs = hgs; | } | | override void visit(Statement s) | { 00000000| buf.writestring("Statement::toCBuffer()"); 00000000| buf.writenl(); 00000000| assert(0); | } | | override void visit(ErrorStatement s) | { 1| buf.writestring("__error__"); 1| buf.writenl(); | } | | override void visit(ExpStatement s) | { 1632| if (s.exp && s.exp.op == TOK.declaration && 147| (cast(DeclarationExp)s.exp).declaration) | { | // bypass visit(DeclarationExp) 146| (cast(DeclarationExp)s.exp).declaration.dsymbolToBuffer(buf, hgs); 146| return; | } 670| if (s.exp) 670| s.exp.expressionToBuffer(buf, hgs); 670| buf.writeByte(';'); 670| if (!hgs.forStmtInit) 670| buf.writenl(); | } | | override void visit(CompileStatement s) | { 00000000| buf.writestring("mixin("); 00000000| argsToBuffer(s.exps, buf, hgs, null); 00000000| buf.writestring(");"); 00000000| if (!hgs.forStmtInit) 00000000| buf.writenl(); | } | | override void visit(CompoundStatement s) | { 8814| foreach (sx; *s.statements) | { 1570| if (sx) 1567| sx.accept(this); | } | } | | override void visit(CompoundDeclarationStatement s) | { 20| bool anywritten = false; 192| foreach (sx; *s.statements) | { 88| auto ds = sx ? sx.isExpStatement() : null; 88| if (ds && ds.exp.op == TOK.declaration) | { 44| auto d = (cast(DeclarationExp)ds.exp).declaration; 44| assert(d.isDeclaration()); 44| if (auto v = d.isVarDeclaration()) | { 44| scope ppv = new DsymbolPrettyPrintVisitor(buf, hgs); 44| ppv.visitVarDecl(v, anywritten); | } | else 00000000| d.dsymbolToBuffer(buf, hgs); 44| anywritten = true; | } | } 20| buf.writeByte(';'); 20| if (!hgs.forStmtInit) 12| buf.writenl(); | } | | override void visit(UnrolledLoopStatement s) | { 00000000| buf.writestring("/*unrolled*/ {"); 00000000| buf.writenl(); 00000000| buf.level++; 00000000| foreach (sx; *s.statements) | { 00000000| if (sx) 00000000| sx.accept(this); | } 00000000| buf.level--; 00000000| buf.writeByte('}'); 00000000| buf.writenl(); | } | | override void visit(ScopeStatement s) | { 220| buf.writeByte('{'); 220| buf.writenl(); 220| buf.level++; 220| if (s.statement) 220| s.statement.accept(this); 220| buf.level--; 220| buf.writeByte('}'); 220| buf.writenl(); | } | | override void visit(WhileStatement s) | { 8| buf.writestring("while ("); 8| s.condition.expressionToBuffer(buf, hgs); 8| buf.writeByte(')'); 8| buf.writenl(); 8| if (s._body) 8| s._body.accept(this); | } | | override void visit(DoStatement s) | { 8| buf.writestring("do"); 8| buf.writenl(); 8| if (s._body) 8| s._body.accept(this); 8| buf.writestring("while ("); 8| s.condition.expressionToBuffer(buf, hgs); 8| buf.writestring(");"); 8| buf.writenl(); | } | | override void visit(ForStatement s) | { 27| buf.writestring("for ("); 27| if (s._init) | { 16| hgs.forStmtInit++; 16| s._init.accept(this); 16| hgs.forStmtInit--; | } | else 11| buf.writeByte(';'); 27| if (s.condition) | { 19| buf.writeByte(' '); 19| s.condition.expressionToBuffer(buf, hgs); | } 27| buf.writeByte(';'); 27| if (s.increment) | { 19| buf.writeByte(' '); 19| s.increment.expressionToBuffer(buf, hgs); | } 27| buf.writeByte(')'); 27| buf.writenl(); 27| buf.writeByte('{'); 27| buf.writenl(); 27| buf.level++; 27| if (s._body) 24| s._body.accept(this); 27| buf.level--; 27| buf.writeByte('}'); 27| buf.writenl(); | } | | private void foreachWithoutBody(ForeachStatement s) | { 23| buf.writestring(Token.toString(s.op)); 23| buf.writestring(" ("); 161| foreach (i, p; *s.parameters) | { 23| if (i) 00000000| buf.writestring(", "); 23| if (stcToBuffer(buf, p.storageClass)) 9| buf.writeByte(' '); 23| if (p.type) 18| typeToBuffer(p.type, p.ident, buf, hgs); | else 5| buf.writestring(p.ident.toString()); | } 23| buf.writestring("; "); 23| s.aggr.expressionToBuffer(buf, hgs); 23| buf.writeByte(')'); 23| buf.writenl(); | } | | override void visit(ForeachStatement s) | { 23| foreachWithoutBody(s); 23| buf.writeByte('{'); 23| buf.writenl(); 23| buf.level++; 23| if (s._body) 23| s._body.accept(this); 23| buf.level--; 23| buf.writeByte('}'); 23| buf.writenl(); | } | | private void foreachRangeWithoutBody(ForeachRangeStatement s) | { 00000000| buf.writestring(Token.toString(s.op)); 00000000| buf.writestring(" ("); 00000000| if (s.prm.type) 00000000| typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); | else 00000000| buf.writestring(s.prm.ident.toString()); 00000000| buf.writestring("; "); 00000000| s.lwr.expressionToBuffer(buf, hgs); 00000000| buf.writestring(" .. "); 00000000| s.upr.expressionToBuffer(buf, hgs); 00000000| buf.writeByte(')'); 00000000| buf.writenl(); | } | | override void visit(ForeachRangeStatement s) | { 00000000| foreachRangeWithoutBody(s); 00000000| buf.writeByte('{'); 00000000| buf.writenl(); 00000000| buf.level++; 00000000| if (s._body) 00000000| s._body.accept(this); 00000000| buf.level--; 00000000| buf.writeByte('}'); 00000000| buf.writenl(); | } | | override void visit(StaticForeachStatement s) | { 00000000| buf.writestring("static "); 00000000| if (s.sfe.aggrfe) | { 00000000| visit(s.sfe.aggrfe); | } | else | { 00000000| assert(s.sfe.rangefe); 00000000| visit(s.sfe.rangefe); | } | } | | override void visit(ForwardingStatement s) | { 00000000| s.statement.accept(this); | } | | override void visit(IfStatement s) | { 58| buf.writestring("if ("); 58| if (Parameter p = s.prm) | { 22| StorageClass stc = p.storageClass; 35| if (!p.type && !stc) 00000000| stc = STC.auto_; 22| if (stcToBuffer(buf, stc)) 18| buf.writeByte(' '); 22| if (p.type) 9| typeToBuffer(p.type, p.ident, buf, hgs); | else 13| buf.writestring(p.ident.toString()); 22| buf.writestring(" = "); | } 58| s.condition.expressionToBuffer(buf, hgs); 58| buf.writeByte(')'); 58| buf.writenl(); 58| if (s.ifbody.isScopeStatement()) | { 34| s.ifbody.accept(this); | } | else | { 24| buf.level++; 24| s.ifbody.accept(this); 24| buf.level--; | } 58| if (s.elsebody) | { 32| buf.writestring("else"); 32| if (!s.elsebody.isIfStatement()) | { 24| buf.writenl(); | } | else | { 8| buf.writeByte(' '); | } 64| if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement()) | { 8| s.elsebody.accept(this); | } | else | { 24| buf.level++; 24| s.elsebody.accept(this); 24| buf.level--; | } | } | } | | override void visit(ConditionalStatement s) | { 25| s.condition.conditionToBuffer(buf, hgs); 25| buf.writenl(); 25| buf.writeByte('{'); 25| buf.writenl(); 25| buf.level++; 25| if (s.ifbody) 25| s.ifbody.accept(this); 25| buf.level--; 25| buf.writeByte('}'); 25| buf.writenl(); 25| if (s.elsebody) | { 17| buf.writestring("else"); 17| buf.writenl(); 17| buf.writeByte('{'); 17| buf.level++; 17| buf.writenl(); 17| s.elsebody.accept(this); 17| buf.level--; 17| buf.writeByte('}'); | } 25| buf.writenl(); | } | | override void visit(PragmaStatement s) | { 8| buf.writestring("pragma ("); 8| buf.writestring(s.ident.toString()); 16| if (s.args && s.args.dim) | { 8| buf.writestring(", "); 8| argsToBuffer(s.args, buf, hgs); | } 8| buf.writeByte(')'); 8| if (s._body) | { 00000000| buf.writenl(); 00000000| buf.writeByte('{'); 00000000| buf.writenl(); 00000000| buf.level++; 00000000| s._body.accept(this); 00000000| buf.level--; 00000000| buf.writeByte('}'); 00000000| buf.writenl(); | } | else | { 8| buf.writeByte(';'); 8| buf.writenl(); | } | } | | override void visit(StaticAssertStatement s) | { 00000000| s.sa.dsymbolToBuffer(buf, hgs); | } | | override void visit(SwitchStatement s) | { 24| buf.writestring(s.isFinal ? "final switch (" : "switch ("); 12| s.condition.expressionToBuffer(buf, hgs); 12| buf.writeByte(')'); 12| buf.writenl(); 12| if (s._body) | { 12| if (!s._body.isScopeStatement()) | { 00000000| buf.writeByte('{'); 00000000| buf.writenl(); 00000000| buf.level++; 00000000| s._body.accept(this); 00000000| buf.level--; 00000000| buf.writeByte('}'); 00000000| buf.writenl(); | } | else | { 12| s._body.accept(this); | } | } | } | | override void visit(CaseStatement s) | { 44| buf.writestring("case "); 44| s.exp.expressionToBuffer(buf, hgs); 44| buf.writeByte(':'); 44| buf.writenl(); 44| s.statement.accept(this); | } | | override void visit(CaseRangeStatement s) | { 00000000| buf.writestring("case "); 00000000| s.first.expressionToBuffer(buf, hgs); 00000000| buf.writestring(": .. case "); 00000000| s.last.expressionToBuffer(buf, hgs); 00000000| buf.writeByte(':'); 00000000| buf.writenl(); 00000000| s.statement.accept(this); | } | | override void visit(DefaultStatement s) | { 8| buf.writestring("default:"); 8| buf.writenl(); 8| s.statement.accept(this); | } | | override void visit(GotoDefaultStatement s) | { 8| buf.writestring("goto default;"); 8| buf.writenl(); | } | | override void visit(GotoCaseStatement s) | { 8| buf.writestring("goto case"); 8| if (s.exp) | { 8| buf.writeByte(' '); 8| s.exp.expressionToBuffer(buf, hgs); | } 8| buf.writeByte(';'); 8| buf.writenl(); | } | | override void visit(SwitchErrorStatement s) | { 00000000| buf.writestring("SwitchErrorStatement::toCBuffer()"); 00000000| buf.writenl(); | } | | override void visit(ReturnStatement s) | { 411| buf.writestring("return "); 411| if (s.exp) 409| s.exp.expressionToBuffer(buf, hgs); 411| buf.writeByte(';'); 411| buf.writenl(); | } | | override void visit(BreakStatement s) | { 44| buf.writestring("break"); 44| if (s.ident) | { 8| buf.writeByte(' '); 8| buf.writestring(s.ident.toString()); | } 44| buf.writeByte(';'); 44| buf.writenl(); | } | | override void visit(ContinueStatement s) | { 16| buf.writestring("continue"); 16| if (s.ident) | { 8| buf.writeByte(' '); 8| buf.writestring(s.ident.toString()); | } 16| buf.writeByte(';'); 16| buf.writenl(); | } | | override void visit(SynchronizedStatement s) | { 16| buf.writestring("synchronized"); 16| if (s.exp) | { 8| buf.writeByte('('); 8| s.exp.expressionToBuffer(buf, hgs); 8| buf.writeByte(')'); | } 16| if (s._body) | { 16| buf.writeByte(' '); 16| s._body.accept(this); | } | } | | override void visit(WithStatement s) | { 8| buf.writestring("with ("); 8| s.exp.expressionToBuffer(buf, hgs); 8| buf.writestring(")"); 8| buf.writenl(); 8| if (s._body) 8| s._body.accept(this); | } | | override void visit(TryCatchStatement s) | { 16| buf.writestring("try"); 16| buf.writenl(); 16| if (s._body) | { 16| if (s._body.isScopeStatement()) | { 8| s._body.accept(this); | } | else | { 8| buf.level++; 8| s._body.accept(this); 8| buf.level--; | } | } 96| foreach (c; *s.catches) | { 16| visit(c); | } | } | | override void visit(TryFinallyStatement s) | { 16| buf.writestring("try"); 16| buf.writenl(); 16| buf.writeByte('{'); 16| buf.writenl(); 16| buf.level++; 16| s._body.accept(this); 16| buf.level--; 16| buf.writeByte('}'); 16| buf.writenl(); 16| buf.writestring("finally"); 16| buf.writenl(); 16| if (s.finalbody.isScopeStatement()) | { 8| s.finalbody.accept(this); | } | else | { 8| buf.level++; 8| s.finalbody.accept(this); 8| buf.level--; | } | } | | override void visit(ScopeGuardStatement s) | { 25| buf.writestring(Token.toString(s.tok)); 25| buf.writeByte(' '); 25| if (s.statement) 24| s.statement.accept(this); | } | | override void visit(ThrowStatement s) | { 00000000| buf.writestring("throw "); 00000000| s.exp.expressionToBuffer(buf, hgs); 00000000| buf.writeByte(';'); 00000000| buf.writenl(); | } | | override void visit(DebugStatement s) | { 00000000| if (s.statement) | { 00000000| s.statement.accept(this); | } | } | | override void visit(GotoStatement s) | { 1| buf.writestring("goto "); 1| buf.writestring(s.ident.toString()); 1| buf.writeByte(';'); 1| buf.writenl(); | } | | override void visit(LabelStatement s) | { 9| buf.writestring(s.ident.toString()); 9| buf.writeByte(':'); 9| buf.writenl(); 9| if (s.statement) 9| s.statement.accept(this); | } | | override void visit(AsmStatement s) | { 16| buf.writestring("asm { "); 16| Token* t = s.tokens; 16| buf.level++; 56| while (t) | { 40| buf.writestring(t.toChars()); 40| if (t.next && 24| t.value != TOK.min && 40| t.value != TOK.comma && t.next.value != TOK.comma && 16| t.value != TOK.leftBracket && t.next.value != TOK.leftBracket && 8| t.next.value != TOK.rightBracket && 16| t.value != TOK.leftParentheses && t.next.value != TOK.leftParentheses && 8| t.next.value != TOK.rightParentheses && 16| t.value != TOK.dot && t.next.value != TOK.dot) | { 8| buf.writeByte(' '); | } 40| t = t.next; | } 16| buf.level--; 16| buf.writestring("; }"); 16| buf.writenl(); | } | | override void visit(ImportStatement s) | { 48| foreach (imp; *s.imports) | { 8| imp.dsymbolToBuffer(buf, hgs); | } | } | | void visit(Catch c) | { 16| buf.writestring("catch"); 16| if (c.type) | { 16| buf.writeByte('('); 16| typeToBuffer(c.type, c.ident, buf, hgs); 16| buf.writeByte(')'); | } 16| buf.writenl(); 16| buf.writeByte('{'); 16| buf.writenl(); 16| buf.level++; 16| if (c.handler) 16| c.handler.accept(this); 16| buf.level--; 16| buf.writeByte('}'); 16| buf.writenl(); | } |} | |private void dsymbolToBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) |{ 16450| scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 16450| s.accept(v); |} | |private extern (C++) final class DsymbolPrettyPrintVisitor : Visitor |{ | alias visit = Visitor.visit; |public: | OutBuffer* buf; | HdrGenState* hgs; | 168517| extern (D) this(OutBuffer* buf, HdrGenState* hgs) | { 168517| this.buf = buf; 168517| this.hgs = hgs; | } | | //////////////////////////////////////////////////////////////////////////// | | override void visit(Dsymbol s) | { 00000000| buf.writestring(s.toChars()); | } | | override void visit(StaticAssert s) | { 8| buf.writestring(s.kind()); 8| buf.writeByte('('); 8| s.exp.expressionToBuffer(buf, hgs); 8| if (s.msg) | { 8| buf.writestring(", "); 8| s.msg.expressionToBuffer(buf, hgs); | } 8| buf.writestring(");"); 8| buf.writenl(); | } | | override void visit(DebugSymbol s) | { 00000000| buf.writestring("debug = "); 00000000| if (s.ident) 00000000| buf.writestring(s.ident.toString()); | else 00000000| buf.print(s.level); 00000000| buf.writeByte(';'); 00000000| buf.writenl(); | } | | override void visit(VersionSymbol s) | { 00000000| buf.writestring("version = "); 00000000| if (s.ident) 00000000| buf.writestring(s.ident.toString()); | else 00000000| buf.print(s.level); 00000000| buf.writeByte(';'); 00000000| buf.writenl(); | } | | override void visit(EnumMember em) | { 24| if (em.type) 00000000| typeToBuffer(em.type, em.ident, buf, hgs); | else 24| buf.writestring(em.ident.toString()); 24| if (em.value) | { 00000000| buf.writestring(" = "); 00000000| em.value.expressionToBuffer(buf, hgs); | } | } | | override void visit(Import imp) | { 71| if (hgs.hdrgen && imp.id == Id.object) 00000000| return; // object is imported by default 44| if (imp.isstatic) 00000000| buf.writestring("static "); 44| buf.writestring("import "); 44| if (imp.aliasId) | { 2| buf.printf("%s = ", imp.aliasId.toChars()); | } 85| if (imp.packages && imp.packages.dim) | { 342| foreach (const pid; *imp.packages) | { 73| buf.printf("%s.", pid.toChars()); | } | } 44| buf.writestring(imp.id.toString()); 44| if (imp.names.dim) | { 24| buf.writestring(" : "); 248| foreach (const i, const name; imp.names) | { 44| if (i) 20| buf.writestring(", "); 44| const _alias = imp.aliases[i]; 44| if (_alias) 22| buf.printf("%s = %s", _alias.toChars(), name.toChars()); | else 22| buf.writestring(name.toChars()); | } | } 44| buf.writeByte(';'); 44| buf.writenl(); | } | | override void visit(AliasThis d) | { 00000000| buf.writestring("alias "); 00000000| buf.writestring(d.ident.toString()); 00000000| buf.writestring(" this;\n"); | } | | override void visit(AttribDeclaration d) | { 86| if (!d.decl) | { 24| buf.writeByte(';'); 24| buf.writenl(); 24| return; | } 62| if (d.decl.dim == 0) 00000000| buf.writestring("{}"); 171| else if (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration()) | { | // hack for bugzilla 8081 24| buf.writestring("{}"); | } 38| else if (d.decl.dim == 1) | { 26| (*d.decl)[0].accept(this); 26| return; | } | else | { 12| buf.writenl(); 12| buf.writeByte('{'); 12| buf.writenl(); 12| buf.level++; 162| foreach (de; *d.decl) 42| de.accept(this); 12| buf.level--; 12| buf.writeByte('}'); | } 36| buf.writenl(); | } | | override void visit(StorageClassDeclaration d) | { 10| if (stcToBuffer(buf, d.stc)) 10| buf.writeByte(' '); 10| visit(cast(AttribDeclaration)d); | } | | override void visit(DeprecatedDeclaration d) | { 00000000| buf.writestring("deprecated("); 00000000| d.msg.expressionToBuffer(buf, hgs); 00000000| buf.writestring(") "); 00000000| visit(cast(AttribDeclaration)d); | } | | override void visit(LinkDeclaration d) | { 9| buf.writestring("extern ("); 9| buf.writestring(linkageToString(d.linkage)); 9| buf.writestring(") "); 9| visit(cast(AttribDeclaration)d); | } | | override void visit(CPPMangleDeclaration d) | { 00000000| string s; 00000000| final switch (d.cppmangle) | { 00000000| case CPPMANGLE.asClass: 00000000| s = "class"; 00000000| break; 00000000| case CPPMANGLE.asStruct: 00000000| s = "struct"; 00000000| break; 00000000| case CPPMANGLE.def: 00000000| break; | } 00000000| buf.writestring("extern (C++, "); 00000000| buf.writestring(s); 00000000| buf.writestring(") "); 00000000| visit(cast(AttribDeclaration)d); | } | | override void visit(ProtDeclaration d) | { 28| protectionToBuffer(buf, d.protection); 28| buf.writeByte(' '); 28| AttribDeclaration ad = cast(AttribDeclaration)d; 55| if (ad.decl.dim == 1 && (*ad.decl)[0].isProtDeclaration) 2| visit(cast(AttribDeclaration)(*ad.decl)[0]); | else 26| visit(cast(AttribDeclaration)d); | } | | override void visit(AlignDeclaration d) | { 14| buf.writestring("align "); 14| if (d.ealign) 4| buf.printf("(%s) ", d.ealign.toChars()); 14| visit(cast(AttribDeclaration)d); | } | | override void visit(AnonDeclaration d) | { 00000000| buf.writestring(d.isunion ? "union" : "struct"); 00000000| buf.writenl(); 00000000| buf.writestring("{"); 00000000| buf.writenl(); 00000000| buf.level++; 00000000| if (d.decl) | { 00000000| foreach (de; *d.decl) 00000000| de.accept(this); | } 00000000| buf.level--; 00000000| buf.writestring("}"); 00000000| buf.writenl(); | } | | override void visit(PragmaDeclaration d) | { 24| buf.writestring("pragma ("); 24| buf.writestring(d.ident.toString()); 48| if (d.args && d.args.dim) | { 24| buf.writestring(", "); 24| argsToBuffer(d.args, buf, hgs); | } 24| buf.writeByte(')'); 24| visit(cast(AttribDeclaration)d); | } | | override void visit(ConditionalDeclaration d) | { 9| d.condition.conditionToBuffer(buf, hgs); 9| if (d.decl || d.elsedecl) | { 9| buf.writenl(); 9| buf.writeByte('{'); 9| buf.writenl(); 9| buf.level++; 9| if (d.decl) | { 150| foreach (de; *d.decl) 41| de.accept(this); | } 9| buf.level--; 9| buf.writeByte('}'); 9| if (d.elsedecl) | { 00000000| buf.writenl(); 00000000| buf.writestring("else"); 00000000| buf.writenl(); 00000000| buf.writeByte('{'); 00000000| buf.writenl(); 00000000| buf.level++; 00000000| foreach (de; *d.elsedecl) 00000000| de.accept(this); 00000000| buf.level--; 00000000| buf.writeByte('}'); | } | } | else 00000000| buf.writeByte(':'); 9| buf.writenl(); | } | | override void visit(StaticForeachDeclaration s) | { | void foreachWithoutBody(ForeachStatement s) | { 1| buf.writestring(Token.toString(s.op)); 1| buf.writestring(" ("); 7| foreach (i, p; *s.parameters) | { 1| if (i) 00000000| buf.writestring(", "); 1| if (stcToBuffer(buf, p.storageClass)) 1| buf.writeByte(' '); 1| if (p.type) 00000000| typeToBuffer(p.type, p.ident, buf, hgs); | else 1| buf.writestring(p.ident.toString()); | } 1| buf.writestring("; "); 1| s.aggr.expressionToBuffer(buf, hgs); 1| buf.writeByte(')'); 1| buf.writenl(); | } | | void foreachRangeWithoutBody(ForeachRangeStatement s) | { | /* s.op ( prm ; lwr .. upr ) | */ 00000000| buf.writestring(Token.toString(s.op)); 00000000| buf.writestring(" ("); 00000000| if (s.prm.type) 00000000| typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); | else 00000000| buf.writestring(s.prm.ident.toString()); 00000000| buf.writestring("; "); 00000000| s.lwr.expressionToBuffer(buf, hgs); 00000000| buf.writestring(" .. "); 00000000| s.upr.expressionToBuffer(buf, hgs); 00000000| buf.writeByte(')'); 00000000| buf.writenl(); | } | 1| buf.writestring("static "); 1| if (s.sfe.aggrfe) | { 1| foreachWithoutBody(s.sfe.aggrfe); | } | else | { 00000000| assert(s.sfe.rangefe); 00000000| foreachRangeWithoutBody(s.sfe.rangefe); | } 1| buf.writeByte('{'); 1| buf.writenl(); 1| buf.level++; 1| visit(cast(AttribDeclaration)s); 1| buf.level--; 1| buf.writeByte('}'); 1| buf.writenl(); | | } | | override void visit(CompileDeclaration d) | { 1| buf.writestring("mixin("); 1| argsToBuffer(d.exps, buf, hgs, null); 1| buf.writestring(");"); 1| buf.writenl(); | } | | override void visit(UserAttributeDeclaration d) | { 00000000| buf.writestring("@("); 00000000| argsToBuffer(d.atts, buf, hgs); 00000000| buf.writeByte(')'); 00000000| visit(cast(AttribDeclaration)d); | } | | override void visit(TemplateDeclaration d) | { | version (none) | { | // Should handle template functions for doc generation | if (onemember && onemember.isFuncDeclaration()) | buf.writestring("foo "); | } 945| if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d)) 167| return; 304| if (hgs.ddoc) 74| buf.writestring(d.kind()); | else 230| buf.writestring("template"); 304| buf.writeByte(' '); 304| buf.writestring(d.ident.toString()); 304| buf.writeByte('('); 608| visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); 304| buf.writeByte(')'); 304| visitTemplateConstraint(d.constraint); 380| if (hgs.hdrgen || hgs.fullDump) | { 230| hgs.tpltMember++; 230| buf.writenl(); 230| buf.writeByte('{'); 230| buf.writenl(); 230| buf.level++; 834| foreach (s; *d.members) 48| s.accept(this); 230| buf.level--; 230| buf.writeByte('}'); 230| buf.writenl(); 230| hgs.tpltMember--; | } | } | | bool visitEponymousMember(TemplateDeclaration d) | { 794| if (!d.members || d.members.dim != 1) 202| return false; 195| Dsymbol onemember = (*d.members)[0]; 195| if (onemember.ident != d.ident) 25| return false; 170| if (FuncDeclaration fd = onemember.isFuncDeclaration()) | { 111| assert(fd.type); 111| if (stcToBuffer(buf, fd.storage_class)) 16| buf.writeByte(' '); 111| functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); 111| visitTemplateConstraint(d.constraint); 111| hgs.tpltMember++; 111| bodyToBuffer(fd); 111| hgs.tpltMember--; 111| return true; | } 59| if (AggregateDeclaration ad = onemember.isAggregateDeclaration()) | { 46| buf.writestring(ad.kind()); 46| buf.writeByte(' '); 46| buf.writestring(ad.ident.toString()); 46| buf.writeByte('('); 92| visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); 46| buf.writeByte(')'); 46| visitTemplateConstraint(d.constraint); 46| visitBaseClasses(ad.isClassDeclaration()); 46| hgs.tpltMember++; 46| if (ad.members) | { 46| buf.writenl(); 46| buf.writeByte('{'); 46| buf.writenl(); 46| buf.level++; 270| foreach (s; *ad.members) 44| s.accept(this); 46| buf.level--; 46| buf.writeByte('}'); | } | else 00000000| buf.writeByte(';'); 46| buf.writenl(); 46| hgs.tpltMember--; 46| return true; | } 13| if (VarDeclaration vd = onemember.isVarDeclaration()) | { 12| if (d.constraint) 2| return false; 10| if (stcToBuffer(buf, vd.storage_class)) 8| buf.writeByte(' '); 10| if (vd.type) 6| typeToBuffer(vd.type, vd.ident, buf, hgs); | else 4| buf.writestring(vd.ident.toString()); 10| buf.writeByte('('); 20| visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters); 10| buf.writeByte(')'); 10| if (vd._init) | { 10| buf.writestring(" = "); 10| ExpInitializer ie = vd._init.isExpInitializer(); 30| if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) 00000000| (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); | else 10| vd._init.initializerToBuffer(buf, hgs); | } 10| buf.writeByte(';'); 10| buf.writenl(); 10| return true; | } 1| return false; | } | | void visitTemplateParameters(TemplateParameters* parameters) | { 752| if (!parameters || !parameters.dim) 14| return; 2642| foreach (i, p; *parameters) | { 389| if (i) 27| buf.writestring(", "); 389| p.templateParameterToBuffer(buf, hgs); | } | } | | void visitTemplateConstraint(Expression constraint) | { 461| if (!constraint) 249| return; 212| buf.writestring(" if ("); 212| constraint.expressionToBuffer(buf, hgs); 212| buf.writeByte(')'); | } | | override void visit(TemplateInstance ti) | { 164783| buf.writestring(ti.name.toChars()); 164783| tiargsToBuffer(ti, buf, hgs); | 164783| if (hgs.fullDump) | { 5| buf.writenl(); 5| dumpTemplateInstance(ti, buf, hgs); | } | } | | override void visit(TemplateMixin tm) | { 42| buf.writestring("mixin "); 42| typeToBuffer(tm.tqual, null, buf, hgs); 42| tiargsToBuffer(tm, buf, hgs); 84| if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0) | { 41| buf.writeByte(' '); 41| buf.writestring(tm.ident.toString()); | } 42| buf.writeByte(';'); 42| buf.writenl(); 42| if (hgs.fullDump) 1| dumpTemplateInstance(tm, buf, hgs); | } | | override void visit(EnumDeclaration d) | { 17| auto oldInEnumDecl = hgs.inEnumDecl; 17| scope(exit) hgs.inEnumDecl = oldInEnumDecl; 17| hgs.inEnumDecl = d; 17| buf.writestring("enum "); 17| if (d.ident) | { 17| buf.writestring(d.ident.toString()); 17| buf.writeByte(' '); | } 17| if (d.memtype) | { 1| buf.writestring(": "); 1| typeToBuffer(d.memtype, null, buf, hgs); | } 17| if (!d.members) | { 9| buf.writeByte(';'); 9| buf.writenl(); 9| return; | } 8| buf.writenl(); 8| buf.writeByte('{'); 8| buf.writenl(); 8| buf.level++; 96| foreach (em; *d.members) | { 24| if (!em) 00000000| continue; 24| em.accept(this); 24| buf.writeByte(','); 24| buf.writenl(); | } 8| buf.level--; 8| buf.writeByte('}'); 8| buf.writenl(); | } | | override void visit(Nspace d) | { 00000000| buf.writestring("extern (C++, "); 00000000| buf.writestring(d.ident.toString()); 00000000| buf.writeByte(')'); 00000000| buf.writenl(); 00000000| buf.writeByte('{'); 00000000| buf.writenl(); 00000000| buf.level++; 00000000| foreach (s; *d.members) 00000000| s.accept(this); 00000000| buf.level--; 00000000| buf.writeByte('}'); 00000000| buf.writenl(); | } | | override void visit(StructDeclaration d) | { 58| buf.writestring(d.kind()); 58| buf.writeByte(' '); 58| if (!d.isAnonymous()) 58| buf.writestring(d.toChars()); 58| if (!d.members) | { 00000000| buf.writeByte(';'); 00000000| buf.writenl(); 00000000| return; | } 58| buf.writenl(); 58| buf.writeByte('{'); 58| buf.writenl(); 58| buf.level++; 462| foreach (s; *d.members) 96| s.accept(this); 58| buf.level--; 58| buf.writeByte('}'); 58| buf.writenl(); | } | | override void visit(ClassDeclaration d) | { 123| if (!d.isAnonymous()) | { 119| buf.writestring(d.kind()); 119| buf.writeByte(' '); 119| buf.writestring(d.ident.toString()); | } 123| visitBaseClasses(d); 123| if (d.members) | { 121| buf.writenl(); 121| buf.writeByte('{'); 121| buf.writenl(); 121| buf.level++; 1977| foreach (s; *d.members) 538| s.accept(this); 121| buf.level--; 121| buf.writeByte('}'); | } | else 2| buf.writeByte(';'); 123| buf.writenl(); | } | | void visitBaseClasses(ClassDeclaration d) | { 302| if (!d || !d.baseclasses.dim) 136| return; 33| if (!d.isAnonymous()) 29| buf.writestring(" : "); 279| foreach (i, b; *d.baseclasses) | { 45| if (i) 12| buf.writestring(", "); 45| typeToBuffer(b.type, null, buf, hgs); | } | } | | override void visit(AliasDeclaration d) | { 149| if (d.storage_class & STC.local) 00000000| return; 149| buf.writestring("alias "); 149| if (d.aliassym) | { 16| buf.writestring(d.ident.toString()); 16| buf.writestring(" = "); 16| if (stcToBuffer(buf, d.storage_class)) 00000000| buf.writeByte(' '); 16| d.aliassym.accept(this); | } 133| else if (d.type.ty == Tfunction) | { 8| if (stcToBuffer(buf, d.storage_class)) 00000000| buf.writeByte(' '); 8| typeToBuffer(d.type, d.ident, buf, hgs); | } 125| else if (d.ident) | { 372| hgs.declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring); 124| buf.writestring(d.ident.toString()); 124| buf.writestring(" = "); 124| if (stcToBuffer(buf, d.storage_class)) 8| buf.writeByte(' '); 124| typeToBuffer(d.type, null, buf, hgs); 124| hgs.declstring = false; | } 149| buf.writeByte(';'); 149| buf.writenl(); | } | | override void visit(VarDeclaration d) | { 274| if (d.storage_class & STC.local) 3| return; 271| visitVarDecl(d, false); 271| buf.writeByte(';'); 271| buf.writenl(); | } | | void visitVarDecl(VarDeclaration v, bool anywritten) | { 315| if (anywritten) | { 24| buf.writestring(", "); 24| buf.writestring(v.ident.toString()); | } | else | { 291| if (stcToBuffer(buf, v.storage_class)) 84| buf.writeByte(' '); 291| if (v.type) 224| typeToBuffer(v.type, v.ident, buf, hgs); | else 67| buf.writestring(v.ident.toString()); | } 315| if (v._init) | { 155| buf.writestring(" = "); 155| auto ie = v._init.isExpInitializer(); 385| if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) 19| (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); | else 136| v._init.initializerToBuffer(buf, hgs); | } | } | | override void visit(FuncDeclaration f) | { | //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); 594| if (stcToBuffer(buf, f.storage_class)) 29| buf.writeByte(' '); 594| auto tf = cast(TypeFunction)f.type; 594| typeToBuffer(tf, f.ident, buf, hgs); | 594| if (hgs.hdrgen) | { | // if the return type is missing (e.g. ref functions or auto) 1077| if (!tf.next || f.storage_class & STC.auto_) | { 87| hgs.autoMember++; 87| bodyToBuffer(f); 87| hgs.autoMember--; | } 950| else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions) | { 236| buf.writeByte(';'); 236| buf.writenl(); | } | else 259| bodyToBuffer(f); | } | else 12| bodyToBuffer(f); | } | | void bodyToBuffer(FuncDeclaration f) | { 2858| if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember)) | { 30| buf.writeByte(';'); 30| buf.writenl(); 30| return; | } 1030| const savetlpt = hgs.tpltMember; 1030| const saveauto = hgs.autoMember; 1030| hgs.tpltMember = 0; 1030| hgs.autoMember = 0; 1030| buf.writenl(); 1030| bool requireDo = false; | // in{} 1030| if (f.frequires) | { 153| foreach (frequire; *f.frequires) | { 30| buf.writestring("in"); 30| if (auto es = frequire.isExpStatement()) | { 34| assert(es.exp && es.exp.op == TOK.assert_); 17| buf.writestring(" ("); 17| (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); 17| buf.writeByte(')'); 17| buf.writenl(); 17| requireDo = false; | } | else | { 13| buf.writenl(); 13| frequire.statementToBuffer(buf, hgs); 13| requireDo = true; | } | } | } | // out{} 1030| if (f.fensures) | { 231| foreach (fensure; *f.fensures) | { 56| buf.writestring("out"); 56| if (auto es = fensure.ensure.isExpStatement()) | { 68| assert(es.exp && es.exp.op == TOK.assert_); 34| buf.writestring(" ("); 34| if (fensure.id) | { 17| buf.writestring(fensure.id.toString()); | } 34| buf.writestring("; "); 34| (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); 34| buf.writeByte(')'); 34| buf.writenl(); 34| requireDo = false; | } | else | { 22| if (fensure.id) | { 13| buf.writeByte('('); 13| buf.writestring(fensure.id.toString()); 13| buf.writeByte(')'); | } 22| buf.writenl(); 22| fensure.ensure.statementToBuffer(buf, hgs); 22| requireDo = true; | } | } | } 1030| if (requireDo) | { 12| buf.writestring("do"); 12| buf.writenl(); | } 1030| buf.writeByte('{'); 1030| buf.writenl(); 1030| buf.level++; 1030| f.fbody.statementToBuffer(buf, hgs); 1030| buf.level--; 1030| buf.writeByte('}'); 1030| buf.writenl(); 1030| hgs.tpltMember = savetlpt; 1030| hgs.autoMember = saveauto; | } | | override void visit(FuncLiteralDeclaration f) | { 2445| if (f.type.ty == Terror) | { 789| buf.writestring("__error"); 789| return; | } 1656| if (f.tok != TOK.reserved) | { 640| buf.writestring(f.kind()); 640| buf.writeByte(' '); | } 1656| TypeFunction tf = cast(TypeFunction)f.type; | 2080| if (!f.inferRetType && tf.next) 424| typeToBuffer(tf.next, null, buf, hgs); 1656| parametersToBuffer(tf.parameterList, buf, hgs); | | // https://issues.dlang.org/show_bug.cgi?id=20074 | void printAttribute(string str) | { 741| buf.writeByte(' '); 741| buf.writestring(str); | } 1656| tf.attributesApply(&printAttribute); | | 1656| CompoundStatement cs = f.fbody.isCompoundStatement(); 1656| Statement s1; 1861| if (f.semanticRun >= PASS.semantic3done && cs) | { 204| s1 = (*cs.statements)[cs.statements.dim - 1]; | } | else 2904| s1 = !cs ? f.fbody : null; 3312| ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null; 2764| if (rs && rs.exp) | { 1106| buf.writestring(" => "); 1106| rs.exp.expressionToBuffer(buf, hgs); | } | else | { 550| hgs.tpltMember++; 550| bodyToBuffer(f); 550| hgs.tpltMember--; | } | } | | override void visit(PostBlitDeclaration d) | { 10| if (stcToBuffer(buf, d.storage_class)) 8| buf.writeByte(' '); 10| buf.writestring("this(this)"); 10| bodyToBuffer(d); | } | | override void visit(DtorDeclaration d) | { 20| if (d.storage_class & STC.trusted) 10| buf.writestring("@trusted "); 20| if (d.storage_class & STC.safe) 10| buf.writestring("@safe "); 20| if (d.storage_class & STC.nogc) 10| buf.writestring("@nogc "); 20| if (d.storage_class & STC.disable) 10| buf.writestring("@disable "); | 20| buf.writestring("~this()"); 20| bodyToBuffer(d); | } | | override void visit(StaticCtorDeclaration d) | { 48| if (stcToBuffer(buf, d.storage_class & ~STC.static_)) 32| buf.writeByte(' '); 48| if (d.isSharedStaticCtorDeclaration()) 20| buf.writestring("shared "); 48| buf.writestring("static this()"); 96| if (hgs.hdrgen && !hgs.tpltMember) | { 40| buf.writeByte(';'); 40| buf.writenl(); | } | else 8| bodyToBuffer(d); | } | | override void visit(StaticDtorDeclaration d) | { 40| if (stcToBuffer(buf, d.storage_class & ~STC.static_)) 32| buf.writeByte(' '); 40| if (d.isSharedStaticDtorDeclaration()) 16| buf.writestring("shared "); 40| buf.writestring("static ~this()"); 80| if (hgs.hdrgen && !hgs.tpltMember) | { 40| buf.writeByte(';'); 40| buf.writenl(); | } | else 00000000| bodyToBuffer(d); | } | | override void visit(InvariantDeclaration d) | { 19| if (hgs.hdrgen) 16| return; 3| if (stcToBuffer(buf, d.storage_class)) 00000000| buf.writeByte(' '); 3| buf.writestring("invariant"); 3| if(auto es = d.fbody.isExpStatement()) | { 00000000| assert(es.exp && es.exp.op == TOK.assert_); 00000000| buf.writestring(" ("); 00000000| (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); 00000000| buf.writestring(");"); 00000000| buf.writenl(); | } | else | { 3| bodyToBuffer(d); | } | } | | override void visit(UnitTestDeclaration d) | { 24| if (hgs.hdrgen) 24| return; 00000000| if (stcToBuffer(buf, d.storage_class)) 00000000| buf.writeByte(' '); 00000000| buf.writestring("unittest"); 00000000| bodyToBuffer(d); | } | | override void visit(NewDeclaration d) | { 00000000| if (stcToBuffer(buf, d.storage_class & ~STC.static_)) 00000000| buf.writeByte(' '); 00000000| buf.writestring("new"); 00000000| parametersToBuffer(d.parameterList, buf, hgs); 00000000| bodyToBuffer(d); | } | | override void visit(Module m) | { 43| moduleToBuffer2(m, buf, hgs); | } |} | |private extern (C++) final class ExpressionPrettyPrintVisitor : Visitor |{ | alias visit = Visitor.visit; |public: | OutBuffer* buf; | HdrGenState* hgs; | 189226| extern (D) this(OutBuffer* buf, HdrGenState* hgs) | { 189226| this.buf = buf; 189226| this.hgs = hgs; | } | | //////////////////////////////////////////////////////////////////////////// | override void visit(Expression e) | { 00000000| buf.writestring(Token.toString(e.op)); | } | | override void visit(IntegerExp e) | { 123866| const dinteger_t v = e.toInteger(); 123866| if (e.type) | { 123866| Type t = e.type; | L1: 130716| switch (t.ty) | { 6850| case Tenum: | { 6850| TypeEnum te = cast(TypeEnum)t; 6850| if (hgs.fullDump) | { 1| auto sym = te.sym; 1| if (hgs.inEnumDecl && sym && hgs.inEnumDecl != sym) foreach(i;0 .. sym.members.dim) | { 00000000| EnumMember em = cast(EnumMember) (*sym.members)[i]; 00000000| if (em.value.toInteger == v) | { 00000000| buf.printf("%s.%s", sym.toChars(), em.ident.toChars()); 00000000| return ; | } | } | //assert(0, "We could not find the EmumMember");// for some reason it won't append char* ~ e.toChars() ~ " in " ~ sym.toChars() ); | } | 6850| buf.printf("cast(%s)", te.sym.toChars()); 6850| t = te.sym.memtype; 6850| goto L1; | } 00000000| case Twchar: | // BUG: need to cast(wchar) 8| case Tdchar: | // BUG: need to cast(dchar) 8| if (cast(uinteger_t)v > 0xFF) | { 8| buf.printf("'\\U%08llx'", cast(long)v); 8| break; | } 00000000| goto case; 116| case Tchar: | { 116| size_t o = buf.length; 116| if (v == '\'') 8| buf.writestring("'\\''"); 214| else if (isprint(cast(int)v) && v != '\\') 106| buf.printf("'%c'", cast(int)v); | else 2| buf.printf("'\\x%02x'", cast(int)v); 116| if (hgs.ddoc) 1| escapeDdocString(buf, o); 116| break; | } 531| case Tint8: 531| buf.writestring("cast(byte)"); 531| goto L2; 272| case Tint16: 272| buf.writestring("cast(short)"); 272| goto L2; 32342| case Tint32: | L2: 33145| buf.printf("%d", cast(int)v); 33145| break; 1106| case Tuns8: 1106| buf.writestring("cast(ubyte)"); 1106| goto case Tuns32; 273| case Tuns16: 273| buf.writestring("cast(ushort)"); 273| goto case Tuns32; 3963| case Tuns32: 3963| buf.printf("%uu", cast(uint)v); 3963| break; 169| case Tint64: 169| buf.printf("%lldL", v); 169| break; 76378| case Tuns64: 76378| buf.printf("%lluLU", v); 76378| break; 10087| case Tbool: 20174| buf.writestring(v ? "true" : "false"); 10087| break; 6| case Tpointer: 6| buf.writestring("cast("); 6| buf.writestring(t.toChars()); 6| buf.writeByte(')'); 6| if (target.ptrsize == 8) 6| goto case Tuns64; | else 00000000| goto case Tuns32; 00000000| default: | /* This can happen if errors, such as | * the type is painted on like in fromConstInitializer(). | */ 00000000| if (!global.errors) | { 00000000| assert(0); | } 00000000| break; | } | } 00000000| else if (v & 0x8000000000000000L) 00000000| buf.printf("0x%llx", v); | else 00000000| buf.print(v); | } | | override void visit(ErrorExp e) | { 38| buf.writestring("__error"); | } | | override void visit(VoidInitExp e) | { 00000000| buf.writestring("__void"); | } | | 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. */ 426| const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; 426| char[BUFFER_LEN] buffer; 426| CTFloat.sprint(buffer.ptr, 'g', value); 426| assert(strlen(buffer.ptr) < BUFFER_LEN); 426| if (hgs.hdrgen) | { 7| real_t r = CTFloat.parse(buffer.ptr); 7| if (r != value) // if exact duplication 00000000| CTFloat.sprint(buffer.ptr, 'a', value); | } 426| buf.writestring(buffer.ptr); 426| if (buffer.ptr[strlen(buffer.ptr) - 1] == '.') 00000000| buf.remove(buf.length() - 1, 1); | 426| if (type) | { 426| Type t = type.toBasetype(); 426| switch (t.ty) | { 184| case Tfloat32: 188| case Timaginary32: 192| case Tcomplex32: 192| buf.writeByte('F'); 192| break; 44| case Tfloat80: 48| case Timaginary80: 52| case Tcomplex80: 52| buf.writeByte('L'); 52| break; 182| default: 182| break; | } 426| if (t.isimaginary()) 23| buf.writeByte('i'); | } | } | | override void visit(RealExp e) | { 410| floatToBuffer(e.type, e.value); | } | | override void visit(ComplexExp e) | { | /* Print as: | * (re+imi) | */ 8| buf.writeByte('('); 8| floatToBuffer(e.type, creall(e.value)); 8| buf.writeByte('+'); 8| floatToBuffer(e.type, cimagl(e.value)); 8| buf.writestring("i)"); | } | | override void visit(IdentifierExp e) | { 4736| if (hgs.hdrgen || hgs.ddoc) 585| buf.writestring(e.ident.toHChars2()); | else 2061| buf.writestring(e.ident.toString()); | } | | override void visit(DsymbolExp e) | { 1| buf.writestring(e.s.toChars()); | } | | override void visit(ThisExp e) | { 463| buf.writestring("this"); | } | | override void visit(SuperExp e) | { 7| buf.writestring("super"); | } | | override void visit(NullExp e) | { 114| buf.writestring("null"); | } | | override void visit(StringExp e) | { 8756| buf.writeByte('"'); 8756| const o = buf.length; 22247180| for (size_t i = 0; i < e.len; i++) | { 11114834| const c = e.charAt(i); 11114834| switch (c) | { 56| case '"': 128| case '\\': 128| buf.writeByte('\\'); 128| goto default; 11114834| default: 11114834| if (c <= 0xFF) | { 22229661| if (c <= 0x7F && isprint(c)) 11114411| buf.writeByte(c); | else 423| buf.printf("\\x%02x", c); | } 00000000| else if (c <= 0xFFFF) 00000000| buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); | else 00000000| buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); 11114834| break; | } | } 8756| if (hgs.ddoc) 5| escapeDdocString(buf, o); 8756| buf.writeByte('"'); 8756| if (e.postfix) 26| buf.writeByte(e.postfix); | } | | override void visit(ArrayLiteralExp e) | { 2704| buf.writeByte('['); 2704| argsToBuffer(e.elements, buf, hgs, e.basis); 2704| buf.writeByte(']'); | } | | override void visit(AssocArrayLiteralExp e) | { 6| buf.writeByte('['); 46| foreach (i, key; *e.keys) | { 7| if (i) 1| buf.writestring(", "); 7| expToBuffer(key, PREC.assign, buf, hgs); 7| buf.writeByte(':'); 7| auto value = (*e.values)[i]; 7| expToBuffer(value, PREC.assign, buf, hgs); | } 6| buf.writeByte(']'); | } | | override void visit(StructLiteralExp e) | { 213| buf.writestring(e.sd.toChars()); 213| 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); 213| if (e.stageflags & stageToCBuffer) 3| buf.writestring(""); | else | { 210| const old = e.stageflags; 210| e.stageflags |= stageToCBuffer; 210| argsToBuffer(e.elements, buf, hgs); 210| e.stageflags = old; | } 213| buf.writeByte(')'); | } | | override void visit(TypeExp e) | { 20141| typeToBuffer(e.type, null, buf, hgs); | } | | override void visit(ScopeExp e) | { 12312| if (e.sds.isTemplateInstance()) | { 12281| e.sds.dsymbolToBuffer(buf, hgs); | } 62| else if (hgs !is null && hgs.ddoc) | { | // fixes bug 6491 00000000| if (auto m = e.sds.isModule()) 00000000| buf.writestring(m.md.toChars()); | else 00000000| buf.writestring(e.sds.toChars()); | } | else | { 31| buf.writestring(e.sds.kind()); 31| buf.writeByte(' '); 31| buf.writestring(e.sds.toChars()); | } | } | | override void visit(TemplateExp e) | { 328| buf.writestring(e.td.toChars()); | } | | override void visit(NewExp e) | { 48| if (e.thisexp) | { 00000000| expToBuffer(e.thisexp, PREC.primary, buf, hgs); 00000000| buf.writeByte('.'); | } 48| buf.writestring("new "); 48| if (e.newargs && e.newargs.dim) | { 00000000| buf.writeByte('('); 00000000| argsToBuffer(e.newargs, buf, hgs); 00000000| buf.writeByte(')'); | } 48| typeToBuffer(e.newtype, null, buf, hgs); 76| if (e.arguments && e.arguments.dim) | { 19| buf.writeByte('('); 19| argsToBuffer(e.arguments, buf, hgs); 19| buf.writeByte(')'); | } | } | | override void visit(NewAnonClassExp e) | { 4| if (e.thisexp) | { 00000000| expToBuffer(e.thisexp, PREC.primary, buf, hgs); 00000000| buf.writeByte('.'); | } 4| buf.writestring("new"); 4| if (e.newargs && e.newargs.dim) | { 00000000| buf.writeByte('('); 00000000| argsToBuffer(e.newargs, buf, hgs); 00000000| buf.writeByte(')'); | } 4| buf.writestring(" class "); 6| if (e.arguments && e.arguments.dim) | { 00000000| buf.writeByte('('); 00000000| argsToBuffer(e.arguments, buf, hgs); 00000000| buf.writeByte(')'); | } 4| if (e.cd) 4| e.cd.dsymbolToBuffer(buf, hgs); | } | | override void visit(SymOffExp e) | { 120| if (e.offset) 2| buf.printf("(& %s%+lld)", e.var.toChars(), e.offset); 118| else if (e.var.isTypeInfoDeclaration()) 1| buf.writestring(e.var.toChars()); | else 117| buf.printf("& %s", e.var.toChars()); | } | | override void visit(VarExp e) | { 7454| buf.writestring(e.var.toChars()); | } | | override void visit(OverExp e) | { 2| buf.writestring(e.vars.ident.toString()); | } | | override void visit(TupleExp e) | { 104| if (e.e0) | { 00000000| buf.writeByte('('); 00000000| e.e0.accept(this); 00000000| buf.writestring(", tuple("); 00000000| argsToBuffer(e.exps, buf, hgs); 00000000| buf.writestring("))"); | } | else | { 104| buf.writestring("tuple("); 104| argsToBuffer(e.exps, buf, hgs); 104| buf.writeByte(')'); | } | } | | override void visit(FuncExp e) | { 2429| e.fd.dsymbolToBuffer(buf, hgs); | //buf.writestring(e.fd.toChars()); | } | | override 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. | */ 1| if (e.declaration) | { 00000000| if (auto var = e.declaration.isVarDeclaration()) | { | // For debugging use: | // - Avoid printing newline. | // - Intentionally use the format (Type var;) | // which isn't correct as regular D code. 00000000| buf.writeByte('('); | 00000000| scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 00000000| v.visitVarDecl(var, false); | 00000000| buf.writeByte(';'); 00000000| buf.writeByte(')'); | } 00000000| else e.declaration.dsymbolToBuffer(buf, hgs); | } | } | | override void visit(TypeidExp e) | { 6| buf.writestring("typeid("); 6| objectToBuffer(e.obj, buf, hgs); 6| buf.writeByte(')'); | } | | override void visit(TraitsExp e) | { 40| buf.writestring("__traits("); 40| if (e.ident) 40| buf.writestring(e.ident.toString()); 40| if (e.args) | { 273| foreach (arg; *e.args) | { 51| buf.writestring(", "); 51| objectToBuffer(arg, buf, hgs); | } | } 40| buf.writeByte(')'); | } | | override void visit(HaltExp e) | { 00000000| buf.writestring("halt"); | } | | override void visit(IsExp e) | { 396| buf.writestring("is("); 396| typeToBuffer(e.targ, e.id, buf, hgs); 396| if (e.tok2 != TOK.reserved) | { 8| buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2)); | } 388| else if (e.tspec) | { 359| if (e.tok == TOK.colon) 341| buf.writestring(" : "); | else 18| buf.writestring(" == "); 359| typeToBuffer(e.tspec, null, buf, hgs); | } 755| if (e.parameters && e.parameters.dim) | { 16| buf.writestring(", "); 16| scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 16| v.visitTemplateParameters(e.parameters); | } 396| buf.writeByte(')'); | } | | override void visit(UnaExp e) | { 129| buf.writestring(Token.toString(e.op)); 129| expToBuffer(e.e1, precedence[e.op], buf, hgs); | } | | override void visit(BinExp e) | { 1368| expToBuffer(e.e1, precedence[e.op], buf, hgs); 1368| buf.writeByte(' '); 1368| buf.writestring(Token.toString(e.op)); 1368| buf.writeByte(' '); 1368| expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs); | } | | override void visit(CommaExp e) | { | // CommaExp is generated by the compiler so it shouldn't | // appear in error messages or header files. | // For now, this treats the case where the compiler | // generates CommaExp for temporaries by calling | // the `sideeffect.copyToTemp` function. 8| auto ve = e.e2.isVarExp(); | | // not a CommaExp introduced for temporaries, go on | // the old path 12| if (!ve || !(ve.var.storage_class & STC.temp)) | { 6| visit(cast(BinExp)e); 6| return; | } | | // CommaExp that contain temporaries inserted via | // `copyToTemp` are usually of the form | // ((T __temp = exp), __tmp). | // Asserts are here to easily spot | // missing cases where CommaExp | // are used for other constructs 2| auto vd = ve.var.isVarDeclaration(); 4| assert(vd && vd._init); 2| auto exp = vd._init.isExpInitializer.exp; 2| assert(exp); 2| Expression commaExtract; 2| if (auto ce = exp.isConstructExp()) 1| commaExtract = ce.e2; 1| else if (auto se = exp.isStructLiteralExp) 1| commaExtract = se; | | // not one of the known cases, go on the old path 2| if (!commaExtract) | { 00000000| visit(cast(BinExp)e); 00000000| return; | } 2| expToBuffer(commaExtract, precedence[exp.op], buf, hgs); | } | | override void visit(CompileExp e) | { 2| buf.writestring("mixin("); 2| argsToBuffer(e.exps, buf, hgs, null); 2| buf.writeByte(')'); | } | | override void visit(ImportExp e) | { 00000000| buf.writestring("import("); 00000000| expToBuffer(e.e1, PREC.assign, buf, hgs); 00000000| buf.writeByte(')'); | } | | override void visit(AssertExp e) | { 425| buf.writestring("assert("); 425| expToBuffer(e.e1, PREC.assign, buf, hgs); 425| if (e.msg) | { 200| buf.writestring(", "); 200| expToBuffer(e.msg, PREC.assign, buf, hgs); | } 425| buf.writeByte(')'); | } | | override void visit(DotIdExp e) | { 807| expToBuffer(e.e1, PREC.primary, buf, hgs); 807| buf.writeByte('.'); 807| buf.writestring(e.ident.toString()); | } | | override void visit(DotTemplateExp e) | { 18| expToBuffer(e.e1, PREC.primary, buf, hgs); 18| buf.writeByte('.'); 18| buf.writestring(e.td.toChars()); | } | | override void visit(DotVarExp e) | { 653| expToBuffer(e.e1, PREC.primary, buf, hgs); 653| buf.writeByte('.'); 653| buf.writestring(e.var.toChars()); | } | | override void visit(DotTemplateInstanceExp e) | { 271| expToBuffer(e.e1, PREC.primary, buf, hgs); 271| buf.writeByte('.'); 271| e.ti.dsymbolToBuffer(buf, hgs); | } | | override void visit(DelegateExp e) | { 11| buf.writeByte('&'); 15| if (!e.func.isNested() || e.func.needThis()) | { 7| expToBuffer(e.e1, PREC.primary, buf, hgs); 7| buf.writeByte('.'); | } 11| buf.writestring(e.func.toChars()); | } | | override void visit(DotTypeExp e) | { 00000000| expToBuffer(e.e1, PREC.primary, buf, hgs); 00000000| buf.writeByte('.'); 00000000| buf.writestring(e.sym.toChars()); | } | | override void visit(CallExp e) | { 1366| if (e.e1.op == TOK.type) | { | /* 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 | */ 1| e.e1.accept(this); | } | else 1365| expToBuffer(e.e1, precedence[e.op], buf, hgs); 1366| buf.writeByte('('); 1366| argsToBuffer(e.arguments, buf, hgs); 1366| buf.writeByte(')'); | } | | override void visit(PtrExp e) | { 67| buf.writeByte('*'); 67| expToBuffer(e.e1, precedence[e.op], buf, hgs); | } | | override void visit(DeleteExp e) | { 4| buf.writestring("delete "); 4| expToBuffer(e.e1, precedence[e.op], buf, hgs); | } | | override void visit(CastExp e) | { 309| buf.writestring("cast("); 309| if (e.to) 309| typeToBuffer(e.to, null, buf, hgs); | else | { 00000000| MODtoBuffer(buf, e.mod); | } 309| buf.writeByte(')'); 309| expToBuffer(e.e1, precedence[e.op], buf, hgs); | } | | override void visit(VectorExp e) | { 421| buf.writestring("cast("); 421| typeToBuffer(e.to, null, buf, hgs); 421| buf.writeByte(')'); 421| expToBuffer(e.e1, precedence[e.op], buf, hgs); | } | | override void visit(VectorArrayExp e) | { 00000000| expToBuffer(e.e1, PREC.primary, buf, hgs); 00000000| buf.writestring(".array"); | } | | override void visit(SliceExp e) | { 268| expToBuffer(e.e1, precedence[e.op], buf, hgs); 268| buf.writeByte('['); 427| if (e.upr || e.lwr) | { 109| if (e.lwr) 109| sizeToBuffer(e.lwr, buf, hgs); | else 00000000| buf.writeByte('0'); 109| buf.writestring(".."); 109| if (e.upr) 109| sizeToBuffer(e.upr, buf, hgs); | else 00000000| buf.writeByte('$'); | } 268| buf.writeByte(']'); | } | | override void visit(ArrayLengthExp e) | { 13| expToBuffer(e.e1, PREC.primary, buf, hgs); 13| buf.writestring(".length"); | } | | override void visit(IntervalExp e) | { 29| expToBuffer(e.lwr, PREC.assign, buf, hgs); 29| buf.writestring(".."); 29| expToBuffer(e.upr, PREC.assign, buf, hgs); | } | | override void visit(DelegatePtrExp e) | { 1| expToBuffer(e.e1, PREC.primary, buf, hgs); 1| buf.writestring(".ptr"); | } | | override void visit(DelegateFuncptrExp e) | { 00000000| expToBuffer(e.e1, PREC.primary, buf, hgs); 00000000| buf.writestring(".funcptr"); | } | | override void visit(ArrayExp e) | { 142| expToBuffer(e.e1, PREC.primary, buf, hgs); 142| buf.writeByte('['); 142| argsToBuffer(e.arguments, buf, hgs); 142| buf.writeByte(']'); | } | | override void visit(DotExp e) | { 3| expToBuffer(e.e1, PREC.primary, buf, hgs); 3| buf.writeByte('.'); 3| expToBuffer(e.e2, PREC.primary, buf, hgs); | } | | override void visit(IndexExp e) | { 186| expToBuffer(e.e1, PREC.primary, buf, hgs); 186| buf.writeByte('['); 186| sizeToBuffer(e.e2, buf, hgs); 186| buf.writeByte(']'); | } | | override void visit(PostExp e) | { 80| expToBuffer(e.e1, precedence[e.op], buf, hgs); 80| buf.writestring(Token.toString(e.op)); | } | | override void visit(PreExp e) | { 1| buf.writestring(Token.toString(e.op)); 1| expToBuffer(e.e1, precedence[e.op], buf, hgs); | } | | override void visit(RemoveExp e) | { 00000000| expToBuffer(e.e1, PREC.primary, buf, hgs); 00000000| buf.writestring(".remove("); 00000000| expToBuffer(e.e2, PREC.assign, buf, hgs); 00000000| buf.writeByte(')'); | } | | override void visit(CondExp e) | { 27| expToBuffer(e.econd, PREC.oror, buf, hgs); 27| buf.writestring(" ? "); 27| expToBuffer(e.e1, PREC.expr, buf, hgs); 27| buf.writestring(" : "); 27| expToBuffer(e.e2, PREC.cond, buf, hgs); | } | | override void visit(DefaultInitExp e) | { 00000000| buf.writestring(Token.toString(e.subop)); | } | | override void visit(ClassReferenceExp e) | { 7| buf.writestring(e.value.toChars()); | } |} | | |private void templateParameterToBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) |{ 563| scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); 563| tp.accept(v); |} | |private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor |{ | alias visit = Visitor.visit; |public: | OutBuffer* buf; | HdrGenState* hgs; | 17837| extern (D) this(OutBuffer* buf, HdrGenState* hgs) | { 17837| this.buf = buf; 17837| this.hgs = hgs; | } | | override void visit(TemplateTypeParameter tp) | { 17289| buf.writestring(tp.ident.toString()); 17289| if (tp.specType) | { 808| buf.writestring(" : "); 808| typeToBuffer(tp.specType, null, buf, hgs); | } 17289| if (tp.defaultType) | { 11| buf.writestring(" = "); 11| typeToBuffer(tp.defaultType, null, buf, hgs); | } | } | | override void visit(TemplateThisParameter tp) | { 9| buf.writestring("this "); 9| visit(cast(TemplateTypeParameter)tp); | } | | override void visit(TemplateAliasParameter tp) | { 79| buf.writestring("alias "); 79| if (tp.specType) 00000000| typeToBuffer(tp.specType, tp.ident, buf, hgs); | else 79| buf.writestring(tp.ident.toString()); 79| if (tp.specAlias) | { 2| buf.writestring(" : "); 2| objectToBuffer(tp.specAlias, buf, hgs); | } 79| if (tp.defaultAlias) | { 23| buf.writestring(" = "); 23| objectToBuffer(tp.defaultAlias, buf, hgs); | } | } | | override void visit(TemplateValueParameter tp) | { 251| typeToBuffer(tp.valType, tp.ident, buf, hgs); 251| if (tp.specValue) | { 00000000| buf.writestring(" : "); 00000000| tp.specValue.expressionToBuffer(buf, hgs); | } 251| if (tp.defaultValue) | { 143| buf.writestring(" = "); 143| tp.defaultValue.expressionToBuffer(buf, hgs); | } | } | | override void visit(TemplateTupleParameter tp) | { 218| buf.writestring(tp.ident.toString()); 218| buf.writestring("..."); | } |} | |private void conditionToBuffer(Condition c, OutBuffer* buf, HdrGenState* hgs) |{ 34| scope v = new ConditionPrettyPrintVisitor(buf, hgs); 34| c.accept(v); |} | |private extern (C++) final class ConditionPrettyPrintVisitor : Visitor |{ | alias visit = Visitor.visit; |public: | OutBuffer* buf; | HdrGenState* hgs; | 34| extern (D) this(OutBuffer* buf, HdrGenState* hgs) | { 34| this.buf = buf; 34| this.hgs = hgs; | } | | override void visit(DebugCondition c) | { 00000000| buf.writestring("debug ("); 00000000| if (c.ident) 00000000| buf.writestring(c.ident.toString()); | else 00000000| buf.print(c.level); 00000000| buf.writeByte(')'); | } | | override void visit(VersionCondition c) | { 10| buf.writestring("version ("); 10| if (c.ident) 10| buf.writestring(c.ident.toString()); | else 00000000| buf.print(c.level); 10| buf.writeByte(')'); | } | | override void visit(StaticIfCondition c) | { 24| buf.writestring("static if ("); 24| c.exp.expressionToBuffer(buf, hgs); 24| buf.writeByte(')'); | } |} | |void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs) |{ 00000000| scope v = new StatementPrettyPrintVisitor(buf, hgs); 00000000| (cast() s).accept(v); |} | |void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs) |{ 380753| typeToBuffer(cast() t, ident, buf, hgs); |} | |void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) |{ 133| scope v = new DsymbolPrettyPrintVisitor(buf, hgs); 133| s.accept(v); |} | |// used from TemplateInstance::toChars() and TemplateMixin::toChars() |void toCBufferInstance(const TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false) |{ 151874| HdrGenState hgs; 151874| hgs.fullQual = qualifyTypes; 151874| scope v = new DsymbolPrettyPrintVisitor(buf, &hgs); 151874| v.visit(cast() ti); |} | |void toCBuffer(const Initializer iz, OutBuffer* buf, HdrGenState* hgs) |{ 21| initializerToBuffer(cast() iz, buf, hgs); |} | |bool stcToBuffer(OutBuffer* buf, StorageClass stc) |{ 32838| bool result = false; 32838| if ((stc & (STC.return_ | STC.scope_)) == (STC.return_ | STC.scope_)) 00000000| stc &= ~STC.scope_; 32838| if (stc & STC.scopeinferred) 11198| stc &= ~(STC.scope_ | STC.scopeinferred); 38038| while (stc) | { 5224| const s = stcToString(stc); 5224| if (!s.length) 24| break; 5200| if (result) 240| buf.writeByte(' '); 5200| result = true; 5200| buf.writestring(s); | } 32838| return result; |} | |/************************************************* | * Pick off one of the storage classes from stc, | * and return a string representation of it. | * stc is reduced by the one picked. | */ |string stcToString(ref StorageClass stc) |{ | struct SCstring | { | StorageClass stc; | TOK tok; | string id; | } | 5244| __gshared SCstring* table = | [ | SCstring(STC.auto_, TOK.auto_), | SCstring(STC.scope_, TOK.scope_), | SCstring(STC.static_, TOK.static_), | SCstring(STC.extern_, TOK.extern_), | SCstring(STC.const_, TOK.const_), | SCstring(STC.final_, TOK.final_), | SCstring(STC.abstract_, TOK.abstract_), | SCstring(STC.synchronized_, TOK.synchronized_), | SCstring(STC.deprecated_, TOK.deprecated_), | SCstring(STC.override_, TOK.override_), | SCstring(STC.lazy_, TOK.lazy_), | SCstring(STC.alias_, TOK.alias_), | SCstring(STC.out_, TOK.out_), | SCstring(STC.in_, TOK.in_), | SCstring(STC.manifest, TOK.enum_), | SCstring(STC.immutable_, TOK.immutable_), | SCstring(STC.shared_, TOK.shared_), | SCstring(STC.nothrow_, TOK.nothrow_), | SCstring(STC.wild, TOK.inout_), | SCstring(STC.pure_, TOK.pure_), | SCstring(STC.ref_, TOK.ref_), | SCstring(STC.return_, TOK.return_), | SCstring(STC.tls), | SCstring(STC.gshared, TOK.gshared), | SCstring(STC.nogc, TOK.at, "@nogc"), | SCstring(STC.property, TOK.at, "@property"), | SCstring(STC.safe, TOK.at, "@safe"), | SCstring(STC.trusted, TOK.at, "@trusted"), | SCstring(STC.system, TOK.at, "@system"), | SCstring(STC.disable, TOK.at, "@disable"), | SCstring(STC.future, TOK.at, "@__future"), | SCstring(STC.local, TOK.at, "__local"), | SCstring(0, TOK.reserved) | ]; 40514| for (int i = 0; table[i].stc; i++) | { 20233| StorageClass tbl = table[i].stc; 20233| assert(tbl & STCStorageClass); 20233| if (stc & tbl) | { 5220| stc &= ~tbl; 5220| if (tbl == STC.tls) // TOKtls was removed 00000000| return "__thread"; 5220| TOK tok = table[i].tok; 10257| if (tok != TOK.at && !table[i].id.length) 235| table[i].id = Token.toString(tok); // lazilly initialize table 5220| return table[i].id; | } | } | //printf("stc = %llx\n", stc); 24| return null; |} | |const(char)* stcToChars(ref StorageClass stc) |{ 00000000| const s = stcToString(stc); 00000000| return &s[0]; // assume 0 terminated |} | | |/// Ditto |extern (D) string trustToString(TRUST trust) pure nothrow |{ 12497| final switch (trust) | { 00000000| case TRUST.default_: 00000000| return null; 578| case TRUST.system: 578| return "@system"; 40| case TRUST.trusted: 40| return "@trusted"; 11879| case TRUST.safe: 11879| return "@safe"; | } |} | |private void linkageToBuffer(OutBuffer* buf, LINK linkage) |{ 61| const s = linkageToString(linkage); 61| if (s.length) | { 61| buf.writestring("extern ("); 61| buf.writestring(s); 61| buf.writeByte(')'); | } |} | |const(char)* linkageToChars(LINK linkage) |{ | /// Works because we return a literal 256| return linkageToString(linkage).ptr; |} | |string linkageToString(LINK linkage) pure nothrow |{ 326| final switch (linkage) | { 00000000| case LINK.default_: 00000000| return null; 41| case LINK.d: 41| return "D"; 224| case LINK.c: 224| return "C"; 49| case LINK.cpp: 49| return "C++"; 4| case LINK.windows: 4| return "Windows"; 3| case LINK.pascal: 3| return "Pascal"; 3| case LINK.objc: 3| return "Objective-C"; 2| case LINK.system: 2| return "System"; | } |} | |void protectionToBuffer(OutBuffer* buf, Prot prot) |{ 313| buf.writestring(protectionToString(prot.kind)); 318| if (prot.kind == Prot.Kind.package_ && prot.pkg) | { 5| buf.writeByte('('); 5| buf.writestring(prot.pkg.toPrettyChars(true)); 5| buf.writeByte(')'); | } |} | |/** | * Returns: | * a human readable representation of `kind` | */ |const(char)* protectionToChars(Prot.Kind kind) |{ | // Null terminated because we return a literal 11| return protectionToString(kind).ptr; |} | |/// Ditto |extern (D) string protectionToString(Prot.Kind kind) nothrow pure |{ 438| final switch (kind) | { 8| case Prot.Kind.undefined: 8| return null; 00000000| case Prot.Kind.none: 00000000| return "none"; 226| case Prot.Kind.private_: 226| return "private"; 27| case Prot.Kind.package_: 27| return "package"; 31| case Prot.Kind.protected_: 31| return "protected"; 138| case Prot.Kind.public_: 138| return "public"; 8| case Prot.Kind.export_: 8| return "export"; | } |} | |// Print the full function signature with correct ident, attributes and template args |void functionToBufferFull(TypeFunction tf, OutBuffer* buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) |{ | //printf("TypeFunction::toCBuffer() this = %p\n", this); 342| visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); |} | |// 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) |{ 26| HdrGenState hgs; 26| visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs); |} | |void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs) |{ 51761| scope v = new ExpressionPrettyPrintVisitor(buf, hgs); 51761| (cast() e).accept(v); |} | |/************************************************** | * Write out argument types to buf. | */ |void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments) |{ 18900| if (!arguments || !arguments.dim) 4237| return; 5215| HdrGenState hgs; 38477| foreach (i, arg; *arguments) | { 5708| if (i) 493| buf.writestring(", "); 5708| typeToBuffer(arg.type, null, buf, &hgs); | } |} | |void toCBuffer(const TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs) |{ 17274| scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs); 17274| (cast() tp).accept(v); |} | |void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects) |{ 8083| if (!objects || !objects.dim) 7979| return; 52| HdrGenState hgs; 364| foreach (i, o; *objects) | { 52| if (i) 00000000| buf.writestring(", "); 52| objectToBuffer(o, buf, &hgs); | } |} | |/************************************************************* | * Pretty print function parameters. | * Params: | * pl = parameter list to print | * Returns: Null-terminated string representing parameters. | */ |extern (C++) const(char)* parametersTypeToChars(ParameterList pl) |{ 21246| OutBuffer buf; 10623| HdrGenState hgs; 10623| parametersToBuffer(pl, &buf, &hgs); 10623| return buf.extractChars(); |} | |/************************************************************* | * Pretty print function parameter. | * Params: | * parameter = parameter to print. | * tf = TypeFunction which holds parameter. | * fullQual = whether to fully qualify types. | * Returns: Null-terminated string representing parameters. | */ |const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual) |{ 8264| OutBuffer buf; 4132| HdrGenState hgs; 4132| hgs.fullQual = fullQual; | 4132| parameterToBuffer(parameter, &buf, &hgs); | 4141| if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.dim - 1]) | { 7| buf.writestring("..."); | } 4132| return buf.extractChars(); |} | | |/************************************************* | * Write ParameterList to buffer. | * Params: | * pl = parameter list to serialize | * buf = buffer to write it to | * hgs = context | */ | |private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* hgs) |{ 27233| buf.writeByte('('); 163521| foreach (i; 0 .. pl.length) | { 27274| if (i) 3027| buf.writestring(", "); 27274| pl[i].parameterToBuffer(buf, hgs); | } 27233| final switch (pl.varargs) | { 27150| case VarArg.none: 27150| break; | 35| case VarArg.variadic: 35| if (pl.length) 23| buf.writestring(", "); | 35| if (stcToBuffer(buf, pl.stc)) 2| buf.writeByte(' '); 35| goto case VarArg.typesafe; | 83| case VarArg.typesafe: 83| buf.writestring("..."); 83| break; | } 27233| buf.writeByte(')'); |} | | |/*********************************************************** | * Write parameter `p` to buffer `buf`. | * Params: | * p = parameter to serialize | * buf = buffer to write it to | * hgs = context | */ |private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs) |{ 31407| if (p.userAttribDecl) | { 66| buf.writeByte('@'); | 132| bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call; 66| if (isAnonymous) 49| buf.writeByte('('); | 66| argsToBuffer(p.userAttribDecl.atts, buf, hgs); | 66| if (isAnonymous) 49| buf.writeByte(')'); 66| buf.writeByte(' '); | } 31407| if (p.storageClass & STC.auto_) 477| buf.writestring("auto "); 31407| if (p.storageClass & STC.return_) 2564| buf.writestring("return "); | 31407| if (p.storageClass & STC.in_) 288| buf.writestring("in "); 31119| else if (p.storageClass & STC.out_) 19| buf.writestring("out "); 31100| else if (p.storageClass & STC.lazy_) 33| buf.writestring("lazy "); 31067| else if (p.storageClass & STC.alias_) 00000000| buf.writestring("alias "); | 31407| if (p.storageClass & STC.ref_) 2159| buf.writestring("ref "); | 31407| StorageClass stc = p.storageClass; 62814| if (p.type && p.type.mod & MODFlags.shared_) 4| stc &= ~STC.shared_; | 31407| if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ | STC.scope_ | STC.scopeinferred))) 4618| buf.writeByte(' '); | 31407| if (p.storageClass & STC.alias_) | { 00000000| if (p.ident) 00000000| buf.writestring(p.ident.toString()); | } 31407| else if (p.type.ty == Tident && 3382| (cast(TypeIdentifier)p.type).ident.toString().length > 3 && 1835| strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) | { | // print parameter name, instead of undetermined type parameter 1351| buf.writestring(p.ident.toString()); | } | else | { 60112| typeToBuffer(p.type, p.ident, buf, hgs, (stc & STC.in_) ? MODFlags.const_ : 0); | } | 31407| if (p.defaultArg) | { 69| buf.writestring(" = "); 69| p.defaultArg.expToBuffer(PREC.assign, buf, hgs); | } |} | | |/************************************************** | * Write out argument list to buf. | */ |private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null) |{ 9294| if (!expressions || !expressions.dim) 634| return; | version (all) | { 50570| foreach (i, el; *expressions) | { 9632| if (i) 5618| buf.writestring(", "); 9632| if (!el) 2677| el = basis; 9632| if (el) 9631| expToBuffer(el, PREC.assign, buf, hgs); | } | } | else | { | // Sparse style formatting, for debug use only | // [0..dim: basis, 1: e1, 5: e5] | if (basis) | { | buf.writestring("0.."); | buf.print(expressions.dim); | buf.writestring(": "); | expToBuffer(basis, PREC.assign, buf, hgs); | } | foreach (i, el; *expressions) | { | if (el) | { | if (basis) | { | buf.writestring(", "); | buf.print(i); | buf.writestring(": "); | } | else if (i) | buf.writestring(", "); | expToBuffer(el, PREC.assign, buf, hgs); | } | } | } |} | |private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) |{ 29214| if (e.type == Type.tsize_t) | { 26902| Expression ex = (e.op == TOK.cast_ ? (cast(CastExp)e).e1 : e); 13451| ex = ex.optimize(WANTvalue); 26902| const dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1; 13451| if (cast(sinteger_t)uval >= 0) | { 13423| dinteger_t sizemax = void; 13423| if (target.ptrsize == 8) 13420| sizemax = 0xFFFFFFFFFFFFFFFFUL; 3| else if (target.ptrsize == 4) 3| sizemax = 0xFFFFFFFFU; 00000000| else if (target.ptrsize == 2) 00000000| sizemax = 0xFFFFU; | else 00000000| assert(0); 26846| if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) | { 13423| buf.print(uval); 13423| return; | } | } | } 15791| expToBuffer(e, PREC.assign, buf, hgs); |} | |private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs) |{ 137465| scope v = new ExpressionPrettyPrintVisitor(buf, hgs); 137465| e.accept(v); |} | |/************************************************** | * Write expression out to buf, but wrap it | * in ( ) if its precedence is less than pr. | */ |private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs) |{ | debug | { 133834| if (precedence[e.op] == PREC.zero) 00000000| printf("precedence not defined for token '%s'\n", Token.toChars(e.op)); | } 133834| if (e.op == 0xFF) | { 00000000| buf.writestring(""); 00000000| return; | } 133834| assert(precedence[e.op] != PREC.zero); 133834| assert(pr != PREC.zero); | /* Despite precedence, we don't allow a= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel)) | { 216| buf.writeByte('('); 216| e.expressionToBuffer(buf, hgs); 216| buf.writeByte(')'); | } | else | { 133618| e.expressionToBuffer(buf, hgs); | } |} | | |/************************************************** | * An entry point to pretty-print type. | */ |private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGenState* hgs, | ubyte modMask = 0) |{ 572790| if (auto tf = t.isTypeFunction()) | { 1389| visitFuncIdentWithPrefix(tf, ident, null, buf, hgs); 1389| return; | } 571401| visitWithMask(t, modMask, buf, hgs); 571401| if (ident) | { 27565| buf.writeByte(' '); 27565| buf.writestring(ident.toString()); | } |} | |private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* hgs) |{ | // Tuples and functions don't use the type constructor syntax 764390| if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) | { 606137| typeToBufferx(t, buf, hgs); | } | else | { 52751| ubyte m = t.mod & ~(t.mod & modMask); 52751| if (m & MODFlags.shared_) | { 561| MODtoBuffer(buf, MODFlags.shared_); 561| buf.writeByte('('); | } 52751| if (m & MODFlags.wild) | { 4001| MODtoBuffer(buf, MODFlags.wild); 4001| buf.writeByte('('); | } 52751| if (m & (MODFlags.const_ | MODFlags.immutable_)) | { 48132| MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_)); 48132| buf.writeByte('('); | } 52751| typeToBufferx(t, buf, hgs); 52751| if (m & (MODFlags.const_ | MODFlags.immutable_)) 48132| buf.writeByte(')'); 52751| if (m & MODFlags.wild) 4001| buf.writeByte(')'); 52751| if (m & MODFlags.shared_) 561| buf.writeByte(')'); | } |} | | |private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) |{ 6| buf.writeByte('{'); 6| buf.writenl(); 6| buf.level++; | 6| if (ti.aliasdecl) | { 4| ti.aliasdecl.dsymbolToBuffer(buf, hgs); 4| buf.writenl(); | } 2| else if (ti.members) | { 12| foreach(m;*ti.members) 2| m.dsymbolToBuffer(buf, hgs); | } | 6| buf.level--; 6| buf.writeByte('}'); 6| buf.writenl(); | |} | |private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs) |{ 164825| buf.writeByte('!'); 164825| if (ti.nest) | { 00000000| buf.writestring("(...)"); 00000000| return; | } 164825| if (!ti.tiargs) | { 00000000| buf.writestring("()"); 00000000| return; | } 164825| if (ti.tiargs.dim == 1) | { 83249| RootObject oarg = (*ti.tiargs)[0]; 83249| if (Type t = isType(oarg)) | { 384267| if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.dim == 0)) | { 36475| buf.writestring(t.toChars()); 36475| return; | } | } 9127| else if (Expression e = isExpression(oarg)) | { 29037| if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.this_) | { 4766| buf.writestring(e.toChars()); 4766| return; | } | } | } 123584| buf.writeByte('('); 123584| ti.nestUp(); 1260888| foreach (i, arg; *ti.tiargs) | { 222534| if (i) 105343| buf.writestring(", "); 222534| objectToBuffer(arg, buf, hgs); | } 123584| ti.nestDown(); 123584| buf.writeByte(')'); |} | |/**************************************** | * This makes a 'pretty' version of the template arguments. | * It's analogous to genIdent() which makes a mangled version. | */ |private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs) |{ | //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 https://issues.dlang.org/show_bug.cgi?id=7375 | * Perhaps it would be better to demangle what genIdent() does. | */ 222668| if (auto t = isType(oarg)) | { | //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); 117677| typeToBuffer(t, null, buf, hgs); | } 104991| else if (auto e = isExpression(oarg)) | { 100079| if (e.op == TOK.variable) 5558| e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 100079| expToBuffer(e, PREC.assign, buf, hgs); | } 4912| else if (Dsymbol s = isDsymbol(oarg)) | { 9822| const p = s.ident ? s.ident.toChars() : s.toChars(); 4911| buf.writestring(p); | } 1| else if (auto v = isTuple(oarg)) | { 00000000| auto args = &v.objects; 00000000| foreach (i, arg; *args) | { 00000000| if (i) 00000000| buf.writestring(", "); 00000000| objectToBuffer(arg, buf, hgs); | } | } 1| else if (auto p = isParameter(oarg)) | { 1| parameterToBuffer(p, buf, hgs); | } 00000000| else if (!oarg) | { 00000000| buf.writestring("NULL"); | } | else | { | debug | { 00000000| printf("bad Object = %p\n", oarg); | } 00000000| assert(0); | } |} | | |private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBuffer* buf, HdrGenState* hgs) |{ 12768| if (t.inuse) | { 00000000| t.inuse = 2; // flag error to caller 00000000| return; | } 12768| t.inuse++; 12812| if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) | { 22| linkageToBuffer(buf, t.linkage); 22| buf.writeByte(' '); | } 12768| if (t.next) | { 12765| typeToBuffer(t.next, null, buf, hgs); 12765| if (ident) 12765| buf.writeByte(' '); | } 3| else if (hgs.ddoc) 00000000| buf.writestring("auto "); 12768| if (ident) 12768| buf.writestring(ident); 12768| parametersToBuffer(t.parameterList, buf, hgs); | /* Use postfix style for attributes | */ 12768| if (t.mod) | { 13| buf.writeByte(' '); 13| MODtoBuffer(buf, t.mod); | } | | void dg(string str) | { 41206| buf.writeByte(' '); 41206| buf.writestring(str); | } 12768| t.attributesApply(&dg); | 12768| t.inuse--; |} | |private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, | OutBuffer* buf, HdrGenState* hgs) |{ 1731| if (t.inuse) | { 00000000| t.inuse = 2; // flag error to caller 00000000| return; | } 1731| t.inuse++; | | /* Use 'storage class' (prefix) style for attributes | */ 1731| if (t.mod) | { 128| MODtoBuffer(buf, t.mod); 128| buf.writeByte(' '); | } | | void ignoreReturn(string str) | { 3007| if (str != "return") | { | // don't write 'ref' for ctors 3019| if ((ident == Id.ctor) && str == "ref") 3| return; 2963| buf.writestring(str); 2963| buf.writeByte(' '); | } | } 1731| t.attributesApply(&ignoreReturn); | 1815| if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) | { 39| linkageToBuffer(buf, t.linkage); 39| buf.writeByte(' '); | } 2675| if (ident && ident.toHChars2() != ident.toChars()) | { | // Don't print return type for ctor, dtor, unittest, etc | } 1650| else if (t.next) | { 1576| typeToBuffer(t.next, null, buf, hgs); 1576| if (ident) 795| buf.writeByte(' '); | } 74| else if (hgs.ddoc) 14| buf.writestring("auto "); 1731| if (ident) 944| buf.writestring(ident.toHChars2()); 1731| if (td) | { 167| buf.writeByte('('); 1197| foreach (i, p; *td.origParameters) | { 174| if (i) 59| buf.writestring(", "); 174| p.templateParameterToBuffer(buf, hgs); | } 167| buf.writeByte(')'); | } 1731| parametersToBuffer(t.parameterList, buf, hgs); 1731| if (t.isreturn) | { 41| buf.writestring(" return"); | } 1731| t.inuse--; |} | | |private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* hgs) |{ | void visitError(ErrorInitializer iz) | { 00000000| buf.writestring("__error__"); | } | | void visitVoid(VoidInitializer iz) | { 00000000| buf.writestring("void"); | } | | void visitStruct(StructInitializer si) | { | //printf("StructInitializer::toCBuffer()\n"); 8| buf.writeByte('{'); 88| foreach (i, const id; si.field) | { 16| if (i) 8| buf.writestring(", "); 16| if (id) | { 00000000| buf.writestring(id.toString()); 00000000| buf.writeByte(':'); | } 16| if (auto iz = si.value[i]) 16| initializerToBuffer(iz, buf, hgs); | } 8| buf.writeByte('}'); | } | | void visitArray(ArrayInitializer ai) | { 24| buf.writeByte('['); 328| foreach (i, ex; ai.index) | { 64| if (i) 40| buf.writestring(", "); 64| if (ex) | { 24| ex.expressionToBuffer(buf, hgs); 24| buf.writeByte(':'); | } 64| if (auto iz = ai.value[i]) 64| initializerToBuffer(iz, buf, hgs); | } 24| buf.writeByte(']'); | } | | void visitExp(ExpInitializer ei) | { 215| ei.exp.expressionToBuffer(buf, hgs); | } | 247| final switch (inx.kind) | { 00000000| case InitKind.error: return visitError (inx.isErrorInitializer ()); 00000000| case InitKind.void_: return visitVoid (inx.isVoidInitializer ()); 24| case InitKind.struct_: return visitStruct(inx.isStructInitializer()); 72| case InitKind.array: return visitArray (inx.isArrayInitializer ()); 645| case InitKind.exp: return visitExp (inx.isExpInitializer ()); | } |} | | |private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) |{ | void visitType(Type t) | { 00000000| printf("t = %p, ty = %d\n", t, t.ty); 00000000| assert(0); | } | | void visitError(TypeError t) | { 10| buf.writestring("_error_"); | } | | void visitBasic(TypeBasic t) | { | //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); 396779| buf.writestring(t.dstring); | } | | void visitTraits(TypeTraits t) | { | //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod); 2| t.exp.expressionToBuffer(buf, hgs); | } | | void visitVector(TypeVector t) | { | //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod); 5132| buf.writestring("__vector("); 5132| visitWithMask(t.basetype, t.mod, buf, hgs); 5132| buf.writestring(")"); | } | | void visitSArray(TypeSArray t) | { 28808| visitWithMask(t.next, t.mod, buf, hgs); 28808| buf.writeByte('['); 28808| sizeToBuffer(t.dim, buf, hgs); 28808| buf.writeByte(']'); | } | | void visitDArray(TypeDArray t) | { 74967| Type ut = t.castMod(0); 74967| if (hgs.declstring) 00000000| goto L1; 74967| if (ut.equals(Type.tstring)) 31829| buf.writestring("string"); 43138| else if (ut.equals(Type.twstring)) 147| buf.writestring("wstring"); 42991| else if (ut.equals(Type.tdstring)) 154| buf.writestring("dstring"); | else | { | L1: 42837| visitWithMask(t.next, t.mod, buf, hgs); 42837| buf.writestring("[]"); | } | } | | void visitAArray(TypeAArray t) | { 1697| visitWithMask(t.next, t.mod, buf, hgs); 1697| buf.writeByte('['); 1697| visitWithMask(t.index, 0, buf, hgs); 1697| buf.writeByte(']'); | } | | void visitPointer(TypePointer t) | { | //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty); 19189| if (t.next.ty == Tfunction) 11874| visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function", buf, hgs); | else | { 7315| visitWithMask(t.next, t.mod, buf, hgs); 7315| buf.writeByte('*'); | } | } | | void visitReference(TypeReference t) | { 00000000| visitWithMask(t.next, t.mod, buf, hgs); 00000000| buf.writeByte('&'); | } | | void visitFunction(TypeFunction t) | { | //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref); 00000000| visitFuncIdentWithPostfix(t, null, buf, hgs); | } | | void visitDelegate(TypeDelegate t) | { 868| visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate", buf, hgs); | } | | void visitTypeQualifiedHelper(TypeQualified t) | { 114891| foreach (id; t.idents) | { 32| if (id.dyncast() == DYNCAST.dsymbol) | { 1| buf.writeByte('.'); 1| TemplateInstance ti = cast(TemplateInstance)id; 1| ti.dsymbolToBuffer(buf, hgs); | } 31| else if (id.dyncast() == DYNCAST.expression) | { 2| buf.writeByte('['); 2| (cast(Expression)id).expressionToBuffer(buf, hgs); 2| buf.writeByte(']'); | } 29| else if (id.dyncast() == DYNCAST.type) | { 00000000| buf.writeByte('['); 00000000| typeToBufferx(cast(Type)id, buf, hgs); 00000000| buf.writeByte(']'); | } | else | { 29| buf.writeByte('.'); 29| buf.writestring(id.toString()); | } | } | } | | void visitIdentifier(TypeIdentifier t) | { 37392| buf.writestring(t.ident.toString()); 37392| visitTypeQualifiedHelper(t); | } | | void visitInstance(TypeInstance t) | { 352| t.tempinst.dsymbolToBuffer(buf, hgs); 352| visitTypeQualifiedHelper(t); | } | | void visitTypeof(TypeTypeof t) | { 521| buf.writestring("typeof("); 521| t.exp.expressionToBuffer(buf, hgs); 521| buf.writeByte(')'); 521| visitTypeQualifiedHelper(t); | } | | void visitReturn(TypeReturn t) | { 00000000| buf.writestring("typeof(return)"); 00000000| visitTypeQualifiedHelper(t); | } | | void visitEnum(TypeEnum t) | { 4890| buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); | } | | void visitStruct(TypeStruct t) | { | // https://issues.dlang.org/show_bug.cgi?id=13776 | // Don't use ti.toAlias() to avoid forward reference error | // while printing messages. 158824| TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null; 104219| if (ti && ti.aliasdecl == t.sym) 49336| buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); | else 109488| buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); | } | | void visitClass(TypeClass t) | { | // https://issues.dlang.org/show_bug.cgi?id=13776 | // Don't use ti.toAlias() to avoid forward reference error | // while printing messages. 10510| TemplateInstance ti = t.sym.parent.isTemplateInstance(); 12156| if (ti && ti.aliasdecl == t.sym) 3252| buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars()); | else 17768| buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars()); | } | | void visitTuple(TypeTuple t) | { 455| parametersToBuffer(ParameterList(t.arguments, VarArg.none), buf, hgs); | } | | void visitSlice(TypeSlice t) | { 1| visitWithMask(t.next, t.mod, buf, hgs); 1| buf.writeByte('['); 1| sizeToBuffer(t.lwr, buf, hgs); 1| buf.writestring(" .. "); 1| sizeToBuffer(t.upr, buf, hgs); 1| buf.writeByte(']'); | } | | void visitNull(TypeNull t) | { 347| buf.writestring("typeof(null)"); | } | | void visitMixin(TypeMixin t) | { 1| buf.writestring("mixin("); 1| argsToBuffer(t.exps, buf, hgs, null); 1| buf.writeByte(')'); | } | 658888| switch (t.ty) | { 1190337| default: return t.isTypeBasic() ? 396779| visitBasic(cast(TypeBasic)t) : 00000000| visitType(t); | 30| case Terror: return visitError(cast(TypeError)t); 6| case Ttraits: return visitTraits(cast(TypeTraits)t); 15396| case Tvector: return visitVector(cast(TypeVector)t); 86424| case Tsarray: return visitSArray(cast(TypeSArray)t); 224901| case Tarray: return visitDArray(cast(TypeDArray)t); 5091| case Taarray: return visitAArray(cast(TypeAArray)t); 57567| case Tpointer: return visitPointer(cast(TypePointer)t); 00000000| case Treference: return visitReference(cast(TypeReference)t); 00000000| case Tfunction: return visitFunction(cast(TypeFunction)t); 2604| case Tdelegate: return visitDelegate(cast(TypeDelegate)t); 112176| case Tident: return visitIdentifier(cast(TypeIdentifier)t); 1056| case Tinstance: return visitInstance(cast(TypeInstance)t); 1563| case Ttypeof: return visitTypeof(cast(TypeTypeof)t); 00000000| case Treturn: return visitReturn(cast(TypeReturn)t); 7335| case Tenum: return visitEnum(cast(TypeEnum)t); 238236| case Tstruct: return visitStruct(cast(TypeStruct)t); 31530| case Tclass: return visitClass(cast(TypeClass)t); 1365| case Ttuple: return visitTuple (cast(TypeTuple)t); 3| case Tslice: return visitSlice(cast(TypeSlice)t); 1041| case Tnull: return visitNull(cast(TypeNull)t); 3| case Tmixin: return visitMixin(cast(TypeMixin)t); | } |} src/dmd/hdrgen.d is 82% covered <<<<<< EOF # path=./src-dmd-entity.lst |/** | * Defines the named entities to support the "\\&Entity;" escape sequence for strings / character literals. | * | * Specification $(LINK2 https://dlang.org/spec/entity.html, Named Character Entities) | * | * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved | * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) | * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/entity.d, _entity.d) | * Documentation: https://dlang.org/phobos/dmd_entity.html | * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/entity.d | */ | |module dmd.entity; | |import core.stdc.ctype; | |nothrow: | |public int HtmlNamedEntity(const(char)* p, size_t length) |{ 345| int tableIndex = tolower(*p) - 'a'; 690| if (tableIndex >= 0 && tableIndex < 26) | { 33230| foreach (entity; namesTable[tableIndex]) | { 10961| if (entity.name == p[0 .. length]) 344| return entity.value; | } | } 1| return -1; |} | |private: | |/********************************************* | * 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 |{ | string name; | uint value; |} | |// @todo@ order namesTable and names? by frequency |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 |]; | |immutable 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 AB